feat: Ajout des Bundles de fichiers [#24]

This commit is contained in:
Luc SORIGNET
2025-02-10 18:35:24 +01:00
parent fb7fbaf839
commit ffc6ce8de8
25 changed files with 1736 additions and 743 deletions

View File

@ -161,6 +161,13 @@ class Student(models.Model):
return self.birth_date.strftime('%d-%m-%Y')
return None
class RegistrationFileGroup(models.Model):
name = models.CharField(max_length=255)
description = models.TextField(blank=True, null=True)
def __str__(self):
return self.name
def registration_file_path(instance, filename):
# Génère le chemin : registration_files/dossier_rf_{student_id}/filename
return f'registration_files/dossier_rf_{instance.student_id}/{filename}'
@ -196,6 +203,11 @@ class RegistrationForm(models.Model):
# Many-to-Many Relationship
discounts = models.ManyToManyField(Discount, blank=True, related_name='register_forms')
fileGroup = models.ForeignKey(RegistrationFileGroup,
on_delete=models.CASCADE,
related_name='file_group',
null=True,
blank=True)
def __str__(self):
return "RF_" + self.student.last_name + "_" + self.student.first_name
@ -209,6 +221,7 @@ class RegistrationFileTemplate(models.Model):
order = models.PositiveIntegerField(default=0) # Ajout du champ order
date_added = models.DateTimeField(auto_now_add=True)
is_required = models.BooleanField(default=False)
group = models.ForeignKey(RegistrationFileGroup, on_delete=models.CASCADE, related_name='file_templates')
@property
def formatted_date_added(self):

View File

@ -1,5 +1,5 @@
from rest_framework import serializers
from .models import RegistrationFileTemplate, RegistrationFile, RegistrationForm, Student, Guardian, Sibling, Language
from .models import RegistrationFileTemplate, RegistrationFile, RegistrationFileGroup, RegistrationForm, Student, Guardian, Sibling, Language
from School.models import SchoolClass, Fee, Discount, FeeType
from School.serializers import FeeSerializer, DiscountSerializer
from Auth.models import Profile
@ -11,6 +11,11 @@ from django.utils import timezone
import pytz
from datetime import datetime
class RegistrationFileGroupSerializer(serializers.ModelSerializer):
class Meta:
model = RegistrationFileGroup
fields = '__all__'
class RegistrationFileSerializer(serializers.ModelSerializer):
class Meta:
model = RegistrationFile

View File

@ -3,95 +3,205 @@
<head>
<meta charset="UTF-8">
<title>{{ pdf_title }}</title>
<style type="text/css">
<style>
@page {
size: A4;
margin: 2cm;
}
body {
font-weight: 200;
font-size: 14px;
font-family: Helvetica, Arial, sans-serif;
font-size: 11pt;
line-height: 1.3;
margin: 0;
padding: 0;
color:#333;
}
.container {
width: 100%;
}
.header {
font-size: 20px;
font-weight: 100;
text-align: center;
color: #007cae;
margin-bottom: 30px;
border-bottom: 2px solid #333;
padding-bottom: 10px;
}
.title {
font-size: 22px;
font-weight: 100;
/* text-align: right;*/
padding: 10px 20px 0px 20px;
font-size: 18pt;
font-weight: bold;
margin: 0;
padding: 0;
}
.title span {
color: #007cae;
.section {
margin-bottom: 15px; /* Réduit de 25px à 15px */
padding: 10px; /* Réduit de 15px à 10px */
page-break-inside: avoid;
}
.details {
padding: 10px 20px 0px 20px;
text-align: left !important;
/*margin-left: 40%;*/
.section-title {
font-size: 16pt;
font-weight: bold;
margin: 0 0 10px 0; /* Réduit de 15px à 10px */
padding-bottom: 3px; /* Réduit de 5px à 3px */
border-bottom: 1px solid #333;
text-align: center;
}
.hrItem {
border: none;
height: 1px;
/* Set the hr color */
color: #333; /* old IE */
background-color: #fff; /* Modern Browsers */
table {
width: 100%;
border-collapse: collapse;
margin-bottom: 10px;
}
td {
padding: 4px;
vertical-align: top;
}
.label-cell {
font-weight: bold;
width: 150px;
}
.value-cell {
width: auto;
}
.half-row td {
width: 50%;
}
.subsection-title {
font-size: 12pt;
font-weight: bold;
margin-bottom: 5px; /* Réduit de 10px à 5px */
}
.signature {
margin-top: 30px;
text-align: right;
font-style: italic;
}
.signature-text {
font-weight: bold;
}
.clearfix::after {
content: "";
clear: both;
display: table;
}
p {
margin: 0; /* Ajout de margin 0 pour les paragraphes */
padding: 0; /* Ajout de padding 0 pour les paragraphes */
}
</style>
</head>
<body>
{% load myTemplateTag %}
<div class='wrapper'>
<div class='header'>
<p class='title'>{{ pdf_title }}</p>
<div class="container">
<div class="header">
<h1 class="title">{{ pdf_title }}</h1>
</div>
<div>
<div class='details'>
Signé le : <b>{{ signatureDate }}</b> <br/>
A : <b>{{ signatureTime }}</b>
<hr class='hrItem' />
<h1>ELEVE</h1>
<div class="section">
<h2 class="section-title">ÉLÈVE</h2>
{% with level=student|getStudentLevel %}
{% with gender=student|getStudentGender %}
NOM : <b>{{ student.last_name }}</b> <br/>
PRENOM : <b>{{ student.first_name }}</b> <br/>
ADRESSE : <b>{{ student.address }}</b> <br/>
GENRE : <b>{{ gender }}</b> <br/>
NE(E) LE : <b>{{ student.birth_date }}</b> <br/>
A : <b>{{ student.birth_place }} ({{ student.birth_postal_code }})</b> <br/>
NATIONALITE : <b>{{ student.nationality }}</b> <br/>
NIVEAU : <b>{{ level }}</b> <br/>
MEDECIN TRAITANT : <b>{{ student.attending_physician }}</b> <br/>
<table>
<tr class="half-row">
<td class="label-cell">NOM :</td>
<td>{{ student.last_name }}</td>
<td class="label-cell">PRÉNOM :</td>
<td>{{ student.first_name }}</td>
</tr>
<tr>
<td class="label-cell">ADRESSE :</td>
<td colspan="3">{{ student.address }}</td>
</tr>
<tr class="half-row">
<td class="label-cell">GENRE :</td>
<td>{{ gender }}</td>
<td class="label-cell">NÉ(E) LE :</td>
<td>{{ student.birth_date }}</td>
</tr>
<tr>
<td class="label-cell">À :</td>
<td colspan="3">{{ student.birth_place }} ({{ student.birth_postal_code }})</td>
</tr>
<tr class="half-row">
<td class="label-cell">NATIONALITÉ :</td>
<td>{{ student.nationality }}</td>
<td class="label-cell">NIVEAU :</td>
<td>{{ level }}</td>
</tr>
<tr>
<td class="label-cell">MÉDECIN TRAITANT :</td>
<td colspan="3">{{ student.attending_physician }}</td>
</tr>
</table>
{% endwith %}
{% endwith %}
<hr class='hrItem' />
<h1>RESPONSABLES</h1>
</div>
<div class="section">
<h2 class="section-title">RESPONSABLES</h2>
{% with guardians=student.getGuardians %}
{% with siblings=student.getGuardians %}
{% for guardian in guardians%}
<h2>Guardian {{ forloop.counter }}</h2>
NOM : <b>{{ guardian.last_name }}</b> <br/>
PRENOM : <b>{{ guardian.first_name }}</b> <br/>
ADRESSE : <b>{{ guardian.address }}</b> <br/>
NE(E) LE : <b>{{ guardian.birth_date }}</b> <br/>
MAIL : <b>{{ guardian.email }}</b> <br/>
TEL : <b>{{ guardian.phone }}</b> <br/>
PROFESSION : <b>{{ guardian.profession }}</b> <br/>
<div class="subsection">
<h3 class="subsection-title">Responsable {{ forloop.counter }}</h3>
<table>
<tr class="half-row">
<td class="label-cell">NOM :</td>
<td>{{ guardian.last_name }}</td>
<td class="label-cell">PRÉNOM :</td>
<td>{{ guardian.first_name }}</td>
</tr>
<tr>
<td class="label-cell">ADRESSE :</td>
<td colspan="3">{{ guardian.address }}</td>
</tr>
<tr class="half-row">
<td class="label-cell">NÉ(E) LE :</td>
<td>{{ guardian.birth_date }}</td>
<td class="label-cell">EMAIL :</td>
<td>{{ guardian.email }}</td>
</tr>
<tr class="half-row">
<td class="label-cell">TÉLÉPHONE :</td>
<td>{{ guardian.phone }}</td>
<td class="label-cell">PROFESSION :</td>
<td>{{ guardian.profession }}</td>
</tr>
</table>
</div>
{% endfor %}
<hr class='hrItem' />
<h1>FRATRIE</h1>
{% endwith %}
</div>
<div class="section">
<h2 class="section-title">FRATRIE</h2>
{% with siblings=student.getGuardians %}
{% for sibling in siblings%}
<h2>Frère - Soeur {{ forloop.counter }}</h2>
NOM : <b>{{ sibling.last_name }}</b> <br/>
PRENOM : <b>{{ sibling.first_name }}</b> <br/>
NE(E) LE : <b>{{ sibling.birth_date }}</b> <br/>
<div class="subsection">
<h3 class="subsection-title">Frère/Sœur {{ forloop.counter }}</h3>
<table>
<tr class="half-row">
<td class="label-cell">NOM :</td>
<td>{{ sibling.last_name }}</td>
<td class="label-cell">PRÉNOM :</td>
<td>{{ sibling.first_name }}</td>
</tr>
<tr>
<td class="label-cell">NÉ(E) LE :</td>
<td colspan="3">{{ sibling.birth_date }}</td>
</tr>
</table>
</div>
{% endfor %}
<hr class='hrItem' />
<h1>MODALITES DE PAIEMENT</h1>
{% endwith %}
</div>
<div class="section">
<h2 class="section-title">MODALITÉS DE PAIEMENT</h2>
{% with paymentMethod=student|getStudentPaymentMethod %}
<b>{{ paymentMethod }}</b> <br/>
{% endwith %}
{% endwith %}
<p>{{ paymentMethod }}</p>
{% endwith %}
</div>
<div class="signature">
Fait le <span class="signature-text">{{ signatureDate }}</span> à <span class="signature-text">{{ signatureTime }}</span>
</div>
</div>
</body>
</html>

View File

@ -1,41 +1,41 @@
from django.urls import path, re_path
from . import views
from .views import RegistrationFileTemplateView, RegisterFormListView, RegisterFormView, StudentView, GuardianView, ChildrenListView, StudentListView, RegistrationFileView
# RF
from .views import RegisterFormView, RegisterFormWithIdView, send, resend, archive
# SubClasses
from .views import StudentView, GuardianView, ChildrenListView, StudentListView
# Files
from .views import RegistrationFileTemplateView, RegistrationFileTemplateSimpleView, RegistrationFileView, RegistrationFileSimpleView
from .views import RegistrationFileGroupView, RegistrationFileGroupSimpleView, get_registration_files_by_group
urlpatterns = [
re_path(r'^registerForms/(?P<_filter>[a-zA-z]+)$', RegisterFormListView.as_view(), name="registerForms"),
re_path(r'^registerForm$', RegisterFormView.as_view(), name="registerForm"),
re_path(r'^registerForm/(?P<_id>[0-9]+)$', RegisterFormView.as_view(), name="registerForm"),
# Page de formulaire d'inscription - ELEVE
re_path(r'^student/(?P<_id>[0-9]+)$', StudentView.as_view(), name="students"),
# Page de formulaire d'inscription - RESPONSABLE
re_path(r'^lastGuardian$', GuardianView.as_view(), name="lastGuardian"),
# Envoi d'un dossier d'inscription
re_path(r'^send/(?P<_id>[0-9]+)$', views.send, name="send"),
# Archivage d'un dossier d'inscription
re_path(r'^archive/(?P<_id>[0-9]+)$', views.archive, name="archive"),
# Envoi d'une relance de dossier d'inscription
re_path(r'^sendRelance/(?P<_id>[0-9]+)$', views.relance, name="sendRelance"),
# Page PARENT - Liste des children
re_path(r'^children/(?P<_id>[0-9]+)$', ChildrenListView.as_view(), name="children"),
re_path(r'^registerForms/(?P<id>[0-9]+)/archive$', archive, name="archive"),
re_path(r'^registerForms/(?P<id>[0-9]+)/resend$', resend, name="resend"),
re_path(r'^registerForms/(?P<id>[0-9]+)/send$', send, name="send"),
re_path(r'^registerForms/(?P<id>[0-9]+)$', RegisterFormWithIdView.as_view(), name="registerForm"),
re_path(r'^registerForms$', RegisterFormView.as_view(), name="registerForms"),
# Page INSCRIPTION - Liste des élèves
re_path(r'^students$', StudentListView.as_view(), name="students"),
# Page de formulaire d'inscription - ELEVE
re_path(r'^students/(?P<id>[0-9]+)$', StudentView.as_view(), name="students"),
# Page PARENT - Liste des children
re_path(r'^children/(?P<id>[0-9]+)$', ChildrenListView.as_view(), name="children"),
# Page de formulaire d'inscription - RESPONSABLE
re_path(r'^lastGuardianId$', GuardianView.as_view(), name="lastGuardianId"),
# modèles de fichiers d'inscription
re_path(r'^registrationFileTemplates/(?P<id>[0-9]+)$', RegistrationFileTemplateSimpleView.as_view(), name="registrationFileTemplate"),
re_path(r'^registrationFileTemplates$', RegistrationFileTemplateView.as_view(), name='registrationFileTemplates'),
re_path(r'^registrationFileTemplates/(?P<_id>[0-9]+)$', RegistrationFileTemplateView.as_view(), name="registrationFileTemplate"),
# fichiers d'inscription
re_path(r'^registrationFiles/(?P<_id>[0-9]+)$', RegistrationFileView.as_view(), name='registrationFiles'),
re_path(r'^registrationFiles', RegistrationFileView.as_view(), name="registrationFiles"),
re_path(r'^registrationFiles/(?P<id>[0-9]+)$', RegistrationFileSimpleView.as_view(), name='registrationFiles'),
re_path(r'^registrationFiles$', RegistrationFileView.as_view(), name="registrationFiles"),
re_path(r'^registrationFileGroups/(?P<id>[0-9]+)$', RegistrationFileGroupSimpleView.as_view(), name='registrationFileGroupDetail'),
re_path(r'^registrationFileGroups/(?P<id>[0-9]+)/registrationFiles$', get_registration_files_by_group, name="get_registration_files_by_group"),
re_path(r'^registrationFileGroups$', RegistrationFileGroupView.as_view(), name='registrationFileGroups'),
]

View File

@ -1,450 +0,0 @@
from django.http.response import JsonResponse
from django.contrib.auth import login, authenticate, get_user_model
from django.views.decorators.csrf import ensure_csrf_cookie, csrf_protect
from django.utils.decorators import method_decorator
from django.core.cache import cache
from django.core.paginator import Paginator
from django.core.files import File
from django.db.models import Q # Ajout de cet import
from rest_framework.parsers import JSONParser,MultiPartParser, FormParser
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework import status
from drf_yasg.utils import swagger_auto_schema
from drf_yasg import openapi
import json
from pathlib import Path
import os
from io import BytesIO
import Subscriptions.mailManager as mailer
import Subscriptions.util as util
from Subscriptions.automate import Automate_RF_Register, load_config, getStateMachineObjectState, updateStateMachine
from .serializers import RegistrationFormSerializer, StudentSerializer, RegistrationFormByParentSerializer, StudentByRFCreationSerializer, RegistrationFileSerializer, RegistrationFileTemplateSerializer, RegistrationFormByParentSerializer, StudentByRFCreationSerializer
from .pagination import CustomPagination
from .signals import clear_cache
from .models import Student, Guardian, RegistrationForm, RegistrationFileTemplate, RegistrationFile
from .automate import Automate_RF_Register, load_config, getStateMachineObjectState, updateStateMachine
from Auth.models import Profile
from N3wtSchool import settings, renderers, bdd
class RegisterFormListView(APIView):
"""
Gère la liste des dossiers dinscription, lecture et création.
"""
pagination_class = CustomPagination
def get_register_form(self, _filter, search=None):
"""
Récupère les fiches d'inscriptions en fonction du filtre passé.
_filter: Filtre pour déterminer l'état des fiches ('pending', 'archived', 'subscribed')
search: Terme de recherche (optionnel)
"""
if _filter == 'pending':
exclude_states = [RegistrationForm.RegistrationFormStatus.RF_VALIDATED, RegistrationForm.RegistrationFormStatus.RF_ARCHIVED]
return bdd.searchObjects(RegistrationForm, search, _excludeStates=exclude_states)
elif _filter == 'archived':
return bdd.getObjects(RegistrationForm, 'status', RegistrationForm.RegistrationFormStatus.RF_ARCHIVED)
elif _filter == 'subscribed':
return bdd.getObjects(RegistrationForm, 'status', RegistrationForm.RegistrationFormStatus.RF_VALIDATED)
return None
@swagger_auto_schema(
manual_parameters=[
openapi.Parameter('_filter', openapi.IN_PATH, description="filtre", type=openapi.TYPE_STRING, enum=['pending', 'archived', 'subscribed'], required=True),
openapi.Parameter('search', openapi.IN_QUERY, description="search", type=openapi.TYPE_STRING, required=False),
openapi.Parameter('page_size', openapi.IN_QUERY, description="limite de page lors de la pagination", type=openapi.TYPE_INTEGER, required=False),
],
responses={200: RegistrationFormSerializer(many=True)}
)
def get(self, request, _filter):
"""
Récupère les fiches d'inscriptions en fonction du filtre passé.
"""
# Récupération des paramètres
search = request.GET.get('search', '').strip()
page_size = request.GET.get('page_size', None)
# Gestion du page_size
if page_size is not None:
try:
page_size = int(page_size)
except ValueError:
page_size = settings.NB_RESULT_PER_PAGE
# Définir le cache_key en fonction du filtre
page_number = request.GET.get('page', 1)
cache_key = f'N3WT_ficheInscriptions_{_filter}_page_{page_number}_search_{search if _filter == "pending" else ""}'
cached_page = cache.get(cache_key)
if cached_page:
return JsonResponse(cached_page, safe=False)
# Récupérer les fiches d'inscriptions en fonction du filtre
registerForms_List = self.get_register_form(_filter, search)
if not registerForms_List:
return JsonResponse({'error' : 'aucune donnée trouvée', 'count' :0}, safe=False)
# Pagination
paginator = self.pagination_class()
page = paginator.paginate_queryset(registerForms_List, request)
if page is not None:
registerForms_serializer = RegistrationFormSerializer(page, many=True)
response_data = paginator.get_paginated_response(registerForms_serializer.data)
cache.set(cache_key, response_data, timeout=60*15)
return JsonResponse(response_data, safe=False)
return JsonResponse({'error' : 'aucune donnée trouvée', 'count' :0}, safe=False)
@swagger_auto_schema(
manual_parameters=[
],
responses={200: RegistrationFormSerializer(many=True)}
)
def post(self, request):
studentFormList_serializer=JSONParser().parse(request)
for studentForm_data in studentFormList_serializer:
# Ajout de la date de mise à jour
studentForm_data["last_update"] = util.convertToStr(util._now(), '%d-%m-%Y %H:%M')
json.dumps(studentForm_data)
# Ajout du code d'inscription
code = util.genereRandomCode(12)
studentForm_data["codeLienInscription"] = code
studentForm_serializer = RegistrationFormSerializer(data=studentForm_data)
if studentForm_serializer.is_valid():
studentForm_serializer.save()
return JsonResponse(studentForm_serializer.errors, safe=False)
@method_decorator(csrf_protect, name='dispatch')
@method_decorator(ensure_csrf_cookie, name='dispatch')
class RegisterFormView(APIView):
"""
Gère la lecture, création, modification et suppression dun dossier dinscription.
"""
pagination_class = CustomPagination
def get(self, request, _id):
"""
Récupère un dossier d'inscription donné.
"""
registerForm=bdd.getObject(RegistrationForm, "student__id", _id)
registerForm_serializer=RegistrationFormSerializer(registerForm)
return JsonResponse(registerForm_serializer.data, safe=False)
def post(self, request):
"""
Crée un dossier d'inscription.
"""
studentForm_data=JSONParser().parse(request)
# Ajout de la date de mise à jour
studentForm_data["last_update"] = util.convertToStr(util._now(), '%d-%m-%Y %H:%M')
json.dumps(studentForm_data)
# Ajout du code d'inscription
code = util.genereRandomCode(12)
studentForm_data["codeLienInscription"] = code
guardiansId = studentForm_data.pop('idGuardians', [])
studentForm_serializer = RegistrationFormSerializer(data=studentForm_data)
if studentForm_serializer.is_valid():
di = studentForm_serializer.save()
# Mise à jour de l'automate
updateStateMachine(di, 'creationDI')
# Récupération du reponsable associé
for guardianId in guardiansId:
guardian = Guardian.objects.get(id=guardianId)
di.student.guardians.add(guardian)
di.save()
return JsonResponse(studentForm_serializer.data, safe=False)
return JsonResponse(studentForm_serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST)
def put(self, request, _id):
"""
Modifie un dossier d'inscription donné.
"""
studentForm_data=JSONParser().parse(request)
_status = studentForm_data.pop('status', 0)
studentForm_data["last_update"] = str(util.convertToStr(util._now(), '%d-%m-%Y %H:%M'))
registerForm = bdd.getObject(_objectName=RegistrationForm, _columnName='student__id', _value=_id)
if _status == RegistrationForm.RegistrationFormStatus.RF_UNDER_REVIEW:
try:
# Génération de la fiche d'inscription au format PDF
base_dir = f"registration_files/dossier_rf_{registerForm.pk}"
os.makedirs(base_dir, exist_ok=True)
# Fichier PDF initial
initial_pdf = f"{base_dir}/rf_{registerForm.student.last_name}_{registerForm.student.first_name}.pdf"
registerForm.registration_file = util.rfToPDF(registerForm, initial_pdf)
registerForm.save()
# Récupération des fichiers d'inscription
fileNames = RegistrationFile.get_files_from_rf(registerForm.pk)
if registerForm.registration_file:
fileNames.insert(0, registerForm.registration_file.path)
# Création du fichier PDF Fusionné
merged_pdf = f"{base_dir}/dossier_complet_{registerForm.pk}.pdf"
util.merge_files_pdf(fileNames, merged_pdf)
# Mise à jour du champ registration_file avec le fichier fusionné
with open(merged_pdf, 'rb') as f:
registerForm.registration_file.save(
os.path.basename(merged_pdf),
File(f),
save=True
)
# Mise à jour de l'automate
updateStateMachine(registerForm, 'saisiDI')
except Exception as e:
return JsonResponse({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
elif _status == RegistrationForm.RegistrationFormStatus.RF_VALIDATED:
# L'école a validé le dossier d'inscription
# Mise à jour de l'automate
updateStateMachine(registerForm, 'valideDI')
studentForm_serializer = RegistrationFormSerializer(registerForm, data=studentForm_data)
if studentForm_serializer.is_valid():
studentForm_serializer.save()
return JsonResponse(studentForm_serializer.data, safe=False)
return JsonResponse(studentForm_serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST)
def delete(self, request, id):
"""
Supprime un dossier d'inscription donné.
"""
register_form = bdd.getObject(_objectName=RegistrationForm, _columnName='student__id', _value=id)
if register_form != None:
student = register_form.student
student.guardians.clear()
student.profiles.clear()
student.registration_files.clear()
student.delete()
clear_cache()
return JsonResponse("La suppression du dossier a été effectuée avec succès", safe=False)
return JsonResponse({"errorMessage":'Aucun dossier d\'inscription rattaché à l\'élève'}, safe=False, status=status.HTTP_404_NOT_FOUND)
class StudentView(APIView):
"""
Gère la lecture dun élève donné.
"""
def get(self, request, _id):
student = bdd.getObject(_objectName=Student, _columnName='id', _value=_id)
if student is None:
return JsonResponse({"errorMessage":'Aucun élève trouvé'}, safe=False, status=status.HTTP_404_NOT_FOUND)
student_serializer = StudentSerializer(student)
return JsonResponse(student_serializer.data, safe=False)
class GuardianView(APIView):
"""
Récupère le dernier ID de responsable légal créé.
"""
def get(self, request):
lastGuardian = bdd.getLastId(Guardian)
return JsonResponse({"lastid":lastGuardian}, safe=False)
def send(request, _id):
"""
Envoie le dossier dinscription par e-mail.
"""
register_form = bdd.getObject(_objectName=RegistrationForm, _columnName='student__id', _value=_id)
if register_form != None:
student = register_form.student
guardian = student.getMainGuardian()
email = guardian.email
errorMessage = mailer.sendRegisterForm(email)
if errorMessage == '':
register_form.last_update=util.convertToStr(util._now(), '%d-%m-%Y %H:%M')
# Mise à jour de l'automate
updateStateMachine(register_form, 'envoiDI')
return JsonResponse({"message": f"Le dossier d'inscription a bien été envoyé à l'addresse {email}"}, safe=False)
return JsonResponse({"errorMessage":errorMessage}, safe=False, status=status.HTTP_400_BAD_REQUEST)
return JsonResponse({"errorMessage":'Aucun dossier d\'inscription rattaché à l\'élève'}, safe=False, status=status.HTTP_404_NOT_FOUND)
def archive(request, _id):
"""
Archive le dossier dinscription visé.
"""
register_form = bdd.getObject(_objectName=RegistrationForm, _columnName='student__id', _value=_id)
if register_form != None:
register_form.last_update=util.convertToStr(util._now(), '%d-%m-%Y %H:%M')
# Mise à jour de l'automate
updateStateMachine(register_form, 'archiveDI')
return JsonResponse({"errorMessage":''}, safe=False, status=status.HTTP_400_BAD_REQUEST)
return JsonResponse({"errorMessage":'Aucun dossier d\'inscription rattaché à l\'élève'}, safe=False, status=status.HTTP_404_NOT_FOUND)
def relance(request, _id):
"""
Relance un dossier dinscription par e-mail.
"""
register_form = bdd.getObject(_objectName=RegistrationForm, _columnName='student__id', _value=_id)
if register_form != None:
student = register_form.student
guardian = student.getMainGuardian()
email = guardian.email
errorMessage = mailer.envoieRelanceDossierInscription(email, register_form.codeLienInscription)
if errorMessage == '':
register_form.status=RegistrationForm.RegistrationFormStatus.RF_SENT
register_form.last_update=util.convertToStr(util._now(), '%d-%m-%Y %H:%M')
register_form.save()
return JsonResponse({"errorMessage":errorMessage}, safe=False, status=status.HTTP_400_BAD_REQUEST)
return JsonResponse({"errorMessage":'Aucun dossier d\'inscription rattaché à l\'élève'}, safe=False, status=status.HTTP_404_NOT_FOUND)
# API utilisée pour la vue parent
class ChildrenListView(APIView):
"""
Pour la vue parent : liste les élèves rattachés à un profil donné.
"""
# Récupération des élèves d'un parent
# idProfile : identifiant du profil connecté rattaché aux fiches d'élèves
def get(self, request, _id):
students = bdd.getObjects(_objectName=RegistrationForm, _columnName='student__guardians__associated_profile__id', _value=_id)
students_serializer = RegistrationFormByParentSerializer(students, many=True)
return JsonResponse(students_serializer.data, safe=False)
# API utilisée pour la vue de création d'un DI
class StudentListView(APIView):
"""
Pour la vue de création dun dossier dinscription : liste les élèves disponibles.
"""
# Récupération de la liste des élèves inscrits ou en cours d'inscriptions
def get(self, request):
students = bdd.getAllObjects(_objectName=Student)
students_serializer = StudentByRFCreationSerializer(students, many=True)
return JsonResponse(students_serializer.data, safe=False)
class RegistrationFileTemplateView(APIView):
"""
Gère les fichiers templates pour les dossiers dinscription.
"""
parser_classes = (MultiPartParser, FormParser)
def get(self, request, _id=None):
"""
Récupère les fichiers templates pour les dossiers dinscription.
"""
if _id is None:
files = RegistrationFileTemplate.objects.all()
serializer = RegistrationFileTemplateSerializer(files, many=True)
return Response(serializer.data)
else :
registationFileTemplate = bdd.getObject(_objectName=RegistrationFileTemplate, _columnName='id', _value=_id)
if registationFileTemplate is None:
return JsonResponse({"errorMessage":'Le fichier d\'inscription n\'a pas été trouvé'}, safe=False, status=status.HTTP_404_NOT_FOUND)
serializer = RegistrationFileTemplateSerializer(registationFileTemplate)
return JsonResponse(serializer.data, safe=False)
def put(self, request, _id):
"""
Met à jour un fichier template existant.
"""
registationFileTemplate = bdd.getObject(_objectName=RegistrationFileTemplate, _columnName='id', _value=_id)
if registationFileTemplate is None:
return JsonResponse({'erreur': 'Le fichier d\'inscription n\'a pas été trouvé'}, safe=False, status=status.HTTP_404_NOT_FOUND)
serializer = RegistrationFileTemplateSerializer(registationFileTemplate,data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def post(self, request):
"""
Crée un fichier template pour les dossiers dinscription.
"""
serializer = RegistrationFileTemplateSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def delete(self, request, _id):
"""
Supprime un fichier template existant.
"""
registrationFileTemplate = bdd.getObject(_objectName=RegistrationFileTemplate, _columnName='id', _value=_id)
if registrationFileTemplate is not None:
registrationFileTemplate.file.delete() # Supprimer le fichier uploadé
registrationFileTemplate.delete()
return JsonResponse({'message': 'La suppression du fichier d\'inscription a été effectuée avec succès'}, safe=False, status=status.HTTP_204_NO_CONTENT)
else:
return JsonResponse({'erreur': 'Le fichier d\'inscription n\'a pas été trouvé'}, safe=False, status=status.HTTP_404_NOT_FOUND)
class RegistrationFileView(APIView):
"""
Gère la création, mise à jour et suppression de fichiers liés à un dossier dinscription.
"""
parser_classes = (MultiPartParser, FormParser)
def get(self, request, _id=None):
"""
Récupère les fichiers liés à un dossier dinscription donné.
"""
if (_id is None):
files = RegistrationFile.objects.all()
serializer = RegistrationFileSerializer(files, many=True)
return Response(serializer.data)
else:
registationFile = bdd.getObject(_objectName=RegistrationFile, _columnName='id', _value=_id)
if registationFile is None:
return JsonResponse({"errorMessage":'Le fichier d\'inscription n\'a pas été trouvé'}, safe=False, status=status.HTTP_404_NOT_FOUND)
serializer = RegistrationFileSerializer(registationFile)
return JsonResponse(serializer.data, safe=False)
def post(self, request):
"""
Crée un RegistrationFile pour le RegistrationForm associé.
"""
serializer = RegistrationFileSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def put(self, request, fileId):
"""
Met à jour un RegistrationFile existant.
"""
registrationFile = bdd.getObject(_objectName=RegistrationFile, _columnName='id', _value=fileId)
if registrationFile is None:
return JsonResponse({'erreur': 'Le fichier d\'inscription n\'a pas été trouvé'}, safe=False, status=status.HTTP_404_NOT_FOUND)
serializer = RegistrationFileSerializer(registrationFile, data=request.data)
if serializer.is_valid():
serializer.save()
return Response({'message': 'Fichier mis à jour avec succès', 'data': serializer.data}, status=status.HTTP_200_OK)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def delete(self, request, _id):
"""
Supprime un RegistrationFile existant.
"""
registrationFile = bdd.getObject(_objectName=RegistrationFile, _columnName='id', _value=_id)
if registrationFile is not None:
registrationFile.file.delete() # Supprimer le fichier uploadé
registrationFile.delete()
return JsonResponse({'message': 'La suppression du fichier a été effectuée avec succès'}, safe=False)
else:
return JsonResponse({'erreur': 'Le fichier n\'a pas été trouvé'}, safe=False, status=status.HTTP_404_NOT_FOUND)

View File

@ -0,0 +1,24 @@
from .register_form_views import RegisterFormView, RegisterFormWithIdView, send, resend, archive
from .registration_file_views import RegistrationFileTemplateView, RegistrationFileTemplateSimpleView, RegistrationFileView, RegistrationFileSimpleView
from .registration_file_group_views import RegistrationFileGroupView, RegistrationFileGroupSimpleView, get_registration_files_by_group
from .student_views import StudentView, StudentListView, ChildrenListView
from .guardian_views import GuardianView
__all__ = [
'RegisterFormView',
'RegisterFormWithIdView',
'send',
'resend',
'archive',
'RegistrationFileView',
'RegistrationFileSimpleView',
'RegistrationFileTemplateView',
'RegistrationFileTemplateSimpleView',
'RegistrationFileGroupView',
'RegistrationFileGroupSimpleView',
'get_registration_files_by_group',
'StudentView',
'StudentListView',
'ChildrenListView',
'GuardianView',
]

View File

@ -0,0 +1,34 @@
from django.http.response import JsonResponse
from rest_framework.views import APIView
from drf_yasg.utils import swagger_auto_schema
from drf_yasg import openapi
from Subscriptions.models import Guardian
from N3wtSchool import bdd
class GuardianView(APIView):
"""
Gestion des responsables légaux.
"""
@swagger_auto_schema(
operation_description="Récupère le dernier ID de responsable légal créé",
operation_summary="Récupèrer le dernier ID de responsable légal créé",
responses={
200: openapi.Response(
description="Dernier ID du responsable légal",
schema=openapi.Schema(
type=openapi.TYPE_OBJECT,
properties={
'lastid': openapi.Schema(
type=openapi.TYPE_INTEGER,
description="Dernier ID créé"
)
}
)
)
}
)
def get(self, request):
lastGuardian = bdd.getLastId(Guardian)
return JsonResponse({"lastid":lastGuardian}, safe=False)

View File

@ -0,0 +1,385 @@
from django.http.response import JsonResponse
from django.views.decorators.csrf import ensure_csrf_cookie, csrf_protect
from django.utils.decorators import method_decorator
from django.core.cache import cache
from rest_framework.parsers import JSONParser
from rest_framework.views import APIView
from rest_framework.decorators import action, api_view
from rest_framework import status
from drf_yasg.utils import swagger_auto_schema
from drf_yasg import openapi
import json
import os
from django.core.files import File
import Subscriptions.mailManager as mailer
import Subscriptions.util as util
from Subscriptions.serializers import RegistrationFormSerializer
from Subscriptions.pagination import CustomPagination
from Subscriptions.signals import clear_cache
from Subscriptions.models import Student, Guardian, RegistrationForm, RegistrationFile, RegistrationFileGroup
from Subscriptions.automate import updateStateMachine
from N3wtSchool import settings, bdd
import logging
logger = logging.getLogger(__name__)
# /Subscriptions/registerForms
class RegisterFormView(APIView):
"""
Gère la liste des dossiers dinscription, lecture et création.
"""
pagination_class = CustomPagination
@swagger_auto_schema(
manual_parameters=[
openapi.Parameter('filter', openapi.IN_QUERY, description="filtre", type=openapi.TYPE_STRING, enum=['pending', 'archived', 'subscribed'], required=True),
openapi.Parameter('search', openapi.IN_QUERY, description="search", type=openapi.TYPE_STRING, required=False),
openapi.Parameter('page_size', openapi.IN_QUERY, description="limite de page lors de la pagination", type=openapi.TYPE_INTEGER, required=False),
],
responses={200: RegistrationFormSerializer(many=True)},
operation_description="Récupère les dossier d'inscriptions en fonction du filtre passé.",
operation_summary="Récupérer les dossier d'inscriptions",
examples={
"application/json": [
{
"id": 1,
"student": {
"id": 1,
"first_name": "John",
"last_name": "Doe",
"date_of_birth": "2010-01-01"
},
"status": "pending",
"last_update": "10-02-2025 10:00"
},
{
"id": 2,
"student": {
"id": 2,
"first_name": "Jane",
"last_name": "Doe",
"date_of_birth": "2011-02-02"
},
"status": "archived",
"last_update": "09-02-2025 09:00"
}
]
}
)
def get(self, request):
"""
Récupère les fiches d'inscriptions en fonction du filtre passé.
"""
# Récupération des paramètres
filter = request.GET.get('filter', '').strip()
search = request.GET.get('search', '').strip()
page_size = request.GET.get('page_size', None)
# Gestion du page_size
if page_size is not None:
try:
page_size = int(page_size)
except ValueError:
page_size = settings.NB_RESULT_PER_PAGE
# Définir le cache_key en fonction du filtre
page_number = request.GET.get('page', 1)
cache_key = f'N3WT_ficheInscriptions_{filter}_page_{page_number}_search_{search if filter == "pending" else ""}'
cached_page = cache.get(cache_key)
if cached_page:
return JsonResponse(cached_page, safe=False)
# Récupérer les dossier d'inscriptions en fonction du filtre
registerForms_List = None
if filter == 'pending':
exclude_states = [RegistrationForm.RegistrationFormStatus.RF_VALIDATED, RegistrationForm.RegistrationFormStatus.RF_ARCHIVED]
registerForms_List = bdd.searchObjects(RegistrationForm, search, _excludeStates=exclude_states)
elif filter == 'archived':
registerForms_List = bdd.getObjects(RegistrationForm, 'status', RegistrationForm.RegistrationFormStatus.RF_ARCHIVED)
elif filter == 'subscribed':
registerForms_List = bdd.getObjects(RegistrationForm, 'status', RegistrationForm.RegistrationFormStatus.RF_VALIDATED)
else:
registerForms_List = None
if not registerForms_List:
return JsonResponse({'error': 'aucune donnée trouvée', 'count': 0}, safe=False)
# Pagination
paginator = self.pagination_class()
page = paginator.paginate_queryset(registerForms_List, request)
if page is not None:
registerForms_serializer = RegistrationFormSerializer(page, many=True)
response_data = paginator.get_paginated_response(registerForms_serializer.data)
cache.set(cache_key, response_data, timeout=60 * 15)
return JsonResponse(response_data, safe=False)
return JsonResponse({'error': 'aucune donnée trouvée', 'count': 0}, safe=False)
@swagger_auto_schema(
request_body=RegistrationFormSerializer,
responses={200: RegistrationFormSerializer()},
operation_description="Crée un dossier d'inscription.",
operation_summary="Créer un dossier d'inscription",
examples={
"application/json": {
"student": {
"id": 1,
"first_name": "John",
"last_name": "Doe",
"date_of_birth": "2010-01-01"
},
"status": "pending",
"last_update": "10-02-2025 10:00",
"codeLienInscription": "ABC123XYZ456"
}
}
)
@method_decorator(csrf_protect, name='dispatch')
@method_decorator(ensure_csrf_cookie, name='dispatch')
def post(self, request):
"""
Crée un dossier d'inscription.
"""
regiterFormData = request.data.copy()
logger.info(f"Création d'un dossier d'inscription {request}")
# Ajout de la date de mise à jour
regiterFormData["last_update"] = util.convertToStr(util._now(), '%d-%m-%Y %H:%M')
# Ajout du code d'inscription
code = util.genereRandomCode(12)
regiterFormData["codeLienInscription"] = code
guardiansId = regiterFormData.pop('idGuardians', [])
registerForm_serializer = RegistrationFormSerializer(data=regiterFormData)
fileGroupId = regiterFormData.pop('fileGroup', None)
if registerForm_serializer.is_valid():
di = registerForm_serializer.save()
# Mise à jour de l'automate
updateStateMachine(di, 'creationDI')
# Récupération du reponsable associé
for guardianId in guardiansId:
guardian = Guardian.objects.get(id=guardianId)
di.student.guardians.add(guardian)
di.save()
if fileGroupId:
di.fileGroup = RegistrationFileGroup.objects.get(id=fileGroupId)
di.save()
return JsonResponse(registerForm_serializer.data, safe=False)
else:
logger.error(f"Erreur lors de la validation des données {regiterFormData}")
return JsonResponse(registerForm_serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST)
# /Subscriptions/registerForms/{id}
class RegisterFormWithIdView(APIView):
"""
Gère la lecture, création, modification et suppression dun dossier dinscription.
"""
pagination_class = CustomPagination
@swagger_auto_schema(
responses={200: RegistrationFormSerializer()},
operation_description="Récupère un dossier d'inscription donné.",
operation_summary="Récupérer un dossier d'inscription",
examples={
"application/json": {
"id": 1,
"student": {
"id": 1,
"first_name": "John",
"last_name": "Doe",
"date_of_birth": "2010-01-01"
},
}
}
)
def get(self, request, id):
"""
Récupère un dossier d'inscription donné.
"""
registerForm = bdd.getObject(RegistrationForm, "student__id", id)
if registerForm is None:
return JsonResponse({"errorMessage":'Le dossier d\'inscription n\'a pas été trouvé'}, safe=False, status=status.HTTP_404_NOT_FOUND)
registerForm_serializer = RegistrationFormSerializer(registerForm)
return JsonResponse(registerForm_serializer.data, safe=False)
@swagger_auto_schema(
request_body=RegistrationFormSerializer,
responses={200: RegistrationFormSerializer()},
operation_description="Modifie un dossier d'inscription donné.",
operation_summary="Modifier un dossier d'inscription",
examples={
"application/json": {
"id": 1,
"student": {
"id": 1,
"first_name": "John",
"last_name": "Doe",
"date_of_birth": "2010-01-01"
},
"status": "under_review",
"last_update": "10-02-2025 10:00"
}
}
)
@method_decorator(csrf_protect, name='dispatch')
@method_decorator(ensure_csrf_cookie, name='dispatch')
def put(self, request, id):
"""
Modifie un dossier d'inscription donné.
"""
studentForm_data = JSONParser().parse(request)
_status = studentForm_data.pop('status', 0)
studentForm_data["last_update"] = str(util.convertToStr(util._now(), '%d-%m-%Y %H:%M'))
registerForm = bdd.getObject(_objectName=RegistrationForm, _columnName='student__id', _value=id)
if _status == RegistrationForm.RegistrationFormStatus.RF_UNDER_REVIEW:
try:
# Génération de la fiche d'inscription au format PDF
base_dir = f"data/registration_files/dossier_rf_{registerForm.pk}"
os.makedirs(base_dir, exist_ok=True)
# Fichier PDF initial
initial_pdf = f"{base_dir}/rf_{registerForm.student.last_name}_{registerForm.student.first_name}.pdf"
registerForm.registration_file = util.rfToPDF(registerForm, initial_pdf)
registerForm.save()
# Récupération des fichiers d'inscription
fileNames = RegistrationFile.get_files_from_rf(registerForm.pk)
if registerForm.registration_file:
fileNames.insert(0, registerForm.registration_file.path)
# Création du fichier PDF Fusionné
merged_pdf = f"{base_dir}/dossier_complet_{registerForm.pk}.pdf"
util.merge_files_pdf(fileNames, merged_pdf)
# Mise à jour du champ registration_file avec le fichier fusionné
with open(merged_pdf, 'rb') as f:
registerForm.registration_file.save(
os.path.basename(merged_pdf),
File(f),
save=True
)
# Mise à jour de l'automate
updateStateMachine(registerForm, 'saisiDI')
except Exception as e:
return JsonResponse({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
elif _status == RegistrationForm.RegistrationFormStatus.RF_VALIDATED:
# L'école a validé le dossier d'inscription
# Mise à jour de l'automate
updateStateMachine(registerForm, 'valideDI')
studentForm_serializer = RegistrationFormSerializer(registerForm, data=studentForm_data)
if studentForm_serializer.is_valid():
studentForm_serializer.save()
return JsonResponse(studentForm_serializer.data, safe=False)
return JsonResponse(studentForm_serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST)
@swagger_auto_schema(
responses={204: 'No Content'},
operation_description="Supprime un dossier d'inscription donné.",
operation_summary="Supprimer un dossier d'inscription"
)
@method_decorator(csrf_protect, name='dispatch')
@method_decorator(ensure_csrf_cookie, name='dispatch')
def delete(self, request, id):
"""
Supprime un dossier d'inscription donné.
"""
register_form = bdd.getObject(_objectName=RegistrationForm, _columnName='student__id', _value=id)
if register_form != None:
student = register_form.student
student.guardians.clear()
student.profiles.clear()
student.registration_files.clear()
student.delete()
clear_cache()
return JsonResponse("La suppression du dossier a été effectuée avec succès", safe=False)
return JsonResponse({"errorMessage":'Aucun dossier d\'inscription rattaché à l\'élève'}, safe=False, status=status.HTTP_404_NOT_FOUND)
@swagger_auto_schema(
method='get',
responses={200: openapi.Response('Success', schema=openapi.Schema(
type=openapi.TYPE_OBJECT,
properties={
'message': openapi.Schema(type=openapi.TYPE_STRING)
}
))},
operation_description="Envoie le dossier d'inscription par e-mail",
operation_summary="Envoyer un dossier d'inscription"
)
@api_view(['GET'])
def send(request,id):
"""Envoie le dossier d'inscription par e-mail."""
register_form = bdd.getObject(_objectName=RegistrationForm, _columnName='student__id', _value=id)
if register_form != None:
student = register_form.student
guardian = student.getMainGuardian()
email = guardian.email
errorMessage = mailer.sendRegisterForm(email)
if errorMessage == '':
register_form.last_update=util.convertToStr(util._now(), '%d-%m-%Y %H:%M')
updateStateMachine(register_form, 'envoiDI')
return JsonResponse({"message": f"Le dossier d'inscription a bien été envoyé à l'addresse {email}"}, safe=False)
return JsonResponse({"errorMessage":errorMessage}, safe=False, status=status.HTTP_400_BAD_REQUEST)
return JsonResponse({"errorMessage":'Dossier d\'inscription non trouvé'}, safe=False, status=status.HTTP_404_NOT_FOUND)
@swagger_auto_schema(
method='get',
responses={200: openapi.Response('Success', schema=openapi.Schema(
type=openapi.TYPE_OBJECT,
properties={
'message': openapi.Schema(type=openapi.TYPE_STRING)
}
))},
operation_description="Archive le dossier d'inscription",
operation_summary="Archiver un dossier d'inscription"
)
@api_view(['GET'])
def archive(request,id):
"""Archive le dossier d'inscription."""
register_form = bdd.getObject(_objectName=RegistrationForm, _columnName='student__id', _value=id)
if register_form != None:
register_form.last_update=util.convertToStr(util._now(), '%d-%m-%Y %H:%M')
updateStateMachine(register_form, 'archiveDI')
return JsonResponse({"message": "Le dossier a été archivé avec succès"}, safe=False)
return JsonResponse({"errorMessage":'Dossier d\'inscription non trouvé'}, safe=False, status=status.HTTP_404_NOT_FOUND)
@swagger_auto_schema(
method='get',
responses={200: openapi.Response('Success', schema=openapi.Schema(
type=openapi.TYPE_OBJECT,
properties={
'message': openapi.Schema(type=openapi.TYPE_STRING)
}
))},
operation_description="Relance un dossier d'inscription par e-mail",
operation_summary="Relancer un dossier d'inscription"
)
@api_view(['GET'])
def resend(request,id):
"""Relance un dossier d'inscription par e-mail."""
register_form = bdd.getObject(_objectName=RegistrationForm, _columnName='student__id', _value=id)
if register_form != None:
student = register_form.student
guardian = student.getMainGuardian()
email = guardian.email
errorMessage = mailer.envoieRelanceDossierInscription(email, register_form.codeLienInscription)
if errorMessage == '':
register_form.status=RegistrationForm.RegistrationFormStatus.RF_SENT
register_form.last_update=util.convertToStr(util._now(), '%d-%m-%Y %H:%M')
register_form.save()
return JsonResponse({"message": f"Le dossier a été renvoyé à l'adresse {email}"}, safe=False)
return JsonResponse({"errorMessage":errorMessage}, safe=False, status=status.HTTP_400_BAD_REQUEST)
return JsonResponse({"errorMessage":'Dossier d\'inscription non trouvé'}, safe=False, status=status.HTTP_404_NOT_FOUND)

View File

@ -0,0 +1,125 @@
from django.http.response import JsonResponse
from drf_yasg.utils import swagger_auto_schema
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework import status
from rest_framework.decorators import action, api_view
from drf_yasg.utils import swagger_auto_schema
from drf_yasg import openapi
from Subscriptions.serializers import RegistrationFileGroupSerializer
from Subscriptions.models import RegistrationFileGroup, RegistrationFileTemplate
from N3wtSchool import bdd
class RegistrationFileGroupView(APIView):
@swagger_auto_schema(
operation_description="Récupère tous les groupes de fichiers d'inscription",
responses={200: RegistrationFileGroupSerializer(many=True)}
)
def get(self, request):
"""
Récupère tous les groupes de fichiers d'inscription.
"""
groups = RegistrationFileGroup.objects.all()
serializer = RegistrationFileGroupSerializer(groups, many=True)
return Response(serializer.data)
@swagger_auto_schema(
operation_description="Crée un nouveau groupe de fichiers d'inscription",
request_body=RegistrationFileGroupSerializer,
responses={
201: RegistrationFileGroupSerializer,
400: "Données invalides"
}
)
def post(self, request):
"""
Crée un nouveau groupe de fichiers d'inscription.
"""
serializer = RegistrationFileGroupSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class RegistrationFileGroupSimpleView(APIView):
@swagger_auto_schema(
operation_description="Récupère un groupe de fichiers d'inscription spécifique",
responses={
200: RegistrationFileGroupSerializer,
404: "Groupe non trouvé"
}
)
def get(self, request, id):
"""
Récupère un groupe de fichiers d'inscription spécifique.
"""
group = bdd.getObject(_objectName=RegistrationFileGroup, _columnName='id', _value=id)
if group is None:
return JsonResponse({"errorMessage": "Le groupe de fichiers n'a pas été trouvé"},
status=status.HTTP_404_NOT_FOUND)
serializer = RegistrationFileGroupSerializer(group)
return JsonResponse(serializer.data)
@swagger_auto_schema(
operation_description="Met à jour un groupe de fichiers d'inscription",
request_body=RegistrationFileGroupSerializer,
responses={
200: RegistrationFileGroupSerializer,
400: "Données invalides",
404: "Groupe non trouvé"
}
)
def put(self, request, id):
"""
Met à jour un groupe de fichiers d'inscription existant.
"""
group = bdd.getObject(_objectName=RegistrationFileGroup, _columnName='id', _value=id)
if group is None:
return JsonResponse({'erreur': "Le groupe de fichiers n'a pas été trouvé"},
status=status.HTTP_404_NOT_FOUND)
serializer = RegistrationFileGroupSerializer(group, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
@swagger_auto_schema(
operation_description="Supprime un groupe de fichiers d'inscription",
responses={
204: "Suppression réussie",
404: "Groupe non trouvé"
}
)
def delete(self, request, id):
"""
Supprime un groupe de fichiers d'inscription.
"""
group = bdd.getObject(_objectName=RegistrationFileGroup, _columnName='id', _value=id)
if group is not None:
group.delete()
return JsonResponse({'message': 'La suppression du groupe a été effectuée avec succès'},
status=status.HTTP_204_NO_CONTENT)
return JsonResponse({'erreur': "Le groupe de fichiers n'a pas été trouvé"},
status=status.HTTP_404_NOT_FOUND)
@swagger_auto_schema(
method='get',
responses={200: openapi.Response('Success', schema=openapi.Schema(
type=openapi.TYPE_OBJECT,
properties={
'message': openapi.Schema(type=openapi.TYPE_STRING)
}
))},
operation_description="Récupère les fichiers d'inscription d'un groupe donné",
operation_summary="Récupèrer les fichiers d'inscription d'un groupe donné"
)
@api_view(['GET'])
def get_registration_files_by_group(request, id):
try:
group = RegistrationFileGroup.objects.get(id=id)
templates = RegistrationFileTemplate.objects.filter(group=group)
templates_data = list(templates.values())
return JsonResponse(templates_data, safe=False)
except RegistrationFileGroup.DoesNotExist:
return JsonResponse({'error': 'Le groupe de fichiers n\'a pas été trouvé'}, status=404)

View File

@ -0,0 +1,211 @@
from django.http.response import JsonResponse
from django.core.files import File
from drf_yasg.utils import swagger_auto_schema
from drf_yasg import openapi
from rest_framework.parsers import MultiPartParser, FormParser
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework import status
import os
from Subscriptions.serializers import RegistrationFileTemplateSerializer, RegistrationFileSerializer
from Subscriptions.models import RegistrationFileTemplate, RegistrationFile
from N3wtSchool import bdd
class RegistrationFileTemplateView(APIView):
@swagger_auto_schema(
operation_description="Récupère tous les fichiers templates pour les dossiers d'inscription",
responses={200: RegistrationFileTemplateSerializer(many=True)}
)
def get(self, request):
"""
Récupère les fichiers templates pour les dossiers dinscription.
"""
files = RegistrationFileTemplate.objects.all()
serializer = RegistrationFileTemplateSerializer(files, many=True)
return Response(serializer.data)
@swagger_auto_schema(
operation_description="Crée un nouveau fichier template pour les dossiers d'inscription",
request_body=RegistrationFileTemplateSerializer,
responses={
201: RegistrationFileTemplateSerializer,
400: "Données invalides"
}
)
def post(self, request):
"""
Crée un fichier template pour les dossiers dinscription.
"""
serializer = RegistrationFileTemplateSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class RegistrationFileTemplateSimpleView(APIView):
"""
Gère les fichiers templates pour les dossiers dinscription.
"""
parser_classes = (MultiPartParser, FormParser)
@swagger_auto_schema(
operation_description="Récupère un fichier template spécifique",
responses={
200: RegistrationFileTemplateSerializer,
404: "Fichier template non trouvé"
}
)
def get(self, request, id):
"""
Récupère les fichiers templates pour les dossiers dinscription.
"""
registationFileTemplate = bdd.getObject(_objectName=RegistrationFileTemplate, _columnName='id', _value=id)
if registationFileTemplate is None:
return JsonResponse({"errorMessage":'Le fichier d\'inscription n\'a pas été trouvé'}, safe=False, status=status.HTTP_404_NOT_FOUND)
serializer = RegistrationFileTemplateSerializer(registationFileTemplate)
return JsonResponse(serializer.data, safe=False)
@swagger_auto_schema(
operation_description="Met à jour un fichier template existant",
request_body=RegistrationFileTemplateSerializer,
responses={
201: RegistrationFileTemplateSerializer,
400: "Données invalides",
404: "Fichier template non trouvé"
}
)
def put(self, request, id):
"""
Met à jour un fichier template existant.
"""
registationFileTemplate = bdd.getObject(_objectName=RegistrationFileTemplate, _columnName='id', _value=id)
if registationFileTemplate is None:
return JsonResponse({'erreur': 'Le fichier d\'inscription n\'a pas été trouvé'}, safe=False, status=status.HTTP_404_NOT_FOUND)
serializer = RegistrationFileTemplateSerializer(registationFileTemplate,data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
@swagger_auto_schema(
operation_description="Supprime un fichier template",
responses={
204: "Suppression réussie",
404: "Fichier template non trouvé"
}
)
def delete(self, request, id):
"""
Supprime un fichier template existant.
"""
registrationFileTemplate = bdd.getObject(_objectName=RegistrationFileTemplate, _columnName='id', _value=id)
if registrationFileTemplate is not None:
registrationFileTemplate.file.delete() # Supprimer le fichier uploadé
registrationFileTemplate.delete()
return JsonResponse({'message': 'La suppression du fichier d\'inscription a été effectuée avec succès'}, safe=False, status=status.HTTP_204_NO_CONTENT)
else:
return JsonResponse({'erreur': 'Le fichier d\'inscription n\'a pas été trouvé'}, safe=False, status=status.HTTP_404_NOT_FOUND)
class RegistrationFileView(APIView):
@swagger_auto_schema(
operation_description="Récupère tous les fichiers d'inscription",
responses={200: RegistrationFileSerializer(many=True)}
)
def get(self, request):
"""
Récupère les fichiers liés à un dossier dinscription donné.
"""
files = RegistrationFile.objects.all()
serializer = RegistrationFileSerializer(files, many=True)
return Response(serializer.data)
@swagger_auto_schema(
operation_description="Crée un nouveau fichier d'inscription",
request_body=RegistrationFileSerializer,
responses={
201: RegistrationFileSerializer,
400: "Données invalides"
}
)
def post(self, request):
"""
Crée un RegistrationFile pour le RegistrationForm associé.
"""
serializer = RegistrationFileSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class RegistrationFileSimpleView(APIView):
"""
Gère la création, mise à jour et suppression de fichiers liés à un dossier dinscription.
"""
parser_classes = (MultiPartParser, FormParser)
@swagger_auto_schema(
operation_description="Récupère un fichier d'inscription spécifique",
responses={
200: RegistrationFileSerializer,
404: "Fichier non trouvé"
}
)
def get(self, request, id):
"""
Récupère les fichiers liés à un dossier dinscription donné.
"""
registationFile = bdd.getObject(_objectName=RegistrationFile, _columnName='id', _value=id)
if registationFile is None:
return JsonResponse({"errorMessage":'Le fichier d\'inscription n\'a pas été trouvé'}, safe=False, status=status.HTTP_404_NOT_FOUND)
serializer = RegistrationFileSerializer(registationFile)
return JsonResponse(serializer.data, safe=False)
@swagger_auto_schema(
operation_description="Met à jour un fichier d'inscription existant",
request_body=RegistrationFileSerializer,
responses={
200: openapi.Response(
description="Fichier mis à jour avec succès",
schema=RegistrationFileSerializer
),
400: "Données invalides",
404: "Fichier non trouvé"
}
)
def put(self, request, id):
"""
Met à jour un RegistrationFile existant.
"""
registrationFile = bdd.getObject(_objectName=RegistrationFile, _columnName='id', _value=id)
if registrationFile is None:
return JsonResponse({'erreur': 'Le fichier d\'inscription n\'a pas été trouvé'}, safe=False, status=status.HTTP_404_NOT_FOUND)
serializer = RegistrationFileSerializer(registrationFile, data=request.data)
if serializer.is_valid():
serializer.save()
return Response({'message': 'Fichier mis à jour avec succès', 'data': serializer.data}, status=status.HTTP_200_OK)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
@swagger_auto_schema(
operation_description="Supprime un fichier d'inscription",
responses={
200: "Suppression réussie",
404: "Fichier non trouvé"
}
)
def delete(self, request, id):
"""
Supprime un RegistrationFile existant.
"""
registrationFile = bdd.getObject(_objectName=RegistrationFile, _columnName='id', _value=id)
if registrationFile is not None:
registrationFile.file.delete() # Supprimer le fichier uploadé
registrationFile.delete()
return JsonResponse({'message': 'La suppression du fichier a été effectuée avec succès'}, safe=False)
else:
return JsonResponse({'erreur': 'Le fichier n\'a pas été trouvé'}, safe=False, status=status.HTTP_404_NOT_FOUND)

View File

@ -0,0 +1,83 @@
from django.http.response import JsonResponse
from rest_framework.views import APIView
from rest_framework import status
from drf_yasg.utils import swagger_auto_schema
from drf_yasg import openapi
from Subscriptions.serializers import StudentByRFCreationSerializer, RegistrationFormByParentSerializer, StudentSerializer
from Subscriptions.models import Student, RegistrationForm
from N3wtSchool import bdd
class StudentView(APIView):
"""
Gère la lecture dun élève donné.
"""
@swagger_auto_schema(
operation_summary="Récupérer les informations d'un élève",
operation_description="Retourne les détails d'un élève spécifique à partir de son ID",
responses={
200: openapi.Response('Détails de l\'élève', StudentSerializer),
404: openapi.Response('Élève non trouvé')
},
manual_parameters=[
openapi.Parameter(
'id', openapi.IN_PATH,
description="ID de l'élève",
type=openapi.TYPE_INTEGER,
required=True
)
]
)
def get(self, request, id):
student = bdd.getObject(_objectName=Student, _columnName='id', _value=id)
if student is None:
return JsonResponse({"errorMessage":'Aucun élève trouvé'}, safe=False, status=status.HTTP_404_NOT_FOUND)
student_serializer = StudentSerializer(student)
return JsonResponse(student_serializer.data, safe=False)
# API utilisée pour la vue de création d'un DI
class StudentListView(APIView):
"""
Pour la vue de création dun dossier dinscription : liste les élèves disponibles.
"""
@swagger_auto_schema(
operation_summary="Lister tous les élèves",
operation_description="Retourne la liste de tous les élèves inscrits ou en cours d'inscription",
responses={
200: openapi.Response('Liste des élèves', StudentByRFCreationSerializer(many=True))
}
)
# Récupération de la liste des élèves inscrits ou en cours d'inscriptions
def get(self, request):
students = bdd.getAllObjects(_objectName=Student)
students_serializer = StudentByRFCreationSerializer(students, many=True)
return JsonResponse(students_serializer.data, safe=False)
# API utilisée pour la vue parent
class ChildrenListView(APIView):
"""
Pour la vue parent : liste les élèves rattachés à un profil donné.
"""
@swagger_auto_schema(
operation_summary="Lister les élèves d'un parent",
operation_description="Retourne la liste des élèves associés à un profil parent spécifique",
responses={
200: openapi.Response('Liste des élèves du parent', RegistrationFormByParentSerializer(many=True))
},
manual_parameters=[
openapi.Parameter(
'id', openapi.IN_PATH,
description="ID du profil parent",
type=openapi.TYPE_INTEGER,
required=True
)
]
)
# Récupération des élèves d'un parent
# idProfile : identifiant du profil connecté rattaché aux fiches d'élèves
def get(self, request, id):
students = bdd.getObjects(_objectName=RegistrationForm, _columnName='student__guardians__associated_profile__id', _value=id)
students_serializer = RegistrationFormByParentSerializer(students, many=True)
return JsonResponse(students_serializer.data, safe=False)

0
Back-End/src/app.js Normal file
View File

View File