mirror of
https://git.v0id.ovh/n3wt-innov/n3wt-school.git
synced 2026-01-28 23:43:22 +00:00
221 lines
9.9 KiB
Python
221 lines
9.9 KiB
Python
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 django.views.decorators.csrf import ensure_csrf_cookie, csrf_protect
|
||
from django.utils.decorators import method_decorator
|
||
from Subscriptions.models import StudentCompetency, Student
|
||
from Common.models import Domain
|
||
from django.conf import settings
|
||
from datetime import date
|
||
from N3wtSchool.renderers import render_to_pdf
|
||
from django.core.files import File
|
||
from io import BytesIO
|
||
import os
|
||
import logging
|
||
|
||
logger = logging.getLogger(__name__)
|
||
|
||
@method_decorator(csrf_protect, name='dispatch')
|
||
@method_decorator(ensure_csrf_cookie, name='dispatch')
|
||
class StudentCompetencyListCreateView(APIView):
|
||
def get(self, request):
|
||
student_id = request.GET.get('student_id')
|
||
if not student_id:
|
||
return JsonResponse({'error': 'student_id requis'}, status=400)
|
||
try:
|
||
student = Student.objects.get(id=student_id)
|
||
except Student.DoesNotExist:
|
||
return JsonResponse({'error': 'Élève introuvable'}, status=404)
|
||
|
||
student_competencies = StudentCompetency.objects.filter(student=student).select_related(
|
||
'establishment_competency',
|
||
'establishment_competency__competency',
|
||
'establishment_competency__competency__category',
|
||
'establishment_competency__competency__category__domain',
|
||
'establishment_competency__custom_category',
|
||
'establishment_competency__custom_category__domain',
|
||
)
|
||
|
||
result = []
|
||
total_competencies = 0
|
||
domaines = Domain.objects.all()
|
||
for domaine in domaines:
|
||
domaine_dict = {
|
||
"domaine_id": domaine.id,
|
||
"domaine_nom": domaine.name,
|
||
"categories": []
|
||
}
|
||
categories = domaine.categories.all()
|
||
for categorie in categories:
|
||
categorie_dict = {
|
||
"categorie_id": categorie.id,
|
||
"categorie_nom": categorie.name,
|
||
"competences": []
|
||
}
|
||
# On ne boucle que sur les compétences du student pour cette catégorie
|
||
for sc in student_competencies:
|
||
ec = sc.establishment_competency
|
||
# Cas compétence de référence
|
||
if ec.competency and ec.competency.category_id == categorie.id:
|
||
comp = ec.competency
|
||
categorie_dict["competences"].append({
|
||
"competence_id": ec.id, # <-- retourne l'id de l'EstablishmentCompetency
|
||
"nom": comp.name,
|
||
"score": sc.score,
|
||
"comment": sc.comment or "",
|
||
})
|
||
total_competencies += 1
|
||
# Cas compétence custom
|
||
elif ec.competency is None and ec.custom_category_id == categorie.id:
|
||
categorie_dict["competences"].append({
|
||
"competence_id": ec.id, # <-- retourne l'id de l'EstablishmentCompetency
|
||
"nom": ec.custom_name,
|
||
"score": sc.score,
|
||
"comment": sc.comment or "",
|
||
})
|
||
total_competencies += 1
|
||
if categorie_dict["competences"]:
|
||
domaine_dict["categories"].append(categorie_dict)
|
||
if domaine_dict["categories"]:
|
||
result.append(domaine_dict)
|
||
|
||
return JsonResponse({
|
||
"count": total_competencies,
|
||
"data": result
|
||
}, safe=False, status=200)
|
||
|
||
def put(self, request):
|
||
"""
|
||
Met à jour en masse les notes des compétences d'un élève.
|
||
Attend une liste d'objets {"competenceId": ..., "grade": ...}
|
||
"""
|
||
data = request.data
|
||
if not isinstance(data, list):
|
||
return JsonResponse({"error": "Une liste est attendue."}, status=400)
|
||
updated = []
|
||
errors = []
|
||
for item in data:
|
||
comp_id = item.get("competenceId")
|
||
grade = item.get("grade")
|
||
student_id = item.get('studentId')
|
||
if comp_id is None or grade is None:
|
||
errors.append({"competenceId": comp_id, "error": "champ manquant"})
|
||
continue
|
||
try:
|
||
# Ajoute le filtre student_id
|
||
sc = StudentCompetency.objects.get(
|
||
establishment_competency_id=comp_id,
|
||
student_id=student_id
|
||
)
|
||
sc.score = grade
|
||
sc.save()
|
||
updated.append(comp_id)
|
||
except StudentCompetency.DoesNotExist:
|
||
errors.append({"competenceId": comp_id, "error": "not found"})
|
||
|
||
# Génération du PDF si au moins une compétence a été mise à jour
|
||
if updated:
|
||
student = Student.objects.get(id=student_id)
|
||
# Reconstituer la structure "domaines" comme dans le GET
|
||
student_competencies = StudentCompetency.objects.filter(student=student).select_related(
|
||
'establishment_competency',
|
||
'establishment_competency__competency',
|
||
'establishment_competency__competency__category',
|
||
'establishment_competency__competency__category__domain',
|
||
'establishment_competency__custom_category',
|
||
'establishment_competency__custom_category__domain',
|
||
)
|
||
result = []
|
||
domaines = Domain.objects.all()
|
||
for domaine in domaines:
|
||
domaine_dict = {
|
||
"nom": domaine.name,
|
||
"categories": []
|
||
}
|
||
categories = domaine.categories.all()
|
||
for categorie in categories:
|
||
categorie_dict = {
|
||
"nom": categorie.name,
|
||
"competences": []
|
||
}
|
||
for sc in student_competencies:
|
||
ec = sc.establishment_competency
|
||
if ec.competency and ec.competency.category_id == categorie.id:
|
||
comp = ec.competency
|
||
categorie_dict["competences"].append({
|
||
"nom": comp.name,
|
||
"score": sc.score,
|
||
"comment": sc.comment or "",
|
||
})
|
||
elif ec.competency is None and ec.custom_category_id == categorie.id:
|
||
categorie_dict["competences"].append({
|
||
"nom": ec.custom_name,
|
||
"score": sc.score,
|
||
"comment": sc.comment or "",
|
||
})
|
||
if categorie_dict["competences"]:
|
||
domaine_dict["categories"].append(categorie_dict)
|
||
if domaine_dict["categories"]:
|
||
result.append(domaine_dict)
|
||
|
||
context = {
|
||
"student": {
|
||
"first_name": student.first_name,
|
||
"last_name": student.last_name,
|
||
"level": student.level,
|
||
"class_name": student.associated_class.atmosphere_name,
|
||
},
|
||
"date": date.today().strftime("%d/%m/%Y"),
|
||
"domaines": result,
|
||
}
|
||
print('génération du PDF...')
|
||
pdf_result = render_to_pdf('pdfs/bilan_competences.html', context)
|
||
|
||
# Vérifier si un fichier bilan_form existe déjà et le supprimer
|
||
if student.bilan_form and student.bilan_form.name:
|
||
if os.path.isabs(student.bilan_form.path):
|
||
existing_file_path = student.bilan_form.path
|
||
else:
|
||
existing_file_path = os.path.join(settings.MEDIA_ROOT, student.bilan_form.name.lstrip('/'))
|
||
|
||
if os.path.exists(existing_file_path):
|
||
os.remove(existing_file_path)
|
||
student.bilan_form.delete(save=False)
|
||
logger.info(f"Ancien PDF supprimé : {existing_file_path}")
|
||
else:
|
||
logger.info(f"File does not exist: {existing_file_path}")
|
||
|
||
try:
|
||
filename = f"bilan_competences_{student.last_name}_{student.first_name}.pdf"
|
||
student.bilan_form.save(
|
||
os.path.basename(filename), # Utiliser uniquement le nom de fichier
|
||
File(BytesIO(pdf_result.content)),
|
||
save=True
|
||
)
|
||
except Exception as e:
|
||
logger.error(f"Erreur lors de la sauvegarde du fichier PDF : {e}")
|
||
raise
|
||
# Exemple : retour du PDF dans la réponse HTTP (pour test)
|
||
|
||
return JsonResponse({"updated": updated, "errors": errors}, status=200)
|
||
|
||
@method_decorator(csrf_protect, name='dispatch')
|
||
@method_decorator(ensure_csrf_cookie, name='dispatch')
|
||
class StudentCompetencySimpleView(APIView):
|
||
def get(self, request, id):
|
||
return JsonResponse("ok", safe=False, status=status.HTTP_200_OK)
|
||
|
||
# def put(self, request, id):
|
||
# try:
|
||
# absence = AbsenceManagement.objects.get(id=id)
|
||
# serializer = AbsenceManagementSerializer(absence, data=request.data)
|
||
# if serializer.is_valid():
|
||
# serializer.save()
|
||
# return JsonResponse(serializer.data, safe=False, status=status.HTTP_200_OK)
|
||
# return JsonResponse(serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST)
|
||
# except AbsenceManagement.DoesNotExist:
|
||
# return JsonResponse({"error": "Absence not found"}, safe=False, status=status.HTTP_404_NOT_FOUND)
|
||
|
||
# def delete(self, request, id):
|
||
# return delete_object(AbsenceManagement, id) |