Notifications with new Flutter app [Kinda work!]
All checks were successful
Build Docker and Deploy / Build Docker Container (push) Successful in 1m56s
Build Docker and Deploy / Deploy to Server (push) Successful in 5s

This commit is contained in:
Mike Schwörer 2024-06-01 15:37:59 +02:00
parent 0560330f68
commit e397f009b9
Signed by: Mikescher
GPG Key ID: D3C7172E0A70F8CF
19 changed files with 198 additions and 551 deletions

View File

@ -33,3 +33,7 @@
- [ ] sq.DBOptions - enable CommentTrimmer and DefaultConverter - [ ] sq.DBOptions - enable CommentTrimmer and DefaultConverter
- [ ] run unit-tests... - [ ] run unit-tests...
- [ ] Copy db.Migrate code - [ ] Copy db.Migrate code
- [ ] Disable compat | remove code
- [x] compat message title
- [ ] ...

View File

@ -216,7 +216,7 @@ class _AccountRootPageState extends State<AccountRootPage> {
padding: const EdgeInsets.fromLTRB(4, 1, 4, 1), padding: const EdgeInsets.fromLTRB(4, 1, 4, 1),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.blue, color: Colors.blue,
borderRadius: BorderRadius.only(topLeft: Radius.circular(8)), borderRadius: BorderRadius.only(topLeft: Radius.circular(4)),
), ),
), ),
), ),
@ -228,7 +228,7 @@ class _AccountRootPageState extends State<AccountRootPage> {
padding: const EdgeInsets.fromLTRB(4, 1, 4, 1), padding: const EdgeInsets.fromLTRB(4, 1, 4, 1),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.purple, color: Colors.purple,
borderRadius: BorderRadius.only(topLeft: Radius.circular(8)), borderRadius: BorderRadius.only(topLeft: Radius.circular(4)),
), ),
), ),
), ),
@ -240,18 +240,7 @@ class _AccountRootPageState extends State<AccountRootPage> {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Row( Text(user.username ?? user.userID, overflow: TextOverflow.ellipsis),
children: [
Expanded(child: Text(user.username ?? user.userID, overflow: TextOverflow.ellipsis)),
IconButton(
icon: FaIcon(FontAwesomeIcons.pen),
iconSize: 18,
padding: EdgeInsets.fromLTRB(0, 0, 4, 0),
constraints: BoxConstraints(),
onPressed: () {/*TODO*/},
),
],
),
const SizedBox(height: 4), const SizedBox(height: 4),
Row( Row(
children: [ children: [
@ -282,6 +271,29 @@ class _AccountRootPageState extends State<AccountRootPage> {
], ],
), ),
), ),
Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
IconButton(
icon: FaIcon(FontAwesomeIcons.pen),
iconSize: 18,
padding: EdgeInsets.all(4),
constraints: BoxConstraints(),
style: ButtonStyle(tapTargetSize: MaterialTapTargetSize.shrinkWrap),
onPressed: () {/*TODO*/},
),
const SizedBox(height: 4),
if (!user.isPro)
IconButton(
icon: FaIcon(FontAwesomeIcons.cartCircleArrowUp),
iconSize: 18,
padding: EdgeInsets.all(4),
constraints: BoxConstraints(),
style: ButtonStyle(tapTargetSize: MaterialTapTargetSize.shrinkWrap),
onPressed: () {/*TODO*/},
),
],
),
], ],
); );
} }
@ -458,6 +470,7 @@ class _AccountRootPageState extends State<AccountRootPage> {
acc.set(user.user, user.clients[0], KeyTokenAuth(userId: user.user.userID, tokenAdmin: user.adminKey, tokenSend: user.sendKey)); acc.set(user.user, user.clients[0], KeyTokenAuth(userId: user.user.userID, tokenAdmin: user.adminKey, tokenSend: user.sendKey));
await acc.save(); await acc.save();
Toaster.success("Success", 'Successfully Created a new account');
} catch (exc, trace) { } catch (exc, trace) {
ApplicationLog.error('Failed to create user account: ' + exc.toString(), trace: trace); ApplicationLog.error('Failed to create user account: ' + exc.toString(), trace: trace);
Toaster.error("Error", 'Failed to create user account'); Toaster.error("Error", 'Failed to create user account');
@ -469,6 +482,7 @@ class _AccountRootPageState extends State<AccountRootPage> {
void _logout() async { void _logout() async {
final acc = Provider.of<UserAccount>(context, listen: false); final acc = Provider.of<UserAccount>(context, listen: false);
//TODO clear messages/channels/etc in open views
acc.clear(); acc.clear();
await acc.save(); await acc.save();

View File

@ -149,12 +149,13 @@ class _AccountLoginPageState extends State<AccountLoginPage> {
final user = await APIClient.getUser(kta, uid); final user = await APIClient.getUser(kta, uid);
final client = await APIClient.addClient(acc.auth, fcmToken, Globals().deviceModel, Globals().version, Globals().hostname, Globals().clientType); final client = await APIClient.addClient(kta, fcmToken, Globals().deviceModel, Globals().version, Globals().hostname, Globals().clientType);
acc.set(user, client, kta); acc.set(user, client, kta);
await acc.save(); await acc.save();
Toaster.success("Login", "Successfully logged in"); Toaster.success("Login", "Successfully logged in");
Navigator.popUntil(context, (route) => route.isFirst);
} catch (exc, trace) { } catch (exc, trace) {
ApplicationLog.error('Failed to verify token: ' + exc.toString(), trace: trace); ApplicationLog.error('Failed to verify token: ' + exc.toString(), trace: trace);
Toaster.error("Error", 'Failed to verify token'); Toaster.error("Error", 'Failed to verify token');

View File

@ -57,7 +57,7 @@ class _DebugMainPageState extends State<DebugMainPage> {
ButtonSegment<DebugMainPageSubPage>(value: DebugMainPageSubPage.colors, icon: Icon(FontAwesomeIcons.solidPaintRoller, size: 14)), ButtonSegment<DebugMainPageSubPage>(value: DebugMainPageSubPage.colors, icon: Icon(FontAwesomeIcons.solidPaintRoller, size: 14)),
ButtonSegment<DebugMainPageSubPage>(value: DebugMainPageSubPage.actions, icon: Icon(FontAwesomeIcons.solidHammer, size: 14)), ButtonSegment<DebugMainPageSubPage>(value: DebugMainPageSubPage.actions, icon: Icon(FontAwesomeIcons.solidHammer, size: 14)),
ButtonSegment<DebugMainPageSubPage>(value: DebugMainPageSubPage.requests, icon: Icon(FontAwesomeIcons.solidNetworkWired, size: 14)), ButtonSegment<DebugMainPageSubPage>(value: DebugMainPageSubPage.requests, icon: Icon(FontAwesomeIcons.solidNetworkWired, size: 14)),
ButtonSegment<DebugMainPageSubPage>(value: DebugMainPageSubPage.persistence, icon: Icon(FontAwesomeIcons.solidFloppyDisk, size: 14)), ButtonSegment<DebugMainPageSubPage>(value: DebugMainPageSubPage.persistence, icon: Icon(FontAwesomeIcons.solidDatabase, size: 14)),
ButtonSegment<DebugMainPageSubPage>(value: DebugMainPageSubPage.logs, icon: Icon(FontAwesomeIcons.solidFileLines, size: 14)), ButtonSegment<DebugMainPageSubPage>(value: DebugMainPageSubPage.logs, icon: Icon(FontAwesomeIcons.solidFileLines, size: 14)),
], ],
style: ButtonStyle( style: ButtonStyle(

View File

@ -535,7 +535,7 @@ func (h CompatHandler) Requery(g *gin.Context) ginresp.HTTPResponse {
} }
compMsgs = append(compMsgs, models.CompatMessage{ compMsgs = append(compMsgs, models.CompatMessage{
Title: h.app.CompatizeMessageTitle(ctx, v), Title: v.Title,
Body: v.Content, Body: v.Content,
Priority: v.Priority, Priority: v.Priority,
Timestamp: v.Timestamp().Unix(), Timestamp: v.Timestamp().Unix(),
@ -783,7 +783,7 @@ func (h CompatHandler) Expand(g *gin.Context) ginresp.HTTPResponse {
Success: true, Success: true,
Message: "ok", Message: "ok",
Data: models.CompatMessage{ Data: models.CompatMessage{
Title: h.app.CompatizeMessageTitle(ctx, msg), Title: msg.Title,
Body: msg.Content, Body: msg.Content,
Trimmed: langext.Ptr(false), Trimmed: langext.Ptr(false),
Priority: msg.Priority, Priority: msg.Priority,

View File

@ -7,7 +7,6 @@ import (
"errors" "errors"
"fmt" "fmt"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"gogs.mikescher.com/BlackForestBytes/goext/langext"
"gogs.mikescher.com/BlackForestBytes/goext/syncext" "gogs.mikescher.com/BlackForestBytes/goext/syncext"
"time" "time"
) )
@ -149,6 +148,25 @@ func (j *DeliveryRetryJob) redeliver(ctx *simplectx.SimpleContext, delivery mode
return return
} }
user, err := j.app.Database.Primary.GetUser(ctx, delivery.ReceiverUserID)
if err != nil {
log.Err(err).Str("ReceiverUserID", delivery.ReceiverUserID.String()).Msg("Failed to get user")
ctx.RollbackTransaction()
return
}
channel, err := j.app.Database.Primary.GetChannelByID(ctx, msg.ChannelID)
if err != nil {
log.Err(err).Str("ChannelID", msg.ChannelID.String()).Msg("Failed to get channel")
ctx.RollbackTransaction()
return
}
if channel == nil {
log.Error().Str("ChannelID", msg.ChannelID.String()).Msg("Failed to get channel")
ctx.RollbackTransaction()
return
}
if msg.Deleted { if msg.Deleted {
err = j.app.Database.Primary.SetDeliveryFailed(ctx, delivery) err = j.app.Database.Primary.SetDeliveryFailed(ctx, delivery)
if err != nil { if err != nil {
@ -158,29 +176,7 @@ func (j *DeliveryRetryJob) redeliver(ctx *simplectx.SimpleContext, delivery mode
} }
} else { } else {
isCompatClient, err := j.app.Database.Primary.IsCompatClient(ctx, client.ClientID) fcmDelivID, err := j.app.DeliverMessage(ctx, user, client, *channel, msg)
if err != nil {
log.Err(err).Str("MessageID", delivery.MessageID.String()).Str("ClientID", client.ClientID.String()).Msg("Failed to get <IsCompatClient>")
ctx.RollbackTransaction()
return
}
var titleOverride *string = nil
var msgidOverride *string = nil
if isCompatClient {
messageIdComp, err := j.app.Database.Primary.ConvertToCompatIDOrCreate(ctx, "messageid", msg.MessageID.String())
if err != nil {
log.Err(err).Str("MessageID", delivery.MessageID.String()).Str("ClientID", client.ClientID.String()).Msg("Failed to query/create messageid")
ctx.RollbackTransaction()
return
}
titleOverride = langext.Ptr(j.app.CompatizeMessageTitle(ctx, msg))
msgidOverride = langext.Ptr(fmt.Sprintf("%d", messageIdComp))
}
fcmDelivID, err := j.app.DeliverMessage(ctx, client, msg, titleOverride, msgidOverride)
if err == nil { if err == nil {
err = j.app.Database.Primary.SetDeliverySuccess(ctx, delivery, fcmDelivID) err = j.app.Database.Primary.SetDeliverySuccess(ctx, delivery, fcmDelivID)
if err != nil { if err != nil {

View File

@ -10,7 +10,6 @@ import (
"blackforestbytes.com/simplecloudnotifier/push" "blackforestbytes.com/simplecloudnotifier/push"
"context" "context"
"errors" "errors"
"fmt"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding" "github.com/gin-gonic/gin/binding"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
@ -356,8 +355,8 @@ func (app *Application) NormalizeUsername(v string) string {
return strings.TrimSpace(v) return strings.TrimSpace(v)
} }
func (app *Application) DeliverMessage(ctx context.Context, client models.Client, msg models.Message, compatTitleOverride *string, compatMsgIDOverride *string) (string, error) { func (app *Application) DeliverMessage(ctx context.Context, user models.User, client models.Client, channel models.Channel, msg models.Message) (string, error) {
fcmDelivID, err := app.Pusher.SendNotification(ctx, client, msg, compatTitleOverride, compatMsgIDOverride) fcmDelivID, err := app.Pusher.SendNotification(ctx, user, client, channel, msg)
if err != nil { if err != nil {
log.Warn().Str("MessageID", msg.MessageID.String()).Str("ClientID", client.ClientID.String()).Err(err).Msg("FCM Delivery failed") log.Warn().Str("MessageID", msg.MessageID.String()).Str("ClientID", client.ClientID.String()).Err(err).Msg("FCM Delivery failed")
return "", err return "", err
@ -371,20 +370,3 @@ func (app *Application) InsertRequestLog(data models.RequestLog) {
log.Error().Msg("failed to insert request-log (queue full)") log.Error().Msg("failed to insert request-log (queue full)")
} }
} }
func (app *Application) CompatizeMessageTitle(ctx TxContext, msg models.Message) string {
if msg.ChannelInternalName == "main" {
if rexCompatTitleChannel.IsMatch(msg.Title) {
return "!" + msg.Title // channel in title ?!
}
return msg.Title
}
channel, err := app.Database.Primary.GetChannelByID(ctx, msg.ChannelID)
if err != nil {
return fmt.Sprintf("[%s] %s", "%SCN-ERR%", msg.Title)
}
return fmt.Sprintf("[%s] %s", channel.DisplayName, msg.Title)
}

View File

@ -185,19 +185,7 @@ func (app *Application) SendMessage(g *gin.Context, ctx *AppContext, UserID *mod
for _, client := range clients { for _, client := range clients {
isCompatClient, err := app.Database.Primary.IsCompatClient(ctx, client.ClientID) fcmDelivID, err := app.DeliverMessage(ctx, user, client, channel, msg)
if err != nil {
return nil, langext.Ptr(ginresp.SendAPIError(g, 500, apierr.DATABASE_ERROR, hl.NONE, "Failed to query compat_clients", err))
}
var titleOverride *string = nil
var msgidOverride *string = nil
if isCompatClient {
titleOverride = langext.Ptr(app.CompatizeMessageTitle(ctx, msg))
msgidOverride = langext.Ptr(fmt.Sprintf("%d", compatMsgID))
}
fcmDelivID, err := app.DeliverMessage(ctx, client, msg, titleOverride, msgidOverride)
if err != nil { if err != nil {
_, err = app.Database.Primary.CreateRetryDelivery(ctx, client, msg) _, err = app.Database.Primary.CreateRetryDelivery(ctx, client, msg)
if err != nil { if err != nil {

View File

@ -5,7 +5,7 @@ package models
import "gogs.mikescher.com/BlackForestBytes/goext/langext" import "gogs.mikescher.com/BlackForestBytes/goext/langext"
import "gogs.mikescher.com/BlackForestBytes/goext/enums" import "gogs.mikescher.com/BlackForestBytes/goext/enums"
const ChecksumEnumGenerator = "08404cad6879118878e2b64db01bb6bf54cda9d51e3d3ff91b239e9a8459fecd" // GoExtVersion: 0.0.463 const ChecksumEnumGenerator = "5b115c5f107801af608630d2c5adce57cd4b050d176c8cd3db5c132020bf153c" // GoExtVersion: 0.0.463
// ================================ ClientType ================================ // ================================ ClientType ================================
// //

View File

@ -15,7 +15,7 @@ import "reflect"
import "regexp" import "regexp"
import "strings" import "strings"
const ChecksumCharsetIDGenerator = "08404cad6879118878e2b64db01bb6bf54cda9d51e3d3ff91b239e9a8459fecd" // GoExtVersion: 0.0.463 const ChecksumCharsetIDGenerator = "5b115c5f107801af608630d2c5adce57cd4b050d176c8cd3db5c132020bf153c" // GoExtVersion: 0.0.463
const idlen = 24 const idlen = 24

View File

@ -2,6 +2,7 @@ package models
import ( import (
"context" "context"
"fmt"
"github.com/jmoiron/sqlx" "github.com/jmoiron/sqlx"
"gogs.mikescher.com/BlackForestBytes/goext/langext" "gogs.mikescher.com/BlackForestBytes/goext/langext"
"gogs.mikescher.com/BlackForestBytes/goext/sq" "gogs.mikescher.com/BlackForestBytes/goext/sq"
@ -94,6 +95,14 @@ func (m Message) ShortContent() string {
return (*m.Content)[0:ContentLengthShort-3] + "..." return (*m.Content)[0:ContentLengthShort-3] + "..."
} }
func (m Message) FormatNotificationTitle(user User, channel Channel) string {
if m.ChannelInternalName == user.DefaultChannel() {
return m.Title
}
return fmt.Sprintf("[%s] %s", channel.DisplayName, m.Title)
}
type MessageJSON struct { type MessageJSON struct {
MessageID MessageID `json:"message_id"` MessageID MessageID `json:"message_id"`
SenderUserID UserID `json:"sender_user_id"` SenderUserID UserID `json:"sender_user_id"`

View File

@ -12,6 +12,6 @@ func NewDummy() NotificationClient {
return &DummyConnector{} return &DummyConnector{}
} }
func (d DummyConnector) SendNotification(ctx context.Context, client models.Client, msg models.Message, compatTitleOverride *string, compatMsgIDOverride *string) (string, error) { func (d DummyConnector) SendNotification(ctx context.Context, user models.User, client models.Client, channel models.Channel, msg models.Message) (string, error) {
return "%DUMMY%", nil return "%DUMMY%", nil
} }

View File

@ -11,10 +11,8 @@ import (
"fmt" "fmt"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"gogs.mikescher.com/BlackForestBytes/goext/langext"
"io" "io"
"net/http" "net/http"
"strconv"
"strings" "strings"
"time" "time"
) )
@ -53,32 +51,36 @@ type Notification struct {
Priority int Priority int
} }
func (fb FirebaseConnector) SendNotification(ctx context.Context, client models.Client, msg models.Message, compatTitleOverride *string, compatMsgIDOverride *string) (string, error) { func (fb FirebaseConnector) SendNotification(ctx context.Context, user models.User, client models.Client, channel models.Channel, msg models.Message) (string, error) {
uri := "https://fcm.googleapis.com/v1/projects/" + fb.fbProject + "/messages:send" uri := "https://fcm.googleapis.com/v1/projects/" + fb.fbProject + "/messages:send"
jsonBody := gin.H{ jsonBody := gin.H{
"data": gin.H{
"scn_msg_id": langext.Coalesce(compatMsgIDOverride, msg.MessageID.String()),
"usr_msg_id": langext.Coalesce(msg.UserMessageID, ""),
"client_id": client.ClientID.String(),
"timestamp": strconv.FormatInt(msg.Timestamp().Unix(), 10),
"priority": strconv.Itoa(msg.Priority),
"trimmed": langext.Conditional(msg.NeedsTrim(), "true", "false"),
"title": langext.Coalesce(compatTitleOverride, msg.Title),
"body": langext.Coalesce(msg.TrimmedContent(), ""),
},
"token": client.FCMToken, "token": client.FCMToken,
"android": gin.H{
"priority": "high",
},
"apns": gin.H{},
} }
if client.Type == models.ClientTypeIOS { if client.Type == models.ClientTypeIOS {
jsonBody["notification"] = gin.H{ jsonBody["notification"] = gin.H{
"title": msg.Title, "title": msg.Title,
"body": msg.ShortContent(), "body": msg.ShortContent(),
} }
jsonBody["apns"] = gin.H{}
} else if client.Type == models.ClientTypeAndroid {
jsonBody["android"] = gin.H{
"priority": "high",
"collapse_key": msg.ChannelID.String(),
"notification": gin.H{
"event_time": msg.Timestamp().Format(time.RFC3339),
"title": msg.FormatNotificationTitle(user, channel),
"body": msg.ShortContent(),
},
"fcm_options": gin.H{},
}
} else {
jsonBody["notification"] = gin.H{
"title": msg.FormatNotificationTitle(user, channel),
"body": msg.ShortContent(),
}
} }
bytesBody, err := json.Marshal(gin.H{"message": jsonBody}) bytesBody, err := json.Marshal(gin.H{"message": jsonBody})

View File

@ -6,5 +6,5 @@ import (
) )
type NotificationClient interface { type NotificationClient interface {
SendNotification(ctx context.Context, client models.Client, msg models.Message, compatTitleOverride *string, compatMsgIDOverride *string) (string, error) SendNotification(ctx context.Context, user models.User, client models.Client, channel models.Channel, msg models.Message) (string, error)
} }

View File

@ -8,10 +8,8 @@ import (
) )
type SinkData struct { type SinkData struct {
Message models.Message Message models.Message
Client models.Client Client models.Client
CompatTitleOverride *string
CompatMsgIDOverride *string
} }
type TestSink struct { type TestSink struct {
@ -26,7 +24,7 @@ func (d *TestSink) Last() SinkData {
return d.Data[len(d.Data)-1] return d.Data[len(d.Data)-1]
} }
func (d *TestSink) SendNotification(ctx context.Context, client models.Client, msg models.Message, compatTitleOverride *string, compatMsgIDOverride *string) (string, error) { func (d *TestSink) SendNotification(ctx context.Context, user models.User, client models.Client, channel models.Channel, msg models.Message) (string, error) {
id, err := langext.NewHexUUID() id, err := langext.NewHexUUID()
if err != nil { if err != nil {
return "", err return "", err
@ -35,10 +33,8 @@ func (d *TestSink) SendNotification(ctx context.Context, client models.Client, m
key := "TestSink[" + id + "]" key := "TestSink[" + id + "]"
d.Data = append(d.Data, SinkData{ d.Data = append(d.Data, SinkData{
Message: msg, Message: msg,
Client: client, Client: client,
CompatTitleOverride: compatTitleOverride,
CompatMsgIDOverride: compatMsgIDOverride,
}) })
return key, nil return key, nil

View File

@ -19,63 +19,39 @@
"parameters": [ "parameters": [
{ {
"type": "string", "type": "string",
"example": "test",
"name": "channel",
"in": "query"
},
{
"type": "string",
"example": "This is a message",
"name": "content", "name": "content",
"in": "query" "in": "query"
}, },
{ {
"type": "string", "type": "string",
"example": "P3TNH8mvv14fm",
"name": "key",
"in": "query"
},
{
"type": "string",
"example": "db8b0e6a-a08c-4646",
"name": "msg_id", "name": "msg_id",
"in": "query" "in": "query"
}, },
{ {
"enum": [
0,
1,
2
],
"type": "integer", "type": "integer",
"example": 1,
"name": "priority", "name": "priority",
"in": "query" "in": "query"
}, },
{
"type": "string",
"example": "example-server",
"name": "sender_name",
"in": "query"
},
{ {
"type": "number", "type": "number",
"example": 1669824037,
"name": "timestamp", "name": "timestamp",
"in": "query" "in": "query"
}, },
{ {
"type": "string", "type": "string",
"example": "Hello World",
"name": "title", "name": "title",
"in": "query" "in": "query"
}, },
{ {
"type": "string", "type": "integer",
"example": "7725",
"name": "user_id", "name": "user_id",
"in": "query" "in": "query"
}, },
{
"type": "string",
"name": "user_key",
"in": "query"
},
{ {
"description": " ", "description": " ",
"name": "post_body", "name": "post_body",
@ -86,62 +62,38 @@
}, },
{ {
"type": "string", "type": "string",
"example": "test",
"name": "channel",
"in": "formData"
},
{
"type": "string",
"example": "This is a message",
"name": "content", "name": "content",
"in": "formData" "in": "formData"
}, },
{ {
"type": "string", "type": "string",
"example": "P3TNH8mvv14fm",
"name": "key",
"in": "formData"
},
{
"type": "string",
"example": "db8b0e6a-a08c-4646",
"name": "msg_id", "name": "msg_id",
"in": "formData" "in": "formData"
}, },
{ {
"enum": [
0,
1,
2
],
"type": "integer", "type": "integer",
"example": 1,
"name": "priority", "name": "priority",
"in": "formData" "in": "formData"
}, },
{
"type": "string",
"example": "example-server",
"name": "sender_name",
"in": "formData"
},
{ {
"type": "number", "type": "number",
"example": 1669824037,
"name": "timestamp", "name": "timestamp",
"in": "formData" "in": "formData"
}, },
{ {
"type": "string", "type": "string",
"example": "Hello World",
"name": "title", "name": "title",
"in": "formData" "in": "formData"
}, },
{ {
"type": "string", "type": "integer",
"example": "7725",
"name": "user_id", "name": "user_id",
"in": "formData" "in": "formData"
},
{
"type": "string",
"name": "user_key",
"in": "formData"
} }
], ],
"responses": { "responses": {
@ -2615,63 +2567,39 @@
"parameters": [ "parameters": [
{ {
"type": "string", "type": "string",
"example": "test",
"name": "channel",
"in": "query"
},
{
"type": "string",
"example": "This is a message",
"name": "content", "name": "content",
"in": "query" "in": "query"
}, },
{ {
"type": "string", "type": "string",
"example": "P3TNH8mvv14fm",
"name": "key",
"in": "query"
},
{
"type": "string",
"example": "db8b0e6a-a08c-4646",
"name": "msg_id", "name": "msg_id",
"in": "query" "in": "query"
}, },
{ {
"enum": [
0,
1,
2
],
"type": "integer", "type": "integer",
"example": 1,
"name": "priority", "name": "priority",
"in": "query" "in": "query"
}, },
{
"type": "string",
"example": "example-server",
"name": "sender_name",
"in": "query"
},
{ {
"type": "number", "type": "number",
"example": 1669824037,
"name": "timestamp", "name": "timestamp",
"in": "query" "in": "query"
}, },
{ {
"type": "string", "type": "string",
"example": "Hello World",
"name": "title", "name": "title",
"in": "query" "in": "query"
}, },
{ {
"type": "string", "type": "integer",
"example": "7725",
"name": "user_id", "name": "user_id",
"in": "query" "in": "query"
}, },
{
"type": "string",
"name": "user_key",
"in": "query"
},
{ {
"description": " ", "description": " ",
"name": "post_body", "name": "post_body",
@ -2682,62 +2610,38 @@
}, },
{ {
"type": "string", "type": "string",
"example": "test",
"name": "channel",
"in": "formData"
},
{
"type": "string",
"example": "This is a message",
"name": "content", "name": "content",
"in": "formData" "in": "formData"
}, },
{ {
"type": "string", "type": "string",
"example": "P3TNH8mvv14fm",
"name": "key",
"in": "formData"
},
{
"type": "string",
"example": "db8b0e6a-a08c-4646",
"name": "msg_id", "name": "msg_id",
"in": "formData" "in": "formData"
}, },
{ {
"enum": [
0,
1,
2
],
"type": "integer", "type": "integer",
"example": 1,
"name": "priority", "name": "priority",
"in": "formData" "in": "formData"
}, },
{
"type": "string",
"example": "example-server",
"name": "sender_name",
"in": "formData"
},
{ {
"type": "number", "type": "number",
"example": 1669824037,
"name": "timestamp", "name": "timestamp",
"in": "formData" "in": "formData"
}, },
{ {
"type": "string", "type": "string",
"example": "Hello World",
"name": "title", "name": "title",
"in": "formData" "in": "formData"
}, },
{ {
"type": "string", "type": "integer",
"example": "7725",
"name": "user_id", "name": "user_id",
"in": "formData" "in": "formData"
},
{
"type": "string",
"name": "user_key",
"in": "formData"
} }
], ],
"responses": { "responses": {
@ -2785,121 +2689,73 @@
"parameters": [ "parameters": [
{ {
"type": "string", "type": "string",
"example": "test",
"name": "channel",
"in": "query"
},
{
"type": "string",
"example": "This is a message",
"name": "content", "name": "content",
"in": "query" "in": "query"
}, },
{ {
"type": "string", "type": "string",
"example": "P3TNH8mvv14fm",
"name": "key",
"in": "query"
},
{
"type": "string",
"example": "db8b0e6a-a08c-4646",
"name": "msg_id", "name": "msg_id",
"in": "query" "in": "query"
}, },
{ {
"enum": [
0,
1,
2
],
"type": "integer", "type": "integer",
"example": 1,
"name": "priority", "name": "priority",
"in": "query" "in": "query"
}, },
{
"type": "string",
"example": "example-server",
"name": "sender_name",
"in": "query"
},
{ {
"type": "number", "type": "number",
"example": 1669824037,
"name": "timestamp", "name": "timestamp",
"in": "query" "in": "query"
}, },
{ {
"type": "string", "type": "string",
"example": "Hello World",
"name": "title", "name": "title",
"in": "query" "in": "query"
}, },
{ {
"type": "string", "type": "integer",
"example": "7725",
"name": "user_id", "name": "user_id",
"in": "query" "in": "query"
}, },
{ {
"type": "string", "type": "string",
"example": "test", "name": "user_key",
"name": "channel", "in": "query"
"in": "formData"
}, },
{ {
"type": "string", "type": "string",
"example": "This is a message",
"name": "content", "name": "content",
"in": "formData" "in": "formData"
}, },
{ {
"type": "string", "type": "string",
"example": "P3TNH8mvv14fm",
"name": "key",
"in": "formData"
},
{
"type": "string",
"example": "db8b0e6a-a08c-4646",
"name": "msg_id", "name": "msg_id",
"in": "formData" "in": "formData"
}, },
{ {
"enum": [
0,
1,
2
],
"type": "integer", "type": "integer",
"example": 1,
"name": "priority", "name": "priority",
"in": "formData" "in": "formData"
}, },
{
"type": "string",
"example": "example-server",
"name": "sender_name",
"in": "formData"
},
{ {
"type": "number", "type": "number",
"example": 1669824037,
"name": "timestamp", "name": "timestamp",
"in": "formData" "in": "formData"
}, },
{ {
"type": "string", "type": "string",
"example": "Hello World",
"name": "title", "name": "title",
"in": "formData" "in": "formData"
}, },
{ {
"type": "string", "type": "integer",
"example": "7725",
"name": "user_id", "name": "user_id",
"in": "formData" "in": "formData"
},
{
"type": "string",
"name": "user_key",
"in": "formData"
} }
], ],
"responses": { "responses": {
@ -3395,46 +3251,26 @@
"handler.SendMessage.combined": { "handler.SendMessage.combined": {
"type": "object", "type": "object",
"properties": { "properties": {
"channel": {
"type": "string",
"example": "test"
},
"content": { "content": {
"type": "string", "type": "string"
"example": "This is a message"
},
"key": {
"type": "string",
"example": "P3TNH8mvv14fm"
}, },
"msg_id": { "msg_id": {
"type": "string", "type": "string"
"example": "db8b0e6a-a08c-4646"
}, },
"priority": { "priority": {
"type": "integer", "type": "integer"
"enum": [
0,
1,
2
],
"example": 1
},
"sender_name": {
"type": "string",
"example": "example-server"
}, },
"timestamp": { "timestamp": {
"type": "number", "type": "number"
"example": 1669824037
}, },
"title": { "title": {
"type": "string", "type": "string"
"example": "Hello World"
}, },
"user_id": { "user_id": {
"type": "string", "type": "integer"
"example": "7725" },
"user_key": {
"type": "string"
} }
} }
}, },
@ -3463,7 +3299,7 @@
"type": "integer" "type": "integer"
}, },
"scn_msg_id": { "scn_msg_id": {
"type": "string" "type": "integer"
}, },
"success": { "success": {
"type": "boolean" "type": "boolean"

View File

@ -327,36 +327,19 @@ definitions:
type: object type: object
handler.SendMessage.combined: handler.SendMessage.combined:
properties: properties:
channel:
example: test
type: string
content: content:
example: This is a message
type: string
key:
example: P3TNH8mvv14fm
type: string type: string
msg_id: msg_id:
example: db8b0e6a-a08c-4646
type: string type: string
priority: priority:
enum:
- 0
- 1
- 2
example: 1
type: integer type: integer
sender_name:
example: example-server
type: string
timestamp: timestamp:
example: 1669824037
type: number type: number
title: title:
example: Hello World
type: string type: string
user_id: user_id:
example: "7725" type: integer
user_key:
type: string type: string
type: object type: object
handler.SendMessage.response: handler.SendMessage.response:
@ -376,7 +359,7 @@ definitions:
quota_max: quota_max:
type: integer type: integer
scn_msg_id: scn_msg_id:
type: string type: integer
success: success:
type: boolean type: boolean
suppress_send: suppress_send:
@ -765,90 +748,52 @@ paths:
description: All parameter can be set via query-parameter or the json body. description: All parameter can be set via query-parameter or the json body.
Only UserID, UserKey and Title are required Only UserID, UserKey and Title are required
parameters: parameters:
- example: test - in: query
in: query
name: channel
type: string
- example: This is a message
in: query
name: content name: content
type: string type: string
- example: P3TNH8mvv14fm - in: query
in: query
name: key
type: string
- example: db8b0e6a-a08c-4646
in: query
name: msg_id name: msg_id
type: string type: string
- enum: - in: query
- 0
- 1
- 2
example: 1
in: query
name: priority name: priority
type: integer type: integer
- example: example-server - in: query
in: query
name: sender_name
type: string
- example: 1669824037
in: query
name: timestamp name: timestamp
type: number type: number
- example: Hello World - in: query
in: query
name: title name: title
type: string type: string
- example: "7725" - in: query
in: query
name: user_id name: user_id
type: integer
- in: query
name: user_key
type: string type: string
- description: ' ' - description: ' '
in: body in: body
name: post_body name: post_body
schema: schema:
$ref: '#/definitions/handler.SendMessage.combined' $ref: '#/definitions/handler.SendMessage.combined'
- example: test - in: formData
in: formData
name: channel
type: string
- example: This is a message
in: formData
name: content name: content
type: string type: string
- example: P3TNH8mvv14fm - in: formData
in: formData
name: key
type: string
- example: db8b0e6a-a08c-4646
in: formData
name: msg_id name: msg_id
type: string type: string
- enum: - in: formData
- 0
- 1
- 2
example: 1
in: formData
name: priority name: priority
type: integer type: integer
- example: example-server - in: formData
in: formData
name: sender_name
type: string
- example: 1669824037
in: formData
name: timestamp name: timestamp
type: number type: number
- example: Hello World - in: formData
in: formData
name: title name: title
type: string type: string
- example: "7725" - in: formData
in: formData
name: user_id name: user_id
type: integer
- in: formData
name: user_key
type: string type: string
responses: responses:
"200": "200":
@ -2546,90 +2491,52 @@ paths:
description: All parameter can be set via query-parameter or the json body. description: All parameter can be set via query-parameter or the json body.
Only UserID, UserKey and Title are required Only UserID, UserKey and Title are required
parameters: parameters:
- example: test - in: query
in: query
name: channel
type: string
- example: This is a message
in: query
name: content name: content
type: string type: string
- example: P3TNH8mvv14fm - in: query
in: query
name: key
type: string
- example: db8b0e6a-a08c-4646
in: query
name: msg_id name: msg_id
type: string type: string
- enum: - in: query
- 0
- 1
- 2
example: 1
in: query
name: priority name: priority
type: integer type: integer
- example: example-server - in: query
in: query
name: sender_name
type: string
- example: 1669824037
in: query
name: timestamp name: timestamp
type: number type: number
- example: Hello World - in: query
in: query
name: title name: title
type: string type: string
- example: "7725" - in: query
in: query
name: user_id name: user_id
type: integer
- in: query
name: user_key
type: string type: string
- description: ' ' - description: ' '
in: body in: body
name: post_body name: post_body
schema: schema:
$ref: '#/definitions/handler.SendMessage.combined' $ref: '#/definitions/handler.SendMessage.combined'
- example: test - in: formData
in: formData
name: channel
type: string
- example: This is a message
in: formData
name: content name: content
type: string type: string
- example: P3TNH8mvv14fm - in: formData
in: formData
name: key
type: string
- example: db8b0e6a-a08c-4646
in: formData
name: msg_id name: msg_id
type: string type: string
- enum: - in: formData
- 0
- 1
- 2
example: 1
in: formData
name: priority name: priority
type: integer type: integer
- example: example-server - in: formData
in: formData
name: sender_name
type: string
- example: 1669824037
in: formData
name: timestamp name: timestamp
type: number type: number
- example: Hello World - in: formData
in: formData
name: title name: title
type: string type: string
- example: "7725" - in: formData
in: formData
name: user_id name: user_id
type: integer
- in: formData
name: user_key
type: string type: string
responses: responses:
"200": "200":
@ -2662,85 +2569,47 @@ paths:
description: All parameter can be set via query-parameter or form-data body. description: All parameter can be set via query-parameter or form-data body.
Only UserID, UserKey and Title are required Only UserID, UserKey and Title are required
parameters: parameters:
- example: test - in: query
in: query
name: channel
type: string
- example: This is a message
in: query
name: content name: content
type: string type: string
- example: P3TNH8mvv14fm - in: query
in: query
name: key
type: string
- example: db8b0e6a-a08c-4646
in: query
name: msg_id name: msg_id
type: string type: string
- enum: - in: query
- 0
- 1
- 2
example: 1
in: query
name: priority name: priority
type: integer type: integer
- example: example-server - in: query
in: query
name: sender_name
type: string
- example: 1669824037
in: query
name: timestamp name: timestamp
type: number type: number
- example: Hello World - in: query
in: query
name: title name: title
type: string type: string
- example: "7725" - in: query
in: query
name: user_id name: user_id
type: integer
- in: query
name: user_key
type: string type: string
- example: test - in: formData
in: formData
name: channel
type: string
- example: This is a message
in: formData
name: content name: content
type: string type: string
- example: P3TNH8mvv14fm - in: formData
in: formData
name: key
type: string
- example: db8b0e6a-a08c-4646
in: formData
name: msg_id name: msg_id
type: string type: string
- enum: - in: formData
- 0
- 1
- 2
example: 1
in: formData
name: priority name: priority
type: integer type: integer
- example: example-server - in: formData
in: formData
name: sender_name
type: string
- example: 1669824037
in: formData
name: timestamp name: timestamp
type: number type: number
- example: Hello World - in: formData
in: formData
name: title name: title
type: string type: string
- example: "7725" - in: formData
in: formData
name: user_id name: user_id
type: integer
- in: formData
name: user_key
type: string type: string
responses: responses:
"200": "200":

View File

@ -704,44 +704,6 @@ func TestCompatRequery(t *testing.T) {
} }
func TestCompatTitlePatch(t *testing.T) {
ws, baseUrl, stop := tt.StartSimpleWebserver(t)
defer stop()
pusher := ws.Pusher.(*push.TestSink)
r0 := tt.RequestPost[gin.H](t, baseUrl, "/api/v2/users", gin.H{
"agent_model": "DUMMY_PHONE",
"agent_version": "4X",
"client_type": "ANDROID",
"fcm_token": "DUMMY_FCM",
})
uid := r0["user_id"].(string)
admintok := r0["admin_key"].(string)
sendtok := r0["send_key"].(string)
type clientlist struct {
Clients []gin.H `json:"clients"`
}
clist1 := tt.RequestAuthGet[clientlist](t, admintok, baseUrl, fmt.Sprintf("/api/v2/users/%s/clients", url.QueryEscape(uid)))
tt.SetCompatClient(t, ws, clist1.Clients[0]["client_id"].(string))
_ = tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{
"key": sendtok,
"user_id": uid,
"title": "HelloWorld_001",
"channel": "TestChan",
})
tt.AssertEqual(t, "messageCount", 1, len(pusher.Data))
tt.AssertStrRepEqual(t, "msg.title", "HelloWorld_001", pusher.Last().Message.Title)
tt.AssertStrRepEqual(t, "msg.ovrTitle", "[TestChan] HelloWorld_001", pusher.Last().CompatTitleOverride)
}
func TestCompatAckCount(t *testing.T) { func TestCompatAckCount(t *testing.T) {
_, baseUrl, stop := tt.StartSimpleWebserver(t) _, baseUrl, stop := tt.StartSimpleWebserver(t)
defer stop() defer stop()

View File

@ -2,7 +2,6 @@ package util
import ( import (
"blackforestbytes.com/simplecloudnotifier/logic" "blackforestbytes.com/simplecloudnotifier/logic"
"gogs.mikescher.com/BlackForestBytes/goext/sq"
"testing" "testing"
"time" "time"
) )
@ -65,14 +64,3 @@ func CreateCompatID(t *testing.T, ws *logic.Application, idtype string, newid st
return uidold return uidold
} }
func SetCompatClient(t *testing.T, ws *logic.Application, cid string) {
ctx := ws.NewSimpleTransactionContext(5 * time.Second)
defer ctx.Cancel()
_, err := ws.Database.Primary.DB().Exec(ctx, "INSERT INTO compat_clients (client_id) VALUES (:cid)", sq.PP{"cid": cid})
TestFailIfErr(t, err)
err = ctx.CommitTransaction()
TestFailIfErr(t, err)
}