diff --git a/Back-End/DocuSeal/urls.py b/Back-End/DocuSeal/urls.py index 9e4be83..06a434b 100644 --- a/Back-End/DocuSeal/urls.py +++ b/Back-End/DocuSeal/urls.py @@ -1,8 +1,9 @@ from django.urls import path, re_path -from .views import generate_jwt_token, clone_template, remove_template +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 index 0d46723..a0c35cb 100644 --- a/Back-End/DocuSeal/views.py +++ b/Back-End/DocuSeal/views.py @@ -13,8 +13,6 @@ import requests def generate_jwt_token(request): # Vérifier la clé API api_key = request.headers.get('X-Auth-Token') - print(f'api_key : {api_key}') - print(f'settings.DOCUSEAL_JWT["API_KEY"] : {settings.DOCUSEAL_JWT["API_KEY"]}') if not api_key or api_key != settings.DOCUSEAL_JWT["API_KEY"]: return Response({'error': 'Invalid API key'}, status=status.HTTP_401_UNAUTHORIZED) @@ -124,4 +122,35 @@ def remove_template(request, id): 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) \ No newline at end of file + return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) + +@csrf_exempt +@api_view(['GET']) +def download_template(request, slug): + # Vérifier la clé API + api_key = request.headers.get('X-Auth-Token') + if not api_key or api_key != settings.DOCUSEAL_JWT["API_KEY"]: + return Response({'error': 'Invalid API key'}, 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 cloner le template + download_url = f'https://docuseal.com/submitters/{slug}/download' + + # Faire la requête pour cloner le template + try: + response = requests.get(download_url, headers={ + 'Content-Type': 'application/json', + 'X-Auth-Token': settings.DOCUSEAL_JWT['API_KEY'] + }) + + 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/Subscriptions/models.py b/Back-End/Subscriptions/models.py index f889116..4eddb33 100644 --- a/Back-End/Subscriptions/models.py +++ b/Back-End/Subscriptions/models.py @@ -219,12 +219,16 @@ class RegistrationForm(models.Model): def __str__(self): return "RF_" + self.student.last_name + "_" + self.student.first_name +def registration_file_upload_to(instance, filename): + return f"registration_files/dossier_rf_{instance.register_form.pk}/{filename}" + class RegistrationTemplate(models.Model): master = models.ForeignKey(RegistrationTemplateMaster, on_delete=models.CASCADE, related_name='templates') template_id = models.IntegerField(primary_key=True) slug = models.CharField(max_length=255, default="") name = models.CharField(max_length=255, default="") registration_form = models.ForeignKey(RegistrationForm, on_delete=models.CASCADE, related_name='templates') + file = models.FileField(null=True,blank=True, upload_to=registration_file_upload_to) def __str__(self): return self.name @@ -234,7 +238,7 @@ class RegistrationTemplate(models.Model): """ Récupère tous les fichiers liés à un dossier d’inscription donné. """ - registration_files = RegistrationTemplate.objects.filter(register_form_id=register_form_id).order_by('template__order') + registration_files = RegistrationTemplate.objects.filter(registration_form=register_form_id) filenames = [] for reg_file in registration_files: filenames.append(reg_file.file.path) diff --git a/Front-End/src/app/actions/registerFileGroupAction.js b/Front-End/src/app/actions/registerFileGroupAction.js index 2280bc5..c051596 100644 --- a/Front-End/src/app/actions/registerFileGroupAction.js +++ b/Front-End/src/app/actions/registerFileGroupAction.js @@ -1,7 +1,8 @@ import { BE_SUBSCRIPTION_REGISTRATIONFILE_GROUPS_URL, BE_SUBSCRIPTION_REGISTRATION_TEMPLATES_URL, BE_SUBSCRIPTION_REGISTRATION_TEMPLATE_MASTER_URL, - FE_API_DOCUSEAL_CLONE_URL + FE_API_DOCUSEAL_CLONE_URL, + FE_API_DOCUSEAL_DOWNLOAD_URL } from '@/utils/Url'; const requestResponseHandler = async (response) => { @@ -208,4 +209,14 @@ export const cloneTemplate = (templateId, email) => { }) }) .then(requestResponseHandler) +} + +export const downloadTemplate = (slug) => { + return fetch(`${FE_API_DOCUSEAL_DOWNLOAD_URL}/${slug}`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + } + }) + .then(requestResponseHandler) } \ No newline at end of file diff --git a/Front-End/src/components/Inscription/InscriptionFormShared.js b/Front-End/src/components/Inscription/InscriptionFormShared.js index 067f655..830885c 100644 --- a/Front-End/src/components/Inscription/InscriptionFormShared.js +++ b/Front-End/src/components/Inscription/InscriptionFormShared.js @@ -7,8 +7,8 @@ import Loader from '@/components/Loader'; import Button from '@/components/Button'; import DjangoCSRFToken from '@/components/DjangoCSRFToken'; import Table from '@/components/Table'; -import { fetchRegistrationTemplateMaster, createRegistrationTemplates, fetchRegisterForm, deleteRegistrationTemplates, fetchTemplatesFromRegistrationFiles } from '@/app/actions/subscriptionAction'; -import { fetchRegistrationFileFromGroup } from '@/app/actions/registerFileGroupAction'; +import { fetchRegisterForm, fetchTemplatesFromRegistrationFiles } from '@/app/actions/subscriptionAction'; +import { fetchRegistrationFileFromGroup, fetchRegistrationTemplateMaster, downloadTemplate, createRegistrationTemplates, deleteRegistrationTemplates } from '@/app/actions/registerFileGroupAction'; import { Download, Upload, Trash2, Eye } from 'lucide-react'; import { BASE_URL } from '@/utils/Url'; import DraggableFileUpload from '@/components/DraggableFileUpload'; @@ -19,6 +19,7 @@ import StudentInfoForm from '@/components/Inscription/StudentInfoForm'; import FilesToSign from '@/components/Inscription/FilesToSign'; import FilesToUpload from '@/components/Inscription/FilesToUpload'; import { DocusealForm } from '@docuseal/react'; +import { ESTABLISHMENT_ID } from '@/utils/Url'; /** * Composant de formulaire d'inscription partagé @@ -170,7 +171,9 @@ export default function InscriptionFormShared({ student: { ...formData, guardians - } + }, + establishment: ESTABLISHMENT_ID, + status:3 } onSubmit(data); }; @@ -273,10 +276,11 @@ export default function InscriptionFormShared({ src={"https://docuseal.com/s/"+requiredFileTemplates[currentPage - 2].slug} withDownloadButton={false} onComplete={() => { - const formContainer = document.getElementById('form_container'); - if (formContainer) { - formContainer.style.display = 'none'; - } + downloadTemplate(requiredFileTemplates[currentPage - 2].slug) + .then((data) => { + logger.debug("PDF URL : ", data) + }) + .catch((error) => console.error(error)); }} > diff --git a/Front-End/src/pages/api/docuseal/downloadTemplate/[slug].js b/Front-End/src/pages/api/docuseal/downloadTemplate/[slug].js new file mode 100644 index 0000000..76402d2 --- /dev/null +++ b/Front-End/src/pages/api/docuseal/downloadTemplate/[slug].js @@ -0,0 +1,32 @@ +import { BE_DOCUSEAL_DOWNLOAD_TEMPLATE } from '@/utils/Url'; + +export default function handler(req, res) { + if (req.method === 'GET') { + const { slug } = req.query; + console.log('slug : ', slug) + + fetch(`${BE_DOCUSEAL_DOWNLOAD_TEMPLATE}/${slug}`, { + method: 'GET', + headers: { + 'X-Auth-Token': process.env.DOCUSEAL_API_KEY + } + }) + .then(response => { + if (!response.ok) { + return response.json().then(err => { throw new Error(err.message); }); + } + return response.json(); + }) + .then(data => { + console.log('Template downloaded successfully:', data); + res.status(200).json(data); + }) + .catch(error => { + console.error('Error downloading template:', error); + res.status(500).json({ error: 'Internal Server Error' }); + }); + } else { + res.setHeader('Allow', ['GET']); + res.status(405).end(`Method ${req.method} Not Allowed`); + } +} \ No newline at end of file diff --git a/Front-End/src/pages/api/docuseal/generateToken.js b/Front-End/src/pages/api/docuseal/generateToken.js index fd2d1dc..7418668 100644 --- a/Front-End/src/pages/api/docuseal/generateToken.js +++ b/Front-End/src/pages/api/docuseal/generateToken.js @@ -2,8 +2,6 @@ import { BE_DOCUSEAL_GET_JWT } from '@/utils/Url'; export default function handler(req, res) { if (req.method === 'POST') { - console.log('DOCUSEAL_API_KEY:', process.env.DOCUSEAL_API_KEY); - fetch(BE_DOCUSEAL_GET_JWT, { method: 'POST', headers: { diff --git a/Front-End/src/utils/Url.js b/Front-End/src/utils/Url.js index e79f7dc..c690d1e 100644 --- a/Front-End/src/utils/Url.js +++ b/Front-End/src/utils/Url.js @@ -8,6 +8,7 @@ export const BASE_URL = process.env.NEXT_PUBLIC_API_URL; export const BE_DOCUSEAL_GET_JWT = `${BASE_URL}/DocuSeal/generateToken` export const BE_DOCUSEAL_CLONE_TEMPLATE = `${BASE_URL}/DocuSeal/cloneTemplate` export const BE_DOCUSEAL_REMOVE_TEMPLATE = `${BASE_URL}/DocuSeal/removeTemplate` +export const BE_DOCUSEAL_DOWNLOAD_TEMPLATE = `${BASE_URL}/DocuSeal/downloadTemplate` // GESTION LOGIN export const BE_AUTH_NEW_PASSWORD_URL = `${BASE_URL}/Auth/newPassword` @@ -89,4 +90,5 @@ export const FE_PARENTS_SETTINGS_URL = `/parents/settings` export const FE_PARENTS_EDIT_INSCRIPTION_URL = `/parents/editInscription` // API DOCUSEAL -export const FE_API_DOCUSEAL_CLONE_URL = `/api/docuseal/cloneTemplate` \ No newline at end of file +export const FE_API_DOCUSEAL_CLONE_URL = `/api/docuseal/cloneTemplate` +export const FE_API_DOCUSEAL_DOWNLOAD_URL = `/api/docuseal/downloadTemplate` \ No newline at end of file