mirror of
https://git.v0id.ovh/n3wt-innov/n3wt-school.git
synced 2026-01-28 23:43:22 +00:00
feat: Gestion multi-profil multi-école
This commit is contained in:
@ -19,7 +19,7 @@ from jwt.exceptions import ExpiredSignatureError, InvalidTokenError
|
||||
import json
|
||||
|
||||
from . import validator
|
||||
from .models import Profile
|
||||
from .models import Profile, ProfileRole
|
||||
from rest_framework.decorators import action, api_view
|
||||
|
||||
from Auth.serializers import ProfileSerializer, ProfilUpdateSerializer
|
||||
@ -56,7 +56,10 @@ class SessionView(APIView):
|
||||
'user': openapi.Schema(type=openapi.TYPE_OBJECT, properties={
|
||||
'id': openapi.Schema(type=openapi.TYPE_INTEGER),
|
||||
'email': openapi.Schema(type=openapi.TYPE_STRING),
|
||||
'role': openapi.Schema(type=openapi.TYPE_STRING)
|
||||
'roles': openapi.Schema(type=openapi.TYPE_ARRAY, items=openapi.Items(type=openapi.TYPE_OBJECT, properties={
|
||||
'role_type': openapi.Schema(type=openapi.TYPE_STRING),
|
||||
'establishment': openapi.Schema(type=openapi.TYPE_STRING)
|
||||
}))
|
||||
})
|
||||
})),
|
||||
401: openapi.Response('Session invalide')
|
||||
@ -67,15 +70,16 @@ class SessionView(APIView):
|
||||
|
||||
try:
|
||||
decoded_token = jwt.decode(token, settings.SECRET_KEY, algorithms=['HS256'])
|
||||
print(f'decode : {decoded_token}')
|
||||
userid = decoded_token.get('id')
|
||||
userid = decoded_token.get('user_id')
|
||||
user = Profile.objects.get(id=userid)
|
||||
|
||||
roles = ProfileRole.objects.filter(profile=user).values('role_type', 'establishment__name')
|
||||
|
||||
response_data = {
|
||||
'user': {
|
||||
'id': user.id,
|
||||
'email': user.email,
|
||||
'role': user.droit, # Assure-toi que le champ 'droit' existe et contient le rôle
|
||||
'roles': list(roles)
|
||||
}
|
||||
}
|
||||
return JsonResponse(response_data, status=status.HTTP_200_OK)
|
||||
@ -103,13 +107,11 @@ class ProfileView(APIView):
|
||||
}
|
||||
)
|
||||
def post(self, request):
|
||||
profil_data=JSONParser().parse(request)
|
||||
print(f'{profil_data}')
|
||||
profil_data = JSONParser().parse(request)
|
||||
profil_serializer = ProfileSerializer(data=profil_data)
|
||||
|
||||
if profil_serializer.is_valid():
|
||||
profil_serializer.save()
|
||||
|
||||
profil = profil_serializer.save()
|
||||
return JsonResponse(profil_serializer.data, safe=False)
|
||||
|
||||
return JsonResponse(profil_serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST)
|
||||
@ -122,8 +124,8 @@ class ProfileSimpleView(APIView):
|
||||
responses={200: ProfileSerializer}
|
||||
)
|
||||
def get(self, request, id):
|
||||
profil=bdd.getObject(Profile, "id", id)
|
||||
profil_serializer=ProfileSerializer(profil)
|
||||
profil = bdd.getObject(Profile, "id", id)
|
||||
profil_serializer = ProfileSerializer(profil)
|
||||
return JsonResponse(profil_serializer.data, safe=False)
|
||||
|
||||
@swagger_auto_schema(
|
||||
@ -135,12 +137,12 @@ class ProfileSimpleView(APIView):
|
||||
}
|
||||
)
|
||||
def put(self, request, id):
|
||||
data=JSONParser().parse(request)
|
||||
data = JSONParser().parse(request)
|
||||
profil = Profile.objects.get(id=id)
|
||||
profil_serializer = ProfilUpdateSerializer(profil, data=data)
|
||||
if profil_serializer.is_valid():
|
||||
profil_serializer.save()
|
||||
return JsonResponse("Updated Successfully", safe=False)
|
||||
return JsonResponse(profil_serializer.data, safe=False)
|
||||
|
||||
return JsonResponse(profil_serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
@ -157,10 +159,11 @@ class LoginView(APIView):
|
||||
operation_description="Connexion utilisateur",
|
||||
request_body=openapi.Schema(
|
||||
type=openapi.TYPE_OBJECT,
|
||||
required=['email', 'password'],
|
||||
required=['email', 'password', 'role_type'],
|
||||
properties={
|
||||
'email': openapi.Schema(type=openapi.TYPE_STRING),
|
||||
'password': openapi.Schema(type=openapi.TYPE_STRING)
|
||||
'password': openapi.Schema(type=openapi.TYPE_STRING),
|
||||
'role_type': openapi.Schema(type=openapi.TYPE_STRING)
|
||||
}
|
||||
),
|
||||
responses={
|
||||
@ -193,40 +196,45 @@ class LoginView(APIView):
|
||||
password=data.get('password'),
|
||||
)
|
||||
if user is not None:
|
||||
if user.is_active:
|
||||
login(request, user)
|
||||
user.estConnecte = True
|
||||
user.save()
|
||||
clear_cache()
|
||||
retour = ''
|
||||
# Générer le JWT avec la bonne syntaxe datetime
|
||||
access_payload = {
|
||||
'user_id': user.id,
|
||||
'email': user.email,
|
||||
'droit': user.droit,
|
||||
'establishment': user.establishment.id,
|
||||
'type': 'access',
|
||||
'exp': datetime.utcnow() + settings.SIMPLE_JWT['ACCESS_TOKEN_LIFETIME'],
|
||||
'iat': datetime.utcnow(),
|
||||
}
|
||||
role_type = data.get('role_type')
|
||||
primary_role = ProfileRole.objects.filter(profile=user, role_type=role_type, is_active=True).first()
|
||||
|
||||
access_token = jwt.encode(access_payload, settings.SIMPLE_JWT['SIGNING_KEY'], algorithm=settings.SIMPLE_JWT['ALGORITHM'])
|
||||
# Générer le Refresh Token (exp: 7 jours)
|
||||
refresh_payload = {
|
||||
'user_id': user.id,
|
||||
'type': 'refresh',
|
||||
'exp': datetime.utcnow() + settings.SIMPLE_JWT['REFRESH_TOKEN_LIFETIME'],
|
||||
'iat': datetime.utcnow(),
|
||||
}
|
||||
refresh_token = jwt.encode(refresh_payload, settings.SIMPLE_JWT['SIGNING_KEY'], algorithm=settings.SIMPLE_JWT['ALGORITHM'])
|
||||
if not primary_role:
|
||||
return JsonResponse({"errorMessage": "Role not assigned to the user"}, status=status.HTTP_401_UNAUTHORIZED)
|
||||
|
||||
return JsonResponse({
|
||||
'token': access_token,
|
||||
'refresh': refresh_token
|
||||
}, safe=False)
|
||||
login(request, user)
|
||||
user.save()
|
||||
clear_cache()
|
||||
retour = ''
|
||||
|
||||
# Récupérer tous les rôles de l'utilisateur avec le type spécifié
|
||||
roles = ProfileRole.objects.filter(profile=user, role_type=role_type).values('role_type', 'establishment__id', 'establishment__name')
|
||||
|
||||
# Générer le JWT avec la bonne syntaxe datetime
|
||||
access_payload = {
|
||||
'user_id': user.id,
|
||||
'email': user.email,
|
||||
'roles': list(roles),
|
||||
'type': 'access',
|
||||
'exp': datetime.utcnow() + settings.SIMPLE_JWT['ACCESS_TOKEN_LIFETIME'],
|
||||
'iat': datetime.utcnow(),
|
||||
}
|
||||
|
||||
access_token = jwt.encode(access_payload, settings.SIMPLE_JWT['SIGNING_KEY'], algorithm=settings.SIMPLE_JWT['ALGORITHM'])
|
||||
# Générer le Refresh Token (exp: 7 jours)
|
||||
refresh_payload = {
|
||||
'user_id': user.id,
|
||||
'type': 'refresh',
|
||||
'exp': datetime.utcnow() + settings.SIMPLE_JWT['REFRESH_TOKEN_LIFETIME'],
|
||||
'iat': datetime.utcnow(),
|
||||
}
|
||||
refresh_token = jwt.encode(refresh_payload, settings.SIMPLE_JWT['SIGNING_KEY'], algorithm=settings.SIMPLE_JWT['ALGORITHM'])
|
||||
|
||||
return JsonResponse({
|
||||
'token': access_token,
|
||||
'refresh': refresh_token
|
||||
}, safe=False)
|
||||
|
||||
else:
|
||||
retour = error.returnMessage[error.PROFIL_INACTIVE]
|
||||
else:
|
||||
retour = error.returnMessage[error.WRONG_ID]
|
||||
|
||||
@ -235,7 +243,6 @@ class LoginView(APIView):
|
||||
'errorMessage': retour,
|
||||
}, safe=False, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
|
||||
class RefreshJWTView(APIView):
|
||||
@swagger_auto_schema(
|
||||
operation_description="Rafraîchir le token d'accès",
|
||||
@ -295,13 +302,20 @@ class RefreshJWTView(APIView):
|
||||
|
||||
# Récupérer les informations utilisateur
|
||||
user = Profile.objects.get(id=payload['user_id'])
|
||||
role_type = payload.get('role_type')
|
||||
|
||||
# Récupérer le rôle principal de l'utilisateur
|
||||
primary_role = ProfileRole.objects.filter(profile=user, role_type=role_type).first()
|
||||
|
||||
if not primary_role:
|
||||
return JsonResponse({'errorMessage': 'No role assigned to the user'}, status=400)
|
||||
|
||||
# Générer un nouveau Access Token avec les informations complètes
|
||||
new_access_payload = {
|
||||
'user_id': user.id,
|
||||
'email': user.email,
|
||||
'droit': user.droit,
|
||||
'establishment': user.establishment.id,
|
||||
'role_type': primary_role.get_role_type_display(),
|
||||
'establishment': primary_role.establishment.id,
|
||||
'type': 'access',
|
||||
'exp': datetime.utcnow() + settings.SIMPLE_JWT['ACCESS_TOKEN_LIFETIME'],
|
||||
'iat': datetime.utcnow(),
|
||||
@ -311,6 +325,7 @@ class RefreshJWTView(APIView):
|
||||
|
||||
new_refresh_payload = {
|
||||
'user_id': user.id,
|
||||
'role_type': role_type,
|
||||
'type': 'refresh',
|
||||
'exp': datetime.utcnow() + settings.SIMPLE_JWT['REFRESH_TOKEN_LIFETIME'],
|
||||
'iat': datetime.utcnow(),
|
||||
@ -335,6 +350,14 @@ class RefreshJWTView(APIView):
|
||||
class SubscribeView(APIView):
|
||||
@swagger_auto_schema(
|
||||
operation_description="Inscription utilisateur",
|
||||
manual_parameters=[
|
||||
openapi.Parameter(
|
||||
'establishment_id', openapi.IN_QUERY,
|
||||
description="ID de l'établissement",
|
||||
type=openapi.TYPE_INTEGER,
|
||||
required=True
|
||||
)
|
||||
],
|
||||
request_body=openapi.Schema(
|
||||
type=openapi.TYPE_OBJECT,
|
||||
required=['email', 'password1', 'password2'],
|
||||
@ -359,37 +382,54 @@ class SubscribeView(APIView):
|
||||
def post(self, request):
|
||||
retourErreur = error.returnMessage[error.BAD_URL]
|
||||
retour = ''
|
||||
newProfilConnection=JSONParser().parse(request)
|
||||
newProfilConnection = JSONParser().parse(request)
|
||||
establishment_id = request.GET.get('establishment_id')
|
||||
|
||||
if not establishment_id:
|
||||
return JsonResponse({'message': retour, 'errorMessage': 'establishment_id manquant', "errorFields": {}, "id": -1}, safe=False, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
validatorSubscription = validator.ValidatorSubscription(data=newProfilConnection)
|
||||
validationOk, errorFields = validatorSubscription.validate()
|
||||
|
||||
|
||||
if validationOk:
|
||||
|
||||
# On vérifie que l'email existe : si ce n'est pas le cas, on retourne une erreur
|
||||
profil = bdd.getProfile(Profile.objects.all(), newProfilConnection.get('email'))
|
||||
if profil == None:
|
||||
if profil is None:
|
||||
retourErreur = error.returnMessage[error.PROFIL_NOT_EXISTS]
|
||||
else:
|
||||
if profil.is_active:
|
||||
retourErreur=error.returnMessage[error.PROFIL_ACTIVE]
|
||||
return JsonResponse({'message':retour,'errorMessage':retourErreur, "errorFields":errorFields, "id":profil.id}, safe=False)
|
||||
# Vérifier si le profil a déjà un rôle actif pour l'établissement donné
|
||||
active_roles = ProfileRole.objects.filter(profile=profil, establishment_id=establishment_id, is_active=True)
|
||||
if active_roles.exists():
|
||||
retourErreur = error.returnMessage[error.PROFIL_ACTIVE]
|
||||
return JsonResponse({'message': retour, 'errorMessage': retourErreur, "errorFields": errorFields, "id": profil.id}, safe=False)
|
||||
else:
|
||||
try:
|
||||
profil.set_password(newProfilConnection.get('password1'))
|
||||
profil.is_active = True
|
||||
profil.full_clean()
|
||||
profil.save()
|
||||
|
||||
# Utiliser le sérialiseur ProfileRoleSerializer pour créer ou mettre à jour le rôle
|
||||
role_data = {
|
||||
'profile': profil.id,
|
||||
'establishment_id': establishment_id,
|
||||
'role_type': ProfileRole.RoleType.PROFIL_PARENT,
|
||||
'is_active': True
|
||||
}
|
||||
role_serializer = ProfileRoleSerializer(data=role_data)
|
||||
if role_serializer.is_valid():
|
||||
role_serializer.save()
|
||||
else:
|
||||
return JsonResponse(role_serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
clear_cache()
|
||||
retour = error.returnMessage[error.MESSAGE_ACTIVATION_PROFILE]
|
||||
retourErreur=''
|
||||
return JsonResponse({'message':retour,'errorMessage':retourErreur, "errorFields":errorFields, "id":profil.id}, safe=False)
|
||||
retourErreur = ''
|
||||
return JsonResponse({'message': retour, 'errorMessage': retourErreur, "errorFields": errorFields, "id": profil.id}, safe=False)
|
||||
except ValidationError as e:
|
||||
retourErreur = error.returnMessage[error.WRONG_MAIL_FORMAT]
|
||||
return JsonResponse({'message':retour,'errorMessage':retourErreur, "errorFields":errorFields}, safe=False)
|
||||
return JsonResponse({'message': retour, 'errorMessage': retourErreur, "errorFields": errorFields}, safe=False)
|
||||
|
||||
return JsonResponse({'message':retour, 'errorMessage':retourErreur, "errorFields":errorFields, "id":-1}, safe=False)
|
||||
return JsonResponse({'message': retour, 'errorMessage': retourErreur, "errorFields": errorFields, "id": -1}, safe=False)
|
||||
|
||||
@method_decorator(csrf_protect, name='dispatch')
|
||||
@method_decorator(ensure_csrf_cookie, name='dispatch')
|
||||
@ -417,26 +457,29 @@ class NewPasswordView(APIView):
|
||||
def post(self, request):
|
||||
retourErreur = error.returnMessage[error.BAD_URL]
|
||||
retour = ''
|
||||
newProfilConnection=JSONParser().parse(request)
|
||||
newProfilConnection = JSONParser().parse(request)
|
||||
|
||||
validatorNewPassword = validator.ValidatorNewPassword(data=newProfilConnection)
|
||||
validationOk, errorFields = validatorNewPassword.validate()
|
||||
if validationOk:
|
||||
|
||||
profil = bdd.getProfile(Profile.objects.all(), newProfilConnection.get('email'))
|
||||
if profil == None:
|
||||
if profil is None:
|
||||
retourErreur = error.returnMessage[error.PROFIL_NOT_EXISTS]
|
||||
else:
|
||||
# Génération d'une URL provisoire pour modifier le mot de passe
|
||||
profil.code = util.genereRandomCode(12)
|
||||
profil.datePeremption = util.calculeDatePeremption(util._now(), settings.EXPIRATION_URL_NB_DAYS)
|
||||
profil.save()
|
||||
clear_cache()
|
||||
retourErreur = ''
|
||||
retour = error.returnMessage[error.MESSAGE_REINIT_PASSWORD]%(newProfilConnection.get('email'))
|
||||
mailer.envoieReinitMotDePasse(newProfilConnection.get('email'), profil.code)
|
||||
try:
|
||||
# Génération d'une URL provisoire pour modifier le mot de passe
|
||||
profil.code = util.genereRandomCode(12)
|
||||
profil.datePeremption = util.calculeDatePeremption(util._now(), settings.EXPIRATION_URL_NB_DAYS)
|
||||
profil.save()
|
||||
clear_cache()
|
||||
retourErreur = ''
|
||||
retour = error.returnMessage[error.MESSAGE_REINIT_PASSWORD] % (newProfilConnection.get('email'))
|
||||
mailer.envoieReinitMotDePasse(newProfilConnection.get('email'), profil.code)
|
||||
except ValidationError as e:
|
||||
retourErreur = error.returnMessage[error.WRONG_MAIL_FORMAT]
|
||||
return JsonResponse({'message': retour, 'errorMessage': retourErreur, "errorFields": errorFields}, safe=False)
|
||||
|
||||
return JsonResponse({'message':retour, 'errorMessage':retourErreur, "errorFields":errorFields}, safe=False)
|
||||
return JsonResponse({'message': retour, 'errorMessage': retourErreur, "errorFields": errorFields}, safe=False)
|
||||
|
||||
@method_decorator(csrf_protect, name='dispatch')
|
||||
@method_decorator(ensure_csrf_cookie, name='dispatch')
|
||||
@ -465,7 +508,7 @@ class ResetPasswordView(APIView):
|
||||
def post(self, request, code):
|
||||
retourErreur = error.returnMessage[error.BAD_URL]
|
||||
retour = ''
|
||||
newProfilConnection=JSONParser().parse(request)
|
||||
newProfilConnection = JSONParser().parse(request)
|
||||
|
||||
validatorResetPassword = validator.ValidatorResetPassword(data=newProfilConnection)
|
||||
validationOk, errorFields = validatorResetPassword.validate()
|
||||
@ -474,16 +517,15 @@ class ResetPasswordView(APIView):
|
||||
if profil:
|
||||
|
||||
if datetime.strptime(util.convertToStr(util._now(), '%d-%m-%Y %H:%M'), '%d-%m-%Y %H:%M') > datetime.strptime(profil.datePeremption, '%d-%m-%Y %H:%M'):
|
||||
retourErreur = error.returnMessage[error.EXPIRED_URL]%(_uuid)
|
||||
retourErreur = error.returnMessage[error.EXPIRED_URL] % (_uuid)
|
||||
elif validationOk:
|
||||
retour = error.returnMessage[error.PASSWORD_CHANGED]
|
||||
|
||||
profil.set_password(newProfilConnection.get('password1'))
|
||||
profil.code = ''
|
||||
profil.datePeremption = ''
|
||||
profil.is_active = True
|
||||
profil.save()
|
||||
clear_cache()
|
||||
retourErreur=''
|
||||
retourErreur = ''
|
||||
|
||||
return JsonResponse({'message':retour, "errorMessage":retourErreur, "errorFields":errorFields}, safe=False)
|
||||
return JsonResponse({'message': retour, "errorMessage": retourErreur, "errorFields": errorFields}, safe=False)
|
||||
|
||||
Reference in New Issue
Block a user