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)