mirror of
https://github.com/usual2970/certimate.git
synced 2025-06-07 21:19: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"`
|
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type AccessConfigForSlackBot struct {
|
||||||
|
BotToken string `json:"botToken"`
|
||||||
|
DefaultChannelId string `json:"defaultChannelId,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
type AccessConfigForSSH struct {
|
type AccessConfigForSSH struct {
|
||||||
Host string `json:"host"`
|
Host string `json:"host"`
|
||||||
Port int32 `json:"port"`
|
Port int32 `json:"port"`
|
||||||
|
@ -71,6 +71,7 @@ const (
|
|||||||
AccessProviderTypeRainYun = AccessProviderType("rainyun")
|
AccessProviderTypeRainYun = AccessProviderType("rainyun")
|
||||||
AccessProviderTypeRatPanel = AccessProviderType("ratpanel")
|
AccessProviderTypeRatPanel = AccessProviderType("ratpanel")
|
||||||
AccessProviderTypeSafeLine = AccessProviderType("safeline")
|
AccessProviderTypeSafeLine = AccessProviderType("safeline")
|
||||||
|
AccessProviderTypeSlackBot = AccessProviderType("slackbot")
|
||||||
AccessProviderTypeSSH = AccessProviderType("ssh")
|
AccessProviderTypeSSH = AccessProviderType("ssh")
|
||||||
AccessProviderTypeSSLCOM = AccessProviderType("sslcom")
|
AccessProviderTypeSSLCOM = AccessProviderType("sslcom")
|
||||||
AccessProviderTypeTelegramBot = AccessProviderType("telegrambot")
|
AccessProviderTypeTelegramBot = AccessProviderType("telegrambot")
|
||||||
@ -274,6 +275,7 @@ const (
|
|||||||
NotificationProviderTypeEmail = NotificationProviderType(AccessProviderTypeEmail)
|
NotificationProviderTypeEmail = NotificationProviderType(AccessProviderTypeEmail)
|
||||||
NotificationProviderTypeLarkBot = NotificationProviderType(AccessProviderTypeLarkBot)
|
NotificationProviderTypeLarkBot = NotificationProviderType(AccessProviderTypeLarkBot)
|
||||||
NotificationProviderTypeMattermost = NotificationProviderType(AccessProviderTypeMattermost)
|
NotificationProviderTypeMattermost = NotificationProviderType(AccessProviderTypeMattermost)
|
||||||
|
NotificationProviderTypeSlackBot = NotificationProviderType(AccessProviderTypeSlackBot)
|
||||||
NotificationProviderTypeTelegramBot = NotificationProviderType(AccessProviderTypeTelegramBot)
|
NotificationProviderTypeTelegramBot = NotificationProviderType(AccessProviderTypeTelegramBot)
|
||||||
NotificationProviderTypeWebhook = NotificationProviderType(AccessProviderTypeWebhook)
|
NotificationProviderTypeWebhook = NotificationProviderType(AccessProviderTypeWebhook)
|
||||||
NotificationProviderTypeWeComBot = NotificationProviderType(AccessProviderTypeWeComBot)
|
NotificationProviderTypeWeComBot = NotificationProviderType(AccessProviderTypeWeComBot)
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
pEmail "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/email"
|
pEmail "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/email"
|
||||||
pLarkBot "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/larkbot"
|
pLarkBot "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/larkbot"
|
||||||
pMattermost "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/mattermost"
|
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"
|
pTelegramBot "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/telegrambot"
|
||||||
pWebhook "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/webhook"
|
pWebhook "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/webhook"
|
||||||
pWeComBot "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/wecombot"
|
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:
|
case domain.NotificationProviderTypeTelegramBot:
|
||||||
{
|
{
|
||||||
access := domain.AccessConfigForTelegramBot{}
|
access := domain.AccessConfigForTelegramBot{}
|
||||||
|
@ -58,6 +58,7 @@ func (n *NotifierProvider) Notify(ctx context.Context, subject string, message s
|
|||||||
|
|
||||||
// REF: https://bark.day.app/#/tutorial
|
// REF: https://bark.day.app/#/tutorial
|
||||||
req := n.httpClient.R().
|
req := n.httpClient.R().
|
||||||
|
SetContext(ctx).
|
||||||
SetHeader("Content-Type", "application/json").
|
SetHeader("Content-Type", "application/json").
|
||||||
SetBody(map[string]any{
|
SetBody(map[string]any{
|
||||||
"title": subject,
|
"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) {
|
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
|
// REF: https://discord.com/developers/docs/resources/message#create-message
|
||||||
req := n.httpClient.R().
|
req := n.httpClient.R().
|
||||||
|
SetContext(ctx).
|
||||||
SetHeader("Content-Type", "application/json").
|
SetHeader("Content-Type", "application/json").
|
||||||
SetHeader("Authorization", "Bot "+n.config.BotToken).
|
SetHeader("Authorization", "Bot "+n.config.BotToken).
|
||||||
SetBody(map[string]any{
|
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
|
// REF: https://gotify.net/api-docs#/message/createMessage
|
||||||
req := n.httpClient.R().
|
req := n.httpClient.R().
|
||||||
|
SetContext(ctx).
|
||||||
SetHeader("Content-Type", "application/json").
|
SetHeader("Content-Type", "application/json").
|
||||||
SetHeader("Authorization", "Bearer "+n.config.Token).
|
SetHeader("Authorization", "Bearer "+n.config.Token).
|
||||||
SetBody(map[string]any{
|
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
|
// REF: https://developers.mattermost.com/api-documentation/#/operations/Login
|
||||||
loginReq := n.httpClient.R().
|
loginReq := n.httpClient.R().
|
||||||
|
SetContext(ctx).
|
||||||
SetHeader("Content-Type", "application/json").
|
SetHeader("Content-Type", "application/json").
|
||||||
SetBody(map[string]any{
|
SetBody(map[string]any{
|
||||||
"login_id": n.config.Username,
|
"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
|
// REF: https://developers.mattermost.com/api-documentation/#/operations/CreatePost
|
||||||
postReq := n.httpClient.R().
|
postReq := n.httpClient.R().
|
||||||
|
SetContext(ctx).
|
||||||
SetHeader("Content-Type", "application/json").
|
SetHeader("Content-Type", "application/json").
|
||||||
SetHeader("Authorization", "Bearer "+loginResp.Header().Get("Token")).
|
SetHeader("Authorization", "Bearer "+loginResp.Header().Get("Token")).
|
||||||
SetBody(map[string]any{
|
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) {
|
func (n *NotifierProvider) Notify(ctx context.Context, subject string, message string) (res *notifier.NotifyResult, err error) {
|
||||||
// REF: https://pushover.net/api
|
// REF: https://pushover.net/api
|
||||||
req := n.httpClient.R().
|
req := n.httpClient.R().
|
||||||
|
SetContext(ctx).
|
||||||
SetHeader("Content-Type", "application/json").
|
SetHeader("Content-Type", "application/json").
|
||||||
SetBody(map[string]any{
|
SetBody(map[string]any{
|
||||||
"title": subject,
|
"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) {
|
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
|
// 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().
|
req := n.httpClient.R().
|
||||||
|
SetContext(ctx).
|
||||||
SetHeader("Content-Type", "application/json").
|
SetHeader("Content-Type", "application/json").
|
||||||
SetBody(map[string]any{
|
SetBody(map[string]any{
|
||||||
"title": subject,
|
"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) {
|
func (n *NotifierProvider) Notify(ctx context.Context, subject string, message string) (res *notifier.NotifyResult, err error) {
|
||||||
// REF: https://sct.ftqq.com/
|
// REF: https://sct.ftqq.com/
|
||||||
req := n.httpClient.R().
|
req := n.httpClient.R().
|
||||||
|
SetContext(ctx).
|
||||||
SetHeader("Content-Type", "application/json").
|
SetHeader("Content-Type", "application/json").
|
||||||
SetBody(map[string]any{
|
SetBody(map[string]any{
|
||||||
"text": subject,
|
"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) {
|
func (n *NotifierProvider) Notify(ctx context.Context, subject string, message string) (res *notifier.NotifyResult, err error) {
|
||||||
// REF: https://core.telegram.org/bots/api#sendmessage
|
// REF: https://core.telegram.org/bots/api#sendmessage
|
||||||
req := n.httpClient.R().
|
req := n.httpClient.R().
|
||||||
|
SetContext(ctx).
|
||||||
SetHeader("Content-Type", "application/json").
|
SetHeader("Content-Type", "application/json").
|
||||||
SetBody(map[string]any{
|
SetBody(map[string]any{
|
||||||
"chat_id": n.config.ChatId,
|
"chat_id": n.config.ChatId,
|
||||||
|
@ -139,7 +139,7 @@ func (n *NotifierProvider) Notify(ctx context.Context, subject string, message s
|
|||||||
|
|
||||||
// 生成请求
|
// 生成请求
|
||||||
// 其中 GET 请求需转换为查询参数
|
// 其中 GET 请求需转换为查询参数
|
||||||
req := n.httpClient.R().SetHeaderMultiValues(webhookHeaders)
|
req := n.httpClient.R().SetContext(ctx).SetHeaderMultiValues(webhookHeaders)
|
||||||
req.URL = webhookUrl.String()
|
req.URL = webhookUrl.String()
|
||||||
req.Method = webhookMethod
|
req.Method = webhookMethod
|
||||||
if webhookMethod == http.MethodGet {
|
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) {
|
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
|
// REF: https://developer.work.weixin.qq.com/document/path/91770
|
||||||
req := n.httpClient.R().
|
req := n.httpClient.R().
|
||||||
|
SetContext(ctx).
|
||||||
SetHeader("Content-Type", "application/json").
|
SetHeader("Content-Type", "application/json").
|
||||||
SetBody(map[string]any{
|
SetBody(map[string]any{
|
||||||
"msgtype": "text",
|
"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 AccessFormRainYunConfig from "./AccessFormRainYunConfig";
|
||||||
import AccessFormRatPanelConfig from "./AccessFormRatPanelConfig";
|
import AccessFormRatPanelConfig from "./AccessFormRatPanelConfig";
|
||||||
import AccessFormSafeLineConfig from "./AccessFormSafeLineConfig";
|
import AccessFormSafeLineConfig from "./AccessFormSafeLineConfig";
|
||||||
|
import AccessFormSlackBotConfig from "./AccessFormSlackBotConfig";
|
||||||
import AccessFormSSHConfig from "./AccessFormSSHConfig";
|
import AccessFormSSHConfig from "./AccessFormSSHConfig";
|
||||||
import AccessFormSSLComConfig from "./AccessFormSSLComConfig";
|
import AccessFormSSLComConfig from "./AccessFormSSLComConfig";
|
||||||
import AccessFormTelegramBotConfig from "./AccessFormTelegramBotConfig";
|
import AccessFormTelegramBotConfig from "./AccessFormTelegramBotConfig";
|
||||||
@ -289,6 +290,8 @@ const AccessForm = forwardRef<AccessFormInstance, AccessFormProps>(({ className,
|
|||||||
return <AccessFormRatPanelConfig {...nestedFormProps} />;
|
return <AccessFormRatPanelConfig {...nestedFormProps} />;
|
||||||
case ACCESS_PROVIDERS.SAFELINE:
|
case ACCESS_PROVIDERS.SAFELINE:
|
||||||
return <AccessFormSafeLineConfig {...nestedFormProps} />;
|
return <AccessFormSafeLineConfig {...nestedFormProps} />;
|
||||||
|
case ACCESS_PROVIDERS.SLACKBOT:
|
||||||
|
return <AccessFormSlackBotConfig {...nestedFormProps} />;
|
||||||
case ACCESS_PROVIDERS.SSH:
|
case ACCESS_PROVIDERS.SSH:
|
||||||
return <AccessFormSSHConfig {...nestedFormProps} />;
|
return <AccessFormSSHConfig {...nestedFormProps} />;
|
||||||
case ACCESS_PROVIDERS.TELEGRAMBOT:
|
case ACCESS_PROVIDERS.TELEGRAMBOT:
|
||||||
|
@ -28,7 +28,8 @@ const AccessFormDiscordBotConfig = ({ form: formInst, formName, disabled, initia
|
|||||||
botToken: z
|
botToken: z
|
||||||
.string({ message: t("access.form.discordbot_token.placeholder") })
|
.string({ message: t("access.form.discordbot_token.placeholder") })
|
||||||
.min(1, 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(),
|
defaultChannelId: z.string().nullish(),
|
||||||
});
|
});
|
||||||
const formRule = createSchemaFieldRule(formSchema);
|
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
|
botToken: z
|
||||||
.string({ message: t("access.form.telegrambot_token.placeholder") })
|
.string({ message: t("access.form.telegrambot_token.placeholder") })
|
||||||
.min(1, 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
|
defaultChatId: z
|
||||||
.preprocess(
|
.preprocess(
|
||||||
(v) => (v == null || v === "" ? undefined : Number(v)),
|
(v) => (v == null || v === "" ? undefined : Number(v)),
|
||||||
|
@ -20,6 +20,7 @@ import { useNotifyChannelsStore } from "@/stores/notify";
|
|||||||
import NotifyNodeConfigFormDiscordBotConfig from "./NotifyNodeConfigFormDiscordBotConfig";
|
import NotifyNodeConfigFormDiscordBotConfig from "./NotifyNodeConfigFormDiscordBotConfig";
|
||||||
import NotifyNodeConfigFormEmailConfig from "./NotifyNodeConfigFormEmailConfig";
|
import NotifyNodeConfigFormEmailConfig from "./NotifyNodeConfigFormEmailConfig";
|
||||||
import NotifyNodeConfigFormMattermostConfig from "./NotifyNodeConfigFormMattermostConfig";
|
import NotifyNodeConfigFormMattermostConfig from "./NotifyNodeConfigFormMattermostConfig";
|
||||||
|
import NotifyNodeConfigFormSlackBotConfig from "./NotifyNodeConfigFormSlackBotConfig";
|
||||||
import NotifyNodeConfigFormTelegramBotConfig from "./NotifyNodeConfigFormTelegramBotConfig";
|
import NotifyNodeConfigFormTelegramBotConfig from "./NotifyNodeConfigFormTelegramBotConfig";
|
||||||
import NotifyNodeConfigFormWebhookConfig from "./NotifyNodeConfigFormWebhookConfig";
|
import NotifyNodeConfigFormWebhookConfig from "./NotifyNodeConfigFormWebhookConfig";
|
||||||
|
|
||||||
@ -117,6 +118,8 @@ const NotifyNodeConfigForm = forwardRef<NotifyNodeConfigFormInstance, NotifyNode
|
|||||||
return <NotifyNodeConfigFormEmailConfig {...nestedFormProps} />;
|
return <NotifyNodeConfigFormEmailConfig {...nestedFormProps} />;
|
||||||
case NOTIFICATION_PROVIDERS.MATTERMOST:
|
case NOTIFICATION_PROVIDERS.MATTERMOST:
|
||||||
return <NotifyNodeConfigFormMattermostConfig {...nestedFormProps} />;
|
return <NotifyNodeConfigFormMattermostConfig {...nestedFormProps} />;
|
||||||
|
case NOTIFICATION_PROVIDERS.SLACKBOT:
|
||||||
|
return <NotifyNodeConfigFormSlackBotConfig {...nestedFormProps} />;
|
||||||
case NOTIFICATION_PROVIDERS.TELEGRAMBOT:
|
case NOTIFICATION_PROVIDERS.TELEGRAMBOT:
|
||||||
return <NotifyNodeConfigFormTelegramBotConfig {...nestedFormProps} />;
|
return <NotifyNodeConfigFormTelegramBotConfig {...nestedFormProps} />;
|
||||||
case NOTIFICATION_PROVIDERS.WEBHOOK:
|
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
|
| AccessConfigForRainYun
|
||||||
| AccessConfigForRatPanel
|
| AccessConfigForRatPanel
|
||||||
| AccessConfigForSafeLine
|
| AccessConfigForSafeLine
|
||||||
|
| AccessConfigForSlackBot
|
||||||
| AccessConfigForSSH
|
| AccessConfigForSSH
|
||||||
| AccessConfigForSSLCom
|
| AccessConfigForSSLCom
|
||||||
| AccessConfigForTelegramBot
|
| AccessConfigForTelegramBot
|
||||||
@ -361,6 +362,11 @@ export type AccessConfigForSafeLine = {
|
|||||||
allowInsecureConnections?: boolean;
|
allowInsecureConnections?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type AccessConfigForSlackBot = {
|
||||||
|
botToken: string;
|
||||||
|
defaultChannelId?: string;
|
||||||
|
};
|
||||||
|
|
||||||
export type AccessConfigForSSH = {
|
export type AccessConfigForSSH = {
|
||||||
host: string;
|
host: string;
|
||||||
port: number;
|
port: number;
|
||||||
|
@ -61,6 +61,7 @@ export const ACCESS_PROVIDERS = Object.freeze({
|
|||||||
RAINYUN: "rainyun",
|
RAINYUN: "rainyun",
|
||||||
RATPANEL: "ratpanel",
|
RATPANEL: "ratpanel",
|
||||||
SAFELINE: "safeline",
|
SAFELINE: "safeline",
|
||||||
|
SLACKBOT: "slackbot",
|
||||||
SSH: "ssh",
|
SSH: "ssh",
|
||||||
SSLCOM: "sslcom",
|
SSLCOM: "sslcom",
|
||||||
TELEGRAMBOT: "telegrambot",
|
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.LARKBOT, "provider.larkbot", "/imgs/providers/lark.svg", [ACCESS_USAGES.NOTIFICATION]],
|
||||||
[ACCESS_PROVIDERS.WECOMBOT, "provider.wecombot", "/imgs/providers/wecom.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.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.TELEGRAMBOT, "provider.telegrambot", "/imgs/providers/telegram.svg", [ACCESS_USAGES.NOTIFICATION]],
|
||||||
[ACCESS_PROVIDERS.MATTERMOST, "provider.mattermost", "/imgs/providers/mattermost.svg", [ACCESS_USAGES.NOTIFICATION]],
|
[ACCESS_PROVIDERS.MATTERMOST, "provider.mattermost", "/imgs/providers/mattermost.svg", [ACCESS_USAGES.NOTIFICATION]],
|
||||||
].map((e) => [
|
].map((e) => [
|
||||||
@ -594,6 +596,7 @@ export const NOTIFICATION_PROVIDERS = Object.freeze({
|
|||||||
EMAIL: `${ACCESS_PROVIDERS.EMAIL}`,
|
EMAIL: `${ACCESS_PROVIDERS.EMAIL}`,
|
||||||
LARKBOT: `${ACCESS_PROVIDERS.LARKBOT}`,
|
LARKBOT: `${ACCESS_PROVIDERS.LARKBOT}`,
|
||||||
MATTERMOST: `${ACCESS_PROVIDERS.MATTERMOST}`,
|
MATTERMOST: `${ACCESS_PROVIDERS.MATTERMOST}`,
|
||||||
|
SLACKBOT: `${ACCESS_PROVIDERS.SLACKBOT}`,
|
||||||
TELEGRAMBOT: `${ACCESS_PROVIDERS.TELEGRAMBOT}`,
|
TELEGRAMBOT: `${ACCESS_PROVIDERS.TELEGRAMBOT}`,
|
||||||
WEBHOOK: `${ACCESS_PROVIDERS.WEBHOOK}`,
|
WEBHOOK: `${ACCESS_PROVIDERS.WEBHOOK}`,
|
||||||
WECOMBOT: `${ACCESS_PROVIDERS.WECOMBOT}`,
|
WECOMBOT: `${ACCESS_PROVIDERS.WECOMBOT}`,
|
||||||
@ -620,6 +623,7 @@ export const notificationProvidersMap: Map<NotificationProvider["type"] | string
|
|||||||
[NOTIFICATION_PROVIDERS.LARKBOT],
|
[NOTIFICATION_PROVIDERS.LARKBOT],
|
||||||
[NOTIFICATION_PROVIDERS.WECOMBOT],
|
[NOTIFICATION_PROVIDERS.WECOMBOT],
|
||||||
[NOTIFICATION_PROVIDERS.DISCORDBOT],
|
[NOTIFICATION_PROVIDERS.DISCORDBOT],
|
||||||
|
[NOTIFICATION_PROVIDERS.SLACKBOT],
|
||||||
[NOTIFICATION_PROVIDERS.TELEGRAMBOT],
|
[NOTIFICATION_PROVIDERS.TELEGRAMBOT],
|
||||||
[NOTIFICATION_PROVIDERS.MATTERMOST],
|
[NOTIFICATION_PROVIDERS.MATTERMOST],
|
||||||
].map(([type]) => [
|
].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.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.label": "Discord bot token",
|
||||||
"access.form.discordbot_token.placeholder": "Please enter 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.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.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>",
|
"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.label": "SafeLine API token",
|
||||||
"access.form.safeline_api_token.placeholder": "Please enter 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.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.label": "Server host",
|
||||||
"access.form.ssh_host.placeholder": "Please enter server host",
|
"access.form.ssh_host.placeholder": "Please enter server host",
|
||||||
"access.form.ssh_port.label": "Server port",
|
"access.form.ssh_port.label": "Server port",
|
||||||
|
@ -68,7 +68,7 @@
|
|||||||
"provider.dynv6": "dynv6",
|
"provider.dynv6": "dynv6",
|
||||||
"provider.edgio": "Edgio",
|
"provider.edgio": "Edgio",
|
||||||
"provider.edgio.applications": "Edgio - Applications",
|
"provider.edgio.applications": "Edgio - Applications",
|
||||||
"provider.email": "Email",
|
"provider.email": "Email (SMTP)",
|
||||||
"provider.fastly": "Fastly",
|
"provider.fastly": "Fastly",
|
||||||
"provider.flexcdn": "FlexCDN",
|
"provider.flexcdn": "FlexCDN",
|
||||||
"provider.gcore": "Gcore",
|
"provider.gcore": "Gcore",
|
||||||
@ -96,7 +96,7 @@
|
|||||||
"provider.lecdn": "LeCDN",
|
"provider.lecdn": "LeCDN",
|
||||||
"provider.letsencrypt": "Let's Encrypt",
|
"provider.letsencrypt": "Let's Encrypt",
|
||||||
"provider.letsencryptstaging": "Let's Encrypt Staging Environment",
|
"provider.letsencryptstaging": "Let's Encrypt Staging Environment",
|
||||||
"provider.local": "Local deployment",
|
"provider.local": "Local host",
|
||||||
"provider.mattermost": "Mattermost",
|
"provider.mattermost": "Mattermost",
|
||||||
"provider.namecheap": "Namecheap",
|
"provider.namecheap": "Namecheap",
|
||||||
"provider.namedotcom": "Name.com",
|
"provider.namedotcom": "Name.com",
|
||||||
@ -118,7 +118,8 @@
|
|||||||
"provider.ratpanel.console": "RatPanel - Console",
|
"provider.ratpanel.console": "RatPanel - Console",
|
||||||
"provider.ratpanel.site": "RatPanel - Website",
|
"provider.ratpanel.site": "RatPanel - Website",
|
||||||
"provider.safeline": "SafeLine",
|
"provider.safeline": "SafeLine",
|
||||||
"provider.ssh": "SSH deployment",
|
"provider.slackbot": "Slack Bot",
|
||||||
|
"provider.ssh": "Remote host (SSH)",
|
||||||
"provider.sslcom": "SSL.com",
|
"provider.sslcom": "SSL.com",
|
||||||
"provider.telegrambot": "Telegram Bot",
|
"provider.telegrambot": "Telegram Bot",
|
||||||
"provider.tencentcloud": "Tencent Cloud",
|
"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.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.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.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.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.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.",
|
"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.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.label": "Discord 机器人 API Token",
|
||||||
"access.form.discordbot_token.placeholder": "请输入 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.label": "默认的 Discord 频道 ID(可选)",
|
||||||
"access.form.discordbot_default_channel_id.placeholder": "请输入默认的 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>",
|
"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.label": "雷池 API Token",
|
||||||
"access.form.safeline_api_token.placeholder": "请输入雷池 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.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.label": "服务器地址",
|
||||||
"access.form.ssh_host.placeholder": "请输入服务器地址",
|
"access.form.ssh_host.placeholder": "请输入服务器地址",
|
||||||
"access.form.ssh_port.label": "服务器端口",
|
"access.form.ssh_port.label": "服务器端口",
|
||||||
|
@ -68,7 +68,7 @@
|
|||||||
"provider.dynv6": "dynv6",
|
"provider.dynv6": "dynv6",
|
||||||
"provider.edgio": "Edgio",
|
"provider.edgio": "Edgio",
|
||||||
"provider.edgio.applications": "Edgio - Applications",
|
"provider.edgio.applications": "Edgio - Applications",
|
||||||
"provider.email": "邮件",
|
"provider.email": "邮件(SMTP)",
|
||||||
"provider.fastly": "Fastly",
|
"provider.fastly": "Fastly",
|
||||||
"provider.flexcdn": "FlexCDN",
|
"provider.flexcdn": "FlexCDN",
|
||||||
"provider.gcore": "Gcore",
|
"provider.gcore": "Gcore",
|
||||||
@ -96,7 +96,7 @@
|
|||||||
"provider.lecdn": "LeCDN",
|
"provider.lecdn": "LeCDN",
|
||||||
"provider.letsencrypt": "Let's Encrypt",
|
"provider.letsencrypt": "Let's Encrypt",
|
||||||
"provider.letsencryptstaging": "Let's Encrypt 测试环境",
|
"provider.letsencryptstaging": "Let's Encrypt 测试环境",
|
||||||
"provider.local": "本地部署",
|
"provider.local": "本地主机",
|
||||||
"provider.mattermost": "Mattermost",
|
"provider.mattermost": "Mattermost",
|
||||||
"provider.namecheap": "Namecheap",
|
"provider.namecheap": "Namecheap",
|
||||||
"provider.namedotcom": "Name.com",
|
"provider.namedotcom": "Name.com",
|
||||||
@ -118,7 +118,8 @@
|
|||||||
"provider.ratpanel.console": "耗子面板 - 控制台",
|
"provider.ratpanel.console": "耗子面板 - 控制台",
|
||||||
"provider.ratpanel.site": "耗子面板 - 网站",
|
"provider.ratpanel.site": "耗子面板 - 网站",
|
||||||
"provider.safeline": "雷池",
|
"provider.safeline": "雷池",
|
||||||
"provider.ssh": "SSH 部署",
|
"provider.slackbot": "Slack 机器人",
|
||||||
|
"provider.ssh": "远程主机(SSH)",
|
||||||
"provider.sslcom": "SSL.com",
|
"provider.sslcom": "SSL.com",
|
||||||
"provider.telegrambot": "Telegram 机器人",
|
"provider.telegrambot": "Telegram 机器人",
|
||||||
"provider.tencentcloud": "腾讯云",
|
"provider.tencentcloud": "腾讯云",
|
||||||
|
@ -826,6 +826,9 @@
|
|||||||
"workflow_node.notify.form.mattermost_channel_id.label": "Mattermost 频道 ID(可选)",
|
"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.placeholder": "请输入 Mattermost 频道 ID 以覆盖默认值",
|
||||||
"workflow_node.notify.form.mattermost_channel_id.tooltip": "不填写时,将使用所选通知渠道授权的默认频道 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.label": "Telegram 会话 ID(可选)",
|
||||||
"workflow_node.notify.form.telegrambot_chat_id.placeholder": "请输入 Telegram 会话 ID 以覆盖默认值",
|
"workflow_node.notify.form.telegrambot_chat_id.placeholder": "请输入 Telegram 会话 ID 以覆盖默认值",
|
||||||
"workflow_node.notify.form.telegrambot_chat_id.tooltip": "不填写时,将使用所选通知渠道授权的默认会话 ID。",
|
"workflow_node.notify.form.telegrambot_chat_id.tooltip": "不填写时,将使用所选通知渠道授权的默认会话 ID。",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user