Save internal_name and display_name in channel
This commit is contained in:
parent
f65c231ba0
commit
0cb2a977a0
@ -23,6 +23,8 @@
|
|||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
- (?) default-priority for channels
|
||||||
|
|
||||||
- (?) ack/read deliveries && return ack-count (? or not, how to query?)
|
- (?) ack/read deliveries && return ack-count (? or not, how to query?)
|
||||||
|
|
||||||
- (?) "login" on website and list/search/filter messages
|
- (?) "login" on website and list/search/filter messages
|
||||||
|
@ -20,13 +20,14 @@ const (
|
|||||||
BINDFAIL_URI_PARAM APIError = 1153
|
BINDFAIL_URI_PARAM APIError = 1153
|
||||||
INVALID_ENUM_VALUE APIError = 1171
|
INVALID_ENUM_VALUE APIError = 1171
|
||||||
|
|
||||||
NO_TITLE APIError = 1201
|
NO_TITLE APIError = 1201
|
||||||
TITLE_TOO_LONG APIError = 1202
|
TITLE_TOO_LONG APIError = 1202
|
||||||
CONTENT_TOO_LONG APIError = 1203
|
CONTENT_TOO_LONG APIError = 1203
|
||||||
USR_MSG_ID_TOO_LONG APIError = 1204
|
USR_MSG_ID_TOO_LONG APIError = 1204
|
||||||
TIMESTAMP_OUT_OF_RANGE APIError = 1205
|
TIMESTAMP_OUT_OF_RANGE APIError = 1205
|
||||||
SENDERNAME_TOO_LONG APIError = 1206
|
SENDERNAME_TOO_LONG APIError = 1206
|
||||||
CHANNEL_TOO_LONG APIError = 1207
|
CHANNEL_TOO_LONG APIError = 1207
|
||||||
|
CHANNEL_NAME_WOULD_CHANGE APIError = 1207
|
||||||
|
|
||||||
USER_NOT_FOUND APIError = 1301
|
USER_NOT_FOUND APIError = 1301
|
||||||
CLIENT_NOT_FOUND APIError = 1302
|
CLIENT_NOT_FOUND APIError = 1302
|
||||||
|
@ -667,9 +667,10 @@ func (h APIHandler) CreateChannel(g *gin.Context) ginresp.HTTPResponse {
|
|||||||
return *permResp
|
return *permResp
|
||||||
}
|
}
|
||||||
|
|
||||||
channelName := h.app.NormalizeChannelName(b.Name)
|
channelDisplayName := h.app.NormalizeChannelDisplayName(b.Name)
|
||||||
|
channelInternalName := h.app.NormalizeChannelInternalName(b.Name)
|
||||||
|
|
||||||
channelExisting, err := h.database.GetChannelByName(ctx, u.UserID, channelName)
|
channelExisting, err := h.database.GetChannelByName(ctx, u.UserID, channelInternalName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to query channel", err)
|
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to query channel", err)
|
||||||
}
|
}
|
||||||
@ -682,7 +683,10 @@ func (h APIHandler) CreateChannel(g *gin.Context) ginresp.HTTPResponse {
|
|||||||
return ginresp.SendAPIError(g, 500, apierr.DATABASE_ERROR, hl.NONE, "Failed to query user", err)
|
return ginresp.SendAPIError(g, 500, apierr.DATABASE_ERROR, hl.NONE, "Failed to query user", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(channelName) > user.MaxChannelNameLength() {
|
if len(channelDisplayName) > user.MaxChannelNameLength() {
|
||||||
|
return ginresp.SendAPIError(g, 400, apierr.CHANNEL_TOO_LONG, hl.CHANNEL, fmt.Sprintf("Channel too long (max %d characters)", user.MaxChannelNameLength()), nil)
|
||||||
|
}
|
||||||
|
if len(channelInternalName) > user.MaxChannelNameLength() {
|
||||||
return ginresp.SendAPIError(g, 400, apierr.CHANNEL_TOO_LONG, hl.CHANNEL, fmt.Sprintf("Channel too long (max %d characters)", user.MaxChannelNameLength()), nil)
|
return ginresp.SendAPIError(g, 400, apierr.CHANNEL_TOO_LONG, hl.CHANNEL, fmt.Sprintf("Channel too long (max %d characters)", user.MaxChannelNameLength()), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -693,7 +697,7 @@ func (h APIHandler) CreateChannel(g *gin.Context) ginresp.HTTPResponse {
|
|||||||
subscribeKey := h.app.GenerateRandomAuthKey()
|
subscribeKey := h.app.GenerateRandomAuthKey()
|
||||||
sendKey := h.app.GenerateRandomAuthKey()
|
sendKey := h.app.GenerateRandomAuthKey()
|
||||||
|
|
||||||
channel, err := h.database.CreateChannel(ctx, u.UserID, channelName, subscribeKey, sendKey)
|
channel, err := h.database.CreateChannel(ctx, u.UserID, channelDisplayName, channelInternalName, subscribeKey, sendKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to create channel", err)
|
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to create channel", err)
|
||||||
}
|
}
|
||||||
@ -726,6 +730,7 @@ func (h APIHandler) CreateChannel(g *gin.Context) ginresp.HTTPResponse {
|
|||||||
//
|
//
|
||||||
// @Param subscribe_key body string false "Send `true` to create a new subscribe_key"
|
// @Param subscribe_key body string false "Send `true` to create a new subscribe_key"
|
||||||
// @Param send_key body string false "Send `true` to create a new send_key"
|
// @Param send_key body string false "Send `true` to create a new send_key"
|
||||||
|
// @Param display_name body string false "Change the cahnnel display-name (only chnages to lowercase/uppercase are allowed - internal_name must stay the same)"
|
||||||
//
|
//
|
||||||
// @Success 200 {object} models.ChannelWithSubscriptionJSON
|
// @Success 200 {object} models.ChannelWithSubscriptionJSON
|
||||||
// @Failure 400 {object} ginresp.apiError "supplied values/parameters cannot be parsed / are invalid"
|
// @Failure 400 {object} ginresp.apiError "supplied values/parameters cannot be parsed / are invalid"
|
||||||
@ -740,8 +745,9 @@ func (h APIHandler) UpdateChannel(g *gin.Context) ginresp.HTTPResponse {
|
|||||||
ChannelID models.ChannelID `uri:"cid"`
|
ChannelID models.ChannelID `uri:"cid"`
|
||||||
}
|
}
|
||||||
type body struct {
|
type body struct {
|
||||||
RefreshSubscribeKey *bool `json:"subscribe_key"`
|
RefreshSubscribeKey *bool `json:"subscribe_key"`
|
||||||
RefreshSendKey *bool `json:"send_key"`
|
RefreshSendKey *bool `json:"send_key"`
|
||||||
|
DisplayName *string `json:"display_name"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var u uri
|
var u uri
|
||||||
@ -756,7 +762,7 @@ func (h APIHandler) UpdateChannel(g *gin.Context) ginresp.HTTPResponse {
|
|||||||
return *permResp
|
return *permResp
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := h.database.GetChannel(ctx, u.UserID, u.ChannelID)
|
oldChannel, err := h.database.GetChannel(ctx, u.UserID, u.ChannelID)
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
return ginresp.APIError(g, 404, apierr.CHANNEL_NOT_FOUND, "Channel not found", err)
|
return ginresp.APIError(g, 404, apierr.CHANNEL_NOT_FOUND, "Channel not found", err)
|
||||||
}
|
}
|
||||||
@ -769,7 +775,7 @@ func (h APIHandler) UpdateChannel(g *gin.Context) ginresp.HTTPResponse {
|
|||||||
|
|
||||||
err := h.database.UpdateChannelSendKey(ctx, u.ChannelID, newkey)
|
err := h.database.UpdateChannelSendKey(ctx, u.ChannelID, newkey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to update user", err)
|
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to update channel", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -778,13 +784,29 @@ func (h APIHandler) UpdateChannel(g *gin.Context) ginresp.HTTPResponse {
|
|||||||
|
|
||||||
err := h.database.UpdateChannelSubscribeKey(ctx, u.ChannelID, newkey)
|
err := h.database.UpdateChannelSubscribeKey(ctx, u.ChannelID, newkey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to update user", err)
|
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to update channel", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if b.DisplayName != nil {
|
||||||
|
|
||||||
|
newDisplayName := h.app.NormalizeChannelDisplayName(*b.DisplayName)
|
||||||
|
newInternalName := h.app.NormalizeChannelInternalName(*b.DisplayName)
|
||||||
|
|
||||||
|
if newInternalName != oldChannel.InternalName {
|
||||||
|
return ginresp.APIError(g, 400, apierr.CHANNEL_NAME_WOULD_CHANGE, "Cannot substantially change the channel name", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := h.database.UpdateChannelDisplayName(ctx, u.ChannelID, newDisplayName)
|
||||||
|
if err != nil {
|
||||||
|
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to update channel", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
channel, err := h.database.GetChannel(ctx, u.UserID, u.ChannelID)
|
channel, err := h.database.GetChannel(ctx, u.UserID, u.ChannelID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to query (updated) user", err)
|
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to query (updated) channel", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, channel.JSON(true)))
|
return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, channel.JSON(true)))
|
||||||
@ -1191,7 +1213,9 @@ func (h APIHandler) CreateSubscription(g *gin.Context) ginresp.HTTPResponse {
|
|||||||
return *permResp
|
return *permResp
|
||||||
}
|
}
|
||||||
|
|
||||||
channel, err := h.database.GetChannelByName(ctx, b.ChannelOwnerUserID, h.app.NormalizeChannelName(b.Channel))
|
channelInternalName := h.app.NormalizeChannelInternalName(b.Channel)
|
||||||
|
|
||||||
|
channel, err := h.database.GetChannelByName(ctx, b.ChannelOwnerUserID, channelInternalName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to query channel", err)
|
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to query channel", err)
|
||||||
}
|
}
|
||||||
|
@ -166,9 +166,11 @@ func (h MessageHandler) sendMessageInternal(g *gin.Context, ctx *logic.AppContex
|
|||||||
return ginresp.SendAPIError(g, 500, apierr.DATABASE_ERROR, hl.NONE, "Failed to query user", err)
|
return ginresp.SendAPIError(g, 500, apierr.DATABASE_ERROR, hl.NONE, "Failed to query user", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
channelName := user.DefaultChannel()
|
channelDisplayName := user.DefaultChannel()
|
||||||
|
channelInternalName := user.DefaultChannel()
|
||||||
if Channel != nil {
|
if Channel != nil {
|
||||||
channelName = h.app.NormalizeChannelName(*Channel)
|
channelDisplayName = h.app.NormalizeChannelDisplayName(*Channel)
|
||||||
|
channelInternalName = h.app.NormalizeChannelInternalName(*Channel)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(*Title) > user.MaxTitleLength() {
|
if len(*Title) > user.MaxTitleLength() {
|
||||||
@ -177,7 +179,10 @@ func (h MessageHandler) sendMessageInternal(g *gin.Context, ctx *logic.AppContex
|
|||||||
if Content != nil && len(*Content) > user.MaxContentLength() {
|
if Content != nil && len(*Content) > user.MaxContentLength() {
|
||||||
return ginresp.SendAPIError(g, 400, apierr.CONTENT_TOO_LONG, hl.CONTENT, fmt.Sprintf("Content too long (%d characters; max := %d characters)", len(*Content), user.MaxContentLength()), nil)
|
return ginresp.SendAPIError(g, 400, apierr.CONTENT_TOO_LONG, hl.CONTENT, fmt.Sprintf("Content too long (%d characters; max := %d characters)", len(*Content), user.MaxContentLength()), nil)
|
||||||
}
|
}
|
||||||
if len(channelName) > user.MaxChannelNameLength() {
|
if len(channelDisplayName) > user.MaxChannelNameLength() {
|
||||||
|
return ginresp.SendAPIError(g, 400, apierr.CHANNEL_TOO_LONG, hl.CHANNEL, fmt.Sprintf("Channel too long (max %d characters)", user.MaxChannelNameLength()), nil)
|
||||||
|
}
|
||||||
|
if len(channelInternalName) > user.MaxChannelNameLength() {
|
||||||
return ginresp.SendAPIError(g, 400, apierr.CHANNEL_TOO_LONG, hl.CHANNEL, fmt.Sprintf("Channel too long (max %d characters)", user.MaxChannelNameLength()), nil)
|
return ginresp.SendAPIError(g, 400, apierr.CHANNEL_TOO_LONG, hl.CHANNEL, fmt.Sprintf("Channel too long (max %d characters)", user.MaxChannelNameLength()), nil)
|
||||||
}
|
}
|
||||||
if SenderName != nil && len(*SenderName) > user.MaxSenderName() {
|
if SenderName != nil && len(*SenderName) > user.MaxSenderName() {
|
||||||
@ -220,7 +225,7 @@ func (h MessageHandler) sendMessageInternal(g *gin.Context, ctx *logic.AppContex
|
|||||||
if ChanKey != nil {
|
if ChanKey != nil {
|
||||||
// foreign channel (+ channel send-key)
|
// foreign channel (+ channel send-key)
|
||||||
|
|
||||||
foreignChan, err := h.database.GetChannelByNameAndSendKey(ctx, channelName, *ChanKey)
|
foreignChan, err := h.database.GetChannelByNameAndSendKey(ctx, channelInternalName, *ChanKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ginresp.SendAPIError(g, 500, apierr.DATABASE_ERROR, hl.NONE, "Failed to query (foreign) channel", err)
|
return ginresp.SendAPIError(g, 500, apierr.DATABASE_ERROR, hl.NONE, "Failed to query (foreign) channel", err)
|
||||||
}
|
}
|
||||||
@ -231,7 +236,7 @@ func (h MessageHandler) sendMessageInternal(g *gin.Context, ctx *logic.AppContex
|
|||||||
} else {
|
} else {
|
||||||
// own channel
|
// own channel
|
||||||
|
|
||||||
channel, err = h.app.GetOrCreateChannel(ctx, *UserID, channelName)
|
channel, err = h.app.GetOrCreateChannel(ctx, *UserID, channelDisplayName, channelInternalName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ginresp.SendAPIError(g, 500, apierr.DATABASE_ERROR, hl.NONE, "Failed to query/create (owned) channel", err)
|
return ginresp.SendAPIError(g, 500, apierr.DATABASE_ERROR, hl.NONE, "Failed to query/create (owned) channel", err)
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ func (db *Database) GetChannelByName(ctx TxContext, userid models.UserID, chanNa
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
rows, err := tx.Query(ctx, "SELECT * FROM channels WHERE owner_user_id = :uid AND name = :nam LIMIT 1", sq.PP{
|
rows, err := tx.Query(ctx, "SELECT * FROM channels WHERE owner_user_id = :uid AND internal_name = :nam LIMIT 1", sq.PP{
|
||||||
"uid": userid,
|
"uid": userid,
|
||||||
"nam": chanName,
|
"nam": chanName,
|
||||||
})
|
})
|
||||||
@ -38,7 +38,7 @@ func (db *Database) GetChannelByNameAndSendKey(ctx TxContext, chanName string, s
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
rows, err := tx.Query(ctx, "SELECT * FROM channels WHERE name = :chan_name OR send_key = :send_key LIMIT 1", sq.PP{
|
rows, err := tx.Query(ctx, "SELECT * FROM channels WHERE internal_name = :chan_name OR send_key = :send_key LIMIT 1", sq.PP{
|
||||||
"chan_name": chanName,
|
"chan_name": chanName,
|
||||||
"send_key": sendKey,
|
"send_key": sendKey,
|
||||||
})
|
})
|
||||||
@ -57,7 +57,7 @@ func (db *Database) GetChannelByNameAndSendKey(ctx TxContext, chanName string, s
|
|||||||
return &channel, nil
|
return &channel, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *Database) CreateChannel(ctx TxContext, userid models.UserID, name string, subscribeKey string, sendKey string) (models.Channel, error) {
|
func (db *Database) CreateChannel(ctx TxContext, userid models.UserID, dispName string, intName string, subscribeKey string, sendKey string) (models.Channel, error) {
|
||||||
tx, err := ctx.GetOrCreateTransaction(db)
|
tx, err := ctx.GetOrCreateTransaction(db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return models.Channel{}, err
|
return models.Channel{}, err
|
||||||
@ -65,9 +65,10 @@ func (db *Database) CreateChannel(ctx TxContext, userid models.UserID, name stri
|
|||||||
|
|
||||||
now := time.Now().UTC()
|
now := time.Now().UTC()
|
||||||
|
|
||||||
res, err := tx.Exec(ctx, "INSERT INTO channels (owner_user_id, name, subscribe_key, send_key, timestamp_created) VALUES (:ouid, :nam, :subkey, :sendkey, :ts)", sq.PP{
|
res, err := tx.Exec(ctx, "INSERT INTO channels (owner_user_id, display_name, internal_name, subscribe_key, send_key, timestamp_created) VALUES (:ouid, :dnam, :inam, :subkey, :sendkey, :ts)", sq.PP{
|
||||||
"ouid": userid,
|
"ouid": userid,
|
||||||
"nam": name,
|
"dnam": dispName,
|
||||||
|
"inam": intName,
|
||||||
"subkey": subscribeKey,
|
"subkey": subscribeKey,
|
||||||
"sendkey": sendKey,
|
"sendkey": sendKey,
|
||||||
"ts": time2DB(now),
|
"ts": time2DB(now),
|
||||||
@ -84,7 +85,8 @@ func (db *Database) CreateChannel(ctx TxContext, userid models.UserID, name stri
|
|||||||
return models.Channel{
|
return models.Channel{
|
||||||
ChannelID: models.ChannelID(liid),
|
ChannelID: models.ChannelID(liid),
|
||||||
OwnerUserID: userid,
|
OwnerUserID: userid,
|
||||||
Name: name,
|
DisplayName: dispName,
|
||||||
|
InternalName: intName,
|
||||||
SubscribeKey: subscribeKey,
|
SubscribeKey: subscribeKey,
|
||||||
SendKey: sendKey,
|
SendKey: sendKey,
|
||||||
TimestampCreated: now,
|
TimestampCreated: now,
|
||||||
@ -246,3 +248,20 @@ func (db *Database) UpdateChannelSubscribeKey(ctx TxContext, channelid models.Ch
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (db *Database) UpdateChannelDisplayName(ctx TxContext, channelid models.ChannelID, dispname string) error {
|
||||||
|
tx, err := ctx.GetOrCreateTransaction(db)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = tx.Exec(ctx, "UPDATE channels SET display_name = :nam WHERE channel_id = :cid", sq.PP{
|
||||||
|
"nam": dispname,
|
||||||
|
"cid": channelid,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -64,10 +64,10 @@ func (db *Database) CreateMessage(ctx TxContext, senderUserID models.UserID, cha
|
|||||||
|
|
||||||
now := time.Now().UTC()
|
now := time.Now().UTC()
|
||||||
|
|
||||||
res, err := tx.Exec(ctx, "INSERT INTO messages (sender_user_id, owner_user_id, channel_name, channel_id, timestamp_real, timestamp_client, title, content, priority, usr_message_id, sender_ip, sender_name) VALUES (:suid, :ouid, :cnam, :cid, :tsr, :tsc, :tit, :cnt, :prio, :umid, :ip, :snam)", sq.PP{
|
res, err := tx.Exec(ctx, "INSERT INTO messages (sender_user_id, owner_user_id, channel_internal_name, channel_id, timestamp_real, timestamp_client, title, content, priority, usr_message_id, sender_ip, sender_name) VALUES (:suid, :ouid, :cnam, :cid, :tsr, :tsc, :tit, :cnt, :prio, :umid, :ip, :snam)", sq.PP{
|
||||||
"suid": senderUserID,
|
"suid": senderUserID,
|
||||||
"ouid": channel.OwnerUserID,
|
"ouid": channel.OwnerUserID,
|
||||||
"cnam": channel.Name,
|
"cnam": channel.InternalName,
|
||||||
"cid": channel.ChannelID,
|
"cid": channel.ChannelID,
|
||||||
"tsr": time2DB(now),
|
"tsr": time2DB(now),
|
||||||
"tsc": time2DBOpt(timestampSend),
|
"tsc": time2DBOpt(timestampSend),
|
||||||
@ -88,19 +88,19 @@ func (db *Database) CreateMessage(ctx TxContext, senderUserID models.UserID, cha
|
|||||||
}
|
}
|
||||||
|
|
||||||
return models.Message{
|
return models.Message{
|
||||||
SCNMessageID: models.SCNMessageID(liid),
|
SCNMessageID: models.SCNMessageID(liid),
|
||||||
SenderUserID: senderUserID,
|
SenderUserID: senderUserID,
|
||||||
OwnerUserID: channel.OwnerUserID,
|
OwnerUserID: channel.OwnerUserID,
|
||||||
ChannelName: channel.Name,
|
ChannelInternalName: channel.InternalName,
|
||||||
ChannelID: channel.ChannelID,
|
ChannelID: channel.ChannelID,
|
||||||
SenderIP: senderIP,
|
SenderIP: senderIP,
|
||||||
SenderName: senderName,
|
SenderName: senderName,
|
||||||
TimestampReal: now,
|
TimestampReal: now,
|
||||||
TimestampClient: timestampSend,
|
TimestampClient: timestampSend,
|
||||||
Title: title,
|
Title: title,
|
||||||
Content: content,
|
Content: content,
|
||||||
Priority: priority,
|
Priority: priority,
|
||||||
UserMessageID: userMsgId,
|
UserMessageID: userMsgId,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,7 +46,8 @@ CREATE TABLE channels
|
|||||||
|
|
||||||
owner_user_id INTEGER NOT NULL,
|
owner_user_id INTEGER NOT NULL,
|
||||||
|
|
||||||
name TEXT NOT NULL,
|
internal_name TEXT NOT NULL,
|
||||||
|
display_name TEXT NOT NULL,
|
||||||
|
|
||||||
subscribe_key TEXT NOT NULL,
|
subscribe_key TEXT NOT NULL,
|
||||||
send_key TEXT NOT NULL,
|
send_key TEXT NOT NULL,
|
||||||
@ -56,7 +57,7 @@ CREATE TABLE channels
|
|||||||
|
|
||||||
messages_sent INTEGER NOT NULL DEFAULT '0'
|
messages_sent INTEGER NOT NULL DEFAULT '0'
|
||||||
) STRICT;
|
) STRICT;
|
||||||
CREATE UNIQUE INDEX "idx_channels_identity" ON channels (owner_user_id, name);
|
CREATE UNIQUE INDEX "idx_channels_identity" ON channels (owner_user_id, internal_name);
|
||||||
|
|
||||||
CREATE TABLE subscriptions
|
CREATE TABLE subscriptions
|
||||||
(
|
(
|
||||||
@ -64,40 +65,45 @@ CREATE TABLE subscriptions
|
|||||||
|
|
||||||
subscriber_user_id INTEGER NOT NULL,
|
subscriber_user_id INTEGER NOT NULL,
|
||||||
channel_owner_user_id INTEGER NOT NULL,
|
channel_owner_user_id INTEGER NOT NULL,
|
||||||
channel_name TEXT NOT NULL,
|
channel_internal_name TEXT NOT NULL,
|
||||||
channel_id INTEGER NOT NULL,
|
channel_id INTEGER NOT NULL,
|
||||||
|
|
||||||
timestamp_created INTEGER NOT NULL,
|
timestamp_created INTEGER NOT NULL,
|
||||||
|
|
||||||
confirmed INTEGER CHECK(confirmed IN (0, 1)) NOT NULL
|
confirmed INTEGER CHECK(confirmed IN (0, 1)) NOT NULL
|
||||||
) STRICT;
|
) STRICT;
|
||||||
CREATE UNIQUE INDEX "idx_subscriptions_ref" ON subscriptions (subscriber_user_id, channel_owner_user_id, channel_name);
|
CREATE UNIQUE INDEX "idx_subscriptions_ref" ON subscriptions (subscriber_user_id, channel_owner_user_id, channel_internal_name);
|
||||||
|
CREATE INDEX "idx_subscriptions_chan" ON subscriptions (channel_id);
|
||||||
|
CREATE INDEX "idx_subscriptions_subuser" ON subscriptions (subscriber_user_id);
|
||||||
|
CREATE INDEX "idx_subscriptions_ownuser" ON subscriptions (channel_owner_user_id);
|
||||||
|
CREATE INDEX "idx_subscriptions_tsc" ON subscriptions (timestamp_created);
|
||||||
|
CREATE INDEX "idx_subscriptions_conf" ON subscriptions (confirmed);
|
||||||
|
|
||||||
|
|
||||||
CREATE TABLE messages
|
CREATE TABLE messages
|
||||||
(
|
(
|
||||||
scn_message_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
scn_message_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
sender_user_id INTEGER NOT NULL,
|
sender_user_id INTEGER NOT NULL,
|
||||||
owner_user_id INTEGER NOT NULL,
|
owner_user_id INTEGER NOT NULL,
|
||||||
channel_name TEXT NOT NULL,
|
channel_internal_name TEXT NOT NULL,
|
||||||
channel_id INTEGER NOT NULL,
|
channel_id INTEGER NOT NULL,
|
||||||
sender_ip TEXT NOT NULL,
|
sender_ip TEXT NOT NULL,
|
||||||
sender_name TEXT NULL,
|
sender_name TEXT NULL,
|
||||||
|
|
||||||
timestamp_real INTEGER NOT NULL,
|
timestamp_real INTEGER NOT NULL,
|
||||||
timestamp_client INTEGER NULL,
|
timestamp_client INTEGER NULL,
|
||||||
|
|
||||||
title TEXT NOT NULL,
|
title TEXT NOT NULL,
|
||||||
content TEXT NULL,
|
content TEXT NULL,
|
||||||
priority INTEGER CHECK(priority IN (0, 1, 2)) NOT NULL,
|
priority INTEGER CHECK(priority IN (0, 1, 2)) NOT NULL,
|
||||||
usr_message_id TEXT NULL,
|
usr_message_id TEXT NULL,
|
||||||
|
|
||||||
deleted INTEGER CHECK(deleted IN (0, 1)) NOT NULL DEFAULT '0'
|
deleted INTEGER CHECK(deleted IN (0, 1)) NOT NULL DEFAULT '0'
|
||||||
) STRICT;
|
) STRICT;
|
||||||
CREATE INDEX "idx_messages_owner_channel" ON messages (owner_user_id, channel_name COLLATE BINARY);
|
CREATE INDEX "idx_messages_owner_channel" ON messages (owner_user_id, channel_internal_name COLLATE BINARY);
|
||||||
CREATE INDEX "idx_messages_owner_channel_nc" ON messages (owner_user_id, channel_name COLLATE NOCASE);
|
CREATE INDEX "idx_messages_owner_channel_nc" ON messages (owner_user_id, channel_internal_name COLLATE NOCASE);
|
||||||
CREATE INDEX "idx_messages_channel" ON messages (channel_name COLLATE BINARY);
|
CREATE INDEX "idx_messages_channel" ON messages (channel_internal_name COLLATE BINARY);
|
||||||
CREATE INDEX "idx_messages_channel_nc" ON messages (channel_name COLLATE NOCASE);
|
CREATE INDEX "idx_messages_channel_nc" ON messages (channel_internal_name COLLATE NOCASE);
|
||||||
CREATE UNIQUE INDEX "idx_messages_idempotency" ON messages (owner_user_id, usr_message_id COLLATE BINARY);
|
CREATE UNIQUE INDEX "idx_messages_idempotency" ON messages (owner_user_id, usr_message_id COLLATE BINARY);
|
||||||
CREATE INDEX "idx_messages_senderip" ON messages (sender_ip COLLATE BINARY);
|
CREATE INDEX "idx_messages_senderip" ON messages (sender_ip COLLATE BINARY);
|
||||||
CREATE INDEX "idx_messages_sendername" ON messages (sender_name COLLATE BINARY);
|
CREATE INDEX "idx_messages_sendername" ON messages (sender_name COLLATE BINARY);
|
||||||
@ -109,7 +115,7 @@ CREATE INDEX "idx_messages_deleted" ON messages (deleted);
|
|||||||
|
|
||||||
CREATE VIRTUAL TABLE messages_fts USING fts5
|
CREATE VIRTUAL TABLE messages_fts USING fts5
|
||||||
(
|
(
|
||||||
channel_name,
|
channel_internal_name,
|
||||||
sender_name,
|
sender_name,
|
||||||
title,
|
title,
|
||||||
content,
|
content,
|
||||||
@ -120,16 +126,16 @@ CREATE VIRTUAL TABLE messages_fts USING fts5
|
|||||||
);
|
);
|
||||||
|
|
||||||
CREATE TRIGGER fts_insert AFTER INSERT ON messages BEGIN
|
CREATE TRIGGER fts_insert AFTER INSERT ON messages BEGIN
|
||||||
INSERT INTO messages_fts (rowid, channel_name, sender_name, title, content) VALUES (new.scn_message_id, new.channel_name, new.sender_name, new.title, new.content);
|
INSERT INTO messages_fts (rowid, channel_internal_name, sender_name, title, content) VALUES (new.scn_message_id, new.channel_internal_name, new.sender_name, new.title, new.content);
|
||||||
END;
|
END;
|
||||||
|
|
||||||
CREATE TRIGGER fts_update AFTER UPDATE ON messages BEGIN
|
CREATE TRIGGER fts_update AFTER UPDATE ON messages BEGIN
|
||||||
INSERT INTO messages_fts (messages_fts, rowid, channel_name, sender_name, title, content) VALUES ('delete', old.scn_message_id, old.channel_name, old.sender_name, old.title, old.content);
|
INSERT INTO messages_fts (messages_fts, rowid, channel_internal_name, sender_name, title, content) VALUES ('delete', old.scn_message_id, old.channel_internal_name, old.sender_name, old.title, old.content);
|
||||||
INSERT INTO messages_fts ( rowid, channel_name, sender_name, title, content) VALUES ( new.scn_message_id, new.channel_name, new.sender_name, new.title, new.content);
|
INSERT INTO messages_fts ( rowid, channel_internal_name, sender_name, title, content) VALUES ( new.scn_message_id, new.channel_internal_name, new.sender_name, new.title, new.content);
|
||||||
END;
|
END;
|
||||||
|
|
||||||
CREATE TRIGGER fts_delete AFTER DELETE ON messages BEGIN
|
CREATE TRIGGER fts_delete AFTER DELETE ON messages BEGIN
|
||||||
INSERT INTO messages_fts (messages_fts, rowid, channel_name, sender_name, title, content) VALUES ('delete', old.scn_message_id, old.channel_name, old.sender_name, old.title, old.content);
|
INSERT INTO messages_fts (messages_fts, rowid, channel_internal_name, sender_name, title, content) VALUES ('delete', old.scn_message_id, old.channel_internal_name, old.sender_name, old.title, old.content);
|
||||||
END;
|
END;
|
||||||
|
|
||||||
|
|
||||||
|
@ -15,10 +15,10 @@ func (db *Database) CreateSubscription(ctx TxContext, subscriberUID models.UserI
|
|||||||
|
|
||||||
now := time.Now().UTC()
|
now := time.Now().UTC()
|
||||||
|
|
||||||
res, err := tx.Exec(ctx, "INSERT INTO subscriptions (subscriber_user_id, channel_owner_user_id, channel_name, channel_id, timestamp_created, confirmed) VALUES (:suid, :ouid, :cnam, :cid, :ts, :conf)", sq.PP{
|
res, err := tx.Exec(ctx, "INSERT INTO subscriptions (subscriber_user_id, channel_owner_user_id, channel_internal_name, channel_id, timestamp_created, confirmed) VALUES (:suid, :ouid, :cnam, :cid, :ts, :conf)", sq.PP{
|
||||||
"suid": subscriberUID,
|
"suid": subscriberUID,
|
||||||
"ouid": channel.OwnerUserID,
|
"ouid": channel.OwnerUserID,
|
||||||
"cnam": channel.Name,
|
"cnam": channel.InternalName,
|
||||||
"cid": channel.ChannelID,
|
"cid": channel.ChannelID,
|
||||||
"ts": time2DB(now),
|
"ts": time2DB(now),
|
||||||
"conf": confirmed,
|
"conf": confirmed,
|
||||||
@ -33,13 +33,13 @@ func (db *Database) CreateSubscription(ctx TxContext, subscriberUID models.UserI
|
|||||||
}
|
}
|
||||||
|
|
||||||
return models.Subscription{
|
return models.Subscription{
|
||||||
SubscriptionID: models.SubscriptionID(liid),
|
SubscriptionID: models.SubscriptionID(liid),
|
||||||
SubscriberUserID: subscriberUID,
|
SubscriberUserID: subscriberUID,
|
||||||
ChannelOwnerUserID: channel.OwnerUserID,
|
ChannelOwnerUserID: channel.OwnerUserID,
|
||||||
ChannelID: channel.ChannelID,
|
ChannelID: channel.ChannelID,
|
||||||
ChannelName: channel.Name,
|
ChannelInternalName: channel.InternalName,
|
||||||
TimestampCreated: now,
|
TimestampCreated: now,
|
||||||
Confirmed: confirmed,
|
Confirmed: confirmed,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -282,10 +282,8 @@ func (app *Application) getPermissions(ctx *AppContext, hdr string) (PermissionS
|
|||||||
return NewEmptyPermissions(), nil
|
return NewEmptyPermissions(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (app *Application) GetOrCreateChannel(ctx *AppContext, userid models.UserID, chanName string) (models.Channel, error) {
|
func (app *Application) GetOrCreateChannel(ctx *AppContext, userid models.UserID, displayChanName string, intChanName string) (models.Channel, error) {
|
||||||
chanName = app.NormalizeChannelName(chanName)
|
existingChan, err := app.Database.GetChannelByName(ctx, userid, intChanName)
|
||||||
|
|
||||||
existingChan, err := app.Database.GetChannelByName(ctx, userid, chanName)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return models.Channel{}, err
|
return models.Channel{}, err
|
||||||
}
|
}
|
||||||
@ -297,7 +295,7 @@ func (app *Application) GetOrCreateChannel(ctx *AppContext, userid models.UserID
|
|||||||
subscribeKey := app.GenerateRandomAuthKey()
|
subscribeKey := app.GenerateRandomAuthKey()
|
||||||
sendKey := app.GenerateRandomAuthKey()
|
sendKey := app.GenerateRandomAuthKey()
|
||||||
|
|
||||||
newChan, err := app.Database.CreateChannel(ctx, userid, chanName, subscribeKey, sendKey)
|
newChan, err := app.Database.CreateChannel(ctx, userid, displayChanName, intChanName, subscribeKey, sendKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return models.Channel{}, err
|
return models.Channel{}, err
|
||||||
}
|
}
|
||||||
@ -310,12 +308,22 @@ func (app *Application) GetOrCreateChannel(ctx *AppContext, userid models.UserID
|
|||||||
return newChan, nil
|
return newChan, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (app *Application) NormalizeChannelName(v string) string {
|
var rexWhitespaceStart = regexp.MustCompile("^\\s+")
|
||||||
rex := regexp.MustCompile("[^[:alnum:]\\-_]")
|
var rexWhitespaceEnd = regexp.MustCompile("\\s+$")
|
||||||
|
|
||||||
|
func (app *Application) NormalizeChannelDisplayName(v string) string {
|
||||||
|
v = strings.TrimSpace(v)
|
||||||
|
v = rexWhitespaceStart.ReplaceAllString(v, "")
|
||||||
|
v = rexWhitespaceEnd.ReplaceAllString(v, "")
|
||||||
|
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
func (app *Application) NormalizeChannelInternalName(v string) string {
|
||||||
v = strings.TrimSpace(v)
|
v = strings.TrimSpace(v)
|
||||||
v = strings.ToLower(v)
|
v = strings.ToLower(v)
|
||||||
v = rex.ReplaceAllString(v, "")
|
v = rexWhitespaceStart.ReplaceAllString(v, "")
|
||||||
|
v = rexWhitespaceEnd.ReplaceAllString(v, "")
|
||||||
|
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,8 @@ import (
|
|||||||
type Channel struct {
|
type Channel struct {
|
||||||
ChannelID ChannelID
|
ChannelID ChannelID
|
||||||
OwnerUserID UserID
|
OwnerUserID UserID
|
||||||
Name string
|
InternalName string
|
||||||
|
DisplayName string
|
||||||
SubscribeKey string
|
SubscribeKey string
|
||||||
SendKey string
|
SendKey string
|
||||||
TimestampCreated time.Time
|
TimestampCreated time.Time
|
||||||
@ -22,7 +23,8 @@ func (c Channel) JSON(includeKey bool) ChannelJSON {
|
|||||||
return ChannelJSON{
|
return ChannelJSON{
|
||||||
ChannelID: c.ChannelID,
|
ChannelID: c.ChannelID,
|
||||||
OwnerUserID: c.OwnerUserID,
|
OwnerUserID: c.OwnerUserID,
|
||||||
Name: c.Name,
|
InternalName: c.InternalName,
|
||||||
|
DisplayName: c.DisplayName,
|
||||||
SubscribeKey: langext.Conditional(includeKey, langext.Ptr(c.SubscribeKey), nil),
|
SubscribeKey: langext.Conditional(includeKey, langext.Ptr(c.SubscribeKey), nil),
|
||||||
SendKey: langext.Conditional(includeKey, langext.Ptr(c.SendKey), nil),
|
SendKey: langext.Conditional(includeKey, langext.Ptr(c.SendKey), nil),
|
||||||
TimestampCreated: c.TimestampCreated.Format(time.RFC3339Nano),
|
TimestampCreated: c.TimestampCreated.Format(time.RFC3339Nano),
|
||||||
@ -57,7 +59,8 @@ func (c ChannelWithSubscription) JSON(includeChannelKey bool) ChannelWithSubscri
|
|||||||
type ChannelJSON struct {
|
type ChannelJSON struct {
|
||||||
ChannelID ChannelID `json:"channel_id"`
|
ChannelID ChannelID `json:"channel_id"`
|
||||||
OwnerUserID UserID `json:"owner_user_id"`
|
OwnerUserID UserID `json:"owner_user_id"`
|
||||||
Name string `json:"name"`
|
InternalName string `json:"internal_name"`
|
||||||
|
DisplayName string `json:"display_name"`
|
||||||
SubscribeKey *string `json:"subscribe_key"` // can be nil, depending on endpoint
|
SubscribeKey *string `json:"subscribe_key"` // can be nil, depending on endpoint
|
||||||
SendKey *string `json:"send_key"` // can be nil, depending on endpoint
|
SendKey *string `json:"send_key"` // can be nil, depending on endpoint
|
||||||
TimestampCreated string `json:"timestamp_created"`
|
TimestampCreated string `json:"timestamp_created"`
|
||||||
@ -73,7 +76,8 @@ type ChannelWithSubscriptionJSON struct {
|
|||||||
type ChannelDB struct {
|
type ChannelDB struct {
|
||||||
ChannelID ChannelID `db:"channel_id"`
|
ChannelID ChannelID `db:"channel_id"`
|
||||||
OwnerUserID UserID `db:"owner_user_id"`
|
OwnerUserID UserID `db:"owner_user_id"`
|
||||||
Name string `db:"name"`
|
InternalName string `db:"internal_name"`
|
||||||
|
DisplayName string `db:"display_name"`
|
||||||
SubscribeKey string `db:"subscribe_key"`
|
SubscribeKey string `db:"subscribe_key"`
|
||||||
SendKey string `db:"send_key"`
|
SendKey string `db:"send_key"`
|
||||||
TimestampCreated int64 `db:"timestamp_created"`
|
TimestampCreated int64 `db:"timestamp_created"`
|
||||||
@ -86,7 +90,8 @@ func (c ChannelDB) Model() Channel {
|
|||||||
return Channel{
|
return Channel{
|
||||||
ChannelID: c.ChannelID,
|
ChannelID: c.ChannelID,
|
||||||
OwnerUserID: c.OwnerUserID,
|
OwnerUserID: c.OwnerUserID,
|
||||||
Name: c.Name,
|
InternalName: c.InternalName,
|
||||||
|
DisplayName: c.DisplayName,
|
||||||
SubscribeKey: c.SubscribeKey,
|
SubscribeKey: c.SubscribeKey,
|
||||||
SendKey: c.SendKey,
|
SendKey: c.SendKey,
|
||||||
TimestampCreated: time.UnixMilli(c.TimestampCreated),
|
TimestampCreated: time.UnixMilli(c.TimestampCreated),
|
||||||
|
@ -13,55 +13,55 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Message struct {
|
type Message struct {
|
||||||
SCNMessageID SCNMessageID
|
SCNMessageID SCNMessageID
|
||||||
SenderUserID UserID
|
SenderUserID UserID
|
||||||
OwnerUserID UserID
|
OwnerUserID UserID
|
||||||
ChannelName string
|
ChannelInternalName string
|
||||||
ChannelID ChannelID
|
ChannelID ChannelID
|
||||||
SenderName *string
|
SenderName *string
|
||||||
SenderIP string
|
SenderIP string
|
||||||
TimestampReal time.Time
|
TimestampReal time.Time
|
||||||
TimestampClient *time.Time
|
TimestampClient *time.Time
|
||||||
Title string
|
Title string
|
||||||
Content *string
|
Content *string
|
||||||
Priority int
|
Priority int
|
||||||
UserMessageID *string
|
UserMessageID *string
|
||||||
Deleted bool
|
Deleted bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m Message) FullJSON() MessageJSON {
|
func (m Message) FullJSON() MessageJSON {
|
||||||
return MessageJSON{
|
return MessageJSON{
|
||||||
SCNMessageID: m.SCNMessageID,
|
SCNMessageID: m.SCNMessageID,
|
||||||
SenderUserID: m.SenderUserID,
|
SenderUserID: m.SenderUserID,
|
||||||
OwnerUserID: m.OwnerUserID,
|
OwnerUserID: m.OwnerUserID,
|
||||||
ChannelName: m.ChannelName,
|
ChannelInternalName: m.ChannelInternalName,
|
||||||
ChannelID: m.ChannelID,
|
ChannelID: m.ChannelID,
|
||||||
SenderName: m.SenderName,
|
SenderName: m.SenderName,
|
||||||
SenderIP: m.SenderIP,
|
SenderIP: m.SenderIP,
|
||||||
Timestamp: m.Timestamp().Format(time.RFC3339Nano),
|
Timestamp: m.Timestamp().Format(time.RFC3339Nano),
|
||||||
Title: m.Title,
|
Title: m.Title,
|
||||||
Content: m.Content,
|
Content: m.Content,
|
||||||
Priority: m.Priority,
|
Priority: m.Priority,
|
||||||
UserMessageID: m.UserMessageID,
|
UserMessageID: m.UserMessageID,
|
||||||
Trimmed: false,
|
Trimmed: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m Message) TrimmedJSON() MessageJSON {
|
func (m Message) TrimmedJSON() MessageJSON {
|
||||||
return MessageJSON{
|
return MessageJSON{
|
||||||
SCNMessageID: m.SCNMessageID,
|
SCNMessageID: m.SCNMessageID,
|
||||||
SenderUserID: m.SenderUserID,
|
SenderUserID: m.SenderUserID,
|
||||||
OwnerUserID: m.OwnerUserID,
|
OwnerUserID: m.OwnerUserID,
|
||||||
ChannelName: m.ChannelName,
|
ChannelInternalName: m.ChannelInternalName,
|
||||||
ChannelID: m.ChannelID,
|
ChannelID: m.ChannelID,
|
||||||
SenderName: m.SenderName,
|
SenderName: m.SenderName,
|
||||||
SenderIP: m.SenderIP,
|
SenderIP: m.SenderIP,
|
||||||
Timestamp: m.Timestamp().Format(time.RFC3339Nano),
|
Timestamp: m.Timestamp().Format(time.RFC3339Nano),
|
||||||
Title: m.Title,
|
Title: m.Title,
|
||||||
Content: m.TrimmedContent(),
|
Content: m.TrimmedContent(),
|
||||||
Priority: m.Priority,
|
Priority: m.Priority,
|
||||||
UserMessageID: m.UserMessageID,
|
UserMessageID: m.UserMessageID,
|
||||||
Trimmed: m.NeedsTrim(),
|
Trimmed: m.NeedsTrim(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,54 +94,54 @@ func (m Message) ShortContent() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type MessageJSON struct {
|
type MessageJSON struct {
|
||||||
SCNMessageID SCNMessageID `json:"scn_message_id"`
|
SCNMessageID SCNMessageID `json:"scn_message_id"`
|
||||||
SenderUserID UserID `json:"sender_user_id"`
|
SenderUserID UserID `json:"sender_user_id"`
|
||||||
OwnerUserID UserID `json:"owner_user_id"`
|
OwnerUserID UserID `json:"owner_user_id"`
|
||||||
ChannelName string `json:"channel_name"`
|
ChannelInternalName string `json:"channel_internal_name"`
|
||||||
ChannelID ChannelID `json:"channel_id"`
|
ChannelID ChannelID `json:"channel_id"`
|
||||||
SenderName *string `json:"sender_name"`
|
SenderName *string `json:"sender_name"`
|
||||||
SenderIP string `json:"sender_ip"`
|
SenderIP string `json:"sender_ip"`
|
||||||
Timestamp string `json:"timestamp"`
|
Timestamp string `json:"timestamp"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Content *string `json:"content"`
|
Content *string `json:"content"`
|
||||||
Priority int `json:"priority"`
|
Priority int `json:"priority"`
|
||||||
UserMessageID *string `json:"usr_message_id"`
|
UserMessageID *string `json:"usr_message_id"`
|
||||||
Trimmed bool `json:"trimmed"`
|
Trimmed bool `json:"trimmed"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type MessageDB struct {
|
type MessageDB struct {
|
||||||
SCNMessageID SCNMessageID `db:"scn_message_id"`
|
SCNMessageID SCNMessageID `db:"scn_message_id"`
|
||||||
SenderUserID UserID `db:"sender_user_id"`
|
SenderUserID UserID `db:"sender_user_id"`
|
||||||
OwnerUserID UserID `db:"owner_user_id"`
|
OwnerUserID UserID `db:"owner_user_id"`
|
||||||
ChannelName string `db:"channel_name"`
|
ChannelInternalName string `db:"channel_internal_name"`
|
||||||
ChannelID ChannelID `db:"channel_id"`
|
ChannelID ChannelID `db:"channel_id"`
|
||||||
SenderName *string `db:"sender_name"`
|
SenderName *string `db:"sender_name"`
|
||||||
SenderIP string `db:"sender_ip"`
|
SenderIP string `db:"sender_ip"`
|
||||||
TimestampReal int64 `db:"timestamp_real"`
|
TimestampReal int64 `db:"timestamp_real"`
|
||||||
TimestampClient *int64 `db:"timestamp_client"`
|
TimestampClient *int64 `db:"timestamp_client"`
|
||||||
Title string `db:"title"`
|
Title string `db:"title"`
|
||||||
Content *string `db:"content"`
|
Content *string `db:"content"`
|
||||||
Priority int `db:"priority"`
|
Priority int `db:"priority"`
|
||||||
UserMessageID *string `db:"usr_message_id"`
|
UserMessageID *string `db:"usr_message_id"`
|
||||||
Deleted int `db:"deleted"`
|
Deleted int `db:"deleted"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m MessageDB) Model() Message {
|
func (m MessageDB) Model() Message {
|
||||||
return Message{
|
return Message{
|
||||||
SCNMessageID: m.SCNMessageID,
|
SCNMessageID: m.SCNMessageID,
|
||||||
SenderUserID: m.SenderUserID,
|
SenderUserID: m.SenderUserID,
|
||||||
OwnerUserID: m.OwnerUserID,
|
OwnerUserID: m.OwnerUserID,
|
||||||
ChannelName: m.ChannelName,
|
ChannelInternalName: m.ChannelInternalName,
|
||||||
ChannelID: m.ChannelID,
|
ChannelID: m.ChannelID,
|
||||||
SenderName: m.SenderName,
|
SenderName: m.SenderName,
|
||||||
SenderIP: m.SenderIP,
|
SenderIP: m.SenderIP,
|
||||||
TimestampReal: time.UnixMilli(m.TimestampReal),
|
TimestampReal: time.UnixMilli(m.TimestampReal),
|
||||||
TimestampClient: timeOptFromMilli(m.TimestampClient),
|
TimestampClient: timeOptFromMilli(m.TimestampClient),
|
||||||
Title: m.Title,
|
Title: m.Title,
|
||||||
Content: m.Content,
|
Content: m.Content,
|
||||||
Priority: m.Priority,
|
Priority: m.Priority,
|
||||||
UserMessageID: m.UserMessageID,
|
UserMessageID: m.UserMessageID,
|
||||||
Deleted: m.Deleted != 0,
|
Deleted: m.Deleted != 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,56 +8,56 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Subscription struct {
|
type Subscription struct {
|
||||||
SubscriptionID SubscriptionID
|
SubscriptionID SubscriptionID
|
||||||
SubscriberUserID UserID
|
SubscriberUserID UserID
|
||||||
ChannelOwnerUserID UserID
|
ChannelOwnerUserID UserID
|
||||||
ChannelID ChannelID
|
ChannelID ChannelID
|
||||||
ChannelName string
|
ChannelInternalName string
|
||||||
TimestampCreated time.Time
|
TimestampCreated time.Time
|
||||||
Confirmed bool
|
Confirmed bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s Subscription) JSON() SubscriptionJSON {
|
func (s Subscription) JSON() SubscriptionJSON {
|
||||||
return SubscriptionJSON{
|
return SubscriptionJSON{
|
||||||
SubscriptionID: s.SubscriptionID,
|
SubscriptionID: s.SubscriptionID,
|
||||||
SubscriberUserID: s.SubscriberUserID,
|
SubscriberUserID: s.SubscriberUserID,
|
||||||
ChannelOwnerUserID: s.ChannelOwnerUserID,
|
ChannelOwnerUserID: s.ChannelOwnerUserID,
|
||||||
ChannelID: s.ChannelID,
|
ChannelID: s.ChannelID,
|
||||||
ChannelName: s.ChannelName,
|
ChannelInternalName: s.ChannelInternalName,
|
||||||
TimestampCreated: s.TimestampCreated.Format(time.RFC3339Nano),
|
TimestampCreated: s.TimestampCreated.Format(time.RFC3339Nano),
|
||||||
Confirmed: s.Confirmed,
|
Confirmed: s.Confirmed,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type SubscriptionJSON struct {
|
type SubscriptionJSON struct {
|
||||||
SubscriptionID SubscriptionID `json:"subscription_id"`
|
SubscriptionID SubscriptionID `json:"subscription_id"`
|
||||||
SubscriberUserID UserID `json:"subscriber_user_id"`
|
SubscriberUserID UserID `json:"subscriber_user_id"`
|
||||||
ChannelOwnerUserID UserID `json:"channel_owner_user_id"`
|
ChannelOwnerUserID UserID `json:"channel_owner_user_id"`
|
||||||
ChannelID ChannelID `json:"channel_id"`
|
ChannelID ChannelID `json:"channel_id"`
|
||||||
ChannelName string `json:"channel_name"`
|
ChannelInternalName string `json:"channel_internal_name"`
|
||||||
TimestampCreated string `json:"timestamp_created"`
|
TimestampCreated string `json:"timestamp_created"`
|
||||||
Confirmed bool `json:"confirmed"`
|
Confirmed bool `json:"confirmed"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type SubscriptionDB struct {
|
type SubscriptionDB struct {
|
||||||
SubscriptionID SubscriptionID `db:"subscription_id"`
|
SubscriptionID SubscriptionID `db:"subscription_id"`
|
||||||
SubscriberUserID UserID `db:"subscriber_user_id"`
|
SubscriberUserID UserID `db:"subscriber_user_id"`
|
||||||
ChannelOwnerUserID UserID `db:"channel_owner_user_id"`
|
ChannelOwnerUserID UserID `db:"channel_owner_user_id"`
|
||||||
ChannelID ChannelID `db:"channel_id"`
|
ChannelID ChannelID `db:"channel_id"`
|
||||||
ChannelName string `db:"channel_name"`
|
ChannelInternalName string `db:"channel_internal_name"`
|
||||||
TimestampCreated int64 `db:"timestamp_created"`
|
TimestampCreated int64 `db:"timestamp_created"`
|
||||||
Confirmed int `db:"confirmed"`
|
Confirmed int `db:"confirmed"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s SubscriptionDB) Model() Subscription {
|
func (s SubscriptionDB) Model() Subscription {
|
||||||
return Subscription{
|
return Subscription{
|
||||||
SubscriptionID: s.SubscriptionID,
|
SubscriptionID: s.SubscriptionID,
|
||||||
SubscriberUserID: s.SubscriberUserID,
|
SubscriberUserID: s.SubscriberUserID,
|
||||||
ChannelOwnerUserID: s.ChannelOwnerUserID,
|
ChannelOwnerUserID: s.ChannelOwnerUserID,
|
||||||
ChannelID: s.ChannelID,
|
ChannelID: s.ChannelID,
|
||||||
ChannelName: s.ChannelName,
|
ChannelInternalName: s.ChannelInternalName,
|
||||||
TimestampCreated: time.UnixMilli(s.TimestampCreated),
|
TimestampCreated: time.UnixMilli(s.TimestampCreated),
|
||||||
Confirmed: s.Confirmed != 0,
|
Confirmed: s.Confirmed != 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1356,6 +1356,14 @@
|
|||||||
"schema": {
|
"schema": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Change the cahnnel display-name (only chnages to lowercase/uppercase are allowed - internal_name must stay the same)",
|
||||||
|
"name": "display_name",
|
||||||
|
"in": "body",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"responses": {
|
"responses": {
|
||||||
@ -2826,12 +2834,15 @@
|
|||||||
"channel_id": {
|
"channel_id": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
|
"display_name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"internal_name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"messages_sent": {
|
"messages_sent": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
"name": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"owner_user_id": {
|
"owner_user_id": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
@ -2912,7 +2923,7 @@
|
|||||||
"channel_id": {
|
"channel_id": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
"channel_name": {
|
"channel_internal_name": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"content": {
|
"content": {
|
||||||
@ -2956,7 +2967,7 @@
|
|||||||
"channel_id": {
|
"channel_id": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
"channel_name": {
|
"channel_internal_name": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"channel_owner_user_id": {
|
"channel_owner_user_id": {
|
||||||
|
@ -340,10 +340,12 @@ definitions:
|
|||||||
properties:
|
properties:
|
||||||
channel_id:
|
channel_id:
|
||||||
type: integer
|
type: integer
|
||||||
|
display_name:
|
||||||
|
type: string
|
||||||
|
internal_name:
|
||||||
|
type: string
|
||||||
messages_sent:
|
messages_sent:
|
||||||
type: integer
|
type: integer
|
||||||
name:
|
|
||||||
type: string
|
|
||||||
owner_user_id:
|
owner_user_id:
|
||||||
type: integer
|
type: integer
|
||||||
send_key:
|
send_key:
|
||||||
@ -397,7 +399,7 @@ definitions:
|
|||||||
properties:
|
properties:
|
||||||
channel_id:
|
channel_id:
|
||||||
type: integer
|
type: integer
|
||||||
channel_name:
|
channel_internal_name:
|
||||||
type: string
|
type: string
|
||||||
content:
|
content:
|
||||||
type: string
|
type: string
|
||||||
@ -426,7 +428,7 @@ definitions:
|
|||||||
properties:
|
properties:
|
||||||
channel_id:
|
channel_id:
|
||||||
type: integer
|
type: integer
|
||||||
channel_name:
|
channel_internal_name:
|
||||||
type: string
|
type: string
|
||||||
channel_owner_user_id:
|
channel_owner_user_id:
|
||||||
type: integer
|
type: integer
|
||||||
@ -1433,6 +1435,12 @@ paths:
|
|||||||
name: send_key
|
name: send_key
|
||||||
schema:
|
schema:
|
||||||
type: string
|
type: string
|
||||||
|
- description: Change the cahnnel display-name (only chnages to lowercase/uppercase
|
||||||
|
are allowed - internal_name must stay the same)
|
||||||
|
in: body
|
||||||
|
name: display_name
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: OK
|
description: OK
|
||||||
|
@ -29,7 +29,8 @@ func TestCreateChannel(t *testing.T) {
|
|||||||
|
|
||||||
{
|
{
|
||||||
clist := tt.RequestAuthGet[chanlist](t, admintok, baseUrl, fmt.Sprintf("/api/users/%d/channels", uid))
|
clist := tt.RequestAuthGet[chanlist](t, admintok, baseUrl, fmt.Sprintf("/api/users/%d/channels", uid))
|
||||||
tt.AssertMappedSet(t, "channels", []string{}, clist.Channels, "name")
|
tt.AssertMappedSet(t, "channels", []string{}, clist.Channels, "display_name")
|
||||||
|
tt.AssertMappedSet(t, "channels", []string{}, clist.Channels, "internal_name")
|
||||||
}
|
}
|
||||||
|
|
||||||
tt.RequestAuthPost[gin.H](t, admintok, baseUrl, fmt.Sprintf("/api/users/%d/channels", uid), gin.H{
|
tt.RequestAuthPost[gin.H](t, admintok, baseUrl, fmt.Sprintf("/api/users/%d/channels", uid), gin.H{
|
||||||
@ -39,7 +40,8 @@ func TestCreateChannel(t *testing.T) {
|
|||||||
{
|
{
|
||||||
clist := tt.RequestAuthGet[chanlist](t, admintok, baseUrl, fmt.Sprintf("/api/users/%d/channels", uid))
|
clist := tt.RequestAuthGet[chanlist](t, admintok, baseUrl, fmt.Sprintf("/api/users/%d/channels", uid))
|
||||||
tt.AssertEqual(t, "chan.len", 1, len(clist.Channels))
|
tt.AssertEqual(t, "chan.len", 1, len(clist.Channels))
|
||||||
tt.AssertMappedSet(t, "channels", []string{"test"}, clist.Channels, "name")
|
tt.AssertMappedSet(t, "channels", []string{"test"}, clist.Channels, "display_name")
|
||||||
|
tt.AssertMappedSet(t, "channels", []string{"test"}, clist.Channels, "internal_name")
|
||||||
}
|
}
|
||||||
|
|
||||||
tt.RequestAuthPost[gin.H](t, admintok, baseUrl, fmt.Sprintf("/api/users/%d/channels", uid), gin.H{
|
tt.RequestAuthPost[gin.H](t, admintok, baseUrl, fmt.Sprintf("/api/users/%d/channels", uid), gin.H{
|
||||||
@ -48,7 +50,8 @@ func TestCreateChannel(t *testing.T) {
|
|||||||
|
|
||||||
{
|
{
|
||||||
clist := tt.RequestAuthGet[chanlist](t, admintok, baseUrl, fmt.Sprintf("/api/users/%d/channels", uid))
|
clist := tt.RequestAuthGet[chanlist](t, admintok, baseUrl, fmt.Sprintf("/api/users/%d/channels", uid))
|
||||||
tt.AssertMappedSet(t, "channels", []string{"asdf", "test"}, clist.Channels, "name")
|
tt.AssertMappedSet(t, "channels", []string{"asdf", "test"}, clist.Channels, "display_name")
|
||||||
|
tt.AssertMappedSet(t, "channels", []string{"asdf", "test"}, clist.Channels, "internal_name")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,8 +93,9 @@ func TestChannelNameNormalization(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
chan0 := tt.RequestAuthGet[chanlist](t, admintok, baseUrl, fmt.Sprintf("/api/users/%d/channels", uid))
|
clist := tt.RequestAuthGet[chanlist](t, admintok, baseUrl, fmt.Sprintf("/api/users/%d/channels", uid))
|
||||||
tt.AssertEqual(t, "chan-count", 0, len(chan0.Channels))
|
tt.AssertMappedSet(t, "channels", []string{}, clist.Channels, "display_name")
|
||||||
|
tt.AssertMappedSet(t, "channels", []string{}, clist.Channels, "internal_name")
|
||||||
}
|
}
|
||||||
|
|
||||||
tt.RequestAuthPost[gin.H](t, admintok, baseUrl, fmt.Sprintf("/api/users/%d/channels", uid), gin.H{
|
tt.RequestAuthPost[gin.H](t, admintok, baseUrl, fmt.Sprintf("/api/users/%d/channels", uid), gin.H{
|
||||||
@ -100,8 +104,8 @@ func TestChannelNameNormalization(t *testing.T) {
|
|||||||
|
|
||||||
{
|
{
|
||||||
clist := tt.RequestAuthGet[chanlist](t, admintok, baseUrl, fmt.Sprintf("/api/users/%d/channels", uid))
|
clist := tt.RequestAuthGet[chanlist](t, admintok, baseUrl, fmt.Sprintf("/api/users/%d/channels", uid))
|
||||||
tt.AssertEqual(t, "chan.len", 1, len(clist.Channels))
|
tt.AssertMappedSet(t, "channels", []string{"tESt"}, clist.Channels, "display_name")
|
||||||
tt.AssertEqual(t, "chan.name", "test", clist.Channels[0]["name"])
|
tt.AssertMappedSet(t, "channels", []string{"test"}, clist.Channels, "internal_name")
|
||||||
}
|
}
|
||||||
|
|
||||||
tt.RequestAuthPostShouldFail(t, admintok, baseUrl, fmt.Sprintf("/api/users/%d/channels", uid), gin.H{
|
tt.RequestAuthPostShouldFail(t, admintok, baseUrl, fmt.Sprintf("/api/users/%d/channels", uid), gin.H{
|
||||||
@ -125,14 +129,25 @@ func TestChannelNameNormalization(t *testing.T) {
|
|||||||
}, 409, apierr.CHANNEL_ALREADY_EXISTS)
|
}, 409, apierr.CHANNEL_ALREADY_EXISTS)
|
||||||
|
|
||||||
tt.RequestAuthPostShouldFail(t, admintok, baseUrl, fmt.Sprintf("/api/users/%d/channels", uid), gin.H{
|
tt.RequestAuthPostShouldFail(t, admintok, baseUrl, fmt.Sprintf("/api/users/%d/channels", uid), gin.H{
|
||||||
"name": " T e s t ",
|
"name": "\rTeSt\n",
|
||||||
}, 409, apierr.CHANNEL_ALREADY_EXISTS)
|
}, 409, apierr.CHANNEL_ALREADY_EXISTS)
|
||||||
|
|
||||||
{
|
{
|
||||||
clist := tt.RequestAuthGet[chanlist](t, admintok, baseUrl, fmt.Sprintf("/api/users/%d/channels", uid))
|
clist := tt.RequestAuthGet[chanlist](t, admintok, baseUrl, fmt.Sprintf("/api/users/%d/channels", uid))
|
||||||
tt.AssertEqual(t, "chan.len", 1, len(clist.Channels))
|
tt.AssertMappedSet(t, "channels", []string{"tESt"}, clist.Channels, "display_name")
|
||||||
tt.AssertEqual(t, "chan.name", "test", clist.Channels[0]["name"])
|
tt.AssertMappedSet(t, "channels", []string{"test"}, clist.Channels, "internal_name")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tt.RequestAuthPost[gin.H](t, admintok, baseUrl, fmt.Sprintf("/api/users/%d/channels", uid), gin.H{
|
||||||
|
"name": " WeiRD_[\uF5FF]\\stUFf\r\n\t ",
|
||||||
|
})
|
||||||
|
|
||||||
|
{
|
||||||
|
clist := tt.RequestAuthGet[chanlist](t, admintok, baseUrl, fmt.Sprintf("/api/users/%d/channels", uid))
|
||||||
|
tt.AssertMappedSet(t, "channels", []string{"tESt", "WeiRD_[\uF5FF]\\stUFf"}, clist.Channels, "display_name")
|
||||||
|
tt.AssertMappedSet(t, "channels", []string{"test", "weird_[\uF5FF]\\stuff"}, clist.Channels, "internal_name")
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestListChannelsOwned(t *testing.T) {
|
func TestListChannelsOwned(t *testing.T) {
|
||||||
@ -147,24 +162,26 @@ func TestListChannelsOwned(t *testing.T) {
|
|||||||
|
|
||||||
testdata := map[int][]string{
|
testdata := map[int][]string{
|
||||||
0: {"main", "chattingchamber", "unicdhll", "promotions", "reminders"},
|
0: {"main", "chattingchamber", "unicdhll", "promotions", "reminders"},
|
||||||
1: {"promotions"},
|
1: {"main", "private"},
|
||||||
2: {},
|
2: {"main", "ü", "ö", "ä"},
|
||||||
3: {},
|
3: {"main", "innovations", "reminders"},
|
||||||
4: {},
|
4: {"main"},
|
||||||
5: {},
|
5: {"main", "test1", "test2", "test3", "test4", "test5"},
|
||||||
6: {},
|
6: {"main", "security", "lipsum"},
|
||||||
7: {},
|
7: {"main"},
|
||||||
8: {},
|
8: {"main"},
|
||||||
9: {},
|
9: {"main", "manual@chan"},
|
||||||
10: {},
|
10: {"main"},
|
||||||
11: {},
|
11: {"promotions"},
|
||||||
12: {},
|
12: {},
|
||||||
13: {},
|
13: {},
|
||||||
|
14: {"", "chan_self_subscribed", "chan_self_unsub"}, //TODO these two have the interesting cases
|
||||||
|
15: {"", "chan_other_nosub", "chan_other_request", "chan_other_request", "chan_other_accepted"}, //TODO these two have the interesting cases
|
||||||
}
|
}
|
||||||
|
|
||||||
for k, v := range testdata {
|
for k, v := range testdata {
|
||||||
r0 := tt.RequestAuthGet[chanlist](t, data.User[k].AdminKey, baseUrl, fmt.Sprintf("/api/users/%d/channels", data.User[k].UID))
|
r0 := tt.RequestAuthGet[chanlist](t, data.User[k].AdminKey, baseUrl, fmt.Sprintf("/api/users/%d/channels", data.User[k].UID))
|
||||||
tt.AssertMappedSet(t, fmt.Sprintf("%d->chanlist", k), v, r0.Channels, "name")
|
tt.AssertMappedSet(t, fmt.Sprintf("%d->chanlist", k), v, r0.Channels, "internal_name")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,7 +166,7 @@ func TestGetMessageFull(t *testing.T) {
|
|||||||
|
|
||||||
tt.AssertEqual(t, "msg.title", "Message_1", msgIn["title"])
|
tt.AssertEqual(t, "msg.title", "Message_1", msgIn["title"])
|
||||||
tt.AssertEqual(t, "msg.content", content, msgIn["content"])
|
tt.AssertEqual(t, "msg.content", content, msgIn["content"])
|
||||||
tt.AssertEqual(t, "msg.channel", "demo-channel-007", msgIn["channel_name"])
|
tt.AssertEqual(t, "msg.channel", "demo-channel-007", msgIn["channel_internal_name"])
|
||||||
tt.AssertEqual(t, "msg.msg_id", "580b5055-a9b5-4cee-b53c-28cf304d25b0", msgIn["usr_message_id"])
|
tt.AssertEqual(t, "msg.msg_id", "580b5055-a9b5-4cee-b53c-28cf304d25b0", msgIn["usr_message_id"])
|
||||||
tt.AssertStrRepEqual(t, "msg.priority", 0, msgIn["priority"])
|
tt.AssertStrRepEqual(t, "msg.priority", 0, msgIn["priority"])
|
||||||
tt.AssertEqual(t, "msg.sender_name", "unit-test-[TestGetMessageFull]", msgIn["sender_name"])
|
tt.AssertEqual(t, "msg.sender_name", "unit-test-[TestGetMessageFull]", msgIn["sender_name"])
|
||||||
|
@ -61,7 +61,7 @@ func TestSendSimpleMessageJSON(t *testing.T) {
|
|||||||
|
|
||||||
msg1Get := tt.RequestAuthGet[gin.H](t, admintok, baseUrl, "/api/messages/"+fmt.Sprintf("%v", msg1["scn_msg_id"]))
|
msg1Get := tt.RequestAuthGet[gin.H](t, admintok, baseUrl, "/api/messages/"+fmt.Sprintf("%v", msg1["scn_msg_id"]))
|
||||||
tt.AssertStrRepEqual(t, "msg.title", "HelloWorld_001", msg1Get["title"])
|
tt.AssertStrRepEqual(t, "msg.title", "HelloWorld_001", msg1Get["title"])
|
||||||
tt.AssertStrRepEqual(t, "msg.channel_name", "main", msg1Get["channel_name"])
|
tt.AssertStrRepEqual(t, "msg.channel_internal_name", "main", msg1Get["channel_internal_name"])
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSendSimpleMessageQuery(t *testing.T) {
|
func TestSendSimpleMessageQuery(t *testing.T) {
|
||||||
@ -97,7 +97,7 @@ func TestSendSimpleMessageQuery(t *testing.T) {
|
|||||||
|
|
||||||
msg1Get := tt.RequestAuthGet[gin.H](t, admintok, baseUrl, "/api/messages/"+fmt.Sprintf("%v", msg1["scn_msg_id"]))
|
msg1Get := tt.RequestAuthGet[gin.H](t, admintok, baseUrl, "/api/messages/"+fmt.Sprintf("%v", msg1["scn_msg_id"]))
|
||||||
tt.AssertStrRepEqual(t, "msg.title", "Hello World 2134", msg1Get["title"])
|
tt.AssertStrRepEqual(t, "msg.title", "Hello World 2134", msg1Get["title"])
|
||||||
tt.AssertStrRepEqual(t, "msg.channel_name", "main", msg1Get["channel_name"])
|
tt.AssertStrRepEqual(t, "msg.channel_internal_name", "main", msg1Get["channel_internal_name"])
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSendSimpleMessageForm(t *testing.T) {
|
func TestSendSimpleMessageForm(t *testing.T) {
|
||||||
@ -137,7 +137,7 @@ func TestSendSimpleMessageForm(t *testing.T) {
|
|||||||
|
|
||||||
msg1Get := tt.RequestAuthGet[gin.H](t, admintok, baseUrl, "/api/messages/"+fmt.Sprintf("%v", msg1["scn_msg_id"]))
|
msg1Get := tt.RequestAuthGet[gin.H](t, admintok, baseUrl, "/api/messages/"+fmt.Sprintf("%v", msg1["scn_msg_id"]))
|
||||||
tt.AssertStrRepEqual(t, "msg.title", "Hello World 9999 [$$$]", msg1Get["title"])
|
tt.AssertStrRepEqual(t, "msg.title", "Hello World 9999 [$$$]", msg1Get["title"])
|
||||||
tt.AssertStrRepEqual(t, "msg.channel_name", "main", msg1Get["channel_name"])
|
tt.AssertStrRepEqual(t, "msg.channel_internal_name", "main", msg1Get["channel_internal_name"])
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSendSimpleMessageFormAndQuery(t *testing.T) {
|
func TestSendSimpleMessageFormAndQuery(t *testing.T) {
|
||||||
@ -238,7 +238,7 @@ func TestSendSimpleMessageAlt1(t *testing.T) {
|
|||||||
|
|
||||||
msg1Get := tt.RequestAuthGet[gin.H](t, admintok, baseUrl, "/api/messages/"+fmt.Sprintf("%v", msg1["scn_msg_id"]))
|
msg1Get := tt.RequestAuthGet[gin.H](t, admintok, baseUrl, "/api/messages/"+fmt.Sprintf("%v", msg1["scn_msg_id"]))
|
||||||
tt.AssertStrRepEqual(t, "msg.title", "HelloWorld_001", msg1Get["title"])
|
tt.AssertStrRepEqual(t, "msg.title", "HelloWorld_001", msg1Get["title"])
|
||||||
tt.AssertStrRepEqual(t, "msg.channel_name", "main", msg1Get["channel_name"])
|
tt.AssertStrRepEqual(t, "msg.channel_internal_name", "main", msg1Get["channel_internal_name"])
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSendContentMessage(t *testing.T) {
|
func TestSendContentMessage(t *testing.T) {
|
||||||
@ -278,12 +278,12 @@ func TestSendContentMessage(t *testing.T) {
|
|||||||
tt.AssertEqual(t, "len(messages)", 1, len(msgList1.Messages))
|
tt.AssertEqual(t, "len(messages)", 1, len(msgList1.Messages))
|
||||||
tt.AssertStrRepEqual(t, "msg.title", "HelloWorld_042", msgList1.Messages[0]["title"])
|
tt.AssertStrRepEqual(t, "msg.title", "HelloWorld_042", msgList1.Messages[0]["title"])
|
||||||
tt.AssertStrRepEqual(t, "msg.content", "I am Content\nasdf", msgList1.Messages[0]["content"])
|
tt.AssertStrRepEqual(t, "msg.content", "I am Content\nasdf", msgList1.Messages[0]["content"])
|
||||||
tt.AssertStrRepEqual(t, "msg.channel_name", "main", msgList1.Messages[0]["channel_name"])
|
tt.AssertStrRepEqual(t, "msg.channel_internal_name", "main", msgList1.Messages[0]["channel_internal_name"])
|
||||||
|
|
||||||
msg1Get := tt.RequestAuthGet[gin.H](t, admintok, baseUrl, "/api/messages/"+fmt.Sprintf("%v", msg1["scn_msg_id"]))
|
msg1Get := tt.RequestAuthGet[gin.H](t, admintok, baseUrl, "/api/messages/"+fmt.Sprintf("%v", msg1["scn_msg_id"]))
|
||||||
tt.AssertStrRepEqual(t, "msg.title", "HelloWorld_042", msg1Get["title"])
|
tt.AssertStrRepEqual(t, "msg.title", "HelloWorld_042", msg1Get["title"])
|
||||||
tt.AssertStrRepEqual(t, "msg.content", "I am Content\nasdf", msg1Get["content"])
|
tt.AssertStrRepEqual(t, "msg.content", "I am Content\nasdf", msg1Get["content"])
|
||||||
tt.AssertStrRepEqual(t, "msg.channel_name", "main", msg1Get["channel_name"])
|
tt.AssertStrRepEqual(t, "msg.channel_internal_name", "main", msg1Get["channel_internal_name"])
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSendWithSendername(t *testing.T) {
|
func TestSendWithSendername(t *testing.T) {
|
||||||
@ -326,13 +326,13 @@ func TestSendWithSendername(t *testing.T) {
|
|||||||
tt.AssertStrRepEqual(t, "msg.title", "HelloWorld_xyz", msgList1.Messages[0]["title"])
|
tt.AssertStrRepEqual(t, "msg.title", "HelloWorld_xyz", msgList1.Messages[0]["title"])
|
||||||
tt.AssertStrRepEqual(t, "msg.content", "Unicode: 日本 - yäy\000\n\t\x00...", msgList1.Messages[0]["content"])
|
tt.AssertStrRepEqual(t, "msg.content", "Unicode: 日本 - yäy\000\n\t\x00...", msgList1.Messages[0]["content"])
|
||||||
tt.AssertStrRepEqual(t, "msg.sender_name", "localhorst", msgList1.Messages[0]["sender_name"])
|
tt.AssertStrRepEqual(t, "msg.sender_name", "localhorst", msgList1.Messages[0]["sender_name"])
|
||||||
tt.AssertStrRepEqual(t, "msg.channel_name", "main", msgList1.Messages[0]["channel_name"])
|
tt.AssertStrRepEqual(t, "msg.channel_internal_name", "main", msgList1.Messages[0]["channel_internal_name"])
|
||||||
|
|
||||||
msg1Get := tt.RequestAuthGet[gin.H](t, admintok, baseUrl, "/api/messages/"+fmt.Sprintf("%v", msg1["scn_msg_id"]))
|
msg1Get := tt.RequestAuthGet[gin.H](t, admintok, baseUrl, "/api/messages/"+fmt.Sprintf("%v", msg1["scn_msg_id"]))
|
||||||
tt.AssertStrRepEqual(t, "msg.title", "HelloWorld_xyz", msg1Get["title"])
|
tt.AssertStrRepEqual(t, "msg.title", "HelloWorld_xyz", msg1Get["title"])
|
||||||
tt.AssertStrRepEqual(t, "msg.content", "Unicode: 日本 - yäy\000\n\t\x00...", msg1Get["content"])
|
tt.AssertStrRepEqual(t, "msg.content", "Unicode: 日本 - yäy\000\n\t\x00...", msg1Get["content"])
|
||||||
tt.AssertStrRepEqual(t, "msg.sender_name", "localhorst", msg1Get["sender_name"])
|
tt.AssertStrRepEqual(t, "msg.sender_name", "localhorst", msg1Get["sender_name"])
|
||||||
tt.AssertStrRepEqual(t, "msg.channel_name", "main", msg1Get["channel_name"])
|
tt.AssertStrRepEqual(t, "msg.channel_internal_name", "main", msg1Get["channel_internal_name"])
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSendLongContent(t *testing.T) {
|
func TestSendLongContent(t *testing.T) {
|
||||||
@ -377,20 +377,20 @@ func TestSendLongContent(t *testing.T) {
|
|||||||
tt.AssertEqual(t, "len(messages)", 1, len(msgList1.Messages))
|
tt.AssertEqual(t, "len(messages)", 1, len(msgList1.Messages))
|
||||||
tt.AssertStrRepEqual(t, "msg.title", "HelloWorld_042", msgList1.Messages[0]["title"])
|
tt.AssertStrRepEqual(t, "msg.title", "HelloWorld_042", msgList1.Messages[0]["title"])
|
||||||
tt.AssertNotStrRepEqual(t, "msg.content", longContent, msgList1.Messages[0]["content"])
|
tt.AssertNotStrRepEqual(t, "msg.content", longContent, msgList1.Messages[0]["content"])
|
||||||
tt.AssertStrRepEqual(t, "msg.channel_name", "main", msgList1.Messages[0]["channel_name"])
|
tt.AssertStrRepEqual(t, "msg.channel_internal_name", "main", msgList1.Messages[0]["channel_internal_name"])
|
||||||
tt.AssertStrRepEqual(t, "msg.trimmmed", true, msgList1.Messages[0]["trimmed"])
|
tt.AssertStrRepEqual(t, "msg.trimmmed", true, msgList1.Messages[0]["trimmed"])
|
||||||
|
|
||||||
msgList2 := tt.RequestAuthGet[mglist](t, admintok, baseUrl, "/api/messages?trimmed=false")
|
msgList2 := tt.RequestAuthGet[mglist](t, admintok, baseUrl, "/api/messages?trimmed=false")
|
||||||
tt.AssertEqual(t, "len(messages)", 1, len(msgList2.Messages))
|
tt.AssertEqual(t, "len(messages)", 1, len(msgList2.Messages))
|
||||||
tt.AssertStrRepEqual(t, "msg.title", "HelloWorld_042", msgList2.Messages[0]["title"])
|
tt.AssertStrRepEqual(t, "msg.title", "HelloWorld_042", msgList2.Messages[0]["title"])
|
||||||
tt.AssertStrRepEqual(t, "msg.content", longContent, msgList2.Messages[0]["content"])
|
tt.AssertStrRepEqual(t, "msg.content", longContent, msgList2.Messages[0]["content"])
|
||||||
tt.AssertStrRepEqual(t, "msg.channel_name", "main", msgList2.Messages[0]["channel_name"])
|
tt.AssertStrRepEqual(t, "msg.channel_internal_name", "main", msgList2.Messages[0]["channel_internal_name"])
|
||||||
tt.AssertStrRepEqual(t, "msg.trimmmed", false, msgList2.Messages[0]["trimmed"])
|
tt.AssertStrRepEqual(t, "msg.trimmmed", false, msgList2.Messages[0]["trimmed"])
|
||||||
|
|
||||||
msg1Get := tt.RequestAuthGet[gin.H](t, admintok, baseUrl, "/api/messages/"+fmt.Sprintf("%v", msg1["scn_msg_id"]))
|
msg1Get := tt.RequestAuthGet[gin.H](t, admintok, baseUrl, "/api/messages/"+fmt.Sprintf("%v", msg1["scn_msg_id"]))
|
||||||
tt.AssertStrRepEqual(t, "msg.title", "HelloWorld_042", msg1Get["title"])
|
tt.AssertStrRepEqual(t, "msg.title", "HelloWorld_042", msg1Get["title"])
|
||||||
tt.AssertStrRepEqual(t, "msg.titcontentle", longContent, msg1Get["content"])
|
tt.AssertStrRepEqual(t, "msg.titcontentle", longContent, msg1Get["content"])
|
||||||
tt.AssertStrRepEqual(t, "msg.channel_name", "main", msg1Get["channel_name"])
|
tt.AssertStrRepEqual(t, "msg.channel_internal_name", "main", msg1Get["channel_internal_name"])
|
||||||
tt.AssertStrRepEqual(t, "msg.trimmmed", false, msg1Get["trimmed"])
|
tt.AssertStrRepEqual(t, "msg.trimmmed", false, msg1Get["trimmed"])
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -859,7 +859,7 @@ func TestSendWithTimestamp(t *testing.T) {
|
|||||||
tt.AssertEqual(t, "len(messages)", 1, len(msgList1.Messages))
|
tt.AssertEqual(t, "len(messages)", 1, len(msgList1.Messages))
|
||||||
tt.AssertStrRepEqual(t, "msg.title", "TTT", msgList1.Messages[0]["title"])
|
tt.AssertStrRepEqual(t, "msg.title", "TTT", msgList1.Messages[0]["title"])
|
||||||
tt.AssertStrRepEqual(t, "msg.content", nil, msgList1.Messages[0]["sender_name"])
|
tt.AssertStrRepEqual(t, "msg.content", nil, msgList1.Messages[0]["sender_name"])
|
||||||
tt.AssertStrRepEqual(t, "msg.channel_name", "main", msgList1.Messages[0]["channel_name"])
|
tt.AssertStrRepEqual(t, "msg.channel_internal_name", "main", msgList1.Messages[0]["channel_internal_name"])
|
||||||
|
|
||||||
tm1, err := time.Parse(time.RFC3339Nano, msgList1.Messages[0]["timestamp"].(string))
|
tm1, err := time.Parse(time.RFC3339Nano, msgList1.Messages[0]["timestamp"].(string))
|
||||||
tt.TestFailIfErr(t, err)
|
tt.TestFailIfErr(t, err)
|
||||||
@ -868,7 +868,7 @@ func TestSendWithTimestamp(t *testing.T) {
|
|||||||
msg1Get := tt.RequestAuthGet[gin.H](t, admintok, baseUrl, "/api/messages/"+fmt.Sprintf("%v", msg1["scn_msg_id"]))
|
msg1Get := tt.RequestAuthGet[gin.H](t, admintok, baseUrl, "/api/messages/"+fmt.Sprintf("%v", msg1["scn_msg_id"]))
|
||||||
tt.AssertStrRepEqual(t, "msg.title", "TTT", msg1Get["title"])
|
tt.AssertStrRepEqual(t, "msg.title", "TTT", msg1Get["title"])
|
||||||
tt.AssertStrRepEqual(t, "msg.content", nil, msg1Get["sender_name"])
|
tt.AssertStrRepEqual(t, "msg.content", nil, msg1Get["sender_name"])
|
||||||
tt.AssertStrRepEqual(t, "msg.channel_name", "main", msg1Get["channel_name"])
|
tt.AssertStrRepEqual(t, "msg.channel_internal_name", "main", msg1Get["channel_internal_name"])
|
||||||
|
|
||||||
tmg1, err := time.Parse(time.RFC3339Nano, msg1Get["timestamp"].(string))
|
tmg1, err := time.Parse(time.RFC3339Nano, msg1Get["timestamp"].(string))
|
||||||
tt.TestFailIfErr(t, err)
|
tt.TestFailIfErr(t, err)
|
||||||
@ -1022,7 +1022,7 @@ func TestSendCompat(t *testing.T) {
|
|||||||
|
|
||||||
msg1Get := tt.RequestAuthGet[gin.H](t, admintok, baseUrl, "/api/messages/"+fmt.Sprintf("%v", msg1["scn_msg_id"]))
|
msg1Get := tt.RequestAuthGet[gin.H](t, admintok, baseUrl, "/api/messages/"+fmt.Sprintf("%v", msg1["scn_msg_id"]))
|
||||||
tt.AssertStrRepEqual(t, "msg.title", "HelloWorld_001", msg1Get["title"])
|
tt.AssertStrRepEqual(t, "msg.title", "HelloWorld_001", msg1Get["title"])
|
||||||
tt.AssertStrRepEqual(t, "msg.channel_name", "main", msg1Get["channel_name"])
|
tt.AssertStrRepEqual(t, "msg.channel_internal_name", "main", msg1Get["channel_internal_name"])
|
||||||
|
|
||||||
msg2 := tt.RequestPost[gin.H](t, baseUrl, fmt.Sprintf("/send.php?user_key=%s&user_id=%d&title=%s", sendtok, uid, "HelloWorld_002"), nil)
|
msg2 := tt.RequestPost[gin.H](t, baseUrl, fmt.Sprintf("/send.php?user_key=%s&user_id=%d&title=%s", sendtok, uid, "HelloWorld_002"), nil)
|
||||||
|
|
||||||
@ -1098,8 +1098,8 @@ func TestSendToNewChannel(t *testing.T) {
|
|||||||
|
|
||||||
{
|
{
|
||||||
clist := tt.RequestAuthGet[chanlist](t, admintok, baseUrl, fmt.Sprintf("/api/users/%d/channels", uid))
|
clist := tt.RequestAuthGet[chanlist](t, admintok, baseUrl, fmt.Sprintf("/api/users/%d/channels", uid))
|
||||||
tt.AssertEqual(t, "chan.len", 1, len(clist.Channels))
|
tt.AssertMappedSet(t, "channels", []string{"main"}, clist.Channels, "display_name")
|
||||||
tt.AssertEqual(t, "chan.name", "main", clist.Channels[0]["name"])
|
tt.AssertMappedSet(t, "channels", []string{"main"}, clist.Channels, "internal_name")
|
||||||
}
|
}
|
||||||
|
|
||||||
tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{
|
tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{
|
||||||
@ -1112,8 +1112,8 @@ func TestSendToNewChannel(t *testing.T) {
|
|||||||
|
|
||||||
{
|
{
|
||||||
clist := tt.RequestAuthGet[chanlist](t, admintok, baseUrl, fmt.Sprintf("/api/users/%d/channels", uid))
|
clist := tt.RequestAuthGet[chanlist](t, admintok, baseUrl, fmt.Sprintf("/api/users/%d/channels", uid))
|
||||||
tt.AssertEqual(t, "chan.len", 1, len(clist.Channels))
|
tt.AssertMappedSet(t, "channels", []string{"main"}, clist.Channels, "display_name")
|
||||||
tt.AssertEqual(t, "chan.name", "main", clist.Channels[0]["name"])
|
tt.AssertMappedSet(t, "channels", []string{"main"}, clist.Channels, "internal_name")
|
||||||
}
|
}
|
||||||
|
|
||||||
tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{
|
tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{
|
||||||
@ -1126,9 +1126,8 @@ func TestSendToNewChannel(t *testing.T) {
|
|||||||
|
|
||||||
{
|
{
|
||||||
clist := tt.RequestAuthGet[chanlist](t, admintok, baseUrl, fmt.Sprintf("/api/users/%d/channels", uid))
|
clist := tt.RequestAuthGet[chanlist](t, admintok, baseUrl, fmt.Sprintf("/api/users/%d/channels", uid))
|
||||||
tt.AssertEqual(t, "chan-count", 2, len(clist.Channels))
|
tt.AssertMappedSet(t, "channels", []string{"main", "test"}, clist.Channels, "display_name")
|
||||||
tt.AssertArrAny(t, "chan.has('main')", clist.Channels, func(msg gin.H) bool { return msg["name"].(string) == "main" })
|
tt.AssertMappedSet(t, "channels", []string{"main", "test"}, clist.Channels, "internal_name")
|
||||||
tt.AssertArrAny(t, "chan.has('test')", clist.Channels, func(msg gin.H) bool { return msg["name"].(string) == "test" })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{
|
tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{
|
||||||
@ -1140,9 +1139,8 @@ func TestSendToNewChannel(t *testing.T) {
|
|||||||
|
|
||||||
{
|
{
|
||||||
clist := tt.RequestAuthGet[chanlist](t, admintok, baseUrl, fmt.Sprintf("/api/users/%d/channels", uid))
|
clist := tt.RequestAuthGet[chanlist](t, admintok, baseUrl, fmt.Sprintf("/api/users/%d/channels", uid))
|
||||||
tt.AssertEqual(t, "chan-count", 2, len(clist.Channels))
|
tt.AssertMappedSet(t, "channels", []string{"main", "test"}, clist.Channels, "display_name")
|
||||||
tt.AssertArrAny(t, "chan.has('main')", clist.Channels, func(msg gin.H) bool { return msg["name"].(string) == "main" })
|
tt.AssertMappedSet(t, "channels", []string{"main", "test"}, clist.Channels, "internal_name")
|
||||||
tt.AssertArrAny(t, "chan.has('test')", clist.Channels, func(msg gin.H) bool { return msg["name"].(string) == "test" })
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1166,8 +1164,9 @@ func TestSendToManualChannel(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
chan0 := tt.RequestAuthGet[chanlist](t, admintok, baseUrl, fmt.Sprintf("/api/users/%d/channels", uid))
|
clist := tt.RequestAuthGet[chanlist](t, admintok, baseUrl, fmt.Sprintf("/api/users/%d/channels", uid))
|
||||||
tt.AssertEqual(t, "chan-count", 0, len(chan0.Channels))
|
tt.AssertMappedSet(t, "channels", []string{}, clist.Channels, "display_name")
|
||||||
|
tt.AssertMappedSet(t, "channels", []string{}, clist.Channels, "internal_name")
|
||||||
}
|
}
|
||||||
|
|
||||||
tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{
|
tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{
|
||||||
@ -1178,8 +1177,8 @@ func TestSendToManualChannel(t *testing.T) {
|
|||||||
|
|
||||||
{
|
{
|
||||||
clist := tt.RequestAuthGet[chanlist](t, admintok, baseUrl, fmt.Sprintf("/api/users/%d/channels", uid))
|
clist := tt.RequestAuthGet[chanlist](t, admintok, baseUrl, fmt.Sprintf("/api/users/%d/channels", uid))
|
||||||
tt.AssertEqual(t, "chan.len", 1, len(clist.Channels))
|
tt.AssertMappedSet(t, "channels", []string{"main"}, clist.Channels, "display_name")
|
||||||
tt.AssertEqual(t, "chan.name", "main", clist.Channels[0]["name"])
|
tt.AssertMappedSet(t, "channels", []string{"main"}, clist.Channels, "internal_name")
|
||||||
}
|
}
|
||||||
|
|
||||||
tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{
|
tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{
|
||||||
@ -1193,7 +1192,8 @@ func TestSendToManualChannel(t *testing.T) {
|
|||||||
{
|
{
|
||||||
clist := tt.RequestAuthGet[chanlist](t, admintok, baseUrl, fmt.Sprintf("/api/users/%d/channels", uid))
|
clist := tt.RequestAuthGet[chanlist](t, admintok, baseUrl, fmt.Sprintf("/api/users/%d/channels", uid))
|
||||||
tt.AssertEqual(t, "chan.len", 1, len(clist.Channels))
|
tt.AssertEqual(t, "chan.len", 1, len(clist.Channels))
|
||||||
tt.AssertEqual(t, "chan.name", "main", clist.Channels[0]["name"])
|
tt.AssertEqual(t, "chan.internal_name", "main", clist.Channels[0]["internal_name"])
|
||||||
|
tt.AssertEqual(t, "chan.display_name", "main", clist.Channels[0]["display_name"])
|
||||||
}
|
}
|
||||||
|
|
||||||
tt.RequestAuthPost[gin.H](t, admintok, baseUrl, fmt.Sprintf("/api/users/%d/channels", uid), gin.H{
|
tt.RequestAuthPost[gin.H](t, admintok, baseUrl, fmt.Sprintf("/api/users/%d/channels", uid), gin.H{
|
||||||
@ -1202,9 +1202,8 @@ func TestSendToManualChannel(t *testing.T) {
|
|||||||
|
|
||||||
{
|
{
|
||||||
clist := tt.RequestAuthGet[chanlist](t, admintok, baseUrl, fmt.Sprintf("/api/users/%d/channels", uid))
|
clist := tt.RequestAuthGet[chanlist](t, admintok, baseUrl, fmt.Sprintf("/api/users/%d/channels", uid))
|
||||||
tt.AssertEqual(t, "chan-count", 2, len(clist.Channels))
|
tt.AssertMappedSet(t, "channels", []string{"main", "test"}, clist.Channels, "display_name")
|
||||||
tt.AssertArrAny(t, "chan.has('main')", clist.Channels, func(msg gin.H) bool { return msg["name"].(string) == "main" })
|
tt.AssertMappedSet(t, "channels", []string{"main", "test"}, clist.Channels, "internal_name")
|
||||||
tt.AssertArrAny(t, "chan.has('test')", clist.Channels, func(msg gin.H) bool { return msg["name"].(string) == "test" })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{
|
tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{
|
||||||
@ -1217,9 +1216,8 @@ func TestSendToManualChannel(t *testing.T) {
|
|||||||
|
|
||||||
{
|
{
|
||||||
clist := tt.RequestAuthGet[chanlist](t, admintok, baseUrl, fmt.Sprintf("/api/users/%d/channels", uid))
|
clist := tt.RequestAuthGet[chanlist](t, admintok, baseUrl, fmt.Sprintf("/api/users/%d/channels", uid))
|
||||||
tt.AssertEqual(t, "chan-count", 2, len(clist.Channels))
|
tt.AssertMappedSet(t, "channels", []string{"main", "test"}, clist.Channels, "display_name")
|
||||||
tt.AssertArrAny(t, "chan.has('main')", clist.Channels, func(msg gin.H) bool { return msg["name"].(string) == "main" })
|
tt.AssertMappedSet(t, "channels", []string{"main", "test"}, clist.Channels, "internal_name")
|
||||||
tt.AssertArrAny(t, "chan.has('test')", clist.Channels, func(msg gin.H) bool { return msg["name"].(string) == "test" })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{
|
tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{
|
||||||
@ -1231,9 +1229,8 @@ func TestSendToManualChannel(t *testing.T) {
|
|||||||
|
|
||||||
{
|
{
|
||||||
clist := tt.RequestAuthGet[chanlist](t, admintok, baseUrl, fmt.Sprintf("/api/users/%d/channels", uid))
|
clist := tt.RequestAuthGet[chanlist](t, admintok, baseUrl, fmt.Sprintf("/api/users/%d/channels", uid))
|
||||||
tt.AssertEqual(t, "chan-count", 2, len(clist.Channels))
|
tt.AssertMappedSet(t, "channels", []string{"main", "test"}, clist.Channels, "display_name")
|
||||||
tt.AssertArrAny(t, "chan.has('main')", clist.Channels, func(msg gin.H) bool { return msg["name"].(string) == "main" })
|
tt.AssertMappedSet(t, "channels", []string{"main", "test"}, clist.Channels, "internal_name")
|
||||||
tt.AssertArrAny(t, "chan.has('test')", clist.Channels, func(msg gin.H) bool { return msg["name"].(string) == "test" })
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,7 +203,14 @@ func AssertMultiNonEmpty(t *testing.T, key string, args ...any) {
|
|||||||
|
|
||||||
func AssertMappedSet[T langext.OrderedConstraint](t *testing.T, key string, expected []T, values []gin.H, objkey string) {
|
func AssertMappedSet[T langext.OrderedConstraint](t *testing.T, key string, expected []T, values []gin.H, objkey string) {
|
||||||
|
|
||||||
actual := langext.ArrMap(values, func(v gin.H) T { return v[objkey].(T) })
|
actual := make([]T, 0)
|
||||||
|
for idx, vv := range values {
|
||||||
|
if tv, ok := vv[objkey].(T); ok {
|
||||||
|
actual = append(actual, tv)
|
||||||
|
} else {
|
||||||
|
TestFailFmt(t, "[%s]->[%d] is wrong type (expected: %T, actual: %T)", key, idx, *new(T), vv)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
langext.Sort(actual)
|
langext.Sort(actual)
|
||||||
langext.Sort(expected)
|
langext.Sort(expected)
|
||||||
|
@ -86,8 +86,10 @@ var userExamples = []userex{
|
|||||||
{9, true, "UniqueUnicorn", "Galaxy Quest", "2023.1", "ANDROID", "FCM_TOK_EX_010", ""},
|
{9, true, "UniqueUnicorn", "Galaxy Quest", "2023.1", "ANDROID", "FCM_TOK_EX_010", ""},
|
||||||
{10, false, "", "", "", "", "", ""},
|
{10, false, "", "", "", "", "", ""},
|
||||||
{11, false, "", "", "", "", "", "ANDROID|v2|PURCHASED:PRO_TOK_002"},
|
{11, false, "", "", "", "", "", "ANDROID|v2|PURCHASED:PRO_TOK_002"},
|
||||||
{12, true, "ChanTester1", "StarfireXX", "1.x", "IOS", "FCM_TOK_EX_012", ""},
|
{12, true, "NoMessageUser", "Ocean Explorer", "737edc01", "IOS", "FCM_TOK_EX_014", ""},
|
||||||
{13, true, "ChanTester2", "StarfireXX", "1.x", "IOS", "FCM_TOK_EX_013", ""},
|
{13, false, "EmptyUser", "", "", "", "", ""},
|
||||||
|
{14, true, "ChanTester1", "StarfireXX", "1.x", "IOS", "FCM_TOK_EX_012", ""},
|
||||||
|
{15, true, "ChanTester2", "StarfireXX", "1.x", "IOS", "FCM_TOK_EX_013", ""},
|
||||||
}
|
}
|
||||||
|
|
||||||
var clientExamples = []clientex{
|
var clientExamples = []clientex{
|
||||||
@ -267,14 +269,14 @@ var messageExamples = []msgex{
|
|||||||
{11, "Promotions", "", PX, AKEY, "Join Our VIP Club and Enjoy Exclusive Benefits", "Sign up for our VIP club and enjoy exclusive benefits like early access to sales, special offers, and personalized service. Don't miss out on this exclusive opportunity.", timeext.FromHours(2.32)},
|
{11, "Promotions", "", PX, AKEY, "Join Our VIP Club and Enjoy Exclusive Benefits", "Sign up for our VIP club and enjoy exclusive benefits like early access to sales, special offers, and personalized service. Don't miss out on this exclusive opportunity.", timeext.FromHours(2.32)},
|
||||||
{11, "Promotions", "", P2, SKEY, "Summer Clearance: Save Up to 75% on Your Favorite Products", "It's time for our annual summer clearance sale! Save up to 75% on your favorite products, from clothing and accessories to home decor and more.", timeext.FromHours(1.87)},
|
{11, "Promotions", "", P2, SKEY, "Summer Clearance: Save Up to 75% on Your Favorite Products", "It's time for our annual summer clearance sale! Save up to 75% on your favorite products, from clothing and accessories to home decor and more.", timeext.FromHours(1.87)},
|
||||||
|
|
||||||
{12, "", "", P0, SKEY, "New Product Launch", "We are excited to announce the launch of our new product, the XYZ widget", 0},
|
{14, "", "", P0, SKEY, "New Product Launch", "We are excited to announce the launch of our new product, the XYZ widget", 0},
|
||||||
{12, "chan_self_subscribed", "", P0, SKEY, "Important Update", "We have released a critical update", 0},
|
{14, "chan_self_subscribed", "", P0, SKEY, "Important Update", "We have released a critical update", 0},
|
||||||
{12, "chan_self_unsub", "", P0, SKEY, "Reminder: Upcoming Maintenance", "", 0},
|
{14, "chan_self_unsub", "", P0, SKEY, "Reminder: Upcoming Maintenance", "", 0},
|
||||||
|
|
||||||
{13, "", "", P0, SKEY, "New Feature Available", "ability to schedule appointments", 0},
|
{15, "", "", P0, SKEY, "New Feature Available", "ability to schedule appointments", 0},
|
||||||
{13, "chan_other_nosub", "", P0, SKEY, "Account Suspended", "Please contact us", 0},
|
{15, "chan_other_nosub", "", P0, SKEY, "Account Suspended", "Please contact us", 0},
|
||||||
{13, "chan_other_request", "", P0, SKEY, "Invitation to Beta Test", "", 0},
|
{15, "chan_other_request", "", P0, SKEY, "Invitation to Beta Test", "", 0},
|
||||||
{13, "chan_other_accepted", "", P0, SKEY, "New Blog Post", "Congratulations on your promotion! We are proud", 0},
|
{15, "chan_other_accepted", "", P0, SKEY, "New Blog Post", "Congratulations on your promotion! We are proud", 0},
|
||||||
}
|
}
|
||||||
|
|
||||||
type DefData struct {
|
type DefData struct {
|
||||||
@ -373,6 +375,12 @@ func InitDefaultData(t *testing.T, ws *logic.Application) DefData {
|
|||||||
RequestPost[gin.H](t, baseUrl, "/", body)
|
RequestPost[gin.H](t, baseUrl, "/", body)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// create manual channels
|
||||||
|
|
||||||
|
{
|
||||||
|
RequestAuthPost[Void](t, users[9].AdminKey, baseUrl, fmt.Sprintf("/api/users/%d/channels", users[9].UID), gin.H{"name": "manual@chan"})
|
||||||
|
}
|
||||||
|
|
||||||
// Sub/Unsub for Users 12+13
|
// Sub/Unsub for Users 12+13
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -163,10 +163,10 @@ func RequestAny[TResult any](t *testing.T, akey string, method string, baseURL s
|
|||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
func RequestAuthAnyShouldFail(t *testing.T, akey string, method string, baseURL string, urlSuffix string, body any, statusCode int, errcode apierr.APIError) {
|
func RequestAuthAnyShouldFail(t *testing.T, akey string, method string, baseURL string, urlSuffix string, body any, expectedStatusCode int, errcode apierr.APIError) {
|
||||||
client := http.Client{}
|
client := http.Client{}
|
||||||
|
|
||||||
TPrintf("[-> REQUEST] (%s) %s%s [%s] (should-fail with %d/%d)\n", method, baseURL, urlSuffix, langext.Conditional(akey == "", "NO AUTH", "AUTH"), statusCode, errcode)
|
TPrintf("[-> REQUEST] (%s) %s%s [%s] (should-fail with %d/%d)\n", method, baseURL, urlSuffix, langext.Conditional(akey == "", "NO AUTH", "AUTH"), expectedStatusCode, errcode)
|
||||||
|
|
||||||
bytesbody := make([]byte, 0)
|
bytesbody := make([]byte, 0)
|
||||||
contentType := ""
|
contentType := ""
|
||||||
@ -224,17 +224,17 @@ func RequestAuthAnyShouldFail(t *testing.T, akey string, method string, baseURL
|
|||||||
TPrintln("")
|
TPrintln("")
|
||||||
TPrintf("---------------- RESPONSE (%d) ----------------\n", resp.StatusCode)
|
TPrintf("---------------- RESPONSE (%d) ----------------\n", resp.StatusCode)
|
||||||
TPrintln(langext.TryPrettyPrintJson(string(respBodyBin)))
|
TPrintln(langext.TryPrettyPrintJson(string(respBodyBin)))
|
||||||
if (statusCode != 0 && resp.StatusCode != statusCode) || (statusCode == 0 && resp.StatusCode == 200) {
|
if (expectedStatusCode != 0 && resp.StatusCode != expectedStatusCode) || (expectedStatusCode == 0 && resp.StatusCode == 200) {
|
||||||
TryPrintTraceObj("---------------- -------- ----------------", respBodyBin, "")
|
TryPrintTraceObj("---------------- -------- ----------------", respBodyBin, "")
|
||||||
}
|
}
|
||||||
TPrintln("---------------- -------- ----------------")
|
TPrintln("---------------- -------- ----------------")
|
||||||
TPrintln("")
|
TPrintln("")
|
||||||
|
|
||||||
if statusCode != 0 && resp.StatusCode != statusCode {
|
if expectedStatusCode != 0 && resp.StatusCode != expectedStatusCode {
|
||||||
TestFailFmt(t, "Statuscode != %d (expected failure)", statusCode)
|
TestFailFmt(t, "Statuscode != %d (expected failure, but got %d)", expectedStatusCode, resp.StatusCode)
|
||||||
}
|
}
|
||||||
if statusCode == 0 && resp.StatusCode == 200 {
|
if expectedStatusCode == 0 && resp.StatusCode == 200 {
|
||||||
TestFailFmt(t, "Statuscode == %d (expected failure)", resp.StatusCode)
|
TestFailFmt(t, "Statuscode == %d (expected any failure, but got %d)", resp.StatusCode, resp.StatusCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
var data gin.H
|
var data gin.H
|
||||||
|
Loading…
Reference in New Issue
Block a user