From 0800d25b309d38be7fa251928748e54b10649140 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mike=20Schw=C3=B6rer?=
Date: Thu, 4 Dec 2025 10:25:15 +0100
Subject: [PATCH] Remove required user_id param when sending messages
---
scnserver/api/handler/compat.go | 11 +++---
scnserver/api/handler/external.go | 28 +++++++--------
scnserver/api/handler/message.go | 24 ++++++-------
scnserver/db/impl/primary/users.go | 12 ++++++-
scnserver/logic/message.go | 26 +++++++-------
scnserver/test/channel_test.go | 13 +++----
scnserver/test/keytoken_test.go | 47 +++++++++----------------
scnserver/test/main_test.go | 13 +++++--
scnserver/test/message_test.go | 41 ++++++++--------------
scnserver/test/send_test.go | 56 +++++++++++-------------------
scnserver/test/user_test.go | 25 ++++++-------
scnserver/test/util/factory.go | 8 ++---
scnserver/website/api.html | 4 +--
scnserver/website/api_more.html | 9 ++---
scnserver/website/index.html | 5 ---
scnserver/website/js/logic.js | 7 ----
16 files changed, 138 insertions(+), 191 deletions(-)
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
-
-
Authentification Key
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");