# -*- coding: UTF-8 -* """ScoDoc models : departements """ import re from app import db, models from app.models import SHORT_STR_LEN from app.models.preferences import ScoPreference from app.scodoc.sco_exceptions import ScoValueError VALID_DEPT_EXP = re.compile(r"^[\w@\\\-\.]+$") class Departement(models.ScoDocModel): """Un département ScoDoc""" id = db.Column(db.Integer, primary_key=True) acronym = db.Column( db.String(SHORT_STR_LEN), nullable=False, index=True, unique=True ) # ne change jamais, voir la pref. DeptName description = db.Column(db.Text()) # pas utilisé par ScoDoc : voir DeptFullName date_creation = db.Column(db.DateTime(timezone=True), server_default=db.func.now()) visible = db.Column( db.Boolean(), nullable=False, default=True, server_default="true" ) # sur page d'accueil # entreprises = db.relationship("Entreprise", lazy="dynamic", backref="departement") etudiants = db.relationship( "Identite", back_populates="departement", cascade="all,delete-orphan", lazy="dynamic", ) # This means if a Departement is deleted, all related Identite instances are also # deleted (all,delete). The orphan part means that if an Identite instance becomes # detached from its parent Departement (for example, by setting my_identite.departement = None), # it will be deleted. formations = db.relationship("Formation", lazy="dynamic", backref="departement") formsemestres = db.relationship( "FormSemestre", lazy="dynamic", backref="departement" ) preferences = db.relationship( "ScoPreference", lazy="dynamic", backref="departement" ) semsets = db.relationship("NotesSemSet", lazy="dynamic", backref="departement") referentiels = db.relationship( "ApcReferentielCompetences", lazy="dynamic", backref="departement" ) def __repr__(self): return f"<{self.__class__.__name__}(id={self.id}, acronym='{self.acronym}')>" @classmethod def get_departement(cls, dept_ident: str | int) -> "Departement": "Le département, par id ou acronyme. Erreur 404 si pas trouvé." try: dept_id = int(dept_ident) except ValueError: dept_id = None if dept_id is None: return cls.query.filter_by(acronym=dept_ident).first_or_404() return cls.get_or_404(dept_id) def to_dict(self, with_dept_name=True, with_dept_preferences=False): data = { "id": self.id, "acronym": self.acronym, "description": self.description, "visible": self.visible, "date_creation": self.date_creation, } if with_dept_name: pref = ScoPreference.query.filter_by( dept_id=self.id, name="DeptName" ).first() data["dept_name"] = pref.value if pref else None # Ceci n'est pas encore utilisé, mais pourrait être publié # par l'API après nettoyage des préférences. if with_dept_preferences: data["preferences"] = { p.name: p.value for p in ScoPreference.query.filter_by(dept_id=self.id) } return data @classmethod def invalid_dept_acronym(cls, dept_acronym: str) -> bool: "Check that dept_acronym is invalid" return ( not dept_acronym or (len(dept_acronym) >= SHORT_STR_LEN) or not VALID_DEPT_EXP.match(dept_acronym) ) @classmethod def from_acronym(cls, acronym): dept = cls.query.filter_by(acronym=acronym).first_or_404() return dept def create_dept(acronym: str, visible=True) -> Departement: "Create new departement" if Departement.invalid_dept_acronym(acronym): raise ScoValueError("acronyme departement invalide") existing = Departement.query.filter_by(acronym=acronym).count() if existing: raise ScoValueError(f"acronyme {acronym} déjà existant") departement = Departement(acronym=acronym, visible=visible) p1 = ScoPreference(name="DeptName", value=acronym, departement=departement) db.session.add(p1) db.session.add(departement) db.session.commit() return departement