EDT: gestion de plusieurs enseignants par évènement

This commit is contained in:
Emmanuel Viennet 2024-01-03 22:11:49 +01:00
parent 96aaca9746
commit 6423baa34b
3 changed files with 75 additions and 40 deletions

View File

@ -192,15 +192,16 @@ class ConfigAssiduitesForm(FlaskForm):
validators=[Optional(), check_ics_regexp],
)
edt_ics_uid_field = StringField(
label="Champ contenant l'enseignant",
label="Champ contenant les enseignants",
description="""champ de l'évènement calendrier: DESCRIPTION, SUMMARY, ...""",
validators=[Optional(), check_ics_field],
)
edt_ics_uid_regexp = StringField(
label="Extraction de l'enseignant",
description=r"""expression régulière python dont le premier groupe doit
correspondre à l'identifiant (edt_id) de l'enseignant associé à l'évènement.
Exemple: <tt>Enseignant : ([0-9]+)</tt>
label="Extraction des enseignants",
description=r"""expression régulière python permettant d'extraire les
identifiants des enseignants associés à l'évènement.
(contrairement aux autres champs, il peut y avoir plusieurs enseignants par évènement.)
Exemple: <tt>[0-9]+</tt>
""",
validators=[Optional(), check_ics_regexp],
)

View File

@ -132,7 +132,8 @@ def load_calendar(
) from exc
except FileNotFoundError as exc:
log(
f"formsemestre_load_calendar: ics not found for {formsemestre or ''}\npath='{ics_filename}'"
f"""formsemestre_load_calendar: ics not found for {
formsemestre or ''}\npath='{ics_filename}'"""
)
raise ScoValueError(
f"Fichier ics introuvable (filename={ics_filename})"
@ -229,7 +230,8 @@ def formsemestre_edt_dict(
scu.EMO_WARNING} {event['edt_module']}</span>"""
bubble = "code module non trouvé dans ScoDoc. Vérifier configuration."
case _: # module EDT bien retrouvé dans ScoDoc
bubble = f"{modimpl.module.abbrev or modimpl.module.titre or ''} ({event['edt_module']})"
bubble = f"""{modimpl.module.abbrev or modimpl.module.titre or ''
} ({event['edt_module']})"""
mod_disp = (
f"""<span class="mod-name mod-code">{modimpl.module.code}</span>"""
)
@ -249,20 +251,24 @@ def formsemestre_edt_dict(
else ""
)
ens_user_name = event["ens"].user_name if event["ens"] else None
ens_nomprenom = event["ens"].get_nomprenom() if event["ens"] else None
ens_nomprenoms = (
"(" + ", ".join([u.get_nomprenom() for u in event["users"]]) + ")"
if event["users"]
else ""
)
ens_user_names = (
",".join([u.user_name for u in event["users"]]) if event["users"] else ""
)
d = {
# Champs utilisés par tui.calendar
"calendarId": "cal1",
"title": f"""{title} {group_disp} {
'('+ens_nomprenom+')' if ens_nomprenom else ''
} {link_abs}""",
"title": f"""{title} {group_disp} {ens_nomprenoms} {link_abs}""",
"start": event["start"],
"end": event["end"],
"backgroundColor": event["group_bg_color"],
# Infos brutes pour usage API éventuel
"ens_edt": event["edt_ens"],
"ens_user_name": ens_user_name,
"edt_ens_ids": event["edt_ens_ids"],
"ens_user_names": ens_user_names,
"group_id": group.id if group else None,
"group_edt_id": event["edt_group"],
"moduleimpl_id": modimpl.id if modimpl else None,
@ -354,7 +360,7 @@ def load_and_convert_ics(formsemestre: FormSemestre) -> tuple[list[dict], list[s
if "DESCRIPTION" in event:
# --- Titre de l'évènement
title_edt = (
extract_event_data(event, edt_ics_title_field, edt_ics_title_pattern)
extract_event_edt_id(event, edt_ics_title_field, edt_ics_title_pattern)
if edt_ics_title_pattern
else "non configuré"
)
@ -362,7 +368,7 @@ def load_and_convert_ics(formsemestre: FormSemestre) -> tuple[list[dict], list[s
title = title_edt
# --- Group
if edt_ics_group_pattern:
edt_group = extract_event_data(
edt_group = extract_event_edt_id(
event, edt_ics_group_field, edt_ics_group_pattern
)
edt_groups_ids.add(edt_group)
@ -385,7 +391,7 @@ def load_and_convert_ics(formsemestre: FormSemestre) -> tuple[list[dict], list[s
# --- ModuleImpl
if edt_ics_mod_pattern:
edt_module = extract_event_data(
edt_module = extract_event_edt_id(
event, edt_ics_mod_field, edt_ics_mod_pattern
)
modimpl: ModuleImpl = edt2modimpl.get(edt_module, None)
@ -394,19 +400,22 @@ def load_and_convert_ics(formsemestre: FormSemestre) -> tuple[list[dict], list[s
else:
modimpl = False
edt_module = ""
# --- Enseignant
# --- Enseignants
users: list[User] = []
if edt_ics_uid_pattern:
edt_ens = extract_event_data(
ens_edt_ids = extract_event_edt_ids(
event, edt_ics_uid_field, edt_ics_uid_pattern
)
if edt_ens in edt2user:
ens = edt2user[edt_ens]
else:
ens = User.query.filter_by(edt_id=edt_ens).first()
edt2user[edt_ens] = ens
for ens_edt_id in ens_edt_ids:
if ens_edt_id in edt2user:
ens = edt2user[ens_edt_id]
else:
ens = User.query.filter_by(edt_id=ens_edt_id).first()
edt2user[ens_edt_id] = ens
if ens:
users.append(ens)
else:
ens = None
edt_ens = ""
ens_edt_ids = []
#
events_sco.append(
{
@ -418,8 +427,8 @@ def load_and_convert_ics(formsemestre: FormSemestre) -> tuple[list[dict], list[s
"modimpl": modimpl, # False si extracteur non configuré
"edt_module": edt_module, # id module edt non traduit
# Enseignant
"edt_ens": edt_ens, # id ens edt, non traduit
"ens": ens,
"edt_ens_ids": ens_edt_ids, # ids ens edt, normalisés mais non traduits
"users": users,
# heures pour saisie abs: en heure LOCALE DU SERVEUR
"heure_deb": event.decoded("dtstart")
.replace(tzinfo=timezone.utc)
@ -437,14 +446,14 @@ def load_and_convert_ics(formsemestre: FormSemestre) -> tuple[list[dict], list[s
return events_sco, sorted(edt_groups_ids)
def extract_event_data(
def extract_event_edt_id(
event: icalendar.cal.Event,
ics_field: str,
pattern: re.Pattern,
none_if_no_match=False,
) -> str | None:
"""Extrait la chaine (id) de l'évènement et la normalise.
Si l'event n'a pas le champs: "-"
Si l'event n'a pas le champ: "-"
Si pas de match: None
"""
if not event.has_key(ics_field):
@ -457,6 +466,25 @@ def extract_event_data(
return None if none_if_no_match else data
def extract_event_edt_ids(
event: icalendar.cal.Event,
ics_field: str,
pattern: re.Pattern,
) -> list[str] | None:
"""Extrait les edt_id de l'évènement et les normalise.
Si l'event n'a pas le champ: None
Si pas de match: liste vide
Utilisé pour les enseignants uniquement.
"""
if not event.has_key(ics_field):
return
data = event.decoded(ics_field).decode("utf-8") # assume ics in utf8
matches = pattern.findall(data)
# nota: pattern may have zero or one group, so the result
# is a list of strings, not a list of matches
return [scu.normalize_edt_id(m) for m in matches if m]
def formsemestre_retreive_modimpls_from_edt_id(
formsemestre: FormSemestre,
) -> dict[str, ModuleImpl]:

View File

@ -86,17 +86,23 @@ def generate_ens_calendars():
nb_events += len(events)
ens: User | None = None
for event in events:
edt_ens = sco_edt_cal.extract_event_data(
event, edt_ics_uid_field, edt_ics_uid_pattern, none_if_no_match=True
ens_edt_ids = sco_edt_cal.extract_event_edt_ids(
event, edt_ics_uid_field, edt_ics_uid_pattern
)
if edt_ens in edt2user:
ens = edt2user[edt_ens]
else:
ens = User.query.filter_by(edt_id=edt_ens).first()
edt2user[edt_ens] = ens
if ens: # si l'utilisateur est reconnu
event.add("X-ScoDoc-user", ens.user_name)
edt_by_uid[edt_ens].add_component(event)
users = []
for ens_edt_id in ens_edt_ids:
if ens_edt_id in edt2user:
ens = edt2user[ens_edt_id]
else:
ens = User.query.filter_by(edt_id=ens_edt_id).first()
edt2user[ens_edt_id] = ens
if ens:
users.append(ens)
edt_by_uid[ens_edt_id].add_component(event)
if users: # si un utilisateur est reconnu dans l'event
event.add("X-ScoDoc-users", ",".join([u.user_name for u in users]))
_write_user_calendars(edt_by_uid)
log(
f"""generate_ens_calendars: done in {(time.time()-t0):g}s, processed {