Améliore import/export formations APC.

This commit is contained in:
Emmanuel Viennet 2023-01-25 11:17:52 -03:00
parent 3ba553c090
commit fca090649c
14 changed files with 81 additions and 34 deletions

View File

@ -55,7 +55,8 @@ class Formation(db.Model):
modules = db.relationship("Module", lazy="dynamic", backref="formation") modules = db.relationship("Module", lazy="dynamic", backref="formation")
def __repr__(self): def __repr__(self):
return f"<{self.__class__.__name__}(id={self.id}, dept_id={self.dept_id}, acronyme='{self.acronyme!r}')>" return f"""<{self.__class__.__name__}(id={self.id}, dept_id={
self.dept_id}, acronyme={self.acronyme!r}, version={self.version})>"""
def to_html(self) -> str: def to_html(self) -> str:
"titre complet pour affichage" "titre complet pour affichage"

View File

@ -111,6 +111,7 @@ class UniteEns(db.Model):
e["ects"] = e["ects"] e["ects"] = e["ects"]
e["coefficient"] = e["coefficient"] if e["coefficient"] else 0.0 e["coefficient"] = e["coefficient"] if e["coefficient"] else 0.0
e["code_apogee"] = e["code_apogee"] or "" # pas de None e["code_apogee"] = e["code_apogee"] or "" # pas de None
e["parcour"] = self.parcour.to_dict() if self.parcour else None
if with_module_ue_coefs: if with_module_ue_coefs:
if convert_objects: if convert_objects:
e["module_ue_coefs"] = [ e["module_ue_coefs"] = [

View File

@ -99,7 +99,7 @@ def html_edit_formation_apc(
H = [ H = [
render_template( render_template(
"pn/form_ues.html", "pn/form_ues.j2",
formation=formation, formation=formation,
semestre_ids=semestre_ids, semestre_ids=semestre_ids,
editable=editable, editable=editable,
@ -122,7 +122,7 @@ def html_edit_formation_apc(
).first() ).first()
H += [ H += [
render_template( render_template(
"pn/form_mods.html", "pn/form_mods.j2",
formation=formation, formation=formation,
titre=f"Ressources du S{semestre_idx}", titre=f"Ressources du S{semestre_idx}",
create_element_msg="créer une nouvelle ressource", create_element_msg="créer une nouvelle ressource",
@ -138,7 +138,7 @@ def html_edit_formation_apc(
if ues_by_sem[semestre_idx].count() > 0 if ues_by_sem[semestre_idx].count() > 0
else "", else "",
render_template( render_template(
"pn/form_mods.html", "pn/form_mods.j2",
formation=formation, formation=formation,
titre=f"Situations d'Apprentissage et d'Évaluation (SAÉs) S{semestre_idx}", titre=f"Situations d'Apprentissage et d'Évaluation (SAÉs) S{semestre_idx}",
create_element_msg="créer une nouvelle SAÉ", create_element_msg="créer une nouvelle SAÉ",
@ -154,7 +154,7 @@ def html_edit_formation_apc(
if ues_by_sem[semestre_idx].count() > 0 if ues_by_sem[semestre_idx].count() > 0
else "", else "",
render_template( render_template(
"pn/form_mods.html", "pn/form_mods.j2",
formation=formation, formation=formation,
titre=f"Autres modules (non BUT) du S{semestre_idx}", titre=f"Autres modules (non BUT) du S{semestre_idx}",
create_element_msg="créer un nouveau module", create_element_msg="créer un nouveau module",
@ -196,7 +196,7 @@ def html_ue_infos(ue):
and ue.matieres.count() == 0 and ue.matieres.count() == 0
) )
return render_template( return render_template(
"pn/ue_infos.html", "pn/ue_infos.j2",
titre=f"UE {ue.acronyme} {ue.titre}", titre=f"UE {ue.acronyme} {ue.titre}",
ue=ue, ue=ue,
formsemestres=formsemestres, formsemestres=formsemestres,

View File

@ -723,7 +723,7 @@ def ue_table(formation_id=None, semestre_idx=1, msg=""): # was ue_list
"libjs/jQuery-tagEditor/jquery.caret.min.js", "libjs/jQuery-tagEditor/jquery.caret.min.js",
"js/module_tag_editor.js", "js/module_tag_editor.js",
], ],
page_title=f"Programme {formation.acronyme}", page_title=f"Programme {formation.acronyme} v{formation.version}",
), ),
f"""<h2>{formation.to_html()} {lockicon} f"""<h2>{formation.to_html()} {lockicon}
</h2> </h2>
@ -765,7 +765,7 @@ du programme" (menu "Semestre") si vous avez un semestre en cours);
# Description de la formation # Description de la formation
H.append( H.append(
render_template( render_template(
"pn/form_descr.html", "pn/form_descr.j2",
formation=formation, formation=formation,
parcours=parcours, parcours=parcours,
editable=editable, editable=editable,
@ -913,8 +913,12 @@ du programme" (menu "Semestre") si vous avez un semestre en cours);
<li><a class="stdlink" href="{ <li><a class="stdlink" href="{
url_for('notes.formation_export', scodoc_dept=g.scodoc_dept, url_for('notes.formation_export', scodoc_dept=g.scodoc_dept,
formation_id=formation_id, format='xml') formation_id=formation_id, format='xml')
}">Export XML de la formation</a> }">Export XML de la formation</a> ou
(permet de la sauvegarder pour l'échanger avec un autre site) <a class="stdlink" href="{
url_for('notes.formation_export', scodoc_dept=g.scodoc_dept,
formation_id=formation_id, format='xml', export_codes_apo=0)
}">sans codes Apogée</a>
(permet de l'enregistrer pour l'échanger avec un autre site)
</li> </li>
<li><a class="stdlink" href="{ <li><a class="stdlink" href="{

View File

@ -109,6 +109,7 @@ def formation_export(
export_ids=False, export_ids=False,
export_tags=True, export_tags=True,
export_external_ues=False, export_external_ues=False,
export_codes_apo=True,
format=None, format=None,
): ):
"""Get a formation, with UE, matieres, modules """Get a formation, with UE, matieres, modules
@ -116,30 +117,45 @@ def formation_export(
""" """
formation: Formation = Formation.query.get_or_404(formation_id) formation: Formation = Formation.query.get_or_404(formation_id)
f_dict = formation.to_dict(with_refcomp_attrs=True) f_dict = formation.to_dict(with_refcomp_attrs=True)
selector = {"formation_id": formation_id} if not export_ids:
del f_dict["formation_id"]
del f_dict["dept_id"]
ues = formation.ues
if not export_external_ues: if not export_external_ues:
selector["is_external"] = False ues = ues.filter_by(is_external=False)
ues = sco_edit_ue.ue_list(selector) ues = ues.all()
f_dict["ue"] = ues ues.sort(key=lambda u: (u.semestre_idx or 0, u.numero or 0, u.acronyme))
for ue_dict in ues: f_dict["ue"] = []
ue_id = ue_dict["ue_id"] for ue in ues:
ue_dict = ue.to_dict()
f_dict["ue"].append(ue_dict)
ue_dict.pop("module_ue_coefs", None)
if formation.is_apc(): if formation.is_apc():
# BUT: indique niveau de compétence associé à l'UE # BUT: indique niveau de compétence associé à l'UE
ue = UniteEns.query.get(ue_id)
if ue.niveau_competence: if ue.niveau_competence:
ue_dict["apc_niveau_libelle"] = ue.niveau_competence.libelle ue_dict["apc_niveau_libelle"] = ue.niveau_competence.libelle
ue_dict["apc_niveau_annee"] = ue.niveau_competence.annee ue_dict["apc_niveau_annee"] = ue.niveau_competence.annee
ue_dict["apc_niveau_ordre"] = ue.niveau_competence.ordre ue_dict["apc_niveau_ordre"] = ue.niveau_competence.ordre
ue_dict["reference"] = ue_id # pour les coefficients # Et le parcour:
if ue.parcour:
ue_dict["parcour"] = [ue.parcour.to_dict(with_annees=False)]
ue_dict["reference"] = ue.id # pour les coefficients
if not export_ids: if not export_ids:
del ue_dict["id"] for id_id in (
del ue_dict["ue_id"] "id",
del ue_dict["formation_id"] "ue_id",
if "niveau_competence_id" in ue_dict: "formation_id",
del ue_dict["niveau_competence_id"] "parcour_id",
"niveau_competence_id",
):
ue_dict.pop(id_id, None)
if not export_codes_apo:
ue_dict.pop("code_apogee", None)
if ue_dict["ects"] is None: if ue_dict["ects"] is None:
del ue_dict["ects"] del ue_dict["ects"]
mats = sco_edit_matiere.matiere_list({"ue_id": ue_id}) mats = sco_edit_matiere.matiere_list({"ue_id": ue.id})
mats.sort(key=lambda m: m["numero"] or 0)
ue_dict["matiere"] = mats ue_dict["matiere"] = mats
for mat in mats: for mat in mats:
matiere_id = mat["matiere_id"] matiere_id = mat["matiere_id"]
@ -148,6 +164,7 @@ def formation_export(
del mat["matiere_id"] del mat["matiere_id"]
del mat["ue_id"] del mat["ue_id"]
mods = sco_edit_module.module_list({"matiere_id": matiere_id}) mods = sco_edit_module.module_list({"matiere_id": matiere_id})
mods.sort(key=lambda m: (m["numero"] or 0, m["code"]))
mat["module"] = mods mat["module"] = mods
for mod in mods: for mod in mods:
module_id = mod["module_id"] module_id = mod["module_id"]
@ -183,6 +200,8 @@ def formation_export(
del mod["matiere_id"] del mod["matiere_id"]
del mod["module_id"] del mod["module_id"]
del mod["formation_id"] del mod["formation_id"]
if not export_codes_apo:
del mod["code_apogee"]
if mod["ects"] is None: if mod["ects"] is None:
del mod["ects"] del mod["ects"]
@ -323,14 +342,30 @@ def formation_import_xml(doc: str, import_tags=True, use_local_refcomp=False):
referentiel_competence_id, ue_info[1] referentiel_competence_id, ue_info[1]
) )
ue_id = sco_edit_ue.do_ue_create(ue_info[1]) ue_id = sco_edit_ue.do_ue_create(ue_info[1])
ue: UniteEns = UniteEns.query.get(ue_id)
assert ue
if xml_ue_id: if xml_ue_id:
ues_old2new[xml_ue_id] = ue_id ues_old2new[xml_ue_id] = ue_id
# élément optionnel présent dans les exports BUT: # élément optionnel présent dans les exports BUT:
ue_reference = ue_info[1].get("reference") ue_reference = ue_info[1].get("reference")
if ue_reference: if ue_reference:
ue_reference_to_id[int(ue_reference)] = ue_id ue_reference_to_id[int(ue_reference)] = ue_id
# -- create matieres # -- create matieres
for mat_info in ue_info[2]: for mat_info in ue_info[2]:
if mat_info[0] == "parcour":
# Parcours (BUT)
code_parcours = mat_info[1]["code"]
parcour = ApcParcours.query.filter_by(
code=code_parcours,
referentiel_id=referentiel_competence_id,
).first()
if parcour:
ue.parcour = parcour
db.session.add(ue)
else:
log(f"Warning: parcours {code_parcours} inexistant !")
continue
assert mat_info[0] == "matiere" assert mat_info[0] == "matiere"
mat_info[1]["ue_id"] = ue_id mat_info[1]["ue_id"] = ue_id
mat_id = sco_edit_matiere.do_matiere_create(mat_info[1]) mat_id = sco_edit_matiere.do_matiere_create(mat_info[1])
@ -382,12 +417,12 @@ def formation_import_xml(doc: str, import_tags=True, use_local_refcomp=False):
# associe les parcours de ce module (BUT) # associe les parcours de ce module (BUT)
if referentiel_competence_id is not None: if referentiel_competence_id is not None:
code_parcours = child[1]["code"] code_parcours = child[1]["code"]
parcours = ApcParcours.query.filter_by( parcour = ApcParcours.query.filter_by(
code=code_parcours, code=code_parcours,
referentiel_id=referentiel_competence_id, referentiel_id=referentiel_competence_id,
).first() ).first()
if parcours: if parcour:
module.parcours.append(parcours) module.parcours.append(parcour)
db.session.add(module) db.session.add(module)
else: else:
log( log(

View File

@ -200,7 +200,7 @@ def etud_photo_html(etud: dict = None, etudid=None, title=None, size="small") ->
return abort(404, "etudiant inconnu") return abort(404, "etudiant inconnu")
etud = etuds[0] etud = etuds[0]
else: else:
raise ValueError("etud_photo_html: either etud or etudid must be specified") abort(404, "etud_photo_html: either etud or etudid must be specified")
photo_url = etud_photo_url(etud, size=size) photo_url = etud_photo_url(etud, size=size)
nom = etud.get("nomprenom", etud["nom_disp"]) nom = etud.get("nomprenom", etud["nom_disp"])
if title is None: if title is None:
@ -244,7 +244,7 @@ def photo_pathname(photo_filename: str, size="orig"):
elif size == "orig": elif size == "orig":
version = "" version = ""
else: else:
raise ValueError("invalid size parameter for photo") abort(404, "invalid size parameter for photo")
if not photo_filename: if not photo_filename:
return False return False
path = os.path.join(PHOTO_DIR, photo_filename) + version + IMAGE_EXT path = os.path.join(PHOTO_DIR, photo_filename) + version + IMAGE_EXT

View File

@ -49,7 +49,8 @@
<span class="formation_module_ue">(<a title="UE de rattachement">{{mod.ue.acronyme}}</a>)</span>, <span class="formation_module_ue">(<a title="UE de rattachement">{{mod.ue.acronyme}}</a>)</span>,
{% endif %} {% endif %}
parcours <b>{{ mod.get_parcours()|map(attribute="code")|join("</b>, <b>")|default('tronc commun', true)|safe - parcours <b>{{ mod.get_parcours()|map(attribute="code")|join("</b>, <b>")|default('tronc commun',
true)|safe
}}</b> }}</b>
{% if mod.heures_cours or mod.heures_td or mod.heures_tp %} {% if mod.heures_cours or mod.heures_td or mod.heures_tp %}
({{mod.heures_cours|default("&nbsp;",true)|safe}}/{{mod.heures_td|default("&nbsp;",true)|safe}}/{{mod.heures_tp|default("&nbsp;",true)|safe}}, ({{mod.heures_cours|default("&nbsp;",true)|safe}}/{{mod.heures_td|default("&nbsp;",true)|safe}}/{{mod.heures_tp|default("&nbsp;",true)|safe}},

View File

@ -704,10 +704,15 @@ def formation_list(format=None, formation_id=None, args={}):
@scodoc @scodoc
@permission_required(Permission.ScoView) @permission_required(Permission.ScoView)
@scodoc7func @scodoc7func
def formation_export(formation_id, export_ids=False, format=None): def formation_export(
formation_id, export_ids=False, format=None, export_codes_apo=True
):
"Export de la formation au format indiqué (xml ou json)" "Export de la formation au format indiqué (xml ou json)"
return sco_formations.formation_export( return sco_formations.formation_export(
formation_id, export_ids=export_ids, format=format formation_id,
export_ids=export_ids,
format=format,
export_codes_apo=export_codes_apo,
) )

View File

@ -216,7 +216,7 @@ def edit_modules_ue_coefs():
</h2> </h2>
""", """,
render_template( render_template(
"pn/form_modules_ue_coefs.html", "pn/form_modules_ue_coefs.j2",
formation=formation, formation=formation,
data_source=url_for( data_source=url_for(
"notes.table_modules_ue_coefs", "notes.table_modules_ue_coefs",

View File

@ -1,7 +1,7 @@
# -*- mode: python -*- # -*- mode: python -*-
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
SCOVERSION = "9.4.31" SCOVERSION = "9.4.32"
SCONAME = "ScoDoc" SCONAME = "ScoDoc"