uptime kuma webhook endpoint
This commit is contained in:
parent
674714f0f3
commit
bef0b8189e
@ -311,3 +311,87 @@ func (h MessageHandler) sendMessageInternal(g *gin.Context, ctx *logic.AppContex
|
|||||||
CompatMessageID: compatMsgID,
|
CompatMessageID: compatMsgID,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UptimeKumaWebHook swaggerdoc
|
||||||
|
//
|
||||||
|
// @Summary Send a new message
|
||||||
|
// @Description All parameter can be set via query-parameter or the json body. Only UserID, UserKey and Title are required
|
||||||
|
// @Tags External
|
||||||
|
//
|
||||||
|
// @Param query_data query handler.UptimeKumaWebHook.query false " "
|
||||||
|
// @Param post_body body handler.UptimeKumaWebHook.uptimeKumaWebhookBody false " "
|
||||||
|
//
|
||||||
|
// @Success 200 {object} any
|
||||||
|
// @Failure 400 {object} ginresp.apiError
|
||||||
|
// @Failure 401 {object} ginresp.apiError "The user_id was not found or 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 /webhook/uptime-kuma [POST]
|
||||||
|
func (h MessageHandler) UptimeKumaWebHook(g *gin.Context) ginresp.HTTPResponse {
|
||||||
|
type query struct {
|
||||||
|
UserID *models.UserID `form:"user_id" example:"7725"`
|
||||||
|
KeyToken *string `form:"key" example:"P3TNH8mvv14fm"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type uptimeKumaWebhookBody struct {
|
||||||
|
Heartbeat *struct {
|
||||||
|
Time string `json:"time"`
|
||||||
|
Status int `json:"status"`
|
||||||
|
Msg string `json:"msg"`
|
||||||
|
Timezone string `json:"timezone"`
|
||||||
|
TimezoneOffset string `json:"timezoneOffset"`
|
||||||
|
LocalDateTime string `json:"localDateTime"`
|
||||||
|
} `json:"heartbeat"`
|
||||||
|
Monitor *struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Url *string `json:"url"`
|
||||||
|
} `json:"monitor"`
|
||||||
|
Msg string `json:"msg"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var b uptimeKumaWebhookBody
|
||||||
|
var q query
|
||||||
|
|
||||||
|
ctx, httpErr := h.app.StartRequest(g, nil, &q, &b, nil)
|
||||||
|
if httpErr != nil {
|
||||||
|
return *httpErr
|
||||||
|
}
|
||||||
|
defer ctx.Cancel()
|
||||||
|
|
||||||
|
var title = ""
|
||||||
|
|
||||||
|
var content = ""
|
||||||
|
content += fmt.Sprintf("%v\n", b.Msg)
|
||||||
|
if b.Monitor != nil {
|
||||||
|
content += fmt.Sprintf("%v\n", b.Monitor.Name)
|
||||||
|
if b.Monitor.Url != nil {
|
||||||
|
content += fmt.Sprintf("url: %v\n", *b.Monitor.Url)
|
||||||
|
}
|
||||||
|
|
||||||
|
if b.Heartbeat != nil {
|
||||||
|
statusString := "down"
|
||||||
|
|
||||||
|
if b.Heartbeat.Status == 1 {
|
||||||
|
statusString = "up"
|
||||||
|
}
|
||||||
|
title = fmt.Sprintf("%v %v!", b.Monitor.Name, statusString)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if b.Heartbeat != nil {
|
||||||
|
content += "\n===== Heartbeat ======\n"
|
||||||
|
content += fmt.Sprintf("msg: %v\n", b.Heartbeat.Msg)
|
||||||
|
content += fmt.Sprintf("timestamp: %v\n", b.Heartbeat.Time)
|
||||||
|
content += fmt.Sprintf("timezone: %v\n", b.Heartbeat.Timezone)
|
||||||
|
content += fmt.Sprintf("timezone offset: %v\n", b.Heartbeat.TimezoneOffset)
|
||||||
|
content += fmt.Sprintf("local date time: %v\n", b.Heartbeat.TimezoneOffset)
|
||||||
|
}
|
||||||
|
okResp, errResp := h.sendMessageInternal(g, ctx, q.UserID, q.KeyToken, nil, &title, &content, langext.Ptr(1), nil, nil, nil)
|
||||||
|
|
||||||
|
if errResp != nil {
|
||||||
|
return *errResp
|
||||||
|
}
|
||||||
|
return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, okResp))
|
||||||
|
}
|
||||||
|
@ -122,7 +122,6 @@ func (r *Router) Init(e *gin.Engine) error {
|
|||||||
|
|
||||||
apiv2 := e.Group("/api/v2/")
|
apiv2 := e.Group("/api/v2/")
|
||||||
{
|
{
|
||||||
|
|
||||||
apiv2.POST("/users", r.Wrap(r.apiHandler.CreateUser))
|
apiv2.POST("/users", r.Wrap(r.apiHandler.CreateUser))
|
||||||
apiv2.GET("/users/:uid", r.Wrap(r.apiHandler.GetUser))
|
apiv2.GET("/users/:uid", r.Wrap(r.apiHandler.GetUser))
|
||||||
apiv2.PATCH("/users/:uid", r.Wrap(r.apiHandler.UpdateUser))
|
apiv2.PATCH("/users/:uid", r.Wrap(r.apiHandler.UpdateUser))
|
||||||
@ -164,6 +163,9 @@ func (r *Router) Init(e *gin.Engine) error {
|
|||||||
sendAPI.POST("/", r.Wrap(r.messageHandler.SendMessage))
|
sendAPI.POST("/", r.Wrap(r.messageHandler.SendMessage))
|
||||||
sendAPI.POST("/send", r.Wrap(r.messageHandler.SendMessage))
|
sendAPI.POST("/send", r.Wrap(r.messageHandler.SendMessage))
|
||||||
sendAPI.POST("/send.php", r.Wrap(r.messageHandler.SendMessageCompat))
|
sendAPI.POST("/send.php", r.Wrap(r.messageHandler.SendMessageCompat))
|
||||||
|
|
||||||
|
sendAPI.POST("/webhook/uptime-kuma", r.Wrap(r.messageHandler.UptimeKumaWebHook))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ================
|
// ================
|
||||||
|
@ -4,7 +4,7 @@ package models
|
|||||||
|
|
||||||
import "gogs.mikescher.com/BlackForestBytes/goext/langext"
|
import "gogs.mikescher.com/BlackForestBytes/goext/langext"
|
||||||
|
|
||||||
const ChecksumGenerator = "a41b8d265c326a65d7be07c74aa2318064c6307256bd92b684c5adb4a8f82d97"
|
const ChecksumGenerator = "38908fc9adc16eb3a1266e4bca06e50ebc8613c5d3c9a4fea39314115f66544e"
|
||||||
|
|
||||||
type Enum interface {
|
type Enum interface {
|
||||||
Valid() bool
|
Valid() bool
|
||||||
|
@ -2731,6 +2731,69 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"/webhook/uptime-kuma": {
|
||||||
|
"post": {
|
||||||
|
"description": "All parameter can be set via query-parameter or the json body. Only UserID, UserKey and Title are required",
|
||||||
|
"tags": [
|
||||||
|
"External"
|
||||||
|
],
|
||||||
|
"summary": "Send a new message",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"example": "P3TNH8mvv14fm",
|
||||||
|
"name": "key",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"example": "7725",
|
||||||
|
"name": "user_id",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": " ",
|
||||||
|
"name": "post_body",
|
||||||
|
"in": "body",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/handler.UptimeKumaWebHook.uptimeKumaWebhookBody"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"type": "object"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/ginresp.apiError"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "The user_id was not found or the user_key is wrong",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/ginresp.apiError"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"403": {
|
||||||
|
"description": "The user has exceeded its daily quota - wait 24 hours or upgrade your account",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/ginresp.apiError"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "An internal server error occurred - try again later",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/ginresp.apiError"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"definitions": {
|
"definitions": {
|
||||||
@ -3386,6 +3449,45 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"handler.UptimeKumaWebHook.uptimeKumaWebhookBody": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"heartbeat": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"localDateTime": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"msg": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"time": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"timezone": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"timezoneOffset": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"monitor": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"msg": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"handler.pingResponse": {
|
"handler.pingResponse": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
@ -3633,9 +3735,30 @@
|
|||||||
"default_channel": {
|
"default_channel": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"default_priority": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
"is_pro": {
|
"is_pro": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
"max_body_size": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"max_channel_description_length": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"max_channel_name_length": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"max_sender_name_length": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"max_title_length": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"max_user_message_id_length": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
"messages_sent": {
|
"messages_sent": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
@ -3680,9 +3803,30 @@
|
|||||||
"default_channel": {
|
"default_channel": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"default_priority": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
"is_pro": {
|
"is_pro": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
"max_body_size": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"max_channel_description_length": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"max_channel_name_length": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"max_sender_name_length": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"max_title_length": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"max_user_message_id_length": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
"messages_sent": {
|
"messages_sent": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
|
@ -458,6 +458,31 @@ definitions:
|
|||||||
user_id:
|
user_id:
|
||||||
type: integer
|
type: integer
|
||||||
type: object
|
type: object
|
||||||
|
handler.UptimeKumaWebHook.uptimeKumaWebhookBody:
|
||||||
|
properties:
|
||||||
|
heartbeat:
|
||||||
|
properties:
|
||||||
|
localDateTime:
|
||||||
|
type: string
|
||||||
|
msg:
|
||||||
|
type: string
|
||||||
|
time:
|
||||||
|
type: string
|
||||||
|
timezone:
|
||||||
|
type: string
|
||||||
|
timezoneOffset:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
monitor:
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
url:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
msg:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
handler.pingResponse:
|
handler.pingResponse:
|
||||||
properties:
|
properties:
|
||||||
info:
|
info:
|
||||||
@ -621,8 +646,22 @@ definitions:
|
|||||||
properties:
|
properties:
|
||||||
default_channel:
|
default_channel:
|
||||||
type: string
|
type: string
|
||||||
|
default_priority:
|
||||||
|
type: integer
|
||||||
is_pro:
|
is_pro:
|
||||||
type: boolean
|
type: boolean
|
||||||
|
max_body_size:
|
||||||
|
type: integer
|
||||||
|
max_channel_description_length:
|
||||||
|
type: integer
|
||||||
|
max_channel_name_length:
|
||||||
|
type: integer
|
||||||
|
max_sender_name_length:
|
||||||
|
type: integer
|
||||||
|
max_title_length:
|
||||||
|
type: integer
|
||||||
|
max_user_message_id_length:
|
||||||
|
type: integer
|
||||||
messages_sent:
|
messages_sent:
|
||||||
type: integer
|
type: integer
|
||||||
quota_max:
|
quota_max:
|
||||||
@ -652,8 +691,22 @@ definitions:
|
|||||||
type: array
|
type: array
|
||||||
default_channel:
|
default_channel:
|
||||||
type: string
|
type: string
|
||||||
|
default_priority:
|
||||||
|
type: integer
|
||||||
is_pro:
|
is_pro:
|
||||||
type: boolean
|
type: boolean
|
||||||
|
max_body_size:
|
||||||
|
type: integer
|
||||||
|
max_channel_description_length:
|
||||||
|
type: integer
|
||||||
|
max_channel_name_length:
|
||||||
|
type: integer
|
||||||
|
max_sender_name_length:
|
||||||
|
type: integer
|
||||||
|
max_title_length:
|
||||||
|
type: integer
|
||||||
|
max_user_message_id_length:
|
||||||
|
type: integer
|
||||||
messages_sent:
|
messages_sent:
|
||||||
type: integer
|
type: integer
|
||||||
quota_max:
|
quota_max:
|
||||||
@ -2548,6 +2601,49 @@ paths:
|
|||||||
summary: Send a new message (compatibility)
|
summary: Send a new message (compatibility)
|
||||||
tags:
|
tags:
|
||||||
- External
|
- External
|
||||||
|
/webhook/uptime-kuma:
|
||||||
|
post:
|
||||||
|
description: All parameter can be set via query-parameter or the json body.
|
||||||
|
Only UserID, UserKey and Title are required
|
||||||
|
parameters:
|
||||||
|
- example: P3TNH8mvv14fm
|
||||||
|
in: query
|
||||||
|
name: key
|
||||||
|
type: string
|
||||||
|
- example: "7725"
|
||||||
|
in: query
|
||||||
|
name: user_id
|
||||||
|
type: string
|
||||||
|
- description: ' '
|
||||||
|
in: body
|
||||||
|
name: post_body
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/handler.UptimeKumaWebHook.uptimeKumaWebhookBody'
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
"400":
|
||||||
|
description: Bad Request
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ginresp.apiError'
|
||||||
|
"401":
|
||||||
|
description: The user_id was not found or the user_key is wrong
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ginresp.apiError'
|
||||||
|
"403":
|
||||||
|
description: The user has exceeded its daily quota - wait 24 hours or upgrade
|
||||||
|
your account
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ginresp.apiError'
|
||||||
|
"500":
|
||||||
|
description: An internal server error occurred - try again later
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ginresp.apiError'
|
||||||
|
summary: Send a new message
|
||||||
|
tags:
|
||||||
|
- External
|
||||||
swagger: "2.0"
|
swagger: "2.0"
|
||||||
tags:
|
tags:
|
||||||
- name: External
|
- name: External
|
||||||
|
@ -1780,3 +1780,43 @@ func TestSendWithPermissionSendKey(t *testing.T) {
|
|||||||
func TestSendDeliveryRetry(t *testing.T) {
|
func TestSendDeliveryRetry(t *testing.T) {
|
||||||
t.SkipNow() //TODO
|
t.SkipNow() //TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUptimeKuma(t *testing.T) {
|
||||||
|
ws, baseUrl, stop := tt.StartSimpleWebserver(t)
|
||||||
|
defer stop()
|
||||||
|
|
||||||
|
pusher := ws.Pusher.(*push.TestSink)
|
||||||
|
|
||||||
|
r0 := tt.RequestPost[gin.H](t, baseUrl, "/api/v2/users", gin.H{
|
||||||
|
"agent_model": "DUMMY_PHONE",
|
||||||
|
"agent_version": "4X",
|
||||||
|
"client_type": "ANDROID",
|
||||||
|
"fcm_token": "DUMMY_FCM",
|
||||||
|
})
|
||||||
|
|
||||||
|
uid := r0["user_id"].(string)
|
||||||
|
admintok := r0["admin_key"].(string)
|
||||||
|
sendtok := r0["send_key"].(string)
|
||||||
|
|
||||||
|
suffix := fmt.Sprintf("/webhook/uptime-kuma?user_id=%v&key=%v", uid, sendtok)
|
||||||
|
_ = tt.RequestPost[gin.H](t, baseUrl, suffix, gin.H{
|
||||||
|
"msg": "Uptime Kuma failed with 503!",
|
||||||
|
"heartbeat": gin.H{
|
||||||
|
"status": 0,
|
||||||
|
},
|
||||||
|
"monitor": gin.H{
|
||||||
|
"name": "Test-Kuma",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
tt.AssertEqual(t, "messageCount", 1, len(pusher.Data))
|
||||||
|
tt.AssertStrRepEqual(t, "msg.title", "Test-Kuma down!", pusher.Last().Message.Title)
|
||||||
|
|
||||||
|
type mglist struct {
|
||||||
|
Messages []gin.H `json:"messages"`
|
||||||
|
}
|
||||||
|
|
||||||
|
msgList1 := tt.RequestAuthGet[mglist](t, admintok, baseUrl, "/api/v2/messages")
|
||||||
|
tt.AssertEqual(t, "len(messages)", 1, len(msgList1.Messages))
|
||||||
|
tt.AssertStrRepEqual(t, "msg.title", "Test-Kuma down!", msgList1.Messages[0]["title"])
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user