diff --git a/app/models/formsemestre.py b/app/models/formsemestre.py index 994e201d..4506eed0 100644 --- a/app/models/formsemestre.py +++ b/app/models/formsemestre.py @@ -280,7 +280,10 @@ class FormSemestre(db.Model): raise ScoValueError("Le semestre n'a pas de groupe par défaut") def get_edt_ids(self) -> list[str]: - "l'ids pour l'emploi du temps: à défaut, les codes étape Apogée" + """Les ids pour l'emploi du temps: à défaut, les codes étape Apogée. + Les edt_id de formsemestres ne sont pas normalisés afin de contrôler + précisément l'accès au fichier ics. + """ return ( scu.split_id(self.edt_id) or [e.etape_apo.strip() for e in self.etapes if e.etape_apo] diff --git a/app/models/groups.py b/app/models/groups.py index 6c112058..7250f1e6 100644 --- a/app/models/groups.py +++ b/app/models/groups.py @@ -251,8 +251,11 @@ class GroupDescr(ScoDocModel): return d def get_edt_ids(self) -> list[str]: - "les ids pour l'emploi du temps: à défaut, le nom scodoc du groupe" - return scu.split_id(self.edt_id) or [self.group_name] or [] + "les ids normalisés pour l'emploi du temps: à défaut, le nom scodoc du groupe" + return [ + scu.normalize_edt_id(x) + for x in scu.split_id(self.edt_id) or [self.group_name] or [] + ] def get_nb_inscrits(self) -> int: """Nombre inscrits à ce group et au formsemestre. diff --git a/app/models/moduleimpls.py b/app/models/moduleimpls.py index a98fcf0f..b674ed99 100644 --- a/app/models/moduleimpls.py +++ b/app/models/moduleimpls.py @@ -67,11 +67,10 @@ class ModuleImpl(db.Model): def get_edt_ids(self) -> list[str]: "les ids pour l'emploi du temps: à défaut, les codes Apogée" - return ( - scu.split_id(self.edt_id) - or scu.split_id(self.code_apogee) - or self.module.get_edt_ids() - ) + return [ + scu.normalize_edt_id(x) + for x in scu.split_id(self.edt_id) or scu.split_id(self.code_apogee) + ] or self.module.get_edt_ids() def get_evaluations_poids(self) -> pd.DataFrame: """Les poids des évaluations vers les UE (accès via cache)""" diff --git a/app/models/modules.py b/app/models/modules.py index 0410395c..430835a9 100644 --- a/app/models/modules.py +++ b/app/models/modules.py @@ -292,7 +292,10 @@ class Module(db.Model): def get_edt_ids(self) -> list[str]: "les ids pour l'emploi du temps: à défaut, le 1er code Apogée" - return scu.split_id(self.edt_id) or scu.split_id(self.code_apogee) or [] + return [ + scu.normalize_edt_id(x) + for x in scu.split_id(self.edt_id) or scu.split_id(self.code_apogee) or [] + ] def get_parcours(self) -> list[ApcParcours]: """Les parcours utilisant ce module. diff --git a/app/scodoc/sco_edt_cal.py b/app/scodoc/sco_edt_cal.py index 8f3c0715..7440de93 100644 --- a/app/scodoc/sco_edt_cal.py +++ b/app/scodoc/sco_edt_cal.py @@ -343,7 +343,7 @@ def load_and_convert_ics(formsemestre: FormSemestre) -> tuple[list[dict], list[s group_name: _COLOR_PALETTE[i % (len(_COLOR_PALETTE) - 1) + 1] for i, group_name in enumerate(edt2group) } - edt_groups_ids = set() # les ids de groupes tels que dans l'ics + edt_groups_ids = set() # les ids de groupes normalisés tels que dans l'ics default_group = formsemestre.get_default_group() edt2modimpl = formsemestre_retreive_modimpls_from_edt_id(formsemestre) edt2user: dict[str, User | None] = {} # construit au fur et à mesure (cache) @@ -442,14 +442,17 @@ def extract_event_data( ics_field: str, pattern: re.Pattern, none_if_no_match=False, -) -> str: - """Extrait la chaine (id) de l'évènement.""" +) -> str | None: + """Extrait la chaine (id) de l'évènement et la normalise. + Si l'event n'a pas le champs: "-" + Si pas de match: None + """ if not event.has_key(ics_field): return "-" data = event.decoded(ics_field).decode("utf-8") # assume ics in utf8 m = pattern.search(data) if m and len(m.groups()) > 0: - return m.group(1) + return scu.normalize_edt_id(m.group(1)) # fallback: if not none_if_no_match, ics field complete return None if none_if_no_match else data @@ -457,7 +460,7 @@ def extract_event_data( def formsemestre_retreive_modimpls_from_edt_id( formsemestre: FormSemestre, ) -> dict[str, ModuleImpl]: - """Construit un dict donnant le moduleimpl de chaque edt_id""" + """Construit un dict donnant le moduleimpl de chaque edt_id (normalisé)""" edt2modimpl = {} for modimpl in formsemestre.modimpls: for edt_id in modimpl.get_edt_ids(): @@ -469,10 +472,13 @@ def formsemestre_retreive_modimpls_from_edt_id( def formsemestre_retreive_groups_from_edt_id( formsemestre: FormSemestre, ) -> dict[str, GroupDescr]: - """Construit un dict donnant le groupe de chaque edt_id""" + """Construit un dict donnant le groupe de chaque edt_id + La clé edt_id est sans accents, lowercase. + """ edt2group = {} + group: GroupDescr for partition in formsemestre.partitions: - for g in partition.groups: - for edt_id in g.get_edt_ids(): - edt2group[edt_id] = g + for group in partition.groups: + for edt_id in group.get_edt_ids(): + edt2group[edt_id] = group return edt2group diff --git a/app/scodoc/sco_utils.py b/app/scodoc/sco_utils.py index 7f23f846..62e83200 100644 --- a/app/scodoc/sco_utils.py +++ b/app/scodoc/sco_utils.py @@ -841,6 +841,18 @@ def suppress_accents(s): return s # may be int +def normalize_edt_id(edt_id: str) -> str: + """Normalize les identifiants edt pour faciliter la correspondance + entre les identifiants ScoDoc et ceux dans l'ics: + Passe tout en majuscules sans accents ni espaces. + """ + return ( + None + if edt_id is None + else suppress_accents(edt_id or "").upper().replace(" ", "") + ) + + class PurgeChars: """delete all chars except those belonging to the specified string"""