Implement /shoutrrr endpoint
This commit is contained in:
@@ -28,8 +28,10 @@ func NewExternalHandler(app *logic.Application) ExternalHandler {
|
|||||||
|
|
||||||
// UptimeKuma swaggerdoc
|
// UptimeKuma swaggerdoc
|
||||||
//
|
//
|
||||||
// @Summary Send a new message
|
// @Summary Send a new message (uses uptime-kuma notification schema)
|
||||||
// @Description All parameter can be set via query-parameter or the json body. Only UserID, UserKey and Title are required
|
// @Description Set necessary parameter via query (key, channel etc.), title+message are build from uptime-kuma payload
|
||||||
|
// @Description You can specify different channels/priorities for [up] and [down] notifications
|
||||||
|
//
|
||||||
// @Tags External
|
// @Tags External
|
||||||
//
|
//
|
||||||
// @Param query_data query handler.UptimeKuma.query false " "
|
// @Param query_data query handler.UptimeKuma.query false " "
|
||||||
@@ -136,3 +138,58 @@ func (h ExternalHandler) UptimeKuma(pctx ginext.PreContext) ginext.HTTPResponse
|
|||||||
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Shoutrrr swaggerdoc
|
||||||
|
//
|
||||||
|
// @Summary Send a new message (uses shoutrrr generic:// format=json schema)
|
||||||
|
// @Description Set necessary parameter via query (key, channel etc.), title+message are set via the shoutrrr payload
|
||||||
|
// @Description Use the shoutrrr format `generic://{{url}}?template=json`
|
||||||
|
//
|
||||||
|
// @Tags External
|
||||||
|
//
|
||||||
|
// @Param query_data query handler.Shoutrrr.query false " "
|
||||||
|
// @Param post_body body handler.Shoutrrr.body false " "
|
||||||
|
//
|
||||||
|
// @Success 200 {object} handler.Shoutrrr.response
|
||||||
|
// @Failure 400 {object} ginresp.apiError
|
||||||
|
// @Failure 401 {object} ginresp.apiError "The user_key is wrong"
|
||||||
|
// @Failure 403 {object} ginresp.apiError "The user has exceeded its daily quota - wait 24 hours or upgrade your account"
|
||||||
|
// @Failure 500 {object} ginresp.apiError "An internal server error occurred - try again later"
|
||||||
|
//
|
||||||
|
// @Router /external/v1/uptime-kuma [POST]
|
||||||
|
func (h ExternalHandler) Shoutrrr(pctx ginext.PreContext) ginext.HTTPResponse {
|
||||||
|
type query struct {
|
||||||
|
KeyToken *string `form:"key" example:"P3TNH8mvv14fm"`
|
||||||
|
Channel *string `form:"channel"`
|
||||||
|
Priority *int `form:"priority"`
|
||||||
|
SenderName *string `form:"senderName"`
|
||||||
|
}
|
||||||
|
type body struct {
|
||||||
|
Title string `json:"title"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
}
|
||||||
|
type response struct {
|
||||||
|
MessageID models.MessageID `json:"message_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var b body
|
||||||
|
var q query
|
||||||
|
ctx, g, errResp := pctx.Query(&q).Body(&b).Start()
|
||||||
|
if errResp != nil {
|
||||||
|
return *errResp
|
||||||
|
}
|
||||||
|
defer ctx.Cancel()
|
||||||
|
|
||||||
|
return h.app.DoRequest(ctx, g, models.TLockReadWrite, func(ctx *logic.AppContext, finishSuccess func(r ginext.HTTPResponse) ginext.HTTPResponse) ginext.HTTPResponse {
|
||||||
|
|
||||||
|
okResp, errResp := h.app.SendMessage(g, ctx, q.KeyToken, q.Channel, &b.Title, &b.Message, q.Priority, nil, nil, q.SenderName)
|
||||||
|
if errResp != nil {
|
||||||
|
return *errResp
|
||||||
|
}
|
||||||
|
|
||||||
|
return finishSuccess(ginext.JSON(http.StatusOK, response{
|
||||||
|
MessageID: okResp.Message.MessageID,
|
||||||
|
}))
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -182,6 +182,7 @@ func (r *Router) Init(e *ginext.GinWrapper) error {
|
|||||||
sendAPI.POST("/send.php").Handle(r.compatHandler.SendMessage)
|
sendAPI.POST("/send.php").Handle(r.compatHandler.SendMessage)
|
||||||
|
|
||||||
sendAPI.POST("/external/v1/uptime-kuma").Handle(r.externalHandler.UptimeKuma)
|
sendAPI.POST("/external/v1/uptime-kuma").Handle(r.externalHandler.UptimeKuma)
|
||||||
|
sendAPI.POST("/external/v1/shoutrrr").Handle(r.externalHandler.Shoutrrr)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
127
scnserver/test/shoutrrr_test.go
Normal file
127
scnserver/test/shoutrrr_test.go
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"blackforestbytes.com/simplecloudnotifier/push"
|
||||||
|
tt "blackforestbytes.com/simplecloudnotifier/test/util"
|
||||||
|
"fmt"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestShoutrrrBasic(t *testing.T) {
|
||||||
|
ws, baseUrl, stop := tt.StartSimpleWebserver(t)
|
||||||
|
defer stop()
|
||||||
|
|
||||||
|
data := tt.InitSingleData(t, ws)
|
||||||
|
|
||||||
|
pusher := ws.Pusher.(*push.TestSink)
|
||||||
|
|
||||||
|
suffix := fmt.Sprintf("/external/v1/shoutrrr?key=%v", data.SendKey)
|
||||||
|
_ = tt.RequestPost[gin.H](t, baseUrl, suffix, gin.H{
|
||||||
|
"title": "Test Title",
|
||||||
|
"message": "Test Message Content",
|
||||||
|
})
|
||||||
|
|
||||||
|
tt.AssertEqual(t, "messageCount", 1, len(pusher.Data))
|
||||||
|
tt.AssertStrRepEqual(t, "msg.title", "Test Title", pusher.Last().Message.Title)
|
||||||
|
tt.AssertStrRepEqual(t, "msg.content", "Test Message Content", pusher.Last().Message.Content)
|
||||||
|
|
||||||
|
type mglist struct {
|
||||||
|
Messages []gin.H `json:"messages"`
|
||||||
|
}
|
||||||
|
|
||||||
|
msgList1 := tt.RequestAuthGet[mglist](t, data.AdminKey, baseUrl, "/api/v2/messages")
|
||||||
|
tt.AssertEqual(t, "len(messages)", 1, len(msgList1.Messages))
|
||||||
|
tt.AssertStrRepEqual(t, "msg.title", "Test Title", msgList1.Messages[0]["title"])
|
||||||
|
tt.AssertStrRepEqual(t, "msg.content", "Test Message Content", msgList1.Messages[0]["content"])
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestShoutrrrChannelNone(t *testing.T) {
|
||||||
|
ws, baseUrl, stop := tt.StartSimpleWebserver(t)
|
||||||
|
defer stop()
|
||||||
|
|
||||||
|
data := tt.InitSingleData(t, ws)
|
||||||
|
|
||||||
|
pusher := ws.Pusher.(*push.TestSink)
|
||||||
|
|
||||||
|
suffix := fmt.Sprintf("/external/v1/shoutrrr?key=%v", data.SendKey)
|
||||||
|
_ = tt.RequestPost[gin.H](t, baseUrl, suffix, gin.H{
|
||||||
|
"title": "Test Title",
|
||||||
|
"message": "Test Message",
|
||||||
|
})
|
||||||
|
|
||||||
|
tt.AssertEqual(t, "messageCount", 1, len(pusher.Data))
|
||||||
|
tt.AssertStrRepEqual(t, "msg.channel", "main", pusher.Last().Message.ChannelInternalName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestShoutrrrChannelCustom(t *testing.T) {
|
||||||
|
ws, baseUrl, stop := tt.StartSimpleWebserver(t)
|
||||||
|
defer stop()
|
||||||
|
|
||||||
|
data := tt.InitSingleData(t, ws)
|
||||||
|
|
||||||
|
pusher := ws.Pusher.(*push.TestSink)
|
||||||
|
|
||||||
|
suffix := fmt.Sprintf("/external/v1/shoutrrr?key=%v&channel=CTEST", data.SendKey)
|
||||||
|
_ = tt.RequestPost[gin.H](t, baseUrl, suffix, gin.H{
|
||||||
|
"title": "Test Title",
|
||||||
|
"message": "Test Message",
|
||||||
|
})
|
||||||
|
|
||||||
|
tt.AssertEqual(t, "messageCount", 1, len(pusher.Data))
|
||||||
|
tt.AssertStrRepEqual(t, "msg.channel", "CTEST", pusher.Last().Message.ChannelInternalName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestShoutrrrPriorityNone(t *testing.T) {
|
||||||
|
ws, baseUrl, stop := tt.StartSimpleWebserver(t)
|
||||||
|
defer stop()
|
||||||
|
|
||||||
|
data := tt.InitSingleData(t, ws)
|
||||||
|
|
||||||
|
pusher := ws.Pusher.(*push.TestSink)
|
||||||
|
|
||||||
|
suffix := fmt.Sprintf("/external/v1/shoutrrr?key=%v", data.SendKey)
|
||||||
|
_ = tt.RequestPost[gin.H](t, baseUrl, suffix, gin.H{
|
||||||
|
"title": "Test Title",
|
||||||
|
"message": "Test Message",
|
||||||
|
})
|
||||||
|
|
||||||
|
tt.AssertEqual(t, "messageCount", 1, len(pusher.Data))
|
||||||
|
tt.AssertStrRepEqual(t, "msg.priority", 1, pusher.Last().Message.Priority)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestShoutrrrPrioritySingle(t *testing.T) {
|
||||||
|
ws, baseUrl, stop := tt.StartSimpleWebserver(t)
|
||||||
|
defer stop()
|
||||||
|
|
||||||
|
data := tt.InitSingleData(t, ws)
|
||||||
|
|
||||||
|
pusher := ws.Pusher.(*push.TestSink)
|
||||||
|
|
||||||
|
suffix0 := fmt.Sprintf("/external/v1/shoutrrr?key=%v&priority=0", data.SendKey)
|
||||||
|
_ = tt.RequestPost[gin.H](t, baseUrl, suffix0, gin.H{
|
||||||
|
"title": "Test Title",
|
||||||
|
"message": "Test Message",
|
||||||
|
})
|
||||||
|
|
||||||
|
tt.AssertEqual(t, "messageCount", 1, len(pusher.Data))
|
||||||
|
tt.AssertStrRepEqual(t, "msg.prio", 0, pusher.Last().Message.Priority)
|
||||||
|
|
||||||
|
suffix1 := fmt.Sprintf("/external/v1/shoutrrr?key=%v&priority=1", data.SendKey)
|
||||||
|
_ = tt.RequestPost[gin.H](t, baseUrl, suffix1, gin.H{
|
||||||
|
"title": "Test Title",
|
||||||
|
"message": "Test Message",
|
||||||
|
})
|
||||||
|
|
||||||
|
tt.AssertEqual(t, "messageCount", 2, len(pusher.Data))
|
||||||
|
tt.AssertStrRepEqual(t, "msg.prio", 1, pusher.Last().Message.Priority)
|
||||||
|
|
||||||
|
suffix2 := fmt.Sprintf("/external/v1/shoutrrr?key=%v&priority=2", data.SendKey)
|
||||||
|
_ = tt.RequestPost[gin.H](t, baseUrl, suffix2, gin.H{
|
||||||
|
"title": "Test Title",
|
||||||
|
"message": "Test Message",
|
||||||
|
})
|
||||||
|
|
||||||
|
tt.AssertEqual(t, "messageCount", 3, len(pusher.Data))
|
||||||
|
tt.AssertStrRepEqual(t, "msg.prio", 2, pusher.Last().Message.Priority)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user