From 0fb668b21284a682a8dd5addd14e47c580723f13 Mon Sep 17 00:00:00 2001 From: N3WT DE COMPET Date: Sat, 29 Nov 2025 11:33:21 +0100 Subject: [PATCH] feat: push test [#N3WTS-17] --- Back-End/Auth/views.py | 1 - Back-End/DocuSeal/urls.py | 9 -- Back-End/DocuSeal/views.py | 200 ------------------------------- Back-End/Establishment/models.py | 1 - Back-End/N3wtSchool/settings.py | 7 -- Back-End/N3wtSchool/urls.py | 1 - Back-End/Subscriptions/models.py | 6 +- Back-End/requirements.txt | Bin 1302 -> 3672 bytes 8 files changed, 4 insertions(+), 221 deletions(-) delete mode 100644 Back-End/DocuSeal/urls.py delete mode 100644 Back-End/DocuSeal/views.py diff --git a/Back-End/Auth/views.py b/Back-End/Auth/views.py index ccf9478..b66c904 100644 --- a/Back-End/Auth/views.py +++ b/Back-End/Auth/views.py @@ -236,7 +236,6 @@ def makeToken(user): "establishment__name": role.establishment.name, "establishment__evaluation_frequency": role.establishment.evaluation_frequency, "establishment__total_capacity": role.establishment.total_capacity, - "establishment__api_docuseal": role.establishment.api_docuseal, "establishment__logo": logo_url, }) diff --git a/Back-End/DocuSeal/urls.py b/Back-End/DocuSeal/urls.py deleted file mode 100644 index 06a434b..0000000 --- a/Back-End/DocuSeal/urls.py +++ /dev/null @@ -1,9 +0,0 @@ -from django.urls import path, re_path -from .views import generate_jwt_token, clone_template, remove_template, download_template - -urlpatterns = [ - re_path(r'generateToken$', generate_jwt_token, name='generate_jwt_token'), - re_path(r'cloneTemplate$', clone_template, name='clone_template'), - re_path(r'removeTemplate/(?P[0-9]+)$', remove_template, name='remove_template'), - re_path(r'downloadTemplate/(?P[\w-]+)$', download_template, name='download_template') -] diff --git a/Back-End/DocuSeal/views.py b/Back-End/DocuSeal/views.py deleted file mode 100644 index 9a21cb3..0000000 --- a/Back-End/DocuSeal/views.py +++ /dev/null @@ -1,200 +0,0 @@ -from django.conf import settings -from django.views.decorators.csrf import csrf_exempt -from rest_framework.decorators import api_view -from rest_framework.response import Response -from rest_framework import status -import jwt -import datetime -import requests -from Establishment.models import Establishment - -@csrf_exempt -@api_view(['POST']) -def generate_jwt_token(request): - # Récupérer l'établissement concerné (par ID ou autre info transmise) - establishment_id = request.data.get('establishment_id') - if not establishment_id: - return Response({'error': 'establishment_id requis'}, status=status.HTTP_400_BAD_REQUEST) - - try: - establishment = Establishment.objects.get(id=establishment_id) - except Establishment.DoesNotExist: - return Response({'error': "Établissement introuvable"}, status=status.HTTP_404_NOT_FOUND) - - # Vérifier la clé API reçue dans le header - api_key = request.headers.get('X-Auth-Token') - if not api_key or not establishment.api_docuseal or api_key != establishment.api_docuseal: - return Response({'error': 'Clé API invalide'}, status=status.HTTP_401_UNAUTHORIZED) - - # Récupérer les données de la requête - user_email = request.data.get('user_email') - documents_urls = request.data.get('documents_urls', []) - template_id = request.data.get('id') - - if not user_email: - return Response({'error': 'User email is required'}, status=status.HTTP_400_BAD_REQUEST) - - # Utiliser la clé API de l'établissement comme secret JWT - jwt_secret = establishment.api_docuseal - jwt_algorithm = settings.DOCUSEAL_JWT['ALGORITHM'] - expiration_delta = settings.DOCUSEAL_JWT['EXPIRATION_DELTA'] - - payload = { - 'user_email': user_email, - 'documents_urls': documents_urls, - 'template_id': template_id, - 'exp': datetime.datetime.utcnow() + expiration_delta - } - - token = jwt.encode(payload, jwt_secret, algorithm=jwt_algorithm) - return Response({'token': token}, status=status.HTTP_200_OK) - -@csrf_exempt -@api_view(['POST']) -def clone_template(request): - # Récupérer l'établissement concerné - establishment_id = request.data.get('establishment_id') - print(f"establishment_id : {establishment_id}") - if not establishment_id: - return Response({'error': 'establishment_id requis'}, status=status.HTTP_400_BAD_REQUEST) - - try: - establishment = Establishment.objects.get(id=establishment_id) - except Establishment.DoesNotExist: - return Response({'error': "Établissement introuvable"}, status=status.HTTP_404_NOT_FOUND) - - # Vérifier la clé API reçue dans le header - api_key = request.headers.get('X-Auth-Token') - if not api_key or not establishment.api_docuseal or api_key != establishment.api_docuseal: - return Response({'error': 'Clé API invalide'}, status=status.HTTP_401_UNAUTHORIZED) - - # Récupérer les données de la requête - document_id = request.data.get('templateId') - email = request.data.get('email') - is_required = request.data.get('is_required') - - # Vérifier les données requises - if not document_id: - return Response({'error': 'template ID is required'}, status=status.HTTP_400_BAD_REQUEST) - - # URL de l'API de DocuSeal pour cloner le template - clone_url = f'https://docuseal.com/api/templates/{document_id}/clone' - - # Faire la requête pour cloner le template - try: - response = requests.post(clone_url, headers={ - 'Content-Type': 'application/json', - 'X-Auth-Token': establishment.api_docuseal - }) - - if response.status_code != status.HTTP_200_OK: - return Response({'error': 'Failed to clone template'}, status=response.status_code) - - data = response.json() - - if is_required: - # URL de l'API de DocuSeal pour créer une submission - submission_url = f'https://docuseal.com/api/submissions' - - try: - clone_id = data['id'] - response = requests.post(submission_url, json={ - 'template_id': clone_id, - 'send_email': False, - 'submitters': [{'email': email}] - }, headers={ - 'Content-Type': 'application/json', - 'X-Auth-Token': establishment.api_docuseal - }) - - if response.status_code != status.HTTP_200_OK: - return Response({'error': 'Failed to create submission'}, status=response.status_code) - - data = response.json() - data[0]['id'] = clone_id - return Response(data[0], status=status.HTTP_200_OK) - - except requests.RequestException as e: - return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) - else: - print(f'NOT REQUIRED -> on ne crée pas de submission') - return Response(data, status=status.HTTP_200_OK) - - except requests.RequestException as e: - return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) - -@csrf_exempt -@api_view(['DELETE']) -def remove_template(request, id): - # Récupérer l'établissement concerné - establishment_id = request.GET.get('establishment_id') - if not establishment_id: - return Response({'error': 'establishment_id requis'}, status=status.HTTP_400_BAD_REQUEST) - - try: - establishment = Establishment.objects.get(id=establishment_id) - except Establishment.DoesNotExist: - return Response({'error': "Établissement introuvable"}, status=status.HTTP_404_NOT_FOUND) - - # Vérifier la clé API reçue dans le header - api_key = request.headers.get('X-Auth-Token') - if not api_key or not establishment.api_docuseal or api_key != establishment.api_docuseal: - return Response({'error': 'Clé API invalide'}, status=status.HTTP_401_UNAUTHORIZED) - - # URL de l'API de DocuSeal pour supprimer le template - - clone_url = f'https://docuseal.com/api/templates/{id}' - - try: - response = requests.delete(clone_url, headers={ - 'X-Auth-Token': establishment.api_docuseal - }) - - if response.status_code != status.HTTP_200_OK: - return Response({'error': 'Failed to remove template'}, status=response.status_code) - - data = response.json() - return Response(data, status=status.HTTP_200_OK) - - except requests.RequestException as e: - return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) - -@csrf_exempt -@api_view(['GET']) -def download_template(request, slug): - # Récupérer l'établissement concerné - establishment_id = request.GET.get('establishment_id') - if not establishment_id: - return Response({'error': 'establishment_id requis'}, status=status.HTTP_400_BAD_REQUEST) - - try: - establishment = Establishment.objects.get(id=establishment_id) - except Establishment.DoesNotExist: - return Response({'error': "Établissement introuvable"}, status=status.HTTP_404_NOT_FOUND) - - # Vérifier la clé API reçue dans le header - api_key = request.headers.get('X-Auth-Token') - if not api_key or not establishment.api_docuseal or api_key != establishment.api_docuseal: - return Response({'error': 'Clé API invalide'}, status=status.HTTP_401_UNAUTHORIZED) - - # Vérifier les données requises - if not slug: - return Response({'error': 'slug is required'}, status=status.HTTP_400_BAD_REQUEST) - - # URL de l'API de DocuSeal pour télécharger le template - download_url = f'https://docuseal.com/submitters/{slug}/download' - - try: - response = requests.get(download_url, headers={ - 'Content-Type': 'application/json', - 'X-Auth-Token': establishment.api_docuseal - }) - - if response.status_code != status.HTTP_200_OK: - return Response({'error': 'Failed to download template'}, status=response.status_code) - - data = response.json() - return Response(data, status=status.HTTP_200_OK) - - except requests.RequestException as e: - return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) diff --git a/Back-End/Establishment/models.py b/Back-End/Establishment/models.py index 27d6099..e79c292 100644 --- a/Back-End/Establishment/models.py +++ b/Back-End/Establishment/models.py @@ -27,7 +27,6 @@ class Establishment(models.Model): licence_code = models.CharField(max_length=100, blank=True) is_active = models.BooleanField(default=True) created_at = models.DateTimeField(auto_now_add=True) - api_docuseal = models.CharField(max_length=255, blank=True, null=True) logo = models.FileField( upload_to=registration_logo_upload_to, null=True, diff --git a/Back-End/N3wtSchool/settings.py b/Back-End/N3wtSchool/settings.py index 5a7a8c6..8214b73 100644 --- a/Back-End/N3wtSchool/settings.py +++ b/Back-End/N3wtSchool/settings.py @@ -349,13 +349,6 @@ SIMPLE_JWT = { 'TOKEN_TYPE_CLAIM': 'token_type', } -# Configuration for DocuSeal JWT -DOCUSEAL_JWT = { - 'ALGORITHM': 'HS256', - 'SIGNING_KEY': SECRET_KEY, - 'EXPIRATION_DELTA': timedelta(hours=1) -} - # Django Channels Configuration ASGI_APPLICATION = 'N3wtSchool.asgi.application' diff --git a/Back-End/N3wtSchool/urls.py b/Back-End/N3wtSchool/urls.py index 458d0b2..8ebb2ff 100644 --- a/Back-End/N3wtSchool/urls.py +++ b/Back-End/N3wtSchool/urls.py @@ -46,7 +46,6 @@ urlpatterns = [ path("GestionEmail/", include(("GestionEmail.urls", 'GestionEmail'), namespace='GestionEmail')), path("GestionNotification/", include(("GestionNotification.urls", 'GestionNotification'), namespace='GestionNotification')), path("School/", include(("School.urls", 'School'), namespace='School')), - path("DocuSeal/", include(("DocuSeal.urls", 'DocuSeal'), namespace='DocuSeal')), path("Planning/", include(("Planning.urls", 'Planning'), namespace='Planning')), path("Establishment/", include(("Establishment.urls", 'Establishment'), namespace='Establishment')), path("Settings/", include(("Settings.urls", 'Settings'), namespace='Settings')), diff --git a/Back-End/Subscriptions/models.py b/Back-End/Subscriptions/models.py index 4334c88..b9abb78 100644 --- a/Back-End/Subscriptions/models.py +++ b/Back-End/Subscriptions/models.py @@ -294,12 +294,13 @@ class RegistrationForm(models.Model): ####################### MASTER FILES ######################## ############################################################# -####### DocuSeal masters (documents école, à signer ou pas) ####### +####### Formulaires masters (documents école, à signer ou pas) ####### class RegistrationSchoolFileMaster(models.Model): groups = models.ManyToManyField(RegistrationFileGroup, related_name='school_file_masters', blank=True) id = models.IntegerField(primary_key=True) name = models.CharField(max_length=255, default="") is_required = models.BooleanField(default=False) + formMasterData = models.JSONField(default=list, blank=True, null=True) def __str__(self): return f'{self.group.name} - {self.id}' @@ -321,7 +322,7 @@ def registration_school_file_upload_to(instance, filename): def registration_parent_file_upload_to(instance, filename): return f"registration_files/dossier_rf_{instance.registration_form.pk}/parent/{filename}" -####### DocuSeal templates (par dossier d'inscription) ####### +####### Formulaires templates (par dossier d'inscription) ####### class RegistrationSchoolFileTemplate(models.Model): master = models.ForeignKey(RegistrationSchoolFileMaster, on_delete=models.CASCADE, related_name='school_file_templates', blank=True) id = models.IntegerField(primary_key=True) @@ -329,6 +330,7 @@ class RegistrationSchoolFileTemplate(models.Model): name = models.CharField(max_length=255, default="") registration_form = models.ForeignKey(RegistrationForm, on_delete=models.CASCADE, related_name='school_file_templates', blank=True) file = models.FileField(null=True,blank=True, upload_to=registration_school_file_upload_to) + formTemplateData = models.JSONField(default=list, blank=True, null=True) def __str__(self): return self.name diff --git a/Back-End/requirements.txt b/Back-End/requirements.txt index 57e40e90bafe7057092065383beb0bf0633484ee..5d93dbdd6605bc9f71d8c7b72a4c812de0638177 100644 GIT binary patch literal 3672 zcmZ{nUvFAR5XJYoQa=io!FK9ADoy#I&rP`~BYiK+_vO1XE}QaFmSr2ZYyJMdXWPksFYBZX z%C5}HzAW@hqrZ0He-*wp*1pW;jpxJ3ek-40mus(VLq*#uXH(iP>rft`O0QOyopOP8 z6c*<(-b0+b7mkIZ*$3QwN0H}avCmpQZ7&KQ!}2bCsA{FpQa-yf4KGK?Y9^{;6_vh( z6@+-0H>^8FU#ik&m*Z0T@u1?Xli$P1gF1)hhxnITCc)-LRglT`Iz!C@-_^rim?~rS zCTe2Bn`&lV-RHe_KA6QmP~5G&VF?~yqayf(?S7?LC*?7!bT=*yF{|F{cPc^U#m+%_)-mON2$wBsa8A)iF|ePPbJR-L8G2J`gKHi_2z1?h;WapCPFhh zVMPNrFm&VtBWWF^H= zYbqLxk*HtNigTWa3THCB3M zgpK+~W!z?W`fl}EsUJ)IoxH==bysU6#N1Bg#O^t)(e}y$la26>q#*7oddQ85Kdf>? zzYh&H`W1z3#57hiSx5AxZ@m-7t@LnEUN&2L_jw>QeEEj3F3C6QnEIk@bH$k{U)#lS zmqBFRlJiH!K$G54VDc?qJ$$R-;XTDo`ln8zW;P%^I=@d-lQ%9Hek#A0uTep=;a*_- zMHPN2pUUU3(<|q`Iq~(YYNUeS^!d4qVlCG$FkMq=8J5m%Qpn&8Jds1b~*$9@ia#dMp~{w6p_yy#-1HnwuA zqw;R->Br20hS=Us@IW{EDAL>6XJ@*vox2d%%yD~m_BAk!^qY5*XBGDUC?C~jcg}N2 zX7v6fRLl-{78St0@%;C;L08^B*pkoHsUFV-%n})&C*fyu`pUnGnypN3_MKGBCghfa zNlyy9Ag4Fu8kb*U2j$Pr;mN!e?*2=hJIA*w-R2FOl`;FgLD{>WH$3QuRkRoGmEz}A zXJ@No_QE`m$*Z@FHBaSiD*lHsQRRD8%Xuc(M7$>A!W+jl13IMbOuE)ru>}&Q_l&bG=)9_MlGD6>dQGI~(Wx zz2z9`=dE6G&>eRj5C1>nUcbPO5vCnI- literal 1302 zcmZuxO>g5M5WVwXjBK1V?ZJnYs%o{`NL_h>T&d~~&y|kZjHc^EEq18TA~jOn@aBNmYQj^UzlNYN>0CJ$K1cl?2==v_7Fq@n>Z zKyQ$4ktUqSD8mFiJK_V$loAlCEa>$C5T8G!JAw|7f%Bn6)t!Z^*Am!7x%YMAW2z=C z2OTluuCTNn&C=N3Un$$vn0!k|Js4cQ6T0QHnf1*(U5!RtaQ}ej_4WV~<`MYx#Ya#E zVxaK<&fb%mgVi6G!auP*c(o)g!4%37nmAS~EI_en_#=Cfr=khOanGj1e~j4#rVO-_F97Xr~jKYN|gg8tXcgZ3{!Q5>W?N$7{3aExF9{_+=epowrC z{T%Xp_THWh<|b8k2Nu$*d^n1#H%^lM1b^aBEUYS!qoAqa0>#$v(w!hy%>_*r)`?=s z74s(yH^`ztP9K2&ZT<24*S%DY;B|R>ekn}s`5sThfVCji=@3V71WiL#^8`orW`NOa zPNlXKIW0@@)s|h^vgoRpY(NQ3UGv~m2GTX(kfFU1Xz=IT>rc`dv$1nje$ccHHT&ld zxDi3{Fx29yc+Gn{3<)w*wWeL(TFU zpvt?xX6+J`E$(eVE6X<^fb?ZnJiJ-2$U|hiC7P_^GC(Z8Mqx@pzVe<-wnThE`j$qd z2|ta))jO{jbumMpie9{F*+uu-0Xqi4bDFwg7n#*G8mkk#k|9OW1vCL9eP5i@U%jyU UTa52qSt@KApbc1YYI=|U0woZR5dZ)H