Update opolka/ScoDoc from ScoDoc/ScoDoc #2

Merged
opolka merged 1272 commits from ScoDoc/ScoDoc:master into master 2024-05-27 09:11:04 +02:00
3 changed files with 75 additions and 40 deletions
Showing only changes of commit 6423baa34b - Show all commits

View File

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

View File

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

View File

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