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 if err := s.db.First(&row, "key = ?", key).Error; err != nil { return "", nil // key not found → return zero value } 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 increments the visit counter. Returns (totalVisits, counted, error). // For simplicity, every call increments (fingerprint dedup is handled in-memory by the handler layer). func (s *SiteStore) RecordVisit(_ string) (int, bool, error) { total, err := s.IncrementVisits() return total, true, err } // SMTPConfig holds the mail sender configuration stored in the DB. type SMTPConfig struct { Email string `json:"email"` Password string `json:"password"` FromName string `json:"fromName"` Host string `json:"host"` Port string `json:"port"` } // IsConfiguredEmail returns true if the SMTP config is ready to send mail. func (c SMTPConfig) IsConfiguredEmail() bool { return c.Email != "" && c.Password != "" && c.Host != "" } func (s *SiteStore) GetSMTPConfig() (SMTPConfig, error) { cfg := SMTPConfig{ Host: "smtp.qq.com", Port: "465", } 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 { pairs := [][2]string{ {"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 }