Merge pull request #583 from catfishlty/feat/pushplus

feat(notify): add pushplus
This commit is contained in:
Yoan.liu 2025-04-03 17:41:46 +08:00 committed by GitHub
commit 74d66a0131
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 224 additions and 1 deletions

View File

@ -13,6 +13,7 @@ const (
NotifyChannelTypeDingTalk = NotifyChannelType("dingtalk")
NotifyChannelTypeEmail = NotifyChannelType("email")
NotifyChannelTypeLark = NotifyChannelType("lark")
NotifyChannelTypePushPlus = NotifyChannelType("pushplus")
NotifyChannelTypeServerChan = NotifyChannelType("serverchan")
NotifyChannelTypeTelegram = NotifyChannelType("telegram")
NotifyChannelTypeWebhook = NotifyChannelType("webhook")

View File

@ -9,6 +9,7 @@ import (
pDingTalk "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/dingtalk"
pEmail "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/email"
pLark "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/lark"
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"
pWebhook "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/webhook"
@ -50,6 +51,11 @@ func createNotifier(channel domain.NotifyChannelType, channelConfig map[string]a
WebhookUrl: maputil.GetString(channelConfig, "webhookUrl"),
})
case domain.NotifyChannelTypePushPlus:
return pPushPlus.NewNotifier(&pPushPlus.NotifierConfig{
Token: maputil.GetString(channelConfig, "token"),
})
case domain.NotifyChannelTypeServerChan:
return pServerChan.NewNotifier(&pServerChan.NotifierConfig{
Url: maputil.GetString(channelConfig, "url"),

View File

@ -1,4 +1,4 @@
package notifier
package notifier
import (
"context"

View File

@ -0,0 +1,113 @@
package pushplus
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"log/slog"
"net/http"
"github.com/pkg/errors"
"github.com/usual2970/certimate/internal/pkg/core/notifier"
)
type NotifierConfig struct {
// PushPlus Token
Token string `json:"token"`
}
type NotifierProvider struct {
config *NotifierConfig
logger *slog.Logger
// 未来将移除
httpClient *http.Client
}
var _ notifier.Notifier = (*NotifierProvider)(nil)
func NewNotifier(config *NotifierConfig) (*NotifierProvider, error) {
if config == nil {
panic("config is nil")
}
return &NotifierProvider{
config: config,
httpClient: http.DefaultClient,
}, nil
}
func (n *NotifierProvider) WithLogger(logger *slog.Logger) notifier.Notifier {
if logger == nil {
n.logger = slog.Default()
} else {
n.logger = logger
}
return n
}
// Notify 发送通知
// 参考文档https://pushplus.plus/doc/guide/api.html
func (n *NotifierProvider) Notify(ctx context.Context, subject string, message string) (res *notifier.NotifyResult, err error) {
// 请求体
reqBody := &struct {
Token string `json:"token"`
Title string `json:"title"`
Content string `json:"content"`
}{
Token: n.config.Token,
Title: subject,
Content: message,
}
// Make request
body, err := json.Marshal(reqBody)
if err != nil {
return nil, errors.Wrap(err, "encode message body")
}
req, err := http.NewRequestWithContext(
ctx,
http.MethodPost,
"https://www.pushplus.plus/send",
bytes.NewReader(body),
)
if err != nil {
return nil, errors.Wrap(err, "create new request")
}
req.Header.Set("Content-Type", "application/json; charset=utf-8")
// Send request to pushplus service
resp, err := n.httpClient.Do(req)
if err != nil {
return nil, errors.Wrapf(err, "send request to pushplus server")
}
defer resp.Body.Close()
result, err := io.ReadAll(resp.Body)
if err != nil {
return nil, errors.Wrap(err, "read response")
}
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("pushplus returned status code %d: %s", resp.StatusCode, string(result))
}
// 解析响应
var errorResponse struct {
Code int `json:"code"`
Msg string `json:"msg"`
}
if err := json.Unmarshal(result, &errorResponse); err != nil {
return nil, errors.Wrap(err, "decode response")
}
if errorResponse.Code != 200 {
return nil, fmt.Errorf("pushplus returned error: %s", errorResponse.Msg)
}
return &notifier.NotifyResult{}, nil
}

View File

@ -0,0 +1,56 @@
package pushplus_test
import (
"context"
"flag"
"fmt"
"strings"
"testing"
provider "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/pushplus"
)
const (
mockSubject = "test_subject"
mockMessage = "test_message"
)
var fToken string
func init() {
argsPrefix := "CERTIMATE_NOTIFIER_PUSHPLUS_"
flag.StringVar(&fToken, argsPrefix+"TOKEN", "", "")
}
/*
Shell command to run this test:
go test -v ./pushplus_test.go -args \
--CERTIMATE_NOTIFIER_PUSHPLUS_TOKEN="your-pushplus-token" \
*/
func TestNotify(t *testing.T) {
flag.Parse()
t.Run("Notify", func(t *testing.T) {
t.Log(strings.Join([]string{
"args:",
fmt.Sprintf("TOKEN: %v", fToken),
}, "\n"))
notifier, err := provider.NewNotifier(&provider.NotifierConfig{
Token: fToken,
})
if err != nil {
t.Errorf("err: %+v", err)
return
}
res, err := notifier.Notify(context.Background(), mockSubject, mockMessage)
if err != nil {
t.Errorf("err: %+v", err)
return
}
t.Logf("ok: %v", res)
})
}

View File

@ -8,6 +8,7 @@ import NotifyChannelEditFormBarkFields from "./NotifyChannelEditFormBarkFields";
import NotifyChannelEditFormDingTalkFields from "./NotifyChannelEditFormDingTalkFields";
import NotifyChannelEditFormEmailFields from "./NotifyChannelEditFormEmailFields";
import NotifyChannelEditFormLarkFields from "./NotifyChannelEditFormLarkFields";
import NotifyChannelEditFormPushPlusFields from "./NotifyChannelEditFormPushPlusFields";
import NotifyChannelEditFormServerChanFields from "./NotifyChannelEditFormServerChanFields";
import NotifyChannelEditFormTelegramFields from "./NotifyChannelEditFormTelegramFields";
import NotifyChannelEditFormWebhookFields from "./NotifyChannelEditFormWebhookFields";
@ -50,6 +51,8 @@ const NotifyChannelEditForm = forwardRef<NotifyChannelEditFormInstance, NotifyCh
return <NotifyChannelEditFormEmailFields />;
case NOTIFY_CHANNELS.LARK:
return <NotifyChannelEditFormLarkFields />;
case NOTIFY_CHANNELS.PUSHPLUS:
return <NotifyChannelEditFormPushPlusFields />;
case NOTIFY_CHANNELS.SERVERCHAN:
return <NotifyChannelEditFormServerChanFields />;
case NOTIFY_CHANNELS.TELEGRAM:

View File

@ -0,0 +1,28 @@
import { useTranslation } from "react-i18next";
import { Form, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod";
const NotifyChannelEditFormPushPlusFields = () => {
const { t } = useTranslation();
const formSchema = z.object({
token: z.string({ message: t("settings.notification.channel.form.pushplus_token.placeholder") }),
});
const formRule = createSchemaFieldRule(formSchema);
return (
<>
<Form.Item
name="token"
label={t("settings.notification.channel.form.pushplus_token.label")}
rules={[formRule]}
tooltip={<span dangerouslySetInnerHTML={{ __html: t("settings.notification.channel.form.pushplus_token.tooltip") }}></span>}
>
<Input placeholder={t("settings.notification.channel.form.pushplus_token.placeholder")} />
</Form.Item>
</>
);
};
export default NotifyChannelEditFormPushPlusFields;

View File

@ -41,6 +41,7 @@ export const NOTIFY_CHANNELS = Object.freeze({
DINGTALK: "dingtalk",
EMAIL: "email",
LARK: "lark",
PUSHPLUS: "pushplus",
SERVERCHAN: "serverchan",
TELEGRAM: "telegram",
WEBHOOK: "webhook",
@ -59,6 +60,7 @@ export type NotifyChannelsSettingsContent = {
[NOTIFY_CHANNELS.DINGTALK]?: DingTalkNotifyChannelConfig;
[NOTIFY_CHANNELS.EMAIL]?: EmailNotifyChannelConfig;
[NOTIFY_CHANNELS.LARK]?: LarkNotifyChannelConfig;
[NOTIFY_CHANNELS.PUSHPLUS]?: PushPlusNotifyChannelConfig;
[NOTIFY_CHANNELS.SERVERCHAN]?: ServerChanNotifyChannelConfig;
[NOTIFY_CHANNELS.TELEGRAM]?: TelegramNotifyChannelConfig;
[NOTIFY_CHANNELS.WEBHOOK]?: WebhookNotifyChannelConfig;
@ -93,6 +95,11 @@ export type LarkNotifyChannelConfig = {
enabled?: boolean;
};
export type PushPlusNotifyChannelConfig = {
token: string;
enabled?: boolean;
};
export type ServerChanNotifyChannelConfig = {
url: string;
enabled?: boolean;
@ -124,6 +131,7 @@ export const notifyChannelsMap: Map<NotifyChannel["type"], NotifyChannel> = new
[NOTIFY_CHANNELS.EMAIL, "common.notifier.email"],
[NOTIFY_CHANNELS.DINGTALK, "common.notifier.dingtalk"],
[NOTIFY_CHANNELS.LARK, "common.notifier.lark"],
[NOTIFY_CHANNELS.PUSHPLUS, "common.notifier.pushplus"],
[NOTIFY_CHANNELS.WECOM, "common.notifier.wecom"],
[NOTIFY_CHANNELS.TELEGRAM, "common.notifier.telegram"],
[NOTIFY_CHANNELS.SERVERCHAN, "common.notifier.serverchan"],

View File

@ -39,6 +39,7 @@
"common.notifier.dingtalk": "DingTalk",
"common.notifier.email": "Email",
"common.notifier.lark": "Lark",
"common.notifier.pushplus": "PushPlus",
"common.notifier.serverchan": "ServerChan",
"common.notifier.telegram": "Telegram",
"common.notifier.webhook": "Webhook",

View File

@ -56,6 +56,9 @@
"settings.notification.channel.form.lark_webhook_url.label": "Webhook URL",
"settings.notification.channel.form.lark_webhook_url.placeholder": "Please enter Webhook URL",
"settings.notification.channel.form.lark_webhook_url.tooltip": "For more information, see <a href=\"https://www.feishu.cn/hc/en-US/articles/807992406756\" target=\"_blank\">https://www.feishu.cn/hc/en-US/articles/807992406756</a>",
"settings.notification.channel.form.pushplus_token.placeholder": "Please enter Token",
"settings.notification.channel.form.pushplus_token.label": "Token",
"settings.notification.channel.form.pushplus_token.tooltip": "For more information, see <a href=\"https://www.pushplus.plus/push1.html\" target=\"_blank\">https://www.pushplus.plus/push1.html</a>",
"settings.notification.channel.form.serverchan_url.label": "Server URL",
"settings.notification.channel.form.serverchan_url.placeholder": "Please enter ServerChan server URL (e.g. https://sctapi.ftqq.com/*****.send)",
"settings.notification.channel.form.serverchan_url.tooltip": "For more information, see <a href=\"https://sct.ftqq.com/forward\" target=\"_blank\">https://sct.ftqq.com/forward</a>",

View File

@ -39,6 +39,7 @@
"common.notifier.dingtalk": "钉钉",
"common.notifier.email": "邮件",
"common.notifier.lark": "飞书",
"common.notifier.pushplus": "PushPlus推送加",
"common.notifier.serverchan": "Server 酱",
"common.notifier.telegram": "Telegram",
"common.notifier.webhook": "Webhook",

View File

@ -56,6 +56,9 @@
"settings.notification.channel.form.lark_webhook_url.label": "机器人 Webhook 地址",
"settings.notification.channel.form.lark_webhook_url.placeholder": "请输入机器人 Webhook 地址",
"settings.notification.channel.form.lark_webhook_url.tooltip": "这是什么?请参阅 <a href=\"https://www.feishu.cn/hc/zh-CN/articles/807992406756\" target=\"_blank\">https://www.feishu.cn/hc/zh-CN/articles/807992406756</a>",
"settings.notification.channel.form.pushplus_token.placeholder": "请输入Token",
"settings.notification.channel.form.pushplus_token.label": "Token",
"settings.notification.channel.form.pushplus_token.tooltip": "请参阅 <a href=\"https://www.pushplus.plus/push1.html\" target=\"_blank\">https://www.pushplus.plus/push1.html</a>",
"settings.notification.channel.form.serverchan_url.label": "服务器地址",
"settings.notification.channel.form.serverchan_url.placeholder": "请输入服务器地址(形如: https://sctapi.ftqq.com/*****.send",
"settings.notification.channel.form.serverchan_url.tooltip": "这是什么?请参阅 <a href=\"https://sct.ftqq.com/forward\" target=\"_blank\">https://sct.ftqq.com/forward</a>",