init
This commit is contained in:
292
backend-django/backend/views/commun.py
Normal file
292
backend-django/backend/views/commun.py
Normal file
@@ -0,0 +1,292 @@
|
||||
# --------------------------------------------------------------------------------
|
||||
"""
|
||||
Définitions communes à plusieurs vues
|
||||
"""
|
||||
# --------------------------------------------------------------------------------
|
||||
|
||||
from django.db.models import Q
|
||||
from rest_framework.exceptions import APIException
|
||||
from rest_framework.permissions import SAFE_METHODS, BasePermission
|
||||
|
||||
from ..models import Administre, Decision, Poste, SpecifiqueChoices, Administres_Pams, Postes_Pams
|
||||
|
||||
from ..utils.decorators import (class_logger, decorate_functions,
|
||||
execution_time, query_count)
|
||||
from ..utils.permissions import (Profiles, KEY_READ, KEY_WRITE,
|
||||
get_profile_summary,
|
||||
get_adm_filter_by_lvl4_codes_fil,
|
||||
get_adm_filter_by_lvl4_codes_future_pcp,
|
||||
get_adm_filter_by_lvl4_codes_pcp,
|
||||
get_lvl4_org_codes_by_any_code,
|
||||
get_poste_filter_by_lvl4_codes_fil,
|
||||
get_poste_filter_by_lvl4_codes_pcp,
|
||||
get_queryset_org_by_user, is_truthy)
|
||||
from ..utils.view_predicates import viewset_functions
|
||||
|
||||
# décorateur pour tracer le temps d'exécution d'une vue
|
||||
execution_time_viewset = decorate_functions(
|
||||
lambda cls: execution_time(warn_after=5000, logger_name=cls),
|
||||
viewset_functions,
|
||||
factory=True
|
||||
)
|
||||
|
||||
# décorateur pour tracer le nombre de requêtes d'une vue
|
||||
query_count_viewset = decorate_functions(
|
||||
lambda cls: query_count(warn_after=20, logger_name=cls),
|
||||
viewset_functions,
|
||||
factory=True
|
||||
)
|
||||
|
||||
def api_exception(status_code: int, message: str = None) -> APIException:
|
||||
"""
|
||||
Crée une APIException avec un statut personnalisé.
|
||||
note : inutile d'appeler cette fonction pour un code 500 car APIException(message) suffit
|
||||
|
||||
:param status_code: code de statut HTTP
|
||||
:type status_code: int
|
||||
|
||||
:param message: message de l'exception
|
||||
:type message: str, optional
|
||||
|
||||
:return: exception
|
||||
:rtype: class:`APIException`
|
||||
"""
|
||||
return type('MyException', (APIException,), {'status_code': status_code, 'default_detail': message})
|
||||
|
||||
|
||||
@class_logger
|
||||
class GestionnairePermission(BasePermission):
|
||||
"""
|
||||
Classe de gestion des droits de lecture et d'écriture d'un gestionnaire
|
||||
"""
|
||||
message = "Le gestionnaire n'a pas les droits de lecture ou d'écriture"
|
||||
|
||||
def is_in_list_ok(self, list, list_ok): # A modif en utilisant set
|
||||
"""
|
||||
Cette fonction vérifie que tous les objets de la liste list soient dans la liste list_ok
|
||||
|
||||
:param list: liste 1
|
||||
:type list: list
|
||||
|
||||
:param list: liste 2
|
||||
:type list: list
|
||||
|
||||
:return: booléen indiquant si les objets de la liste 1 sont dans la liste 2
|
||||
:rtype: bool
|
||||
"""
|
||||
for obj in list:
|
||||
if obj not in list_ok:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def verif_droits_adm(self, pk, codes_lvl4, is_fil, is_pcp, is_bvt):
|
||||
"""
|
||||
Cette fonction vérifie si le gestionnaire a bien le droit de modifier (mettre à jour)
|
||||
les attributs du ou des administres d'identifiant pk.
|
||||
|
||||
:param pk: id sap du ou des administrés édités
|
||||
:type org_code: int ou list
|
||||
|
||||
:param codes_lvl4: codes de niveau 4 des référentiels organiques liés à l'utilisateur
|
||||
:type codes_lvl4: Tuple[str]
|
||||
|
||||
:param is_fil: profil filiere
|
||||
:type is_fil: bool
|
||||
|
||||
:param is_pcp: profil pcp
|
||||
:type is_pcp: bool
|
||||
|
||||
:param is_bvt: profil bvt
|
||||
:type is_bvt: bool
|
||||
|
||||
:return: booléen pour indiqué si l'utilisateur a les droits ou non sur l'édition
|
||||
du ou des administrés concernés
|
||||
:rtype: bool
|
||||
"""
|
||||
# On récupère le ou les administrés dont l'id match avec pk (liste ou non)
|
||||
qs = Administre.objects.filter(a_id_sap__in=pk) if isinstance(pk, list) else Administre.objects.filter(a_id_sap=pk)
|
||||
list_a = list(qs.values_list('pk', flat=True))
|
||||
|
||||
# On récupère le ou les administrés autorisés
|
||||
adm_filter = None
|
||||
if is_fil:
|
||||
adm_filter = get_adm_filter_by_lvl4_codes_fil(codes_lvl4)
|
||||
if is_pcp:
|
||||
pcp_filter = get_adm_filter_by_lvl4_codes_pcp(codes_lvl4) | get_adm_filter_by_lvl4_codes_future_pcp(codes_lvl4)
|
||||
adm_filter = adm_filter | pcp_filter if adm_filter else pcp_filter
|
||||
if is_bvt:
|
||||
bvt_filter = Q(**{f'{Administres_Pams.Cols.REL_ADMINISTRE}__{Administre.Cols.REL_SOUS_VIVIER}': 'BVT'})
|
||||
adm_filter = adm_filter | bvt_filter if adm_filter else bvt_filter
|
||||
|
||||
list_a_ok = Administres_Pams.objects.filter(adm_filter).values_list('administre_id', flat=True)
|
||||
perm = self.is_in_list_ok(list_a, list_a_ok)
|
||||
|
||||
msg = 'Administre rights verification ok\n' if perm else 'Administre rights verification not ok\n'
|
||||
self.logger.debug(msg)
|
||||
|
||||
return perm
|
||||
|
||||
|
||||
def verif_droits_poste(self, pk, codes_lvl4, is_fil, is_pcp, is_bvt, is_itd):
|
||||
"""
|
||||
Cette fonction vérifie si le gestionnaire a bien le droit de modifier (mettre à jour)
|
||||
les attributs du ou des postes d'identifiant pk.
|
||||
|
||||
:param pk: id sap du ou des administrés édités
|
||||
:type org_code: int ou list
|
||||
|
||||
:param codes_lvl4: codes de niveau 4 des référentiels organiques liés à l'utilisateur
|
||||
:type codes_lvl4: Tuple[str]
|
||||
|
||||
:param is_fil: profil filiere
|
||||
:type is_fil: bool
|
||||
|
||||
:param is_pcp: profil pcp
|
||||
:type is_pcp: bool
|
||||
|
||||
:param is_bvt: profil bvt
|
||||
:type is_bvt: bool
|
||||
|
||||
:param is_itd: profil itd
|
||||
:type is_itd: bool
|
||||
|
||||
:return: booléen pour indiqué si l'utilisateur a les droits ou non sur l'édition
|
||||
du ou des postes concernés
|
||||
:rtype: bool
|
||||
"""
|
||||
# On récupère le ou les postes dont l'id match avec pk (liste ou non)
|
||||
qs = Poste.objects.filter(p_id__in=pk) if isinstance(pk, list) else Poste.objects.filter(p_id=pk)
|
||||
list_p = list(qs.values_list('pk', flat=True))
|
||||
|
||||
# On créer le filtre avec le ou les postes autorisés
|
||||
poste_filter = None
|
||||
if is_fil:
|
||||
poste_filter = get_poste_filter_by_lvl4_codes_fil(codes_lvl4)
|
||||
if is_pcp:
|
||||
pcp_filter = get_poste_filter_by_lvl4_codes_pcp(codes_lvl4)
|
||||
poste_filter = poste_filter | pcp_filter if poste_filter else pcp_filter
|
||||
if is_itd:
|
||||
itd_filter = Q(**{f'{Postes_Pams.Cols.REL_POSTE}__p_specifique' : SpecifiqueChoices.ITD})
|
||||
poste_filter = poste_filter | itd_filter if poste_filter else itd_filter
|
||||
if is_bvt:
|
||||
bvt_filter = Q(**{f'{Postes_Pams.Cols.REL_POSTE}__{Poste.Cols.M2M_SOUS_VIVIERS}': 'BVT'})
|
||||
poste_filter = poste_filter | bvt_filter if poste_filter else bvt_filter
|
||||
|
||||
list_p_ok = Postes_Pams.objects.filter(poste_filter).values_list('poste_id', flat=True)
|
||||
perm = self.is_in_list_ok(list_p, list_p_ok)
|
||||
|
||||
msg = 'Poste rights verification ok\n' if perm else 'Poste rights verification not ok\n'
|
||||
self.logger.debug(msg)
|
||||
|
||||
return perm
|
||||
|
||||
|
||||
def commun_verif(self, request, view, obj=None):
|
||||
"""
|
||||
Partie commune de la vérification des droits de lecture aux fonctions has_permission et has_object_permission
|
||||
"""
|
||||
P = Profiles
|
||||
|
||||
user = request.user
|
||||
if not user or not user.is_authenticated:
|
||||
self.logger.debug('No user connected\n')
|
||||
return False
|
||||
|
||||
is_super = user.is_superuser
|
||||
|
||||
if is_super and str(view) in ['ReportingView']:
|
||||
self.logger.debug('Rights verification ok : the user is a superuser\n')
|
||||
return True
|
||||
|
||||
summary = get_profile_summary(user)
|
||||
profiles = summary.profiles
|
||||
r_profiles = profiles.get(KEY_READ, ())
|
||||
w_profiles = profiles.get(KEY_WRITE, ())
|
||||
|
||||
if not profiles:
|
||||
self.logger.debug('The user as no profile\n')
|
||||
return False
|
||||
|
||||
if request.method in SAFE_METHODS:
|
||||
resp = True if (r_profiles and r_profiles!=(P.SUPER,)) else False
|
||||
if not resp:
|
||||
msg = 'The user does not have reading rights\n'
|
||||
self.logger.debug(msg)
|
||||
return resp
|
||||
|
||||
# La gestion de droits des administrateurs est faite via IsAdminUser pour les api d'alimentation
|
||||
is_fil = P.FILIERE in w_profiles
|
||||
is_pcp = P.PCP in w_profiles
|
||||
is_bvt = P.BVT in w_profiles
|
||||
is_itd = P.ITD in w_profiles
|
||||
is_hme = P.HME in w_profiles
|
||||
|
||||
codes_lvl4 = get_lvl4_org_codes_by_any_code(summary.org_code)
|
||||
|
||||
if obj: # Modification d'une seule instance
|
||||
if not w_profiles or w_profiles==(P.SUPER,):
|
||||
self.logger.debug('The user does not have writing rights\n')
|
||||
return False
|
||||
|
||||
if isinstance(obj, Administre):
|
||||
pk = obj.pk
|
||||
return self.verif_droits_adm(pk, codes_lvl4, is_fil, is_pcp, is_bvt)
|
||||
|
||||
elif isinstance(obj, Poste):
|
||||
pk = obj.pk
|
||||
return self.verif_droits_poste(pk, codes_lvl4, is_fil, is_pcp, is_bvt, is_itd)
|
||||
|
||||
elif isinstance(obj, Decision):
|
||||
a_pk = obj.administre.pk
|
||||
p_pk = obj.poste.pk
|
||||
return self.verif_droits_poste(p_pk, codes_lvl4, is_fil, is_pcp, is_bvt, is_itd) or \
|
||||
self.verif_droits_adm(a_pk, codes_lvl4, is_fil, is_pcp, is_bvt)
|
||||
|
||||
else: # Vérification globale ou modification multiple
|
||||
|
||||
self.logger.debug('---- Writing profiles ----')
|
||||
self.logger.debug('Expert HME : %s', is_hme)
|
||||
self.logger.debug('Pameur BMOB : %s', is_pcp)
|
||||
self.logger.debug('Gestionnaire BVT : %s', is_bvt)
|
||||
self.logger.debug('Gestionnaire ITD : %s', is_itd)
|
||||
self.logger.debug('Gestionnaire BGCAT : %s', is_fil)
|
||||
self.logger.debug('--------------------------')
|
||||
|
||||
if isinstance(request.data, list):
|
||||
if not w_profiles or w_profiles==(P.SUPER,):
|
||||
self.logger.debug('The user does not have writing rights\n')
|
||||
return False
|
||||
|
||||
if 'a_id_sap' in request.data[0].keys():
|
||||
pk = [adm['a_id_sap'] for adm in request.data]
|
||||
return self.verif_droits_adm(pk, codes_lvl4, is_fil, is_pcp, is_bvt)
|
||||
|
||||
elif 'p_id' in request.data[0].keys():
|
||||
pk = [p['p_id'] for p in request.data]
|
||||
return self.verif_droits_poste(pk, codes_lvl4, is_fil, is_pcp, is_bvt, is_itd)
|
||||
|
||||
self.logger.debug('Global rights verification ok\n')
|
||||
return True # On autorise une permission globale pour ensuite permettre des vérifications au niveau des instances avec has_object_permission
|
||||
|
||||
self.logger.debug('User rights verification failed\n')
|
||||
return False
|
||||
|
||||
|
||||
def has_permission(self, request, view):
|
||||
if request.method != 'GET':
|
||||
self.logger.debug('------------------------- Permissions verification ---------------------')
|
||||
self.logger.debug('Request method : %s', request.method)
|
||||
self.logger.debug('Request data : %s', request.data)
|
||||
self.logger.debug('View : %s', view)
|
||||
|
||||
return self.commun_verif(request=request, view=view)
|
||||
|
||||
def has_object_permission(self, request, view, obj):
|
||||
self.logger.debug('--------------------- Object permissions verification ------------------')
|
||||
self.logger.debug('Request method : %s', request.method)
|
||||
self.logger.debug('Request data : %s', request.data)
|
||||
self.logger.debug('View : %s', view)
|
||||
self.logger.debug('Object : %s', obj)
|
||||
|
||||
return self.commun_verif(request=request, view=view, obj=obj)
|
||||
Reference in New Issue
Block a user