package services import ( "context" "errors" "fmt" "github.com/google/uuid" "time" "veza-backend-api/internal/models" "gorm.io/gorm" ) // RoleService gère les rôles et permissions type RoleService struct { db *gorm.DB } // NewRoleService crée un nouveau service de rôles func NewRoleService(db *gorm.DB) *RoleService { return &RoleService{db: db} } // GetRoles récupère tous les rôles avec leurs permissions func (s *RoleService) GetRoles(ctx context.Context) ([]models.Role, error) { var roles []models.Role if err := s.db.WithContext(ctx).Preload("Permissions").Find(&roles).Error; err != nil { return nil, fmt.Errorf("failed to get roles: %w", err) } return roles, nil } // GetRole récupère un rôle par son ID avec ses permissions func (s *RoleService) GetRole(ctx context.Context, roleID uuid.UUID) (*models.Role, error) { var role models.Role if err := s.db.WithContext(ctx).Preload("Permissions").First(&role, roleID).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil, fmt.Errorf("role not found") } return nil, fmt.Errorf("failed to get role: %w", err) } return &role, nil } // CreateRole crée un nouveau rôle func (s *RoleService) CreateRole(ctx context.Context, role *models.Role) error { if err := s.db.WithContext(ctx).Create(role).Error; err != nil { return fmt.Errorf("failed to create role: %w", err) } return nil } // UpdateRole met à jour un rôle (seulement les rôles non-système) func (s *RoleService) UpdateRole(ctx context.Context, roleID uuid.UUID, updates *models.Role) error { result := s.db.WithContext(ctx).Model(&models.Role{}).Where("id = ? AND is_system = ?", roleID, false).Updates(updates) if result.Error != nil { return fmt.Errorf("failed to update role: %w", result.Error) } if result.RowsAffected == 0 { return fmt.Errorf("role not found or is system role") } return nil } // DeleteRole supprime un rôle (seulement les rôles non-système) func (s *RoleService) DeleteRole(ctx context.Context, roleID uuid.UUID) error { var role models.Role if err := s.db.WithContext(ctx).First(&role, roleID).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return fmt.Errorf("role not found") } return fmt.Errorf("failed to get role: %w", err) } if role.IsSystem { return fmt.Errorf("cannot delete system role") } if err := s.db.WithContext(ctx).Delete(&role).Error; err != nil { return fmt.Errorf("failed to delete role: %w", err) } return nil } // AssignRoleToUser assigne un rôle à un utilisateur // MIGRATION UUID: userID, roleID et assignedBy migrés vers uuid.UUID func (s *RoleService) AssignRoleToUser(ctx context.Context, userID uuid.UUID, roleID uuid.UUID, assignedBy uuid.UUID, expiresAt *time.Time) error { userRole := &models.UserRole{ UserID: userID, RoleID: roleID, AssignedBy: &assignedBy, // UUID AssignedAt: time.Now(), ExpiresAt: expiresAt, IsActive: true, } if err := s.db.WithContext(ctx).Create(userRole).Error; err != nil { return fmt.Errorf("failed to assign role: %w", err) } return nil } // RevokeRoleFromUser révoque un rôle d'un utilisateur func (s *RoleService) RevokeRoleFromUser(ctx context.Context, userID uuid.UUID, roleID uuid.UUID) error { result := s.db.WithContext(ctx).Model(&models.UserRole{}). Where("user_id = ? AND role_id = ?", userID, roleID). Update("is_active", false) if result.Error != nil { return fmt.Errorf("failed to revoke role: %w", result.Error) } if result.RowsAffected == 0 { return fmt.Errorf("role assignment not found") } return nil } // GetUserRoles récupère tous les rôles actifs d'un utilisateur func (s *RoleService) GetUserRoles(ctx context.Context, userID uuid.UUID) ([]models.Role, error) { var roles []models.Role if err := s.db.WithContext(ctx). Table("roles"). Joins("JOIN user_roles ON roles.id = user_roles.role_id"). Where("user_roles.user_id = ? AND user_roles.is_active = ?", userID, true). Preload("Permissions"). Find(&roles).Error; err != nil { return nil, fmt.Errorf("failed to get user roles: %w", err) } return roles, nil } // HasRole vérifie si un utilisateur a un rôle spécifique func (s *RoleService) HasRole(ctx context.Context, userID uuid.UUID, roleName string) (bool, error) { var count int64 if err := s.db.WithContext(ctx). Table("user_roles"). Joins("JOIN roles ON user_roles.role_id = roles.id"). Where("user_roles.user_id = ? AND user_roles.is_active = ? AND roles.name = ?", userID, true, roleName). Count(&count).Error; err != nil { return false, fmt.Errorf("failed to check role: %w", err) } return count > 0, nil } // HasPermission vérifie si un utilisateur a une permission spécifique via ses rôles func (s *RoleService) HasPermission(ctx context.Context, userID uuid.UUID, resource, action string) (bool, error) { var count int64 if err := s.db.WithContext(ctx). Table("permissions"). Joins("JOIN role_permissions ON permissions.id = role_permissions.permission_id"). Joins("JOIN user_roles ON role_permissions.role_id = user_roles.role_id"). Where("user_roles.user_id = ? AND user_roles.is_active = ? AND permissions.resource = ? AND permissions.action = ?", userID, true, resource, action). Count(&count).Error; err != nil { return false, fmt.Errorf("failed to check permission: %w", err) } return count > 0, nil }