From 8e932a8e0b7a3a1f087673d4bbee6a22584abe76 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Fri, 27 Sep 2024 22:37:54 +0200 Subject: [PATCH] =?UTF-8?q?Import=20XML=20formations:=20filtre=20caract?= =?UTF-8?q?=C3=A8res=20de=20contr=C3=B4les=20erron=C3=A9s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/scodoc/sco_formations.py | 12 ++++++++---- app/scodoc/sco_utils.py | 5 +++-- app/scodoc/sco_xml.py | 12 +++++++++++- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/app/scodoc/sco_formations.py b/app/scodoc/sco_formations.py index b05a1b2f9..645606eae 100644 --- a/app/scodoc/sco_formations.py +++ b/app/scodoc/sco_formations.py @@ -222,6 +222,8 @@ def formation_export( """Get a formation, with UE, matieres, modules in desired format """ + if fmt not in ("xml", "json"): + raise ScoValueError("Format invalide") formation = Formation.get_formation(formation_id) f_dict = formation_export_dict( formation, @@ -296,7 +298,7 @@ def _formation_retreive_apc_niveau( return niveau.id if niveau is not None else None -def formation_import_xml(doc: str, import_tags=True, use_local_refcomp=False): +def formation_import_xml(doc: str | bytes, import_tags=True, use_local_refcomp=False): """Create a formation from XML representation (format dumped by formation_export( fmt='xml' )) XML may contain object (UE, modules) ids: this function returns two @@ -311,11 +313,13 @@ def formation_import_xml(doc: str, import_tags=True, use_local_refcomp=False): """ from app.scodoc import sco_edit_formation + if isinstance(doc, bytes): + doc = doc.decode(scu.SCO_ENCODING) try: - dom = xml.dom.minidom.parseString(doc) + dom = xml.dom.minidom.parseString(sco_xml.remove_control_characters(doc)) except Exception as exc: - log("formation_import_xml: invalid XML data") - raise ScoValueError("Fichier XML invalide") from exc + log(f"formation_import_xml: invalid XML data:\n{exc}") + raise ScoValueError(f"Fichier XML invalide {exc}") from exc try: f = dom.getElementsByTagName("formation")[0] # or dom.documentElement diff --git a/app/scodoc/sco_utils.py b/app/scodoc/sco_utils.py index 6b0e8fbc4..e9cbb4149 100644 --- a/app/scodoc/sco_utils.py +++ b/app/scodoc/sco_utils.py @@ -1117,8 +1117,9 @@ def sendXML( attached=False, quote=False, filename=None, -): - if type(data) != list: +) -> Response: + "Réponse XML: data est une liste d'objets" + if not isinstance(data, list): data = [data] # always list-of-dicts if force_outer_xml_tag: data = [{tagname: data}] diff --git a/app/scodoc/sco_xml.py b/app/scodoc/sco_xml.py index 852951560..910629a4f 100644 --- a/app/scodoc/sco_xml.py +++ b/app/scodoc/sco_xml.py @@ -39,6 +39,16 @@ from app.scodoc.sco_vdi import ApoEtapeVDI XML_HEADER = """""" +def remove_control_characters(s: str) -> str: + """supprime tous les caractères de contrôle (code < 32) + sauf les tabs (9), les retours chariot (10 et les sauts de ligne (13). + """ + if not hasattr(remove_control_characters, "control_chars"): + control_chars = dict.fromkeys(i for i in range(32) if i not in (9, 10, 13)) + remove_control_characters.control_chars = control_chars + return s.translate(remove_control_characters.control_chars) + + def quote_xml_attr(data): """Escape &, <, >, quotes and double quotes""" return xml.sax.saxutils.escape(str(data), {"'": "'", '"': """}) @@ -93,7 +103,7 @@ def _dictlist2xml(dictlist, root=None, tagname=None, quote=False): for d in dictlist: elem = ElementTree.Element(tagname) root.append(elem) - if isinstance(d, scalar_types) or isinstance(d, ApoEtapeVDI): + if isinstance(d, (scalar_types, ApoEtapeVDI)): elem.set("code", _repr_as_xml(d)) else: if quote: