diff --git a/app/forms/formsemestre/edit_description.py b/app/forms/formsemestre/edit_description.py index ea9519b80..d10cd8075 100644 --- a/app/forms/formsemestre/edit_description.py +++ b/app/forms/formsemestre/edit_description.py @@ -129,8 +129,14 @@ class FormSemestresImportFromDescrForm(ScoDocForm): FileAllowed(["xlsx"], "Fichier .xlsx uniquement"), ], ) + image_archive_file = FileField( + "Fichier zip avec les images", + validators=[ + FileAllowed(["zip"], "Fichier .zip uniquement"), + ], + ) create_formation = BooleanField( - "Créer les programmes de formations si ils n'existent pas" + "Créer les programmes de formations s'ils n'existent pas", default=True ) submit = SubmitField("Importer et créer les formations") cancel = SubmitField("Annuler") diff --git a/app/formsemestre/import_from_descr.py b/app/formsemestre/import_from_descr.py index 938cdc062..07cdf0c3b 100644 --- a/app/formsemestre/import_from_descr.py +++ b/app/formsemestre/import_from_descr.py @@ -91,7 +91,7 @@ FORMSEMESTRE_FIELDS = ( FieldDescr("titre", "titre du semestre (si vide, sera déduit de la formation)"), FieldDescr( "capacite_accueil", - "capacité d'accueil (nombre ou vide)", + "capacité d'accueil (nombre ou vide).", type="int", default=None, ), @@ -102,7 +102,7 @@ FORMSEMESTRE_FIELDS = ( "date_fin", "date fin des cours du semestre", type="date", optional=False ), FieldDescr("edt_id", "identifiant emplois du temps (optionnel)"), - FieldDescr("etat", "déverrouillage", type="bool", default=True), + FieldDescr("etat", "déverrouillage.", type="bool", default=True), FieldDescr("modalite", "modalité de formation: 'FI', 'FAP', 'FC'", default="FI"), FieldDescr( "elt_sem_apo", @@ -121,15 +121,15 @@ FORMSEMESTRE_DESCR_FIELDS = ( ), FieldDescr( "descr_horaire", - "indication sur l'horaire, texte libre, ex.: les lundis 9h-12h.", + "indication sur l'horaire, texte libre, ex.: les lundis 9h-12h", ), FieldDescr( "descr_date_debut_inscriptions", - "Date d'ouverture des inscriptions (laisser vide pour autoriser tout le temps).", + "Date d'ouverture des inscriptions (laisser vide pour autoriser tout le temps)", type="datetime", ), FieldDescr( - "descr_date_fin_inscriptions", "Date de fin des inscriptions", type="datetime" + "descr_date_fin_inscriptions", "Date de fin des inscriptions.", type="datetime" ), FieldDescr( "descr_wip", @@ -137,12 +137,16 @@ FORMSEMESTRE_DESCR_FIELDS = ( type="bool", default=False, ), - FieldDescr("descr_image", "image illustrant cette formation.", type="image"), - FieldDescr("descr_campus", "campus, par ex. Villetaneuse."), - FieldDescr("descr_salle", "salle"), + FieldDescr( + "descr_image", + "image illustrant cette formation (en excel, nom du fichier dans le zip associé)", + type="image", + ), + FieldDescr("descr_campus", "campus, par ex. Villetaneuse"), + FieldDescr("descr_salle", "salle."), FieldDescr( "descr_dispositif", - "modalité de formation: 0 présentiel, 1 online, 2 hybride.", + "modalité de formation: 0 présentiel, 1 online, 2 hybride", type="int", default=0, ), @@ -151,19 +155,19 @@ FORMSEMESTRE_DESCR_FIELDS = ( ), FieldDescr( "descr_modalites_mcc", - "modalités de contrôle des connaissances", + "modalités de contrôle des connaissances.", allow_html=True, ), FieldDescr( "descr_photo_ens", - "photo de l'enseignant(e) ou autre illustration", + "photo de l'enseignant(e) ou autre illustration (en excel, nom du fichier dans le zip associé)", type="image", ), FieldDescr("descr_public", "public visé"), FieldDescr("descr_prerequis", "prérequis", allow_html=True), FieldDescr( "descr_responsable", - "responsable du cours ou personne chargée de l'organisation du semestre.", + "responsable du cours ou personne chargée de l'organisation du semestre", allow_html=True, ), ) @@ -178,7 +182,7 @@ def describe_field(key: str) -> str: if not FIELDS_BY_KEY: FIELDS_BY_KEY.update({field.key: field for field in ALL_FIELDS}) field = FIELDS_BY_KEY[key] - return field.description + (" HTML autorisé." if field.allow_html else "") + return field.description + (" HTML autorisé" if field.allow_html else "") def generate_sample(): @@ -207,9 +211,7 @@ def check_and_convert(value, field: FieldDescr): case "int": return int(value) case "image": - return None # XXX ignore - if value: # WIP - raise NotImplementedError("image import from Excel not implemented") + return str(value).strip() # image path case "bool": return scu.to_bool(value) case "date": @@ -304,13 +306,14 @@ def _create_formation_and_modimpl(data) -> Formation: def create_formsemestre_from_description( - data: dict, create_formation=False + data: dict, create_formation=False, images: dict | None = None ) -> FormSemestre: """Create from fields in data. - Search formation: if needed and create_formation, create it; - Create formsemestre - Create formsemestre description """ + images = images or {} created = [] # list of created objects XXX unused user = current_user # resp. semestre et module formation = ( @@ -365,13 +368,15 @@ def create_formsemestre_from_description( def create_formsemestres_from_description( - infos: list[dict], create_formation: bool = False + infos: list[dict], create_formation: bool = False, images: dict | None = None ) -> list[FormSemestre]: "Creation de tous les semestres mono-modules" log( f"create_formsemestres_from_description: {len(infos)} items, create_formation={create_formation}" ) return [ - create_formsemestre_from_description(data, create_formation=create_formation) + create_formsemestre_from_description( + data, create_formation=create_formation, images=images + ) for data in infos ] diff --git a/app/templates/formsemestre/import_from_description.j2 b/app/templates/formsemestre/import_from_description.j2 index 65f93aefa..b89aab5f5 100644 --- a/app/templates/formsemestre/import_from_description.j2 +++ b/app/templates/formsemestre/import_from_description.j2 @@ -18,7 +18,8 @@ décrits dans un fichier excel.