mirror of
https://github.com/usual2970/certimate.git
synced 2025-06-07 13:09:51 +00:00
feat: new notification provider: slack bot
This commit is contained in:
parent
8e23b14bf3
commit
e82a59289b
@ -300,6 +300,11 @@ type AccessConfigForSafeLine struct {
|
||||
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
|
||||
}
|
||||
|
||||
type AccessConfigForSlackBot struct {
|
||||
BotToken string `json:"botToken"`
|
||||
DefaultChannelId string `json:"defaultChannelId,omitempty"`
|
||||
}
|
||||
|
||||
type AccessConfigForSSH struct {
|
||||
Host string `json:"host"`
|
||||
Port int32 `json:"port"`
|
||||
|
@ -71,6 +71,7 @@ const (
|
||||
AccessProviderTypeRainYun = AccessProviderType("rainyun")
|
||||
AccessProviderTypeRatPanel = AccessProviderType("ratpanel")
|
||||
AccessProviderTypeSafeLine = AccessProviderType("safeline")
|
||||
AccessProviderTypeSlackBot = AccessProviderType("slackbot")
|
||||
AccessProviderTypeSSH = AccessProviderType("ssh")
|
||||
AccessProviderTypeSSLCOM = AccessProviderType("sslcom")
|
||||
AccessProviderTypeTelegramBot = AccessProviderType("telegrambot")
|
||||
@ -274,6 +275,7 @@ const (
|
||||
NotificationProviderTypeEmail = NotificationProviderType(AccessProviderTypeEmail)
|
||||
NotificationProviderTypeLarkBot = NotificationProviderType(AccessProviderTypeLarkBot)
|
||||
NotificationProviderTypeMattermost = NotificationProviderType(AccessProviderTypeMattermost)
|
||||
NotificationProviderTypeSlackBot = NotificationProviderType(AccessProviderTypeSlackBot)
|
||||
NotificationProviderTypeTelegramBot = NotificationProviderType(AccessProviderTypeTelegramBot)
|
||||
NotificationProviderTypeWebhook = NotificationProviderType(AccessProviderTypeWebhook)
|
||||
NotificationProviderTypeWeComBot = NotificationProviderType(AccessProviderTypeWeComBot)
|
||||
|
@ -11,6 +11,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"
|
||||
pSlackBot "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/slackbot"
|
||||
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"
|
||||
@ -101,6 +102,19 @@ func createNotifierProvider(options *notifierProviderOptions) (notifier.Notifier
|
||||
})
|
||||
}
|
||||
|
||||
case domain.NotificationProviderTypeSlackBot:
|
||||
{
|
||||
access := domain.AccessConfigForSlackBot{}
|
||||
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||
}
|
||||
|
||||
return pSlackBot.NewNotifier(&pSlackBot.NotifierConfig{
|
||||
BotToken: access.BotToken,
|
||||
ChannelId: maputil.GetOrDefaultString(options.ProviderServiceConfig, "channelId", access.DefaultChannelId),
|
||||
})
|
||||
}
|
||||
|
||||
case domain.NotificationProviderTypeTelegramBot:
|
||||
{
|
||||
access := domain.AccessConfigForTelegramBot{}
|
||||
|
@ -58,6 +58,7 @@ func (n *NotifierProvider) Notify(ctx context.Context, subject string, message s
|
||||
|
||||
// REF: https://bark.day.app/#/tutorial
|
||||
req := n.httpClient.R().
|
||||
SetContext(ctx).
|
||||
SetHeader("Content-Type", "application/json").
|
||||
SetBody(map[string]any{
|
||||
"title": subject,
|
||||
|
@ -51,6 +51,7 @@ 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://discord.com/developers/docs/resources/message#create-message
|
||||
req := n.httpClient.R().
|
||||
SetContext(ctx).
|
||||
SetHeader("Content-Type", "application/json").
|
||||
SetHeader("Authorization", "Bot "+n.config.BotToken).
|
||||
SetBody(map[string]any{
|
||||
|
@ -56,6 +56,7 @@ func (n *NotifierProvider) Notify(ctx context.Context, subject string, message s
|
||||
|
||||
// REF: https://gotify.net/api-docs#/message/createMessage
|
||||
req := n.httpClient.R().
|
||||
SetContext(ctx).
|
||||
SetHeader("Content-Type", "application/json").
|
||||
SetHeader("Authorization", "Bearer "+n.config.Token).
|
||||
SetBody(map[string]any{
|
||||
|
@ -58,6 +58,7 @@ func (n *NotifierProvider) Notify(ctx context.Context, subject string, message s
|
||||
|
||||
// REF: https://developers.mattermost.com/api-documentation/#/operations/Login
|
||||
loginReq := n.httpClient.R().
|
||||
SetContext(ctx).
|
||||
SetHeader("Content-Type", "application/json").
|
||||
SetBody(map[string]any{
|
||||
"login_id": n.config.Username,
|
||||
@ -74,6 +75,7 @@ func (n *NotifierProvider) Notify(ctx context.Context, subject string, message s
|
||||
|
||||
// REF: https://developers.mattermost.com/api-documentation/#/operations/CreatePost
|
||||
postReq := n.httpClient.R().
|
||||
SetContext(ctx).
|
||||
SetHeader("Content-Type", "application/json").
|
||||
SetHeader("Authorization", "Bearer "+loginResp.Header().Get("Token")).
|
||||
SetBody(map[string]any{
|
||||
|
@ -51,6 +51,7 @@ 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
|
||||
req := n.httpClient.R().
|
||||
SetContext(ctx).
|
||||
SetHeader("Content-Type", "application/json").
|
||||
SetBody(map[string]any{
|
||||
"title": subject,
|
||||
|
@ -50,6 +50,7 @@ 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#%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().
|
||||
SetContext(ctx).
|
||||
SetHeader("Content-Type", "application/json").
|
||||
SetBody(map[string]any{
|
||||
"title": subject,
|
||||
|
@ -49,6 +49,7 @@ 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://sct.ftqq.com/
|
||||
req := n.httpClient.R().
|
||||
SetContext(ctx).
|
||||
SetHeader("Content-Type", "application/json").
|
||||
SetBody(map[string]any{
|
||||
"text": subject,
|
||||
|
70
internal/pkg/core/notifier/providers/slackbot/slackbot.go
Normal file
70
internal/pkg/core/notifier/providers/slackbot/slackbot.go
Normal file
@ -0,0 +1,70 @@
|
||||
package discordbot
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
|
||||
"github.com/go-resty/resty/v2"
|
||||
|
||||
"github.com/usual2970/certimate/internal/pkg/core/notifier"
|
||||
)
|
||||
|
||||
type NotifierConfig struct {
|
||||
// Slack Bot API Token。
|
||||
BotToken string `json:"botToken"`
|
||||
// Slack Channel ID。
|
||||
ChannelId string `json:"channelId"`
|
||||
}
|
||||
|
||||
type NotifierProvider struct {
|
||||
config *NotifierConfig
|
||||
logger *slog.Logger
|
||||
httpClient *resty.Client
|
||||
}
|
||||
|
||||
var _ notifier.Notifier = (*NotifierProvider)(nil)
|
||||
|
||||
func NewNotifier(config *NotifierConfig) (*NotifierProvider, error) {
|
||||
if config == nil {
|
||||
panic("config is nil")
|
||||
}
|
||||
|
||||
client := resty.New()
|
||||
|
||||
return &NotifierProvider{
|
||||
config: config,
|
||||
logger: slog.Default(),
|
||||
httpClient: client,
|
||||
}, 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) {
|
||||
// REF: https://docs.slack.dev/messaging/sending-and-scheduling-messages#publishing
|
||||
req := n.httpClient.R().
|
||||
SetContext(ctx).
|
||||
SetHeader("Content-Type", "application/json").
|
||||
SetHeader("Authorization", "Bearer "+n.config.BotToken).
|
||||
SetBody(map[string]any{
|
||||
"token": n.config.BotToken,
|
||||
"channel": n.config.ChannelId,
|
||||
"text": subject + "\n" + message,
|
||||
})
|
||||
resp, err := req.Post("https://slack.com/api/chat.postMessage")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("slack api error: failed to send request: %w", err)
|
||||
} else if resp.IsError() {
|
||||
return nil, fmt.Errorf("slack api error: unexpected status code: %d, resp: %s", resp.StatusCode(), resp.String())
|
||||
}
|
||||
|
||||
return ¬ifier.NotifyResult{}, nil
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
package discordbot_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
provider "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/slackbot"
|
||||
)
|
||||
|
||||
const (
|
||||
mockSubject = "test_subject"
|
||||
mockMessage = "test_message"
|
||||
)
|
||||
|
||||
var (
|
||||
fApiToken string
|
||||
fChannelId string
|
||||
)
|
||||
|
||||
func init() {
|
||||
argsPrefix := "CERTIMATE_NOTIFIER_SLACKBOT_"
|
||||
|
||||
flag.StringVar(&fApiToken, argsPrefix+"APITOKEN", "", "")
|
||||
flag.StringVar(&fChannelId, argsPrefix+"CHANNELID", 0, "")
|
||||
}
|
||||
|
||||
/*
|
||||
Shell command to run this test:
|
||||
|
||||
go test -v ./slackbot_test.go -args \
|
||||
--CERTIMATE_NOTIFIER_SLACKBOT_APITOKEN="your-bot-token" \
|
||||
--CERTIMATE_NOTIFIER_SLACKBOT_CHANNELID="your-channel-id"
|
||||
*/
|
||||
func TestNotify(t *testing.T) {
|
||||
flag.Parse()
|
||||
|
||||
t.Run("Notify", func(t *testing.T) {
|
||||
t.Log(strings.Join([]string{
|
||||
"args:",
|
||||
fmt.Sprintf("APITOKEN: %v", fApiToken),
|
||||
fmt.Sprintf("CHANNELID: %v", fChannelId),
|
||||
}, "\n"))
|
||||
|
||||
notifier, err := provider.NewNotifier(&provider.NotifierConfig{
|
||||
BotToken: fApiToken,
|
||||
ChannelId: fChannelId,
|
||||
})
|
||||
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)
|
||||
})
|
||||
}
|
@ -51,6 +51,7 @@ 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://core.telegram.org/bots/api#sendmessage
|
||||
req := n.httpClient.R().
|
||||
SetContext(ctx).
|
||||
SetHeader("Content-Type", "application/json").
|
||||
SetBody(map[string]any{
|
||||
"chat_id": n.config.ChatId,
|
||||
|
@ -139,7 +139,7 @@ func (n *NotifierProvider) Notify(ctx context.Context, subject string, message s
|
||||
|
||||
// 生成请求
|
||||
// 其中 GET 请求需转换为查询参数
|
||||
req := n.httpClient.R().SetHeaderMultiValues(webhookHeaders)
|
||||
req := n.httpClient.R().SetContext(ctx).SetHeaderMultiValues(webhookHeaders)
|
||||
req.URL = webhookUrl.String()
|
||||
req.Method = webhookMethod
|
||||
if webhookMethod == http.MethodGet {
|
||||
|
@ -49,6 +49,7 @@ 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://developer.work.weixin.qq.com/document/path/91770
|
||||
req := n.httpClient.R().
|
||||
SetContext(ctx).
|
||||
SetHeader("Content-Type", "application/json").
|
||||
SetBody(map[string]any{
|
||||
"msgtype": "text",
|
||||
|
1
ui/public/imgs/providers/slack.svg
Normal file
1
ui/public/imgs/providers/slack.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M244.224 643.84c0 59.221333-45.098667 107.264-100.778667 107.264C87.808 751.104 42.666667 703.061333 42.666667 643.84c0-59.221333 45.141333-107.264 100.778666-107.264h100.778667v107.264zM294.613333 643.84c0-59.306667 45.141333-107.306667 100.821334-107.306667 55.637333 0 100.778667 48.042667 100.778666 107.264v268.288c0 59.264-45.141333 107.306667-100.778666 107.306667-55.68 0-100.821333-48.042667-100.821334-107.306667v-268.288z" fill="#E01E5A"></path><path d="M395.392 214.613333c-55.637333 0-100.778667-48.042667-100.778667-107.306666C294.613333 48.042667 339.754667 0 395.392 0c55.68 0 100.821333 48.042667 100.821333 107.306667V214.613333H395.392zM395.392 268.245333c55.68 0 100.821333 48.085333 100.821333 107.306667 0 59.306667-45.141333 107.306667-100.821333 107.306667H143.445333C87.808 482.858667 42.666667 434.816 42.666667 375.552c0-59.221333 45.141333-107.306667 100.778666-107.306667h251.946667z" fill="#36C5F0"></path><path d="M798.549333 375.552c0-59.221333 45.098667-107.306667 100.778667-107.306667 55.637333 0 100.778667 48.085333 100.778667 107.306667 0 59.306667-45.141333 107.306667-100.778667 107.306667h-100.778667V375.552zM748.16 375.552c0 59.306667-45.141333 107.306667-100.821333 107.306667-55.637333 0-100.778667-48.042667-100.778667-107.306667V107.306667C546.56 48.042667 591.701333 0 647.338667 0c55.68 0 100.821333 48.042667 100.821333 107.306667v268.245333z" fill="#2EB67D"></path><path d="M647.381333 804.778667c55.637333 0 100.778667 48.042667 100.778667 107.306666 0 59.264-45.141333 107.306667-100.778667 107.306667-55.68 0-100.821333-48.042667-100.821333-107.306667v-107.306666h100.821333zM647.381333 751.104c-55.68 0-100.821333-48.042667-100.821333-107.306667 0-59.221333 45.141333-107.306667 100.821333-107.306666h251.904c55.68 0 100.778667 48.085333 100.778667 107.306666 0 59.306667-45.098667 107.306667-100.778667 107.306667h-251.904z" fill="#ECB22E"></path></svg>
|
After Width: | Height: | Size: 2.0 KiB |
@ -64,6 +64,7 @@ import AccessFormQiniuConfig from "./AccessFormQiniuConfig";
|
||||
import AccessFormRainYunConfig from "./AccessFormRainYunConfig";
|
||||
import AccessFormRatPanelConfig from "./AccessFormRatPanelConfig";
|
||||
import AccessFormSafeLineConfig from "./AccessFormSafeLineConfig";
|
||||
import AccessFormSlackBotConfig from "./AccessFormSlackBotConfig";
|
||||
import AccessFormSSHConfig from "./AccessFormSSHConfig";
|
||||
import AccessFormSSLComConfig from "./AccessFormSSLComConfig";
|
||||
import AccessFormTelegramBotConfig from "./AccessFormTelegramBotConfig";
|
||||
@ -289,6 +290,8 @@ const AccessForm = forwardRef<AccessFormInstance, AccessFormProps>(({ className,
|
||||
return <AccessFormRatPanelConfig {...nestedFormProps} />;
|
||||
case ACCESS_PROVIDERS.SAFELINE:
|
||||
return <AccessFormSafeLineConfig {...nestedFormProps} />;
|
||||
case ACCESS_PROVIDERS.SLACKBOT:
|
||||
return <AccessFormSlackBotConfig {...nestedFormProps} />;
|
||||
case ACCESS_PROVIDERS.SSH:
|
||||
return <AccessFormSSHConfig {...nestedFormProps} />;
|
||||
case ACCESS_PROVIDERS.TELEGRAMBOT:
|
||||
|
@ -28,7 +28,8 @@ const AccessFormDiscordBotConfig = ({ form: formInst, formName, disabled, initia
|
||||
botToken: z
|
||||
.string({ message: t("access.form.discordbot_token.placeholder") })
|
||||
.min(1, t("access.form.discordbot_token.placeholder"))
|
||||
.max(256, t("common.errmsg.string_max", { max: 256 })),
|
||||
.max(256, t("common.errmsg.string_max", { max: 256 }))
|
||||
.trim(),
|
||||
defaultChannelId: z.string().nullish(),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
|
71
ui/src/components/access/AccessFormSlackBotConfig.tsx
Normal file
71
ui/src/components/access/AccessFormSlackBotConfig.tsx
Normal file
@ -0,0 +1,71 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Form, type FormInstance, Input } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { type AccessConfigForSlackBot } from "@/domain/access";
|
||||
|
||||
type AccessFormSlackBotConfigFieldValues = Nullish<AccessConfigForSlackBot>;
|
||||
|
||||
export type AccessFormSlackBotConfigProps = {
|
||||
form: FormInstance;
|
||||
formName: string;
|
||||
disabled?: boolean;
|
||||
initialValues?: AccessFormSlackBotConfigFieldValues;
|
||||
onValuesChange?: (values: AccessFormSlackBotConfigFieldValues) => void;
|
||||
};
|
||||
|
||||
const initFormModel = (): AccessFormSlackBotConfigFieldValues => {
|
||||
return {
|
||||
botToken: "",
|
||||
};
|
||||
};
|
||||
|
||||
const AccessFormSlackBotConfig = ({ form: formInst, formName, disabled, initialValues, onValuesChange }: AccessFormSlackBotConfigProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const formSchema = z.object({
|
||||
botToken: z
|
||||
.string({ message: t("access.form.slackbot_token.placeholder") })
|
||||
.min(1, t("access.form.slackbot_token.placeholder"))
|
||||
.max(256, t("common.errmsg.string_max", { max: 256 }))
|
||||
.trim(),
|
||||
defaultChannelId: z.string().nullish(),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
|
||||
const handleFormChange = (_: unknown, values: z.infer<typeof formSchema>) => {
|
||||
onValuesChange?.(values);
|
||||
};
|
||||
|
||||
return (
|
||||
<Form
|
||||
form={formInst}
|
||||
disabled={disabled}
|
||||
initialValues={initialValues ?? initFormModel()}
|
||||
layout="vertical"
|
||||
name={formName}
|
||||
onValuesChange={handleFormChange}
|
||||
>
|
||||
<Form.Item
|
||||
name="botToken"
|
||||
label={t("access.form.slackbot_token.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.slackbot_token.tooltip") }}></span>}
|
||||
>
|
||||
<Input.Password autoComplete="new-password" placeholder={t("access.form.slackbot_token.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="defaultChannelId"
|
||||
label={t("access.form.slackbot_default_channel_id.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.slackbot_default_channel_id.tooltip") }}></span>}
|
||||
>
|
||||
<Input allowClear placeholder={t("access.form.slackbot_default_channel_id.placeholder")} />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default AccessFormSlackBotConfig;
|
@ -28,7 +28,8 @@ const AccessFormTelegramBotConfig = ({ form: formInst, formName, disabled, initi
|
||||
botToken: z
|
||||
.string({ message: t("access.form.telegrambot_token.placeholder") })
|
||||
.min(1, t("access.form.telegrambot_token.placeholder"))
|
||||
.max(256, t("common.errmsg.string_max", { max: 256 })),
|
||||
.max(256, t("common.errmsg.string_max", { max: 256 }))
|
||||
.trim(),
|
||||
defaultChatId: z
|
||||
.preprocess(
|
||||
(v) => (v == null || v === "" ? undefined : Number(v)),
|
||||
|
@ -20,6 +20,7 @@ import { useNotifyChannelsStore } from "@/stores/notify";
|
||||
import NotifyNodeConfigFormDiscordBotConfig from "./NotifyNodeConfigFormDiscordBotConfig";
|
||||
import NotifyNodeConfigFormEmailConfig from "./NotifyNodeConfigFormEmailConfig";
|
||||
import NotifyNodeConfigFormMattermostConfig from "./NotifyNodeConfigFormMattermostConfig";
|
||||
import NotifyNodeConfigFormSlackBotConfig from "./NotifyNodeConfigFormSlackBotConfig";
|
||||
import NotifyNodeConfigFormTelegramBotConfig from "./NotifyNodeConfigFormTelegramBotConfig";
|
||||
import NotifyNodeConfigFormWebhookConfig from "./NotifyNodeConfigFormWebhookConfig";
|
||||
|
||||
@ -117,6 +118,8 @@ const NotifyNodeConfigForm = forwardRef<NotifyNodeConfigFormInstance, NotifyNode
|
||||
return <NotifyNodeConfigFormEmailConfig {...nestedFormProps} />;
|
||||
case NOTIFICATION_PROVIDERS.MATTERMOST:
|
||||
return <NotifyNodeConfigFormMattermostConfig {...nestedFormProps} />;
|
||||
case NOTIFICATION_PROVIDERS.SLACKBOT:
|
||||
return <NotifyNodeConfigFormSlackBotConfig {...nestedFormProps} />;
|
||||
case NOTIFICATION_PROVIDERS.TELEGRAMBOT:
|
||||
return <NotifyNodeConfigFormTelegramBotConfig {...nestedFormProps} />;
|
||||
case NOTIFICATION_PROVIDERS.WEBHOOK:
|
||||
|
@ -0,0 +1,55 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Form, type FormInstance, Input } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
type NotifyNodeConfigFormSlackBotConfigFieldValues = Nullish<{
|
||||
channelId?: string;
|
||||
}>;
|
||||
|
||||
export type NotifyNodeConfigFormSlackBotConfigProps = {
|
||||
form: FormInstance;
|
||||
formName: string;
|
||||
disabled?: boolean;
|
||||
initialValues?: NotifyNodeConfigFormSlackBotConfigFieldValues;
|
||||
onValuesChange?: (values: NotifyNodeConfigFormSlackBotConfigFieldValues) => void;
|
||||
};
|
||||
|
||||
const initFormModel = (): NotifyNodeConfigFormSlackBotConfigFieldValues => {
|
||||
return {};
|
||||
};
|
||||
|
||||
const NotifyNodeConfigFormSlackBotConfig = ({ form: formInst, formName, disabled, initialValues, onValuesChange }: NotifyNodeConfigFormSlackBotConfigProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const formSchema = z.object({
|
||||
channelId: z.string().nullish(),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
|
||||
const handleFormChange = (_: unknown, values: z.infer<typeof formSchema>) => {
|
||||
onValuesChange?.(values);
|
||||
};
|
||||
|
||||
return (
|
||||
<Form
|
||||
form={formInst}
|
||||
disabled={disabled}
|
||||
initialValues={initialValues ?? initFormModel()}
|
||||
layout="vertical"
|
||||
name={formName}
|
||||
onValuesChange={handleFormChange}
|
||||
>
|
||||
<Form.Item
|
||||
name="channelId"
|
||||
label={t("workflow_node.notify.form.slackbot_channel_id.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.notify.form.slackbot_channel_id.tooltip") }}></span>}
|
||||
>
|
||||
<Input allowClear placeholder={t("workflow_node.notify.form.slackbot_channel_id.placeholder")} />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default NotifyNodeConfigFormSlackBotConfig;
|
@ -58,6 +58,7 @@ export interface AccessModel extends BaseModel {
|
||||
| AccessConfigForRainYun
|
||||
| AccessConfigForRatPanel
|
||||
| AccessConfigForSafeLine
|
||||
| AccessConfigForSlackBot
|
||||
| AccessConfigForSSH
|
||||
| AccessConfigForSSLCom
|
||||
| AccessConfigForTelegramBot
|
||||
@ -361,6 +362,11 @@ export type AccessConfigForSafeLine = {
|
||||
allowInsecureConnections?: boolean;
|
||||
};
|
||||
|
||||
export type AccessConfigForSlackBot = {
|
||||
botToken: string;
|
||||
defaultChannelId?: string;
|
||||
};
|
||||
|
||||
export type AccessConfigForSSH = {
|
||||
host: string;
|
||||
port: number;
|
||||
|
@ -61,6 +61,7 @@ export const ACCESS_PROVIDERS = Object.freeze({
|
||||
RAINYUN: "rainyun",
|
||||
RATPANEL: "ratpanel",
|
||||
SAFELINE: "safeline",
|
||||
SLACKBOT: "slackbot",
|
||||
SSH: "ssh",
|
||||
SSLCOM: "sslcom",
|
||||
TELEGRAMBOT: "telegrambot",
|
||||
@ -174,6 +175,7 @@ export const accessProvidersMap: Map<AccessProvider["type"] | string, AccessProv
|
||||
[ACCESS_PROVIDERS.LARKBOT, "provider.larkbot", "/imgs/providers/lark.svg", [ACCESS_USAGES.NOTIFICATION]],
|
||||
[ACCESS_PROVIDERS.WECOMBOT, "provider.wecombot", "/imgs/providers/wecom.svg", [ACCESS_USAGES.NOTIFICATION]],
|
||||
[ACCESS_PROVIDERS.DISCORDBOT, "provider.discordbot", "/imgs/providers/discord.svg", [ACCESS_USAGES.NOTIFICATION]],
|
||||
[ACCESS_PROVIDERS.SLACKBOT, "provider.slackbot", "/imgs/providers/slack.svg", [ACCESS_USAGES.NOTIFICATION]],
|
||||
[ACCESS_PROVIDERS.TELEGRAMBOT, "provider.telegrambot", "/imgs/providers/telegram.svg", [ACCESS_USAGES.NOTIFICATION]],
|
||||
[ACCESS_PROVIDERS.MATTERMOST, "provider.mattermost", "/imgs/providers/mattermost.svg", [ACCESS_USAGES.NOTIFICATION]],
|
||||
].map((e) => [
|
||||
@ -594,6 +596,7 @@ export const NOTIFICATION_PROVIDERS = Object.freeze({
|
||||
EMAIL: `${ACCESS_PROVIDERS.EMAIL}`,
|
||||
LARKBOT: `${ACCESS_PROVIDERS.LARKBOT}`,
|
||||
MATTERMOST: `${ACCESS_PROVIDERS.MATTERMOST}`,
|
||||
SLACKBOT: `${ACCESS_PROVIDERS.SLACKBOT}`,
|
||||
TELEGRAMBOT: `${ACCESS_PROVIDERS.TELEGRAMBOT}`,
|
||||
WEBHOOK: `${ACCESS_PROVIDERS.WEBHOOK}`,
|
||||
WECOMBOT: `${ACCESS_PROVIDERS.WECOMBOT}`,
|
||||
@ -620,6 +623,7 @@ export const notificationProvidersMap: Map<NotificationProvider["type"] | string
|
||||
[NOTIFICATION_PROVIDERS.LARKBOT],
|
||||
[NOTIFICATION_PROVIDERS.WECOMBOT],
|
||||
[NOTIFICATION_PROVIDERS.DISCORDBOT],
|
||||
[NOTIFICATION_PROVIDERS.SLACKBOT],
|
||||
[NOTIFICATION_PROVIDERS.TELEGRAMBOT],
|
||||
[NOTIFICATION_PROVIDERS.MATTERMOST],
|
||||
].map(([type]) => [
|
||||
|
@ -163,7 +163,7 @@
|
||||
"access.form.dingtalkbot_secret.tooltip": "For more information, see <a href=\"https://open.dingtalk.com/document/orgapp/customize-robot-security-settings\" target=\"_blank\">https://open.dingtalk.com/document/orgapp/customize-robot-security-settings</a>",
|
||||
"access.form.discordbot_token.label": "Discord bot token",
|
||||
"access.form.discordbot_token.placeholder": "Please enter Discord bot token",
|
||||
"access.form.discordbot_token.tooltip": "How to get it? Please refer to <a href=\"https://docs.discordbotstudio.org/setting-up-dbs/finding-your-bot-token\" target=\"_blank\">https://docs.discordbotstudio.org/setting-up-dbs/finding-your-bot-token</a>",
|
||||
"access.form.discordbot_token.tooltip": "For more information, see <a href=\"https://docs.discordbotstudio.org/setting-up-dbs/finding-your-bot-token\" target=\"_blank\">https://docs.discordbotstudio.org/setting-up-dbs/finding-your-bot-token</a>",
|
||||
"access.form.discordbot_default_channel_id.label": "Default Discord channel ID (Optional)",
|
||||
"access.form.discordbot_default_channel_id.placeholder": "Please enter default Discord channel ID",
|
||||
"access.form.discordbot_default_channel_id.tooltip": "For more information, see <a href=\"https://support.discord.com/hc/en-us/articles/206346498-Where-can-I-find-my-User-Server-Message-ID\" target=\"_blank\">https://support.discord.com/hc/en-us/articles/206346498-Where-can-I-find-my-User-Server-Message-ID</a>",
|
||||
@ -362,6 +362,12 @@
|
||||
"access.form.safeline_api_token.label": "SafeLine API token",
|
||||
"access.form.safeline_api_token.placeholder": "Please enter SafeLine API token",
|
||||
"access.form.safeline_api_token.tooltip": "For more information, see <a href=\"https://docs.waf.chaitin.com/en/reference/articles/openapi\" target=\"_blank\">https://docs.waf.chaitin.com/en/reference/articles/openapi</a>",
|
||||
"access.form.slackbot_token.label": "Slack bot token",
|
||||
"access.form.slackbot_token.placeholder": "Please enter Slack bot token",
|
||||
"access.form.slackbot_token.tooltip": "For more information, see <a href=\"https://docs.slack.dev/authentication/tokens#bot\" target=\"_blank\">https://docs.slack.dev/authentication/tokens#bot</a>",
|
||||
"access.form.slackbot_default_channel_id.label": "Default Slack channel ID (Optional)",
|
||||
"access.form.slackbot_default_channel_id.placeholder": "Please enter default Slack channel ID",
|
||||
"access.form.slackbot_default_channel_id.tooltip": "How to get it? Please refer to <a href=\"https://www.youtube.com/watch?v=Uz5Yi5C2pwQ\" target=\"_blank\">https://www.youtube.com/watch?v=Uz5Yi5C2pwQ</a>",
|
||||
"access.form.ssh_host.label": "Server host",
|
||||
"access.form.ssh_host.placeholder": "Please enter server host",
|
||||
"access.form.ssh_port.label": "Server port",
|
||||
|
@ -68,7 +68,7 @@
|
||||
"provider.dynv6": "dynv6",
|
||||
"provider.edgio": "Edgio",
|
||||
"provider.edgio.applications": "Edgio - Applications",
|
||||
"provider.email": "Email",
|
||||
"provider.email": "Email (SMTP)",
|
||||
"provider.fastly": "Fastly",
|
||||
"provider.flexcdn": "FlexCDN",
|
||||
"provider.gcore": "Gcore",
|
||||
@ -96,7 +96,7 @@
|
||||
"provider.lecdn": "LeCDN",
|
||||
"provider.letsencrypt": "Let's Encrypt",
|
||||
"provider.letsencryptstaging": "Let's Encrypt Staging Environment",
|
||||
"provider.local": "Local deployment",
|
||||
"provider.local": "Local host",
|
||||
"provider.mattermost": "Mattermost",
|
||||
"provider.namecheap": "Namecheap",
|
||||
"provider.namedotcom": "Name.com",
|
||||
@ -118,7 +118,8 @@
|
||||
"provider.ratpanel.console": "RatPanel - Console",
|
||||
"provider.ratpanel.site": "RatPanel - Website",
|
||||
"provider.safeline": "SafeLine",
|
||||
"provider.ssh": "SSH deployment",
|
||||
"provider.slackbot": "Slack Bot",
|
||||
"provider.ssh": "Remote host (SSH)",
|
||||
"provider.sslcom": "SSL.com",
|
||||
"provider.telegrambot": "Telegram Bot",
|
||||
"provider.tencentcloud": "Tencent Cloud",
|
||||
|
@ -827,6 +827,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.slackbot_channel_id.label": "Slack channel ID (Optional)",
|
||||
"workflow_node.notify.form.slackbot_channel_id.placeholder": "Please enter Slack channel ID to override the default value",
|
||||
"workflow_node.notify.form.slackbot_channel_id.tooltip": "Leave it blank to use the default channel ID provided by the authorization.",
|
||||
"workflow_node.notify.form.telegrambot_chat_id.label": "Telegram chat ID (Optional)",
|
||||
"workflow_node.notify.form.telegrambot_chat_id.placeholder": "Please enter Telegram chat ID to override the default value",
|
||||
"workflow_node.notify.form.telegrambot_chat_id.tooltip": "Leave it blank to use the default chat ID provided by the selected authorization.",
|
||||
|
@ -157,7 +157,7 @@
|
||||
"access.form.dingtalkbot_secret.tooltip": "这是什么?请参阅 <a href=\"https://open.dingtalk.com/document/orgapp/customize-robot-security-settings\" target=\"_blank\">https://open.dingtalk.com/document/orgapp/customize-robot-security-settings</a>",
|
||||
"access.form.discordbot_token.label": "Discord 机器人 API Token",
|
||||
"access.form.discordbot_token.placeholder": "请输入 Discord 机器人 API Token",
|
||||
"access.form.discordbot_token.tooltip": "如何获取此参数?请参阅 <a href=\"https://docs.discordbotstudio.org/setting-up-dbs/finding-your-bot-token\" target=\"_blank\">https://docs.discordbotstudio.org/setting-up-dbs/finding-your-bot-token</a>",
|
||||
"access.form.discordbot_token.tooltip": "这是什么?请参阅 <a href=\"https://docs.discordbotstudio.org/setting-up-dbs/finding-your-bot-token\" target=\"_blank\">https://docs.discordbotstudio.org/setting-up-dbs/finding-your-bot-token</a>",
|
||||
"access.form.discordbot_default_channel_id.label": "默认的 Discord 频道 ID(可选)",
|
||||
"access.form.discordbot_default_channel_id.placeholder": "请输入默认的 Discord 频道 ID",
|
||||
"access.form.discordbot_default_channel_id.tooltip": "这是什么?请参阅 <a href=\"https://support.discord.com/hc/en-us/articles/206346498-Where-can-I-find-my-User-Server-Message-ID\" target=\"_blank\">https://support.discord.com/hc/en-us/articles/206346498-Where-can-I-find-my-User-Server-Message-ID</a>",
|
||||
@ -356,6 +356,12 @@
|
||||
"access.form.safeline_api_token.label": "雷池 API Token",
|
||||
"access.form.safeline_api_token.placeholder": "请输入雷池 API Token",
|
||||
"access.form.safeline_api_token.tooltip": "这是什么?请参阅 <a href=\"https://docs.waf-ce.chaitin.cn/zh/%E6%9B%B4%E5%A4%9A%E6%8A%80%E6%9C%AF%E6%96%87%E6%A1%A3/OPENAPI\" target=\"_blank\">https://docs.waf-ce.chaitin.cn/zh/更多技术文档/OPENAPI</a>",
|
||||
"access.form.slackbot_token.label": "Slack 机器人 Token",
|
||||
"access.form.slackbot_token.placeholder": "请输入 Slack 机器人 Token",
|
||||
"access.form.slackbot_token.tooltip": "这是什么?请参阅 <a href=\"https://docs.slack.dev/authentication/tokens#bot\" target=\"_blank\">https://docs.slack.dev/authentication/tokens#bot</a>",
|
||||
"access.form.slackbot_default_channel_id.label": "默认的 Slack 频道 ID(可选)",
|
||||
"access.form.slackbot_default_channel_id.placeholder": "请输入默认的 Slack 频道 ID",
|
||||
"access.form.slackbot_default_channel_id.tooltip": "如何获取此参数?请参阅 <a href=\"https://www.youtube.com/watch?v=Uz5Yi5C2pwQ\" target=\"_blank\">https://www.youtube.com/watch?v=Uz5Yi5C2pwQ</a>",
|
||||
"access.form.ssh_host.label": "服务器地址",
|
||||
"access.form.ssh_host.placeholder": "请输入服务器地址",
|
||||
"access.form.ssh_port.label": "服务器端口",
|
||||
|
@ -68,7 +68,7 @@
|
||||
"provider.dynv6": "dynv6",
|
||||
"provider.edgio": "Edgio",
|
||||
"provider.edgio.applications": "Edgio - Applications",
|
||||
"provider.email": "邮件",
|
||||
"provider.email": "邮件(SMTP)",
|
||||
"provider.fastly": "Fastly",
|
||||
"provider.flexcdn": "FlexCDN",
|
||||
"provider.gcore": "Gcore",
|
||||
@ -96,7 +96,7 @@
|
||||
"provider.lecdn": "LeCDN",
|
||||
"provider.letsencrypt": "Let's Encrypt",
|
||||
"provider.letsencryptstaging": "Let's Encrypt 测试环境",
|
||||
"provider.local": "本地部署",
|
||||
"provider.local": "本地主机",
|
||||
"provider.mattermost": "Mattermost",
|
||||
"provider.namecheap": "Namecheap",
|
||||
"provider.namedotcom": "Name.com",
|
||||
@ -118,7 +118,8 @@
|
||||
"provider.ratpanel.console": "耗子面板 - 控制台",
|
||||
"provider.ratpanel.site": "耗子面板 - 网站",
|
||||
"provider.safeline": "雷池",
|
||||
"provider.ssh": "SSH 部署",
|
||||
"provider.slackbot": "Slack 机器人",
|
||||
"provider.ssh": "远程主机(SSH)",
|
||||
"provider.sslcom": "SSL.com",
|
||||
"provider.telegrambot": "Telegram 机器人",
|
||||
"provider.tencentcloud": "腾讯云",
|
||||
|
@ -826,6 +826,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.slackbot_channel_id.label": "Slack 频道 ID(可选)",
|
||||
"workflow_node.notify.form.slackbot_channel_id.placeholder": "请输入 Slack 频道 ID 以覆盖默认值",
|
||||
"workflow_node.notify.form.slackbot_channel_id.tooltip": "不填写时,将使用所选通知渠道授权的默认频道 ID。",
|
||||
"workflow_node.notify.form.telegrambot_chat_id.label": "Telegram 会话 ID(可选)",
|
||||
"workflow_node.notify.form.telegrambot_chat_id.placeholder": "请输入 Telegram 会话 ID 以覆盖默认值",
|
||||
"workflow_node.notify.form.telegrambot_chat_id.tooltip": "不填写时,将使用所选通知渠道授权的默认会话 ID。",
|
||||
|
Loading…
x
Reference in New Issue
Block a user