Files
BackupX/server/internal/service/settings_service.go
Wu Qing f807ce10e6 feat(audit): 审计日志保留期清理(后端自动清理 + 审计页配置) (#83)
审计日志新增可配置保留期:AuditLogRepository.DeleteBefore + AuditService 保留期监控(每 6h 读取 audit_retention_days,0/缺省=永久保留);审计页新增管理员保留天数配置控件。后端 go test、前端 tsc+vite 通过。
2026-05-27 08:37:34 +08:00

102 lines
3.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package service
import (
"context"
"backupx/server/internal/apperror"
"backupx/server/internal/model"
"backupx/server/internal/repository"
)
// AuditWebhookConfigurer 抽象审计 webhook 配置接口,由 AuditService 实现。
// 用接口解耦避免 settings_service 直接依赖 AuditService 具体类型。
type AuditWebhookConfigurer interface {
SetWebhook(url, secret string)
}
type SettingsService struct {
configs repository.SystemConfigRepository
auditWebhook AuditWebhookConfigurer
}
func NewSettingsService(configs repository.SystemConfigRepository) *SettingsService {
return &SettingsService{configs: configs}
}
// SetAuditWebhookConfigurer 注入 audit webhook 配置接收方。
// 启动时立即用当前 DB 中的设置调用一次,后续每次 Update 变更 webhook key 时同步推送。
func (s *SettingsService) SetAuditWebhookConfigurer(ctx context.Context, configurer AuditWebhookConfigurer) {
if s == nil || configurer == nil {
return
}
s.auditWebhook = configurer
// 启动时同步一次,保证重启后配置不丢失
all, err := s.GetAll(ctx)
if err == nil {
configurer.SetWebhook(all[SettingKeyAuditWebhookURL], all[SettingKeyAuditWebhookSecret])
}
}
// 可被前端写入的系统设置键。新增键必须同步加入此清单,
// 否则 Update 会忽略(安全原则:显式 allow-list
const (
SettingKeySiteName = "site_name"
SettingKeyLanguage = "language"
SettingKeyTimezone = "timezone"
SettingKeyBackupNotificationEnabled = "backup_notification_enabled"
SettingKeyBandwidthLimit = "bandwidth_limit"
SettingKeyAuditWebhookURL = "audit_webhook_url"
SettingKeyAuditWebhookSecret = "audit_webhook_secret"
// SettingKeyAuditRetentionDays 审计日志保留天数0/缺省=永久保留)。
SettingKeyAuditRetentionDays = "audit_retention_days"
)
var settingsKeys = []string{
SettingKeySiteName,
SettingKeyLanguage,
SettingKeyTimezone,
SettingKeyBackupNotificationEnabled,
SettingKeyBandwidthLimit,
SettingKeyAuditWebhookURL,
SettingKeyAuditWebhookSecret,
SettingKeyAuditRetentionDays,
}
func (s *SettingsService) GetAll(ctx context.Context) (map[string]string, error) {
items, err := s.configs.List(ctx)
if err != nil {
return nil, apperror.Internal("SETTINGS_LIST_FAILED", "无法获取系统设置", err)
}
result := make(map[string]string, len(items))
for _, item := range items {
result[item.Key] = item.Value
}
return result, nil
}
func (s *SettingsService) Update(ctx context.Context, settings map[string]string) (map[string]string, error) {
allowed := make(map[string]bool, len(settingsKeys))
for _, key := range settingsKeys {
allowed[key] = true
}
auditWebhookTouched := false
for key, value := range settings {
if !allowed[key] {
continue
}
item := &model.SystemConfig{Key: key, Value: value}
if err := s.configs.Upsert(ctx, item); err != nil {
return nil, apperror.Internal("SETTINGS_UPDATE_FAILED", "无法更新系统设置", err)
}
if key == SettingKeyAuditWebhookURL || key == SettingKeyAuditWebhookSecret {
auditWebhookTouched = true
}
}
// audit webhook 配置变化:立即同步到 AuditService避免重启才生效
if auditWebhookTouched && s.auditWebhook != nil {
all, _ := s.GetAll(ctx)
s.auditWebhook.SetWebhook(all[SettingKeyAuditWebhookURL], all[SettingKeyAuditWebhookSecret])
}
return s.GetAll(ctx)
}