package infrastructure import ( "context" "strings" "mengstack/internal/modules/rbac/domain" "go.uber.org/zap" "gorm.io/gorm" ) type permDef struct { Code string Name string Module string Desc string } var defaultPermissions = []permDef{ {"auth.user.read", "查看用户", "auth", "查看用户列表和详情"}, {"auth.user.write", "管理用户", "auth", "创建、编辑、删除用户"}, {"rbac.role.read", "查看角色", "rbac", "查看角色列表和详情"}, {"rbac.role.write", "管理角色", "rbac", "创建、编辑、删除角色"}, {"rbac.permission.read", "查看权限", "rbac", "查看权限列表"}, {"rbac.permission.assign", "分配权限", "rbac", "为角色分配权限"}, {"rbac.user_role.write", "分配角色", "rbac", "为用户分配角色"}, } func Seed(db *gorm.DB, log *zap.Logger) error { ctx := context.Background() for _, p := range defaultPermissions { var count int64 db.Model(&domain.Permission{}).Where("code = ?", p.Code).Count(&count) if count > 0 { continue } perm := &domain.Permission{ Code: p.Code, Name: p.Name, Module: p.Module, Description: p.Desc, } if err := db.WithContext(ctx).Create(perm).Error; err != nil { return err } log.Info("seeded permission", zap.String("code", p.Code)) } var allPerms []domain.Permission if err := db.WithContext(ctx).Find(&allPerms).Error; err != nil { return err } if len(allPerms) == 0 { return nil } var tenantIDs []string if err := db.WithContext(ctx).Table("users").Distinct("tenant_id"). Pluck("tenant_id", &tenantIDs).Error; err != nil { return err } for _, tid := range tenantIDs { if err := seedTenantRoles(ctx, db, log, tid, allPerms); err != nil { log.Error("seed tenant roles failed", zap.String("tenant_id", tid), zap.Error(err), ) } } return nil } func seedTenantRoles(ctx context.Context, db *gorm.DB, log *zap.Logger, tenantID string, allPerms []domain.Permission) error { superAdmin := &domain.Role{} err := db.WithContext(ctx). Where("tenant_id = ? AND name = ?", tenantID, "super_admin"). First(superAdmin).Error if err == gorm.ErrRecordNotFound { superAdmin = &domain.Role{ TenantID: tenantID, Name: "super_admin", Description: "超级管理员", IsSystem: true, } if err := db.WithContext(ctx).Create(superAdmin).Error; err != nil { return err } permRefs := make([]domain.Permission, len(allPerms)) copy(permRefs, allPerms) if err := db.WithContext(ctx).Model(superAdmin).Association("Permissions").Replace(permRefs); err != nil { return err } log.Info("seeded super_admin role", zap.String("tenant_id", tenantID)) } else if err != nil { return err } tenantAdmin := &domain.Role{} err = db.WithContext(ctx). Where("tenant_id = ? AND name = ?", tenantID, "tenant_admin"). First(tenantAdmin).Error if err == gorm.ErrRecordNotFound { tenantAdmin = &domain.Role{ TenantID: tenantID, Name: "tenant_admin", Description: "租户管理员", IsSystem: true, } if err := db.WithContext(ctx).Create(tenantAdmin).Error; err != nil { return err } adminPermCodes := []string{ "auth.user.read", "auth.user.write", "rbac.role.read", "rbac.permission.read", "rbac.user_role.write", } var adminPerms []domain.Permission for _, p := range allPerms { for _, code := range adminPermCodes { if p.Code == code { adminPerms = append(adminPerms, p) break } } } if len(adminPerms) > 0 { if err := db.WithContext(ctx).Model(tenantAdmin).Association("Permissions").Replace(adminPerms); err != nil { return err } } log.Info("seeded tenant_admin role", zap.String("tenant_id", tenantID)) } else if err != nil { return err } member := &domain.Role{} err = db.WithContext(ctx). Where("tenant_id = ? AND name = ?", tenantID, "member"). First(member).Error if err == gorm.ErrRecordNotFound { member = &domain.Role{ TenantID: tenantID, Name: "member", Description: "普通成员", IsSystem: true, } if err := db.WithContext(ctx).Create(member).Error; err != nil { return err } memberPermCodes := []string{"auth.user.read", "rbac.permission.read"} var memberPerms []domain.Permission for _, p := range allPerms { for _, code := range memberPermCodes { if strings.EqualFold(p.Code, code) { memberPerms = append(memberPerms, p) break } } } if len(memberPerms) > 0 { if err := db.WithContext(ctx).Model(member).Association("Permissions").Replace(memberPerms); err != nil { return err } } log.Info("seeded member role", zap.String("tenant_id", tenantID)) } else if err != nil { return err } return nil }