119 lines
No EOL
4.1 KiB
Python
119 lines
No EOL
4.1 KiB
Python
from django.http import HttpResponseForbidden, HttpResponseRedirect, JsonResponse
|
|
from django.urls import reverse
|
|
from django.shortcuts import get_object_or_404
|
|
from django.db.models import Func, CharField
|
|
|
|
from urllib.parse import urlencode
|
|
import time
|
|
import functools
|
|
import unicodedata
|
|
|
|
from common.models import Thematic, UserConfig, UserThematics
|
|
|
|
|
|
def check_thematic_access(thematic_code, edit_permission_required=False):
|
|
"""Decorator to verify user access to a specific thematic (passed as a parameter)."""
|
|
|
|
def decorator(view_func):
|
|
@functools.wraps(view_func)
|
|
def _wrapped_view(request, *args, **kwargs):
|
|
user_config = UserConfig.objects.filter(user=request.user).first() # Get user access configuration
|
|
thematic = get_object_or_404(Thematic, code=thematic_code) # Get thematic from the given parameter
|
|
|
|
# Check if the user has a configuration
|
|
if not user_config:
|
|
return HttpResponseForbidden("Access denied: You do not have access to this thematic.")
|
|
|
|
# Check if the user has access to the thematic
|
|
if edit_permission_required:
|
|
if not UserThematics.objects.filter(
|
|
user_config=user_config,
|
|
thematic=thematic,
|
|
can_edit_assets=True
|
|
).exists():
|
|
return HttpResponseForbidden("Access denied: You do not have edit permissions for this thematic.")
|
|
else:
|
|
# Si l'utilisateur a un rôle 'admin' ou 'operator', il peut voir tous les assets
|
|
if (
|
|
(not user_config.roles.filter(name__in=['admin','operator']).exists())
|
|
and
|
|
(not UserThematics.objects.filter(
|
|
user_config=user_config,
|
|
thematic=thematic,
|
|
can_view_assets=True
|
|
).exists())
|
|
):
|
|
return HttpResponseForbidden("Access denied: You do not have view permissions for this thematic.")
|
|
|
|
# Execute the view if everything is OK
|
|
return view_func(request, *args, **kwargs)
|
|
|
|
return _wrapped_view
|
|
|
|
return decorator
|
|
|
|
|
|
def redirect_with_variant(viewname, variant=None, url_kwargs=None, extra_query_params=None):
|
|
"""
|
|
Redirige vers une vue avec des paramètres d'URL et le paramètre ?v=... si fourni.
|
|
|
|
:param viewname: nom de la vue (ex: 'controls:controls_detail')
|
|
:param variant: 'mobile' ou 'desktop' (ajouté comme ?v=mobile dans l'URL)
|
|
:param url_kwargs: dictionnaire des arguments de reverse (ex: {'control_id': 3})
|
|
:param extra_query_params: dictionnaire de paramètres supplémentaires à ajouter dans la query string
|
|
"""
|
|
if url_kwargs is None:
|
|
url_kwargs = {}
|
|
if extra_query_params is None:
|
|
extra_query_params = {}
|
|
|
|
if variant:
|
|
extra_query_params['v'] = variant
|
|
|
|
base_url = reverse(viewname, kwargs=url_kwargs)
|
|
|
|
if extra_query_params:
|
|
query_string = urlencode(extra_query_params)
|
|
full_url = f"{base_url}?{query_string}"
|
|
else:
|
|
full_url = base_url
|
|
|
|
return HttpResponseRedirect(full_url)
|
|
|
|
|
|
|
|
def measure_time(func):
|
|
@functools.wraps(func)
|
|
def wrapper(*args, **kwargs):
|
|
start = time.time()
|
|
response = func(*args, **kwargs)
|
|
elapsed = time.time() - start
|
|
print(f"{func.__name__} exécutée en {elapsed:.4f} secondes")
|
|
return response
|
|
return wrapper
|
|
|
|
|
|
|
|
# Appelle la fonction PostgreSQL unaccent(...)
|
|
class Unaccent(Func):
|
|
function = 'public.unaccent_immutable'
|
|
output_field = CharField()
|
|
|
|
def strip_accents_lower(s: str) -> str:
|
|
if not s:
|
|
return ''
|
|
s = ''.join(c for c in unicodedata.normalize('NFD', s) if unicodedata.category(c) != 'Mn')
|
|
return s.lower()
|
|
|
|
|
|
|
|
def get_short_name(user):
|
|
"""
|
|
Retourne 'Prénom N.' à partir d'un objet User.
|
|
"""
|
|
if not user:
|
|
return ""
|
|
first = getattr(user, "first_name", "") or ""
|
|
last = getattr(user, "last_name", "") or ""
|
|
initial = (last[0].upper() + ".") if last else ""
|
|
return f"{first} {initial}".strip() |