chore: opt settings code
This commit is contained in:
@@ -2,62 +2,66 @@ package services
|
||||
|
||||
import (
|
||||
"baihu/internal/constant"
|
||||
"encoding/json"
|
||||
"os"
|
||||
|
||||
"gopkg.in/ini.v1"
|
||||
)
|
||||
|
||||
type ServerConfig struct {
|
||||
Port int `json:"port"`
|
||||
Host string `json:"host"`
|
||||
SiteName string `json:"site_name"`
|
||||
Port int `ini:"port"`
|
||||
Host string `ini:"host"`
|
||||
}
|
||||
|
||||
type DatabaseConfig struct {
|
||||
Type string `json:"type"`
|
||||
Host string `json:"host"`
|
||||
Port int `json:"port"`
|
||||
User string `json:"user"`
|
||||
Password string `json:"password"`
|
||||
DBName string `json:"dbname"`
|
||||
Path string `json:"path"`
|
||||
TablePrefix string `json:"table_prefix"`
|
||||
Type string `ini:"type"`
|
||||
Host string `ini:"host"`
|
||||
Port int `ini:"port"`
|
||||
User string `ini:"user"`
|
||||
Password string `ini:"password"`
|
||||
DBName string `ini:"dbname"`
|
||||
Path string `ini:"path"`
|
||||
TablePrefix string `ini:"table_prefix"`
|
||||
}
|
||||
|
||||
type SecurityConfig struct {
|
||||
JWTSecret string `json:"jwt_secret"`
|
||||
PasswordSalt string `json:"password_salt"`
|
||||
Secret string `ini:"secret"`
|
||||
}
|
||||
|
||||
type TaskConfig struct {
|
||||
DefaultTimeout int `json:"default_timeout"`
|
||||
LogRetentionDays int `json:"log_retention_days"`
|
||||
DefaultTimeout int `ini:"default_timeout"`
|
||||
LogRetentionDays int `ini:"log_retention_days"`
|
||||
}
|
||||
|
||||
type AppConfig struct {
|
||||
Server ServerConfig `json:"server"`
|
||||
Database DatabaseConfig `json:"database"`
|
||||
Security SecurityConfig `json:"security"`
|
||||
Task TaskConfig `json:"task"`
|
||||
Server ServerConfig `ini:"server"`
|
||||
Database DatabaseConfig `ini:"database"`
|
||||
Security SecurityConfig `ini:"security"`
|
||||
Task TaskConfig `ini:"task"`
|
||||
}
|
||||
|
||||
var Config *AppConfig
|
||||
|
||||
func LoadConfig(path string) (*AppConfig, error) {
|
||||
data, err := os.ReadFile(path)
|
||||
cfg, err := ini.Load(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
Config = &AppConfig{}
|
||||
if err := json.Unmarshal(data, Config); err != nil {
|
||||
if err := cfg.MapTo(Config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 设置表前缀到 constant 包
|
||||
if Config.Database.TablePrefix != "" {
|
||||
constant.TablePrefix = Config.Database.TablePrefix
|
||||
// 设置默认数据库路径
|
||||
if Config.Database.Path == "" {
|
||||
Config.Database.Path = constant.DefaultDBPath
|
||||
}
|
||||
|
||||
// 设置表前缀到 constant 包
|
||||
constant.TablePrefix = Config.Database.TablePrefix
|
||||
|
||||
// 设置 Secret 到 constant 包
|
||||
constant.Secret = Config.Security.Secret
|
||||
|
||||
return Config, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
|
||||
"baihu/internal/constant"
|
||||
"baihu/internal/logger"
|
||||
)
|
||||
|
||||
@@ -27,11 +23,9 @@ func (s *InitService) Initialize() *UserService {
|
||||
logger.Warnf("初始化设置失败: %v", err)
|
||||
}
|
||||
|
||||
// 初始化 JWT Secret(也用作密码 salt,必须在创建 UserService 之前)
|
||||
s.initJWTSecret()
|
||||
// 创建 UserService
|
||||
userService := NewUserService()
|
||||
|
||||
// 创建 UserService(依赖 settingsService 获取 salt)
|
||||
userService := NewUserService(s.settingsService)
|
||||
// 创建管理员账号
|
||||
s.initializeAdmin(userService)
|
||||
|
||||
@@ -49,30 +43,3 @@ func (s *InitService) initializeAdmin(userService *UserService) {
|
||||
userService.CreateUser("admin", "123456", "admin@local", "admin")
|
||||
logger.Info("管理员账号创建成功: admin / 123456")
|
||||
}
|
||||
|
||||
// IsInitialized 检查是否已初始化
|
||||
func (s *InitService) IsInitialized() bool {
|
||||
return s.settingsService.Get(constant.SectionSystem, constant.KeyInitialized) == "true"
|
||||
}
|
||||
|
||||
// initJWTSecret 初始化 JWT Secret,如果不存在则生成随机值
|
||||
func (s *InitService) initJWTSecret() {
|
||||
existing := s.settingsService.Get(constant.SectionSystem, constant.KeyJWTSecret)
|
||||
if existing != "" {
|
||||
return
|
||||
}
|
||||
|
||||
// 生成 32 字节随机密钥
|
||||
bytes := make([]byte, 32)
|
||||
if _, err := rand.Read(bytes); err != nil {
|
||||
logger.Warnf("生成 JWT Secret 失败: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
secret := hex.EncodeToString(bytes)
|
||||
if err := s.settingsService.Set(constant.SectionSystem, constant.KeyJWTSecret, secret); err != nil {
|
||||
logger.Warnf("保存 JWT Secret 失败: %v", err)
|
||||
return
|
||||
}
|
||||
logger.Info("JWT Secret 已生成")
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"baihu/internal/database"
|
||||
"baihu/internal/models"
|
||||
)
|
||||
|
||||
type LoginLogService struct{}
|
||||
|
||||
func NewLoginLogService() *LoginLogService {
|
||||
return &LoginLogService{}
|
||||
}
|
||||
|
||||
// Create 创建登录日志
|
||||
func (s *LoginLogService) Create(username, ip, userAgent, status, message string) error {
|
||||
log := &models.LoginLog{
|
||||
Username: username,
|
||||
IP: ip,
|
||||
UserAgent: userAgent,
|
||||
Status: status,
|
||||
Message: message,
|
||||
}
|
||||
return database.DB.Create(log).Error
|
||||
}
|
||||
|
||||
// List 获取登录日志列表
|
||||
func (s *LoginLogService) List(page, pageSize int, username string) ([]models.LoginLog, int64, error) {
|
||||
var logs []models.LoginLog
|
||||
var total int64
|
||||
|
||||
query := database.DB.Model(&models.LoginLog{})
|
||||
if username != "" {
|
||||
query = query.Where("username LIKE ?", "%"+username+"%")
|
||||
}
|
||||
|
||||
if err := query.Count(&total).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
offset := (page - 1) * pageSize
|
||||
if err := query.Order("created_at DESC").Offset(offset).Limit(pageSize).Find(&logs).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return logs, total, nil
|
||||
}
|
||||
|
||||
// CleanOldLogs 清理指定天数前的日志
|
||||
func (s *LoginLogService) CleanOldLogs(days int) (int64, error) {
|
||||
result := database.DB.Exec("DELETE FROM "+models.LoginLog{}.TableName()+" WHERE created_at < datetime('now', ?)", "-"+string(rune(days))+" days")
|
||||
return result.RowsAffected, result.Error
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"baihu/internal/cache"
|
||||
"baihu/internal/constant"
|
||||
"baihu/internal/database"
|
||||
"baihu/internal/models"
|
||||
@@ -17,26 +18,23 @@ func (s *SettingsService) InitSettings() error {
|
||||
for section, keys := range constant.DefaultSettings {
|
||||
for key, value := range keys {
|
||||
var count int64
|
||||
database.DB.Model(&models.Setting{}).
|
||||
Where("section = ? AND key = ?", section, key).
|
||||
Count(&count)
|
||||
database.DB.Model(&models.Setting{}).Where("section = ? AND key = ?", section, key).Count(&count)
|
||||
if count == 0 {
|
||||
setting := &models.Setting{
|
||||
Section: section,
|
||||
Key: key,
|
||||
Value: value,
|
||||
}
|
||||
if err := database.DB.Create(setting).Error; err != nil {
|
||||
if err := database.DB.Create(&models.Setting{Section: section, Key: key, Value: value}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
cache.LoadSiteCache()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get 获取单个设置
|
||||
func (s *SettingsService) Get(section, key string) string {
|
||||
if section == constant.SectionSite {
|
||||
return cache.GetSiteCache(key)
|
||||
}
|
||||
var setting models.Setting
|
||||
if err := database.DB.Where("section = ? AND key = ?", section, key).First(&setting).Error; err != nil {
|
||||
if def, ok := constant.DefaultSettings[section][key]; ok {
|
||||
@@ -50,29 +48,27 @@ func (s *SettingsService) Get(section, key string) string {
|
||||
// Set 设置单个值
|
||||
func (s *SettingsService) Set(section, key, value string) error {
|
||||
var setting models.Setting
|
||||
result := database.DB.Where("section = ? AND key = ?", section, key).First(&setting)
|
||||
if result.Error != nil {
|
||||
setting = models.Setting{Section: section, Key: key, Value: value}
|
||||
return database.DB.Create(&setting).Error
|
||||
if database.DB.Where("section = ? AND key = ?", section, key).First(&setting).Error != nil {
|
||||
return database.DB.Create(&models.Setting{Section: section, Key: key, Value: value}).Error
|
||||
}
|
||||
return database.DB.Model(&setting).Update("value", value).Error
|
||||
}
|
||||
|
||||
// GetSection 获取整个 section 的设置
|
||||
func (s *SettingsService) GetSection(section string) map[string]string {
|
||||
var settings []models.Setting
|
||||
database.DB.Where("section = ?", section).Find(&settings)
|
||||
|
||||
if section == constant.SectionSite {
|
||||
return cache.GetSiteCacheAll()
|
||||
}
|
||||
result := make(map[string]string)
|
||||
// 先填充默认值
|
||||
if defaults, ok := constant.DefaultSettings[section]; ok {
|
||||
for k, v := range defaults {
|
||||
result[k] = v
|
||||
}
|
||||
}
|
||||
// 覆盖数据库值
|
||||
for _, s := range settings {
|
||||
result[s.Key] = s.Value
|
||||
var settings []models.Setting
|
||||
database.DB.Where("section = ?", section).Find(&settings)
|
||||
for _, setting := range settings {
|
||||
result[setting.Key] = setting.Value
|
||||
}
|
||||
return result
|
||||
}
|
||||
@@ -84,5 +80,8 @@ func (s *SettingsService) SetSection(section string, values map[string]string) e
|
||||
return err
|
||||
}
|
||||
}
|
||||
if section == constant.SectionSite {
|
||||
cache.SetSiteCacheBatch(values)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -9,18 +9,14 @@ import (
|
||||
"baihu/internal/models"
|
||||
)
|
||||
|
||||
type UserService struct {
|
||||
settingsService *SettingsService
|
||||
}
|
||||
type UserService struct{}
|
||||
|
||||
func NewUserService(settingsService *SettingsService) *UserService {
|
||||
return &UserService{settingsService: settingsService}
|
||||
func NewUserService() *UserService {
|
||||
return &UserService{}
|
||||
}
|
||||
|
||||
func (us *UserService) hashPassword(password string) string {
|
||||
// 使用 JWT Secret 作为密码 salt
|
||||
salt := us.settingsService.Get(constant.SectionSystem, constant.KeyJWTSecret)
|
||||
hash := sha256.Sum256([]byte(password + salt))
|
||||
hash := sha256.Sum256([]byte(password + constant.Secret))
|
||||
return hex.EncodeToString(hash[:])
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user