156 lines
5.3 KiB
Go
156 lines
5.3 KiB
Go
package services
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
|
|
"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
|
|
}
|