From cdc19695200d7f0ab618461b00f29765d2bf8a68 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Sat, 10 Jul 2021 16:01:37 +0200 Subject: [PATCH] bulletins XML sans jaxml --- app/scodoc/sco_bulletins.py | 19 +- app/scodoc/sco_bulletins_xml.py | 311 ++++++++++++++++---------------- 2 files changed, 168 insertions(+), 162 deletions(-) diff --git a/app/scodoc/sco_bulletins.py b/app/scodoc/sco_bulletins.py index 693b4e52..6ac8e2ec 100644 --- a/app/scodoc/sco_bulletins.py +++ b/app/scodoc/sco_bulletins.py @@ -895,17 +895,16 @@ def do_formsemestre_bulletinetud( et filigranne est un message à placer en "filigranne" (eg "Provisoire"). """ if format == "xml": - bul = repr( - sco_bulletins_xml.make_xml_formsemestre_bulletinetud( - context, - formsemestre_id, - etudid, - REQUEST=REQUEST, - xml_with_decisions=xml_with_decisions, - force_publishing=force_publishing, - version=version, - ) + bul = sco_bulletins_xml.make_xml_formsemestre_bulletinetud( + context, + formsemestre_id, + etudid, + REQUEST=REQUEST, + xml_with_decisions=xml_with_decisions, + force_publishing=force_publishing, + version=version, ) + return bul, "" elif format == "json": diff --git a/app/scodoc/sco_bulletins_xml.py b/app/scodoc/sco_bulletins_xml.py index dc568b92..52c98e33 100644 --- a/app/scodoc/sco_bulletins_xml.py +++ b/app/scodoc/sco_bulletins_xml.py @@ -29,16 +29,20 @@ Note: la structure de ce XML est issue de (mauvais) choix historiques -et ne peut pas être modifiée car d'autres logiciels l'utilisent (portail publication bulletins etudiants). +et ne peut pas être modifiée car d'autres logiciels l'utilisent (portail publication +bulletins etudiants). Je recommande d'utiliser la version JSON. -Malheureusement, le code de génération JSON et XML sont séparés, ce qui est absurde et complique la maintenance (si on ajoute des informations aux bulletins). +Malheureusement, le code de génération JSON et XML sont séparés, ce qui est absurde et +complique la maintenance (si on ajoute des informations aux bulletins). -Je propose de considérer le XMl comme "deprecated" et de ne plus le modifier, sauf nécessité. """ +# revu en juillet 21 pour utiliser ElementTree au lieu de jaxml + import datetime -import jaxml +from xml.etree import ElementTree +from xml.etree.ElementTree import Element import app.scodoc.sco_utils as scu import app.scodoc.notesdb as ndb @@ -53,6 +57,7 @@ from app.scodoc import sco_groups from app.scodoc import sco_photos from app.scodoc import sco_preferences from app.scodoc import sco_etud +from app.scodoc import sco_xml # -------- Bulletin en XML # (fonction séparée: n'utilise pas formsemestre_bulletinetud_dict() @@ -75,14 +80,12 @@ def make_xml_formsemestre_bulletinetud( log("xml_bulletin( formsemestre_id=%s, etudid=%s )" % (formsemestre_id, etudid)) if REQUEST: REQUEST.RESPONSE.setHeader("content-type", scu.XML_MIMETYPE) - if not doc: - doc = jaxml.XML_document(encoding=scu.SCO_ENCODING) sem = sco_formsemestre.get_formsemestre(context, formsemestre_id) if sem["bul_hide_xml"] == "0" or force_publishing: - published = 1 + published = "1" else: - published = 0 + published = "0" if xml_nodate: docdate = "" else: @@ -95,30 +98,34 @@ def make_xml_formsemestre_bulletinetud( "publie": published, } if sem["etapes"]: - el["etape_apo"] = sem["etapes"][0] or "" + el["etape_apo"] = str(sem["etapes"][0]) or "" n = 2 for et in sem["etapes"][1:]: - el["etape_apo" + str(n)] = et or "" + el["etape_apo" + str(n)] = str(et) or "" n += 1 - doc.bulletinetud(**el) - + x = Element("bulletinetud", **el) + if doc: + doc.append(x) + else: + doc = x # Infos sur l'etudiant etudinfo = sco_etud.get_etud_info(etudid=etudid, filled=1)[0] - doc._push() - doc.etudiant( - etudid=etudid, - code_nip=etudinfo["code_nip"], - code_ine=etudinfo["code_ine"], - nom=scu.quote_xml_attr(etudinfo["nom"]), - prenom=scu.quote_xml_attr(etudinfo["prenom"]), - civilite=scu.quote_xml_attr(etudinfo["civilite_str"]), - sexe=scu.quote_xml_attr(etudinfo["civilite_str"]), # compat - photo_url=scu.quote_xml_attr(sco_photos.etud_photo_url(context, etudinfo)), - email=scu.quote_xml_attr(etudinfo["email"]), - emailperso=scu.quote_xml_attr(etudinfo["emailperso"]), + doc.append( + Element( + "etudiant", + etudid=etudid, + code_nip=etudinfo["code_nip"], + code_ine=etudinfo["code_ine"], + nom=scu.quote_xml_attr(etudinfo["nom"]), + prenom=scu.quote_xml_attr(etudinfo["prenom"]), + civilite=scu.quote_xml_attr(etudinfo["civilite_str"]), + sexe=scu.quote_xml_attr(etudinfo["civilite_str"]), # compat + photo_url=scu.quote_xml_attr(sco_photos.etud_photo_url(context, etudinfo)), + email=scu.quote_xml_attr(etudinfo["email"]), + emailperso=scu.quote_xml_attr(etudinfo["emailperso"]), + ) ) - doc._pop() # Disponible pour publication ? if not published: @@ -158,68 +165,61 @@ def make_xml_formsemestre_bulletinetud( context, etudid, formsemestre_id, partitions, partitions_etud_groups, nt ) - doc._push() - doc.note( - value=mg, - min=scu.fmt_note(nt.moy_min), - max=scu.fmt_note(nt.moy_max), - moy=scu.fmt_note(nt.moy_moy), + doc.append( + Element( + "note", + value=mg, + min=scu.fmt_note(nt.moy_min), + max=scu.fmt_note(nt.moy_max), + moy=scu.fmt_note(nt.moy_moy), + ) ) - doc._pop() - doc._push() - doc.rang(value=rang, ninscrits=nbetuds) - doc._pop() + doc.append(Element("rang", value=str(rang), ninscrits=str(nbetuds))) + if rang_gr: for partition in partitions: - doc._push() - doc.rang_group( - group_type=partition["partition_name"], - group_name=gr_name[partition["partition_id"]], - value=rang_gr[partition["partition_id"]], - ninscrits=ninscrits_gr[partition["partition_id"]], + doc.append( + Element( + "rang_group", + group_type=partition["partition_name"], + group_name=gr_name[partition["partition_id"]], + value=str(rang_gr[partition["partition_id"]]), + ninscrits=str(ninscrits_gr[partition["partition_id"]]), + ) ) - doc._pop() - doc._push() - doc.note_max(value=20) # notes toujours sur 20 - doc._pop() - doc._push() - doc.bonus_sport_culture(value=nt.bonus[etudid]) - doc._pop() + doc.append(Element("note_max", value="20")) # notes toujours sur 20 + doc.append(Element("bonus_sport_culture", value=str(nt.bonus[etudid]))) # Liste les UE / modules /evals for ue in ues: ue_status = nt.get_etud_ue_status(etudid, ue["ue_id"]) - doc._push() - doc.ue( + x_ue = Element( + "ue", id=ue["ue_id"], numero=scu.quote_xml_attr(ue["numero"]), acronyme=scu.quote_xml_attr(ue["acronyme"]), titre=scu.quote_xml_attr(ue["titre"]), code_apogee=scu.quote_xml_attr(ue["code_apogee"]), ) - doc._push() + doc.append(x_ue) if ue["type"] != sco_codes_parcours.UE_SPORT: v = ue_status["cur_moy_ue"] else: v = nt.bonus[etudid] - doc.note( - value=scu.fmt_note(v), - min=scu.fmt_note(ue["min"]), - max=scu.fmt_note(ue["max"]), + x_ue.append( + Element( + "note", + value=scu.fmt_note(v), + min=scu.fmt_note(ue["min"]), + max=scu.fmt_note(ue["max"]), + ) ) - doc._pop() try: ects_txt = str(int(ue["ects"])) - except: + except (ValueError, TypeError): ects_txt = "" - doc._push() - doc.ects(value=ects_txt) - doc._pop() - doc._push() - doc.rang(value=str(nt.ue_rangs[ue["ue_id"]][0][etudid])) - doc._pop() - doc._push() - doc.effectif(value=str(nt.ue_rangs[ue["ue_id"]][1])) - doc._pop() + x_ue.append(Element("ects", value=ects_txt)) + x_ue.append(Element("rang", value=str(nt.ue_rangs[ue["ue_id"]][0][etudid]))) + x_ue.append(Element("effectif", value=str(nt.ue_rangs[ue["ue_id"]][1]))) # Liste les modules de l'UE ue_modimpls = [mod for mod in modimpls if mod["module"]["ue_id"] == ue["ue_id"]] for modimpl in ue_modimpls: @@ -229,46 +229,53 @@ def make_xml_formsemestre_bulletinetud( if mod_moy == "NI": # ne mentionne pas les modules ou n'est pas inscrit continue mod = modimpl["module"] - doc._push() # if mod['ects'] is None: # ects = '' # else: # ects = str(mod['ects']) - doc.module( + x_mod = Element( + "module", id=modimpl["moduleimpl_id"], code=mod["code"], - coefficient=mod["coefficient"], - numero=mod["numero"], + coefficient=str(mod["coefficient"]), + numero=str(mod["numero"]), titre=scu.quote_xml_attr(mod["titre"]), abbrev=scu.quote_xml_attr(mod["abbrev"]), code_apogee=scu.quote_xml_attr(mod["code_apogee"]) # ects=ects ects des modules maintenant inutilisés ) - doc._push() + x_ue.append(x_mod) modstat = nt.get_mod_stats(modimpl["moduleimpl_id"]) - doc.note( - value=mod_moy, - min=scu.fmt_note(modstat["min"]), - max=scu.fmt_note(modstat["max"]), - moy=scu.fmt_note(modstat["moy"]), + x_mod.append( + Element( + "note", + value=mod_moy, + min=scu.fmt_note(modstat["min"]), + max=scu.fmt_note(modstat["max"]), + moy=scu.fmt_note(modstat["moy"]), + ) ) - doc._pop() if sco_preferences.get_preference( context, "bul_show_mod_rangs", formsemestre_id ): - doc._push() - doc.rang(value=nt.mod_rangs[modimpl["moduleimpl_id"]][0][etudid]) - doc._pop() - doc._push() - doc.effectif(value=nt.mod_rangs[modimpl["moduleimpl_id"]][1]) - doc._pop() + x_mod.append( + Element( + "rang", + value=str(nt.mod_rangs[modimpl["moduleimpl_id"]][0][etudid]), + ) + ) + x_mod.append( + Element( + "effectif", value=str(nt.mod_rangs[modimpl["moduleimpl_id"]][1]) + ) + ) # --- notes de chaque eval: evals = nt.get_evals_in_mod(modimpl["moduleimpl_id"]) if version != "short": for e in evals: if int(e["visibulletin"]) == 1 or version == "long": - doc._push() - doc.evaluation( + x_eval = Element( + "evaluation", jour=ndb.DateDMYtoISO(e["jour"], null_is_empty=True), heure_debut=ndb.TimetoISO8601( e["heure_debut"], null_is_empty=True @@ -276,19 +283,18 @@ def make_xml_formsemestre_bulletinetud( heure_fin=ndb.TimetoISO8601( e["heure_fin"], null_is_empty=True ), - coefficient=e["coefficient"], - evaluation_type=e["evaluation_type"], + coefficient=str(e["coefficient"]), + evaluation_type=str(e["evaluation_type"]), description=scu.quote_xml_attr(e["description"]), - note_max_origin=e[ - "note_max" - ], # notes envoyées sur 20, ceci juste pour garder trace + # notes envoyées sur 20, ceci juste pour garder trace: + note_max_origin=str(e["note_max"]), ) + x_mod.append(x_eval) val = e["notes"].get(etudid, {"value": "NP"})[ "value" ] # NA si etud demissionnaire val = scu.fmt_note(val, note_max=e["note_max"]) - doc.note(value=val) - doc._pop() + x_eval.append(Element("note", value=val)) # Evaluations incomplètes ou futures: complete_eval_ids = set([e["evaluation_id"] for e in evals]) if sco_preferences.get_preference( @@ -300,8 +306,8 @@ def make_xml_formsemestre_bulletinetud( all_evals.reverse() # plus ancienne d'abord for e in all_evals: if e["evaluation_id"] not in complete_eval_ids: - doc._push() - doc.evaluation( + x_eval = Element( + "evaluation", jour=ndb.DateDMYtoISO(e["jour"], null_is_empty=True), heure_debut=ndb.TimetoISO8601( e["heure_debut"], null_is_empty=True @@ -309,50 +315,45 @@ def make_xml_formsemestre_bulletinetud( heure_fin=ndb.TimetoISO8601( e["heure_fin"], null_is_empty=True ), - coefficient=e["coefficient"], + coefficient=str(e["coefficient"]), description=scu.quote_xml_attr(e["description"]), incomplete="1", - note_max_origin=e[ - "note_max" - ], # notes envoyées sur 20, ceci juste pour garder trace + # notes envoyées sur 20, ceci juste pour garder trace: + note_max_origin=e["note_max"], ) - doc._pop() - doc._pop() - doc._pop() + x_mod.append(x_eval) # UE capitalisee (listee seulement si meilleure que l'UE courante) if ue_status["is_capitalized"]: try: ects_txt = str(int(ue_status["ue"].get("ects", ""))) - except: + except (ValueError, TypeError): ects_txt = "" - doc._push() - doc.ue_capitalisee( + x_ue = Element( + "ue_capitalisee", id=ue["ue_id"], numero=scu.quote_xml_attr(ue["numero"]), acronyme=scu.quote_xml_attr(ue["acronyme"]), titre=scu.quote_xml_attr(ue["titre"]), ) - doc._push() - doc.note(value=scu.fmt_note(ue_status["moy"])) - doc._pop() - doc._push() - doc.ects(value=ects_txt) - doc._pop() - doc._push() - doc.coefficient_ue(value=scu.fmt_note(ue_status["coef_ue"])) - doc._pop() - doc._push() - doc.date_capitalisation(value=ndb.DateDMYtoISO(ue_status["event_date"])) - doc._pop() - doc._pop() + doc.append(x_ue) + x_ue.append(Element("note", value=scu.fmt_note(ue_status["moy"]))) + x_ue.append(Element("ects", value=ects_txt)) + x_ue.append( + Element("coefficient_ue", value=scu.fmt_note(ue_status["coef_ue"])) + ) + x_ue.append( + Element( + "date_capitalisation", + value=ndb.DateDMYtoISO(ue_status["event_date"]), + ) + ) + # --- Absences if sco_preferences.get_preference(context, "bul_show_abs", formsemestre_id): - AbsEtudSem = sco_abs.getAbsSemEtud(context, sem, etudid) - nbabs = AbsEtudSem.CountAbs() - nbabsjust = AbsEtudSem.CountAbsJust() - doc._push() - doc.absences(nbabs=nbabs, nbabsjust=nbabsjust) - doc._pop() + abs_sem_etud = sco_abs.getAbsSemEtud(context, sem, etudid) + nbabs = abs_sem_etud.CountAbs() + nbabsjust = abs_sem_etud.CountAbsJust() + doc.append(Element("absences", nbabs=nbabs, nbabsjust=nbabsjust)) # --- Decision Jury if ( sco_preferences.get_preference(context, "bul_show_decision", formsemestre_id) @@ -367,7 +368,9 @@ def make_xml_formsemestre_bulletinetud( context, "bul_show_uevalid", formsemestre_id ), ) - doc.situation(scu.quote_xml_attr(infos["situation"])) + x_situation = Element("situation") + x_situation.text = scu.quote_xml_attr(infos["situation"]) + doc.append(x_situation) if dpv: decision = dpv["decisions"][0] etat = decision["etat"] @@ -375,54 +378,58 @@ def make_xml_formsemestre_bulletinetud( code = decision["decision_sem"]["code"] else: code = "" - doc._push() - if ( decision["decision_sem"] and "compense_formsemestre_id" in decision["decision_sem"] ): - doc.decision( - code=code, - etat=etat, - compense_formsemestre_id=decision["decision_sem"][ - "compense_formsemestre_id" - ], + doc.append( + Element( + "decision", + code=code, + etat=str(etat), + compense_formsemestre_id=decision["decision_sem"][ + "compense_formsemestre_id" + ], + ) ) else: - doc.decision(code=code, etat=etat) - - doc._pop() + doc.append(Element("decision", code=code, etat=str(etat))) if decision[ "decisions_ue" ]: # and sco_preferences.get_preference(context, 'bul_show_uevalid', formsemestre_id): always publish (car utile pour export Apogee) for ue_id in decision["decisions_ue"].keys(): ue = sco_edit_ue.do_ue_list(context, {"ue_id": ue_id})[0] - doc._push() - doc.decision_ue( - ue_id=ue["ue_id"], - numero=scu.quote_xml_attr(ue["numero"]), - acronyme=scu.quote_xml_attr(ue["acronyme"]), - titre=scu.quote_xml_attr(ue["titre"]), - code=decision["decisions_ue"][ue_id]["code"], + doc.append( + Element( + "decision_ue", + ue_id=ue["ue_id"], + numero=scu.quote_xml_attr(ue["numero"]), + acronyme=scu.quote_xml_attr(ue["acronyme"]), + titre=scu.quote_xml_attr(ue["titre"]), + code=decision["decisions_ue"][ue_id]["code"], + ) ) - doc._pop() for aut in decision["autorisations"]: - doc._push() - doc.autorisation_inscription(semestre_id=aut["semestre_id"]) - doc._pop() + doc.append( + Element( + "autorisation_inscription", semestre_id=str(aut["semestre_id"]) + ) + ) else: - doc._push() - doc.decision(code="", etat="DEM") - doc._pop() + doc.append(Element("decision", code="", etat="DEM")) # --- Appreciations cnx = ndb.GetDBConnexion() apprecs = sco_etud.appreciations_list( cnx, args={"etudid": etudid, "formsemestre_id": formsemestre_id} ) for app in apprecs: - doc.appreciation( - scu.quote_xml_attr(app["comment"]), date=ndb.DateDMYtoISO(app["date"]) + doc.append( + Element( + "appreciation", + scu.quote_xml_attr(app["comment"]), + date=ndb.DateDMYtoISO(app["date"]), + ) ) - return doc + return sco_xml.XML_HEADER + ElementTree.tostring(doc)