loko/streetup/controls/permissions.py
2026-07-22 14:48:40 +02:00

144 lines
No EOL
4.9 KiB
Python

from functools import wraps
from django.http import HttpResponseForbidden
from django.shortcuts import get_object_or_404
from django.utils.translation import gettext as _
from controls.models import Control
from projects.models import ProjectUserAccess
from common.models import UserThematics
def user_can_view_control(user, control):
if hasattr(user, "config") and user.config.roles.filter(name__in=['admin', 'top_manager']).exists():
return True
if control.control_author == user:
return True
if hasattr(control, "visibility") and control.visibility == 'private':
return user == control.control_author
if hasattr(control, "visibility") and control.visibility == 'intern' and ((not hasattr(user, "config")) or user.config.is_intern == False):
return False
if control.project:
has_project_access = ProjectUserAccess.objects.filter(project=control.project, user=user, can_view=True).exists()
if has_project_access:
return True
# Fallback thématique : les contrôles privés sont déjà gérés plus haut ;
# les non-internes sont bloqués à l'étape visibility=='intern' ci-dessus.
# Un interne ayant accès à l'une des thématiques du contrôle peut donc le voir.
if control.thematics.exists() and hasattr(user, "config") and user.config.is_intern:
return UserThematics.objects.filter(
user_config=user.config,
thematic__in=control.thematics.all(),
can_view_interventions=True
).exists()
return False
if control.thematics.exists() and hasattr(user, "config") and user.config.is_intern:
return UserThematics.objects.filter(
user_config=user.config,
thematic__in=control.thematics.all(),
can_view_interventions=True
).exists()
return False
def control_view_required(view_func):
@wraps(view_func)
def _wrapped_view(request, control_id, *args, **kwargs):
control = get_object_or_404(Control, id=control_id)
if user_can_view_control(request.user, control):
return view_func(request, control_id, *args, **kwargs)
return HttpResponseForbidden(_("Vous n'êtes pas autorisé à accéder à ce contrôle."))
return _wrapped_view
def user_can_add_control(user):
if hasattr(user, "config") and user.config.roles.filter(name__in=['admin', 'manager', 'controller']).exists():
return True
return False
def control_add_required(view_func):
@wraps(view_func)
def _wrapped_view(request, *args, **kwargs):
if user_can_add_control(request.user):
return view_func(request, *args, **kwargs)
return HttpResponseForbidden(_("Vous n'êtes pas autorisé à ajouter un contrôle."))
return _wrapped_view
def user_can_change_control(user, control):
if not hasattr(user, "config"):
return False
if user.config.roles.filter(name__in=["admin"]).exists():
return True
if not control.shared_edition:
return user == control.control_author
# 1. L'utilisateur doit avoir un rôle suffisant
has_permission_role = (
hasattr(user, "config") and
user.config.roles.filter(name__in=["manager", "controller"]).exists()
)
# 2. L'utilisateur doit pouvoir voir ce contrôle
can_view = user_can_view_control(user, control)
return has_permission_role and can_view
def control_change_required(view_func):
@wraps(view_func)
def _wrapped_view(request, control_id, *args, **kwargs):
control = get_object_or_404(Control, id=control_id)
if user_can_change_control(request.user, control):
return view_func(request, control_id, *args, **kwargs)
return HttpResponseForbidden(_("Vous n'êtes pas autorisé à modifier ce contrôle."))
return _wrapped_view
# ============================================================================
# Guards pour les fichiers privés (private_media)
# ============================================================================
def guard_control_report_document(obj, user):
"""
Guard pour ControlReport.document.
L'utilisateur doit pouvoir voir le contrôle associé.
"""
if not user.is_authenticated:
return False
return user_can_view_control(user, obj.control)
def guard_control_reference_plan(obj, user):
"""
Guard pour ControlReferencePlan.plan.
L'utilisateur doit pouvoir voir le contrôle associé.
"""
if not user.is_authenticated:
return False
return user_can_view_control(user, obj.control)
def guard_remark_image_file(obj, user):
"""
Guard pour RemarkImage.file et thumbnail.
L'utilisateur doit pouvoir voir le contrôle associé à la remarque.
"""
if not user.is_authenticated:
return False
return user_can_view_control(user, obj.remark.control)