diff --git a/internal/domain/access.go b/internal/domain/access.go index 4e002ecf..482f753a 100644 --- a/internal/domain/access.go +++ b/internal/domain/access.go @@ -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"` diff --git a/internal/domain/provider.go b/internal/domain/provider.go index 8f5c959a..c8cb37d5 100644 --- a/internal/domain/provider.go +++ b/internal/domain/provider.go @@ -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) diff --git a/internal/notify/providers.go b/internal/notify/providers.go index 23f5bb43..7dc63465 100644 --- a/internal/notify/providers.go +++ b/internal/notify/providers.go @@ -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{} diff --git a/internal/pkg/core/notifier/providers/bark/bark.go b/internal/pkg/core/notifier/providers/bark/bark.go index 97ece0be..ec0d44f3 100644 --- a/internal/pkg/core/notifier/providers/bark/bark.go +++ b/internal/pkg/core/notifier/providers/bark/bark.go @@ -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, diff --git a/internal/pkg/core/notifier/providers/discordbot/discordbot.go b/internal/pkg/core/notifier/providers/discordbot/discordbot.go index dbffaba7..3ed0cab7 100644 --- a/internal/pkg/core/notifier/providers/discordbot/discordbot.go +++ b/internal/pkg/core/notifier/providers/discordbot/discordbot.go @@ -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{ diff --git a/internal/pkg/core/notifier/providers/gotify/gotify.go b/internal/pkg/core/notifier/providers/gotify/gotify.go index 81dcb8ad..c82cd5a5 100644 --- a/internal/pkg/core/notifier/providers/gotify/gotify.go +++ b/internal/pkg/core/notifier/providers/gotify/gotify.go @@ -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{ diff --git a/internal/pkg/core/notifier/providers/mattermost/mattermost.go b/internal/pkg/core/notifier/providers/mattermost/mattermost.go index 8e4fb24d..81283f7c 100644 --- a/internal/pkg/core/notifier/providers/mattermost/mattermost.go +++ b/internal/pkg/core/notifier/providers/mattermost/mattermost.go @@ -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{ diff --git a/internal/pkg/core/notifier/providers/pushover/pushover.go b/internal/pkg/core/notifier/providers/pushover/pushover.go index b7f74bba..827a45d6 100644 --- a/internal/pkg/core/notifier/providers/pushover/pushover.go +++ b/internal/pkg/core/notifier/providers/pushover/pushover.go @@ -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, diff --git a/internal/pkg/core/notifier/providers/pushplus/pushplus.go b/internal/pkg/core/notifier/providers/pushplus/pushplus.go index 834f9683..79a27d49 100644 --- a/internal/pkg/core/notifier/providers/pushplus/pushplus.go +++ b/internal/pkg/core/notifier/providers/pushplus/pushplus.go @@ -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, diff --git a/internal/pkg/core/notifier/providers/serverchan/serverchan.go b/internal/pkg/core/notifier/providers/serverchan/serverchan.go index d74b2fcc..d1897ab4 100644 --- a/internal/pkg/core/notifier/providers/serverchan/serverchan.go +++ b/internal/pkg/core/notifier/providers/serverchan/serverchan.go @@ -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, diff --git a/internal/pkg/core/notifier/providers/slackbot/slackbot.go b/internal/pkg/core/notifier/providers/slackbot/slackbot.go new file mode 100644 index 00000000..7b16ad25 --- /dev/null +++ b/internal/pkg/core/notifier/providers/slackbot/slackbot.go @@ -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 +} diff --git a/internal/pkg/core/notifier/providers/slackbot/slackbot_test.go b/internal/pkg/core/notifier/providers/slackbot/slackbot_test.go new file mode 100644 index 00000000..356ef71f --- /dev/null +++ b/internal/pkg/core/notifier/providers/slackbot/slackbot_test.go @@ -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) + }) +} diff --git a/internal/pkg/core/notifier/providers/telegrambot/telegrambot.go b/internal/pkg/core/notifier/providers/telegrambot/telegrambot.go index 99b86a38..39e1f705 100644 --- a/internal/pkg/core/notifier/providers/telegrambot/telegrambot.go +++ b/internal/pkg/core/notifier/providers/telegrambot/telegrambot.go @@ -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, diff --git a/internal/pkg/core/notifier/providers/webhook/webhook.go b/internal/pkg/core/notifier/providers/webhook/webhook.go index 5f62f170..8850ea73 100644 --- a/internal/pkg/core/notifier/providers/webhook/webhook.go +++ b/internal/pkg/core/notifier/providers/webhook/webhook.go @@ -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 { diff --git a/internal/pkg/core/notifier/providers/wecombot/wecombot.go b/internal/pkg/core/notifier/providers/wecombot/wecombot.go index 36c179d4..8f51a70a 100644 --- a/internal/pkg/core/notifier/providers/wecombot/wecombot.go +++ b/internal/pkg/core/notifier/providers/wecombot/wecombot.go @@ -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", diff --git a/ui/public/imgs/providers/slack.svg b/ui/public/imgs/providers/slack.svg new file mode 100644 index 00000000..100af3d4 --- /dev/null +++ b/ui/public/imgs/providers/slack.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ui/src/components/access/AccessForm.tsx b/ui/src/components/access/AccessForm.tsx index 2a28aaac..c8c03290 100644 --- a/ui/src/components/access/AccessForm.tsx +++ b/ui/src/components/access/AccessForm.tsx @@ -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(({ className, return ; case ACCESS_PROVIDERS.SAFELINE: return ; + case ACCESS_PROVIDERS.SLACKBOT: + return ; case ACCESS_PROVIDERS.SSH: return ; case ACCESS_PROVIDERS.TELEGRAMBOT: diff --git a/ui/src/components/access/AccessFormDiscordBotConfig.tsx b/ui/src/components/access/AccessFormDiscordBotConfig.tsx index 5f844ccc..16848686 100644 --- a/ui/src/components/access/AccessFormDiscordBotConfig.tsx +++ b/ui/src/components/access/AccessFormDiscordBotConfig.tsx @@ -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); diff --git a/ui/src/components/access/AccessFormSlackBotConfig.tsx b/ui/src/components/access/AccessFormSlackBotConfig.tsx new file mode 100644 index 00000000..3bea5f58 --- /dev/null +++ b/ui/src/components/access/AccessFormSlackBotConfig.tsx @@ -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; + +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) => { + onValuesChange?.(values); + }; + + return ( +
+ } + > + + + + } + > + + +
+ ); +}; + +export default AccessFormSlackBotConfig; diff --git a/ui/src/components/access/AccessFormTelegramBotConfig.tsx b/ui/src/components/access/AccessFormTelegramBotConfig.tsx index a347610f..82747694 100644 --- a/ui/src/components/access/AccessFormTelegramBotConfig.tsx +++ b/ui/src/components/access/AccessFormTelegramBotConfig.tsx @@ -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)), diff --git a/ui/src/components/workflow/node/NotifyNodeConfigForm.tsx b/ui/src/components/workflow/node/NotifyNodeConfigForm.tsx index 44a4a604..3c612df8 100644 --- a/ui/src/components/workflow/node/NotifyNodeConfigForm.tsx +++ b/ui/src/components/workflow/node/NotifyNodeConfigForm.tsx @@ -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; case NOTIFICATION_PROVIDERS.MATTERMOST: return ; + case NOTIFICATION_PROVIDERS.SLACKBOT: + return ; case NOTIFICATION_PROVIDERS.TELEGRAMBOT: return ; case NOTIFICATION_PROVIDERS.WEBHOOK: diff --git a/ui/src/components/workflow/node/NotifyNodeConfigFormSlackBotConfig.tsx b/ui/src/components/workflow/node/NotifyNodeConfigFormSlackBotConfig.tsx new file mode 100644 index 00000000..5c304060 --- /dev/null +++ b/ui/src/components/workflow/node/NotifyNodeConfigFormSlackBotConfig.tsx @@ -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) => { + onValuesChange?.(values); + }; + + return ( +
+ } + > + + +
+ ); +}; + +export default NotifyNodeConfigFormSlackBotConfig; diff --git a/ui/src/domain/access.ts b/ui/src/domain/access.ts index 9e953963..3582b071 100644 --- a/ui/src/domain/access.ts +++ b/ui/src/domain/access.ts @@ -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; diff --git a/ui/src/domain/provider.ts b/ui/src/domain/provider.ts index 806c8283..2d288a3c 100644 --- a/ui/src/domain/provider.ts +++ b/ui/src/domain/provider.ts @@ -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 [ @@ -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 [ diff --git a/ui/src/i18n/locales/en/nls.access.json b/ui/src/i18n/locales/en/nls.access.json index fe437f87..98717976 100644 --- a/ui/src/i18n/locales/en/nls.access.json +++ b/ui/src/i18n/locales/en/nls.access.json @@ -163,7 +163,7 @@ "access.form.dingtalkbot_secret.tooltip": "For more information, see https://open.dingtalk.com/document/orgapp/customize-robot-security-settings", "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 https://docs.discordbotstudio.org/setting-up-dbs/finding-your-bot-token", + "access.form.discordbot_token.tooltip": "For more information, see https://docs.discordbotstudio.org/setting-up-dbs/finding-your-bot-token", "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 https://support.discord.com/hc/en-us/articles/206346498-Where-can-I-find-my-User-Server-Message-ID", @@ -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 https://docs.waf.chaitin.com/en/reference/articles/openapi", + "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 https://docs.slack.dev/authentication/tokens#bot", + "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 https://www.youtube.com/watch?v=Uz5Yi5C2pwQ", "access.form.ssh_host.label": "Server host", "access.form.ssh_host.placeholder": "Please enter server host", "access.form.ssh_port.label": "Server port", diff --git a/ui/src/i18n/locales/en/nls.provider.json b/ui/src/i18n/locales/en/nls.provider.json index b34c92a7..85966786 100644 --- a/ui/src/i18n/locales/en/nls.provider.json +++ b/ui/src/i18n/locales/en/nls.provider.json @@ -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", diff --git a/ui/src/i18n/locales/en/nls.workflow.nodes.json b/ui/src/i18n/locales/en/nls.workflow.nodes.json index 172d707b..92989ac2 100644 --- a/ui/src/i18n/locales/en/nls.workflow.nodes.json +++ b/ui/src/i18n/locales/en/nls.workflow.nodes.json @@ -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.", diff --git a/ui/src/i18n/locales/zh/nls.access.json b/ui/src/i18n/locales/zh/nls.access.json index 21ad79c5..7e184d55 100644 --- a/ui/src/i18n/locales/zh/nls.access.json +++ b/ui/src/i18n/locales/zh/nls.access.json @@ -157,7 +157,7 @@ "access.form.dingtalkbot_secret.tooltip": "这是什么?请参阅 https://open.dingtalk.com/document/orgapp/customize-robot-security-settings", "access.form.discordbot_token.label": "Discord 机器人 API Token", "access.form.discordbot_token.placeholder": "请输入 Discord 机器人 API Token", - "access.form.discordbot_token.tooltip": "如何获取此参数?请参阅 https://docs.discordbotstudio.org/setting-up-dbs/finding-your-bot-token", + "access.form.discordbot_token.tooltip": "这是什么?请参阅 https://docs.discordbotstudio.org/setting-up-dbs/finding-your-bot-token", "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": "这是什么?请参阅 https://support.discord.com/hc/en-us/articles/206346498-Where-can-I-find-my-User-Server-Message-ID", @@ -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": "这是什么?请参阅 https://docs.waf-ce.chaitin.cn/zh/更多技术文档/OPENAPI", + "access.form.slackbot_token.label": "Slack 机器人 Token", + "access.form.slackbot_token.placeholder": "请输入 Slack 机器人 Token", + "access.form.slackbot_token.tooltip": "这是什么?请参阅 https://docs.slack.dev/authentication/tokens#bot", + "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": "如何获取此参数?请参阅 https://www.youtube.com/watch?v=Uz5Yi5C2pwQ", "access.form.ssh_host.label": "服务器地址", "access.form.ssh_host.placeholder": "请输入服务器地址", "access.form.ssh_port.label": "服务器端口", diff --git a/ui/src/i18n/locales/zh/nls.provider.json b/ui/src/i18n/locales/zh/nls.provider.json index dd12aa27..c4e126e0 100644 --- a/ui/src/i18n/locales/zh/nls.provider.json +++ b/ui/src/i18n/locales/zh/nls.provider.json @@ -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": "腾讯云", diff --git a/ui/src/i18n/locales/zh/nls.workflow.nodes.json b/ui/src/i18n/locales/zh/nls.workflow.nodes.json index b6d27dc7..87f0076b 100644 --- a/ui/src/i18n/locales/zh/nls.workflow.nodes.json +++ b/ui/src/i18n/locales/zh/nls.workflow.nodes.json @@ -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。",