gmao/app_new/core/services/rbac.py

46 lines
1.6 KiB
Python
Raw Normal View History

"""Services transactionnels pour la gestion des rôles RBAC.
Les fonctions de ce module ne valident ni ne commitent la transaction appelante.
Cela permet aux routes d'enregistrer simultanément l'utilisateur et ses accès.
"""
from ...extensions import db
from ..models.rbac import Role, UserRole
def replace_user_roles(user, role_ids, assigned_by=None):
"""Remplace l'ensemble des rôles actifs d'un utilisateur.
Les liens déjà sélectionnés sont conservés (et donc leur traçabilité), les
liens absents sont retirés et les nouveaux sont ajoutés sans doublon.
``role_ids`` peut être vide. Les rôles inactifs ou inconnus sont ignorés.
La fonction travaille dans la transaction courante et ne committe jamais.
"""
normalized_ids = set()
for value in role_ids or ():
try:
normalized_ids.add(int(value))
except (TypeError, ValueError):
continue
active_roles = {
role.id: role
for role in Role.query.filter(Role.id.in_(normalized_ids), Role.is_active.is_(True)).all()
} if normalized_ids else {}
selected_ids = set(active_roles)
existing = {link.role_id: link for link in list(user.role_links)}
for role_id, link in existing.items():
if role_id not in selected_ids:
db.session.delete(link)
for role_id in selected_ids - set(existing):
db.session.add(UserRole(
user_id=user.id,
role_id=role_id,
assigned_by_id=getattr(assigned_by, "id", assigned_by),
))
return [active_roles[role_id] for role_id in sorted(selected_ids)]