diff --git a/app/forms/main/config_assiduites.py b/app/forms/main/config_assiduites.py index ba7198b823..da62b8b4d7 100644 --- a/app/forms/main/config_assiduites.py +++ b/app/forms/main/config_assiduites.py @@ -28,12 +28,14 @@ """ Formulaire configuration Module Assiduités """ +import datetime from flask_wtf import FlaskForm -from wtforms import SubmitField, DecimalField +from wtforms import DecimalField, SubmitField, ValidationError from wtforms.fields.simple import StringField +from wtforms.validators import Optional + from wtforms.widgets import TimeInput -import datetime class TimeField(StringField): @@ -72,9 +74,28 @@ class TimeField(StringField): else: raise ValueError self.data = datetime.time(hour, minutes, seconds) - except ValueError: + except ValueError as exc: self.data = None - raise ValueError(self.gettext("Not a valid time string")) + raise ValueError(self.gettext("Not a valid time string")) from exc + + +def check_tick_time(form, field): + """Le tick_time doit être entre 0 et 60 minutes""" + if field.data < 1 or field.data > 59: + raise ValidationError("Valeur de granularité invalide (entre 1 et 59)") + + +def check_ics_path(form, field): + """Vérifie que le chemin est bien un chemin absolu + et qu'il contient edt_id + """ + data = field.data.strip() + if not data: + return + if not data.startswith("/"): + raise ValidationError("Le chemin vers les ics doit commencer par /") + if not "{edt_id}" in data: + raise ValidationError("Le chemin vers les ics doit utiliser {edt_id}") class ConfigAssiduitesForm(FlaskForm): @@ -84,7 +105,20 @@ class ConfigAssiduitesForm(FlaskForm): lunch_time = TimeField("Heure de midi (date pivot entre Matin et Après Midi)") afternoon_time = TimeField("Fin de la journée") - tick_time = DecimalField("Granularité de la Time Line (temps en minutes)", places=0) + tick_time = DecimalField( + "Granularité de la timeline (temps en minutes)", + places=0, + validators=[check_tick_time], + ) + + edt_ics_path = StringField( + label="Chemin vers les ics", + description="""Chemin absolu unix sur le serveur vers le fichier ics donnant l'emploi + du temps d'un semestre. La balise {edt_id} sera remplacée par l'edt_id du + semestre (par défaut, son code étape Apogée). + Si ce champ n'est pas renseigné, les emplois du temps ne seront pas utilisés.""", + validators=[Optional(), check_ics_path], + ) submit = SubmitField("Valider") cancel = SubmitField("Annuler", render_kw={"formnovalidate": True}) diff --git a/app/forms/main/config_cas.py b/app/forms/main/config_cas.py index 978b84cc84..3a31b47fe4 100644 --- a/app/forms/main/config_cas.py +++ b/app/forms/main/config_cas.py @@ -42,11 +42,13 @@ def check_cas_uid_from_mail_regexp(form, field): if not ScoDocSiteConfig.cas_uid_from_mail_regexp_is_valid(field.data): raise ValidationError("expression régulière invalide") + def check_cas_edt_id_from_xml_regexp(form, field): "Vérifie la regexp fournie pour l'extraction du CAS id" if not ScoDocSiteConfig.cas_edt_id_from_xml_regexp_is_valid(field.data): raise ValidationError("expression régulière pour edt_id invalide") + class ConfigCASForm(FlaskForm): "Formulaire paramétrage CAS" cas_enable = BooleanField("Activer le CAS") diff --git a/app/forms/main/config_personalized_links.py b/app/forms/main/config_personalized_links.py index 1aed313023..b2293a2c2d 100644 --- a/app/forms/main/config_personalized_links.py +++ b/app/forms/main/config_personalized_links.py @@ -29,7 +29,7 @@ def PersonalizedLinksForm() -> _PersonalizedLinksForm: F, f"link_{idx}", StringField( - f"Titre", + "Titre", validators=[ validators.Optional(), validators.Length(min=1, max=80), @@ -42,7 +42,7 @@ def PersonalizedLinksForm() -> _PersonalizedLinksForm: F, f"link_url_{idx}", StringField( - f"URL", + "URL", description="adresse, incluant le http.", validators=[ validators.Optional(), @@ -56,7 +56,7 @@ def PersonalizedLinksForm() -> _PersonalizedLinksForm: F, f"link_with_args_{idx}", BooleanField( - f"ajouter arguments", + "ajouter arguments", description="query string avec ids", ), ) diff --git a/app/models/moduleimpls.py b/app/models/moduleimpls.py index 3ccff4cf8c..75672c1b9b 100644 --- a/app/models/moduleimpls.py +++ b/app/models/moduleimpls.py @@ -42,9 +42,6 @@ class ModuleImpl(db.Model): viewonly=True, ) - def __init__(self, **kwargs): - super(ModuleImpl, self).__init__(**kwargs) - def __repr__(self): return f"<{self.__class__.__name__} {self.id} module={repr(self.module)}>" diff --git a/app/scodoc/sco_edit_module.py b/app/scodoc/sco_edit_module.py index ea0ca9fb7b..4f5b9235ed 100644 --- a/app/scodoc/sco_edit_module.py +++ b/app/scodoc/sco_edit_module.py @@ -74,7 +74,8 @@ _moduleEditor = ndb.EditableTable( "semestre_id", "numero", "code_apogee", - "module_type" + "module_type", + "edt_id", #'ects' ), sortkey="numero, code, titre", @@ -171,7 +172,7 @@ def do_module_delete(oid): d'en créer une nouvelle version pour la modifier sans affecter les semestres déjà en place.
- reprendre """ raise ScoGenError(err_page) @@ -645,7 +646,7 @@ def module_edit( "title": "Code Apogée", "size": 25, "explanation": """(optionnel) code élément pédagogique Apogée ou liste de codes ELP - séparés par des virgules (ce code est propre à chaque établissement, se rapprocher + séparés par des virgules (ce code est propre à chaque établissement, se rapprocher du référent Apogée). """, "validator": lambda val, _: len(val) < APO_CODE_STR_LEN, @@ -682,7 +683,7 @@ def module_edit( ] + ["-1"], "explanation": """Parcours dans lesquels est utilisé ce module.Modifier les coefficients des UE capitalisées
-Formation {formation.titre} ({formation.acronyme}), version { formation.version}, code {formation.formation_code} @@ -969,11 +982,11 @@ def do_formsemestre_createwithmodules(edit=False, formsemestre: FormSemestre = N - {"
Modification effectuée
" if ok + {"Modification effectuée
" if ok else "Modules non modifiés
" } retour au tableau de bord """ @@ -1309,11 +1322,11 @@ def formsemestre_delete(formsemestre_id): html_sco_header.html_sem_header("Suppression du semestre"), """A n'utiliser qu'en cas d'erreur lors de la saisie d'une formation. Normalement, -un semestre ne doit jamais être supprimé +un semestre ne doit jamais être supprimé (on perd la mémoire des notes et de tous les événements liés à ce semestre !).
-Tous les modules de ce semestre seront supprimés. +
Tous les modules de ce semestre seront supprimés. Ceci n'est possible que si :
Dans le doute, si le mode auto n'est pas applicable et que tous les étudiants sont inscrits aux mêmes modules de ce semestre, prenez comme coefficient la somme indiquée. +
Dans le doute, si le mode auto n'est pas applicable et que tous les étudiants sont inscrits aux mêmes modules de ce semestre, prenez comme coefficient la somme indiquée. Sinon, référez vous au programme pédagogique. Les lignes en rouge sont à changer.
@@ -1734,7 +1747,7 @@ def formsemestre_edit_uecoefs(formsemestre_id, err_ue_id=None): return f"""{html_sco_header.html_sem_header("Coefficients des UE du semestre")} {" ".join(message)} - diff --git a/app/scodoc/sco_groups.py b/app/scodoc/sco_groups.py index 46b650b72c..6e21237574 100644 --- a/app/scodoc/sco_groups.py +++ b/app/scodoc/sco_groups.py @@ -79,7 +79,9 @@ partitionEditor = ndb.EditableTable( ) groupEditor = ndb.EditableTable( - "group_descr", "group_id", ("group_id", "partition_id", "group_name", "numero") + "group_descr", + "group_id", + ("group_id", "partition_id", "group_name", "numero", "edt_id"), ) group_list = groupEditor.list diff --git a/app/static/js/assiduites.js b/app/static/js/assiduites.js index 90ed21d642..aecc466968 100644 --- a/app/static/js/assiduites.js +++ b/app/static/js/assiduites.js @@ -1052,7 +1052,7 @@ function editAssiduite(assiduite_id, etat, assi) { } /** - * Récupération des assiduités conflictuelles avec la période de la time line + * Récupération des assiduités conflictuelles avec la période de la timeline * @param {String | Number} etudid identifiant de l'étudiant * @returns {Array[Assiduité]} un tableau d'assiduité */ @@ -1328,17 +1328,17 @@ function generateEtudRow( const HTML = `Configuration du suivi de l'assiduité +
Configuration du suivi de l'assiduité et accès aux emplois du temps