mirror of
https://github.com/woodchen-ink/certimate.git
synced 2025-07-18 17:31:55 +08:00
feat(notify): add mattermost
This commit is contained in:
parent
4e3f499d76
commit
ec0cdf8b96
@ -14,6 +14,7 @@ const (
|
||||
NotifyChannelTypeEmail = NotifyChannelType("email")
|
||||
NotifyChannelTypeGotify = NotifyChannelType("gotify")
|
||||
NotifyChannelTypeLark = NotifyChannelType("lark")
|
||||
NotifyChannelTypeMattermost = NotifyChannelType("mattermost")
|
||||
NotifyChannelTypePushPlus = NotifyChannelType("pushplus")
|
||||
NotifyChannelTypeServerChan = NotifyChannelType("serverchan")
|
||||
NotifyChannelTypeTelegram = NotifyChannelType("telegram")
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
pEmail "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/email"
|
||||
pGotify "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/gotify"
|
||||
pLark "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/lark"
|
||||
pMattermost "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/mattermost"
|
||||
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"
|
||||
@ -59,6 +60,14 @@ func createNotifier(channel domain.NotifyChannelType, channelConfig map[string]a
|
||||
WebhookUrl: maputil.GetString(channelConfig, "webhookUrl"),
|
||||
})
|
||||
|
||||
case domain.NotifyChannelTypeMattermost:
|
||||
return pMattermost.NewNotifier(&pMattermost.NotifierConfig{
|
||||
ServerUrl: maputil.GetString(channelConfig, "serverUrl"),
|
||||
ChannelId: maputil.GetString(channelConfig, "channelId"),
|
||||
Username: maputil.GetString(channelConfig, "username"),
|
||||
Password: maputil.GetString(channelConfig, "password"),
|
||||
})
|
||||
|
||||
case domain.NotifyChannelTypePushPlus:
|
||||
return pPushPlus.NewNotifier(&pPushPlus.NotifierConfig{
|
||||
Token: maputil.GetString(channelConfig, "token"),
|
||||
|
@ -0,0 +1,89 @@
|
||||
package mattermost
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"github.com/nikoksr/notify/service/mattermost"
|
||||
"github.com/usual2970/certimate/internal/pkg/core/notifier"
|
||||
"io"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type NotifierConfig struct {
|
||||
// Mattermost 服务地址。
|
||||
ServerUrl string `json:"serverUrl"`
|
||||
// 频道ID
|
||||
ChannelId string `json:"channelId"`
|
||||
// 用户名
|
||||
Username string `json:"username"`
|
||||
// 密码
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
type NotifierProvider struct {
|
||||
config *NotifierConfig
|
||||
logger *slog.Logger
|
||||
}
|
||||
|
||||
var _ notifier.Notifier = (*NotifierProvider)(nil)
|
||||
|
||||
func NewNotifier(config *NotifierConfig) (*NotifierProvider, error) {
|
||||
if config == nil {
|
||||
panic("config is nil")
|
||||
}
|
||||
|
||||
return &NotifierProvider{
|
||||
config: config,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (n *NotifierProvider) WithLogger(logger *slog.Logger) notifier.Notifier {
|
||||
if logger == nil {
|
||||
n.logger = slog.Default()
|
||||
} else {
|
||||
n.logger = logger
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func (n *NotifierProvider) Notify(ctx context.Context, subject string, message string) (res *notifier.NotifyResult, err error) {
|
||||
srv := mattermost.New(n.config.ServerUrl)
|
||||
|
||||
if err := srv.LoginWithCredentials(ctx, n.config.Username, n.config.Password); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
srv.AddReceivers(n.config.ChannelId)
|
||||
|
||||
// 复写消息样式
|
||||
srv.PreSend(func(req *http.Request) error {
|
||||
m := map[string]interface{}{
|
||||
"channel_id": n.config.ChannelId,
|
||||
"props": map[string]interface{}{
|
||||
"attachments": []map[string]interface{}{
|
||||
{
|
||||
"title": subject,
|
||||
"text": message,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
return ¬ifier.NotifyResult{}, nil
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
package mattermost_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
provider "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/mattermost"
|
||||
)
|
||||
|
||||
const (
|
||||
mockSubject = "test_subject"
|
||||
mockMessage = "test_message"
|
||||
)
|
||||
|
||||
var (
|
||||
fServerUrl string
|
||||
fChannelId string
|
||||
fUsername string
|
||||
fPassword string
|
||||
)
|
||||
|
||||
func init() {
|
||||
argsPrefix := "CERTIMATE_NOTIFIER_MATTERMOST_"
|
||||
|
||||
flag.StringVar(&fServerUrl, argsPrefix+"SERVERURL", "", "")
|
||||
flag.StringVar(&fChannelId, argsPrefix+"CHANNELID", "", "")
|
||||
flag.StringVar(&fUsername, argsPrefix+"USERNAME", "", "")
|
||||
flag.StringVar(&fPassword, argsPrefix+"PASSWORD", "", "")
|
||||
}
|
||||
|
||||
/*
|
||||
Shell command to run this test:
|
||||
|
||||
go test -v ./mattermost_test.go -args \
|
||||
--CERTIMATE_NOTIFIER_MATTERMOST_SERVERURL="https://example.com/your-server-url" \
|
||||
--CERTIMATE_NOTIFIER_MATTERMOST_CHANNELID="your-chanel-id" \
|
||||
--CERTIMATE_NOTIFIER_MATTERMOST_USERNAME="your-username" \
|
||||
--CERTIMATE_NOTIFIER_MATTERMOST_PASSWORD="your-password"
|
||||
*/
|
||||
func TestNotify(t *testing.T) {
|
||||
flag.Parse()
|
||||
|
||||
t.Run("Notify", func(t *testing.T) {
|
||||
t.Log(strings.Join([]string{
|
||||
"args:",
|
||||
fmt.Sprintf("SERVERURL: %v", fServerUrl),
|
||||
fmt.Sprintf("CHANNELID: %v", fChannelId),
|
||||
fmt.Sprintf("USERNAME: %v", fUsername),
|
||||
fmt.Sprintf("PASSWORD: %v", fPassword),
|
||||
}, "\n"))
|
||||
|
||||
notifier, err := provider.NewNotifier(&provider.NotifierConfig{
|
||||
ServerUrl: fServerUrl,
|
||||
ChannelId: fChannelId,
|
||||
Username: fUsername,
|
||||
Password: fPassword,
|
||||
})
|
||||
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)
|
||||
})
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
import { forwardRef, useImperativeHandle, useMemo } from "react";
|
||||
import { Form, type FormInstance } from "antd";
|
||||
import {forwardRef, useImperativeHandle, useMemo} from "react";
|
||||
import {Form, type FormInstance} from "antd";
|
||||
|
||||
import { NOTIFY_CHANNELS, type NotifyChannelsSettingsContent } from "@/domain/settings";
|
||||
import { useAntdForm } from "@/hooks";
|
||||
import {NOTIFY_CHANNELS, type NotifyChannelsSettingsContent} from "@/domain/settings";
|
||||
import {useAntdForm} from "@/hooks";
|
||||
|
||||
import NotifyChannelEditFormBarkFields from "./NotifyChannelEditFormBarkFields";
|
||||
import NotifyChannelEditFormDingTalkFields from "./NotifyChannelEditFormDingTalkFields";
|
||||
@ -14,6 +14,7 @@ import NotifyChannelEditFormServerChanFields from "./NotifyChannelEditFormServer
|
||||
import NotifyChannelEditFormTelegramFields from "./NotifyChannelEditFormTelegramFields";
|
||||
import NotifyChannelEditFormWebhookFields from "./NotifyChannelEditFormWebhookFields";
|
||||
import NotifyChannelEditFormWeComFields from "./NotifyChannelEditFormWeComFields";
|
||||
import NotifyChannelEditFormMattermostFields from "@/components/notification/NotifyChannelEditFormMattermostFields.tsx";
|
||||
|
||||
type NotifyChannelEditFormFieldValues = NotifyChannelsSettingsContent[keyof NotifyChannelsSettingsContent];
|
||||
|
||||
@ -54,6 +55,8 @@ const NotifyChannelEditForm = forwardRef<NotifyChannelEditFormInstance, NotifyCh
|
||||
return <NotifyChannelEditFormGotifyFields />;
|
||||
case NOTIFY_CHANNELS.LARK:
|
||||
return <NotifyChannelEditFormLarkFields />;
|
||||
case NOTIFY_CHANNELS.MATTERMOST:
|
||||
return <NotifyChannelEditFormMattermostFields />;
|
||||
case NOTIFY_CHANNELS.PUSHPLUS:
|
||||
return <NotifyChannelEditFormPushPlusFields />;
|
||||
case NOTIFY_CHANNELS.SERVERCHAN:
|
||||
|
@ -0,0 +1,63 @@
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {Form, Input} from "antd";
|
||||
import {createSchemaFieldRule} from "antd-zod";
|
||||
import {z} from "zod";
|
||||
|
||||
const NotifyChannelEditFormMattermostFields = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const formSchema = z.object({
|
||||
serverUrl: z
|
||||
.string({ message: t("settings.notification.channel.form.mattermost_server_url.placeholder") })
|
||||
.url(t("common.errmsg.url_invalid")),
|
||||
channelId: z
|
||||
.string({ message: t("settings.notification.channel.form.mattermost_channel_id.placeholder") })
|
||||
.nonempty(t("settings.notification.channel.form.mattermost_channel_id.placeholder")),
|
||||
username: z
|
||||
.string({ message: t("settings.notification.channel.form.mattermost_username.placeholder") })
|
||||
.nonempty(t("settings.notification.channel.form.mattermost_username.placeholder")),
|
||||
password: z
|
||||
.string({ message: t("settings.notification.channel.form.mattermost_password.placeholder") })
|
||||
.nonempty(t("settings.notification.channel.form.mattermost_password.placeholder")),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name="serverUrl"
|
||||
label={t("settings.notification.channel.form.mattermost_server_url.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("settings.notification.channel.form.mattermost_server_url.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("settings.notification.channel.form.mattermost_server_url.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="channelId"
|
||||
label={t("settings.notification.channel.form.mattermost_channel_id.label")}
|
||||
rules={[formRule]}
|
||||
>
|
||||
<Input placeholder={t("settings.notification.channel.form.mattermost_channel_id.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="username"
|
||||
label={t("settings.notification.channel.form.mattermost_username.label")}
|
||||
rules={[formRule]}
|
||||
>
|
||||
<Input placeholder={t("settings.notification.channel.form.mattermost_username.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="password"
|
||||
label={t("settings.notification.channel.form.mattermost_password.label")}
|
||||
rules={[formRule]}
|
||||
>
|
||||
<Input.Password placeholder={t("settings.notification.channel.form.mattermost_password.placeholder")} />
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default NotifyChannelEditFormMattermostFields;
|
@ -44,6 +44,7 @@ export const NOTIFY_CHANNELS = Object.freeze({
|
||||
EMAIL: "email",
|
||||
GOTIFY: "gotify",
|
||||
LARK: "lark",
|
||||
MATTERMOST: "mattermost",
|
||||
PUSHPLUS: "pushplus",
|
||||
SERVERCHAN: "serverchan",
|
||||
TELEGRAM: "telegram",
|
||||
@ -64,6 +65,7 @@ export type NotifyChannelsSettingsContent = {
|
||||
[NOTIFY_CHANNELS.EMAIL]?: EmailNotifyChannelConfig;
|
||||
[NOTIFY_CHANNELS.GOTIFY]?: GotifyNotifyChannelConfig;
|
||||
[NOTIFY_CHANNELS.LARK]?: LarkNotifyChannelConfig;
|
||||
[NOTIFY_CHANNELS.MATTERMOST]?: MattermostNotifyChannelConfig;
|
||||
[NOTIFY_CHANNELS.PUSHPLUS]?: PushPlusNotifyChannelConfig;
|
||||
[NOTIFY_CHANNELS.SERVERCHAN]?: ServerChanNotifyChannelConfig;
|
||||
[NOTIFY_CHANNELS.TELEGRAM]?: TelegramNotifyChannelConfig;
|
||||
@ -106,6 +108,14 @@ export type LarkNotifyChannelConfig = {
|
||||
enabled?: boolean;
|
||||
};
|
||||
|
||||
export type MattermostNotifyChannelConfig = {
|
||||
serverUrl: string;
|
||||
channel: string;
|
||||
username: string;
|
||||
password: string;
|
||||
enabled?: boolean;
|
||||
}
|
||||
|
||||
export type PushPlusNotifyChannelConfig = {
|
||||
token: string;
|
||||
enabled?: boolean;
|
||||
@ -143,6 +153,7 @@ export const notifyChannelsMap: Map<NotifyChannel["type"], NotifyChannel> = new
|
||||
[NOTIFY_CHANNELS.DINGTALK, "common.notifier.dingtalk"],
|
||||
[NOTIFY_CHANNELS.GOTIFY, "common.notifier.gotify"],
|
||||
[NOTIFY_CHANNELS.LARK, "common.notifier.lark"],
|
||||
[NOTIFY_CHANNELS.MATTERMOST, "common.notifier.mattermost"],
|
||||
[NOTIFY_CHANNELS.PUSHPLUS, "common.notifier.pushplus"],
|
||||
[NOTIFY_CHANNELS.WECOM, "common.notifier.wecom"],
|
||||
[NOTIFY_CHANNELS.TELEGRAM, "common.notifier.telegram"],
|
||||
|
@ -41,6 +41,7 @@
|
||||
"common.notifier.email": "Email",
|
||||
"common.notifier.gotify": "Gotify",
|
||||
"common.notifier.lark": "Lark",
|
||||
"common.notifier.mattermost": "Mattermost",
|
||||
"common.notifier.pushplus": "PushPlus",
|
||||
"common.notifier.serverchan": "ServerChan",
|
||||
"common.notifier.telegram": "Telegram",
|
||||
|
@ -66,6 +66,15 @@
|
||||
"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.mattermost_server_url.label": "Service URL",
|
||||
"settings.notification.channel.form.mattermost_server_url.placeholder": "Please enter service URL",
|
||||
"settings.notification.channel.form.mattermost_server_url.tooltip": "Example: <b>https://exmaple.com</b>, the protocol needs to be included but the trailing '/' should not be included.",
|
||||
"settings.notification.channel.form.mattermost_channel_id.label": "Channel ID",
|
||||
"settings.notification.channel.form.mattermost_channel_id.placeholder": "Please enter channel ID",
|
||||
"settings.notification.channel.form.mattermost_username.label": "Username",
|
||||
"settings.notification.channel.form.mattermost_username.placeholder": "Please enter username",
|
||||
"settings.notification.channel.form.mattermost_password.label": "Password",
|
||||
"settings.notification.channel.form.mattermost_password.placeholder": "Please enter password",
|
||||
"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>",
|
||||
|
@ -41,6 +41,7 @@
|
||||
"common.notifier.email": "邮件",
|
||||
"common.notifier.gotify": "Gotify",
|
||||
"common.notifier.lark": "飞书",
|
||||
"common.notifier.mattermost": "Mattermost",
|
||||
"common.notifier.pushplus": "PushPlus推送加",
|
||||
"common.notifier.serverchan": "Server 酱",
|
||||
"common.notifier.telegram": "Telegram",
|
||||
|
@ -66,6 +66,15 @@
|
||||
"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.mattermost_server_url.label": "服务地址",
|
||||
"settings.notification.channel.form.mattermost_server_url.placeholder": "请输入服务地址",
|
||||
"settings.notification.channel.form.mattermost_server_url.tooltip": "示例: <b>https://exmaple.com</b>,需要包含协议但不要包含末尾的'/'",
|
||||
"settings.notification.channel.form.mattermost_channel_id.label": "频道ID",
|
||||
"settings.notification.channel.form.mattermost_channel_id.placeholder": "请输入频道ID",
|
||||
"settings.notification.channel.form.mattermost_username.label": "用户名",
|
||||
"settings.notification.channel.form.mattermost_username.placeholder": "请输入用户名",
|
||||
"settings.notification.channel.form.mattermost_password.label": "密码",
|
||||
"settings.notification.channel.form.mattermost_password.placeholder": "请输入密码",
|
||||
"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>",
|
||||
|
Loading…
x
Reference in New Issue
Block a user