45 lines
1.6 KiB
Python
45 lines
1.6 KiB
Python
"""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)]
|
|
|