package repository import ( "errors" "hyapp-admin-server/internal/model" "gorm.io/gorm" ) func (s *Store) ListPermissions() ([]model.Permission, error) { var permissions []model.Permission err := s.db.Order("kind ASC, code ASC").Find(&permissions).Error return permissions, err } func (s *Store) CreatePermission(permission *model.Permission) error { normalized, err := normalizePermission(*permission) if err != nil { return err } *permission = normalized return s.db.Create(permission).Error } func (s *Store) UpdatePermission(id uint, patch model.Permission) (*model.Permission, error) { normalized, err := normalizePermission(patch) if err != nil { return nil, err } var permission model.Permission if err := s.db.First(&permission, id).Error; err != nil { return nil, err } // 权限码会写入 JWT 和前端按钮判断,更新时必须整体校验后一次性落库。 updates := map[string]any{ "name": normalized.Name, "code": normalized.Code, "kind": normalized.Kind, "description": normalized.Description, } if err := s.db.Model(&permission).Updates(updates).Error; err != nil { return nil, err } if err := s.db.First(&permission, id).Error; err != nil { return nil, err } return &permission, nil } func (s *Store) DeletePermission(id uint) error { var roleCount int64 if err := s.db.Table("admin_role_permissions").Where("permission_id = ?", id).Count(&roleCount).Error; err != nil { return err } if roleCount > 0 { return errors.New("permission is bound to roles") } // Menus reference permission_code by string, so deletion must check the code before removing the definition. var menuCount int64 if err := s.db.Model(&model.Menu{}).Where("permission_code = (SELECT code FROM admin_permissions WHERE id = ?)", id).Count(&menuCount).Error; err != nil { return err } if menuCount > 0 { return errors.New("permission is bound to menus") } return s.db.Delete(&model.Permission{}, id).Error } func (s *Store) SyncDefaultPermissions() error { return s.db.Transaction(func(tx *gorm.DB) error { if err := s.syncDefaultPermissions(tx); err != nil { return err } return s.syncDefaultRolePermissionMigrations(tx) }) } func (s *Store) syncDefaultRolePermissionMigrations(tx *gorm.DB) error { var platformAdmin model.Role err := tx.Where("code = ?", "platform-admin").First(&platformAdmin).Error if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { return err } if platformAdmin.ID > 0 { var permissions []model.Permission if err := tx.Find(&permissions).Error; err != nil { return err } if err := tx.Model(&platformAdmin).Association("Permissions").Replace(permissions); err != nil { return err } } var opsAdmin model.Role err = tx.Where("code = ?", "ops-admin").First(&opsAdmin).Error if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { return err } if opsAdmin.ID > 0 { return s.appendRolePermissionsByCode(tx, &opsAdmin, defaultRolePermissionMigrationCodes(opsAdmin.Code)) } return nil } func (s *Store) ListRoles() ([]model.Role, error) { var roles []model.Role err := s.db.Preload("Permissions").Order("id ASC").Find(&roles).Error return roles, err } func (s *Store) CreateRole(role *model.Role, permissionIDs []uint) error { return s.db.Transaction(func(tx *gorm.DB) error { if err := tx.Create(role).Error; err != nil { return err } if len(permissionIDs) == 0 { return nil } var permissions []model.Permission if err := tx.Where("id IN ?", permissionIDs).Find(&permissions).Error; err != nil { return err } return tx.Model(role).Association("Permissions").Replace(permissions) }) } func (s *Store) UpdateRole(roleID uint, patch model.Role, permissionIDs *[]uint) (*model.Role, error) { var role model.Role if err := s.db.First(&role, roleID).Error; err != nil { return nil, err } err := s.db.Transaction(func(tx *gorm.DB) error { updates := map[string]any{ "name": patch.Name, "code": patch.Code, "description": patch.Description, } if err := tx.Model(&role).Updates(updates).Error; err != nil { return err } if permissionIDs != nil { var permissions []model.Permission if len(*permissionIDs) > 0 { if err := tx.Where("id IN ?", *permissionIDs).Find(&permissions).Error; err != nil { return err } } if err := tx.Model(&role).Association("Permissions").Replace(permissions); err != nil { return err } } return nil }) if err != nil { return nil, err } if err := s.db.Preload("Permissions").First(&role, roleID).Error; err != nil { return nil, err } return &role, nil } func (s *Store) DeleteRole(roleID uint) error { var users int64 if err := s.db.Table("admin_user_roles").Where("role_id = ?", roleID).Count(&users).Error; err != nil { return err } if users > 0 { return errors.New("role is bound to users") } return s.db.Delete(&model.Role{}, roleID).Error } func (s *Store) ReplaceRolePermissions(roleID uint, permissionIDs []uint) error { var role model.Role if err := s.db.First(&role, roleID).Error; err != nil { return err } var permissions []model.Permission if len(permissionIDs) > 0 { if err := s.db.Where("id IN ?", permissionIDs).Find(&permissions).Error; err != nil { return err } } return s.db.Model(&role).Association("Permissions").Replace(permissions) }