feat(class): improve class/id/student
This commit is contained in:
@@ -41,7 +41,7 @@ from schemas.class_group import (
|
||||
)
|
||||
from domain.services.grading_calculator import GradingCalculator
|
||||
from domain.services.class_statistics_service import ClassStatisticsService
|
||||
from schemas.student import StudentWithClass, StudentList
|
||||
from schemas.student import StudentWithClass, StudentList, StudentWithEnrollmentInfo, StudentEnrollmentList
|
||||
from schemas.csv_import import (
|
||||
CSVImportResponse,
|
||||
ImportedStudentInfo,
|
||||
@@ -145,7 +145,7 @@ async def get_class(
|
||||
)
|
||||
|
||||
|
||||
@router.get("/{class_id}/students", response_model=StudentList)
|
||||
@router.get("/{class_id}/students", response_model=StudentEnrollmentList)
|
||||
async def get_class_students(
|
||||
class_id: int,
|
||||
session: AsyncSessionDep,
|
||||
@@ -153,7 +153,7 @@ async def get_class_students(
|
||||
at_date: Optional[str] = Query(None, description="Filtrer les élèves inscrits à cette date (YYYY-MM-DD)"),
|
||||
):
|
||||
"""
|
||||
Récupère la liste des étudiants d'une classe.
|
||||
Récupère la liste des étudiants d'une classe avec leurs informations d'inscription.
|
||||
|
||||
Si at_date est fourni, retourne uniquement les élèves qui étaient inscrits à cette date.
|
||||
"""
|
||||
@@ -194,22 +194,29 @@ async def get_class_students(
|
||||
students = []
|
||||
for enrollment in enrollments:
|
||||
student = enrollment.student
|
||||
is_active = enrollment.departure_date is None
|
||||
students.append(
|
||||
StudentWithClass(
|
||||
StudentWithEnrollmentInfo(
|
||||
id=student.id,
|
||||
last_name=student.last_name,
|
||||
first_name=student.first_name,
|
||||
email=student.email,
|
||||
full_name=f"{student.first_name} {student.last_name}",
|
||||
current_class_id=class_id if enrollment.departure_date is None else None,
|
||||
current_class_name=cls.name if enrollment.departure_date is None else None
|
||||
current_class_id=class_id if is_active else None,
|
||||
current_class_name=cls.name if is_active else None,
|
||||
enrollment_id=enrollment.id,
|
||||
enrollment_date=enrollment.enrollment_date,
|
||||
departure_date=enrollment.departure_date,
|
||||
enrollment_reason=enrollment.enrollment_reason,
|
||||
departure_reason=enrollment.departure_reason,
|
||||
is_active=is_active
|
||||
)
|
||||
)
|
||||
|
||||
# Trier par nom de famille puis prénom
|
||||
students.sort(key=lambda s: (s.last_name.lower(), s.first_name.lower()))
|
||||
|
||||
return StudentList(
|
||||
return StudentEnrollmentList(
|
||||
students=students,
|
||||
total=len(students)
|
||||
)
|
||||
|
||||
@@ -281,6 +281,67 @@ async def update_student(
|
||||
)
|
||||
|
||||
|
||||
@router.patch("/{student_id}/email", response_model=StudentWithClass)
|
||||
async def update_student_email(
|
||||
student_id: int,
|
||||
email: str,
|
||||
session: AsyncSessionDep,
|
||||
):
|
||||
"""
|
||||
Modifie rapidement l'email d'un étudiant.
|
||||
Endpoint optimisé pour l'édition inline.
|
||||
"""
|
||||
# Récupérer l'étudiant
|
||||
query = (
|
||||
select(Student)
|
||||
.options(
|
||||
selectinload(Student.enrollments).selectinload(StudentEnrollment.class_group)
|
||||
)
|
||||
.where(Student.id == student_id)
|
||||
)
|
||||
result = await session.execute(query)
|
||||
student = result.scalar_one_or_none()
|
||||
|
||||
if not student:
|
||||
raise HTTPException(status_code=404, detail="Étudiant non trouvé")
|
||||
|
||||
# Vérifier l'unicité du nouvel email si fourni
|
||||
if email and email != student.email:
|
||||
existing_query = select(Student).where(
|
||||
Student.email == email,
|
||||
Student.id != student_id
|
||||
)
|
||||
existing_result = await session.execute(existing_query)
|
||||
if existing_result.scalar_one_or_none():
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail=f"Un autre élève avec l'email '{email}' existe déjà"
|
||||
)
|
||||
|
||||
# Mettre à jour l'email (permet de le vider avec chaîne vide)
|
||||
student.email = email if email else None
|
||||
|
||||
await session.commit()
|
||||
await session.refresh(student)
|
||||
|
||||
# Trouver la classe actuelle
|
||||
current_enrollment = None
|
||||
for enrollment in student.enrollments:
|
||||
if enrollment.departure_date is None:
|
||||
current_enrollment = enrollment
|
||||
break
|
||||
|
||||
return StudentWithClass(
|
||||
id=student.id,
|
||||
last_name=student.last_name,
|
||||
first_name=student.first_name,
|
||||
email=student.email,
|
||||
full_name=f"{student.first_name} {student.last_name}",
|
||||
current_class_id=current_enrollment.class_group_id if current_enrollment else None,
|
||||
current_class_name=current_enrollment.class_group.name if current_enrollment else None
|
||||
)
|
||||
|
||||
|
||||
@router.delete("/{student_id}", status_code=204)
|
||||
async def delete_student(
|
||||
student_id: int,
|
||||
|
||||
@@ -36,6 +36,19 @@ class StudentWithClass(StudentRead):
|
||||
current_class_name: Optional[str] = None
|
||||
|
||||
|
||||
class StudentWithEnrollmentInfo(StudentRead):
|
||||
"""Schema avec les informations d'inscription complètes."""
|
||||
|
||||
current_class_id: Optional[int] = None
|
||||
current_class_name: Optional[str] = None
|
||||
enrollment_id: Optional[int] = None
|
||||
enrollment_date: Optional[date] = None
|
||||
departure_date: Optional[date] = None
|
||||
enrollment_reason: Optional[str] = None
|
||||
departure_reason: Optional[str] = None
|
||||
is_active: bool = True
|
||||
|
||||
|
||||
class StudentDetail(StudentWithClass):
|
||||
"""Schema détaillé avec historique d'inscriptions."""
|
||||
|
||||
@@ -49,6 +62,13 @@ class StudentList(BaseSchema):
|
||||
total: int
|
||||
|
||||
|
||||
class StudentEnrollmentList(BaseSchema):
|
||||
"""Schema pour la liste des étudiants avec informations d'inscription."""
|
||||
|
||||
students: List[StudentWithEnrollmentInfo]
|
||||
total: int
|
||||
|
||||
|
||||
# Schemas pour les inscriptions temporelles
|
||||
class EnrollmentBase(BaseSchema):
|
||||
"""Schema de base pour StudentEnrollment."""
|
||||
|
||||
Reference in New Issue
Block a user