Compare commits
23 Commits
backend-re
...
v2.0.0
Author | SHA1 | Date | |
---|---|---|---|
1bb37eec30
|
|||
59511b2345
|
|||
5b7bc02c61
|
|||
b329f537e7
|
|||
5879e81759
|
|||
f4e88bef77
|
|||
b3ec45309c
|
|||
2fbc892898
|
|||
c46190c3fc
|
|||
860e540de1
|
|||
8cde286cac
|
|||
90830fe384
|
|||
686f89f75d
|
|||
4210af5680
|
|||
aefc368cfd
|
|||
67218d8045
|
|||
c05deb3a41
|
|||
43d0107fb5
|
|||
ece7612f9d
|
|||
a9809d90cb
|
|||
bbc9a79996
|
|||
b71f1885ec
|
|||
885aad2047
|
6
scnserver/.gitignore
vendored
6
scnserver/.gitignore
vendored
@@ -8,6 +8,12 @@ DOCKER_GIT_INFO
|
|||||||
scn_export.dat
|
scn_export.dat
|
||||||
scn_export.json
|
scn_export.json
|
||||||
|
|
||||||
|
scn_export_*.dat
|
||||||
|
scn_export_*.json
|
||||||
|
|
||||||
|
simple_cloud_notifier-202306172202.sql
|
||||||
|
simple_cloud_notifier-*.sql
|
||||||
|
|
||||||
identifier.sqlite
|
identifier.sqlite
|
||||||
|
|
||||||
.idea/dataSources.xml
|
.idea/dataSources.xml
|
||||||
|
@@ -5,7 +5,7 @@ PORT=9090
|
|||||||
NAMESPACE=$(shell git rev-parse --abbrev-ref HEAD)
|
NAMESPACE=$(shell git rev-parse --abbrev-ref HEAD)
|
||||||
HASH=$(shell git rev-parse HEAD)
|
HASH=$(shell git rev-parse HEAD)
|
||||||
|
|
||||||
.PHONY: test swagger pygmentize docker migrate dgi pygmentize lint
|
.PHONY: test swagger pygmentize docker migrate dgi pygmentize lint docker
|
||||||
|
|
||||||
build: swagger pygmentize fmt
|
build: swagger pygmentize fmt
|
||||||
mkdir -p _build
|
mkdir -p _build
|
||||||
@@ -29,7 +29,7 @@ dgi:
|
|||||||
echo -n "COMMITTIME=" >> DOCKER_GIT_INFO ; git log -1 --format=%cd --date=iso >> DOCKER_GIT_INFO
|
echo -n "COMMITTIME=" >> DOCKER_GIT_INFO ; git log -1 --format=%cd --date=iso >> DOCKER_GIT_INFO
|
||||||
echo -n "REMOTE=" >> DOCKER_GIT_INFO ; git config --get remote.origin.url >> DOCKER_GIT_INFO
|
echo -n "REMOTE=" >> DOCKER_GIT_INFO ; git config --get remote.origin.url >> DOCKER_GIT_INFO
|
||||||
|
|
||||||
build-docker: dgi
|
docker: dgi
|
||||||
docker build \
|
docker build \
|
||||||
-t "$(DOCKER_NAME):$(HASH)" \
|
-t "$(DOCKER_NAME):$(HASH)" \
|
||||||
-t "$(DOCKER_NAME):$(NAMESPACE)-latest" \
|
-t "$(DOCKER_NAME):$(NAMESPACE)-latest" \
|
||||||
|
@@ -6,15 +6,9 @@
|
|||||||
|
|
||||||
#### BEFORE RELEASE
|
#### BEFORE RELEASE
|
||||||
|
|
||||||
- migrate old data
|
|
||||||
|
|
||||||
- in my script: use `srvname` for sendername
|
|
||||||
|
|
||||||
- switch send script everywhere (we can use the new server, but we need to send correct channels)
|
|
||||||
|
|
||||||
- app-store link in HTML
|
- app-store link in HTML
|
||||||
|
|
||||||
- deploy
|
- backups (no longer container in my db_backup, perhaps extend it to sqlite?)
|
||||||
|
|
||||||
- ios purchase verification
|
- ios purchase verification
|
||||||
|
|
||||||
@@ -30,6 +24,8 @@
|
|||||||
|
|
||||||
- (?) add querylog (similar to requestlog/errorlog) - only for main-db
|
- (?) add querylog (similar to requestlog/errorlog) - only for main-db
|
||||||
|
|
||||||
|
- (?) specify 'type' of message (debug, info, warn, error, fatal) -> distinct from priority
|
||||||
|
|
||||||
#### LATER
|
#### LATER
|
||||||
|
|
||||||
- do i need bool2db()? it seems to work for keytokens without them?
|
- do i need bool2db()? it seems to work for keytokens without them?
|
||||||
|
@@ -68,6 +68,12 @@ func Wrap(rlacc RequestLogAcceptor, fn WHandlerFunc) gin.HandlerFunc {
|
|||||||
if scn.Conf.ReqLogEnabled {
|
if scn.Conf.ReqLogEnabled {
|
||||||
rlacc.InsertRequestLog(createRequestLog(g, t0, ctr, wrap, nil))
|
rlacc.InsertRequestLog(createRequestLog(g, t0, ctr, wrap, nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
statuscode := wrap.Statuscode()
|
||||||
|
if statuscode/100 != 2 {
|
||||||
|
log.Warn().Str("url", g.Request.Method+"::"+g.Request.URL.String()).Msg(fmt.Sprintf("Request failed with statuscode %d", statuscode))
|
||||||
|
}
|
||||||
|
|
||||||
wrap.Write(g)
|
wrap.Write(g)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -45,12 +45,12 @@ func (h APIHandler) ListUserKeys(g *gin.Context) ginresp.HTTPResponse {
|
|||||||
return *permResp
|
return *permResp
|
||||||
}
|
}
|
||||||
|
|
||||||
clients, err := h.database.ListKeyTokens(ctx, u.UserID)
|
toks, err := h.database.ListKeyTokens(ctx, u.UserID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to query keys", err)
|
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to query keys", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
res := langext.ArrMap(clients, func(v models.KeyToken) models.KeyTokenJSON { return v.JSON() })
|
res := langext.ArrMap(toks, func(v models.KeyToken) models.KeyTokenJSON { return v.JSON() })
|
||||||
|
|
||||||
return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, response{Keys: res}))
|
return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, response{Keys: res}))
|
||||||
}
|
}
|
||||||
@@ -221,9 +221,9 @@ func (h APIHandler) CreateUserKey(g *gin.Context) ginresp.HTTPResponse {
|
|||||||
}
|
}
|
||||||
type body struct {
|
type body struct {
|
||||||
Name string `json:"name" binding:"required"`
|
Name string `json:"name" binding:"required"`
|
||||||
AllChannels *bool `json:"all_channels" binding:"required"`
|
Permissions string `json:"permissions" binding:"required"`
|
||||||
Channels *[]models.ChannelID `json:"channels" binding:"required"`
|
AllChannels *bool `json:"all_channels"`
|
||||||
Permissions *string `json:"permissions" binding:"required"`
|
Channels *[]models.ChannelID `json:"channels"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var u uri
|
var u uri
|
||||||
@@ -234,7 +234,18 @@ func (h APIHandler) CreateUserKey(g *gin.Context) ginresp.HTTPResponse {
|
|||||||
}
|
}
|
||||||
defer ctx.Cancel()
|
defer ctx.Cancel()
|
||||||
|
|
||||||
for _, c := range *b.Channels {
|
channels := langext.Coalesce(b.Channels, make([]models.ChannelID, 0))
|
||||||
|
|
||||||
|
var allChan bool
|
||||||
|
if b.AllChannels == nil && b.Channels != nil {
|
||||||
|
allChan = false
|
||||||
|
} else if b.AllChannels == nil && b.Channels == nil {
|
||||||
|
allChan = true
|
||||||
|
} else {
|
||||||
|
allChan = *b.AllChannels
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range channels {
|
||||||
if err := c.Valid(); err != nil {
|
if err := c.Valid(); err != nil {
|
||||||
return ginresp.APIError(g, 400, apierr.INVALID_BODY_PARAM, "Invalid ChannelID", err)
|
return ginresp.APIError(g, 400, apierr.INVALID_BODY_PARAM, "Invalid ChannelID", err)
|
||||||
}
|
}
|
||||||
@@ -246,9 +257,9 @@ func (h APIHandler) CreateUserKey(g *gin.Context) ginresp.HTTPResponse {
|
|||||||
|
|
||||||
token := h.app.GenerateRandomAuthKey()
|
token := h.app.GenerateRandomAuthKey()
|
||||||
|
|
||||||
perms := models.ParseTokenPermissionList(*b.Permissions)
|
perms := models.ParseTokenPermissionList(b.Permissions)
|
||||||
|
|
||||||
keytok, err := h.database.CreateKeyToken(ctx, b.Name, *ctx.GetPermissionUserID(), *b.AllChannels, *b.Channels, perms, token)
|
keytok, err := h.database.CreateKeyToken(ctx, b.Name, *ctx.GetPermissionUserID(), allChan, channels, perms, token)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to create keytoken in db", err)
|
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to create keytoken in db", err)
|
||||||
}
|
}
|
||||||
|
@@ -5,7 +5,9 @@ import (
|
|||||||
"blackforestbytes.com/simplecloudnotifier/api/ginresp"
|
"blackforestbytes.com/simplecloudnotifier/api/ginresp"
|
||||||
"blackforestbytes.com/simplecloudnotifier/models"
|
"blackforestbytes.com/simplecloudnotifier/models"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
"gogs.mikescher.com/BlackForestBytes/goext/langext"
|
"gogs.mikescher.com/BlackForestBytes/goext/langext"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
@@ -113,6 +115,8 @@ func (h APIHandler) CreateUser(g *gin.Context) ginresp.HTTPResponse {
|
|||||||
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to create read-key in db", err)
|
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to create read-key in db", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Info().Msg(fmt.Sprintf("Sucessfully created new user %s (client: %v)", userobj.UserID, b.NoClient))
|
||||||
|
|
||||||
if b.NoClient {
|
if b.NoClient {
|
||||||
return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, userobj.JSONWithClients(make([]models.Client, 0), adminKey, sendKey, readKey)))
|
return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, userobj.JSONWithClients(make([]models.Client, 0), adminKey, sendKey, readKey)))
|
||||||
} else {
|
} else {
|
||||||
|
@@ -258,7 +258,7 @@ func (h CompatHandler) Info(g *gin.Context) ginresp.HTTPResponse {
|
|||||||
QuotaMax int `json:"quota_max"`
|
QuotaMax int `json:"quota_max"`
|
||||||
IsPro int `json:"is_pro"`
|
IsPro int `json:"is_pro"`
|
||||||
FCMSet bool `json:"fcm_token_set"`
|
FCMSet bool `json:"fcm_token_set"`
|
||||||
UnackCount int `json:"unack_count"`
|
UnackCount int64 `json:"unack_count"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var datq query
|
var datq query
|
||||||
@@ -310,6 +310,16 @@ func (h CompatHandler) Info(g *gin.Context) ginresp.HTTPResponse {
|
|||||||
return ginresp.CompatAPIError(0, "Failed to query clients")
|
return ginresp.CompatAPIError(0, "Failed to query clients")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
filter := models.MessageFilter{
|
||||||
|
Owner: langext.Ptr([]models.UserID{user.UserID}),
|
||||||
|
CompatAcknowledged: langext.Ptr(false),
|
||||||
|
}
|
||||||
|
|
||||||
|
unackCount, err := h.database.CountMessages(ctx, filter)
|
||||||
|
if err != nil {
|
||||||
|
return ginresp.CompatAPIError(0, "Failed to query user")
|
||||||
|
}
|
||||||
|
|
||||||
return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, response{
|
return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, response{
|
||||||
Success: true,
|
Success: true,
|
||||||
Message: "ok",
|
Message: "ok",
|
||||||
@@ -319,7 +329,7 @@ func (h CompatHandler) Info(g *gin.Context) ginresp.HTTPResponse {
|
|||||||
QuotaMax: user.QuotaPerDay(),
|
QuotaMax: user.QuotaPerDay(),
|
||||||
IsPro: langext.Conditional(user.IsPro, 1, 0),
|
IsPro: langext.Conditional(user.IsPro, 1, 0),
|
||||||
FCMSet: len(clients) > 0,
|
FCMSet: len(clients) > 0,
|
||||||
UnackCount: 0,
|
UnackCount: unackCount,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -381,7 +391,7 @@ func (h CompatHandler) Ack(g *gin.Context) ginresp.HTTPResponse {
|
|||||||
return ginresp.SendAPIError(g, 500, apierr.DATABASE_ERROR, hl.NONE, "Failed to query userid<old>", err)
|
return ginresp.SendAPIError(g, 500, apierr.DATABASE_ERROR, hl.NONE, "Failed to query userid<old>", err)
|
||||||
}
|
}
|
||||||
if useridCompNew == nil {
|
if useridCompNew == nil {
|
||||||
return ginresp.SendAPIError(g, 400, apierr.USER_NOT_FOUND, hl.USER_ID, "User not found (compat)", nil)
|
return ginresp.SendAPIError(g, 400, apierr.USER_NOT_FOUND, hl.USER_ID, fmt.Sprintf("User %d not found (compat)", *data.UserID), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err := h.database.GetUser(ctx, models.UserID(*useridCompNew))
|
user, err := h.database.GetUser(ctx, models.UserID(*useridCompNew))
|
||||||
@@ -407,8 +417,8 @@ func (h CompatHandler) Ack(g *gin.Context) ginresp.HTTPResponse {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return ginresp.SendAPIError(g, 500, apierr.DATABASE_ERROR, hl.NONE, "Failed to query messageid<old>", err)
|
return ginresp.SendAPIError(g, 500, apierr.DATABASE_ERROR, hl.NONE, "Failed to query messageid<old>", err)
|
||||||
}
|
}
|
||||||
if useridCompNew == nil {
|
if messageIdComp == nil {
|
||||||
return ginresp.SendAPIError(g, 400, apierr.MESSAGE_NOT_FOUND, hl.USER_ID, "Message not found (compat)", nil)
|
return ginresp.SendAPIError(g, 400, apierr.MESSAGE_NOT_FOUND, hl.NONE, fmt.Sprintf("Message %d not found (compat)", *data.MessageID), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
ackBefore, err := h.database.GetAck(ctx, models.MessageID(*messageIdComp))
|
ackBefore, err := h.database.GetAck(ctx, models.MessageID(*messageIdComp))
|
||||||
@@ -524,7 +534,7 @@ func (h CompatHandler) Requery(g *gin.Context) ginresp.HTTPResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
compMsgs = append(compMsgs, models.CompatMessage{
|
compMsgs = append(compMsgs, models.CompatMessage{
|
||||||
Title: compatizeMessageTitle(ctx, h.app, v),
|
Title: h.app.CompatizeMessageTitle(ctx, v),
|
||||||
Body: v.Content,
|
Body: v.Content,
|
||||||
Priority: v.Priority,
|
Priority: v.Priority,
|
||||||
Timestamp: v.Timestamp().Unix(),
|
Timestamp: v.Timestamp().Unix(),
|
||||||
@@ -772,7 +782,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: compatizeMessageTitle(ctx, h.app, msg),
|
Title: h.app.CompatizeMessageTitle(ctx, msg),
|
||||||
Body: msg.Content,
|
Body: msg.Content,
|
||||||
Trimmed: langext.Ptr(false),
|
Trimmed: langext.Ptr(false),
|
||||||
Priority: msg.Priority,
|
Priority: msg.Priority,
|
||||||
@@ -919,16 +929,3 @@ func (h CompatHandler) Upgrade(g *gin.Context) ginresp.HTTPResponse {
|
|||||||
IsPro: user.IsPro,
|
IsPro: user.IsPro,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
func compatizeMessageTitle(ctx *logic.AppContext, app *logic.Application, msg models.Message) string {
|
|
||||||
if msg.ChannelInternalName == "main" {
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
@@ -10,6 +10,7 @@ import (
|
|||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
"gogs.mikescher.com/BlackForestBytes/goext/dataext"
|
"gogs.mikescher.com/BlackForestBytes/goext/dataext"
|
||||||
"gogs.mikescher.com/BlackForestBytes/goext/langext"
|
"gogs.mikescher.com/BlackForestBytes/goext/langext"
|
||||||
"gogs.mikescher.com/BlackForestBytes/goext/mathext"
|
"gogs.mikescher.com/BlackForestBytes/goext/mathext"
|
||||||
@@ -238,7 +239,7 @@ func (h MessageHandler) sendMessageInternal(g *gin.Context, ctx *logic.AppContex
|
|||||||
return nil, langext.Ptr(ginresp.SendAPIError(g, 500, apierr.DATABASE_ERROR, hl.NONE, "Failed to create message in db", err))
|
return nil, langext.Ptr(ginresp.SendAPIError(g, 500, apierr.DATABASE_ERROR, hl.NONE, "Failed to create message in db", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
cid, err := h.database.CreateCompatID(ctx, "messageid", msg.MessageID.String())
|
compatMsgID, err := h.database.CreateCompatID(ctx, "messageid", msg.MessageID.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, langext.Ptr(ginresp.SendAPIError(g, 500, apierr.DATABASE_ERROR, hl.NONE, "Failed to create compat-id", err))
|
return nil, langext.Ptr(ginresp.SendAPIError(g, 500, apierr.DATABASE_ERROR, hl.NONE, "Failed to create compat-id", err))
|
||||||
}
|
}
|
||||||
@@ -263,6 +264,8 @@ func (h MessageHandler) sendMessageInternal(g *gin.Context, ctx *logic.AppContex
|
|||||||
return nil, langext.Ptr(ginresp.SendAPIError(g, 500, apierr.DATABASE_ERROR, hl.NONE, "Failed to inc token msg-counter", err))
|
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", msg.MessageID, UserID))
|
||||||
|
|
||||||
for _, sub := range subscriptions {
|
for _, sub := range subscriptions {
|
||||||
clients, err := h.database.ListClients(ctx, sub.SubscriberUserID)
|
clients, err := h.database.ListClients(ctx, sub.SubscriberUserID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -281,11 +284,13 @@ func (h MessageHandler) sendMessageInternal(g *gin.Context, ctx *logic.AppContex
|
|||||||
}
|
}
|
||||||
|
|
||||||
var titleOverride *string = nil
|
var titleOverride *string = nil
|
||||||
|
var msgidOverride *string = nil
|
||||||
if isCompatClient {
|
if isCompatClient {
|
||||||
titleOverride = langext.Ptr(compatizeMessageTitle(ctx, h.app, msg))
|
titleOverride = langext.Ptr(h.app.CompatizeMessageTitle(ctx, msg))
|
||||||
|
msgidOverride = langext.Ptr(fmt.Sprintf("%d", compatMsgID))
|
||||||
}
|
}
|
||||||
|
|
||||||
fcmDelivID, err := h.app.DeliverMessage(ctx, client, msg, titleOverride)
|
fcmDelivID, err := h.app.DeliverMessage(ctx, client, msg, titleOverride, msgidOverride)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_, err = h.database.CreateRetryDelivery(ctx, client, msg)
|
_, err = h.database.CreateRetryDelivery(ctx, client, msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -305,6 +310,6 @@ func (h MessageHandler) sendMessageInternal(g *gin.Context, ctx *logic.AppContex
|
|||||||
User: user,
|
User: user,
|
||||||
Message: msg,
|
Message: msg,
|
||||||
MessageIsOld: false,
|
MessageIsOld: false,
|
||||||
CompatMessageID: cid,
|
CompatMessageID: compatMsgID,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
@@ -40,7 +40,7 @@ func NewRouter(app *logic.Application) *Router {
|
|||||||
// @title SimpleCloudNotifier API
|
// @title SimpleCloudNotifier API
|
||||||
// @version 2.0
|
// @version 2.0
|
||||||
// @description API for SCN
|
// @description API for SCN
|
||||||
// @host scn.blackforestbytes.com
|
// @host simplecloudnotifier.de
|
||||||
//
|
//
|
||||||
// @tag.name External
|
// @tag.name External
|
||||||
// @tag.name API-v1
|
// @tag.name API-v1
|
||||||
|
@@ -13,6 +13,7 @@ import (
|
|||||||
"gogs.mikescher.com/BlackForestBytes/goext/langext"
|
"gogs.mikescher.com/BlackForestBytes/goext/langext"
|
||||||
"gogs.mikescher.com/BlackForestBytes/goext/rext"
|
"gogs.mikescher.com/BlackForestBytes/goext/rext"
|
||||||
"gogs.mikescher.com/BlackForestBytes/goext/sq"
|
"gogs.mikescher.com/BlackForestBytes/goext/sq"
|
||||||
|
"gogs.mikescher.com/BlackForestBytes/goext/termext"
|
||||||
"os"
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -89,9 +90,10 @@ func main() {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(os.Stdin)
|
||||||
|
|
||||||
connstr := os.Getenv("SQL_CONN_STR")
|
connstr := os.Getenv("SQL_CONN_STR")
|
||||||
if connstr == "" {
|
if connstr == "" {
|
||||||
scanner := bufio.NewScanner(os.Stdin)
|
|
||||||
|
|
||||||
fmt.Print("Enter DB URL [127.0.0.1:3306]: ")
|
fmt.Print("Enter DB URL [127.0.0.1:3306]: ")
|
||||||
scanner.Scan()
|
scanner.Scan()
|
||||||
@@ -103,21 +105,33 @@ func main() {
|
|||||||
fmt.Print("Enter DB Username [root]: ")
|
fmt.Print("Enter DB Username [root]: ")
|
||||||
scanner.Scan()
|
scanner.Scan()
|
||||||
username := scanner.Text()
|
username := scanner.Text()
|
||||||
if host == "" {
|
if username == "" {
|
||||||
host = "root"
|
username = "root"
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Print("Enter DB Password []: ")
|
fmt.Print("Enter DB Password []: ")
|
||||||
scanner.Scan()
|
scanner.Scan()
|
||||||
pass := scanner.Text()
|
pass := scanner.Text()
|
||||||
if host == "" {
|
if pass == "" {
|
||||||
host = ""
|
pass = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
connstr = fmt.Sprintf("%s:%s@tcp(%s)", username, pass, host)
|
connstr = fmt.Sprintf("%s:%s@tcp(%s)", username, pass, host)
|
||||||
}
|
}
|
||||||
|
|
||||||
_dbold, err := sqlx.Open("mysql", connstr+"/simple_cloud_notifier?parseTime=true")
|
olddbname := os.Getenv("SQL_CONN_DBNAME")
|
||||||
|
if olddbname == "" {
|
||||||
|
|
||||||
|
fmt.Print("Enter DB Name: ")
|
||||||
|
scanner.Scan()
|
||||||
|
olddbname = scanner.Text()
|
||||||
|
if olddbname == "" {
|
||||||
|
olddbname = "scn_final"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
_dbold, err := sqlx.Open("mysql", connstr+"/"+olddbname+"?parseTime=true")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -292,8 +306,8 @@ func migrateUser(ctx context.Context, dbnew sq.DB, dbold sq.DB, user OldUser, ap
|
|||||||
|
|
||||||
_, err = dbnew.Exec(ctx, "INSERT INTO subscriptions (subscription_id, subscriber_user_id, channel_owner_user_id, channel_internal_name, channel_id, timestamp_created, confirmed) VALUES (:sid, :suid, :ouid, :cnam, :cid, :ts, :conf)", sq.PP{
|
_, err = dbnew.Exec(ctx, "INSERT INTO subscriptions (subscription_id, subscriber_user_id, channel_owner_user_id, channel_internal_name, channel_id, timestamp_created, confirmed) VALUES (:sid, :suid, :ouid, :cnam, :cid, :ts, :conf)", sq.PP{
|
||||||
"sid": models.NewSubscriptionID(),
|
"sid": models.NewSubscriptionID(),
|
||||||
"suid": user.UserId,
|
"suid": userid,
|
||||||
"ouid": user.UserId,
|
"ouid": userid,
|
||||||
"cnam": "main",
|
"cnam": "main",
|
||||||
"cid": mainChannelID,
|
"cid": mainChannelID,
|
||||||
"ts": user.TimestampCreated.UnixMilli(),
|
"ts": user.TimestampCreated.UnixMilli(),
|
||||||
@@ -340,7 +354,7 @@ func migrateUser(ctx context.Context, dbnew sq.DB, dbold sq.DB, user OldUser, ap
|
|||||||
dispName := dummyApp.NormalizeChannelDisplayName(chanNameTitle)
|
dispName := dummyApp.NormalizeChannelDisplayName(chanNameTitle)
|
||||||
intName := dummyApp.NormalizeChannelInternalName(chanNameTitle)
|
intName := dummyApp.NormalizeChannelInternalName(chanNameTitle)
|
||||||
|
|
||||||
if v, ok := channelMap[intName]; ok {
|
if v, ok := channelMap[strings.ToLower(intName)]; ok {
|
||||||
channelID = v
|
channelID = v
|
||||||
channelInternalName = intName
|
channelInternalName = intName
|
||||||
} else {
|
} else {
|
||||||
@@ -363,8 +377,8 @@ func migrateUser(ctx context.Context, dbnew sq.DB, dbold sq.DB, user OldUser, ap
|
|||||||
|
|
||||||
_, err = dbnew.Exec(ctx, "INSERT INTO subscriptions (subscription_id, subscriber_user_id, channel_owner_user_id, channel_internal_name, channel_id, timestamp_created, confirmed) VALUES (:sid, :suid, :ouid, :cnam, :cid, :ts, :conf)", sq.PP{
|
_, err = dbnew.Exec(ctx, "INSERT INTO subscriptions (subscription_id, subscriber_user_id, channel_owner_user_id, channel_internal_name, channel_id, timestamp_created, confirmed) VALUES (:sid, :suid, :ouid, :cnam, :cid, :ts, :conf)", sq.PP{
|
||||||
"sid": models.NewSubscriptionID(),
|
"sid": models.NewSubscriptionID(),
|
||||||
"suid": user.UserId,
|
"suid": userid,
|
||||||
"ouid": user.UserId,
|
"ouid": userid,
|
||||||
"cnam": intName,
|
"cnam": intName,
|
||||||
"cid": channelID,
|
"cid": channelID,
|
||||||
"ts": oldmessage.TimestampReal.UnixMilli(),
|
"ts": oldmessage.TimestampReal.UnixMilli(),
|
||||||
@@ -374,7 +388,7 @@ func migrateUser(ctx context.Context, dbnew sq.DB, dbold sq.DB, user OldUser, ap
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
channelMap[intName] = channelID
|
channelMap[strings.ToLower(intName)] = channelID
|
||||||
|
|
||||||
fmt.Printf("Auto Created Channel [%s]: %s\n", dispName, channelID)
|
fmt.Printf("Auto Created Channel [%s]: %s\n", dispName, channelID)
|
||||||
|
|
||||||
@@ -383,6 +397,9 @@ func migrateUser(ctx context.Context, dbnew sq.DB, dbold sq.DB, user OldUser, ap
|
|||||||
}
|
}
|
||||||
|
|
||||||
sendername := determineSenderName(user, oldmessage, title, oldmessage.Content, channelInternalName)
|
sendername := determineSenderName(user, oldmessage, title, oldmessage.Content, channelInternalName)
|
||||||
|
if sendername != nil && *sendername == "" {
|
||||||
|
panic("sendername")
|
||||||
|
}
|
||||||
|
|
||||||
if lastTitle == title && channelID == lastChannel &&
|
if lastTitle == title && channelID == lastChannel &&
|
||||||
langext.PtrEquals(lastContent, oldmessage.Content) &&
|
langext.PtrEquals(lastContent, oldmessage.Content) &&
|
||||||
@@ -394,7 +411,7 @@ func migrateUser(ctx context.Context, dbnew sq.DB, dbold sq.DB, user OldUser, ap
|
|||||||
lastSendername = sendername
|
lastSendername = sendername
|
||||||
lastTimestamp = oldmessage.TimestampReal
|
lastTimestamp = oldmessage.TimestampReal
|
||||||
|
|
||||||
fmt.Printf("Skip message [%d] \"%s\" (fast-duplicate)\n", oldmessage.ScnMessageId, oldmessage.Title)
|
//fmt.Printf("Skip message [%d] \"%s\" (fast-duplicate)\n", oldmessage.ScnMessageId, oldmessage.Title)
|
||||||
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -413,7 +430,7 @@ func migrateUser(ctx context.Context, dbnew sq.DB, dbold sq.DB, user OldUser, ap
|
|||||||
lastSendername = sendername
|
lastSendername = sendername
|
||||||
lastTimestamp = oldmessage.TimestampReal
|
lastTimestamp = oldmessage.TimestampReal
|
||||||
|
|
||||||
fmt.Printf("Skip message [%d] \"%s\" (locally deleted in app)\n", oldmessage.ScnMessageId, oldmessage.Title)
|
//fmt.Printf("Skip message [%d] \"%s\" (locally deleted in app)\n", oldmessage.ScnMessageId, oldmessage.Title)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -421,7 +438,7 @@ func migrateUser(ctx context.Context, dbnew sq.DB, dbold sq.DB, user OldUser, ap
|
|||||||
pp := sq.PP{
|
pp := sq.PP{
|
||||||
"mid": messageid,
|
"mid": messageid,
|
||||||
"suid": userid,
|
"suid": userid,
|
||||||
"ouid": user.UserId,
|
"ouid": userid,
|
||||||
"cnam": channelInternalName,
|
"cnam": channelInternalName,
|
||||||
"cid": channelID,
|
"cid": channelID,
|
||||||
"tsr": oldmessage.TimestampReal.UnixMilli(),
|
"tsr": oldmessage.TimestampReal.UnixMilli(),
|
||||||
@@ -456,7 +473,7 @@ func migrateUser(ctx context.Context, dbnew sq.DB, dbold sq.DB, user OldUser, ap
|
|||||||
_, err = dbnew.Exec(ctx, "INSERT INTO deliveries (delivery_id, message_id, receiver_user_id, receiver_client_id, timestamp_created, timestamp_finalized, status, fcm_message_id, next_delivery) VALUES (:did, :mid, :ruid, :rcid, :tsc, :tsf, :stat, :fcm, :next)", sq.PP{
|
_, err = dbnew.Exec(ctx, "INSERT INTO deliveries (delivery_id, message_id, receiver_user_id, receiver_client_id, timestamp_created, timestamp_finalized, status, fcm_message_id, next_delivery) VALUES (:did, :mid, :ruid, :rcid, :tsc, :tsf, :stat, :fcm, :next)", sq.PP{
|
||||||
"did": models.NewDeliveryID(),
|
"did": models.NewDeliveryID(),
|
||||||
"mid": messageid,
|
"mid": messageid,
|
||||||
"ruid": user.UserId,
|
"ruid": userid,
|
||||||
"rcid": *clientid,
|
"rcid": *clientid,
|
||||||
"tsc": oldmessage.TimestampReal.UnixMilli(),
|
"tsc": oldmessage.TimestampReal.UnixMilli(),
|
||||||
"tsf": oldmessage.TimestampReal.UnixMilli(),
|
"tsf": oldmessage.TimestampReal.UnixMilli(),
|
||||||
@@ -483,7 +500,7 @@ func migrateUser(ctx context.Context, dbnew sq.DB, dbold sq.DB, user OldUser, ap
|
|||||||
_, err = dbnew.Exec(ctx, "INSERT INTO deliveries (delivery_id, message_id, receiver_user_id, receiver_client_id, timestamp_created, timestamp_finalized, status, fcm_message_id, next_delivery) VALUES (:did, :mid, :ruid, :rcid, :tsc, :tsf, :stat, :fcm, :next)", sq.PP{
|
_, err = dbnew.Exec(ctx, "INSERT INTO deliveries (delivery_id, message_id, receiver_user_id, receiver_client_id, timestamp_created, timestamp_finalized, status, fcm_message_id, next_delivery) VALUES (:did, :mid, :ruid, :rcid, :tsc, :tsf, :stat, :fcm, :next)", sq.PP{
|
||||||
"did": models.NewDeliveryID(),
|
"did": models.NewDeliveryID(),
|
||||||
"mid": messageid,
|
"mid": messageid,
|
||||||
"ruid": user.UserId,
|
"ruid": userid,
|
||||||
"rcid": *clientid,
|
"rcid": *clientid,
|
||||||
"tsc": oldmessage.TimestampReal.UnixMilli(),
|
"tsc": oldmessage.TimestampReal.UnixMilli(),
|
||||||
"tsf": oldmessage.TimestampReal.UnixMilli(),
|
"tsf": oldmessage.TimestampReal.UnixMilli(),
|
||||||
@@ -509,6 +526,92 @@ func migrateUser(ctx context.Context, dbnew sq.DB, dbold sq.DB, user OldUser, ap
|
|||||||
lastTimestamp = oldmessage.TimestampReal
|
lastTimestamp = oldmessage.TimestampReal
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
c, err := dbnew.Query(ctx, "SELECT COUNT (*) FROM messages WHERE sender_user_id = :uid", sq.PP{
|
||||||
|
"uid": userid,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !c.Next() {
|
||||||
|
panic(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
count := 0
|
||||||
|
err = c.Scan(&count)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.Close()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if count > 0 {
|
||||||
|
_, err = dbnew.Exec(ctx, "UPDATE users SET messages_sent = :c, timestamp_lastread = :ts0, timestamp_lastsent = :ts1 WHERE user_id = :uid", sq.PP{
|
||||||
|
"uid": userid,
|
||||||
|
"c": count,
|
||||||
|
"ts0": lastTimestamp.UnixMilli(),
|
||||||
|
"ts1": lastTimestamp.UnixMilli(),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_, err = dbnew.Exec(ctx, "UPDATE users SET messages_sent = :c, timestamp_lastread = :ts0 WHERE user_id = :uid", sq.PP{
|
||||||
|
"uid": userid,
|
||||||
|
"c": count,
|
||||||
|
"ts0": user.TimestampCreated.UnixMilli(),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = dbnew.Exec(ctx, "UPDATE keytokens SET messages_sent = :c WHERE owner_user_id = :uid", sq.PP{
|
||||||
|
"uid": userid,
|
||||||
|
"c": count,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
for _, cid := range channelMap {
|
||||||
|
c, err := dbnew.Query(ctx, "SELECT COUNT (*) FROM messages WHERE sender_user_id = :uid AND channel_id = :cid", sq.PP{
|
||||||
|
"cid": cid,
|
||||||
|
"uid": userid,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !c.Next() {
|
||||||
|
panic(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
count := 0
|
||||||
|
err = c.Scan(&count)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.Close()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = dbnew.Exec(ctx, "UPDATE channels SET messages_sent = :c WHERE channel_id = :cid", sq.PP{
|
||||||
|
"cid": cid,
|
||||||
|
"c": count,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func determineSenderName(user OldUser, oldmessage OldMessage, title string, content *string, channame string) *string {
|
func determineSenderName(user OldUser, oldmessage OldMessage, title string, content *string, channame string) *string {
|
||||||
@@ -516,6 +619,8 @@ func determineSenderName(user OldUser, oldmessage OldMessage, title string, cont
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
channame = strings.ToLower(channame)
|
||||||
|
|
||||||
if channame == "t-ctrl" {
|
if channame == "t-ctrl" {
|
||||||
return langext.Ptr("sbox")
|
return langext.Ptr("sbox")
|
||||||
}
|
}
|
||||||
@@ -542,6 +647,42 @@ func determineSenderName(user OldUser, oldmessage OldMessage, title string, cont
|
|||||||
if strings.Contains(title, "error on niflheim-3") {
|
if strings.Contains(title, "error on niflheim-3") {
|
||||||
return langext.Ptr("niflheim-3")
|
return langext.Ptr("niflheim-3")
|
||||||
}
|
}
|
||||||
|
if strings.Contains(title, "error on statussrv") {
|
||||||
|
return langext.Ptr("statussrv")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "error on plan-web-prod") {
|
||||||
|
return langext.Ptr("plan-web-prod")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "error on inoshop") {
|
||||||
|
return langext.Ptr("inoshop")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "error on firestopcloud") {
|
||||||
|
return langext.Ptr("firestopcloud")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "error on plantafelstaging") {
|
||||||
|
return langext.Ptr("plantafelstaging")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "error on plantafeldev") {
|
||||||
|
return langext.Ptr("plantafeldev")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "error on balu-prod") {
|
||||||
|
return langext.Ptr("lbxprod")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "error on dyno-prod") {
|
||||||
|
return langext.Ptr("dyno-prod")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "error on dyno-dev") {
|
||||||
|
return langext.Ptr("dyno-dev")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "error on wkk") {
|
||||||
|
return langext.Ptr("wkk")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "error on lbxdev") {
|
||||||
|
return langext.Ptr("lbxdev")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "error on lbxprod") {
|
||||||
|
return langext.Ptr("lbxprod")
|
||||||
|
}
|
||||||
|
|
||||||
if strings.Contains(*content, "on mscom") {
|
if strings.Contains(*content, "on mscom") {
|
||||||
return langext.Ptr("mscom")
|
return langext.Ptr("mscom")
|
||||||
@@ -664,7 +805,7 @@ func determineSenderName(user OldUser, oldmessage OldMessage, title string, cont
|
|||||||
return langext.Ptr("bfb")
|
return langext.Ptr("bfb")
|
||||||
}
|
}
|
||||||
if strings.Contains(title, "balu-db") {
|
if strings.Contains(title, "balu-db") {
|
||||||
return langext.Ptr("lbprod")
|
return langext.Ptr("lbxprod")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -762,6 +903,31 @@ func determineSenderName(user OldUser, oldmessage OldMessage, title string, cont
|
|||||||
if strings.Contains(*content, "plantafelstaging.de") {
|
if strings.Contains(*content, "plantafelstaging.de") {
|
||||||
return langext.Ptr("plantafeldev")
|
return langext.Ptr("plantafeldev")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if strings.Contains(title, "Update cert_mscom") {
|
||||||
|
return langext.Ptr("mscom")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "Update cert_bfb") {
|
||||||
|
return langext.Ptr("bfb")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "Update staging.app.reuse.me") {
|
||||||
|
return langext.Ptr("wkk")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "Update develop.app.reuse.me") {
|
||||||
|
return langext.Ptr("wkk")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "Update inoshop_staging_bfb") {
|
||||||
|
return langext.Ptr("inoshop")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "Update cert_portfoliomanager_main") {
|
||||||
|
return langext.Ptr("bfb-testserver")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "Update cert_pfm2") {
|
||||||
|
return langext.Ptr("bfb-testserver")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "Update cert_kaz_main") {
|
||||||
|
return langext.Ptr("bfb-testserver")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if channame == "space-warning" {
|
if channame == "space-warning" {
|
||||||
@@ -777,6 +943,9 @@ func determineSenderName(user OldUser, oldmessage OldMessage, title string, cont
|
|||||||
if title == "statussrv" {
|
if title == "statussrv" {
|
||||||
return langext.Ptr("statussrv")
|
return langext.Ptr("statussrv")
|
||||||
}
|
}
|
||||||
|
if title == "virmach01" {
|
||||||
|
return langext.Ptr("statussrv")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if channame == "srv-backup" {
|
if channame == "srv-backup" {
|
||||||
@@ -856,6 +1025,28 @@ func determineSenderName(user OldUser, oldmessage OldMessage, title string, cont
|
|||||||
if strings.Contains(title, "Reboot lbxprod") {
|
if strings.Contains(title, "Reboot lbxprod") {
|
||||||
return langext.Ptr("lbxprod")
|
return langext.Ptr("lbxprod")
|
||||||
}
|
}
|
||||||
|
if strings.Contains(title, "Reboot plantafeldev") {
|
||||||
|
return langext.Ptr("plantafeldev")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "Reboot plantafelstaging") {
|
||||||
|
return langext.Ptr("plantafelstaging")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "Reboot statussrv") {
|
||||||
|
return langext.Ptr("statussrv")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "Reboot heydyno-prod-01") {
|
||||||
|
return langext.Ptr("dyno-prod")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "Reboot heydyno-dev-01") {
|
||||||
|
return langext.Ptr("dyno-dev")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "Reboot lbxdev") {
|
||||||
|
return langext.Ptr("lbxdev")
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.Contains(langext.Coalesce(content, ""), "Server: 'firestopcloud'") {
|
||||||
|
return langext.Ptr("firestopcloud")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if channame == "yt-tvc" {
|
if channame == "yt-tvc" {
|
||||||
@@ -870,6 +1061,124 @@ func determineSenderName(user OldUser, oldmessage OldMessage, title string, cont
|
|||||||
return langext.Ptr("mscom")
|
return langext.Ptr("mscom")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if channame == "backup-rr" {
|
||||||
|
if strings.Contains(title, "bfb/server-plantafelstaging") {
|
||||||
|
return langext.Ptr("plantafelstaging")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "bfb/server-plantafeldev") {
|
||||||
|
return langext.Ptr("plantafeldev")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "bfb/server-wkk") {
|
||||||
|
return langext.Ptr("wkk")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "bfb/holz100") {
|
||||||
|
return langext.Ptr("bfb")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "bfb/clockify") {
|
||||||
|
return langext.Ptr("bfb")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "bfb/gdapi") {
|
||||||
|
return langext.Ptr("bfb")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "mike/databases-mscom") {
|
||||||
|
return langext.Ptr("mscom")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "bfb/databases-bfb") {
|
||||||
|
return langext.Ptr("bfb")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "bfb/server-dynoprod") {
|
||||||
|
return langext.Ptr("dyno-prod")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "bfb/server-dynodev") {
|
||||||
|
return langext.Ptr("dyno-dev")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "bfb/server-baluprod") {
|
||||||
|
return langext.Ptr("lbxprod")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "bfb/server-baludev") {
|
||||||
|
return langext.Ptr("lbxdev")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "bfb/plantafeldigital") {
|
||||||
|
return langext.Ptr("plan-web-prod")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "mike/server-statussrv") {
|
||||||
|
return langext.Ptr("statussrv")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "mike/thunderbird") {
|
||||||
|
return langext.Ptr("niflheim-3")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "mike/seedbox") {
|
||||||
|
return langext.Ptr("sbox")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "bfb/balu") {
|
||||||
|
return langext.Ptr("lbxprod")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "mike/ext-git-graph") {
|
||||||
|
return langext.Ptr("mscom")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "bfb/server-bfbtest") {
|
||||||
|
return langext.Ptr("bfb-testserver")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "mike/server-mscom") {
|
||||||
|
return langext.Ptr("mscom")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "mike/database-statussrv") {
|
||||||
|
return langext.Ptr("statussrv")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "mike/server-mscom") {
|
||||||
|
return langext.Ptr("mscom")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "mike/server-inoshop") {
|
||||||
|
return langext.Ptr("inoshop")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "mike/server-bfb") {
|
||||||
|
return langext.Ptr("bfb")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "bfb/discord") {
|
||||||
|
return langext.Ptr("nifleim-3")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "bfb/server-bfbtest") {
|
||||||
|
return langext.Ptr("bfb-testserver")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "mike/ext-git-graph") {
|
||||||
|
return langext.Ptr("mscom")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "bfb/server-inoshop") {
|
||||||
|
return langext.Ptr("inoshop")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "bfb/server-bfb") {
|
||||||
|
return langext.Ptr("bfb")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "bfb/server-plantafelprod") {
|
||||||
|
return langext.Ptr("plan-web-prod")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "bfb/server-inoshop") {
|
||||||
|
return langext.Ptr("inoshop")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "mike/niflheim-3") {
|
||||||
|
return langext.Ptr("niflheim-3")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "mike/pihole") {
|
||||||
|
return langext.Ptr("pihole")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "bfb/server-firestopcloud") {
|
||||||
|
return langext.Ptr("firestopcloud")
|
||||||
|
}
|
||||||
|
if strings.Contains(title, "bfb/server-agentzero") {
|
||||||
|
return langext.Ptr("agentzero")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if channame == "backup" {
|
||||||
|
if strings.Contains(title, "mike/ext-git-graph") {
|
||||||
|
return langext.Ptr("mscom")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if channame == "spezi-alert" {
|
||||||
|
return langext.Ptr("mscom")
|
||||||
|
}
|
||||||
|
|
||||||
if title == "NCC Upload failed" || title == "NCC Upload successful" {
|
if title == "NCC Upload failed" || title == "NCC Upload successful" {
|
||||||
return langext.Ptr("mscom")
|
return langext.Ptr("mscom")
|
||||||
}
|
}
|
||||||
@@ -878,16 +1187,29 @@ func determineSenderName(user OldUser, oldmessage OldMessage, title string, cont
|
|||||||
return langext.Ptr("mscom")
|
return langext.Ptr("mscom")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if strings.Contains(title, "BFBackup VC migrate") {
|
||||||
|
return langext.Ptr("bfbackup")
|
||||||
|
}
|
||||||
|
|
||||||
if strings.Contains(title, "bfbackup job") {
|
if strings.Contains(title, "bfbackup job") {
|
||||||
return langext.Ptr("bfbackup")
|
return langext.Ptr("bfbackup")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if strings.Contains(title, "bfbackup finished") {
|
||||||
|
return langext.Ptr("bfbackup")
|
||||||
|
}
|
||||||
|
|
||||||
if strings.Contains(title, "Repo migration of /volume1") {
|
if strings.Contains(title, "Repo migration of /volume1") {
|
||||||
return langext.Ptr("bfbackup")
|
return langext.Ptr("bfbackup")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if channame == "docker-watch" {
|
||||||
|
return nil // okay
|
||||||
|
}
|
||||||
|
|
||||||
//fmt.Printf("Failed to determine sender of [%d] '%s' '%s'\n", oldmessage.ScnMessageId, oldmessage.Title, langext.Coalesce(oldmessage.Content, "<NULL>"))
|
//fmt.Printf("Failed to determine sender of [%d] '%s' '%s'\n", oldmessage.ScnMessageId, oldmessage.Title, langext.Coalesce(oldmessage.Content, "<NULL>"))
|
||||||
fmt.Printf("Failed to determine sender of [%d] '%s'\n", oldmessage.ScnMessageId, oldmessage.Title)
|
|
||||||
|
fmt.Printf("%s", termext.Red(fmt.Sprintf("Failed to determine sender of [%d] '%s' -- '%s' -- '%s'\n", oldmessage.ScnMessageId, channame, title, langext.Coalesce(oldmessage.Content, "<NULL>"))))
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@@ -268,6 +268,7 @@ var configDev = func() Config {
|
|||||||
GooglePackageName: confEnv("SCN_GOOG_PACKAGENAME"),
|
GooglePackageName: confEnv("SCN_GOOG_PACKAGENAME"),
|
||||||
GoogleProProductID: confEnv("SCN_GOOG_PROPRODUCTID"),
|
GoogleProProductID: confEnv("SCN_GOOG_PROPRODUCTID"),
|
||||||
Cors: true,
|
Cors: true,
|
||||||
|
ReqLogEnabled: true,
|
||||||
ReqLogMaxBodySize: 2048,
|
ReqLogMaxBodySize: 2048,
|
||||||
ReqLogHistoryMaxCount: 1638,
|
ReqLogHistoryMaxCount: 1638,
|
||||||
ReqLogHistoryMaxDuration: timeext.FromDays(60),
|
ReqLogHistoryMaxDuration: timeext.FromDays(60),
|
||||||
@@ -339,6 +340,7 @@ var configStag = func() Config {
|
|||||||
GooglePackageName: confEnv("SCN_GOOG_PACKAGENAME"),
|
GooglePackageName: confEnv("SCN_GOOG_PACKAGENAME"),
|
||||||
GoogleProProductID: confEnv("SCN_GOOG_PROPRODUCTID"),
|
GoogleProProductID: confEnv("SCN_GOOG_PROPRODUCTID"),
|
||||||
Cors: true,
|
Cors: true,
|
||||||
|
ReqLogEnabled: true,
|
||||||
ReqLogMaxBodySize: 2048,
|
ReqLogMaxBodySize: 2048,
|
||||||
ReqLogHistoryMaxCount: 1638,
|
ReqLogHistoryMaxCount: 1638,
|
||||||
ReqLogHistoryMaxDuration: timeext.FromDays(60),
|
ReqLogHistoryMaxDuration: timeext.FromDays(60),
|
||||||
@@ -398,18 +400,19 @@ var configProd = func() Config {
|
|||||||
ReturnRawErrors: false,
|
ReturnRawErrors: false,
|
||||||
DummyFirebase: false,
|
DummyFirebase: false,
|
||||||
FirebaseTokenURI: "https://oauth2.googleapis.com/token",
|
FirebaseTokenURI: "https://oauth2.googleapis.com/token",
|
||||||
FirebaseProjectID: confEnv("SCN_SCN_FB_PROJECTID"),
|
FirebaseProjectID: confEnv("SCN_FB_PROJECTID"),
|
||||||
FirebasePrivKeyID: confEnv("SCN_SCN_FB_PRIVATEKEYID"),
|
FirebasePrivKeyID: confEnv("SCN_FB_PRIVATEKEYID"),
|
||||||
FirebaseClientMail: confEnv("SCN_SCN_FB_CLIENTEMAIL"),
|
FirebaseClientMail: confEnv("SCN_FB_CLIENTEMAIL"),
|
||||||
FirebasePrivateKey: confEnv("SCN_SCN_FB_PRIVATEKEY"),
|
FirebasePrivateKey: confEnv("SCN_FB_PRIVATEKEY"),
|
||||||
DummyGoogleAPI: false,
|
DummyGoogleAPI: false,
|
||||||
GoogleAPITokenURI: "https://oauth2.googleapis.com/token",
|
GoogleAPITokenURI: "https://oauth2.googleapis.com/token",
|
||||||
GoogleAPIPrivKeyID: confEnv("SCN_SCN_GOOG_PRIVATEKEYID"),
|
GoogleAPIPrivKeyID: confEnv("SCN_GOOG_PRIVATEKEYID"),
|
||||||
GoogleAPIClientMail: confEnv("SCN_SCN_GOOG_CLIENTEMAIL"),
|
GoogleAPIClientMail: confEnv("SCN_GOOG_CLIENTEMAIL"),
|
||||||
GoogleAPIPrivateKey: confEnv("SCN_SCN_GOOG_PRIVATEKEY"),
|
GoogleAPIPrivateKey: confEnv("SCN_GOOG_PRIVATEKEY"),
|
||||||
GooglePackageName: confEnv("SCN_SCN_GOOG_PACKAGENAME"),
|
GooglePackageName: confEnv("SCN_GOOG_PACKAGENAME"),
|
||||||
GoogleProProductID: confEnv("SCN_SCN_GOOG_PROPRODUCTID"),
|
GoogleProProductID: confEnv("SCN_GOOG_PROPRODUCTID"),
|
||||||
Cors: true,
|
Cors: true,
|
||||||
|
ReqLogEnabled: true,
|
||||||
ReqLogMaxBodySize: 2048,
|
ReqLogMaxBodySize: 2048,
|
||||||
ReqLogHistoryMaxCount: 1638,
|
ReqLogHistoryMaxCount: 1638,
|
||||||
ReqLogHistoryMaxDuration: timeext.FromDays(60),
|
ReqLogHistoryMaxDuration: timeext.FromDays(60),
|
||||||
@@ -449,7 +452,7 @@ func confEnv(key string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
ns := os.Getenv("SCN_NAMESPACE")
|
ns := os.Getenv("CONF_NS")
|
||||||
|
|
||||||
cfg, ok := GetConfig(ns)
|
cfg, ok := GetConfig(ns)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@@ -4,6 +4,7 @@ import (
|
|||||||
ct "blackforestbytes.com/simplecloudnotifier/db/cursortoken"
|
ct "blackforestbytes.com/simplecloudnotifier/db/cursortoken"
|
||||||
"blackforestbytes.com/simplecloudnotifier/models"
|
"blackforestbytes.com/simplecloudnotifier/models"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"errors"
|
||||||
"gogs.mikescher.com/BlackForestBytes/goext/sq"
|
"gogs.mikescher.com/BlackForestBytes/goext/sq"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@@ -149,3 +150,31 @@ func (db *Database) ListMessages(ctx TxContext, filter models.MessageFilter, pag
|
|||||||
return data[0:*pageSize], outToken, nil
|
return data[0:*pageSize], outToken, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (db *Database) CountMessages(ctx TxContext, filter models.MessageFilter) (int64, error) {
|
||||||
|
tx, err := ctx.GetOrCreateTransaction(db)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
filterCond, filterJoin, prepParams, err := filter.SQL()
|
||||||
|
|
||||||
|
sqlQuery := "SELECT " + "COUNT(*)" + " FROM messages " + filterJoin + " WHERE ( " + filterCond + " ) "
|
||||||
|
|
||||||
|
rows, err := tx.Query(ctx, sqlQuery, prepParams)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !rows.Next() {
|
||||||
|
return 0, errors.New("COUNT query returned no results")
|
||||||
|
}
|
||||||
|
|
||||||
|
var countRes int64
|
||||||
|
err = rows.Scan(&countRes)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return countRes, nil
|
||||||
|
}
|
||||||
|
@@ -9,7 +9,7 @@ require (
|
|||||||
github.com/jmoiron/sqlx v1.3.5
|
github.com/jmoiron/sqlx v1.3.5
|
||||||
github.com/mattn/go-sqlite3 v1.14.17
|
github.com/mattn/go-sqlite3 v1.14.17
|
||||||
github.com/rs/zerolog v1.29.1
|
github.com/rs/zerolog v1.29.1
|
||||||
gogs.mikescher.com/BlackForestBytes/goext v0.0.156
|
gogs.mikescher.com/BlackForestBytes/goext v0.0.163
|
||||||
gopkg.in/loremipsum.v1 v1.1.2
|
gopkg.in/loremipsum.v1 v1.1.2
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -33,10 +33,11 @@ require (
|
|||||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||||
github.com/ugorji/go/codec v1.2.11 // indirect
|
github.com/ugorji/go/codec v1.2.11 // indirect
|
||||||
golang.org/x/arch v0.3.0 // indirect
|
golang.org/x/arch v0.3.0 // indirect
|
||||||
golang.org/x/crypto v0.9.0 // indirect
|
golang.org/x/crypto v0.10.0 // indirect
|
||||||
golang.org/x/net v0.10.0 // indirect
|
golang.org/x/net v0.10.0 // indirect
|
||||||
golang.org/x/sys v0.8.0 // indirect
|
golang.org/x/sys v0.9.0 // indirect
|
||||||
golang.org/x/text v0.9.0 // indirect
|
golang.org/x/term v0.9.0 // indirect
|
||||||
|
golang.org/x/text v0.10.0 // indirect
|
||||||
google.golang.org/protobuf v1.30.0 // indirect
|
google.golang.org/protobuf v1.30.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
@@ -81,15 +81,13 @@ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS
|
|||||||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||||
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
|
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
|
||||||
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||||
gogs.mikescher.com/BlackForestBytes/goext v0.0.155 h1:eFcWmq9OXk4yCw8mjuyz8+JWiUEqjeSGoWOHwO000co=
|
gogs.mikescher.com/BlackForestBytes/goext v0.0.163 h1:GYC34wLOdBM/CgAov0AyznfHGd09Km106Ijmp8cZmp4=
|
||||||
gogs.mikescher.com/BlackForestBytes/goext v0.0.155/go.mod h1:bIcO9mw2CD03pmJcBaE5YCF6etG5u73OVkUa8Alx3D0=
|
gogs.mikescher.com/BlackForestBytes/goext v0.0.163/go.mod h1:Tood+vqmPqS/meYRnUcGz837wqHkP8BykVpY1h8TWoI=
|
||||||
gogs.mikescher.com/BlackForestBytes/goext v0.0.156 h1:mRRyAkLQCGVbDfG1t+7Y3zTf1S4TNajENiRpX1KTGw8=
|
|
||||||
gogs.mikescher.com/BlackForestBytes/goext v0.0.156/go.mod h1:bIcO9mw2CD03pmJcBaE5YCF6etG5u73OVkUa8Alx3D0=
|
|
||||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||||
golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
|
golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
|
||||||
golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||||
golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
|
golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM=
|
||||||
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
|
golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
|
||||||
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
|
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
|
||||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
@@ -97,10 +95,12 @@ golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
|
golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
|
||||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
golang.org/x/term v0.9.0 h1:GRRCnKYhdQrD8kfRAdQ6Zcw1P0OcELxGLKJvtjVMZ28=
|
||||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo=
|
||||||
|
golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58=
|
||||||
|
golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||||
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
|
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
|
||||||
|
@@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -23,7 +24,9 @@ type AndroidPublisher struct {
|
|||||||
|
|
||||||
func NewAndroidPublisherAPI(conf scn.Config) (AndroidPublisherClient, error) {
|
func NewAndroidPublisherAPI(conf scn.Config) (AndroidPublisherClient, error) {
|
||||||
|
|
||||||
googauth, err := NewAuth(conf.GoogleAPITokenURI, conf.GoogleAPIPrivKeyID, conf.GoogleAPIClientMail, conf.GoogleAPIPrivateKey)
|
pkey := strings.ReplaceAll(conf.GoogleAPIPrivateKey, "\\n", "\n")
|
||||||
|
|
||||||
|
googauth, err := NewAuth(conf.GoogleAPITokenURI, conf.GoogleAPIPrivKeyID, conf.GoogleAPIClientMail, pkey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@@ -6,6 +6,7 @@ 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"
|
||||||
)
|
)
|
||||||
@@ -156,7 +157,29 @@ func (j *DeliveryRetryJob) redeliver(ctx *logic.SimpleContext, delivery models.D
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
fcmDelivID, err := j.app.DeliverMessage(ctx, client, msg, nil)
|
isCompatClient, err := j.app.Database.Primary.IsCompatClient(ctx, client.ClientID)
|
||||||
|
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, msg.MessageID.String(), "messageid")
|
||||||
|
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 {
|
||||||
|
@@ -13,6 +13,15 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type TxContext interface {
|
||||||
|
Deadline() (deadline time.Time, ok bool)
|
||||||
|
Done() <-chan struct{}
|
||||||
|
Err() error
|
||||||
|
Value(key any) any
|
||||||
|
|
||||||
|
GetOrCreateTransaction(db db.DatabaseImpl) (sq.Tx, error)
|
||||||
|
}
|
||||||
|
|
||||||
type AppContext struct {
|
type AppContext struct {
|
||||||
app *Application
|
app *Application
|
||||||
inner context.Context
|
inner context.Context
|
||||||
|
@@ -9,6 +9,7 @@ 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"
|
||||||
@@ -28,6 +29,7 @@ import (
|
|||||||
var rexWhitespaceStart = rext.W(regexp.MustCompile("^\\s+"))
|
var rexWhitespaceStart = rext.W(regexp.MustCompile("^\\s+"))
|
||||||
var rexWhitespaceEnd = rext.W(regexp.MustCompile("\\s+$"))
|
var rexWhitespaceEnd = rext.W(regexp.MustCompile("\\s+$"))
|
||||||
var rexNormalizeUsername = rext.W(regexp.MustCompile("[^[:alnum:]\\-_ ]"))
|
var rexNormalizeUsername = rext.W(regexp.MustCompile("[^[:alnum:]\\-_ ]"))
|
||||||
|
var rexCompatTitleChannel = rext.W(regexp.MustCompile("^\\[(?P<channel>[A-Za-z\\-0-9_ ]+)] (?P<title>(.|\\r|\\n)+)$"))
|
||||||
|
|
||||||
type Application struct {
|
type Application struct {
|
||||||
Config scn.Config
|
Config scn.Config
|
||||||
@@ -262,6 +264,10 @@ func (app *Application) StartRequest(g *gin.Context, uri any, query any, body an
|
|||||||
if err := g.ShouldBindWith(form, binding.Form); err != nil {
|
if err := g.ShouldBindWith(form, binding.Form); err != nil {
|
||||||
return nil, langext.Ptr(ginresp.APIError(g, 400, apierr.BINDFAIL_BODY_PARAM, "Failed to read multipart-form", err))
|
return nil, langext.Ptr(ginresp.APIError(g, 400, apierr.BINDFAIL_BODY_PARAM, "Failed to read multipart-form", err))
|
||||||
}
|
}
|
||||||
|
} else if g.ContentType() == "application/x-www-form-urlencoded" {
|
||||||
|
if err := g.ShouldBindWith(form, binding.Form); err != nil {
|
||||||
|
return nil, langext.Ptr(ginresp.APIError(g, 400, apierr.BINDFAIL_BODY_PARAM, "Failed to read urlencoded-form", err))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if !ignoreWrongContentType {
|
if !ignoreWrongContentType {
|
||||||
return nil, langext.Ptr(ginresp.APIError(g, 400, apierr.BINDFAIL_BODY_PARAM, "missing form body", nil))
|
return nil, langext.Ptr(ginresp.APIError(g, 400, apierr.BINDFAIL_BODY_PARAM, "missing form body", nil))
|
||||||
@@ -357,8 +363,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) (string, error) {
|
func (app *Application) DeliverMessage(ctx context.Context, client models.Client, msg models.Message, compatTitleOverride *string, compatMsgIDOverride *string) (string, error) {
|
||||||
fcmDelivID, err := app.Pusher.SendNotification(ctx, client, msg, compatTitleOverride)
|
fcmDelivID, err := app.Pusher.SendNotification(ctx, client, msg, compatTitleOverride, compatMsgIDOverride)
|
||||||
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
|
||||||
@@ -372,3 +378,20 @@ 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)
|
||||||
|
}
|
||||||
|
@@ -129,6 +129,12 @@ type KeyTokenDB struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (k KeyTokenDB) Model() KeyToken {
|
func (k KeyTokenDB) Model() KeyToken {
|
||||||
|
|
||||||
|
channels := make([]ChannelID, 0)
|
||||||
|
if strings.TrimSpace(k.Channels) != "" {
|
||||||
|
channels = langext.ArrMap(strings.Split(k.Channels, ";"), func(v string) ChannelID { return ChannelID(v) })
|
||||||
|
}
|
||||||
|
|
||||||
return KeyToken{
|
return KeyToken{
|
||||||
KeyTokenID: k.KeyTokenID,
|
KeyTokenID: k.KeyTokenID,
|
||||||
Name: k.Name,
|
Name: k.Name,
|
||||||
@@ -136,7 +142,7 @@ func (k KeyTokenDB) Model() KeyToken {
|
|||||||
TimestampLastUsed: timeOptFromMilli(k.TimestampLastUsed),
|
TimestampLastUsed: timeOptFromMilli(k.TimestampLastUsed),
|
||||||
OwnerUserID: k.OwnerUserID,
|
OwnerUserID: k.OwnerUserID,
|
||||||
AllChannels: k.AllChannels,
|
AllChannels: k.AllChannels,
|
||||||
Channels: langext.ArrMap(strings.Split(k.Channels, ";"), func(v string) ChannelID { return ChannelID(v) }),
|
Channels: channels,
|
||||||
Token: k.Token,
|
Token: k.Token,
|
||||||
Permissions: ParseTokenPermissionList(k.Permissions),
|
Permissions: ParseTokenPermissionList(k.Permissions),
|
||||||
MessagesSent: k.MessagesSent,
|
MessagesSent: k.MessagesSent,
|
||||||
|
@@ -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) (string, error) {
|
func (d DummyConnector) SendNotification(ctx context.Context, client models.Client, msg models.Message, compatTitleOverride *string, compatMsgIDOverride *string) (string, error) {
|
||||||
return "%DUMMY%", nil
|
return "%DUMMY%", nil
|
||||||
}
|
}
|
||||||
|
@@ -15,6 +15,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -29,7 +30,9 @@ type FirebaseConnector struct {
|
|||||||
|
|
||||||
func NewFirebaseConn(conf scn.Config) (NotificationClient, error) {
|
func NewFirebaseConn(conf scn.Config) (NotificationClient, error) {
|
||||||
|
|
||||||
fbauth, err := NewAuth(conf.FirebaseTokenURI, conf.FirebaseProjectID, conf.FirebaseClientMail, conf.FirebasePrivateKey)
|
pkey := strings.ReplaceAll(conf.FirebasePrivateKey, "\\n", "\n")
|
||||||
|
|
||||||
|
fbauth, err := NewAuth(conf.FirebaseTokenURI, conf.FirebaseProjectID, conf.FirebaseClientMail, pkey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -50,13 +53,13 @@ type Notification struct {
|
|||||||
Priority int
|
Priority int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fb FirebaseConnector) SendNotification(ctx context.Context, client models.Client, msg models.Message, compatTitleOverride *string) (string, error) {
|
func (fb FirebaseConnector) SendNotification(ctx context.Context, client models.Client, msg models.Message, compatTitleOverride *string, compatMsgIDOverride *string) (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{
|
"data": gin.H{
|
||||||
"scn_msg_id": msg.MessageID.String(),
|
"scn_msg_id": langext.Coalesce(compatMsgIDOverride, msg.MessageID.String()),
|
||||||
"usr_msg_id": langext.Coalesce(msg.UserMessageID, ""),
|
"usr_msg_id": langext.Coalesce(msg.UserMessageID, ""),
|
||||||
"client_id": client.ClientID.String(),
|
"client_id": client.ClientID.String(),
|
||||||
"timestamp": strconv.FormatInt(msg.Timestamp().Unix(), 10),
|
"timestamp": strconv.FormatInt(msg.Timestamp().Unix(), 10),
|
||||||
@@ -124,5 +127,7 @@ func (fb FirebaseConnector) SendNotification(ctx context.Context, client models.
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Info().Msg(fmt.Sprintf("Sucessfully pushed notification %s", msg.MessageID))
|
||||||
|
|
||||||
return respBody.Name, nil
|
return respBody.Name, nil
|
||||||
}
|
}
|
||||||
|
@@ -6,5 +6,5 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type NotificationClient interface {
|
type NotificationClient interface {
|
||||||
SendNotification(ctx context.Context, client models.Client, msg models.Message, compatTitleOverride *string) (string, error)
|
SendNotification(ctx context.Context, client models.Client, msg models.Message, compatTitleOverride *string, compatMsgIDOverride *string) (string, error)
|
||||||
}
|
}
|
||||||
|
@@ -11,6 +11,7 @@ type SinkData struct {
|
|||||||
Message models.Message
|
Message models.Message
|
||||||
Client models.Client
|
Client models.Client
|
||||||
CompatTitleOverride *string
|
CompatTitleOverride *string
|
||||||
|
CompatMsgIDOverride *string
|
||||||
}
|
}
|
||||||
|
|
||||||
type TestSink struct {
|
type TestSink struct {
|
||||||
@@ -25,7 +26,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) (string, error) {
|
func (d *TestSink) SendNotification(ctx context.Context, client models.Client, msg models.Message, compatTitleOverride *string, compatMsgIDOverride *string) (string, error) {
|
||||||
id, err := langext.NewHexUUID()
|
id, err := langext.NewHexUUID()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
@@ -37,6 +38,7 @@ func (d *TestSink) SendNotification(ctx context.Context, client models.Client, m
|
|||||||
Message: msg,
|
Message: msg,
|
||||||
Client: client,
|
Client: client,
|
||||||
CompatTitleOverride: compatTitleOverride,
|
CompatTitleOverride: compatTitleOverride,
|
||||||
|
CompatMsgIDOverride: compatMsgIDOverride,
|
||||||
})
|
})
|
||||||
|
|
||||||
return key, nil
|
return key, nil
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
"contact": {},
|
"contact": {},
|
||||||
"version": "2.0"
|
"version": "2.0"
|
||||||
},
|
},
|
||||||
"host": "scn.blackforestbytes.com",
|
"host": "simplecloudnotifier.de",
|
||||||
"basePath": "/",
|
"basePath": "/",
|
||||||
"paths": {
|
"paths": {
|
||||||
"/": {
|
"/": {
|
||||||
|
@@ -681,7 +681,7 @@ definitions:
|
|||||||
username:
|
username:
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
host: scn.blackforestbytes.com
|
host: simplecloudnotifier.de
|
||||||
info:
|
info:
|
||||||
contact: {}
|
contact: {}
|
||||||
description: API for SCN
|
description: API for SCN
|
||||||
|
@@ -364,7 +364,7 @@ func TestCompatInfo(t *testing.T) {
|
|||||||
tt.AssertEqual(t, "message", "ok", r2["message"])
|
tt.AssertEqual(t, "message", "ok", r2["message"])
|
||||||
tt.AssertEqual(t, "quota", 1, r2["quota"])
|
tt.AssertEqual(t, "quota", 1, r2["quota"])
|
||||||
tt.AssertEqual(t, "quota_max", 50, r2["quota_max"])
|
tt.AssertEqual(t, "quota_max", 50, r2["quota_max"])
|
||||||
tt.AssertEqual(t, "unack_count", 0, r2["unack_count"])
|
tt.AssertEqual(t, "unack_count", 1, r2["unack_count"])
|
||||||
tt.AssertEqual(t, "user_id", userid, r2["user_id"])
|
tt.AssertEqual(t, "user_id", userid, r2["user_id"])
|
||||||
tt.AssertEqual(t, "user_key", userkey, r2["user_key"])
|
tt.AssertEqual(t, "user_key", userkey, r2["user_key"])
|
||||||
|
|
||||||
@@ -491,7 +491,7 @@ func TestCompatUpdateUserKey(t *testing.T) {
|
|||||||
tt.AssertEqual(t, "message", "ok", r1["message"])
|
tt.AssertEqual(t, "message", "ok", r1["message"])
|
||||||
tt.AssertEqual(t, "quota", 1, r1["quota"])
|
tt.AssertEqual(t, "quota", 1, r1["quota"])
|
||||||
tt.AssertEqual(t, "quota_max", 50, r1["quota_max"])
|
tt.AssertEqual(t, "quota_max", 50, r1["quota_max"])
|
||||||
tt.AssertEqual(t, "unack_count", 0, r1["unack_count"])
|
tt.AssertEqual(t, "unack_count", 1, r1["unack_count"])
|
||||||
tt.AssertEqual(t, "user_id", userid, r1["user_id"])
|
tt.AssertEqual(t, "user_id", userid, r1["user_id"])
|
||||||
tt.AssertEqual(t, "user_key", newkey, r1["user_key"])
|
tt.AssertEqual(t, "user_key", newkey, r1["user_key"])
|
||||||
|
|
||||||
@@ -528,7 +528,7 @@ func TestCompatUpdateFCM(t *testing.T) {
|
|||||||
tt.AssertEqual(t, "message", "ok", r1["message"])
|
tt.AssertEqual(t, "message", "ok", r1["message"])
|
||||||
tt.AssertEqual(t, "quota", 1, r1["quota"])
|
tt.AssertEqual(t, "quota", 1, r1["quota"])
|
||||||
tt.AssertEqual(t, "quota_max", 50, r1["quota_max"])
|
tt.AssertEqual(t, "quota_max", 50, r1["quota_max"])
|
||||||
tt.AssertEqual(t, "unack_count", 0, r1["unack_count"])
|
tt.AssertEqual(t, "unack_count", 1, r1["unack_count"])
|
||||||
tt.AssertEqual(t, "user_id", userid, r1["user_id"])
|
tt.AssertEqual(t, "user_id", userid, r1["user_id"])
|
||||||
tt.AssertEqual(t, "user_key", newkey, r1["user_key"])
|
tt.AssertEqual(t, "user_key", newkey, r1["user_key"])
|
||||||
|
|
||||||
@@ -732,3 +732,90 @@ func TestCompatTitlePatch(t *testing.T) {
|
|||||||
tt.AssertStrRepEqual(t, "msg.ovrTitle", "[TestChan] HelloWorld_001", pusher.Last().CompatTitleOverride)
|
tt.AssertStrRepEqual(t, "msg.ovrTitle", "[TestChan] HelloWorld_001", pusher.Last().CompatTitleOverride)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCompatAckCount(t *testing.T) {
|
||||||
|
_, baseUrl, stop := tt.StartSimpleWebserver(t)
|
||||||
|
defer stop()
|
||||||
|
|
||||||
|
r0 := tt.RequestGet[gin.H](t, baseUrl, fmt.Sprintf("/api/register.php?fcm_token=%s&pro=%s&pro_token=%s", "DUMMY_FCM", "0", ""))
|
||||||
|
tt.AssertEqual(t, "success", true, r0["success"])
|
||||||
|
|
||||||
|
userid := int64(r0["user_id"].(float64))
|
||||||
|
userkey := r0["user_key"].(string)
|
||||||
|
|
||||||
|
{
|
||||||
|
ri1 := tt.RequestGet[gin.H](t, baseUrl, fmt.Sprintf("/api/info.php?user_id=%d&user_key=%s", userid, userkey))
|
||||||
|
tt.AssertEqual(t, "unack_count", 0, ri1["unack_count"])
|
||||||
|
}
|
||||||
|
|
||||||
|
r1 := tt.RequestPost[gin.H](t, baseUrl, "/send.php", tt.FormData{
|
||||||
|
"user_id": fmt.Sprintf("%d", userid),
|
||||||
|
"user_key": userkey,
|
||||||
|
"title": "my title 11 & x",
|
||||||
|
})
|
||||||
|
tt.AssertEqual(t, "success", true, r1["success"])
|
||||||
|
r1scnid := int64(r1["scn_msg_id"].(float64))
|
||||||
|
|
||||||
|
{
|
||||||
|
ri1 := tt.RequestGet[gin.H](t, baseUrl, fmt.Sprintf("/api/info.php?user_id=%d&user_key=%s", userid, userkey))
|
||||||
|
tt.AssertEqual(t, "unack_count", 1, ri1["unack_count"])
|
||||||
|
}
|
||||||
|
|
||||||
|
r2 := tt.RequestPost[gin.H](t, baseUrl, "/send.php", tt.FormData{
|
||||||
|
"user_id": fmt.Sprintf("%d", userid),
|
||||||
|
"user_key": userkey,
|
||||||
|
"title": "my title 11 & x",
|
||||||
|
})
|
||||||
|
tt.AssertEqual(t, "success", true, r2["success"])
|
||||||
|
r2scnid := int64(r2["scn_msg_id"].(float64))
|
||||||
|
|
||||||
|
{
|
||||||
|
ri1 := tt.RequestGet[gin.H](t, baseUrl, fmt.Sprintf("/api/info.php?user_id=%d&user_key=%s", userid, userkey))
|
||||||
|
tt.AssertEqual(t, "unack_count", 2, ri1["unack_count"])
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
ack := tt.RequestGet[gin.H](t, baseUrl, fmt.Sprintf("/api/ack.php?user_id=%d&user_key=%s&scn_msg_id=%d", userid, userkey, r1scnid))
|
||||||
|
tt.AssertEqual(t, "success", true, ack["success"])
|
||||||
|
tt.AssertEqual(t, "prev_ack", 0, ack["prev_ack"])
|
||||||
|
tt.AssertEqual(t, "new_ack", 1, ack["new_ack"])
|
||||||
|
tt.AssertEqual(t, "message", "ok", ack["message"])
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
ri1 := tt.RequestGet[gin.H](t, baseUrl, fmt.Sprintf("/api/info.php?user_id=%d&user_key=%s", userid, userkey))
|
||||||
|
tt.AssertEqual(t, "unack_count", 1, ri1["unack_count"])
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
ack := tt.RequestGet[gin.H](t, baseUrl, fmt.Sprintf("/api/ack.php?user_id=%d&user_key=%s&scn_msg_id=%d", userid, userkey, r1scnid))
|
||||||
|
tt.AssertEqual(t, "success", true, ack["success"])
|
||||||
|
tt.AssertEqual(t, "prev_ack", 1, ack["prev_ack"])
|
||||||
|
tt.AssertEqual(t, "new_ack", 1, ack["new_ack"])
|
||||||
|
tt.AssertEqual(t, "message", "ok", ack["message"])
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
ri1 := tt.RequestGet[gin.H](t, baseUrl, fmt.Sprintf("/api/info.php?user_id=%d&user_key=%s", userid, userkey))
|
||||||
|
tt.AssertEqual(t, "unack_count", 1, ri1["unack_count"])
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
ri1 := tt.RequestGet[gin.H](t, baseUrl, fmt.Sprintf("/api/info.php?user_id=%d&user_key=%s", userid, userkey))
|
||||||
|
tt.AssertEqual(t, "unack_count", 1, ri1["unack_count"])
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
ack := tt.RequestGet[gin.H](t, baseUrl, fmt.Sprintf("/api/ack.php?user_id=%d&user_key=%s&scn_msg_id=%d", userid, userkey, r2scnid))
|
||||||
|
tt.AssertEqual(t, "success", true, ack["success"])
|
||||||
|
tt.AssertEqual(t, "prev_ack", 0, ack["prev_ack"])
|
||||||
|
tt.AssertEqual(t, "new_ack", 1, ack["new_ack"])
|
||||||
|
tt.AssertEqual(t, "message", "ok", ack["message"])
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
ri1 := tt.RequestGet[gin.H](t, baseUrl, fmt.Sprintf("/api/info.php?user_id=%d&user_key=%s", userid, userkey))
|
||||||
|
tt.AssertEqual(t, "unack_count", 0, ri1["unack_count"])
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
@@ -383,6 +383,11 @@ func TestTokenKeysDowngradeSelf(t *testing.T) {
|
|||||||
|
|
||||||
data := tt.InitSingleData(t, ws)
|
data := tt.InitSingleData(t, ws)
|
||||||
|
|
||||||
|
chan0 := tt.RequestAuthPost[gin.H](t, data.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/channels", data.UID), gin.H{
|
||||||
|
"name": "testchan1",
|
||||||
|
})
|
||||||
|
chanid := fmt.Sprintf("%v", chan0["channel_id"])
|
||||||
|
|
||||||
type keyobj struct {
|
type keyobj struct {
|
||||||
AllChannels bool `json:"all_channels"`
|
AllChannels bool `json:"all_channels"`
|
||||||
Channels []string `json:"channels"`
|
Channels []string `json:"channels"`
|
||||||
@@ -415,7 +420,7 @@ func TestTokenKeysDowngradeSelf(t *testing.T) {
|
|||||||
}, 400, apierr.CANNOT_SELFUPDATE_KEY)
|
}, 400, apierr.CANNOT_SELFUPDATE_KEY)
|
||||||
|
|
||||||
tt.RequestAuthPatchShouldFail(t, data.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/keys/%s", data.UID, ak), gin.H{
|
tt.RequestAuthPatchShouldFail(t, data.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/keys/%s", data.UID, ak), gin.H{
|
||||||
"channels": []string{"main"},
|
"channels": []string{chanid},
|
||||||
}, 400, apierr.CANNOT_SELFUPDATE_KEY)
|
}, 400, apierr.CANNOT_SELFUPDATE_KEY)
|
||||||
|
|
||||||
tt.RequestAuthPatch[tt.Void](t, data.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/keys/%s", data.UID, ak), gin.H{
|
tt.RequestAuthPatch[tt.Void](t, data.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/keys/%s", data.UID, ak), gin.H{
|
||||||
@@ -606,3 +611,64 @@ func TestTokenKeysMessageCounter(t *testing.T) {
|
|||||||
assertCounter(4, 4, 0)
|
assertCounter(4, 4, 0)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTokenKeysCreateDefaultParam(t *testing.T) {
|
||||||
|
ws, baseUrl, stop := tt.StartSimpleWebserver(t)
|
||||||
|
defer stop()
|
||||||
|
|
||||||
|
data := tt.InitSingleData(t, ws)
|
||||||
|
|
||||||
|
type keyobj struct {
|
||||||
|
AllChannels bool `json:"all_channels"`
|
||||||
|
Channels []string `json:"channels"`
|
||||||
|
KeytokenId string `json:"keytoken_id"`
|
||||||
|
MessagesSent int `json:"messages_sent"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
OwnerUserId string `json:"owner_user_id"`
|
||||||
|
Permissions string `json:"permissions"`
|
||||||
|
Token string `json:"token"` // only in create
|
||||||
|
}
|
||||||
|
|
||||||
|
chan0 := tt.RequestAuthPost[gin.H](t, data.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/channels", data.UID), gin.H{
|
||||||
|
"name": "testchan1",
|
||||||
|
})
|
||||||
|
chanid := fmt.Sprintf("%v", chan0["channel_id"])
|
||||||
|
|
||||||
|
{
|
||||||
|
key2 := tt.RequestAuthPost[keyobj](t, data.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/keys", data.UID), gin.H{
|
||||||
|
"name": "K2",
|
||||||
|
"permissions": "CS",
|
||||||
|
})
|
||||||
|
|
||||||
|
tt.AssertEqual(t, "Name", "K2", key2.Name)
|
||||||
|
tt.AssertEqual(t, "Permissions", "CS", key2.Permissions)
|
||||||
|
tt.AssertEqual(t, "AllChannels", true, key2.AllChannels)
|
||||||
|
tt.AssertEqual(t, "Channels.Len", 0, len(key2.Channels))
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
key2 := tt.RequestAuthPost[keyobj](t, data.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/keys", data.UID), gin.H{
|
||||||
|
"name": "K3",
|
||||||
|
"permissions": "CS",
|
||||||
|
"channels": []string{chanid},
|
||||||
|
})
|
||||||
|
|
||||||
|
tt.AssertEqual(t, "Name", "K3", key2.Name)
|
||||||
|
tt.AssertEqual(t, "Permissions", "CS", key2.Permissions)
|
||||||
|
tt.AssertEqual(t, "AllChannels", false, key2.AllChannels)
|
||||||
|
tt.AssertEqual(t, "Channels.Len", 1, len(key2.Channels))
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
key2 := tt.RequestAuthPost[keyobj](t, data.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/keys", data.UID), gin.H{
|
||||||
|
"name": "K4",
|
||||||
|
"permissions": "CS",
|
||||||
|
"all_channels": false,
|
||||||
|
})
|
||||||
|
|
||||||
|
tt.AssertEqual(t, "Name", "K4", key2.Name)
|
||||||
|
tt.AssertEqual(t, "Permissions", "CS", key2.Permissions)
|
||||||
|
tt.AssertEqual(t, "AllChannels", false, key2.AllChannels)
|
||||||
|
tt.AssertEqual(t, "Channels.Len", 0, len(key2.Channels))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -300,7 +300,7 @@ pre, pre span
|
|||||||
}
|
}
|
||||||
|
|
||||||
.display_none {
|
.display_none {
|
||||||
display: none;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
#theme-switch {
|
#theme-switch {
|
||||||
|
@@ -23,12 +23,12 @@
|
|||||||
|
|
||||||
<div class="row responsive-label">
|
<div class="row responsive-label">
|
||||||
<div class="col-sm-12 col-md-3"><label for="uid" class="doc">UserID</label></div>
|
<div class="col-sm-12 col-md-3"><label for="uid" class="doc">UserID</label></div>
|
||||||
<div class="col-sm-12 col-md"><input placeholder="UserID" id="uid" class="doc" type="number"></div>
|
<div class="col-sm-12 col-md"><input placeholder="UserID" id="uid" class="doc" type="text" pattern="USR[A-Za-z0-9]{21}"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row responsive-label">
|
<div class="row responsive-label">
|
||||||
<div class="col-sm-12 col-md-3"><label for="ukey" class="doc">Authentification Key</label></div>
|
<div class="col-sm-12 col-md-3"><label for="ukey" class="doc">Authentification Key</label></div>
|
||||||
<div class="col-sm-12 col-md"><input placeholder="Key" id="ukey" class="doc" type="text" maxlength="64"></div>
|
<div class="col-sm-12 col-md"><input placeholder="Key" id="ukey" class="doc" type="text" pattern="[A-Za-z0-9]{64}"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row responsive-label">
|
<div class="row responsive-label">
|
||||||
|
@@ -17,7 +17,6 @@ function send()
|
|||||||
|
|
||||||
uid.classList.remove('input-invalid');
|
uid.classList.remove('input-invalid');
|
||||||
key.classList.remove('input-invalid');
|
key.classList.remove('input-invalid');
|
||||||
msg.classList.remove('input-invalid');
|
|
||||||
cnt.classList.remove('input-invalid');
|
cnt.classList.remove('input-invalid');
|
||||||
pio.classList.remove('input-invalid');
|
pio.classList.remove('input-invalid');
|
||||||
|
|
||||||
@@ -30,7 +29,7 @@ function send()
|
|||||||
if (cha.value !== '') data.append('channel', cha.value);
|
if (cha.value !== '') data.append('channel', cha.value);
|
||||||
|
|
||||||
let xhr = new XMLHttpRequest();
|
let xhr = new XMLHttpRequest();
|
||||||
xhr.open('POST', '/send.php', true);
|
xhr.open('POST', '/', true);
|
||||||
xhr.onreadystatechange = function ()
|
xhr.onreadystatechange = function ()
|
||||||
{
|
{
|
||||||
if (xhr.readyState !== 4) return;
|
if (xhr.readyState !== 4) return;
|
||||||
|
@@ -1,8 +1,8 @@
|
|||||||
<div class="highlight"><pre><span></span><span class="ch">#!/usr/bin/env bash</span>
|
<div class="highlight"><pre><span></span><span class="ch">#!/usr/bin/env bash</span>
|
||||||
|
|
||||||
<span class="c1">#</span>
|
<span class="c1">#</span>
|
||||||
<span class="c1"># Wrapper around SCN ( https://scn.blackforestbytes.com/ )</span>
|
<span class="c1"># Wrapper around SCN ( https://simplecloudnotifier.de/ )</span>
|
||||||
<span class="c1"># ========================================================</span>
|
<span class="c1"># ======================================================</span>
|
||||||
<span class="c1">#</span>
|
<span class="c1">#</span>
|
||||||
<span class="c1"># ./scn_send [@channel] title [content] [priority]</span>
|
<span class="c1"># ./scn_send [@channel] title [content] [priority]</span>
|
||||||
<span class="c1">#</span>
|
<span class="c1">#</span>
|
||||||
@@ -36,7 +36,7 @@ usage<span class="o">()</span><span class="w"> </span><span class="o">{</span>
|
|||||||
|
|
||||||
<span class="nv">args</span><span class="o">=(</span><span class="w"> </span><span class="s2">"</span><span class="nv">$@</span><span class="s2">"</span><span class="w"> </span><span class="o">)</span>
|
<span class="nv">args</span><span class="o">=(</span><span class="w"> </span><span class="s2">"</span><span class="nv">$@</span><span class="s2">"</span><span class="w"> </span><span class="o">)</span>
|
||||||
|
|
||||||
<span class="nv">title</span><span class="o">=</span><span class="nv">$1</span>
|
<span class="nv">title</span><span class="o">=</span><span class="s2">""</span>
|
||||||
<span class="nv">content</span><span class="o">=</span><span class="s2">""</span>
|
<span class="nv">content</span><span class="o">=</span><span class="s2">""</span>
|
||||||
<span class="nv">channel</span><span class="o">=</span><span class="s2">""</span>
|
<span class="nv">channel</span><span class="o">=</span><span class="s2">""</span>
|
||||||
<span class="nv">priority</span><span class="o">=</span><span class="m">1</span>
|
<span class="nv">priority</span><span class="o">=</span><span class="m">1</span>
|
||||||
@@ -52,7 +52,7 @@ usage<span class="o">()</span><span class="w"> </span><span class="o">{</span>
|
|||||||
|
|
||||||
<span class="k">if</span><span class="w"> </span><span class="o">[[</span><span class="w"> </span><span class="s2">"</span><span class="si">${</span><span class="nv">args</span><span class="p">[0]</span><span class="si">}</span><span class="s2">"</span><span class="w"> </span><span class="o">=</span>~<span class="w"> </span>^@.*<span class="w"> </span><span class="o">]]</span><span class="p">;</span><span class="w"> </span><span class="k">then</span>
|
<span class="k">if</span><span class="w"> </span><span class="o">[[</span><span class="w"> </span><span class="s2">"</span><span class="si">${</span><span class="nv">args</span><span class="p">[0]</span><span class="si">}</span><span class="s2">"</span><span class="w"> </span><span class="o">=</span>~<span class="w"> </span>^@.*<span class="w"> </span><span class="o">]]</span><span class="p">;</span><span class="w"> </span><span class="k">then</span>
|
||||||
<span class="w"> </span><span class="nv">channel</span><span class="o">=</span><span class="s2">"</span><span class="si">${</span><span class="nv">args</span><span class="p">[0]</span><span class="si">}</span><span class="s2">"</span>
|
<span class="w"> </span><span class="nv">channel</span><span class="o">=</span><span class="s2">"</span><span class="si">${</span><span class="nv">args</span><span class="p">[0]</span><span class="si">}</span><span class="s2">"</span>
|
||||||
<span class="w"> </span><span class="nb">unset</span><span class="w"> </span><span class="s2">"args[0]"</span>
|
<span class="w"> </span><span class="nv">args</span><span class="o">=(</span><span class="s2">"</span><span class="si">${</span><span class="nv">args</span><span class="p">[@]:</span><span class="nv">1</span><span class="si">}</span><span class="s2">"</span><span class="o">)</span>
|
||||||
<span class="w"> </span><span class="nv">channel</span><span class="o">=</span><span class="s2">"</span><span class="si">${</span><span class="nv">channel</span><span class="p">:</span><span class="nv">1</span><span class="si">}</span><span class="s2">"</span>
|
<span class="w"> </span><span class="nv">channel</span><span class="o">=</span><span class="s2">"</span><span class="si">${</span><span class="nv">channel</span><span class="p">:</span><span class="nv">1</span><span class="si">}</span><span class="s2">"</span>
|
||||||
<span class="k">fi</span>
|
<span class="k">fi</span>
|
||||||
|
|
||||||
@@ -63,24 +63,49 @@ usage<span class="o">()</span><span class="w"> </span><span class="o">{</span>
|
|||||||
<span class="k">fi</span>
|
<span class="k">fi</span>
|
||||||
|
|
||||||
<span class="nv">title</span><span class="o">=</span><span class="s2">"</span><span class="si">${</span><span class="nv">args</span><span class="p">[0]</span><span class="si">}</span><span class="s2">"</span>
|
<span class="nv">title</span><span class="o">=</span><span class="s2">"</span><span class="si">${</span><span class="nv">args</span><span class="p">[0]</span><span class="si">}</span><span class="s2">"</span>
|
||||||
|
<span class="nv">args</span><span class="o">=(</span><span class="s2">"</span><span class="si">${</span><span class="nv">args</span><span class="p">[@]:</span><span class="nv">1</span><span class="si">}</span><span class="s2">"</span><span class="o">)</span>
|
||||||
|
|
||||||
<span class="nv">content</span><span class="o">=</span><span class="s2">""</span>
|
<span class="nv">content</span><span class="o">=</span><span class="s2">""</span>
|
||||||
|
|
||||||
<span class="k">if</span><span class="w"> </span><span class="o">[</span><span class="w"> </span><span class="si">${#</span><span class="nv">args</span><span class="p">[@]</span><span class="si">}</span><span class="w"> </span>-gt<span class="w"> </span><span class="m">1</span><span class="w"> </span><span class="o">]</span><span class="p">;</span><span class="w"> </span><span class="k">then</span>
|
<span class="k">if</span><span class="w"> </span><span class="o">[</span><span class="w"> </span><span class="si">${#</span><span class="nv">args</span><span class="p">[@]</span><span class="si">}</span><span class="w"> </span>-gt<span class="w"> </span><span class="m">0</span><span class="w"> </span><span class="o">]</span><span class="p">;</span><span class="w"> </span><span class="k">then</span>
|
||||||
<span class="w"> </span><span class="nv">content</span><span class="o">=</span><span class="s2">"</span><span class="si">${</span><span class="nv">args</span><span class="p">[0]</span><span class="si">}</span><span class="s2">"</span>
|
<span class="w"> </span><span class="nv">content</span><span class="o">=</span><span class="s2">"</span><span class="si">${</span><span class="nv">args</span><span class="p">[0]</span><span class="si">}</span><span class="s2">"</span>
|
||||||
<span class="w"> </span><span class="nb">unset</span><span class="w"> </span><span class="s2">"args[0]"</span>
|
<span class="w"> </span><span class="nv">args</span><span class="o">=(</span><span class="s2">"</span><span class="si">${</span><span class="nv">args</span><span class="p">[@]:</span><span class="nv">1</span><span class="si">}</span><span class="s2">"</span><span class="o">)</span>
|
||||||
<span class="k">fi</span>
|
<span class="k">fi</span>
|
||||||
|
|
||||||
<span class="k">if</span><span class="w"> </span><span class="o">[</span><span class="w"> </span><span class="si">${#</span><span class="nv">args</span><span class="p">[@]</span><span class="si">}</span><span class="w"> </span>-gt<span class="w"> </span><span class="m">1</span><span class="w"> </span><span class="o">]</span><span class="p">;</span><span class="w"> </span><span class="k">then</span>
|
<span class="k">if</span><span class="w"> </span><span class="o">[</span><span class="w"> </span><span class="si">${#</span><span class="nv">args</span><span class="p">[@]</span><span class="si">}</span><span class="w"> </span>-gt<span class="w"> </span><span class="m">0</span><span class="w"> </span><span class="o">]</span><span class="p">;</span><span class="w"> </span><span class="k">then</span>
|
||||||
<span class="w"> </span><span class="nv">priority</span><span class="o">=</span><span class="s2">"</span><span class="si">${</span><span class="nv">args</span><span class="p">[0]</span><span class="si">}</span><span class="s2">"</span>
|
<span class="w"> </span><span class="nv">priority</span><span class="o">=</span><span class="s2">"</span><span class="si">${</span><span class="nv">args</span><span class="p">[0]</span><span class="si">}</span><span class="s2">"</span>
|
||||||
<span class="w"> </span><span class="nb">unset</span><span class="w"> </span><span class="s2">"args[0]"</span>
|
<span class="w"> </span><span class="nv">args</span><span class="o">=(</span><span class="s2">"</span><span class="si">${</span><span class="nv">args</span><span class="p">[@]:</span><span class="nv">1</span><span class="si">}</span><span class="s2">"</span><span class="o">)</span>
|
||||||
<span class="k">fi</span>
|
<span class="k">fi</span>
|
||||||
|
|
||||||
<span class="k">if</span><span class="w"> </span><span class="o">[</span><span class="w"> </span><span class="si">${#</span><span class="nv">args</span><span class="p">[@]</span><span class="si">}</span><span class="w"> </span>-gt<span class="w"> </span><span class="m">1</span><span class="w"> </span><span class="o">]</span><span class="p">;</span><span class="w"> </span><span class="k">then</span>
|
<span class="k">if</span><span class="w"> </span><span class="o">[</span><span class="w"> </span><span class="si">${#</span><span class="nv">args</span><span class="p">[@]</span><span class="si">}</span><span class="w"> </span>-gt<span class="w"> </span><span class="m">0</span><span class="w"> </span><span class="o">]</span><span class="p">;</span><span class="w"> </span><span class="k">then</span>
|
||||||
<span class="w"> </span>rederr<span class="w"> </span><span class="s2">"Too many arguments to scn_send"</span>
|
<span class="w"> </span>rederr<span class="w"> </span><span class="s2">"Too many arguments to scn_send"</span>
|
||||||
<span class="w"> </span>usage
|
<span class="w"> </span>usage
|
||||||
<span class="w"> </span><span class="nb">exit</span><span class="w"> </span><span class="m">1</span>
|
<span class="w"> </span><span class="nb">exit</span><span class="w"> </span><span class="m">1</span>
|
||||||
<span class="k">fi</span>
|
<span class="k">fi</span>
|
||||||
|
|
||||||
|
<span class="nv">curlparams</span><span class="o">=()</span>
|
||||||
|
|
||||||
|
<span class="nv">curlparams</span><span class="o">+=(</span><span class="w"> </span><span class="s2">"--data"</span><span class="w"> </span><span class="s2">"user_id=</span><span class="si">${</span><span class="nv">SCN_UID</span><span class="si">}</span><span class="s2">"</span><span class="w"> </span><span class="o">)</span>
|
||||||
|
<span class="nv">curlparams</span><span class="o">+=(</span><span class="w"> </span><span class="s2">"--data"</span><span class="w"> </span><span class="s2">"key=</span><span class="si">${</span><span class="nv">SCN_KEY</span><span class="si">}</span><span class="s2">"</span><span class="w"> </span><span class="o">)</span>
|
||||||
|
<span class="nv">curlparams</span><span class="o">+=(</span><span class="w"> </span><span class="s2">"--data"</span><span class="w"> </span><span class="s2">"title=</span><span class="nv">$title</span><span class="s2">"</span><span class="w"> </span><span class="o">)</span>
|
||||||
|
<span class="nv">curlparams</span><span class="o">+=(</span><span class="w"> </span><span class="s2">"--data"</span><span class="w"> </span><span class="s2">"timestamp=</span><span class="nv">$sendtime</span><span class="s2">"</span><span class="w"> </span><span class="o">)</span>
|
||||||
|
<span class="nv">curlparams</span><span class="o">+=(</span><span class="w"> </span><span class="s2">"--data"</span><span class="w"> </span><span class="s2">"msg_id=</span><span class="nv">$usr_msg_id</span><span class="s2">"</span><span class="w"> </span><span class="o">)</span>
|
||||||
|
|
||||||
|
<span class="k">if</span><span class="w"> </span><span class="o">[[</span><span class="w"> </span>-n<span class="w"> </span><span class="s2">"</span><span class="nv">$content</span><span class="s2">"</span><span class="w"> </span><span class="o">]]</span><span class="p">;</span><span class="w"> </span><span class="k">then</span>
|
||||||
|
<span class="w"> </span><span class="nv">curlparams</span><span class="o">+=(</span><span class="s2">"--data"</span><span class="w"> </span><span class="s2">"content=</span><span class="nv">$content</span><span class="s2">"</span><span class="o">)</span>
|
||||||
|
<span class="k">fi</span>
|
||||||
|
|
||||||
|
<span class="k">if</span><span class="w"> </span><span class="o">[[</span><span class="w"> </span>-n<span class="w"> </span><span class="s2">"</span><span class="nv">$priority</span><span class="s2">"</span><span class="w"> </span><span class="o">]]</span><span class="p">;</span><span class="w"> </span><span class="k">then</span>
|
||||||
|
<span class="w"> </span><span class="nv">curlparams</span><span class="o">+=(</span><span class="s2">"--data"</span><span class="w"> </span><span class="s2">"priority=</span><span class="nv">$priority</span><span class="s2">"</span><span class="o">)</span>
|
||||||
|
<span class="k">fi</span>
|
||||||
|
|
||||||
|
<span class="k">if</span><span class="w"> </span><span class="o">[[</span><span class="w"> </span>-n<span class="w"> </span><span class="s2">"</span><span class="nv">$channel</span><span class="s2">"</span><span class="w"> </span><span class="o">]]</span><span class="p">;</span><span class="w"> </span><span class="k">then</span>
|
||||||
|
<span class="w"> </span><span class="nv">curlparams</span><span class="o">+=(</span><span class="s2">"--data"</span><span class="w"> </span><span class="s2">"channel=</span><span class="nv">$channel</span><span class="s2">"</span><span class="o">)</span>
|
||||||
|
<span class="k">fi</span>
|
||||||
|
|
||||||
|
<span class="k">if</span><span class="w"> </span><span class="o">[[</span><span class="w"> </span>-n<span class="w"> </span><span class="s2">"</span><span class="nv">$sender</span><span class="s2">"</span><span class="w"> </span><span class="o">]]</span><span class="p">;</span><span class="w"> </span><span class="k">then</span>
|
||||||
|
<span class="w"> </span><span class="nv">curlparams</span><span class="o">+=(</span><span class="s2">"--data"</span><span class="w"> </span><span class="s2">"sender_name=</span><span class="nv">$sender</span><span class="s2">"</span><span class="o">)</span>
|
||||||
|
<span class="k">fi</span>
|
||||||
|
|
||||||
<span class="k">while</span><span class="w"> </span><span class="nb">true</span><span class="w"> </span><span class="p">;</span><span class="w"> </span><span class="k">do</span>
|
<span class="k">while</span><span class="w"> </span><span class="nb">true</span><span class="w"> </span><span class="p">;</span><span class="w"> </span><span class="k">do</span>
|
||||||
|
|
||||||
@@ -89,16 +114,8 @@ usage<span class="o">()</span><span class="w"> </span><span class="o">{</span>
|
|||||||
<span class="w"> </span><span class="nv">curlresp</span><span class="o">=</span><span class="k">$(</span>curl<span class="w"> </span>--silent<span class="w"> </span><span class="se">\</span>
|
<span class="w"> </span><span class="nv">curlresp</span><span class="o">=</span><span class="k">$(</span>curl<span class="w"> </span>--silent<span class="w"> </span><span class="se">\</span>
|
||||||
<span class="w"> </span>--output<span class="w"> </span><span class="s2">"</span><span class="si">${</span><span class="nv">outf</span><span class="si">}</span><span class="s2">"</span><span class="w"> </span><span class="se">\</span>
|
<span class="w"> </span>--output<span class="w"> </span><span class="s2">"</span><span class="si">${</span><span class="nv">outf</span><span class="si">}</span><span class="s2">"</span><span class="w"> </span><span class="se">\</span>
|
||||||
<span class="w"> </span>--write-out<span class="w"> </span><span class="s2">"%{http_code}"</span><span class="w"> </span><span class="se">\</span>
|
<span class="w"> </span>--write-out<span class="w"> </span><span class="s2">"%{http_code}"</span><span class="w"> </span><span class="se">\</span>
|
||||||
<span class="w"> </span>--data<span class="w"> </span><span class="s2">"user_id=</span><span class="nv">$user_id</span><span class="s2">"</span><span class="w"> </span><span class="se">\</span>
|
<span class="w"> </span><span class="s2">"</span><span class="si">${</span><span class="nv">curlparams</span><span class="p">[@]</span><span class="si">}</span><span class="s2">"</span><span class="w"> </span><span class="se">\</span>
|
||||||
<span class="w"> </span>--data<span class="w"> </span><span class="s2">"key=</span><span class="nv">$user_key</span><span class="s2">"</span><span class="w"> </span><span class="se">\</span>
|
<span class="w"> </span><span class="s2">"https://simplecloudnotifier.de/"</span><span class="w"> </span><span class="k">)</span>
|
||||||
<span class="w"> </span>--data<span class="w"> </span><span class="s2">"title=</span><span class="nv">$title</span><span class="s2">"</span><span class="w"> </span><span class="se">\</span>
|
|
||||||
<span class="w"> </span>--data<span class="w"> </span><span class="s2">"timestamp=</span><span class="nv">$sendtime</span><span class="s2">"</span><span class="w"> </span><span class="se">\</span>
|
|
||||||
<span class="w"> </span>--data<span class="w"> </span><span class="s2">"content=</span><span class="nv">$content</span><span class="s2">"</span><span class="w"> </span><span class="se">\</span>
|
|
||||||
<span class="w"> </span>--data<span class="w"> </span><span class="s2">"priority=</span><span class="nv">$priority</span><span class="s2">"</span><span class="w"> </span><span class="se">\</span>
|
|
||||||
<span class="w"> </span>--data<span class="w"> </span><span class="s2">"msg_id=</span><span class="nv">$usr_msg_id</span><span class="s2">"</span><span class="w"> </span><span class="se">\</span>
|
|
||||||
<span class="w"> </span>--data<span class="w"> </span><span class="s2">"channel=</span><span class="nv">$channel</span><span class="s2">"</span><span class="w"> </span><span class="se">\</span>
|
|
||||||
<span class="w"> </span>--data<span class="w"> </span><span class="s2">"sender_name=</span><span class="nv">$sender</span><span class="s2">"</span><span class="w"> </span><span class="se">\</span>
|
|
||||||
<span class="w"> </span><span class="s2">"https://scn.blackforestbytes.com/"</span><span class="w"> </span><span class="k">)</span>
|
|
||||||
|
|
||||||
<span class="w"> </span><span class="nv">curlout</span><span class="o">=</span><span class="s2">"</span><span class="k">$(</span>cat<span class="w"> </span><span class="s2">"</span><span class="nv">$outf</span><span class="s2">"</span><span class="k">)</span><span class="s2">"</span>
|
<span class="w"> </span><span class="nv">curlout</span><span class="o">=</span><span class="s2">"</span><span class="k">$(</span>cat<span class="w"> </span><span class="s2">"</span><span class="nv">$outf</span><span class="s2">"</span><span class="k">)</span><span class="s2">"</span>
|
||||||
<span class="w"> </span>rm<span class="w"> </span><span class="s2">"</span><span class="nv">$outf</span><span class="s2">"</span>
|
<span class="w"> </span>rm<span class="w"> </span><span class="s2">"</span><span class="nv">$outf</span><span class="s2">"</span>
|
||||||
|
@@ -1,8 +1,8 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
#
|
#
|
||||||
# Wrapper around SCN ( https://scn.blackforestbytes.com/ )
|
# Wrapper around SCN ( https://simplecloudnotifier.de/ )
|
||||||
# ========================================================
|
# ======================================================
|
||||||
#
|
#
|
||||||
# ./scn_send [@channel] title [content] [priority]
|
# ./scn_send [@channel] title [content] [priority]
|
||||||
#
|
#
|
||||||
@@ -36,7 +36,7 @@ function green() { if cfgcol; then echo -e "\x1B[32m$1\x1B[0m"; else ec
|
|||||||
|
|
||||||
args=( "$@" )
|
args=( "$@" )
|
||||||
|
|
||||||
title=$1
|
title=""
|
||||||
content=""
|
content=""
|
||||||
channel=""
|
channel=""
|
||||||
priority=1
|
priority=1
|
||||||
@@ -52,7 +52,7 @@ fi
|
|||||||
|
|
||||||
if [[ "${args[0]}" =~ ^@.* ]]; then
|
if [[ "${args[0]}" =~ ^@.* ]]; then
|
||||||
channel="${args[0]}"
|
channel="${args[0]}"
|
||||||
unset "args[0]"
|
args=("${args[@]:1}")
|
||||||
channel="${channel:1}"
|
channel="${channel:1}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -63,24 +63,49 @@ if [ ${#args[@]} -lt 1 ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
title="${args[0]}"
|
title="${args[0]}"
|
||||||
|
args=("${args[@]:1}")
|
||||||
|
|
||||||
content=""
|
content=""
|
||||||
|
|
||||||
if [ ${#args[@]} -gt 1 ]; then
|
if [ ${#args[@]} -gt 0 ]; then
|
||||||
content="${args[0]}"
|
content="${args[0]}"
|
||||||
unset "args[0]"
|
args=("${args[@]:1}")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ ${#args[@]} -gt 1 ]; then
|
if [ ${#args[@]} -gt 0 ]; then
|
||||||
priority="${args[0]}"
|
priority="${args[0]}"
|
||||||
unset "args[0]"
|
args=("${args[@]:1}")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ ${#args[@]} -gt 1 ]; then
|
if [ ${#args[@]} -gt 0 ]; then
|
||||||
rederr "Too many arguments to scn_send"
|
rederr "Too many arguments to scn_send"
|
||||||
usage
|
usage
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
curlparams=()
|
||||||
|
|
||||||
|
curlparams+=( "--data" "user_id=${SCN_UID}" )
|
||||||
|
curlparams+=( "--data" "key=${SCN_KEY}" )
|
||||||
|
curlparams+=( "--data" "title=$title" )
|
||||||
|
curlparams+=( "--data" "timestamp=$sendtime" )
|
||||||
|
curlparams+=( "--data" "msg_id=$usr_msg_id" )
|
||||||
|
|
||||||
|
if [[ -n "$content" ]]; then
|
||||||
|
curlparams+=("--data" "content=$content")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -n "$priority" ]]; then
|
||||||
|
curlparams+=("--data" "priority=$priority")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -n "$channel" ]]; then
|
||||||
|
curlparams+=("--data" "channel=$channel")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -n "$sender" ]]; then
|
||||||
|
curlparams+=("--data" "sender_name=$sender")
|
||||||
|
fi
|
||||||
|
|
||||||
while true ; do
|
while true ; do
|
||||||
|
|
||||||
@@ -89,16 +114,8 @@ while true ; do
|
|||||||
curlresp=$(curl --silent \
|
curlresp=$(curl --silent \
|
||||||
--output "${outf}" \
|
--output "${outf}" \
|
||||||
--write-out "%{http_code}" \
|
--write-out "%{http_code}" \
|
||||||
--data "user_id=$user_id" \
|
"${curlparams[@]}" \
|
||||||
--data "key=$user_key" \
|
"https://simplecloudnotifier.de/" )
|
||||||
--data "title=$title" \
|
|
||||||
--data "timestamp=$sendtime" \
|
|
||||||
--data "content=$content" \
|
|
||||||
--data "priority=$priority" \
|
|
||||||
--data "msg_id=$usr_msg_id" \
|
|
||||||
--data "channel=$channel" \
|
|
||||||
--data "sender_name=$sender" \
|
|
||||||
"https://scn.blackforestbytes.com/" )
|
|
||||||
|
|
||||||
curlout="$(cat "$outf")"
|
curlout="$(cat "$outf")"
|
||||||
rm "$outf"
|
rm "$outf"
|
||||||
|
Reference in New Issue
Block a user