mirror of
https://git.v0id.ovh/n3wt-innov/n3wt-school.git
synced 2026-01-28 23:43:22 +00:00
feat: push test [#N3WTS-17]
This commit is contained in:
@ -236,7 +236,6 @@ def makeToken(user):
|
|||||||
"establishment__name": role.establishment.name,
|
"establishment__name": role.establishment.name,
|
||||||
"establishment__evaluation_frequency": role.establishment.evaluation_frequency,
|
"establishment__evaluation_frequency": role.establishment.evaluation_frequency,
|
||||||
"establishment__total_capacity": role.establishment.total_capacity,
|
"establishment__total_capacity": role.establishment.total_capacity,
|
||||||
"establishment__api_docuseal": role.establishment.api_docuseal,
|
|
||||||
"establishment__logo": logo_url,
|
"establishment__logo": logo_url,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -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<id>[0-9]+)$', remove_template, name='remove_template'),
|
|
||||||
re_path(r'downloadTemplate/(?P<slug>[\w-]+)$', download_template, name='download_template')
|
|
||||||
]
|
|
||||||
@ -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)
|
|
||||||
@ -27,7 +27,6 @@ class Establishment(models.Model):
|
|||||||
licence_code = models.CharField(max_length=100, blank=True)
|
licence_code = models.CharField(max_length=100, blank=True)
|
||||||
is_active = models.BooleanField(default=True)
|
is_active = models.BooleanField(default=True)
|
||||||
created_at = models.DateTimeField(auto_now_add=True)
|
created_at = models.DateTimeField(auto_now_add=True)
|
||||||
api_docuseal = models.CharField(max_length=255, blank=True, null=True)
|
|
||||||
logo = models.FileField(
|
logo = models.FileField(
|
||||||
upload_to=registration_logo_upload_to,
|
upload_to=registration_logo_upload_to,
|
||||||
null=True,
|
null=True,
|
||||||
|
|||||||
@ -349,13 +349,6 @@ SIMPLE_JWT = {
|
|||||||
'TOKEN_TYPE_CLAIM': 'token_type',
|
'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
|
# Django Channels Configuration
|
||||||
ASGI_APPLICATION = 'N3wtSchool.asgi.application'
|
ASGI_APPLICATION = 'N3wtSchool.asgi.application'
|
||||||
|
|
||||||
|
|||||||
@ -46,7 +46,6 @@ urlpatterns = [
|
|||||||
path("GestionEmail/", include(("GestionEmail.urls", 'GestionEmail'), namespace='GestionEmail')),
|
path("GestionEmail/", include(("GestionEmail.urls", 'GestionEmail'), namespace='GestionEmail')),
|
||||||
path("GestionNotification/", include(("GestionNotification.urls", 'GestionNotification'), namespace='GestionNotification')),
|
path("GestionNotification/", include(("GestionNotification.urls", 'GestionNotification'), namespace='GestionNotification')),
|
||||||
path("School/", include(("School.urls", 'School'), namespace='School')),
|
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("Planning/", include(("Planning.urls", 'Planning'), namespace='Planning')),
|
||||||
path("Establishment/", include(("Establishment.urls", 'Establishment'), namespace='Establishment')),
|
path("Establishment/", include(("Establishment.urls", 'Establishment'), namespace='Establishment')),
|
||||||
path("Settings/", include(("Settings.urls", 'Settings'), namespace='Settings')),
|
path("Settings/", include(("Settings.urls", 'Settings'), namespace='Settings')),
|
||||||
|
|||||||
@ -294,12 +294,13 @@ class RegistrationForm(models.Model):
|
|||||||
####################### MASTER FILES ########################
|
####################### MASTER FILES ########################
|
||||||
#############################################################
|
#############################################################
|
||||||
|
|
||||||
####### DocuSeal masters (documents école, à signer ou pas) #######
|
####### Formulaires masters (documents école, à signer ou pas) #######
|
||||||
class RegistrationSchoolFileMaster(models.Model):
|
class RegistrationSchoolFileMaster(models.Model):
|
||||||
groups = models.ManyToManyField(RegistrationFileGroup, related_name='school_file_masters', blank=True)
|
groups = models.ManyToManyField(RegistrationFileGroup, related_name='school_file_masters', blank=True)
|
||||||
id = models.IntegerField(primary_key=True)
|
id = models.IntegerField(primary_key=True)
|
||||||
name = models.CharField(max_length=255, default="")
|
name = models.CharField(max_length=255, default="")
|
||||||
is_required = models.BooleanField(default=False)
|
is_required = models.BooleanField(default=False)
|
||||||
|
formMasterData = models.JSONField(default=list, blank=True, null=True)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f'{self.group.name} - {self.id}'
|
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):
|
def registration_parent_file_upload_to(instance, filename):
|
||||||
return f"registration_files/dossier_rf_{instance.registration_form.pk}/parent/{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):
|
class RegistrationSchoolFileTemplate(models.Model):
|
||||||
master = models.ForeignKey(RegistrationSchoolFileMaster, on_delete=models.CASCADE, related_name='school_file_templates', blank=True)
|
master = models.ForeignKey(RegistrationSchoolFileMaster, on_delete=models.CASCADE, related_name='school_file_templates', blank=True)
|
||||||
id = models.IntegerField(primary_key=True)
|
id = models.IntegerField(primary_key=True)
|
||||||
@ -329,6 +330,7 @@ class RegistrationSchoolFileTemplate(models.Model):
|
|||||||
name = models.CharField(max_length=255, default="")
|
name = models.CharField(max_length=255, default="")
|
||||||
registration_form = models.ForeignKey(RegistrationForm, on_delete=models.CASCADE, related_name='school_file_templates', blank=True)
|
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)
|
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):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|||||||
Binary file not shown.
Reference in New Issue
Block a user