From 4ee90fab6376ff7b032686ca818b88800c5a5ebb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= <fpeters@entrouvert.com>
Date: Sat, 8 Feb 2020 10:31:14 +0100
Subject: [PATCH 3/4] misc: add open document representation of fields (#36627)

---
 wcs/fields.py | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 95 insertions(+), 1 deletion(-)

diff --git a/wcs/fields.py b/wcs/fields.py
index 52a43aa82..c2f62d74e 100644
--- a/wcs/fields.py
+++ b/wcs/fields.py
@@ -38,7 +38,8 @@ from django.utils.six.moves.html_parser import HTMLParser
 from .qommon import _, N_, force_str
 from .qommon import evalutils
 from .qommon.form import *
-from .qommon.misc import localstrftime, strftime, date_format, ellipsize, xml_node_text
+from .qommon.misc import localstrftime, strftime, date_format, ellipsize, can_thumbnail, xml_node_text
+from .qommon.ods import NS as OD_NS, clean_text as od_clean_text
 from .qommon.template import Template, TemplateError
 from .qommon import get_cfg, get_logger
 
@@ -177,6 +178,7 @@ class Field(object):
     prefill = None
     store_display_value = None
     store_structured_value = None
+    get_opendocument_node_value = None
     condition = None
 
     # flag a field for removal by AnonymiseWorkflowStatusItem
@@ -792,6 +794,15 @@ class StringField(WidgetField):
             return htmltext(force_str(urlize(value, nofollow=True, autoescape=True)))
         return str(value)
 
+    def get_opendocument_node_value(self, value, formdata=None, **kwargs):
+        if value.startswith('http://') or value.startswith('https://'):
+            node = ET.Element('{%s}a' % OD_NS['text'])
+            node.attrib['{%s}href' % OD_NS['xlink']] = value
+        else:
+            node = ET.Element('{%s}span' % OD_NS['text'])
+        node.text = od_clean_text(force_text(value))
+        return node
+
     def get_rst_view_value(self, value, indent=''):
         return indent + str(value or '')
 
@@ -863,6 +874,25 @@ class TextField(WidgetField):
             except:
                 return ''
 
+    def get_opendocument_node_value(self, value, formdata=None, **kwargs):
+        if self.pre:
+            p = ET.Element('{%s}p' % OD_NS['text'])
+            line_break = '<nsa:line-break xmlns:nsa="%(ns)s"/>' % {'ns': OD_NS['text']}
+            as_node = ET.fromstring(str(htmlescape(value)).replace('\n', line_break))
+            p.text = as_node.text
+            p.tail = as_node.tail
+            for child in as_node.getchildren():
+                p.append(child)
+            return p
+        else:
+            paragraphs = []
+            for paragraph in value.splitlines():
+                if paragraph.strip():
+                    p = ET.Element('{%s}p' % OD_NS['text'])
+                    p.text = paragraph
+                    paragraphs.append(p)
+            return paragraphs
+
     def get_view_short_value(self, value, max_len = 30):
         return ellipsize(str(value), max_len)
 
@@ -884,6 +914,12 @@ class EmailField(WidgetField):
     def get_rst_view_value(self, value, indent=''):
         return indent + value
 
+    def get_opendocument_node_value(self, value, formdata=None, **kwargs):
+        a = ET.Element('{%s}a' % OD_NS['text'])
+        a.text = od_clean_text(value)
+        a.attrib['{%s}href' % OD_NS['xlink']] = 'mailto:' + a.text
+        return a
+
 register_field_class(EmailField)
 
 
@@ -913,6 +949,11 @@ class BoolField(WidgetField):
         else:
             return ''
 
+    def get_opendocument_node_value(self, value, formdata=None, **kwargs):
+        span = ET.Element('{%s}span' % OD_NS['text'])
+        span.text = od_clean_text(self.get_view_value(value))
+        return span
+
     def convert_value_from_str(self, value):
         if value is None:
             return None
@@ -1087,6 +1128,19 @@ class FileField(WidgetField):
         t += htmltext('</div>')
         return t.getvalue()
 
+    def get_opendocument_node_value(self, value, formdata=None, **kwargs):
+        show_link = True
+        if value.has_redirect_url():
+            is_in_backoffice = bool(get_request() and get_request().is_in_backoffice())
+            show_link = bool(value.get_redirect_url(backoffice=is_in_backoffice))
+        if show_link and formdata:
+            node = ET.Element('{%s}a' % OD_NS['text'])
+            node.attrib['{%s}href' % OD_NS['xlink']] = '%sdownload?f=%s' % (formdata.get_url(), self.id)
+        else:
+            node = ET.Element('{%s}span' % OD_NS['text'])
+        node.text = od_clean_text(force_text(value))
+        return node
+
     def get_csv_value(self, value, **kwargs):
         return [str(value) if value else '']
 
@@ -1262,6 +1316,11 @@ class DateField(WidgetField):
         except TypeError:
             return value
 
+    def get_opendocument_node_value(self, value, formdata=None, **kwargs):
+        span = ET.Element('{%s}span' % OD_NS['text'])
+        span.text = od_clean_text(self.get_view_value(value))
+        return span
+
     def get_json_value(self, value):
         try:
             return strftime('%Y-%m-%d', value)
@@ -1441,6 +1500,11 @@ class ItemField(WidgetField):
             return value
         return htmltext('<a href="%s">' % carddata.get_url(backoffice=True)) + htmltext('%s</a>') % value
 
+    def get_opendocument_node_value(self, value, formdata=None, **kwargs):
+        span = ET.Element('{%s}span' % OD_NS['text'])
+        span.text = od_clean_text(force_text(value))
+        return span
+
     def add_to_view_form(self, form, value = None):
         real_value = value
         label_value = ''
@@ -1667,6 +1731,11 @@ class ItemsField(WidgetField):
                 pass
         return ''
 
+    def get_opendocument_node_value(self, value, formdata=None, **kwargs):
+        span = ET.Element('{%s}span' % OD_NS['text'])
+        span.text = od_clean_text(self.get_view_value(value))
+        return span
+
     def stats(self, values):
         return item_items_stats(self, values)
 
@@ -2039,6 +2108,31 @@ class TableField(WidgetField):
                     values.append('')
         return values
 
+    def get_opendocument_node_value(self, value, formdata=None, **kwargs):
+        table = ET.Element('{%s}table' % OD_NS['table'])
+        ET.SubElement(table, '{%s}table-column' % OD_NS['table'])
+        for col in self.columns:
+            ET.SubElement(table, '{%s}table-column' % OD_NS['table'])
+        row = ET.SubElement(table, '{%s}table-row' % OD_NS['table'])
+        ET.SubElement(row, '{%s}table-cell' % OD_NS['table'])
+        for col in self.columns:
+            table_cell = ET.SubElement(row, '{%s}table-cell' % OD_NS['table'])
+            cell_value = ET.SubElement(table_cell, '{%s}p' % OD_NS['text'])
+            cell_value.text = col
+        for i, row_label in enumerate(self.rows):
+            row = ET.SubElement(table, '{%s}table-row' % OD_NS['table'])
+            table_cell = ET.SubElement(row, '{%s}table-cell' % OD_NS['table'])
+            cell_value = ET.SubElement(table_cell, '{%s}p' % OD_NS['text'])
+            cell_value.text = row_label
+            for j, col in enumerate(self.columns):
+                table_cell = ET.SubElement(row, '{%s}table-cell' % OD_NS['table'])
+                cell_value = ET.SubElement(table_cell, '{%s}p' % OD_NS['text'])
+                try:
+                    cell_value.text = value[i][j]
+                except IndexError:
+                    pass
+        return table
+
 register_field_class(TableField)
 
 
-- 
2.25.1

