Corrige anciennes formations incohérentes (indices de semestres). Plus de logs.

This commit is contained in:
Emmanuel Viennet 2022-09-08 01:20:04 +02:00
parent d2590c1f91
commit 57a62a10f4
6 changed files with 60 additions and 14 deletions

View File

@ -133,12 +133,15 @@ class Formation(db.Model):
def sanitize_old_formation(self) -> None: def sanitize_old_formation(self) -> None:
""" """
Corrige si nécessaire certains champs issus d'anciennes versions de ScoDoc: Corrige si nécessaire certains champs issus d'anciennes versions de ScoDoc:
Pour les formations APC (BUT) seulement:
- affecte à chaque module de cette formation le semestre de son UE de rattachement, - affecte à chaque module de cette formation le semestre de son UE de rattachement,
si elle en a une. si elle en a une.
- si le module_type n'est pas renseigné, le met à STANDARD. - si le module_type n'est pas renseigné, le met à STANDARD.
- on n'utilise pas de matières: réaffecte tous les modules
à la première matière de leur UE.
Devrait être appelé lorsqu'on change le type de formation vers le BUT, et aussi Devrait être appelé lorsqu'on change le type de formation vers le BUT,
lorsqu'on change le semestre d'une UE BUT. et aussi lorsqu'on change le semestre d'une UE BUT.
Utile pour la migration des anciennes formations vers le BUT. Utile pour la migration des anciennes formations vers le BUT.
En cas de changement, invalide les caches coefs/poids. En cas de changement, invalide les caches coefs/poids.
@ -164,6 +167,7 @@ class Formation(db.Model):
# --- Numéros de modules # --- Numéros de modules
if Module.query.filter_by(formation_id=self.id, numero=None).count() > 0: if Module.query.filter_by(formation_id=self.id, numero=None).count() > 0:
scu.objects_renumber(db, self.modules.all()) scu.objects_renumber(db, self.modules.all())
# --- Types d'UE (avant de rendre le type non nullable) # --- Types d'UE (avant de rendre le type non nullable)
ues_sans_type = UniteEns.query.filter_by(formation_id=self.id, type=None) ues_sans_type = UniteEns.query.filter_by(formation_id=self.id, type=None)
if ues_sans_type.count() > 0: if ues_sans_type.count() > 0:
@ -171,6 +175,19 @@ class Formation(db.Model):
ue.type = 0 ue.type = 0
db.session.add(ue) db.session.add(ue)
# --- Réaffectation des matières:
for ue in self.ues:
mat = ue.matieres.first()
if mat is None:
mat = Matiere()
ue.matieres.append(mat)
db.session.add(mat)
for module in ue.modules:
if module.matiere_id != mat.id:
module.matiere = mat
db.session.add(module)
change = True
db.session.commit() db.session.commit()
if change: if change:
app.clear_scodoc_cache() app.clear_scodoc_cache()

View File

@ -66,7 +66,7 @@ class Module(db.Model):
super(Module, self).__init__(**kwargs) super(Module, self).__init__(**kwargs)
def __repr__(self): def __repr__(self):
return f"<Module{ModuleType(self.module_type or ModuleType.STANDARD).name} id={self.id} code={self.code!r}>" return f"<Module{ModuleType(self.module_type or ModuleType.STANDARD).name} id={self.id} code={self.code!r} semestre_id={self.semestre_id}>"
def to_dict(self, convert_objects=False, with_matiere=False, with_ue=False) -> dict: def to_dict(self, convert_objects=False, with_matiere=False, with_ue=False) -> dict:
"""If convert_objects, convert all attributes to native types """If convert_objects, convert all attributes to native types

View File

