mirror of
https://github.com/certimate-go/certimate.git
synced 2026-09-24 23:10:13 +08:00
feat: drop deprecated notify service
This commit is contained in:
@@ -6,7 +6,6 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -16,16 +15,9 @@ import (
|
||||
"github.com/certimate-go/certimate/internal/app"
|
||||
"github.com/certimate-go/certimate/internal/domain"
|
||||
"github.com/certimate-go/certimate/internal/domain/dtos"
|
||||
"github.com/certimate-go/certimate/internal/notify"
|
||||
"github.com/certimate-go/certimate/internal/repository"
|
||||
xcert "github.com/certimate-go/certimate/pkg/utils/cert"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultExpireSubject = "有 ${COUNT} 张证书即将过期"
|
||||
defaultExpireMessage = "有 ${COUNT} 张证书即将过期,域名分别为 ${DOMAINS},请保持关注!"
|
||||
)
|
||||
|
||||
type certificateRepository interface {
|
||||
ListExpireSoon(ctx context.Context) ([]*domain.Certificate, error)
|
||||
GetById(ctx context.Context, id string) (*domain.Certificate, error)
|
||||
@@ -49,24 +41,6 @@ func NewCertificateService(certificateRepo certificateRepository, settingsRepo s
|
||||
}
|
||||
|
||||
func (s *CertificateService) InitSchedule(ctx context.Context) error {
|
||||
// 每日发送过期证书提醒
|
||||
app.GetScheduler().MustAdd("certificateExpireSoonNotify", "0 0 * * *", func() {
|
||||
certificates, err := s.certificateRepo.ListExpireSoon(context.Background())
|
||||
if err != nil {
|
||||
app.GetLogger().Error("failed to get certificates which expire soon", "err", err)
|
||||
return
|
||||
}
|
||||
|
||||
notification := buildExpireSoonNotification(certificates)
|
||||
if notification == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := notify.SendToAllChannels(notification.Subject, notification.Message); err != nil {
|
||||
app.GetLogger().Error("failed to send notification", "err", err)
|
||||
}
|
||||
})
|
||||
|
||||
// 每日清理过期证书
|
||||
app.GetScheduler().MustAdd("certificateExpiredCleanup", "0 0 * * *", func() {
|
||||
settings, err := s.settingsRepo.GetByName(ctx, "persistence")
|
||||
@@ -75,7 +49,7 @@ func (s *CertificateService) InitSchedule(ctx context.Context) error {
|
||||
return
|
||||
}
|
||||
|
||||
var settingsContent *domain.PersistenceSettingsContent
|
||||
var settingsContent *domain.SettingsContentAsPersistence
|
||||
json.Unmarshal([]byte(settings.Content), &settingsContent)
|
||||
if settingsContent != nil && settingsContent.ExpiredCertificatesMaxDaysRetention != 0 {
|
||||
ret, err := s.certificateRepo.DeleteWhere(
|
||||
@@ -95,7 +69,7 @@ func (s *CertificateService) InitSchedule(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *CertificateService) ArchiveFile(ctx context.Context, req *dtos.CertificateArchiveFileReq) (*dtos.CertificateArchiveFileResp, error) {
|
||||
func (s *CertificateService) DownloadArchivedFile(ctx context.Context, req *dtos.CertificateArchiveFileReq) (*dtos.CertificateArchiveFileResp, error) {
|
||||
certificate, err := s.certificateRepo.GetById(ctx, req.CertificateId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -246,47 +220,3 @@ func (s *CertificateService) ValidatePrivateKey(ctx context.Context, req *dtos.C
|
||||
IsValid: true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func buildExpireSoonNotification(certificates []*domain.Certificate) *struct {
|
||||
Subject string
|
||||
Message string
|
||||
} {
|
||||
if len(certificates) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
subject := defaultExpireSubject
|
||||
message := defaultExpireMessage
|
||||
|
||||
// 查询模板信息
|
||||
settingsRepo := repository.NewSettingsRepository()
|
||||
settings, err := settingsRepo.GetByName(context.Background(), "notifyTemplates")
|
||||
if err == nil {
|
||||
var templates *domain.NotifyTemplatesSettingsContent
|
||||
json.Unmarshal([]byte(settings.Content), &templates)
|
||||
|
||||
if templates != nil && len(templates.NotifyTemplates) > 0 {
|
||||
subject = templates.NotifyTemplates[0].Subject
|
||||
message = templates.NotifyTemplates[0].Message
|
||||
}
|
||||
}
|
||||
|
||||
// 替换变量
|
||||
count := len(certificates)
|
||||
domains := make([]string, count)
|
||||
for i, record := range certificates {
|
||||
domains[i] = record.SubjectAltNames
|
||||
}
|
||||
countStr := strconv.Itoa(count)
|
||||
domainStr := strings.Join(domains, ";")
|
||||
subject = strings.ReplaceAll(subject, "${COUNT}", countStr)
|
||||
subject = strings.ReplaceAll(subject, "${DOMAINS}", domainStr)
|
||||
message = strings.ReplaceAll(message, "${COUNT}", countStr)
|
||||
message = strings.ReplaceAll(message, "${DOMAINS}", domainStr)
|
||||
|
||||
// 返回消息
|
||||
return &struct {
|
||||
Subject string
|
||||
Message string
|
||||
}{Subject: subject, Message: message}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package dtos
|
||||
|
||||
import "github.com/certimate-go/certimate/internal/domain"
|
||||
|
||||
type NotifyTestPushReq struct {
|
||||
Channel domain.NotifyChannelType `json:"channel"`
|
||||
Provider string `json:"provider"`
|
||||
}
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
package domain
|
||||
|
||||
type NotifyChannelType string
|
||||
|
||||
/*
|
||||
消息通知渠道常量值。
|
||||
|
||||
注意:如果追加新的常量值,请保持以 ASCII 排序。
|
||||
NOTICE: If you add new constant, please keep ASCII order.
|
||||
*/
|
||||
// Deprecated: v0.4.x 将废弃
|
||||
const (
|
||||
NotifyChannelTypeBark = NotifyChannelType("bark")
|
||||
NotifyChannelTypeDingTalk = NotifyChannelType("dingtalk")
|
||||
NotifyChannelTypeEmail = NotifyChannelType("email")
|
||||
NotifyChannelTypeGotify = NotifyChannelType("gotify")
|
||||
NotifyChannelTypeLark = NotifyChannelType("lark")
|
||||
NotifyChannelTypeMattermost = NotifyChannelType("mattermost")
|
||||
NotifyChannelTypePushover = NotifyChannelType("pushover")
|
||||
NotifyChannelTypePushPlus = NotifyChannelType("pushplus")
|
||||
NotifyChannelTypeServerChan = NotifyChannelType("serverchan")
|
||||
NotifyChannelTypeTelegram = NotifyChannelType("telegram")
|
||||
NotifyChannelTypeWebhook = NotifyChannelType("webhook")
|
||||
NotifyChannelTypeWeCom = NotifyChannelType("wecom")
|
||||
)
|
||||
@@ -1,10 +1,5 @@
|
||||
package domain
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
const CollectionNameSettings = "settings"
|
||||
|
||||
type Settings struct {
|
||||
@@ -13,33 +8,7 @@ type Settings struct {
|
||||
Content string `json:"content" db:"content"`
|
||||
}
|
||||
|
||||
// Deprecated: v0.4.x 将废弃
|
||||
type NotifyTemplatesSettingsContent struct {
|
||||
NotifyTemplates []struct {
|
||||
Subject string `json:"subject"`
|
||||
Message string `json:"message"`
|
||||
} `json:"notifyTemplates"`
|
||||
}
|
||||
|
||||
// Deprecated: v0.4.x 将废弃
|
||||
type NotifyChannelsSettingsContent map[string]map[string]any
|
||||
|
||||
// Deprecated: v0.4.x 将废弃
|
||||
func (s *Settings) GetNotifyChannelConfig(channel string) (map[string]any, error) {
|
||||
conf := &NotifyChannelsSettingsContent{}
|
||||
if err := json.Unmarshal([]byte(s.Content), conf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
v, ok := (*conf)[channel]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("channel \"%s\" not found", channel)
|
||||
}
|
||||
|
||||
return v, nil
|
||||
}
|
||||
|
||||
type PersistenceSettingsContent struct {
|
||||
type SettingsContentAsPersistence struct {
|
||||
WorkflowRunsMaxDaysRetention int `json:"workflowRunsMaxDaysRetention"`
|
||||
ExpiredCertificatesMaxDaysRetention int `json:"expiredCertificatesMaxDaysRetention"`
|
||||
}
|
||||
|
||||
@@ -107,7 +107,6 @@ type WorkflowNodeConfigForDeploy struct {
|
||||
}
|
||||
|
||||
type WorkflowNodeConfigForNotify struct {
|
||||
Channel string `json:"channel,omitempty"` // Deprecated: v0.4.x 将废弃
|
||||
Provider string `json:"provider"` // 通知提供商
|
||||
ProviderAccessId string `json:"providerAccessId"` // 通知提供商授权记录 ID
|
||||
ProviderConfig map[string]any `json:"providerConfig,omitempty"` // 通知提供商额外配置
|
||||
@@ -173,7 +172,6 @@ func (n *WorkflowNode) GetConfigForDeploy() WorkflowNodeConfigForDeploy {
|
||||
|
||||
func (n *WorkflowNode) GetConfigForNotify() WorkflowNodeConfigForNotify {
|
||||
return WorkflowNodeConfigForNotify{
|
||||
Channel: xmaps.GetString(n.Config, "channel"),
|
||||
Provider: xmaps.GetString(n.Config, "provider"),
|
||||
ProviderAccessId: xmaps.GetString(n.Config, "providerAccessId"),
|
||||
ProviderConfig: xmaps.GetKVMapAny(n.Config, "providerConfig"),
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
package notify
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/sync/errgroup"
|
||||
|
||||
"github.com/certimate-go/certimate/internal/domain"
|
||||
"github.com/certimate-go/certimate/internal/repository"
|
||||
"github.com/certimate-go/certimate/pkg/core"
|
||||
xmaps "github.com/certimate-go/certimate/pkg/utils/maps"
|
||||
)
|
||||
|
||||
// Deprecated: v0.4.x 将废弃
|
||||
func SendToAllChannels(subject, message string) error {
|
||||
notifiers, err := getEnabledNotifiers()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(notifiers) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
var eg errgroup.Group
|
||||
for _, n := range notifiers {
|
||||
if n == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
eg.Go(func() error {
|
||||
_, err := n.Notify(context.Background(), subject, message)
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
err = eg.Wait()
|
||||
return err
|
||||
}
|
||||
|
||||
// Deprecated: v0.4.x 将废弃
|
||||
func SendToChannel(subject, message string, channel string, channelConfig map[string]any) error {
|
||||
notifier, err := createNotifierProviderUseGlobalSettings(domain.NotifyChannelType(channel), channelConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = notifier.Notify(context.Background(), subject, message)
|
||||
return err
|
||||
}
|
||||
|
||||
// Deprecated: v0.4.x 将废弃
|
||||
func getEnabledNotifiers() ([]core.Notifier, error) {
|
||||
settingsRepo := repository.NewSettingsRepository()
|
||||
settings, err := settingsRepo.GetByName(context.Background(), "notifyChannels")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("find notifyChannels error: %w", err)
|
||||
}
|
||||
|
||||
rs := make(map[string]map[string]any)
|
||||
if err := json.Unmarshal([]byte(settings.Content), &rs); err != nil {
|
||||
return nil, fmt.Errorf("unmarshal notifyChannels error: %w", err)
|
||||
}
|
||||
|
||||
notifiers := make([]core.Notifier, 0)
|
||||
for k, v := range rs {
|
||||
if !xmaps.GetBool(v, "enabled") {
|
||||
continue
|
||||
}
|
||||
|
||||
notifier, err := createNotifierProviderUseGlobalSettings(domain.NotifyChannelType(k), v)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
notifiers = append(notifiers, notifier)
|
||||
}
|
||||
|
||||
return notifiers, nil
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
package notify
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/certimate-go/certimate/internal/domain"
|
||||
"github.com/certimate-go/certimate/pkg/core"
|
||||
pBark "github.com/certimate-go/certimate/pkg/core/notifier/providers/bark"
|
||||
pDingTalk "github.com/certimate-go/certimate/pkg/core/notifier/providers/dingtalkbot"
|
||||
pEmail "github.com/certimate-go/certimate/pkg/core/notifier/providers/email"
|
||||
pGotify "github.com/certimate-go/certimate/pkg/core/notifier/providers/gotify"
|
||||
pLark "github.com/certimate-go/certimate/pkg/core/notifier/providers/larkbot"
|
||||
pMattermost "github.com/certimate-go/certimate/pkg/core/notifier/providers/mattermost"
|
||||
pPushover "github.com/certimate-go/certimate/pkg/core/notifier/providers/pushover"
|
||||
pPushPlus "github.com/certimate-go/certimate/pkg/core/notifier/providers/pushplus"
|
||||
pServerChan "github.com/certimate-go/certimate/pkg/core/notifier/providers/serverchan"
|
||||
pTelegram "github.com/certimate-go/certimate/pkg/core/notifier/providers/telegrambot"
|
||||
pWebhook "github.com/certimate-go/certimate/pkg/core/notifier/providers/webhook"
|
||||
pWeCom "github.com/certimate-go/certimate/pkg/core/notifier/providers/wecombot"
|
||||
xmaps "github.com/certimate-go/certimate/pkg/utils/maps"
|
||||
)
|
||||
|
||||
// Deprecated: v0.4.x 将废弃
|
||||
func createNotifierProviderUseGlobalSettings(channel domain.NotifyChannelType, channelConfig map[string]any) (core.Notifier, error) {
|
||||
/*
|
||||
注意:如果追加新的常量值,请保持以 ASCII 排序。
|
||||
NOTICE: If you add new constant, please keep ASCII order.
|
||||
*/
|
||||
switch channel {
|
||||
case domain.NotifyChannelTypeBark:
|
||||
return pBark.NewNotifierProvider(&pBark.NotifierProviderConfig{
|
||||
DeviceKey: xmaps.GetString(channelConfig, "deviceKey"),
|
||||
ServerUrl: xmaps.GetString(channelConfig, "serverUrl"),
|
||||
})
|
||||
|
||||
case domain.NotifyChannelTypeDingTalk:
|
||||
return pDingTalk.NewNotifierProvider(&pDingTalk.NotifierProviderConfig{
|
||||
WebhookUrl: "https://oapi.dingtalk.com/robot/send?access_token=" + xmaps.GetString(channelConfig, "accessToken"),
|
||||
Secret: xmaps.GetString(channelConfig, "secret"),
|
||||
})
|
||||
|
||||
case domain.NotifyChannelTypeEmail:
|
||||
return pEmail.NewNotifierProvider(&pEmail.NotifierProviderConfig{
|
||||
SmtpHost: xmaps.GetString(channelConfig, "smtpHost"),
|
||||
SmtpPort: xmaps.GetInt32(channelConfig, "smtpPort"),
|
||||
SmtpTls: xmaps.GetOrDefaultBool(channelConfig, "smtpTLS", true),
|
||||
Username: xmaps.GetOrDefaultString(channelConfig, "username", xmaps.GetString(channelConfig, "senderAddress")),
|
||||
Password: xmaps.GetString(channelConfig, "password"),
|
||||
SenderAddress: xmaps.GetString(channelConfig, "senderAddress"),
|
||||
ReceiverAddress: xmaps.GetString(channelConfig, "receiverAddress"),
|
||||
})
|
||||
|
||||
case domain.NotifyChannelTypeGotify:
|
||||
return pGotify.NewNotifierProvider(&pGotify.NotifierProviderConfig{
|
||||
ServerUrl: xmaps.GetString(channelConfig, "url"),
|
||||
Token: xmaps.GetString(channelConfig, "token"),
|
||||
Priority: xmaps.GetOrDefaultInt64(channelConfig, "priority", 1),
|
||||
})
|
||||
|
||||
case domain.NotifyChannelTypeLark:
|
||||
return pLark.NewNotifierProvider(&pLark.NotifierProviderConfig{
|
||||
WebhookUrl: xmaps.GetString(channelConfig, "webhookUrl"),
|
||||
})
|
||||
|
||||
case domain.NotifyChannelTypeMattermost:
|
||||
return pMattermost.NewNotifierProvider(&pMattermost.NotifierProviderConfig{
|
||||
ServerUrl: xmaps.GetString(channelConfig, "serverUrl"),
|
||||
ChannelId: xmaps.GetString(channelConfig, "channelId"),
|
||||
Username: xmaps.GetString(channelConfig, "username"),
|
||||
Password: xmaps.GetString(channelConfig, "password"),
|
||||
})
|
||||
|
||||
case domain.NotifyChannelTypePushover:
|
||||
return pPushover.NewNotifierProvider(&pPushover.NotifierProviderConfig{
|
||||
Token: xmaps.GetString(channelConfig, "token"),
|
||||
User: xmaps.GetString(channelConfig, "user"),
|
||||
})
|
||||
|
||||
case domain.NotifyChannelTypePushPlus:
|
||||
return pPushPlus.NewNotifierProvider(&pPushPlus.NotifierProviderConfig{
|
||||
Token: xmaps.GetString(channelConfig, "token"),
|
||||
})
|
||||
|
||||
case domain.NotifyChannelTypeServerChan:
|
||||
return pServerChan.NewNotifierProvider(&pServerChan.NotifierProviderConfig{
|
||||
ServerUrl: xmaps.GetString(channelConfig, "url"),
|
||||
})
|
||||
|
||||
case domain.NotifyChannelTypeTelegram:
|
||||
return pTelegram.NewNotifierProvider(&pTelegram.NotifierProviderConfig{
|
||||
BotToken: xmaps.GetString(channelConfig, "apiToken"),
|
||||
ChatId: xmaps.GetInt64(channelConfig, "chatId"),
|
||||
})
|
||||
|
||||
case domain.NotifyChannelTypeWebhook:
|
||||
return pWebhook.NewNotifierProvider(&pWebhook.NotifierProviderConfig{
|
||||
WebhookUrl: xmaps.GetString(channelConfig, "url"),
|
||||
AllowInsecureConnections: xmaps.GetBool(channelConfig, "allowInsecureConnections"),
|
||||
})
|
||||
|
||||
case domain.NotifyChannelTypeWeCom:
|
||||
return pWeCom.NewNotifierProvider(&pWeCom.NotifierProviderConfig{
|
||||
WebhookUrl: xmaps.GetString(channelConfig, "webhookUrl"),
|
||||
})
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("unsupported notifier channel '%s'", channelConfig)
|
||||
}
|
||||
@@ -4,44 +4,21 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/certimate-go/certimate/internal/domain"
|
||||
"github.com/certimate-go/certimate/internal/domain/dtos"
|
||||
)
|
||||
|
||||
// Deprecated: v0.4.x 将废弃
|
||||
const (
|
||||
notifyTestTitle = "测试通知"
|
||||
notifyTestBody = "欢迎使用 Certimate ,这是一条测试通知。"
|
||||
notifyTestTitle = "[Certimate] Notification Test"
|
||||
notifyTestBody = "Welcome to use Certimate!"
|
||||
)
|
||||
|
||||
// Deprecated: v0.4.x 将废弃
|
||||
type settingsRepository interface {
|
||||
GetByName(ctx context.Context, name string) (*domain.Settings, error)
|
||||
type NotifyService struct{}
|
||||
|
||||
func NewNotifyService() *NotifyService {
|
||||
return &NotifyService{}
|
||||
}
|
||||
|
||||
// Deprecated: v0.4.x 将废弃
|
||||
type NotifyService struct {
|
||||
settingsRepo settingsRepository
|
||||
}
|
||||
|
||||
// Deprecated: v0.4.x 将废弃
|
||||
func NewNotifyService(settingsRepo settingsRepository) *NotifyService {
|
||||
return &NotifyService{
|
||||
settingsRepo: settingsRepo,
|
||||
}
|
||||
}
|
||||
|
||||
// Deprecated: v0.4.x 将废弃
|
||||
func (n *NotifyService) Test(ctx context.Context, req *dtos.NotifyTestPushReq) error {
|
||||
settings, err := n.settingsRepo.GetByName(ctx, "notifyChannels")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get notify channels settings: %w", err)
|
||||
}
|
||||
|
||||
channelConfig, err := settings.GetNotifyChannelConfig(string(req.Channel))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get notify channel \"%s\" config: %w", req.Channel, err)
|
||||
}
|
||||
|
||||
return SendToChannel(notifyTestTitle, notifyTestBody, string(req.Channel), channelConfig)
|
||||
func (n *NotifyService) TestPush(ctx context.Context, req *dtos.NotifyTestPushReq) error {
|
||||
// TODO: 测试通知
|
||||
return fmt.Errorf("not implemented")
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
)
|
||||
|
||||
type certificateService interface {
|
||||
ArchiveFile(ctx context.Context, req *dtos.CertificateArchiveFileReq) (*dtos.CertificateArchiveFileResp, error)
|
||||
DownloadArchivedFile(ctx context.Context, req *dtos.CertificateArchiveFileReq) (*dtos.CertificateArchiveFileResp, error)
|
||||
ValidateCertificate(ctx context.Context, req *dtos.CertificateValidateCertificateReq) (*dtos.CertificateValidateCertificateResp, error)
|
||||
ValidatePrivateKey(ctx context.Context, req *dtos.CertificateValidatePrivateKeyReq) (*dtos.CertificateValidatePrivateKeyResp, error)
|
||||
}
|
||||
@@ -38,7 +38,7 @@ func (handler *CertificateHandler) archiveFile(e *core.RequestEvent) error {
|
||||
return resp.Err(e, err)
|
||||
}
|
||||
|
||||
if res, err := handler.service.ArchiveFile(e.Request.Context(), req); err != nil {
|
||||
if res, err := handler.service.DownloadArchivedFile(e.Request.Context(), req); err != nil {
|
||||
return resp.Err(e, err)
|
||||
} else {
|
||||
return resp.Ok(e, res)
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
)
|
||||
|
||||
type notifyService interface {
|
||||
Test(ctx context.Context, req *dtos.NotifyTestPushReq) error
|
||||
TestPush(ctx context.Context, req *dtos.NotifyTestPushReq) error
|
||||
}
|
||||
|
||||
type NotifyHandler struct {
|
||||
@@ -33,7 +33,7 @@ func (handler *NotifyHandler) test(e *core.RequestEvent) error {
|
||||
return resp.Err(e, err)
|
||||
}
|
||||
|
||||
if err := handler.service.Test(e.Request.Context(), req); err != nil {
|
||||
if err := handler.service.TestPush(e.Request.Context(), req); err != nil {
|
||||
return resp.Err(e, err)
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ func Register(router *router.Router[*core.RequestEvent]) {
|
||||
certificateSvc = certificate.NewCertificateService(certificateRepo, settingsRepo)
|
||||
workflowSvc = workflow.NewWorkflowService(workflowRepo, workflowRunRepo, settingsRepo)
|
||||
statisticsSvc = statistics.NewStatisticsService(statisticsRepo)
|
||||
notifySvc = notify.NewNotifyService(settingsRepo)
|
||||
notifySvc = notify.NewNotifyService()
|
||||
|
||||
group := router.Group("/api")
|
||||
group.Bind(apis.RequireSuperuserAuth())
|
||||
|
||||
@@ -33,33 +33,6 @@ func (n *notifyNode) Process(ctx context.Context) error {
|
||||
nodeCfg := n.node.GetConfigForNotify()
|
||||
n.logger.Info("ready to send notification ...", slog.Any("config", nodeCfg))
|
||||
|
||||
if nodeCfg.Provider == "" {
|
||||
// Deprecated: v0.4.x 将废弃
|
||||
// 兼容旧版本的通知渠道
|
||||
n.logger.Warn("WARNING! you are using the notification channel from global settings, which will be deprecated in the future")
|
||||
|
||||
// 获取通知配置
|
||||
settings, err := n.settingsRepo.GetByName(ctx, "notifyChannels")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 获取通知渠道
|
||||
channelConfig, err := settings.GetNotifyChannelConfig(nodeCfg.Channel)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 发送通知
|
||||
if err := notify.SendToChannel(nodeCfg.Subject, nodeCfg.Message, nodeCfg.Channel, channelConfig); err != nil {
|
||||
n.logger.Warn("failed to send notification", slog.String("channel", nodeCfg.Channel))
|
||||
return err
|
||||
}
|
||||
|
||||
n.logger.Info("notification completed")
|
||||
return nil
|
||||
}
|
||||
|
||||
// 检测是否可以跳过本次执行
|
||||
if skippable := n.checkCanSkip(ctx); skippable {
|
||||
n.logger.Info(fmt.Sprintf("skip this notification, because all the previous nodes have been skipped"))
|
||||
|
||||
@@ -59,7 +59,7 @@ func (s *WorkflowService) InitSchedule(ctx context.Context) error {
|
||||
return
|
||||
}
|
||||
|
||||
var settingsContent *domain.PersistenceSettingsContent
|
||||
var settingsContent *domain.SettingsContentAsPersistence
|
||||
json.Unmarshal([]byte(settings.Content), &settingsContent)
|
||||
if settingsContent != nil && settingsContent.WorkflowRunsMaxDaysRetention != 0 {
|
||||
ret, err := s.workflowRunRepo.DeleteWhere(
|
||||
|
||||
@@ -2,7 +2,7 @@ import { ClientResponseError } from "pocketbase";
|
||||
|
||||
import { getPocketBase } from "@/repository/_pocketbase";
|
||||
|
||||
export const notifyTest = async (channel: string) => {
|
||||
export const notifyTest = async (provider: string) => {
|
||||
const pb = getPocketBase();
|
||||
|
||||
const resp = await pb.send<BaseResponse>("/api/notify/test", {
|
||||
@@ -11,7 +11,7 @@ export const notifyTest = async (channel: string) => {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: {
|
||||
channel,
|
||||
provider,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -1,126 +0,0 @@
|
||||
import { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useRequest } from "ahooks";
|
||||
import { Button, Form, Input, Skeleton, message, notification } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { ClientResponseError } from "pocketbase";
|
||||
import { z } from "zod";
|
||||
|
||||
import Show from "@/components/Show";
|
||||
import { type NotifyTemplatesSettingsContent, SETTINGS_NAMES, defaultNotifyTemplate } from "@/domain/settings";
|
||||
import { useAntdForm } from "@/hooks";
|
||||
import { get as getSettings, save as saveSettings } from "@/repository/settings";
|
||||
import { getErrMsg } from "@/utils/error";
|
||||
|
||||
export interface NotifyTemplateFormProps {
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
}
|
||||
|
||||
const NotifyTemplateForm = ({ className, style }: NotifyTemplateFormProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [messageApi, MessageContextHolder] = message.useMessage();
|
||||
const [notificationApi, NotificationContextHolder] = notification.useNotification();
|
||||
|
||||
const formSchema = z.object({
|
||||
subject: z
|
||||
.string()
|
||||
.min(1, t("settings.notification.template.form.subject.placeholder"))
|
||||
.max(1000, t("common.errmsg.string_max", { max: 1000 })),
|
||||
message: z
|
||||
.string()
|
||||
.min(1, t("settings.notification.template.form.message.placeholder"))
|
||||
.max(1000, t("common.errmsg.string_max", { max: 1000 })),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const {
|
||||
form: formInst,
|
||||
formPending,
|
||||
formProps,
|
||||
} = useAntdForm<z.infer<typeof formSchema>>({
|
||||
initialValues: defaultNotifyTemplate,
|
||||
onSubmit: async (values) => {
|
||||
try {
|
||||
const settings = await getSettings<NotifyTemplatesSettingsContent>(SETTINGS_NAMES.NOTIFY_TEMPLATES);
|
||||
await saveSettings<NotifyTemplatesSettingsContent>({
|
||||
...settings,
|
||||
content: {
|
||||
notifyTemplates: [values],
|
||||
},
|
||||
});
|
||||
|
||||
messageApi.success(t("common.text.operation_succeeded"));
|
||||
} catch (err) {
|
||||
notificationApi.error({ message: t("common.text.request_error"), description: getErrMsg(err) });
|
||||
|
||||
throw err;
|
||||
}
|
||||
},
|
||||
});
|
||||
const [formChanged, setFormChanged] = useState(false);
|
||||
|
||||
const { loading } = useRequest(
|
||||
() => {
|
||||
return getSettings<NotifyTemplatesSettingsContent>(SETTINGS_NAMES.NOTIFY_TEMPLATES);
|
||||
},
|
||||
{
|
||||
onError: (err) => {
|
||||
if (err instanceof ClientResponseError && err.isAbort) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.error(err);
|
||||
},
|
||||
onFinally: (_, resp) => {
|
||||
const template = resp?.content?.notifyTemplates?.[0] ?? defaultNotifyTemplate;
|
||||
formInst.setFieldsValue(template);
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const handleInputChange = () => {
|
||||
setFormChanged(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={className} style={style}>
|
||||
{MessageContextHolder}
|
||||
{NotificationContextHolder}
|
||||
|
||||
<Show when={!loading} fallback={<Skeleton active />}>
|
||||
<Form {...formProps} form={formInst} disabled={formPending} layout="vertical">
|
||||
<Form.Item
|
||||
name="subject"
|
||||
label={t("settings.notification.template.form.subject.label")}
|
||||
extra={t("settings.notification.template.form.subject.extra")}
|
||||
rules={[formRule]}
|
||||
>
|
||||
<Input placeholder={t("settings.notification.template.form.subject.placeholder")} onChange={handleInputChange} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="message"
|
||||
label={t("settings.notification.template.form.message.label")}
|
||||
extra={t("settings.notification.template.form.message.extra")}
|
||||
rules={[formRule]}
|
||||
>
|
||||
<Input.TextArea
|
||||
autoSize={{ minRows: 3, maxRows: 10 }}
|
||||
placeholder={t("settings.notification.template.form.message.placeholder")}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item>
|
||||
<Button type="primary" htmlType="submit" disabled={!formChanged} loading={formPending}>
|
||||
{t("common.button.save")}
|
||||
</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Show>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default NotifyTemplateForm;
|
||||
@@ -8,12 +8,12 @@ import { getErrMsg } from "@/utils/error";
|
||||
export interface NotifyTestButtonProps {
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
channel: string;
|
||||
disabled?: boolean;
|
||||
provider: string;
|
||||
size?: ButtonProps["size"];
|
||||
}
|
||||
|
||||
const NotifyTestButton = ({ className, style, channel, disabled, size }: NotifyTestButtonProps) => {
|
||||
const NotifyTestButton = ({ className, style, provider, disabled, size }: NotifyTestButtonProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [messageApi, MessageContextHolder] = message.useMessage();
|
||||
@@ -21,10 +21,10 @@ const NotifyTestButton = ({ className, style, channel, disabled, size }: NotifyT
|
||||
|
||||
const { loading, run: executeNotifyTest } = useRequest(
|
||||
() => {
|
||||
return notifyTest(channel);
|
||||
return notifyTest(provider);
|
||||
},
|
||||
{
|
||||
refreshDeps: [channel],
|
||||
refreshDeps: [provider],
|
||||
manual: true,
|
||||
onSuccess: () => {
|
||||
messageApi.success(t("settings.notification.push_test.pushed"));
|
||||
|
||||
@@ -2,11 +2,6 @@ import { type CAProviderType } from "./provider";
|
||||
|
||||
export const SETTINGS_NAMES = Object.freeze({
|
||||
EMAILS: "emails",
|
||||
NOTIFY_TEMPLATES: "notifyTemplates",
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
NOTIFY_CHANNELS: "notifyChannels",
|
||||
SSL_PROVIDER: "sslProvider",
|
||||
PERSISTENCE: "persistence",
|
||||
} as const);
|
||||
@@ -24,22 +19,6 @@ export type EmailsSettingsContent = {
|
||||
};
|
||||
// #endregion
|
||||
|
||||
// #region Settings: NotifyTemplates
|
||||
export type NotifyTemplatesSettingsContent = {
|
||||
notifyTemplates: NotifyTemplate[];
|
||||
};
|
||||
|
||||
export type NotifyTemplate = {
|
||||
subject: string;
|
||||
message: string;
|
||||
};
|
||||
|
||||
export const defaultNotifyTemplate: NotifyTemplate = {
|
||||
subject: "有 ${COUNT} 张证书即将过期",
|
||||
message: "有 ${COUNT} 张证书即将过期,域名分别为 ${DOMAINS},请保持关注!",
|
||||
};
|
||||
// #endregion
|
||||
|
||||
// #region Settings: SSLProvider
|
||||
export type SSLProviderSettingsContent = {
|
||||
provider: CAProviderType;
|
||||
|
||||
@@ -210,10 +210,6 @@ export const defaultNodeConfigForDeploy = (): Partial<WorkflowNodeConfigForDeplo
|
||||
export type WorkflowNodeConfigForNotify = {
|
||||
subject: string;
|
||||
message: string;
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
channel?: string;
|
||||
provider: string;
|
||||
providerAccessId: string;
|
||||
providerConfig?: Record<string, unknown>;
|
||||
|
||||
Reference in New Issue
Block a user