From ef0f0f6b43f648be8318457733731338a976d9d1 Mon Sep 17 00:00:00 2001 From: Fu Diwei Date: Fri, 16 May 2025 15:04:39 +0800 Subject: [PATCH] refactor: remove nikoksr/notify deps --- go.mod | 10 +-- go.sum | 12 +--- internal/domain/access.go | 2 +- internal/domain/provider.go | 4 +- internal/notify/providers.go | 8 +-- internal/notify/providers_deprecated.go | 10 +-- .../deployer/providers/webhook/webhook.go | 4 +- .../pkg/core/notifier/providers/bark/bark.go | 40 +++++++---- .../providers/dingtalkbot/dingtalkbot.go | 19 +++--- .../core/notifier/providers/gotify/gotify.go | 63 ++++++----------- .../notifier/providers/gotify/gotify_test.go | 6 +- .../notifier/providers/larkbot/larkbot.go | 17 +++-- .../providers/mattermost/mattermost.go | 67 ++++++++++-------- .../notifier/providers/pushover/pushover.go | 60 +++++----------- .../notifier/providers/pushplus/pushplus.go | 68 ++++++------------- .../providers/serverchan/serverchan.go | 45 ++++++------ .../providers/serverchan/serverchan_test.go | 2 +- .../telegrambot.go} | 38 +++++++---- .../telegrambot_test.go} | 12 ++-- .../notifier/providers/webhook/webhook.go | 10 ++- .../notifier/providers/wecombot/wecombot.go | 46 ++++++------- ui/src/components/access/AccessForm.tsx | 6 +- ...ig.tsx => AccessFormTelegramBotConfig.tsx} | 24 +++---- .../access/AccessFormWebhookConfig.tsx | 3 +- .../workflow/node/NotifyNodeConfigForm.tsx | 6 +- ...NotifyNodeConfigFormTelegramBotConfig.tsx} | 28 +++++--- ui/src/domain/access.ts | 4 +- ui/src/domain/provider.ts | 8 +-- ui/src/i18n/locales/en/nls.access.json | 6 +- ui/src/i18n/locales/en/nls.provider.json | 2 +- .../i18n/locales/en/nls.workflow.nodes.json | 6 +- ui/src/i18n/locales/zh/nls.access.json | 10 +-- ui/src/i18n/locales/zh/nls.provider.json | 2 +- .../i18n/locales/zh/nls.workflow.nodes.json | 6 +- 34 files changed, 303 insertions(+), 351 deletions(-) rename internal/pkg/core/notifier/providers/{telegram/telegram.go => telegrambot/telegrambot.go} (50%) rename internal/pkg/core/notifier/providers/{telegram/telegram_test.go => telegrambot/telegrambot_test.go} (79%) rename ui/src/components/access/{AccessFormTelegramConfig.tsx => AccessFormTelegramBotConfig.tsx} (69%) rename ui/src/components/workflow/node/{NotifyNodeConfigFormTelegramConfig.tsx => NotifyNodeConfigFormTelegramBotConfig.tsx} (60%) diff --git a/go.mod b/go.mod index 7adb56bf..a4ab4379 100644 --- a/go.mod +++ b/go.mod @@ -30,8 +30,10 @@ require ( github.com/aws/aws-sdk-go-v2/service/acm v1.32.0 github.com/aws/aws-sdk-go-v2/service/cloudfront v1.46.1 github.com/baidubce/bce-sdk-go v0.9.226 + github.com/blinkbean/dingtalk v1.1.3 github.com/byteplus-sdk/byteplus-sdk-golang v1.0.46 github.com/go-acme/lego/v4 v4.23.1 + github.com/go-lark/lark v1.16.0 github.com/go-resty/resty/v2 v2.16.5 github.com/go-viper/mapstructure/v2 v2.2.1 github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.148 @@ -39,7 +41,6 @@ require ( github.com/libdns/dynv6 v1.0.0 github.com/libdns/libdns v0.2.3 github.com/luthermonson/go-proxmox v0.2.2 - github.com/nikoksr/notify v1.3.0 github.com/pavlo-v-chernykh/keystore-go/v4 v4.5.0 github.com/pkg/sftp v1.13.9 github.com/pocketbase/dbx v1.11.0 @@ -84,13 +85,11 @@ require ( github.com/alibabacloud-go/tea-utils/v2 v2.0.7 // indirect github.com/avast/retry-go v3.0.0+incompatible // indirect github.com/aws/aws-sdk-go-v2/service/route53 v1.50.0 // indirect - github.com/blinkbean/dingtalk v1.1.3 // indirect github.com/buger/goterm v1.0.4 // indirect github.com/diskfs/go-diskfs v1.5.0 // indirect github.com/djherbis/times v1.6.0 // indirect github.com/emicklei/go-restful/v3 v3.12.1 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect - github.com/go-lark/lark v1.15.1 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonreference v0.21.0 // indirect @@ -99,7 +98,6 @@ require ( github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.16.0 // indirect github.com/go-sql-driver/mysql v1.8.1 // indirect - github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible // indirect github.com/gofrs/uuid v4.4.0+incompatible // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang-jwt/jwt/v5 v5.2.2 // indirect @@ -126,7 +124,6 @@ require ( github.com/qiniu/x v1.10.5 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af // indirect - github.com/technoweenie/multipartstreamer v1.0.1 // indirect github.com/x448/float16 v0.8.4 // indirect go.mongodb.org/mongo-driver v1.17.2 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect @@ -195,12 +192,9 @@ require ( github.com/nrdcg/namesilo v0.2.1 // indirect github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/spf13/cast v1.8.0 // indirect github.com/spf13/cobra v1.9.1 // indirect github.com/spf13/pflag v1.0.6 // indirect - github.com/stretchr/objx v0.5.2 // indirect - github.com/stretchr/testify v1.10.0 // indirect github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1128 // indirect github.com/tjfoc/gmsm v1.4.1 // indirect golang.org/x/image v0.27.0 // indirect diff --git a/go.sum b/go.sum index ae7a9d22..b9d4247d 100644 --- a/go.sum +++ b/go.sum @@ -360,8 +360,8 @@ github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2 github.com/go-kit/kit v0.12.0/go.mod h1:lHd+EkCZPIwYItmGDDRdhinkzX2A1sj+M9biaEaizzs= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= -github.com/go-lark/lark v1.15.1 h1:fo6PQKBJht/71N9Zn3/xjknOYx0TmdVuP+VP8NrUCsI= -github.com/go-lark/lark v1.15.1/go.mod h1:6ltbSztPZRT6IaO9ZIQyVaY5pVp/KeMizDYtfZkU+vM= +github.com/go-lark/lark v1.16.0 h1:U6BwkLM9wrZedSM7cIiMofganr8PCvJN+M75w2lf2Gg= +github.com/go-lark/lark v1.16.0/go.mod h1:6ltbSztPZRT6IaO9ZIQyVaY5pVp/KeMizDYtfZkU+vM= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= @@ -400,8 +400,6 @@ github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8Wd github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= -github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible h1:2cauKuaELYAEARXRkq2LrJ0yDDv1rW7+wrTEdVL3uaU= -github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible/go.mod h1:qf9acutJ8cwBUhm1bqgz6Bei9/C/c93FPDljKWwsOgM= github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= @@ -569,8 +567,6 @@ github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGw github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= -github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible h1:jdpOPRN1zP63Td1hDQbZW73xKmzDvZHzVdNYxhnTMDA= -github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible/go.mod h1:1c7szIrayyPPB/987hsnvNzLushdWf4o/79s3P08L8A= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= @@ -679,8 +675,6 @@ github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OS github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/nikoksr/notify v1.3.0 h1:UxzfxzAYGQD9a5JYLBTVx0lFMxeHCke3rPCkfWdPgLs= -github.com/nikoksr/notify v1.3.0/go.mod h1:Xor2hMmkvrCfkCKvXGbcrESez4brac2zQjhd6U2BbeM= github.com/nrdcg/bunny-go v0.0.0-20240207213615-dde5bf4577a3 h1:ouZ2JWDl8IW5k1qugYbmpbmW8hn85Ig6buSMBRlz3KI= github.com/nrdcg/bunny-go v0.0.0-20240207213615-dde5bf4577a3/go.mod h1:ZwadWt7mVhMHMbAQ1w8IhDqtWO3eWqWq72W7trnaiE8= github.com/nrdcg/desec v0.10.0 h1:qrEDiqnsvNU9QE7lXIXi/tIHAfyaFXKxF2/8/52O8uM= @@ -830,8 +824,6 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM= -github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdn v1.0.1155 h1:ildxJtjnqiKZxWDVKHT/ncIknGDijtg60MuFELON8bY= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdn v1.0.1155/go.mod h1:iLASpooTdyXtx642E5Ws7cfWENsp4/uZ/78TFoln7OI= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/clb v1.0.1161 h1:yGFg9/6j3NP10r9PfSWHfekuq4SwPyqblWnfISfKANo= diff --git a/internal/domain/access.go b/internal/domain/access.go index 35dd9b0a..e27d290a 100644 --- a/internal/domain/access.go +++ b/internal/domain/access.go @@ -260,7 +260,7 @@ type AccessConfigForSSLCom struct { EabHmacKey string `json:"eabHmacKey"` } -type AccessConfigForTelegram struct { +type AccessConfigForTelegramBot struct { BotToken string `json:"botToken"` DefaultChatId int64 `json:"defaultChatId,omitempty"` } diff --git a/internal/domain/provider.go b/internal/domain/provider.go index c635aad1..9226680d 100644 --- a/internal/domain/provider.go +++ b/internal/domain/provider.go @@ -67,7 +67,7 @@ const ( AccessProviderTypeSafeLine = AccessProviderType("safeline") AccessProviderTypeSSH = AccessProviderType("ssh") AccessProviderTypeSSLCOM = AccessProviderType("sslcom") - AccessProviderTypeTelegram = AccessProviderType("telegram") + AccessProviderTypeTelegramBot = AccessProviderType("telegrambot") AccessProviderTypeTencentCloud = AccessProviderType("tencentcloud") AccessProviderTypeUCloud = AccessProviderType("ucloud") AccessProviderTypeUpyun = AccessProviderType("upyun") @@ -259,7 +259,7 @@ const ( NotificationProviderTypeEmail = NotificationProviderType(AccessProviderTypeEmail) NotificationProviderTypeLarkBot = NotificationProviderType(AccessProviderTypeLarkBot) NotificationProviderTypeMattermost = NotificationProviderType(AccessProviderTypeMattermost) - NotificationProviderTypeTelegram = NotificationProviderType(AccessProviderTypeTelegram) + NotificationProviderTypeTelegramBot = NotificationProviderType(AccessProviderTypeTelegramBot) NotificationProviderTypeWebhook = NotificationProviderType(AccessProviderTypeWebhook) NotificationProviderTypeWeComBot = NotificationProviderType(AccessProviderTypeWeComBot) ) diff --git a/internal/notify/providers.go b/internal/notify/providers.go index 10e28f29..70787480 100644 --- a/internal/notify/providers.go +++ b/internal/notify/providers.go @@ -10,7 +10,7 @@ import ( pEmail "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/email" pLarkBot "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/larkbot" pMattermost "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/mattermost" - pTelegram "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/telegram" + pTelegramBot "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/telegrambot" pWebhook "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/webhook" pWeComBot "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/wecombot" httputil "github.com/usual2970/certimate/internal/pkg/utils/http" @@ -87,14 +87,14 @@ func createNotifierProvider(options *notifierProviderOptions) (notifier.Notifier }) } - case domain.NotificationProviderTypeTelegram: + case domain.NotificationProviderTypeTelegramBot: { - access := domain.AccessConfigForTelegram{} + access := domain.AccessConfigForTelegramBot{} if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } - return pTelegram.NewNotifier(&pTelegram.NotifierConfig{ + return pTelegramBot.NewNotifier(&pTelegramBot.NotifierConfig{ BotToken: access.BotToken, ChatId: maputil.GetOrDefaultInt64(options.ProviderExtendedConfig, "chatId", access.DefaultChatId), }) diff --git a/internal/notify/providers_deprecated.go b/internal/notify/providers_deprecated.go index 759d097d..d2d926a6 100644 --- a/internal/notify/providers_deprecated.go +++ b/internal/notify/providers_deprecated.go @@ -14,7 +14,7 @@ import ( pPushover "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/pushover" pPushPlus "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/pushplus" pServerChan "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/serverchan" - pTelegram "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/telegram" + pTelegram "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/telegrambot" pWebhook "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/webhook" pWeCom "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/wecombot" maputil "github.com/usual2970/certimate/internal/pkg/utils/map" @@ -52,9 +52,9 @@ func createNotifierProviderUseGlobalSettings(channel domain.NotifyChannelType, c case domain.NotifyChannelTypeGotify: return pGotify.NewNotifier(&pGotify.NotifierConfig{ - Url: maputil.GetString(channelConfig, "url"), - Token: maputil.GetString(channelConfig, "token"), - Priority: maputil.GetOrDefaultInt64(channelConfig, "priority", 1), + ServerUrl: maputil.GetString(channelConfig, "url"), + Token: maputil.GetString(channelConfig, "token"), + Priority: maputil.GetOrDefaultInt64(channelConfig, "priority", 1), }) case domain.NotifyChannelTypeLark: @@ -83,7 +83,7 @@ func createNotifierProviderUseGlobalSettings(channel domain.NotifyChannelType, c case domain.NotifyChannelTypeServerChan: return pServerChan.NewNotifier(&pServerChan.NotifierConfig{ - Url: maputil.GetString(channelConfig, "url"), + ServerUrl: maputil.GetString(channelConfig, "url"), }) case domain.NotifyChannelTypeTelegram: diff --git a/internal/pkg/core/deployer/providers/webhook/webhook.go b/internal/pkg/core/deployer/providers/webhook/webhook.go index 418b2c1a..3a21717b 100644 --- a/internal/pkg/core/deployer/providers/webhook/webhook.go +++ b/internal/pkg/core/deployer/providers/webhook/webhook.go @@ -159,9 +159,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPE // 生成请求 // 其中 GET 请求需转换为查询参数 - req := d.httpClient.R(). - SetContext(ctx). - SetHeaderMultiValues(webhookHeaders) + req := d.httpClient.R().SetHeaderMultiValues(webhookHeaders) req.URL = webhookUrl.String() req.Method = webhookMethod if webhookMethod == http.MethodGet { diff --git a/internal/pkg/core/notifier/providers/bark/bark.go b/internal/pkg/core/notifier/providers/bark/bark.go index ccdd5736..4d1902f2 100644 --- a/internal/pkg/core/notifier/providers/bark/bark.go +++ b/internal/pkg/core/notifier/providers/bark/bark.go @@ -2,10 +2,11 @@ package bark import ( "context" + "fmt" "log/slog" + "net/http" - "github.com/nikoksr/notify" - "github.com/nikoksr/notify/service/bark" + "github.com/go-resty/resty/v2" "github.com/usual2970/certimate/internal/pkg/core/notifier" ) @@ -19,8 +20,9 @@ type NotifierConfig struct { } type NotifierProvider struct { - config *NotifierConfig - logger *slog.Logger + config *NotifierConfig + logger *slog.Logger + httpClient *resty.Client } var _ notifier.Notifier = (*NotifierProvider)(nil) @@ -30,9 +32,12 @@ func NewNotifier(config *NotifierConfig) (*NotifierProvider, error) { panic("config is nil") } + client := resty.New() + return &NotifierProvider{ - config: config, - logger: slog.Default(), + config: config, + logger: slog.Default(), + httpClient: client, }, nil } @@ -46,16 +51,25 @@ func (n *NotifierProvider) WithLogger(logger *slog.Logger) notifier.Notifier { } func (n *NotifierProvider) Notify(ctx context.Context, subject string, message string) (res *notifier.NotifyResult, err error) { - var srv notify.Notifier - if n.config.ServerUrl == "" { - srv = bark.New(n.config.DeviceKey) - } else { - srv = bark.NewWithServers(n.config.DeviceKey, n.config.ServerUrl) + const defaultServerURL = "https://api.day.app/" + serverUrl := defaultServerURL + if n.config.ServerUrl != "" { + serverUrl = n.config.ServerUrl } - err = srv.Send(ctx, subject, message) + // REF: https://bark.day.app/#/tutorial + req := n.httpClient.R(). + SetHeader("Content-Type", "application/json"). + SetBody(map[string]any{ + "title": subject, + "body": message, + "device_key": n.config.DeviceKey, + }) + resp, err := req.Execute(http.MethodPost, serverUrl) if err != nil { - return nil, err + return nil, fmt.Errorf("bark api error: failed to send request: %w", err) + } else if resp.IsError() { + return nil, fmt.Errorf("bark api error: unexpected status code: %d, resp: %s", resp.StatusCode(), resp.String()) } return ¬ifier.NotifyResult{}, nil diff --git a/internal/pkg/core/notifier/providers/dingtalkbot/dingtalkbot.go b/internal/pkg/core/notifier/providers/dingtalkbot/dingtalkbot.go index ea3c51f3..d6d8b096 100644 --- a/internal/pkg/core/notifier/providers/dingtalkbot/dingtalkbot.go +++ b/internal/pkg/core/notifier/providers/dingtalkbot/dingtalkbot.go @@ -6,7 +6,7 @@ import ( "log/slog" "net/url" - "github.com/nikoksr/notify/service/dingding" + "github.com/blinkbean/dingtalk" "github.com/usual2970/certimate/internal/pkg/core/notifier" ) @@ -48,17 +48,18 @@ func (n *NotifierProvider) WithLogger(logger *slog.Logger) notifier.Notifier { func (n *NotifierProvider) Notify(ctx context.Context, subject string, message string) (res *notifier.NotifyResult, err error) { webhookUrl, err := url.Parse(n.config.WebhookUrl) if err != nil { - return nil, fmt.Errorf("invalid webhook url: %w", err) + return nil, fmt.Errorf("dingtalk api error: invalid webhook url: %w", err) } - srv := dingding.New(&dingding.Config{ - Token: webhookUrl.Query().Get("access_token"), - Secret: n.config.Secret, - }) + var bot *dingtalk.DingTalk + if n.config.Secret == "" { + bot = dingtalk.InitDingTalk([]string{webhookUrl.Query().Get("access_token")}, "") + } else { + bot = dingtalk.InitDingTalkWithSecret(webhookUrl.Query().Get("access_token"), n.config.Secret) + } - err = srv.Send(ctx, subject, message) - if err != nil { - return nil, err + if err := bot.SendTextMessage(subject + "\n" + message); err != nil { + return nil, fmt.Errorf("dingtalk api error: %w", err) } return ¬ifier.NotifyResult{}, nil diff --git a/internal/pkg/core/notifier/providers/gotify/gotify.go b/internal/pkg/core/notifier/providers/gotify/gotify.go index aed6e7c8..05b2f919 100644 --- a/internal/pkg/core/notifier/providers/gotify/gotify.go +++ b/internal/pkg/core/notifier/providers/gotify/gotify.go @@ -1,20 +1,20 @@ package gotify import ( - "bytes" "context" - "encoding/json" "fmt" - "io" "log/slog" "net/http" + "strings" + + "github.com/go-resty/resty/v2" "github.com/usual2970/certimate/internal/pkg/core/notifier" ) type NotifierConfig struct { // Gotify 服务地址。 - Url string `json:"url"` + ServerUrl string `json:"serverUrl"` // Gotify Token。 Token string `json:"token"` // Gotify 消息优先级。 @@ -24,7 +24,7 @@ type NotifierConfig struct { type NotifierProvider struct { config *NotifierConfig logger *slog.Logger - httpClient *http.Client + httpClient *resty.Client } var _ notifier.Notifier = (*NotifierProvider)(nil) @@ -34,10 +34,12 @@ func NewNotifier(config *NotifierConfig) (*NotifierProvider, error) { panic("config is nil") } + client := resty.New() + return &NotifierProvider{ config: config, logger: slog.Default(), - httpClient: http.DefaultClient, + httpClient: client, }, nil } @@ -51,45 +53,22 @@ func (n *NotifierProvider) WithLogger(logger *slog.Logger) notifier.Notifier { } func (n *NotifierProvider) Notify(ctx context.Context, subject string, message string) (res *notifier.NotifyResult, err error) { - reqBody := &struct { - Title string `json:"title"` - Message string `json:"message"` - Priority int64 `json:"priority"` - }{ - Title: subject, - Message: message, - Priority: n.config.Priority, - } + serverUrl := strings.TrimRight(n.config.ServerUrl, "/") - body, err := json.Marshal(reqBody) - if err != nil { - return nil, fmt.Errorf("gotify api error: failed to encode message body: %w", err) - } - - req, err := http.NewRequestWithContext( - ctx, - http.MethodPost, - fmt.Sprintf("%s/message", n.config.Url), - bytes.NewReader(body), - ) - if err != nil { - return nil, fmt.Errorf("gotify api error: failed to create new request: %w", err) - } - - req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", n.config.Token)) - req.Header.Set("Content-Type", "application/json; charset=utf-8") - - resp, err := n.httpClient.Do(req) + // REF: https://gotify.net/api-docs#/message/createMessage + req := n.httpClient.R(). + SetHeader("Content-Type", "application/json"). + SetHeader("Authorization", "Bearer "+n.config.Token). + SetBody(map[string]any{ + "title": subject, + "message": message, + "priority": n.config.Priority, + }) + resp, err := req.Execute(http.MethodPost, fmt.Sprintf("%s/message", serverUrl)) if err != nil { return nil, fmt.Errorf("gotify api error: failed to send request: %w", err) - } - defer resp.Body.Close() - - result, err := io.ReadAll(resp.Body) - if err != nil { - return nil, fmt.Errorf("gotify api error: failed to read response: %w", err) - } else if resp.StatusCode != http.StatusOK { - return nil, fmt.Errorf("gotify api error: unexpected status code: %d, resp: %s", resp.StatusCode, string(result)) + } else if resp.IsError() { + return nil, fmt.Errorf("gotify api error: unexpected status code: %d, resp: %s", resp.StatusCode(), resp.String()) } return ¬ifier.NotifyResult{}, nil diff --git a/internal/pkg/core/notifier/providers/gotify/gotify_test.go b/internal/pkg/core/notifier/providers/gotify/gotify_test.go index 31ad64af..eb0ffd6b 100644 --- a/internal/pkg/core/notifier/providers/gotify/gotify_test.go +++ b/internal/pkg/core/notifier/providers/gotify/gotify_test.go @@ -48,9 +48,9 @@ func TestNotify(t *testing.T) { }, "\n")) notifier, err := provider.NewNotifier(&provider.NotifierConfig{ - Url: fUrl, - Token: fToken, - Priority: fPriority, + ServerUrl: fUrl, + Token: fToken, + Priority: fPriority, }) if err != nil { t.Errorf("err: %+v", err) diff --git a/internal/pkg/core/notifier/providers/larkbot/larkbot.go b/internal/pkg/core/notifier/providers/larkbot/larkbot.go index cf6d65ce..7d3e8a55 100644 --- a/internal/pkg/core/notifier/providers/larkbot/larkbot.go +++ b/internal/pkg/core/notifier/providers/larkbot/larkbot.go @@ -2,9 +2,10 @@ package larkbot import ( "context" + "fmt" "log/slog" - "github.com/nikoksr/notify/service/lark" + "github.com/go-lark/lark" "github.com/usual2970/certimate/internal/pkg/core/notifier" ) @@ -42,11 +43,17 @@ func (n *NotifierProvider) WithLogger(logger *slog.Logger) notifier.Notifier { } func (n *NotifierProvider) Notify(ctx context.Context, subject string, message string) (res *notifier.NotifyResult, err error) { - srv := lark.NewWebhookService(n.config.WebhookUrl) - - err = srv.Send(ctx, subject, message) + bot := lark.NewNotificationBot(n.config.WebhookUrl) + content := lark.NewPostBuilder(). + Title(subject). + TextTag(message, 1, false). + Render() + msg := lark.NewMsgBuffer(lark.MsgPost).Post(content) + resp, err := bot.PostNotificationV2(msg.Build()) if err != nil { - return nil, err + return nil, fmt.Errorf("lark api error: %w", err) + } else if resp.Code != 0 { + return nil, fmt.Errorf("lark api error: code='%d', message='%s'", resp.Code, resp.Msg) } return ¬ifier.NotifyResult{}, nil diff --git a/internal/pkg/core/notifier/providers/mattermost/mattermost.go b/internal/pkg/core/notifier/providers/mattermost/mattermost.go index ed3a507a..4f1c3e9c 100644 --- a/internal/pkg/core/notifier/providers/mattermost/mattermost.go +++ b/internal/pkg/core/notifier/providers/mattermost/mattermost.go @@ -1,15 +1,14 @@ package mattermost import ( - "bytes" "context" - "encoding/json" - "io" + "fmt" "log/slog" "net/http" "strings" - "github.com/nikoksr/notify/service/mattermost" + "github.com/go-resty/resty/v2" + "github.com/usual2970/certimate/internal/pkg/core/notifier" ) @@ -25,8 +24,9 @@ type NotifierConfig struct { } type NotifierProvider struct { - config *NotifierConfig - logger *slog.Logger + config *NotifierConfig + logger *slog.Logger + httpClient *resty.Client } var _ notifier.Notifier = (*NotifierProvider)(nil) @@ -36,9 +36,12 @@ func NewNotifier(config *NotifierConfig) (*NotifierProvider, error) { panic("config is nil") } + client := resty.New() + return &NotifierProvider{ - config: config, - logger: slog.Default(), + config: config, + logger: slog.Default(), + httpClient: client, }, nil } @@ -52,17 +55,29 @@ func (n *NotifierProvider) WithLogger(logger *slog.Logger) notifier.Notifier { } func (n *NotifierProvider) Notify(ctx context.Context, subject string, message string) (res *notifier.NotifyResult, err error) { - srv := mattermost.New(strings.TrimRight(n.config.ServerUrl, "/")) + serverUrl := strings.TrimRight(n.config.ServerUrl, "/") - if err := srv.LoginWithCredentials(ctx, n.config.Username, n.config.Password); err != nil { - return nil, err + // REF: https://developers.mattermost.com/api-documentation/#/operations/Login + loginReq := n.httpClient.R(). + SetHeader("Content-Type", "application/json"). + SetBody(map[string]any{ + "login_id": n.config.Username, + "password": n.config.Password, + }) + loginResp, err := loginReq.Execute(http.MethodPost, fmt.Sprintf("%s/api/v4/users/login", serverUrl)) + if err != nil { + return nil, fmt.Errorf("mattermost api error: failed to send request: %w", err) + } else if loginResp.IsError() { + return nil, fmt.Errorf("mattermost api error: unexpected status code: %d, resp: %s", loginResp.StatusCode(), loginResp.String()) + } else if loginResp.Header().Get("Token") == "" { + return nil, fmt.Errorf("mattermost api error: received empty login token") } - srv.AddReceivers(n.config.ChannelId) - - // 复写消息样式 - srv.PreSend(func(req *http.Request) error { - m := map[string]interface{}{ + // REF: https://developers.mattermost.com/api-documentation/#/operations/CreatePost + postReq := n.httpClient.R(). + SetHeader("Content-Type", "application/json"). + SetHeader("Authorization", "Bearer "+loginResp.Header().Get("Token")). + SetBody(map[string]any{ "channel_id": n.config.ChannelId, "props": map[string]interface{}{ "attachments": []map[string]interface{}{ @@ -72,20 +87,12 @@ func (n *NotifierProvider) Notify(ctx context.Context, subject string, message s }, }, }, - } - - if body, err := json.Marshal(m); err != nil { - return err - } else { - req.ContentLength = int64(len(body)) - req.Body = io.NopCloser(bytes.NewReader(body)) - } - - return nil - }) - - if err = srv.Send(ctx, subject, message); err != nil { - return nil, err + }) + postResp, err := postReq.Execute(http.MethodPost, fmt.Sprintf("%s/api/v4/posts", serverUrl)) + if err != nil { + return nil, fmt.Errorf("mattermost api error: failed to send request: %w", err) + } else if postResp.IsError() { + return nil, fmt.Errorf("mattermost api error: unexpected status code: %d, resp: %s", postResp.StatusCode(), postResp.String()) } return ¬ifier.NotifyResult{}, nil diff --git a/internal/pkg/core/notifier/providers/pushover/pushover.go b/internal/pkg/core/notifier/providers/pushover/pushover.go index f306df1f..459a4950 100644 --- a/internal/pkg/core/notifier/providers/pushover/pushover.go +++ b/internal/pkg/core/notifier/providers/pushover/pushover.go @@ -1,14 +1,13 @@ package pushover import ( - "bytes" "context" - "encoding/json" "fmt" - "io" "log/slog" "net/http" + "github.com/go-resty/resty/v2" + "github.com/usual2970/certimate/internal/pkg/core/notifier" ) @@ -22,7 +21,7 @@ type NotifierConfig struct { type NotifierProvider struct { config *NotifierConfig logger *slog.Logger - httpClient *http.Client + httpClient *resty.Client } var _ notifier.Notifier = (*NotifierProvider)(nil) @@ -32,10 +31,12 @@ func NewNotifier(config *NotifierConfig) (*NotifierProvider, error) { panic("config is nil") } + client := resty.New() + return &NotifierProvider{ config: config, logger: slog.Default(), - httpClient: http.DefaultClient, + httpClient: client, }, nil } @@ -50,46 +51,19 @@ func (n *NotifierProvider) WithLogger(logger *slog.Logger) notifier.Notifier { func (n *NotifierProvider) Notify(ctx context.Context, subject string, message string) (res *notifier.NotifyResult, err error) { // REF: https://pushover.net/api - reqBody := &struct { - Token string `json:"token"` - User string `json:"user"` - Title string `json:"title"` - Message string `json:"message"` - }{ - Token: n.config.Token, - User: n.config.User, - Title: subject, - Message: message, - } - - body, err := json.Marshal(reqBody) - if err != nil { - return nil, fmt.Errorf("pushover api error: failed to encode message body: %w", err) - } - - req, err := http.NewRequestWithContext( - ctx, - http.MethodPost, - "https://api.pushover.net/1/messages.json", - bytes.NewReader(body), - ) - if err != nil { - return nil, fmt.Errorf("pushover api error: failed to create new request: %w", err) - } - - req.Header.Set("Content-Type", "application/json; charset=utf-8") - - resp, err := n.httpClient.Do(req) + req := n.httpClient.R(). + SetHeader("Content-Type", "application/json"). + SetBody(map[string]any{ + "title": subject, + "message": message, + "token": n.config.Token, + "user": n.config.User, + }) + resp, err := req.Execute(http.MethodPost, "https://api.pushover.net/1/messages.json") if err != nil { return nil, fmt.Errorf("pushover api error: failed to send request: %w", err) - } - defer resp.Body.Close() - - result, err := io.ReadAll(resp.Body) - if err != nil { - return nil, fmt.Errorf("pushover api error: failed to read response: %w", err) - } else if resp.StatusCode != http.StatusOK { - return nil, fmt.Errorf("pushover api error: unexpected status code: %d, resp: %s", resp.StatusCode, string(result)) + } else if resp.IsError() { + return nil, fmt.Errorf("pushover api error: unexpected status code: %d, resp: %s", resp.StatusCode(), resp.String()) } return ¬ifier.NotifyResult{}, nil diff --git a/internal/pkg/core/notifier/providers/pushplus/pushplus.go b/internal/pkg/core/notifier/providers/pushplus/pushplus.go index a0ef4c7f..a8a95ac7 100644 --- a/internal/pkg/core/notifier/providers/pushplus/pushplus.go +++ b/internal/pkg/core/notifier/providers/pushplus/pushplus.go @@ -1,14 +1,14 @@ package pushplus import ( - "bytes" "context" "encoding/json" "fmt" - "io" "log/slog" "net/http" + "github.com/go-resty/resty/v2" + "github.com/usual2970/certimate/internal/pkg/core/notifier" ) @@ -20,7 +20,7 @@ type NotifierConfig struct { type NotifierProvider struct { config *NotifierConfig logger *slog.Logger - httpClient *http.Client + httpClient *resty.Client } var _ notifier.Notifier = (*NotifierProvider)(nil) @@ -30,10 +30,12 @@ func NewNotifier(config *NotifierConfig) (*NotifierProvider, error) { panic("config is nil") } + client := resty.New() + return &NotifierProvider{ config: config, logger: slog.Default(), - httpClient: http.DefaultClient, + httpClient: client, }, nil } @@ -47,55 +49,29 @@ func (n *NotifierProvider) WithLogger(logger *slog.Logger) notifier.Notifier { } func (n *NotifierProvider) Notify(ctx context.Context, subject string, message string) (res *notifier.NotifyResult, err error) { - // REF: https://pushplus.plus/doc/guide/api.html - reqBody := &struct { - Token string `json:"token"` - Title string `json:"title"` - Content string `json:"content"` - }{ - Token: n.config.Token, - Title: subject, - Content: message, - } - - body, err := json.Marshal(reqBody) - if err != nil { - return nil, fmt.Errorf("pushplus api error: failed to encode message body: %w", err) - } - - req, err := http.NewRequestWithContext( - ctx, - http.MethodPost, - "https://www.pushplus.plus/send", - bytes.NewReader(body), - ) - if err != nil { - return nil, fmt.Errorf("pushplus api error: failed to create new request: %w", err) - } - - req.Header.Set("Content-Type", "application/json; charset=utf-8") - - resp, err := n.httpClient.Do(req) + // REF: https://pushplus.plus/doc/guide/api.html#%E4%B8%80%E3%80%81%E5%8F%91%E9%80%81%E6%B6%88%E6%81%AF%E6%8E%A5%E5%8F%A3 + req := n.httpClient.R(). + SetHeader("Content-Type", "application/json"). + SetBody(map[string]any{ + "title": subject, + "content": message, + "token": n.config.Token, + }) + resp, err := req.Execute(http.MethodPost, "https://www.pushplus.plus/send") if err != nil { return nil, fmt.Errorf("pushplus api error: failed to send request: %w", err) - } - defer resp.Body.Close() - - result, err := io.ReadAll(resp.Body) - if err != nil { - return nil, fmt.Errorf("pushplus api error: failed to read response: %w", err) - } else if resp.StatusCode != http.StatusOK { - return nil, fmt.Errorf("pushplus api error: unexpected status code: %d, resp: %s", resp.StatusCode, string(result)) + } else if resp.IsError() { + return nil, fmt.Errorf("pushplus api error: unexpected status code: %d, resp: %s", resp.StatusCode(), resp.String()) } var errorResponse struct { - Code int `json:"code"` - Msg string `json:"msg"` + Code int `json:"code"` + Message string `json:"msg"` } - if err := json.Unmarshal(result, &errorResponse); err != nil { - return nil, fmt.Errorf("pushplus api error: failed to decode response: %w", err) + if err := json.Unmarshal(resp.Body(), &errorResponse); err != nil { + return nil, fmt.Errorf("pushplus api error: failed to unmarshal response: %w", err) } else if errorResponse.Code != 200 { - return nil, fmt.Errorf("pushplus api error: unexpected response code: %d, msg: %s", errorResponse.Code, errorResponse.Msg) + return nil, fmt.Errorf("pushplus api error: code='%d', message='%s'", errorResponse.Code, errorResponse.Message) } return ¬ifier.NotifyResult{}, nil diff --git a/internal/pkg/core/notifier/providers/serverchan/serverchan.go b/internal/pkg/core/notifier/providers/serverchan/serverchan.go index 89724b08..cd77ce83 100644 --- a/internal/pkg/core/notifier/providers/serverchan/serverchan.go +++ b/internal/pkg/core/notifier/providers/serverchan/serverchan.go @@ -2,22 +2,24 @@ package serverchan import ( "context" + "fmt" "log/slog" "net/http" - notifyHttp "github.com/nikoksr/notify/service/http" + "github.com/go-resty/resty/v2" "github.com/usual2970/certimate/internal/pkg/core/notifier" ) type NotifierConfig struct { // ServerChan 服务地址。 - Url string `json:"url"` + ServerUrl string `json:"serverUrl"` } type NotifierProvider struct { - config *NotifierConfig - logger *slog.Logger + config *NotifierConfig + logger *slog.Logger + httpClient *resty.Client } var _ notifier.Notifier = (*NotifierProvider)(nil) @@ -27,9 +29,12 @@ func NewNotifier(config *NotifierConfig) (*NotifierProvider, error) { panic("config is nil") } + client := resty.New() + return &NotifierProvider{ - config: config, - logger: slog.Default(), + config: config, + logger: slog.Default(), + httpClient: client, }, nil } @@ -43,24 +48,18 @@ func (n *NotifierProvider) WithLogger(logger *slog.Logger) notifier.Notifier { } func (n *NotifierProvider) Notify(ctx context.Context, subject string, message string) (res *notifier.NotifyResult, err error) { - srv := notifyHttp.New() - - srv.AddReceivers(¬ifyHttp.Webhook{ - URL: n.config.Url, - Header: http.Header{}, - ContentType: "application/json", - Method: http.MethodPost, - BuildPayload: func(subject, message string) (payload any) { - return map[string]string{ - "text": subject, - "desp": message, - } - }, - }) - - err = srv.Send(ctx, subject, message) + // REF: https://sct.ftqq.com/ + req := n.httpClient.R(). + SetHeader("Content-Type", "application/json"). + SetBody(map[string]any{ + "text": subject, + "desp": message, + }) + resp, err := req.Execute(http.MethodPost, n.config.ServerUrl) if err != nil { - return nil, err + return nil, fmt.Errorf("serverchan api error: failed to send request: %w", err) + } else if resp.IsError() { + return nil, fmt.Errorf("serverchan api error: unexpected status code: %d, resp: %s", resp.StatusCode(), resp.String()) } return ¬ifier.NotifyResult{}, nil diff --git a/internal/pkg/core/notifier/providers/serverchan/serverchan_test.go b/internal/pkg/core/notifier/providers/serverchan/serverchan_test.go index 991b4050..5684a593 100644 --- a/internal/pkg/core/notifier/providers/serverchan/serverchan_test.go +++ b/internal/pkg/core/notifier/providers/serverchan/serverchan_test.go @@ -39,7 +39,7 @@ func TestNotify(t *testing.T) { }, "\n")) notifier, err := provider.NewNotifier(&provider.NotifierConfig{ - Url: fUrl, + ServerUrl: fUrl, }) if err != nil { t.Errorf("err: %+v", err) diff --git a/internal/pkg/core/notifier/providers/telegram/telegram.go b/internal/pkg/core/notifier/providers/telegrambot/telegrambot.go similarity index 50% rename from internal/pkg/core/notifier/providers/telegram/telegram.go rename to internal/pkg/core/notifier/providers/telegrambot/telegrambot.go index 218f7ee3..a324ee00 100644 --- a/internal/pkg/core/notifier/providers/telegram/telegram.go +++ b/internal/pkg/core/notifier/providers/telegrambot/telegrambot.go @@ -1,10 +1,12 @@ -package telegram +package telegrambot import ( "context" + "fmt" "log/slog" + "net/http" - "github.com/nikoksr/notify/service/telegram" + "github.com/go-resty/resty/v2" "github.com/usual2970/certimate/internal/pkg/core/notifier" ) @@ -17,8 +19,9 @@ type NotifierConfig struct { } type NotifierProvider struct { - config *NotifierConfig - logger *slog.Logger + config *NotifierConfig + logger *slog.Logger + httpClient *resty.Client } var _ notifier.Notifier = (*NotifierProvider)(nil) @@ -28,9 +31,12 @@ func NewNotifier(config *NotifierConfig) (*NotifierProvider, error) { panic("config is nil") } + client := resty.New() + return &NotifierProvider{ - config: config, - logger: slog.Default(), + config: config, + logger: slog.Default(), + httpClient: client, }, nil } @@ -44,16 +50,18 @@ func (n *NotifierProvider) WithLogger(logger *slog.Logger) notifier.Notifier { } func (n *NotifierProvider) Notify(ctx context.Context, subject string, message string) (res *notifier.NotifyResult, err error) { - srv, err := telegram.New(n.config.BotToken) + // REF: https://core.telegram.org/bots/api#sendmessage + req := n.httpClient.R(). + SetHeader("Content-Type", "application/json"). + SetBody(map[string]any{ + "chat_id": n.config.ChatId, + "text": subject + "\n" + message, + }) + resp, err := req.Execute(http.MethodPost, fmt.Sprintf("https://api.telegram.org/bot%s/sendMessage", n.config.BotToken)) if err != nil { - return nil, err - } - - srv.AddReceivers(n.config.ChatId) - - err = srv.Send(ctx, subject, message) - if err != nil { - return nil, err + return nil, fmt.Errorf("telegram api error: failed to send request: %w", err) + } else if resp.IsError() { + return nil, fmt.Errorf("telegram api error: unexpected status code: %d, resp: %s", resp.StatusCode(), resp.String()) } return ¬ifier.NotifyResult{}, nil diff --git a/internal/pkg/core/notifier/providers/telegram/telegram_test.go b/internal/pkg/core/notifier/providers/telegrambot/telegrambot_test.go similarity index 79% rename from internal/pkg/core/notifier/providers/telegram/telegram_test.go rename to internal/pkg/core/notifier/providers/telegrambot/telegrambot_test.go index e9a7d10b..3a207384 100644 --- a/internal/pkg/core/notifier/providers/telegram/telegram_test.go +++ b/internal/pkg/core/notifier/providers/telegrambot/telegrambot_test.go @@ -1,4 +1,4 @@ -package telegram_test +package telegrambot_test import ( "context" @@ -7,7 +7,7 @@ import ( "strings" "testing" - provider "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/telegram" + provider "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/telegrambot" ) const ( @@ -21,7 +21,7 @@ var ( ) func init() { - argsPrefix := "CERTIMATE_NOTIFIER_TELEGRAM_" + argsPrefix := "CERTIMATE_NOTIFIER_TELEGRAMBOT_" flag.StringVar(&fApiToken, argsPrefix+"APITOKEN", "", "") flag.Int64Var(&fChartId, argsPrefix+"CHATID", 0, "") @@ -30,9 +30,9 @@ func init() { /* Shell command to run this test: - go test -v ./telegram_test.go -args \ - --CERTIMATE_NOTIFIER_TELEGRAM_APITOKEN="your-api-token" \ - --CERTIMATE_NOTIFIER_TELEGRAM_CHATID=123456 + go test -v ./telegrambot_test.go -args \ + --CERTIMATE_NOTIFIER_TELEGRAMBOT_APITOKEN="your-api-token" \ + --CERTIMATE_NOTIFIER_TELEGRAMBOT_CHATID=123456 */ func TestNotify(t *testing.T) { flag.Parse() diff --git a/internal/pkg/core/notifier/providers/webhook/webhook.go b/internal/pkg/core/notifier/providers/webhook/webhook.go index 0e7caaa5..5f62f170 100644 --- a/internal/pkg/core/notifier/providers/webhook/webhook.go +++ b/internal/pkg/core/notifier/providers/webhook/webhook.go @@ -139,9 +139,7 @@ func (n *NotifierProvider) Notify(ctx context.Context, subject string, message s // 生成请求 // 其中 GET 请求需转换为查询参数 - req := n.httpClient.R(). - SetContext(ctx). - SetHeaderMultiValues(webhookHeaders) + req := n.httpClient.R().SetHeaderMultiValues(webhookHeaders) req.URL = webhookUrl.String() req.Method = webhookMethod if webhookMethod == http.MethodGet { @@ -160,12 +158,12 @@ func (n *NotifierProvider) Notify(ctx context.Context, subject string, message s // 发送请求 resp, err := req.Send() if err != nil { - return nil, fmt.Errorf("failed to send webhook request: %w", err) + return nil, fmt.Errorf("webhook error: failed to send request: %w", err) } else if resp.IsError() { - return nil, fmt.Errorf("unexpected webhook response status code: %d", resp.StatusCode()) + return nil, fmt.Errorf("webhook error: unexpected status code: %d, resp: %s", resp.StatusCode(), resp.String()) } - n.logger.Debug("webhook responded", slog.Any("response", resp.String())) + n.logger.Debug("webhook responded", slog.String("response", resp.String())) return ¬ifier.NotifyResult{}, nil } diff --git a/internal/pkg/core/notifier/providers/wecombot/wecombot.go b/internal/pkg/core/notifier/providers/wecombot/wecombot.go index 5db0fff4..daa771e0 100644 --- a/internal/pkg/core/notifier/providers/wecombot/wecombot.go +++ b/internal/pkg/core/notifier/providers/wecombot/wecombot.go @@ -2,10 +2,11 @@ package wecombot import ( "context" + "fmt" "log/slog" "net/http" - notifyHttp "github.com/nikoksr/notify/service/http" + "github.com/go-resty/resty/v2" "github.com/usual2970/certimate/internal/pkg/core/notifier" ) @@ -16,8 +17,9 @@ type NotifierConfig struct { } type NotifierProvider struct { - config *NotifierConfig - logger *slog.Logger + config *NotifierConfig + logger *slog.Logger + httpClient *resty.Client } var _ notifier.Notifier = (*NotifierProvider)(nil) @@ -27,8 +29,12 @@ func NewNotifier(config *NotifierConfig) (*NotifierProvider, error) { panic("config is nil") } + client := resty.New() + return &NotifierProvider{ - config: config, + config: config, + logger: slog.Default(), + httpClient: client, }, nil } @@ -42,26 +48,20 @@ func (n *NotifierProvider) WithLogger(logger *slog.Logger) notifier.Notifier { } func (n *NotifierProvider) Notify(ctx context.Context, subject string, message string) (res *notifier.NotifyResult, err error) { - srv := notifyHttp.New() - - srv.AddReceivers(¬ifyHttp.Webhook{ - URL: n.config.WebhookUrl, - Header: http.Header{}, - ContentType: "application/json", - Method: http.MethodPost, - BuildPayload: func(subject, message string) (payload any) { - return map[string]any{ - "msgtype": "text", - "text": map[string]string{ - "content": subject + "\n\n" + message, - }, - } - }, - }) - - err = srv.Send(ctx, subject, message) + // REF: https://developer.work.weixin.qq.com/document/path/91770 + req := n.httpClient.R(). + SetHeader("Content-Type", "application/json"). + SetBody(map[string]any{ + "msgtype": "text", + "text": map[string]string{ + "content": subject + "\n\n" + message, + }, + }) + resp, err := req.Execute(http.MethodPost, n.config.WebhookUrl) if err != nil { - return nil, err + return nil, fmt.Errorf("wecom api error: failed to send request: %w", err) + } else if resp.IsError() { + return nil, fmt.Errorf("wecom api error: unexpected status code: %d, resp: %s", resp.StatusCode(), resp.String()) } return ¬ifier.NotifyResult{}, nil diff --git a/ui/src/components/access/AccessForm.tsx b/ui/src/components/access/AccessForm.tsx index 0dd2828a..1b618cbc 100644 --- a/ui/src/components/access/AccessForm.tsx +++ b/ui/src/components/access/AccessForm.tsx @@ -57,7 +57,7 @@ import AccessFormRainYunConfig from "./AccessFormRainYunConfig"; import AccessFormSafeLineConfig from "./AccessFormSafeLineConfig"; import AccessFormSSHConfig from "./AccessFormSSHConfig"; import AccessFormSSLComConfig from "./AccessFormSSLComConfig"; -import AccessFormTelegramConfig from "./AccessFormTelegramConfig"; +import AccessFormTelegramBotConfig from "./AccessFormTelegramBotConfig"; import AccessFormTencentCloudConfig from "./AccessFormTencentCloudConfig"; import AccessFormUCloudConfig from "./AccessFormUCloudConfig"; import AccessFormUpyunConfig from "./AccessFormUpyunConfig"; @@ -264,8 +264,8 @@ const AccessForm = forwardRef(({ className, return ; case ACCESS_PROVIDERS.SSH: return ; - case ACCESS_PROVIDERS.TELEGRAM: - return ; + case ACCESS_PROVIDERS.TELEGRAMBOT: + return ; case ACCESS_PROVIDERS.SSLCOM: return ; case ACCESS_PROVIDERS.TENCENTCLOUD: diff --git a/ui/src/components/access/AccessFormTelegramConfig.tsx b/ui/src/components/access/AccessFormTelegramBotConfig.tsx similarity index 69% rename from ui/src/components/access/AccessFormTelegramConfig.tsx rename to ui/src/components/access/AccessFormTelegramBotConfig.tsx index a4eccafb..77b9afa1 100644 --- a/ui/src/components/access/AccessFormTelegramConfig.tsx +++ b/ui/src/components/access/AccessFormTelegramBotConfig.tsx @@ -3,25 +3,25 @@ import { Form, type FormInstance, Input } from "antd"; import { createSchemaFieldRule } from "antd-zod"; import { z } from "zod"; -import { type AccessConfigForTelegram } from "@/domain/access"; +import { type AccessConfigForTelegramBot } from "@/domain/access"; -type AccessFormTelegramConfigFieldValues = Nullish; +type AccessFormTelegramBotConfigFieldValues = Nullish; -export type AccessFormTelegramConfigProps = { +export type AccessFormTelegramBotConfigProps = { form: FormInstance; formName: string; disabled?: boolean; - initialValues?: AccessFormTelegramConfigFieldValues; - onValuesChange?: (values: AccessFormTelegramConfigFieldValues) => void; + initialValues?: AccessFormTelegramBotConfigFieldValues; + onValuesChange?: (values: AccessFormTelegramBotConfigFieldValues) => void; }; -const initFormModel = (): AccessFormTelegramConfigFieldValues => { +const initFormModel = (): AccessFormTelegramBotConfigFieldValues => { return { botToken: "", }; }; -const AccessFormTelegramConfig = ({ form: formInst, formName, disabled, initialValues, onValuesChange }: AccessFormTelegramConfigProps) => { +const AccessFormTelegramBotConfig = ({ form: formInst, formName, disabled, initialValues, onValuesChange }: AccessFormTelegramBotConfigProps) => { const { t } = useTranslation(); const formSchema = z.object({ @@ -38,7 +38,7 @@ const AccessFormTelegramConfig = ({ form: formInst, formName, disabled, initialV .refine((v) => { if (v == null || v + "" === "") return true; return /^\d+$/.test(v + "") && +v! > 0; - }, t("access.form.telegram_default_chat_id.placeholder")) + }, t("access.form.telegram_bot_default_chat_id.placeholder")) ) .nullish(), }); @@ -68,14 +68,14 @@ const AccessFormTelegramConfig = ({ form: formInst, formName, disabled, initialV } + tooltip={} > - + ); }; -export default AccessFormTelegramConfig; +export default AccessFormTelegramBotConfig; diff --git a/ui/src/components/access/AccessFormWebhookConfig.tsx b/ui/src/components/access/AccessFormWebhookConfig.tsx index 69286aa8..0dea7f7c 100644 --- a/ui/src/components/access/AccessFormWebhookConfig.tsx +++ b/ui/src/components/access/AccessFormWebhookConfig.tsx @@ -142,8 +142,7 @@ const AccessFormWebhookConfig = ({ form: formInst, formName, disabled, initialVa { title: "${SUBJECT}", body: "${MESSAGE}", - group: "", - device_keys: "", + device_key: "", }, null, 2 diff --git a/ui/src/components/workflow/node/NotifyNodeConfigForm.tsx b/ui/src/components/workflow/node/NotifyNodeConfigForm.tsx index 32488aeb..d303c2ba 100644 --- a/ui/src/components/workflow/node/NotifyNodeConfigForm.tsx +++ b/ui/src/components/workflow/node/NotifyNodeConfigForm.tsx @@ -19,7 +19,7 @@ import { useNotifyChannelsStore } from "@/stores/notify"; import NotifyNodeConfigFormEmailConfig from "./NotifyNodeConfigFormEmailConfig"; import NotifyNodeConfigFormMattermostConfig from "./NotifyNodeConfigFormMattermostConfig"; -import NotifyNodeConfigFormTelegramConfig from "./NotifyNodeConfigFormTelegramConfig"; +import NotifyNodeConfigFormTelegramBotConfig from "./NotifyNodeConfigFormTelegramBotConfig"; import NotifyNodeConfigFormWebhookConfig from "./NotifyNodeConfigFormWebhookConfig"; type NotifyNodeConfigFormFieldValues = Partial; @@ -114,8 +114,8 @@ const NotifyNodeConfigForm = forwardRef; case NOTIFICATION_PROVIDERS.MATTERMOST: return ; - case NOTIFICATION_PROVIDERS.TELEGRAM: - return ; + case NOTIFICATION_PROVIDERS.TELEGRAMBOT: + return ; case NOTIFICATION_PROVIDERS.WEBHOOK: return ; } diff --git a/ui/src/components/workflow/node/NotifyNodeConfigFormTelegramConfig.tsx b/ui/src/components/workflow/node/NotifyNodeConfigFormTelegramBotConfig.tsx similarity index 60% rename from ui/src/components/workflow/node/NotifyNodeConfigFormTelegramConfig.tsx rename to ui/src/components/workflow/node/NotifyNodeConfigFormTelegramBotConfig.tsx index 07774413..b4e4092e 100644 --- a/ui/src/components/workflow/node/NotifyNodeConfigFormTelegramConfig.tsx +++ b/ui/src/components/workflow/node/NotifyNodeConfigFormTelegramBotConfig.tsx @@ -3,23 +3,29 @@ import { Form, type FormInstance, Input } from "antd"; import { createSchemaFieldRule } from "antd-zod"; import { z } from "zod"; -type NotifyNodeConfigFormTelegramConfigFieldValues = Nullish<{ +type NotifyNodeConfigFormTelegramBotConfigFieldValues = Nullish<{ chatId?: string | number; }>; -export type NotifyNodeConfigFormTelegramConfigProps = { +export type NotifyNodeConfigFormTelegramBotConfigProps = { form: FormInstance; formName: string; disabled?: boolean; - initialValues?: NotifyNodeConfigFormTelegramConfigFieldValues; - onValuesChange?: (values: NotifyNodeConfigFormTelegramConfigFieldValues) => void; + initialValues?: NotifyNodeConfigFormTelegramBotConfigFieldValues; + onValuesChange?: (values: NotifyNodeConfigFormTelegramBotConfigFieldValues) => void; }; -const initFormModel = (): NotifyNodeConfigFormTelegramConfigFieldValues => { +const initFormModel = (): NotifyNodeConfigFormTelegramBotConfigFieldValues => { return {}; }; -const NotifyNodeConfigFormTelegramConfig = ({ form: formInst, formName, disabled, initialValues, onValuesChange }: NotifyNodeConfigFormTelegramConfigProps) => { +const NotifyNodeConfigFormTelegramBotConfig = ({ + form: formInst, + formName, + disabled, + initialValues, + onValuesChange, +}: NotifyNodeConfigFormTelegramBotConfigProps) => { const { t } = useTranslation(); const formSchema = z.object({ @@ -32,7 +38,7 @@ const NotifyNodeConfigFormTelegramConfig = ({ form: formInst, formName, disabled .refine((v) => { if (v == null || v + "" === "") return true; return /^\d+$/.test(v + "") && +v! > 0; - }, t("workflow_node.notify.form.telegram_chat_id.placeholder")) + }, t("workflow_node.notify.form.telegram_bot_chat_id.placeholder")) ) .nullish(), }); @@ -53,14 +59,14 @@ const NotifyNodeConfigFormTelegramConfig = ({ form: formInst, formName, disabled > } + tooltip={} > - + ); }; -export default NotifyNodeConfigFormTelegramConfig; +export default NotifyNodeConfigFormTelegramBotConfig; diff --git a/ui/src/domain/access.ts b/ui/src/domain/access.ts index 0d516385..9e2d7c35 100644 --- a/ui/src/domain/access.ts +++ b/ui/src/domain/access.ts @@ -51,7 +51,7 @@ export interface AccessModel extends BaseModel { | AccessConfigForSafeLine | AccessConfigForSSH | AccessConfigForSSLCom - | AccessConfigForTelegram + | AccessConfigForTelegramBot | AccessConfigForTencentCloud | AccessConfigForUCloud | AccessConfigForUpyun @@ -312,7 +312,7 @@ export type AccessConfigForSSLCom = { eabHmacKey: string; }; -export type AccessConfigForTelegram = { +export type AccessConfigForTelegramBot = { botToken: string; defaultChatId?: number; }; diff --git a/ui/src/domain/provider.ts b/ui/src/domain/provider.ts index fbac84ba..878814f5 100644 --- a/ui/src/domain/provider.ts +++ b/ui/src/domain/provider.ts @@ -54,7 +54,7 @@ export const ACCESS_PROVIDERS = Object.freeze({ SAFELINE: "safeline", SSH: "ssh", SSLCOM: "sslcom", - TELEGRAM: "telegram", + TELEGRAMBOT: "telegrambot", TENCENTCLOUD: "tencentcloud", UCLOUD: "ucloud", UPYUN: "upyun", @@ -157,7 +157,7 @@ export const accessProvidersMap: Map [ e[0] as string, { @@ -547,7 +547,7 @@ export const NOTIFICATION_PROVIDERS = Object.freeze({ EMAIL: `${ACCESS_PROVIDERS.EMAIL}`, LARKBOT: `${ACCESS_PROVIDERS.LARKBOT}`, MATTERMOST: `${ACCESS_PROVIDERS.MATTERMOST}`, - TELEGRAM: `${ACCESS_PROVIDERS.TELEGRAM}`, + TELEGRAMBOT: `${ACCESS_PROVIDERS.TELEGRAMBOT}`, WEBHOOK: `${ACCESS_PROVIDERS.WEBHOOK}`, WECOMBOT: `${ACCESS_PROVIDERS.WECOMBOT}`, } as const); @@ -573,7 +573,7 @@ export const notificationProvidersMap: Map [ type, { diff --git a/ui/src/i18n/locales/en/nls.access.json b/ui/src/i18n/locales/en/nls.access.json index cff44b7c..32ae2885 100644 --- a/ui/src/i18n/locales/en/nls.access.json +++ b/ui/src/i18n/locales/en/nls.access.json @@ -343,9 +343,9 @@ "access.form.telegram_bot_token.label": "Telegram bot token", "access.form.telegram_bot_token.placeholder": "Please enter Telegram bot token", "access.form.telegram_bot_token.tooltip": "How to get the bot token? Please refer to https://gist.github.com/nafiesl/4ad622f344cd1dc3bb1ecbe468ff9f8a", - "access.form.telegram_default_chat_id.label": "Default Telegram chat ID (Optional)", - "access.form.telegram_default_chat_id.placeholder": "Please enter default Telegram chat ID", - "access.form.telegram_default_chat_id.tooltip": "How to get the chat ID? Please refer to https://gist.github.com/nafiesl/4ad622f344cd1dc3bb1ecbe468ff9f8a", + "access.form.telegram_bot_default_chat_id.label": "Default Telegram chat ID (Optional)", + "access.form.telegram_bot_default_chat_id.placeholder": "Please enter default Telegram chat ID", + "access.form.telegram_bot_default_chat_id.tooltip": "How to get the chat ID? Please refer to https://gist.github.com/nafiesl/4ad622f344cd1dc3bb1ecbe468ff9f8a", "access.form.tencentcloud_secret_id.label": "Tencent Cloud SecretId", "access.form.tencentcloud_secret_id.placeholder": "Please enter Tencent Cloud SecretId", "access.form.tencentcloud_secret_id.tooltip": "For more information, see https://cloud.tencent.com/document/product/598/40488?lang=en", diff --git a/ui/src/i18n/locales/en/nls.provider.json b/ui/src/i18n/locales/en/nls.provider.json index 6d67f55c..82eab327 100644 --- a/ui/src/i18n/locales/en/nls.provider.json +++ b/ui/src/i18n/locales/en/nls.provider.json @@ -106,7 +106,7 @@ "provider.safeline": "SafeLine", "provider.ssh": "SSH deployment", "provider.sslcom": "SSL.com", - "provider.telegram": "Telegram", + "provider.telegrambot": "Telegram Bot", "provider.tencentcloud": "Tencent Cloud", "provider.tencentcloud.cdn": "Tencent Cloud - CDN (Content Delivery Network)", "provider.tencentcloud.clb": "Tencent Cloud - CLB (Cloud Load Balancer)", diff --git a/ui/src/i18n/locales/en/nls.workflow.nodes.json b/ui/src/i18n/locales/en/nls.workflow.nodes.json index c9468b33..7b53e6e4 100644 --- a/ui/src/i18n/locales/en/nls.workflow.nodes.json +++ b/ui/src/i18n/locales/en/nls.workflow.nodes.json @@ -776,9 +776,9 @@ "workflow_node.notify.form.mattermost_channel_id.label": "Mattermost channel ID (Optional)", "workflow_node.notify.form.mattermost_channel_id.placeholder": "Please enter Mattermost channel ID to override the default value", "workflow_node.notify.form.mattermost_channel_id.tooltip": "Leave it blank to use the default channel ID provided by the authorization.", - "workflow_node.notify.form.telegram_chat_id.label": "Telegram chat ID (Optional)", - "workflow_node.notify.form.telegram_chat_id.placeholder": "Please enter Telegram chat ID to override the default value", - "workflow_node.notify.form.telegram_chat_id.tooltip": "Leave it blank to use the default chat ID provided by the selected authorization.", + "workflow_node.notify.form.telegram_bot_chat_id.label": "Telegram chat ID (Optional)", + "workflow_node.notify.form.telegram_bot_chat_id.placeholder": "Please enter Telegram chat ID to override the default value", + "workflow_node.notify.form.telegram_bot_chat_id.tooltip": "Leave it blank to use the default chat ID provided by the selected authorization.", "workflow_node.notify.form.webhook_data.label": "Webhook data (Optional)", "workflow_node.notify.form.webhook_data.placeholder": "Please enter Webhook data to override the default value", "workflow_node.notify.form.webhook_data.tooltip": "Leave it blank to use the default Webhook data provided by the authorization.", diff --git a/ui/src/i18n/locales/zh/nls.access.json b/ui/src/i18n/locales/zh/nls.access.json index f73065ea..5af00a92 100644 --- a/ui/src/i18n/locales/zh/nls.access.json +++ b/ui/src/i18n/locales/zh/nls.access.json @@ -334,12 +334,12 @@ "access.form.sslcom_eab_hmac_key.label": "ACME EAB HMAC key", "access.form.sslcom_eab_hmac_key.placeholder": "请输入 ACME EAB HMAC key", "access.form.sslcom_eab_hmac_key.tooltip": "这是什么?请参阅 https://www.ssl.com/how-to/generate-acme-credentials-for-reseller-customers/", - "access.form.telegram_bot_token.label": "Telegram 机器人 API Token", - "access.form.telegram_bot_token.placeholder": "请输入 Telegram 机器人 API Token", + "access.form.telegram_bot_token.label": "Telegram 群机器人 API Token", + "access.form.telegram_bot_token.placeholder": "请输入 Telegram 群机器人 API Token", "access.form.telegram_bot_token.tooltip": "如何获取机器人 API Token?请参阅 https://gist.github.com/nafiesl/4ad622f344cd1dc3bb1ecbe468ff9f8a", - "access.form.telegram_default_chat_id.label": "默认的 Telegram 会话 ID(可选)", - "access.form.telegram_default_chat_id.placeholder": "请输入默认的 Telegram 会话 ID", - "access.form.telegram_default_chat_id.tooltip": "如何获取会话 ID?请参阅 https://gist.github.com/nafiesl/4ad622f344cd1dc3bb1ecbe468ff9f8a", + "access.form.telegram_bot_default_chat_id.label": "默认的 Telegram 会话 ID(可选)", + "access.form.telegram_bot_default_chat_id.placeholder": "请输入默认的 Telegram 会话 ID", + "access.form.telegram_bot_default_chat_id.tooltip": "如何获取会话 ID?请参阅 https://gist.github.com/nafiesl/4ad622f344cd1dc3bb1ecbe468ff9f8a", "access.form.tencentcloud_secret_id.label": "腾讯云 SecretId", "access.form.tencentcloud_secret_id.placeholder": "请输入腾讯云 SecretId", "access.form.tencentcloud_secret_id.tooltip": "这是什么?请参阅 https://cloud.tencent.com/document/product/598/40488", diff --git a/ui/src/i18n/locales/zh/nls.provider.json b/ui/src/i18n/locales/zh/nls.provider.json index 93b5137d..dc635f68 100644 --- a/ui/src/i18n/locales/zh/nls.provider.json +++ b/ui/src/i18n/locales/zh/nls.provider.json @@ -106,7 +106,7 @@ "provider.safeline": "雷池", "provider.ssh": "SSH 部署", "provider.sslcom": "SSL.com", - "provider.telegram": "Telegram", + "provider.telegrambot": "Telegram 群机器人", "provider.tencentcloud": "腾讯云", "provider.tencentcloud.cdn": "腾讯云 - 内容分发网络 CDN", "provider.tencentcloud.clb": "腾讯云 - 负载均衡 CLB", diff --git a/ui/src/i18n/locales/zh/nls.workflow.nodes.json b/ui/src/i18n/locales/zh/nls.workflow.nodes.json index b8c98418..89cbfc11 100644 --- a/ui/src/i18n/locales/zh/nls.workflow.nodes.json +++ b/ui/src/i18n/locales/zh/nls.workflow.nodes.json @@ -775,9 +775,9 @@ "workflow_node.notify.form.mattermost_channel_id.label": "Mattermost 频道 ID(可选)", "workflow_node.notify.form.mattermost_channel_id.placeholder": "请输入 Mattermost 频道 ID 以覆盖默认值", "workflow_node.notify.form.mattermost_channel_id.tooltip": "不填写时,将使用所选通知渠道授权的默认频道 ID。", - "workflow_node.notify.form.telegram_chat_id.label": "Telegram 会话 ID(可选)", - "workflow_node.notify.form.telegram_chat_id.placeholder": "请输入 Telegram 会话 ID 以覆盖默认值", - "workflow_node.notify.form.telegram_chat_id.tooltip": "不填写时,将使用所选通知渠道授权的默认会话 ID。", + "workflow_node.notify.form.telegram_bot_chat_id.label": "Telegram 会话 ID(可选)", + "workflow_node.notify.form.telegram_bot_chat_id.placeholder": "请输入 Telegram 会话 ID 以覆盖默认值", + "workflow_node.notify.form.telegram_bot_chat_id.tooltip": "不填写时,将使用所选通知渠道授权的默认会话 ID。", "workflow_node.notify.form.webhook_data.label": "Webhook 回调数据(可选)", "workflow_node.notify.form.webhook_data.placeholder": "请输入 Webhook 回调数据以覆盖默认值", "workflow_node.notify.form.webhook_data.tooltip": "不填写时,将使用所选部署目标授权的默认 Webhook 回调数据。",