@ -98,12 +98,18 @@ def module_list(*args, **kw):
def do_module_create(args) -> int: def do_module_create(args) -> int:
"Create a module. Returns id of new object." "Create a module. Returns id of new object."
formation = Formation.query.get(args["formation_id"])
# refuse de créer un module APC avec semestres incohérents:
if formation.is_apc():
ue = UniteEns.query.get(args["ue_id"])
if int(args.get("semestre_id", 0)) != ue.semestre_idx:
raise ValueError("Formation incompatible: contacter le support ScoDoc")
# create # create
cnx = ndb.GetDBConnexion() cnx = ndb.GetDBConnexion()
r = _moduleEditor.create(cnx, args) module_id = _moduleEditor.create(cnx, args)
log(f"do_module_create: created {module_id} with {args}")
# news # news
formation = Formation.query.get(args["formation_id"])
ScolarNews.add( ScolarNews.add(
typ=ScolarNews.NEWS_FORM, typ=ScolarNews.NEWS_FORM,
obj=formation.id, obj=formation.id,
@ -111,7 +117,7 @@ def do_module_create(args) -> int:
max_frequency=10 * 60, max_frequency=10 * 60,
) )
formation.invalidate_cached_sems() formation.invalidate_cached_sems()
return r return module_id
def module_create( def module_create(

View File

@ -129,6 +129,7 @@ def do_ue_create(args):
args["ue_code"] = code args["ue_code"] = code
# create # create
ue_id = _ueEditor.create(cnx, args) ue_id = _ueEditor.create(cnx, args)
log(f"do_ue_create: created {ue_id} with {args}")
formation: Formation = Formation.query.get(args["formation_id"]) formation: Formation = Formation.query.get(args["formation_id"])
formation.invalidate_module_coefs() formation.invalidate_module_coefs()

View File

@ -951,8 +951,18 @@ def _formsemestre_check_module_list(module_ids, semestre_idx):
Module.query.get_or_404(module_id).ue.semestre_idx for module_id in module_ids Module.query.get_or_404(module_id).ue.semestre_idx for module_id in module_ids
} }
if mod_sems_idx and mod_sems_idx != {semestre_idx}: if mod_sems_idx and mod_sems_idx != {semestre_idx}:
modules = [Module.query.get_or_404(module_id) for module_id in module_ids]
log(
f"""_formsemestre_check_module_list:
{chr(10).join( str(module) + " " + str(module.ue) for module in modules )}
"""
)
for module in modules:
log(
f"{module.code}\tsemestre_id={module.semestre_id}\tue.semestre_idx={module.ue.semestre_idx}"
)
raise ScoValueError( raise ScoValueError(
"Les modules sélectionnés ne sont pas tous dans le semestre choisi !", f"Les modules sélectionnés ne sont pas tous dans le semestre choisi (S{semestre_idx}) !",
dest_url="javascript:history.back();", dest_url="javascript:history.back();",
) )
@ -1316,7 +1326,7 @@ def do_formsemestres_associate_new_version(formsemestre_ids):
si elles existent (codes d'UE validées). si elles existent (codes d'UE validées).
Les semestre doivent tous appartenir à la meme version de la formation Les semestre doivent tous appartenir à la meme version de la formation
""" """
log("do_formsemestres_associate_new_version %s" % formsemestre_ids) log(f"do_formsemestres_associate_new_version {formsemestre_ids}")
if not formsemestre_ids: if not formsemestre_ids:
return return
# Check: tous de la même formation # Check: tous de la même formation
@ -1336,7 +1346,19 @@ def do_formsemestres_associate_new_version(formsemestre_ids):
modules_old2new, modules_old2new,
ues_old2new, ues_old2new,
) = sco_formations.formation_create_new_version(formation_id, redirect=False) ) = sco_formations.formation_create_new_version(formation_id, redirect=False)
# Log new ues:
for ue_id in ues_old2new:
ue = UniteEns.query.get(ue_id)
new_ue = UniteEns.query.get(ues_old2new[ue_id])
assert ue.semestre_idx == new_ue.semestre_idx
log(f"{ue} -> {new_ue}")
# Log new modules
for module_id in modules_old2new:
mod = Module.query.get(module_id)
new_mod = Module.query.get(modules_old2new[module_id])
assert mod.semestre_id == new_mod.semestre_id
log(f"{mod} -> {new_mod}")
# re-associate
for formsemestre_id in formsemestre_ids: for formsemestre_id in formsemestre_ids:
sem = sco_formsemestre.get_formsemestre(formsemestre_id) sem = sco_formsemestre.get_formsemestre(formsemestre_id)
sem["formation_id"] = formation_id sem["formation_id"] = formation_id

View File

@ -1143,7 +1143,7 @@ def formsemestre_tableau_modules(
H = [] H = []
prev_ue_id = None prev_ue_id = None
for modimpl in modimpls: for modimpl in modimpls:
mod = Module.query.get(modimpl["module_id"]) mod: Module = Module.query.get(modimpl["module_id"])
mod_descr = "Module " + (mod.titre or "") mod_descr = "Module " + (mod.titre or "")
if mod.is_apc(): if mod.is_apc():
coef_descr = ", ".join( coef_descr = ", ".join(
@ -1204,9 +1204,9 @@ def formsemestre_tableau_modules(
and etat["nb_evals_en_cours"] == 0 and etat["nb_evals_en_cours"] == 0
and etat["nb_evals_vides"] == 0 and etat["nb_evals_vides"] == 0
): ):
H.append('<tr class="formsemestre_status_green%s">' % fontorange) H.append(f'<tr class="formsemestre_status_green{fontorange}">')
else: else:
H.append('<tr class="formsemestre_status%s">' % fontorange) H.append(f'<tr class="formsemestre_status{fontorange}">')
H.append( H.append(
f"""<td class="formsemestre_status_code""><a f"""<td class="formsemestre_status_code""><a
@ -1234,14 +1234,14 @@ def formsemestre_tableau_modules(
for coef in coefs: for coef in coefs:
if coef[1] > 0: if coef[1] > 0:
H.append( H.append(
f"""<span class="mod_coef_indicator" f"""<span class="mod_coef_indicator"
title="{coef[0].acronyme}" title="{coef[0].acronyme}"
style="background: { style="background: {
coef[0].color if coef[0].color is not None else 'blue' coef[0].color if coef[0].color is not None else 'blue'
}"></span>""" }"></span>"""
) )
else: else:
H.append(f"""<span class="mod_coef_indicator_zero"></span>""") H.append("""<span class="mod_coef_indicator_zero"></span>""")
H.append("</a>") H.append("</a>")
H.append("</td>") H.append("</td>")
if mod.module_type in ( if mod.module_type in (