feat: 添加种子数据初始化功能,重构多个处理程序以简化错误响应和用户验证
This commit is contained in:
156
pkg/database/seed.go
Normal file
156
pkg/database/seed.go
Normal file
@@ -0,0 +1,156 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"carrotskin/internal/model"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// 默认管理员配置
|
||||
const (
|
||||
defaultAdminUsername = "admin"
|
||||
defaultAdminEmail = "admin@example.com"
|
||||
defaultAdminPassword = "admin123456" // 首次登录后请立即修改
|
||||
)
|
||||
|
||||
// defaultSystemConfigs 默认系统配置
|
||||
var defaultSystemConfigs = []model.SystemConfig{
|
||||
{Key: "site_name", Value: "CarrotSkin", Description: "网站名称", Type: model.ConfigTypeString, IsPublic: true},
|
||||
{Key: "site_description", Value: "一个优秀的Minecraft皮肤站", Description: "网站描述", Type: model.ConfigTypeString, IsPublic: true},
|
||||
{Key: "registration_enabled", Value: "true", Description: "是否允许用户注册", Type: model.ConfigTypeBoolean, IsPublic: true},
|
||||
{Key: "checkin_reward", Value: "10", Description: "签到奖励积分", Type: model.ConfigTypeInteger, IsPublic: true},
|
||||
{Key: "texture_download_reward", Value: "1", Description: "材质被下载奖励积分", Type: model.ConfigTypeInteger, IsPublic: false},
|
||||
{Key: "max_textures_per_user", Value: "50", Description: "每个用户最大材质数量", Type: model.ConfigTypeInteger, IsPublic: false},
|
||||
{Key: "max_profiles_per_user", Value: "5", Description: "每个用户最大角色数量", Type: model.ConfigTypeInteger, IsPublic: false},
|
||||
{Key: "default_avatar", Value: "", Description: "默认头像URL", Type: model.ConfigTypeString, IsPublic: true},
|
||||
}
|
||||
|
||||
// defaultCasbinRules 默认Casbin权限规则
|
||||
var defaultCasbinRules = []model.CasbinRule{
|
||||
// 管理员拥有所有权限
|
||||
{PType: "p", V0: "admin", V1: "*", V2: "*"},
|
||||
// 普通用户权限
|
||||
{PType: "p", V0: "user", V1: "texture", V2: "create"},
|
||||
{PType: "p", V0: "user", V1: "texture", V2: "read"},
|
||||
{PType: "p", V0: "user", V1: "texture", V2: "update_own"},
|
||||
{PType: "p", V0: "user", V1: "texture", V2: "delete_own"},
|
||||
{PType: "p", V0: "user", V1: "profile", V2: "create"},
|
||||
{PType: "p", V0: "user", V1: "profile", V2: "read"},
|
||||
{PType: "p", V0: "user", V1: "profile", V2: "update_own"},
|
||||
{PType: "p", V0: "user", V1: "profile", V2: "delete_own"},
|
||||
{PType: "p", V0: "user", V1: "user", V2: "update_own"},
|
||||
// 角色继承:admin 继承 user 的所有权限
|
||||
{PType: "g", V0: "admin", V1: "user"},
|
||||
}
|
||||
|
||||
// Seed 初始化种子数据
|
||||
func Seed(logger *zap.Logger) error {
|
||||
db, err := GetDB()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Info("开始初始化种子数据...")
|
||||
|
||||
// 初始化默认管理员用户
|
||||
if err := seedAdminUser(db, logger); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 初始化系统配置
|
||||
if err := seedSystemConfigs(db, logger); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 初始化Casbin权限规则
|
||||
if err := seedCasbinRules(db, logger); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Info("种子数据初始化完成")
|
||||
return nil
|
||||
}
|
||||
|
||||
// seedAdminUser 初始化默认管理员用户
|
||||
func seedAdminUser(db *gorm.DB, logger *zap.Logger) error {
|
||||
// 检查是否已存在管理员用户
|
||||
var count int64
|
||||
if err := db.Model(&model.User{}).Where("role = ?", "admin").Count(&count).Error; err != nil {
|
||||
logger.Error("检查管理员用户失败", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
// 如果已存在管理员,跳过创建
|
||||
if count > 0 {
|
||||
logger.Info("管理员用户已存在,跳过创建")
|
||||
return nil
|
||||
}
|
||||
|
||||
// 加密密码
|
||||
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(defaultAdminPassword), bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
logger.Error("密码加密失败", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
// 创建默认管理员
|
||||
admin := &model.User{
|
||||
Username: defaultAdminUsername,
|
||||
Email: defaultAdminEmail,
|
||||
Password: string(hashedPassword),
|
||||
Role: "admin",
|
||||
Status: 1,
|
||||
Points: 0,
|
||||
}
|
||||
|
||||
if err := db.Create(admin).Error; err != nil {
|
||||
logger.Error("创建管理员用户失败", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Info("默认管理员用户创建成功",
|
||||
zap.String("username", defaultAdminUsername),
|
||||
zap.String("email", defaultAdminEmail),
|
||||
)
|
||||
logger.Warn("请立即登录并修改默认管理员密码!默认密码请查看源码中的 defaultAdminPassword 常量")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// seedSystemConfigs 初始化系统配置
|
||||
func seedSystemConfigs(db *gorm.DB, logger *zap.Logger) error {
|
||||
for _, config := range defaultSystemConfigs {
|
||||
// 使用 FirstOrCreate 避免重复插入
|
||||
var existing model.SystemConfig
|
||||
result := db.Where("key = ?", config.Key).First(&existing)
|
||||
if result.Error == gorm.ErrRecordNotFound {
|
||||
if err := db.Create(&config).Error; err != nil {
|
||||
logger.Error("创建系统配置失败", zap.String("key", config.Key), zap.Error(err))
|
||||
return err
|
||||
}
|
||||
logger.Info("创建系统配置", zap.String("key", config.Key))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// seedCasbinRules 初始化Casbin权限规则
|
||||
func seedCasbinRules(db *gorm.DB, logger *zap.Logger) error {
|
||||
for _, rule := range defaultCasbinRules {
|
||||
// 检查规则是否已存在
|
||||
var existing model.CasbinRule
|
||||
query := db.Where("ptype = ? AND v0 = ? AND v1 = ? AND v2 = ?", rule.PType, rule.V0, rule.V1, rule.V2)
|
||||
result := query.First(&existing)
|
||||
if result.Error == gorm.ErrRecordNotFound {
|
||||
if err := db.Create(&rule).Error; err != nil {
|
||||
logger.Error("创建Casbin规则失败", zap.String("ptype", rule.PType), zap.Error(err))
|
||||
return err
|
||||
}
|
||||
logger.Info("创建Casbin规则", zap.String("ptype", rule.PType), zap.String("v0", rule.V0), zap.String("v1", rule.V1))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -82,6 +82,11 @@ func (c *Client) Expire(ctx context.Context, key string, expiration time.Duratio
|
||||
return c.Client.Expire(ctx, key, expiration).Err()
|
||||
}
|
||||
|
||||
// TTL 获取键的剩余过期时间
|
||||
func (c *Client) TTL(ctx context.Context, key string) (time.Duration, error) {
|
||||
return c.Client.TTL(ctx, key).Result()
|
||||
}
|
||||
|
||||
// Incr 自增
|
||||
func (c *Client) Incr(ctx context.Context, key string) (int64, error) {
|
||||
return c.Client.Incr(ctx, key).Result()
|
||||
|
||||
Reference in New Issue
Block a user