210 lines
6.6 KiB
Python
210 lines
6.6 KiB
Python
from typing import List, Optional, Dict, Tuple
|
|
from sqlalchemy.orm import joinedload
|
|
from sqlalchemy import and_
|
|
from models import ClassGroup, Student, Assessment
|
|
from .base_repository import BaseRepository
|
|
|
|
|
|
class ClassRepository(BaseRepository[ClassGroup]):
|
|
"""Repository pour les classes (ClassGroup)."""
|
|
|
|
def __init__(self):
|
|
super().__init__(ClassGroup)
|
|
|
|
def get_or_404(self, id: int) -> ClassGroup:
|
|
"""
|
|
Récupère une classe ou lève une erreur 404.
|
|
|
|
Args:
|
|
id: Identifiant de la classe
|
|
|
|
Returns:
|
|
ClassGroup: La classe trouvée
|
|
|
|
Raises:
|
|
404: Si la classe n'existe pas
|
|
"""
|
|
return ClassGroup.query.get_or_404(id)
|
|
|
|
def find_by_name(self, name: str) -> Optional[ClassGroup]:
|
|
"""
|
|
Trouve une classe par son nom.
|
|
|
|
Args:
|
|
name: Nom de la classe à rechercher
|
|
|
|
Returns:
|
|
Optional[ClassGroup]: La classe trouvée ou None
|
|
"""
|
|
return ClassGroup.query.filter_by(name=name).first()
|
|
|
|
def exists_by_name(self, name: str, exclude_id: Optional[int] = None) -> bool:
|
|
"""
|
|
Vérifie si une classe avec ce nom existe déjà.
|
|
|
|
Args:
|
|
name: Nom à vérifier
|
|
exclude_id: ID de classe à exclure de la recherche (pour la modification)
|
|
|
|
Returns:
|
|
bool: True si une classe avec ce nom existe
|
|
"""
|
|
query = ClassGroup.query.filter_by(name=name)
|
|
|
|
if exclude_id is not None:
|
|
query = query.filter(ClassGroup.id != exclude_id)
|
|
|
|
return query.first() is not None
|
|
|
|
def find_all_ordered(self, order_by: str = 'year_name') -> List[ClassGroup]:
|
|
"""
|
|
Trouve toutes les classes triées selon le critère spécifié.
|
|
|
|
Args:
|
|
order_by: Critère de tri ('year_name', 'name', 'year')
|
|
|
|
Returns:
|
|
List[ClassGroup]: Liste des classes triées
|
|
"""
|
|
query = ClassGroup.query
|
|
|
|
if order_by == 'year_name':
|
|
query = query.order_by(ClassGroup.year, ClassGroup.name)
|
|
elif order_by == 'name':
|
|
query = query.order_by(ClassGroup.name)
|
|
elif order_by == 'year':
|
|
query = query.order_by(ClassGroup.year)
|
|
else:
|
|
# Défaut : tri par nom
|
|
query = query.order_by(ClassGroup.name)
|
|
|
|
return query.all()
|
|
|
|
def count_all(self) -> int:
|
|
"""
|
|
Compte le nombre total de classes.
|
|
|
|
Returns:
|
|
int: Nombre de classes
|
|
"""
|
|
return ClassGroup.query.count()
|
|
|
|
def can_be_deleted(self, id: int) -> Tuple[bool, Dict[str, int]]:
|
|
"""
|
|
Vérifie si une classe peut être supprimée et retourne les dépendances.
|
|
|
|
Args:
|
|
id: Identifiant de la classe
|
|
|
|
Returns:
|
|
Tuple[bool, Dict[str, int]]: (peut_être_supprimée, statistiques_dépendances)
|
|
"""
|
|
students_count = Student.query.filter_by(class_group_id=id).count()
|
|
assessments_count = Assessment.query.filter_by(class_group_id=id).count()
|
|
|
|
dependencies = {
|
|
'students': students_count,
|
|
'assessments': assessments_count
|
|
}
|
|
|
|
can_delete = students_count == 0 and assessments_count == 0
|
|
|
|
return can_delete, dependencies
|
|
|
|
def find_with_students_ordered(self, id: int) -> Optional[ClassGroup]:
|
|
"""
|
|
Trouve une classe avec ses étudiants triés par nom.
|
|
|
|
Args:
|
|
id: Identifiant de la classe
|
|
|
|
Returns:
|
|
Optional[ClassGroup]: La classe avec étudiants triés ou None
|
|
"""
|
|
class_group = ClassGroup.query.get(id)
|
|
if not class_group:
|
|
return None
|
|
|
|
# Charger les étudiants triés
|
|
students = Student.query.filter_by(class_group_id=id).order_by(
|
|
Student.last_name, Student.first_name
|
|
).all()
|
|
|
|
# Assigner les étudiants triés à la classe
|
|
class_group._students_ordered = students
|
|
|
|
return class_group
|
|
|
|
def find_with_recent_assessments(self, id: int, limit: int = 5) -> Optional[ClassGroup]:
|
|
"""
|
|
Trouve une classe avec ses évaluations récentes.
|
|
|
|
Args:
|
|
id: Identifiant de la classe
|
|
limit: Nombre maximum d'évaluations à récupérer
|
|
|
|
Returns:
|
|
Optional[ClassGroup]: La classe avec évaluations récentes ou None
|
|
"""
|
|
class_group = ClassGroup.query.get(id)
|
|
if not class_group:
|
|
return None
|
|
|
|
# Charger les évaluations récentes
|
|
recent_assessments = Assessment.query.filter_by(class_group_id=id).order_by(
|
|
Assessment.date.desc()
|
|
).limit(limit).all()
|
|
|
|
# Assigner les évaluations récentes à la classe
|
|
class_group._recent_assessments = recent_assessments
|
|
|
|
return class_group
|
|
|
|
def find_with_full_details(self, id: int) -> Optional[ClassGroup]:
|
|
"""
|
|
Trouve une classe avec tous ses détails (étudiants et évaluations).
|
|
|
|
Args:
|
|
id: Identifiant de la classe
|
|
|
|
Returns:
|
|
Optional[ClassGroup]: La classe avec tous ses détails ou None
|
|
"""
|
|
return ClassGroup.query.options(
|
|
joinedload(ClassGroup.students),
|
|
joinedload(ClassGroup.assessments)
|
|
).filter_by(id=id).first()
|
|
|
|
def get_students_count(self, id: int) -> int:
|
|
"""
|
|
Compte le nombre d'étudiants dans une classe.
|
|
|
|
Args:
|
|
id: Identifiant de la classe
|
|
|
|
Returns:
|
|
int: Nombre d'étudiants
|
|
"""
|
|
return Student.query.filter_by(class_group_id=id).count()
|
|
|
|
def get_assessments_count(self, id: int) -> int:
|
|
"""
|
|
Compte le nombre d'évaluations dans une classe.
|
|
|
|
Args:
|
|
id: Identifiant de la classe
|
|
|
|
Returns:
|
|
int: Nombre d'évaluations
|
|
"""
|
|
return Assessment.query.filter_by(class_group_id=id).count()
|
|
|
|
def find_for_form_choices(self) -> List[ClassGroup]:
|
|
"""
|
|
Trouve toutes les classes pour les choix de formulaires.
|
|
Optimisé pour n'inclure que les champs nécessaires.
|
|
|
|
Returns:
|
|
List[ClassGroup]: Liste des classes triées par nom
|
|
"""
|
|
return ClassGroup.query.order_by(ClassGroup.name).all() |