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。",