changeset 3472:e12e9e1535d3

tools (xml_tools): new `dataForm2dataDict` and `dataDict2dataForm`: those methods convert a serialisable dict format to `wokkel.data_form.Form` and vice versa
author Goffi <goffi@goffi.org>
date Sat, 27 Feb 2021 18:36:38 +0100
parents d897597cfa94
children cc065c13052c
files sat/plugins/plugin_misc_lists.py sat/tools/xml_tools.py
diffstat 2 files changed, 94 insertions(+), 33 deletions(-) [+]
line wrap: on
line diff
--- a/sat/plugins/plugin_misc_lists.py	Sat Feb 27 18:33:53 2021 +0100
+++ b/sat/plugins/plugin_misc_lists.py	Sat Feb 27 18:36:38 2021 +0100
@@ -20,10 +20,10 @@
 from twisted.internet import defer
 from twisted.words.xish import domish
 from twisted.words.protocols.jabber import jid
-from wokkel import data_form
 from sat.core.i18n import _, D_
 from sat.core.xmpp import SatXMPPEntity
 from sat.core.constants import Const as C
+from sat.tools import xml_tools
 from sat.tools.common import uri
 from sat.tools.common import data_format
 from sat.core.log import getLogger
@@ -455,38 +455,13 @@
         name = name.strip()
         if not name:
             name = shortuuid.uuid()
-        template = TEMPLATES[template_id]
-
-        fields = [
-            data_form.Field(fieldType="hidden", var=NS_TICKETS_TYPE, value=template_id)
-        ]
-        for field_data in template['fields']:
-            field_type = field_data.get('type', 'text-single')
-            kwargs = {
-                "fieldType": field_type,
-                "var": field_data["name"],
-                "label": field_data.get('label'),
-                "value": field_data.get("value"),
-            }
-            if field_type == "xhtml":
-                kwargs.update({
-                    "fieldType": None,
-                    "ext_type": "xml",
-                })
-                if kwargs["value"] is None:
-                    kwargs["value"] = domish.Element((C.NS_XHTML, "div"))
-            elif "options" in field_data:
-                kwargs["options"] = [
-                    data_form.Option(o["value"], o.get("label"))
-                    for o in field_data["options"]
-                ]
-            field = data_form.Field(**kwargs)
-            fields.append(field)
-
-        schema = data_form.Form(
-            "form",
-            formNamespace=APP_NS_TICKETS,
-            fields=fields
+        fields = TEMPLATES[template_id]["fields"].copy()
+        fields.insert(
+            0,
+            {"type": "hidden", "name": NS_TICKETS_TYPE, "value": template_id}
+        )
+        schema = xml_tools.dataDict2dataForm(
+            {"namespace": APP_NS_TICKETS, "fields": fields}
         ).toElement()
 
         service = client.jid.userhostJID()
--- a/sat/tools/xml_tools.py	Sat Feb 27 18:33:53 2021 +0100
+++ b/sat/tools/xml_tools.py	Sat Feb 27 18:36:38 2021 +0100
@@ -194,6 +194,92 @@
     return dataForm2Widgets(form_ui, form, read_only=read_only)
 
 
+def dataForm2dataDict(form: data_form.Form) -> dict:
+    """Convert data form to a simple dict, easily serialisable
+
+    see dataDict2dataForm for a description of the format
+    """
+    fields = []
+    data_dict = {
+        "fields": fields
+    }
+    if form.formNamespace:
+        data_dict["namespace"] = form.formNamespace
+    for form_field in form.fieldList:
+        field = {"type": form_field.fieldType}
+        fields.append(field)
+        for src_name, dest_name in (
+            ('var', 'name'),
+            ('label', 'label'),
+            ('value', 'value'),
+        ):
+            value = getattr(form_field, src_name, None)
+            if value:
+                field[dest_name] = value
+        if form_field.options:
+            options = field["options"] = []
+            for form_opt in form_field.options:
+                opt = {"value": form_opt.value}
+                if form_opt.label:
+                    opt["label"] = form_opt.label
+                options.append(opt)
+
+        if form_field.fieldType is None and form_field.ext_type == "xml":
+            if isinstance(form_field.value, domish.Element):
+                if ((form_field.value.uri == C.NS_XHTML
+                     and form_field.value.name == "div")):
+                    field["type"] = "xhtml"
+                    if form_field.value.children:
+                        log.warning(
+                            "children are not managed for XHTML fields: "
+                            f"{form_field.value.toXml()}"
+                        )
+    return data_dict
+
+
+def dataDict2dataForm(data_dict):
+    """Convert serialisable dict of data to a data form
+
+    The format of the dict is as follow:
+        - an optional "namespace" key with form namespace
+        - a mandatory "fields" key with list of fields as follow:
+            - "type" is mostly the same as data_form.Field.fieldType
+            - "var", "label", and "value" follow same attribude in data_form.Field
+            - "xhtml" is used for "xml" fields with child in the C.NS_XHTML namespace
+            - "options" are list of dict with optional "label" and mandatory "value"
+              following suitable attributes from data_form.Option
+    """
+    # TODO: describe format
+    fields = []
+    for field_data in data_dict["fields"]:
+        field_type = field_data.get('type', 'text-single')
+        kwargs = {
+            "fieldType": field_type,
+            "var": field_data["name"],
+            "label": field_data.get('label'),
+            "value": field_data.get("value"),
+        }
+        if field_type == "xhtml":
+            kwargs.update({
+                "fieldType": None,
+                "ext_type": "xml",
+            })
+            if kwargs["value"] is None:
+                kwargs["value"] = domish.Element((C.NS_XHTML, "div"))
+        elif "options" in field_data:
+            kwargs["options"] = [
+                data_form.Option(o["value"], o.get("label"))
+                for o in field_data["options"]
+            ]
+        field = data_form.Field(**kwargs)
+        fields.append(field)
+    return data_form.Form(
+        "form",
+        formNamespace=data_dict.get("namespace"),
+        fields=fields
+    )
+
+
 def dataFormEltResult2XMLUIData(form_xml):
     """Parse a data form result (not parsed by Wokkel's XEP-0004 implementation).