diff --git a/scnserver/api/handler/compat.go b/scnserver/api/handler/compat.go index 2921917..dfc6733 100644 --- a/scnserver/api/handler/compat.go +++ b/scnserver/api/handler/compat.go @@ -1,6 +1,11 @@ package handler import ( + "database/sql" + "errors" + "fmt" + "net/http" + "blackforestbytes.com/simplecloudnotifier/api/apierr" hl "blackforestbytes.com/simplecloudnotifier/api/apihighlight" "blackforestbytes.com/simplecloudnotifier/api/ginresp" @@ -8,13 +13,9 @@ import ( primarydb "blackforestbytes.com/simplecloudnotifier/db/impl/primary" "blackforestbytes.com/simplecloudnotifier/logic" "blackforestbytes.com/simplecloudnotifier/models" - "database/sql" - "errors" - "fmt" "git.blackforestbytes.com/BlackForestBytes/goext/dataext" "git.blackforestbytes.com/BlackForestBytes/goext/ginext" "git.blackforestbytes.com/BlackForestBytes/goext/langext" - "net/http" ) type CompatHandler struct { @@ -90,7 +91,7 @@ func (h CompatHandler) SendMessage(pctx ginext.PreContext) ginext.HTTPResponse { return ginresp.SendAPIError(g, 400, apierr.USER_NOT_FOUND, hl.USER_ID, "User not found (compat)", nil) } - okResp, errResp := h.app.SendMessage(g, ctx, langext.Ptr(models.UserID(*newid)), data.UserKey, nil, data.Title, data.Content, data.Priority, data.UserMessageID, data.SendTimestamp, nil) + okResp, errResp := h.app.SendMessage(g, ctx, data.UserKey, nil, data.Title, data.Content, data.Priority, data.UserMessageID, data.SendTimestamp, nil) if errResp != nil { return *errResp } else { diff --git a/scnserver/api/handler/external.go b/scnserver/api/handler/external.go index 0afece2..aece95b 100644 --- a/scnserver/api/handler/external.go +++ b/scnserver/api/handler/external.go @@ -1,16 +1,17 @@ package handler import ( + "fmt" + "net/http" + "time" + "blackforestbytes.com/simplecloudnotifier/api/apierr" "blackforestbytes.com/simplecloudnotifier/api/ginresp" primarydb "blackforestbytes.com/simplecloudnotifier/db/impl/primary" "blackforestbytes.com/simplecloudnotifier/logic" "blackforestbytes.com/simplecloudnotifier/models" - "fmt" "git.blackforestbytes.com/BlackForestBytes/goext/ginext" "git.blackforestbytes.com/BlackForestBytes/goext/langext" - "net/http" - "time" ) type ExternalHandler struct { @@ -36,22 +37,21 @@ func NewExternalHandler(app *logic.Application) ExternalHandler { // // @Success 200 {object} handler.UptimeKuma.response // @Failure 400 {object} ginresp.apiError -// @Failure 401 {object} ginresp.apiError "The user_id was not found or the user_key is wrong" +// @Failure 401 {object} ginresp.apiError "The user_key is wrong" // @Failure 403 {object} ginresp.apiError "The user has exceeded its daily quota - wait 24 hours or upgrade your account" // @Failure 500 {object} ginresp.apiError "An internal server error occurred - try again later" // // @Router /external/v1/uptime-kuma [POST] func (h ExternalHandler) UptimeKuma(pctx ginext.PreContext) ginext.HTTPResponse { type query struct { - UserID *models.UserID `form:"user_id" example:"7725"` - KeyToken *string `form:"key" example:"P3TNH8mvv14fm"` - Channel *string `form:"channel"` - ChannelUp *string `form:"channel_up"` - ChannelDown *string `form:"channel_down"` - Priority *int `form:"priority"` - PriorityUp *int `form:"priority_up"` - PriorityDown *int `form:"priority_down"` - SenderName *string `form:"senderName"` + KeyToken *string `form:"key" example:"P3TNH8mvv14fm"` + Channel *string `form:"channel"` + ChannelUp *string `form:"channel_up"` + ChannelDown *string `form:"channel_down"` + Priority *int `form:"priority"` + PriorityUp *int `form:"priority_up"` + PriorityDown *int `form:"priority_down"` + SenderName *string `form:"senderName"` } type body struct { Heartbeat *struct { @@ -125,7 +125,7 @@ func (h ExternalHandler) UptimeKuma(pctx ginext.PreContext) ginext.HTTPResponse priority = q.PriorityDown } - okResp, errResp := h.app.SendMessage(g, ctx, q.UserID, q.KeyToken, channel, &title, &content, priority, nil, timestamp, q.SenderName) + okResp, errResp := h.app.SendMessage(g, ctx, q.KeyToken, channel, &title, &content, priority, nil, timestamp, q.SenderName) if errResp != nil { return *errResp } diff --git a/scnserver/api/handler/message.go b/scnserver/api/handler/message.go index 4660027..c4d669d 100644 --- a/scnserver/api/handler/message.go +++ b/scnserver/api/handler/message.go @@ -1,6 +1,8 @@ package handler import ( + "net/http" + "blackforestbytes.com/simplecloudnotifier/api/apierr" primarydb "blackforestbytes.com/simplecloudnotifier/db/impl/primary" "blackforestbytes.com/simplecloudnotifier/logic" @@ -8,7 +10,6 @@ import ( "git.blackforestbytes.com/BlackForestBytes/goext/dataext" "git.blackforestbytes.com/BlackForestBytes/goext/ginext" "git.blackforestbytes.com/BlackForestBytes/goext/langext" - "net/http" ) type SendMessageResponse struct { @@ -42,7 +43,7 @@ func NewMessageHandler(app *logic.Application) MessageHandler { // // @Success 200 {object} handler.SendMessage.response // @Failure 400 {object} ginresp.apiError -// @Failure 401 {object} ginresp.apiError "The user_id was not found or the user_key is wrong" +// @Failure 401 {object} ginresp.apiError "The user_key is wrong" // @Failure 403 {object} ginresp.apiError "The user has exceeded its daily quota - wait 24 hours or upgrade your account" // @Failure 500 {object} ginresp.apiError "An internal server error occurred - try again later" // @@ -50,15 +51,14 @@ func NewMessageHandler(app *logic.Application) MessageHandler { // @Router /send [POST] func (h MessageHandler) SendMessage(pctx ginext.PreContext) ginext.HTTPResponse { type combined struct { - UserID *models.UserID `json:"user_id" form:"user_id" example:"7725" ` - KeyToken *string `json:"key" form:"key" example:"P3TNH8mvv14fm" ` - Channel *string `json:"channel" form:"channel" example:"test" ` - Title *string `json:"title" form:"title" example:"Hello World" ` - Content *string `json:"content" form:"content" example:"This is a message" ` - Priority *int `json:"priority" form:"priority" example:"1" enums:"0,1,2" ` - UserMessageID *string `json:"msg_id" form:"msg_id" example:"db8b0e6a-a08c-4646" ` - SendTimestamp *float64 `json:"timestamp" form:"timestamp" example:"1669824037" ` - SenderName *string `json:"sender_name" form:"sender_name" example:"example-server" ` + KeyToken *string `json:"key" form:"key" example:"P3TNH8mvv14fm" ` + Channel *string `json:"channel" form:"channel" example:"test" ` + Title *string `json:"title" form:"title" example:"Hello World" ` + Content *string `json:"content" form:"content" example:"This is a message" ` + Priority *int `json:"priority" form:"priority" example:"1" enums:"0,1,2" ` + UserMessageID *string `json:"msg_id" form:"msg_id" example:"db8b0e6a-a08c-4646" ` + SendTimestamp *float64 `json:"timestamp" form:"timestamp" example:"1669824037" ` + SenderName *string `json:"sender_name" form:"sender_name" example:"example-server" ` } type response struct { @@ -88,7 +88,7 @@ func (h MessageHandler) SendMessage(pctx ginext.PreContext) ginext.HTTPResponse // query has highest prio, then form, then json data := dataext.ObjectMerge(dataext.ObjectMerge(b, f), q) - okResp, errResp := h.app.SendMessage(g, ctx, data.UserID, data.KeyToken, data.Channel, data.Title, data.Content, data.Priority, data.UserMessageID, data.SendTimestamp, data.SenderName) + okResp, errResp := h.app.SendMessage(g, ctx, data.KeyToken, data.Channel, data.Title, data.Content, data.Priority, data.UserMessageID, data.SendTimestamp, data.SenderName) if errResp != nil { return *errResp } else { diff --git a/scnserver/db/impl/primary/users.go b/scnserver/db/impl/primary/users.go index a75c506..67a4399 100644 --- a/scnserver/db/impl/primary/users.go +++ b/scnserver/db/impl/primary/users.go @@ -1,12 +1,13 @@ package primary import ( + "time" + scn "blackforestbytes.com/simplecloudnotifier" "blackforestbytes.com/simplecloudnotifier/db" "blackforestbytes.com/simplecloudnotifier/models" "git.blackforestbytes.com/BlackForestBytes/goext/langext" "git.blackforestbytes.com/BlackForestBytes/goext/sq" - "time" ) func (db *Database) CreateUser(ctx db.TxContext, protoken *string, username *string) (models.User, error) { @@ -63,6 +64,15 @@ func (db *Database) GetUser(ctx db.TxContext, userid models.UserID) (models.User return sq.QuerySingle[models.User](ctx, tx, "SELECT * FROM users WHERE user_id = :uid AND deleted=0 LIMIT 1", sq.PP{"uid": userid}, sq.SModeExtended, sq.Safe) } +func (db *Database) GetUserByKey(ctx db.TxContext, key string) (models.User, error) { + tx, err := ctx.GetOrCreateTransaction(db) + if err != nil { + return models.User{}, err + } + + return sq.QuerySingle[models.User](ctx, tx, "SELECT * FROM users WHERE EXISTS(SELECT keytokens.keytoken_id FROM keytokens WHERE keytokens.token = :tok AND users.user_id = keytokens.owner_user_id AND keytokens.deleted=0) AND users.deleted=0 LIMIT 1", sq.PP{"tok": key}, sq.SModeExtended, sq.Safe) +} + func (db *Database) GetUserOpt(ctx db.TxContext, userid models.UserID) (*models.User, error) { tx, err := ctx.GetOrCreateTransaction(db) if err != nil { diff --git a/scnserver/logic/message.go b/scnserver/logic/message.go index d4bc927..87edf99 100644 --- a/scnserver/logic/message.go +++ b/scnserver/logic/message.go @@ -1,21 +1,22 @@ package logic import ( + "database/sql" + "errors" + "fmt" + "strings" + "time" + "blackforestbytes.com/simplecloudnotifier/api/apierr" hl "blackforestbytes.com/simplecloudnotifier/api/apihighlight" "blackforestbytes.com/simplecloudnotifier/api/ginresp" "blackforestbytes.com/simplecloudnotifier/models" - "database/sql" - "errors" - "fmt" "git.blackforestbytes.com/BlackForestBytes/goext/ginext" "git.blackforestbytes.com/BlackForestBytes/goext/langext" "git.blackforestbytes.com/BlackForestBytes/goext/mathext" "git.blackforestbytes.com/BlackForestBytes/goext/timeext" "github.com/gin-gonic/gin" "github.com/rs/zerolog/log" - "strings" - "time" ) type SendMessageResponse struct { @@ -25,7 +26,7 @@ type SendMessageResponse struct { CompatMessageID int64 } -func (app *Application) SendMessage(g *gin.Context, ctx *AppContext, UserID *models.UserID, Key *string, Channel *string, Title *string, Content *string, Priority *int, UserMessageID *string, SendTimestamp *float64, SenderName *string) (*SendMessageResponse, *ginext.HTTPResponse) { +func (app *Application) SendMessage(g *gin.Context, ctx *AppContext, Key *string, Channel *string, Title *string, Content *string, Priority *int, UserMessageID *string, SendTimestamp *float64, SenderName *string) (*SendMessageResponse, *ginext.HTTPResponse) { if Title != nil { Title = langext.Ptr(strings.TrimSpace(*Title)) } @@ -33,9 +34,6 @@ func (app *Application) SendMessage(g *gin.Context, ctx *AppContext, UserID *mod UserMessageID = langext.Ptr(strings.TrimSpace(*UserMessageID)) } - if UserID == nil { - return nil, langext.Ptr(ginresp.SendAPIError(g, 400, apierr.MISSING_UID, hl.USER_ID, "Missing parameter [[user_id]]", nil)) - } if Key == nil { return nil, langext.Ptr(ginresp.SendAPIError(g, 400, apierr.MISSING_TOK, hl.USER_KEY, "Missing parameter [[key]]", nil)) } @@ -49,9 +47,9 @@ func (app *Application) SendMessage(g *gin.Context, ctx *AppContext, UserID *mod return nil, langext.Ptr(ginresp.SendAPIError(g, 400, apierr.NO_TITLE, hl.TITLE, "No title specified", nil)) } - user, err := app.Database.Primary.GetUser(ctx, *UserID) + user, err := app.Database.Primary.GetUserByKey(ctx, *Key) if errors.Is(err, sql.ErrNoRows) { - return nil, langext.Ptr(ginresp.SendAPIError(g, 400, apierr.USER_NOT_FOUND, hl.USER_ID, "User not found", err)) + return nil, langext.Ptr(ginresp.SendAPIError(g, 401, apierr.USER_AUTH_FAILED, hl.USER_KEY, "Key not found or not valid", err)) } if err != nil { return nil, langext.Ptr(ginresp.SendAPIError(g, 500, apierr.DATABASE_ERROR, hl.NONE, "Failed to query user", err)) @@ -126,7 +124,7 @@ func (app *Application) SendMessage(g *gin.Context, ctx *AppContext, UserID *mod return nil, langext.Ptr(ginresp.SendAPIError(g, 403, apierr.QUOTA_REACHED, hl.NONE, fmt.Sprintf("Daily quota reached (%d)", user.QuotaPerDay()), nil)) } - channel, err := app.GetOrCreateChannel(ctx, *UserID, channelDisplayName, channelInternalName) + channel, err := app.GetOrCreateChannel(ctx, user.UserID, channelDisplayName, channelInternalName) if err != nil { return nil, langext.Ptr(ginresp.SendAPIError(g, 500, apierr.DATABASE_ERROR, hl.NONE, "Failed to query/create (owned) channel", err)) } @@ -145,7 +143,7 @@ func (app *Application) SendMessage(g *gin.Context, ctx *AppContext, UserID *mod clientIP := g.ClientIP() - msg, err := app.Database.Primary.CreateMessage(ctx, *UserID, channel, sendTimestamp, *Title, Content, priority, UserMessageID, clientIP, SenderName, keytok.KeyTokenID) + msg, err := app.Database.Primary.CreateMessage(ctx, user.UserID, channel, sendTimestamp, *Title, Content, priority, UserMessageID, clientIP, SenderName, keytok.KeyTokenID) if err != nil { return nil, langext.Ptr(ginresp.SendAPIError(g, 500, apierr.DATABASE_ERROR, hl.NONE, "Failed to create message in db", err)) } @@ -176,7 +174,7 @@ func (app *Application) SendMessage(g *gin.Context, ctx *AppContext, UserID *mod return nil, langext.Ptr(ginresp.SendAPIError(g, 500, apierr.DATABASE_ERROR, hl.NONE, "Failed to inc token msg-counter", err)) } - log.Info().Msg(fmt.Sprintf("Sending new notification %s for user %s (to %d active subscriptions)", msg.MessageID, UserID, len(activeSubscriptions))) + log.Info().Msg(fmt.Sprintf("Sending new notification %s for user %s (to %d active subscriptions)", msg.MessageID, user.UserID, len(activeSubscriptions))) for _, sub := range activeSubscriptions { clients, err := app.Database.Primary.ListClients(ctx, sub.SubscriberUserID) diff --git a/scnserver/test/channel_test.go b/scnserver/test/channel_test.go index 1db9306..03fd86b 100644 --- a/scnserver/test/channel_test.go +++ b/scnserver/test/channel_test.go @@ -1142,9 +1142,8 @@ func TestChannelMessageCounter(t *testing.T) { } tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{ - "key": admintok, - "user_id": uid, - "title": tt.ShortLipsum(1001, 1), + "key": admintok, + "title": tt.ShortLipsum(1001, 1), }) chan0 := tt.RequestAuthGet[chanlist](t, admintok, baseUrl, fmt.Sprintf("/api/v2/users/%s/channels", uid)).Channels[0] @@ -1171,28 +1170,24 @@ func TestChannelMessageCounter(t *testing.T) { assertCounter(1, 0, 0) tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{ - "key": admintok, - "user_id": uid, - "title": tt.ShortLipsum(1002, 1), + "key": admintok, + "title": tt.ShortLipsum(1002, 1), }) assertCounter(2, 0, 0) tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{ "key": admintok, - "user_id": uid, "channel": "Chan1", "title": tt.ShortLipsum(1003, 1), }) tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{ "key": admintok, - "user_id": uid, "channel": "Chan2", "title": tt.ShortLipsum(1004, 1), }) tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{ "key": admintok, - "user_id": uid, "channel": "Chan2", "title": tt.ShortLipsum(1005, 1), }) diff --git a/scnserver/test/keytoken_test.go b/scnserver/test/keytoken_test.go index 2c51de2..15b2d1a 100644 --- a/scnserver/test/keytoken_test.go +++ b/scnserver/test/keytoken_test.go @@ -126,7 +126,6 @@ func TestTokenKeys(t *testing.T) { msg1s := tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{ "key": key7.Token, - "user_id": data.UID, "channel": "testchan1", "title": "HelloWorld_001", }) @@ -137,15 +136,13 @@ func TestTokenKeys(t *testing.T) { tt.RequestPostShouldFail(t, baseUrl, "/", gin.H{ "key": key7.Token, - "user_id": data.UID, "channel": "testchan2", "title": "HelloWorld_001", }, 401, apierr.USER_AUTH_FAILED) // wrong channel tt.RequestPostShouldFail(t, baseUrl, "/", gin.H{ - "key": key7.Token, - "user_id": data.UID, - "title": "HelloWorld_001", + "key": key7.Token, + "title": "HelloWorld_001", }, 401, apierr.USER_AUTH_FAILED) // no channel (=main) tt.RequestAuthGetShouldFail(t, key7.Token, baseUrl, fmt.Sprintf("/api/v2/users/%s", data.UID), 401, apierr.USER_AUTH_FAILED) // no user read perm @@ -160,9 +157,8 @@ func TestTokenKeys(t *testing.T) { }) tt.RequestPostShouldFail(t, baseUrl, "/", gin.H{ - "key": key8.Token, - "user_id": data.UID, - "title": "HelloWorld_001", + "key": key8.Token, + "title": "HelloWorld_001", }, 401, apierr.USER_AUTH_FAILED) // no send perm } @@ -470,15 +466,13 @@ func TestTokenKeysPermissions(t *testing.T) { tt.RequestPostShouldFail(t, baseUrl, "/", gin.H{ "key": key7.Token, - "user_id": data.UID, "channel": "testchan2", "title": "HelloWorld_001", }, 401, apierr.USER_AUTH_FAILED) // wrong channel tt.RequestPostShouldFail(t, baseUrl, "/", gin.H{ - "key": key7.Token, - "user_id": data.UID, - "title": "HelloWorld_001", + "key": key7.Token, + "title": "HelloWorld_001", }, 401, apierr.USER_AUTH_FAILED) // no channel (=main) tt.RequestAuthGetShouldFail(t, key7.Token, baseUrl, fmt.Sprintf("/api/v2/users/%s", data.UID), 401, apierr.USER_AUTH_FAILED) // no user read perm @@ -493,9 +487,8 @@ func TestTokenKeysPermissions(t *testing.T) { }) tt.RequestPostShouldFail(t, baseUrl, "/", gin.H{ - "key": key8.Token, - "user_id": data.UID, - "title": "HelloWorld_001", + "key": key8.Token, + "title": "HelloWorld_001", }, 401, apierr.USER_AUTH_FAILED) // no send perm } @@ -550,44 +543,38 @@ func TestTokenKeysMessageCounter(t *testing.T) { assertCounter(0, 0, 0) tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{ - "key": admintok, - "user_id": uid, - "title": tt.ShortLipsum(1001, 1), + "key": admintok, + "title": tt.ShortLipsum(1001, 1), }) assertCounter(1, 0, 0) tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{ - "key": admintok, - "user_id": uid, - "title": tt.ShortLipsum(1002, 1), + "key": admintok, + "title": tt.ShortLipsum(1002, 1), }) assertCounter(2, 0, 0) tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{ - "key": sendtok, - "user_id": uid, - "title": tt.ShortLipsum(1002, 1), + "key": sendtok, + "title": tt.ShortLipsum(1002, 1), }) assertCounter(2, 1, 0) tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{ "key": sendtok, - "user_id": uid, "channel": "Chan1", "title": tt.ShortLipsum(1003, 1), }) tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{ "key": sendtok, - "user_id": uid, "channel": "Chan2", "title": tt.ShortLipsum(1004, 1), }) tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{ "key": sendtok, - "user_id": uid, "channel": "Chan2", "title": tt.ShortLipsum(1005, 1), }) @@ -597,7 +584,6 @@ func TestTokenKeysMessageCounter(t *testing.T) { tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{ "key": admintok, - "user_id": uid, "channel": "Chan2", "title": tt.ShortLipsum(1004, 1), }) @@ -605,9 +591,8 @@ func TestTokenKeysMessageCounter(t *testing.T) { assertCounter(3, 4, 0) tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{ - "key": admintok, - "user_id": uid, - "title": tt.ShortLipsum(1002, 1), + "key": admintok, + "title": tt.ShortLipsum(1002, 1), }) assertCounter(4, 4, 0) diff --git a/scnserver/test/main_test.go b/scnserver/test/main_test.go index 69ecc8b..95bdbef 100644 --- a/scnserver/test/main_test.go +++ b/scnserver/test/main_test.go @@ -2,11 +2,13 @@ package test import ( "database/sql" + "os" + "testing" + + tt "blackforestbytes.com/simplecloudnotifier/test/util" "git.blackforestbytes.com/BlackForestBytes/goext/exerr" "git.blackforestbytes.com/BlackForestBytes/goext/langext" "github.com/glebarez/go-sqlite" - "os" - "testing" ) func TestMain(m *testing.M) { @@ -20,3 +22,10 @@ func TestMain(m *testing.M) { os.Exit(m.Run()) } + +func TestInitFactory(t *testing.T) { + ws, _, stop := tt.StartSimpleWebserver(t) + defer stop() + + tt.InitDefaultData(t, ws) +} diff --git a/scnserver/test/message_test.go b/scnserver/test/message_test.go index 8a1acb3..20284cd 100644 --- a/scnserver/test/message_test.go +++ b/scnserver/test/message_test.go @@ -418,14 +418,12 @@ func TestDeleteMessage(t *testing.T) { "fcm_token": "DUMMY_FCM", }) - uid := r0["user_id"].(string) sendtok := r0["send_key"].(string) admintok := r0["admin_key"].(string) msg1 := tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{ - "key": sendtok, - "user_id": uid, - "title": "Message_1", + "key": sendtok, + "title": "Message_1", }) tt.RequestAuthGet[tt.Void](t, admintok, baseUrl, "/api/v2/messages/"+fmt.Sprintf("%v", msg1["scn_msg_id"])) @@ -446,15 +444,13 @@ func TestDeleteMessageAndResendUsrMsgId(t *testing.T) { "fcm_token": "DUMMY_FCM", }) - uid := r0["user_id"].(string) sendtok := r0["send_key"].(string) admintok := r0["admin_key"].(string) msg1 := tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{ - "key": sendtok, - "user_id": uid, - "title": "Message_1", - "msg_id": "bef8dd3d-078e-4f89-abf4-5258ad22a2e4", + "key": sendtok, + "title": "Message_1", + "msg_id": "bef8dd3d-078e-4f89-abf4-5258ad22a2e4", }) tt.AssertEqual(t, "suppress_send", false, msg1["suppress_send"]) @@ -462,10 +458,9 @@ func TestDeleteMessageAndResendUsrMsgId(t *testing.T) { tt.RequestAuthGet[tt.Void](t, admintok, baseUrl, "/api/v2/messages/"+fmt.Sprintf("%v", msg1["scn_msg_id"])) msg2 := tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{ - "key": sendtok, - "user_id": uid, - "title": "Message_1", - "msg_id": "bef8dd3d-078e-4f89-abf4-5258ad22a2e4", + "key": sendtok, + "title": "Message_1", + "msg_id": "bef8dd3d-078e-4f89-abf4-5258ad22a2e4", }) tt.AssertEqual(t, "suppress_send", true, msg2["suppress_send"]) @@ -475,10 +470,9 @@ func TestDeleteMessageAndResendUsrMsgId(t *testing.T) { // even though message is deleted, we still get a `suppress_send` on send_message msg3 := tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{ - "key": sendtok, - "user_id": uid, - "title": "Message_1", - "msg_id": "bef8dd3d-078e-4f89-abf4-5258ad22a2e4", + "key": sendtok, + "title": "Message_1", + "msg_id": "bef8dd3d-078e-4f89-abf4-5258ad22a2e4", }) tt.AssertEqual(t, "suppress_send", true, msg3["suppress_send"]) @@ -492,9 +486,8 @@ func TestGetMessageSimple(t *testing.T) { data := tt.InitDefaultData(t, ws) msgOut := tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{ - "key": data.User[0].SendKey, - "user_id": data.User[0].UID, - "title": "Message_1", + "key": data.User[0].SendKey, + "title": "Message_1", }) msgIn := tt.RequestAuthGet[gin.H](t, data.User[0].AdminKey, baseUrl, "/api/v2/messages/"+fmt.Sprintf("%v", msgOut["scn_msg_id"])) @@ -533,7 +526,6 @@ func TestGetMessageFull(t *testing.T) { msgOut := tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{ "key": data.User[0].SendKey, - "user_id": data.User[0].UID, "title": "Message_1", "content": content, "channel": "demo-channel-007", @@ -948,7 +940,6 @@ func TestDeactivatedSubscriptionListMessages(t *testing.T) { newMessageTitle := langext.RandBase62(48) tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{ "key": user15.AdminKey, - "user_id": user15.UID, "channel": chanName, "title": newMessageTitle, }) @@ -1122,7 +1113,6 @@ func TestActiveSubscriptionListMessages(t *testing.T) { newMessageTitle := langext.RandBase62(48) tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{ "key": user15.AdminKey, - "user_id": user15.UID, "channel": chanName, "title": newMessageTitle, }) @@ -1176,7 +1166,6 @@ func TestUnconfirmedSubscriptionListMessages(t *testing.T) { newMessageTitle := langext.RandBase62(48) tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{ "key": user15.AdminKey, - "user_id": user15.UID, "channel": chanName, "title": newMessageTitle, }) @@ -1229,7 +1218,7 @@ func TestListMessagesSubscriptionStatusAllInactiveSubscription(t *testing.T) { subscriptionID, _ := tt.FindSubscriptionByChanName(t, baseUrl, user14, user15.UID, chanName) newMessageTitle := langext.RandBase62(48) - tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{"key": user15.AdminKey, "user_id": user15.UID, "channel": chanName, "title": newMessageTitle}) + tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{"key": user15.AdminKey, "channel": chanName, "title": newMessageTitle}) type msg struct { MessageId string `json:"message_id"` @@ -1282,7 +1271,7 @@ func TestListMessagesSubscriptionStatusAllNoSubscription(t *testing.T) { chan2 := data.User[0].Channels[2] newMessageTitle := langext.RandBase62(48) - tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{"key": user0.AdminKey, "user_id": user0.UID, "channel": chan2.InternalName, "title": newMessageTitle}) + tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{"key": user0.AdminKey, "channel": chan2.InternalName, "title": newMessageTitle}) { messages := tt.RequestAuthGet[mglist](t, user0.AdminKey, baseUrl, "/api/v2/messages") diff --git a/scnserver/test/send_test.go b/scnserver/test/send_test.go index 20e7ca9..4b79c73 100644 --- a/scnserver/test/send_test.go +++ b/scnserver/test/send_test.go @@ -1,18 +1,18 @@ package test import ( - "blackforestbytes.com/simplecloudnotifier/api/apierr" - "blackforestbytes.com/simplecloudnotifier/models" - "blackforestbytes.com/simplecloudnotifier/push" - tt "blackforestbytes.com/simplecloudnotifier/test/util" "fmt" - "git.blackforestbytes.com/BlackForestBytes/goext/langext" - "github.com/gin-gonic/gin" "math/rand/v2" "net/url" "strings" "testing" "time" + + "blackforestbytes.com/simplecloudnotifier/api/apierr" + "blackforestbytes.com/simplecloudnotifier/push" + tt "blackforestbytes.com/simplecloudnotifier/test/util" + "git.blackforestbytes.com/BlackForestBytes/goext/langext" + "github.com/gin-gonic/gin" ) func TestSendSimpleMessageJSON(t *testing.T) { @@ -28,27 +28,23 @@ func TestSendSimpleMessageJSON(t *testing.T) { "fcm_token": "DUMMY_FCM", }) - uid := r0["user_id"].(string) admintok := r0["admin_key"].(string) readtok := r0["read_key"].(string) sendtok := r0["send_key"].(string) msg1 := tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{ - "key": sendtok, - "user_id": uid, - "title": "HelloWorld_001", + "key": sendtok, + "title": "HelloWorld_001", }) tt.RequestPostShouldFail(t, baseUrl, "/", gin.H{ - "key": readtok, - "user_id": uid, - "title": "HelloWorld_001", + "key": readtok, + "title": "HelloWorld_001", }, 401, apierr.USER_AUTH_FAILED) tt.RequestPostShouldFail(t, baseUrl, "/", gin.H{ - "key": "asdf", - "user_id": uid, - "title": "HelloWorld_001", + "key": "asdf", + "title": "HelloWorld_001", }, 401, apierr.USER_AUTH_FAILED) tt.AssertEqual(t, "messageCount", 1, len(pusher.Data)) @@ -117,14 +113,12 @@ func TestSendSimpleMessageForm(t *testing.T) { "fcm_token": "DUMMY_FCM", }) - uid := r0["user_id"].(string) admintok := r0["admin_key"].(string) sendtok := r0["send_key"].(string) msg1 := tt.RequestPost[gin.H](t, baseUrl, "/", tt.FormData{ - "key": sendtok, - "user_id": uid, - "title": "Hello World 9999 [$$$]", + "key": sendtok, + "title": "Hello World 9999 [$$$]", }) tt.AssertEqual(t, "messageCount", 1, len(pusher.Data)) @@ -189,9 +183,8 @@ func TestSendSimpleMessageJSONAndQuery(t *testing.T) { // query overwrite body msg1 := tt.RequestPost[gin.H](t, baseUrl, fmt.Sprintf("/?user_id=%s&key=%s&title=%s", uid, sendtok, url.QueryEscape("1111111")), gin.H{ - "key": "ERR", - "user_id": models.NewUserID(), - "title": "2222222", + "key": "ERR", + "title": "2222222", }) tt.AssertEqual(t, "messageCount", 1, len(pusher.Data)) @@ -212,21 +205,18 @@ func TestSendSimpleMessageAlt1(t *testing.T) { "fcm_token": "DUMMY_FCM", }) - uid := r0["user_id"].(string) admintok := r0["admin_key"].(string) readtok := r0["read_key"].(string) sendtok := r0["send_key"].(string) msg1 := tt.RequestPost[gin.H](t, baseUrl, "/send", gin.H{ - "key": sendtok, - "user_id": uid, - "title": "HelloWorld_001", + "key": sendtok, + "title": "HelloWorld_001", }) tt.RequestPostShouldFail(t, baseUrl, "/send", gin.H{ - "key": readtok, - "user_id": uid, - "title": "HelloWorld_001", + "key": readtok, + "title": "HelloWorld_001", }, 401, apierr.USER_AUTH_FAILED) tt.AssertEqual(t, "messageCount", 1, len(pusher.Data)) @@ -259,13 +249,11 @@ func TestSendContentMessage(t *testing.T) { "fcm_token": "DUMMY_FCM", }) - uid := r0["user_id"].(string) admintok := r0["admin_key"].(string) sendtok := r0["send_key"].(string) msg1 := tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{ "key": sendtok, - "user_id": uid, "title": "HelloWorld_042", "content": "I am Content\nasdf", }) @@ -304,13 +292,11 @@ func TestSendWithSendername(t *testing.T) { "fcm_token": "DUMMY_FCM", }) - uid := r0["user_id"].(string) sendtok := r0["send_key"].(string) admintok := r0["admin_key"].(string) msg1 := tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{ "key": sendtok, - "user_id": uid, "title": "HelloWorld_xyz", "content": "Unicode: 日本 - yäy\000\n\t\x00...", "sender_name": "localhorst", @@ -353,7 +339,6 @@ func TestSendLongContent(t *testing.T) { "fcm_token": "DUMMY_FCM", }) - uid := r0["user_id"].(string) admintok := r0["admin_key"].(string) sendtok := r0["send_key"].(string) @@ -364,7 +349,6 @@ func TestSendLongContent(t *testing.T) { msg1 := tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{ "key": sendtok, - "user_id": uid, "title": "HelloWorld_042", "content": longContent, }) diff --git a/scnserver/test/user_test.go b/scnserver/test/user_test.go index 1a2af0f..6a0d242 100644 --- a/scnserver/test/user_test.go +++ b/scnserver/test/user_test.go @@ -401,36 +401,31 @@ func TestUserMessageCounter(t *testing.T) { assertCounter(0) tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{ - "key": admintok, - "user_id": uid, - "title": tt.ShortLipsum(1001, 1), + "key": admintok, + "title": tt.ShortLipsum(1001, 1), }) assertCounter(1) assertCounter(1) tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{ - "key": admintok, - "user_id": uid, - "title": tt.ShortLipsum(1002, 1), + "key": admintok, + "title": tt.ShortLipsum(1002, 1), }) assertCounter(2) tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{ - "key": admintok, - "user_id": uid, - "title": tt.ShortLipsum(1003, 1), + "key": admintok, + "title": tt.ShortLipsum(1003, 1), }) tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{ - "key": admintok, - "user_id": uid, - "title": tt.ShortLipsum(1004, 1), + "key": admintok, + "title": tt.ShortLipsum(1004, 1), }) tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{ - "key": admintok, - "user_id": uid, - "title": tt.ShortLipsum(1005, 1), + "key": admintok, + "title": tt.ShortLipsum(1005, 1), }) assertCounter(5) diff --git a/scnserver/test/util/factory.go b/scnserver/test/util/factory.go index 41a2234..ecd5c7e 100644 --- a/scnserver/test/util/factory.go +++ b/scnserver/test/util/factory.go @@ -1,15 +1,16 @@ package util import ( - "blackforestbytes.com/simplecloudnotifier/logic" "fmt" + "testing" + "time" + + "blackforestbytes.com/simplecloudnotifier/logic" "git.blackforestbytes.com/BlackForestBytes/goext/langext" "git.blackforestbytes.com/BlackForestBytes/goext/timeext" "github.com/gin-gonic/gin" "github.com/rs/zerolog/log" "gopkg.in/loremipsum.v1" - "testing" - "time" ) // # Generated by https://chat.openai.com/chat @@ -393,7 +394,6 @@ func InitDefaultData(t *testing.T, ws *logic.Application) DefData { for _, mex := range messageExamples { body := gin.H{} body["title"] = mex.Title - body["user_id"] = users[mex.User].UID switch mex.Key { case AKEY: body["key"] = users[mex.User].AdminKey diff --git a/scnserver/website/api.html b/scnserver/website/api.html index 41ad066..7917f54 100644 --- a/scnserver/website/api.html +++ b/scnserver/website/api.html @@ -19,10 +19,9 @@

Simple Cloud Notifier

-

Get your user-id and user-key from the android or iOS app.
And send notifications to your phone by performing a POST request against {{config|baseURL}}/ from anywhere

+

Get your user-key from the android or iOS app.
And send notifications to your phone by performing a POST request against {{config|baseURL}}/ from anywhere

 curl                                                                        \
-    --data "user_id=${userid}"                                              \
     --data "key=${key}"                                                     \
     --data "title=${message_title}"                                         \
     --data "content=${message_body}"                                        \
@@ -35,7 +34,6 @@ curl                                                                        \
     

Most parameters are optional, you can send a message with only a title (default priority and channel will be used)

 curl                                          \
-    --data "user_id={userid}"                 \
     --data "key={key}"                        \
     --data "title={message_title}"            \
     {{config|baseURL}}/
diff --git a/scnserver/website/api_more.html b/scnserver/website/api_more.html index e3bc7bc..b39a742 100644 --- a/scnserver/website/api_more.html +++ b/scnserver/website/api_more.html @@ -52,7 +52,7 @@ All Parameters can either directly be submitted as URL parameters or they can be put into the POST body (either multipart/form-data or JSON).

- You need to supply a valid [user_id, key] pair and a title for your message, all other parameter are optional. + You need to supply a valid key and a title for your message, all other parameter are optional.

@@ -90,7 +90,7 @@ 401 (Unauthorized) - The user_id was not found, the key is wrong or the [user_id, key] combination does not have the SEND permissions on the specified channel + The key is wrong or does not have the SEND permissions on the specified channel 403 (Forbidden) @@ -125,7 +125,6 @@ If needed the content can be supplied in the content parameter.

curl                                          \
-    --data "user_id={userid}"                 \
     --data "key={key}"                        \
     --data "title={message_title}"            \
     --data "content={message_content}"        \
@@ -143,7 +142,6 @@
                 If no priority is supplied the message will get the default priority of 1.
             

curl                                          \
-    --data "user_id={userid}"                 \
     --data "key={key}"                        \
     --data "title={message_title}"            \
     --data "priority={0|1|2}"                 \
@@ -158,7 +156,6 @@
                 Channel names are case-insensitive and can only contain letters, numbers, underscores and minuses ( /[[:alnum:]\-_]+/ )
             

curl                                          \
-    --data "user_id={userid}"                 \
     --data "key={key}"                        \
     --data "title={message_title}"            \
     --data "channel={my_channel}"             \
@@ -229,7 +226,6 @@
                 The message_id is optional - but if you want to use it you need to supply it via the msg_id parameter.
             

curl                                          \
-    --data "user_id={userid}"                 \
     --data "key={key}"                        \
     --data "title={message_title}"            \
     --data "msg_id={message_id}"              \
@@ -248,7 +244,6 @@
                 The custom timestamp must be within 48 hours of the current time. This parameter is only intended to supply a more precise value in case the message sending was delayed.
             

curl                                          \
-    --data "user_id={userid}"                 \
     --data "key={key}"                        \
     --data "title={message_title}"            \
     --data "timestamp={unix_timestamp}"       \
diff --git a/scnserver/website/index.html b/scnserver/website/index.html
index dbf1317..c53eefb 100644
--- a/scnserver/website/index.html
+++ b/scnserver/website/index.html
@@ -21,11 +21,6 @@
 
         

Simple Cloud Notifier

-
-
-
-
-
diff --git a/scnserver/website/js/logic.js b/scnserver/website/js/logic.js index 1bf0ae8..e797895 100644 --- a/scnserver/website/js/logic.js +++ b/scnserver/website/js/logic.js @@ -8,20 +8,17 @@ function send() me.classList.add("btn-disabled"); - let uid = document.getElementById("uid"); let key = document.getElementById("ukey"); let tit = document.getElementById("tit"); let cnt = document.getElementById("cnt"); let pio = document.getElementById("prio"); let cha = document.getElementById("chan"); - uid.classList.remove('input-invalid'); key.classList.remove('input-invalid'); cnt.classList.remove('input-invalid'); pio.classList.remove('input-invalid'); let data = new FormData(); - data.append('user_id', uid.value); data.append('key', key.value); if (tit.value !== '') data.append('title', tit.value); if (cnt.value !== '') data.append('content', cnt.value); @@ -40,7 +37,6 @@ function send() let resp = JSON.parse(xhr.responseText); if (!resp.success || xhr.status !== 200) { - if (resp.errhighlight === 101) uid.classList.add('input-invalid'); if (resp.errhighlight === 102) key.classList.add('input-invalid'); if (resp.errhighlight === 103) tit.classList.add('input-invalid'); if (resp.errhighlight === 104) cnt.classList.add('input-invalid'); @@ -63,7 +59,6 @@ function send() '"a=' + resp.quota + '"a_remain=' + (resp.quota_max-resp.quota) + '"a_max=' + resp.quota_max + - '&preset_user_id=' + uid.value + '&preset_user_key=' + key.value + '&preset_channel=' + cha.value; } @@ -89,7 +84,6 @@ window.addEventListener("load", function () const qp = new URLSearchParams(window.location.search); let btn = document.getElementById("btnSend"); - let uid = document.getElementById("uid"); let key = document.getElementById("ukey"); let tit = document.getElementById("tit"); let cnt = document.getElementById("cnt"); @@ -100,7 +94,6 @@ window.addEventListener("load", function () if (qp.has('preset_priority')) pio.selectedIndex = parseInt(qp.get("preset_priority")); if (qp.has('preset_user_key')) key.value = qp.get("preset_user_key"); - if (qp.has('preset_user_id')) uid.value = qp.get("preset_user_id"); if (qp.has('preset_title')) tit.value = qp.get("preset_title"); if (qp.has('preset_content')) cnt.value = qp.get("preset_content"); if (qp.has('preset_channel')) cha.value = qp.get("preset_channel");