package storage import ( "strconv" "gorm.io/gorm" "gorm.io/gorm/clause" "mengyastore-backend/internal/database" ) type SiteStore struct { db *gorm.DB } func NewSiteStore(db *gorm.DB) (*SiteStore, error) { return &SiteStore{db: db}, nil } func (s *SiteStore) get(key string) (string, error) { var row database.SiteSettingRow // `key` 是 MySQL 保留字,需用反引号转义以避免 SQL 语法错误。 if err := s.db.Where("`key` = ?", key).First(&row).Error; err != nil { return "", nil // 键不存在时返回零值 } return row.Value, nil } func (s *SiteStore) set(key, value string) error { return s.db.Clauses(clause.OnConflict{ Columns: []clause.Column{{Name: "key"}}, DoUpdates: clause.AssignmentColumns([]string{"value"}), }).Create(&database.SiteSettingRow{Key: key, Value: value}).Error } func (s *SiteStore) GetTotalVisits() (int, error) { v, err := s.get("totalVisits") if err != nil || v == "" { return 0, err } n, _ := strconv.Atoi(v) return n, nil } func (s *SiteStore) IncrementVisits() (int, error) { current, err := s.GetTotalVisits() if err != nil { return 0, err } current++ if err := s.set("totalVisits", strconv.Itoa(current)); err != nil { return 0, err } return current, nil } func (s *SiteStore) GetMaintenance() (enabled bool, reason string, err error) { v, err := s.get("maintenance") if err != nil { return false, "", err } enabled = v == "true" reason, err = s.get("maintenanceReason") return enabled, reason, err } func (s *SiteStore) SetMaintenance(enabled bool, reason string) error { v := "false" if enabled { v = "true" } if err := s.set("maintenance", v); err != nil { return err } return s.set("maintenanceReason", reason) } // RecordVisit 递增访问计数,返回 (总访问量, 是否计入, 错误)。 // 去重逻辑由上层 handler 的内存指纹完成,此处无条件累加。 func (s *SiteStore) RecordVisit(_ string) (int, bool, error) { total, err := s.IncrementVisits() return total, true, err } // SMTPConfig 存储数据库中的发件 SMTP 配置。 type SMTPConfig struct { Enabled bool `json:"enabled"` Email string `json:"email"` Password string `json:"password"` FromName string `json:"fromName"` Host string `json:"host"` Port string `json:"port"` } // IsConfiguredEmail 判断邮件通知是否已启用且 SMTP 配置完整。 func (c SMTPConfig) IsConfiguredEmail() bool { return c.Enabled && c.Email != "" && c.Password != "" && c.Host != "" } func (s *SiteStore) GetSMTPConfig() (SMTPConfig, error) { cfg := SMTPConfig{ Enabled: true, // 默认启用 Host: "smtp.qq.com", Port: "465", } if v, _ := s.get("smtpEnabled"); v == "false" { cfg.Enabled = false } if v, _ := s.get("smtpEmail"); v != "" { cfg.Email = v } if v, _ := s.get("smtpPassword"); v != "" { cfg.Password = v } if v, _ := s.get("smtpFromName"); v != "" { cfg.FromName = v } if v, _ := s.get("smtpHost"); v != "" { cfg.Host = v } if v, _ := s.get("smtpPort"); v != "" { cfg.Port = v } return cfg, nil } func (s *SiteStore) SetSMTPConfig(cfg SMTPConfig) error { enabledVal := "true" if !cfg.Enabled { enabledVal = "false" } pairs := [][2]string{ {"smtpEnabled", enabledVal}, {"smtpEmail", cfg.Email}, {"smtpPassword", cfg.Password}, {"smtpFromName", cfg.FromName}, {"smtpHost", cfg.Host}, {"smtpPort", cfg.Port}, } for _, p := range pairs { if err := s.set(p[0], p[1]); err != nil { return err } } return nil }