feat: add Web UI for notification config (feishu + email)
- New config/notify_store.go: persistent notification config (notify.json) - New API: GET/PUT /api/notify/config, POST /api/notify/test-feishu, POST /api/notify/test-email - New Vue page: NotifyConfig.vue with feishu webhook and SMTP settings - Updated cron/init to read from persistent store instead of env vars - Password masked as ******** in API responses, preserved on updates
This commit is contained in:
+30
-22
@@ -1,6 +1,7 @@
|
||||
package notify
|
||||
|
||||
import (
|
||||
"auto-ssl/config"
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
@@ -16,18 +17,31 @@ import (
|
||||
|
||||
// Config holds notification configuration
|
||||
type Config struct {
|
||||
// Feishu webhook
|
||||
FeishuWebhookURL string
|
||||
// SMTP
|
||||
SMTPHost string
|
||||
SMTPPort string
|
||||
SMTPUser string
|
||||
SMTPPassword string
|
||||
SMTPFrom string
|
||||
NotifyTo string // comma-separated email recipients
|
||||
SMTPHost string
|
||||
SMTPPort string
|
||||
SMTPUser string
|
||||
SMTPPassword string
|
||||
SMTPFrom string
|
||||
NotifyTo string
|
||||
ExpiryDays int
|
||||
}
|
||||
|
||||
// LoadNotifyConfig reads notification config from environment
|
||||
// ConfigFromStore converts store config to notify config
|
||||
func ConfigFromStore(nc *config.NotifyConfig) *Config {
|
||||
return &Config{
|
||||
FeishuWebhookURL: nc.FeishuURL,
|
||||
SMTPHost: nc.SMTPHost,
|
||||
SMTPPort: nc.SMTPPort,
|
||||
SMTPUser: nc.SMTPUser,
|
||||
SMTPPassword: nc.SMTPPassword,
|
||||
SMTPFrom: nc.SMTPFrom,
|
||||
NotifyTo: nc.NotifyTo,
|
||||
ExpiryDays: nc.ExpiryDays,
|
||||
}
|
||||
}
|
||||
|
||||
// LoadNotifyConfig reads notification config from environment (legacy fallback)
|
||||
func LoadNotifyConfig() *Config {
|
||||
return &Config{
|
||||
FeishuWebhookURL: os.Getenv("FEISHU_WEBHOOK_URL"),
|
||||
@@ -86,18 +100,18 @@ func (c *Config) NotifyCertExpiring(certs []CertInfo) error {
|
||||
|
||||
// Feishu message format
|
||||
type feishuCard struct {
|
||||
MsgType string `json:"msg_type"`
|
||||
MsgType string `json:"msg_type"`
|
||||
Card *feishuCardContent `json:"card"`
|
||||
}
|
||||
|
||||
type feishuCardContent struct {
|
||||
Header feishuHeader `json:"header"`
|
||||
Elems []feishuElement `json:"elements"`
|
||||
Header feishuHeader `json:"header"`
|
||||
Elems []feishuElement `json:"elements"`
|
||||
}
|
||||
|
||||
type feishuHeader struct {
|
||||
Title feishuText `json:"title"`
|
||||
Template string `json:"template"`
|
||||
Title feishuText `json:"title"`
|
||||
Template string `json:"template"`
|
||||
}
|
||||
|
||||
type feishuText struct {
|
||||
@@ -106,8 +120,8 @@ type feishuText struct {
|
||||
}
|
||||
|
||||
type feishuElement struct {
|
||||
Tag string `json:"tag"`
|
||||
Text *feishuText `json:"text,omitempty"`
|
||||
Tag string `json:"tag"`
|
||||
Text *feishuText `json:"text,omitempty"`
|
||||
Fields *[]feishuField `json:"fields,omitempty"`
|
||||
}
|
||||
|
||||
@@ -117,7 +131,6 @@ type feishuField struct {
|
||||
}
|
||||
|
||||
func (c *Config) sendFeishu(certs []CertInfo) error {
|
||||
// Build card content
|
||||
elements := []feishuElement{}
|
||||
|
||||
for _, cert := range certs {
|
||||
@@ -150,7 +163,6 @@ func (c *Config) sendFeishu(certs []CertInfo) error {
|
||||
)
|
||||
}
|
||||
|
||||
// Summary
|
||||
expiringCount := 0
|
||||
for _, cert := range certs {
|
||||
if cert.DaysLeft <= 7 {
|
||||
@@ -158,7 +170,6 @@ func (c *Config) sendFeishu(certs []CertInfo) error {
|
||||
}
|
||||
}
|
||||
|
||||
// Determine template color
|
||||
template := "blue"
|
||||
if expiringCount > 0 {
|
||||
template = "red"
|
||||
@@ -202,7 +213,6 @@ func (c *Config) sendFeishu(certs []CertInfo) error {
|
||||
}
|
||||
|
||||
func (c *Config) sendEmail(certs []CertInfo) error {
|
||||
// Build HTML email
|
||||
var sb strings.Builder
|
||||
sb.WriteString(`
|
||||
<html>
|
||||
@@ -260,8 +270,6 @@ func (c *Config) sendEmail(certs []CertInfo) error {
|
||||
`)
|
||||
|
||||
htmlContent := sb.String()
|
||||
|
||||
// Subject
|
||||
subject := fmt.Sprintf("🔐 [AutoSSL] %d 个证书即将到期 - 请及时处理", len(certs))
|
||||
|
||||
e := email.NewEmail()
|
||||
|
||||
Reference in New Issue
Block a user