diff --git a/docbow_project/docbow/ods.py b/docbow_project/docbow/ods.py
new file mode 100644
index 0000000..5bb7383
--- /dev/null
+++ b/docbow_project/docbow/ods.py
@@ -0,0 +1,123 @@
+# -*- coding: utf-8 -*-
+#
+# w.c.s. - web application for online forms
+# Copyright (C) 2005-2013 Entr'ouvert
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see .
+
+import zipfile
+
+try:
+ import elementtree.ElementTree as ET
+except ImportError:
+ try:
+ import xml.etree.ElementTree as ET
+ except ImportError:
+ ET = None
+
+
+OFFICE_NS = 'urn:oasis:names:tc:opendocument:xmlns:office:1.0'
+TABLE_NS = 'urn:oasis:names:tc:opendocument:xmlns:table:1.0'
+TEXT_NS = 'urn:oasis:names:tc:opendocument:xmlns:text:1.0'
+XLINK_NS = 'http://www.w3.org/1999/xlink'
+
+
+class Workbook(object):
+ def __init__(self, encoding='utf-8'):
+ self.sheets = []
+ self.encoding = encoding
+
+ def add_sheet(self, name):
+ sheet = WorkSheet(self, name)
+ self.sheets.append(sheet)
+ return sheet
+
+ def get_node(self):
+ root = ET.Element('{%s}document-content' % OFFICE_NS)
+ ET.SubElement(root, '{%s}scripts' % OFFICE_NS)
+ ET.SubElement(root, '{%s}font-face-decls' % OFFICE_NS)
+ body = ET.SubElement(root, '{%s}body' % OFFICE_NS)
+ spreadsheet = ET.SubElement(body, '{%s}spreadsheet' % OFFICE_NS)
+ for sheet in self.sheets:
+ spreadsheet.append(sheet.get_node())
+ return root
+
+ def get_data(self):
+ return ET.tostring(self.get_node(), 'utf-8')
+
+ def save(self, output):
+ z = zipfile.ZipFile(output, 'w')
+ z.writestr('content.xml', self.get_data())
+ z.writestr('mimetype', 'application/vnd.oasis.opendocument.spreadsheet')
+ z.writestr('META-INF/manifest.xml', '''
+
+
+
+
+
+
+''')
+ z.writestr('styles.xml', '''
+
+''')
+ z.close()
+
+
+class WorkSheet(object):
+ def __init__(self, workbook, name):
+ self.cells = {}
+ self.name = name
+ self.workbook = workbook
+
+ def write(self, row, column, value, hint=None):
+ if not row in self.cells:
+ self.cells[row] = {}
+ self.cells[row][column] = WorkCell(self, value, hint=hint)
+
+ def get_node(self):
+ root = ET.Element('{%s}table' % TABLE_NS)
+ root.attrib['{%s}name' % TABLE_NS] = self.name
+ ET.SubElement(root, '{%s}table-column' % TABLE_NS)
+ for i in range(0, max(self.cells.keys())+1):
+ row = ET.SubElement(root, '{%s}table-row' % TABLE_NS)
+ for j in range(0, max(self.cells.get(i).keys())+1):
+ cell = self.cells.get(i, {}).get(j, None)
+ if not cell:
+ ET.SubElement(row, '{%s}table-cell' % TABLE_NS)
+ else:
+ row.append(cell.get_node())
+ return root
+
+
+class WorkCell(object):
+ def __init__(self, worksheet, value, hint=None):
+ if type(value) is not unicode:
+ value = unicode(value, 'utf-8')
+ self.value = value
+ self.worksheet = worksheet
+ self.hint = hint
+
+ def get_node(self):
+ root = ET.Element('{%s}table-cell' % TABLE_NS)
+ root.attrib['{%s}value-type' % OFFICE_NS] = 'string'
+ p = ET.SubElement(root, '{%s}p' % TEXT_NS)
+ if self.hint == 'uri':
+ base_filename = self.value.split('/')[-1]
+ if base_filename:
+ a = ET.SubElement(p, '{%s}a' % TEXT_NS)
+ a.attrib['{%s}href' % XLINK_NS] = self.value
+ a.text = base_filename
+ return root
+ p.text = self.value
+ return root
diff --git a/docbow_project/docbow/templates/docbow/inbox_table.html b/docbow_project/docbow/templates/docbow/inbox_table.html
index d1b1cad..4f367c3 100644
--- a/docbow_project/docbow/templates/docbow/inbox_table.html
+++ b/docbow_project/docbow/templates/docbow/inbox_table.html
@@ -2,3 +2,4 @@
{% load url from future %}
{% block csv.url %}{% url 'inbox-csv' %}{% endblock %}
+{% block ods.url %}{% url 'inbox-ods' %}{% endblock %}
diff --git a/docbow_project/docbow/templates/docbow/mailbox_table.html b/docbow_project/docbow/templates/docbow/mailbox_table.html
index 523ae5c..0700b02 100644
--- a/docbow_project/docbow/templates/docbow/mailbox_table.html
+++ b/docbow_project/docbow/templates/docbow/mailbox_table.html
@@ -27,5 +27,6 @@
{% if total != count %}{{ count }} de {{ total }}{% else %}{{ total }}{% endif %} {% if total == 1 %}document{% else %}documents{% endif %}
/ Export CSV
+ / Export ODS
{% endblock %}
diff --git a/docbow_project/docbow/templates/docbow/outbox_table.html b/docbow_project/docbow/templates/docbow/outbox_table.html
index e456394..2468782 100644
--- a/docbow_project/docbow/templates/docbow/outbox_table.html
+++ b/docbow_project/docbow/templates/docbow/outbox_table.html
@@ -4,3 +4,4 @@
{% block replies %}{% endblock %}
{% block csv.url %}{% url 'outbox-csv' %}{% endblock %}
+{% block ods.url %}{% url 'outbox-ods' %}{% endblock %}
diff --git a/docbow_project/docbow/urls.py b/docbow_project/docbow/urls.py
index d8cdca6..7a4f29f 100644
--- a/docbow_project/docbow/urls.py
+++ b/docbow_project/docbow/urls.py
@@ -16,6 +16,7 @@ urlpatterns = patterns('docbow_project.docbow.views',
url(r'^inbox/(?P\d+)/(?P\d+)/.*$',
'message_attached_file', name='inbox-message-attached-file'),
url(r'^inbox/csv$', 'inbox_csv', name='inbox-csv'),
+ url(r'^inbox/ods$', 'inbox_ods', name='inbox-ods'),
# outbox
@@ -29,6 +30,7 @@ urlpatterns = patterns('docbow_project.docbow.views',
url(r'^outbox_by_document/(?P\d+)/$', 'outbox_by_document',
name='outbox-by-document-message'),
url(r'^outbox/csv$', 'outbox_csv', name='outbox-csv'),
+ url(r'^outbox/ods$', 'outbox_ods', name='outbox-ods'),
url(r'^send_file/$', 'send_file_selector', name='send-file-selector'),
diff --git a/docbow_project/docbow/views.py b/docbow_project/docbow/views.py
index 6b5f317..f1f0880 100644
--- a/docbow_project/docbow/views.py
+++ b/docbow_project/docbow/views.py
@@ -1,5 +1,5 @@
import smtplib
-from itertools import count
+from itertools import count, chain
import socket
import os.path
import collections
@@ -541,6 +541,24 @@ class CSVMultipleObjectMixin(object):
return response
+class ODSMultipleObjectMixin(CSVMultipleObjectMixin):
+ worksheet_name = '1'
+
+ def get(self, request, *args, **kwargs):
+ from . import ods
+ import cStringIO as StringIO
+ response = HttpResponse(mimetype='application/vnd.oasis.opendocument.spreadsheet')
+ response['Content-Disposition'] = 'attachment; filename="%s"' % self.filename
+ workbook = ods.Workbook(encoding='utf-8')
+ sheet = workbook.add_sheet(self.worksheet_name.encode('utf-8'))
+ rows = chain(((0, self.get_header()),), enumerate(self.get_rows(), 1))
+ for i, row in rows:
+ for j, cell in enumerate(row):
+ sheet.write(i, j, unicode(cell).encode('utf-8'))
+ workbook.save(response)
+ return response
+
+
class CSVMailboxView(CSVMultipleObjectMixin, ExtraContextMixin,
MailboxQuerysetMixin, MultipleObjectMixin,
tables_views.SingleTableMixin, View):
@@ -569,6 +587,14 @@ class CSVMailboxView(CSVMultipleObjectMixin, ExtraContextMixin,
yield self.get_row(table_row)
+class ODSMailboxView(ODSMultipleObjectMixin, CSVMailboxView):
+ @property
+ def filename(self):
+ return '{prefix}-{user}-{date}.ods'.format(
+ prefix=self.filename_prefix,
+ user=self.request.user,
+ date=datetime.date.today())
+
class CSVInboxView(CSVMailboxView):
outbox = False
@@ -578,13 +604,30 @@ class CSVInboxView(CSVMailboxView):
inbox_csv = CSVInboxView.as_view()
+
class CSVOutboxView(CSVMailboxView):
outbox = True
table_class = tables.OutboxCsvTable
filename_prefix = 'outbox'
+
outbox_csv = CSVOutboxView.as_view()
+
+class ODSInboxView(ODSMailboxView, CSVInboxView):
+ pass
+
+
+inbox_ods = ODSInboxView.as_view()
+
+
+class ODSOutboxView(ODSMailboxView, CSVOutboxView):
+ pass
+
+
+outbox_ods = ODSOutboxView.as_view()
+
+
class InboxView(DateFilterMixinView, MailboxView):
outbox = False
table_class = tables.InboxTable