summaryrefslogtreecommitdiff
path: root/ishtar_common
diff options
context:
space:
mode:
Diffstat (limited to 'ishtar_common')
-rw-r--r--ishtar_common/libreoffice.py30
-rw-r--r--ishtar_common/models.py20
-rw-r--r--ishtar_common/utils.py8
-rw-r--r--ishtar_common/views.py19
4 files changed, 65 insertions, 12 deletions
diff --git a/ishtar_common/libreoffice.py b/ishtar_common/libreoffice.py
index 3869ca81a..573d99361 100644
--- a/ishtar_common/libreoffice.py
+++ b/ishtar_common/libreoffice.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import time
@@ -8,15 +8,37 @@ from com.sun.star.beans import PropertyValue
from com.sun.star.connection import NoConnectException
from com.sun.star.sheet.ValidationType import LIST
+# nosec: filename used is generated and sanitized
+import subprocess # nosec
+
#from com.sun.star.table import CellRangeAddress, CellAddress
-from ishtar_common.utils import num2col
+from ishtar_common.utils import num2col, sanitize_filepath
from django.conf import settings
RETRY = 5
+def get_connection():
+ return "socket,host={},port={};urp".format(
+ settings.LIBREOFFICE_HOST, settings.LIBREOFFICE_PORT
+ )
+
+
+def convert_document(document, destination_format):
+ if not document.lower().endswith(".ods") and not document.lower().endswith(".odt"):
+ return document
+ document = sanitize_filepath(document)
+ connection = get_connection() + ";StarOffice.ComponentContext"
+ args = [settings.UNOCONV_BINARY, "--connection", connection, "-f", destination_format,
+ document]
+ # nosec: filename is generated and sanitized
+ popen = subprocess.Popen(args) # nosec
+ popen.wait(timeout=20)
+ dest_document = document[:-4] + "." + destination_format
+ return dest_document
+
class UnoClient:
def __init__(self):
@@ -30,9 +52,7 @@ class UnoClient:
resolver = local_context.ServiceManager.createInstanceWithContext(
"com.sun.star.bridge.UnoUrlResolver", local_context)
- connection = "socket,host={},port={};urp".format(
- settings.LIBREOFFICE_HOST, settings.LIBREOFFICE_PORT
- )
+ connection = get_connection()
try:
self.service_manager = resolver.resolve(
"uno:{};StarOffice.ServiceManager".format(connection))
diff --git a/ishtar_common/models.py b/ishtar_common/models.py
index 73f140625..c7fe7be8a 100644
--- a/ishtar_common/models.py
+++ b/ishtar_common/models.py
@@ -2057,11 +2057,23 @@ class Dashboard(object):
return v
-EXPORT_FORMATS = []
+EXPORT_FORMATS = [("", "---")]
+EXPORT_FORMATS_CONTENT_TYPE = {
+ "xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
+ "docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
+ "pdf": "application/pdf",
+ "html": "text/html",
+ "odt": "application/vnd.oasis.opendocument.text",
+ "ods": "application/vnd.oasis.opendocument.spreadsheet",
+}
if settings.USE_LIBREOFFICE:
- EXPORT_FORMATS.append(("xlsx", _("XLSX")))
- EXPORT_FORMATS.append(("pdf", _("PDF")))
+ EXPORT_FORMATS = [
+ ("docx", _("DOCX")),
+ ("html", _("HTML")),
+ ("pdf", _("PDF")),
+ ("xlsx", _("XLSX")),
+ ]
EXPORT_FORMATS_DICT = dict(EXPORT_FORMATS)
@@ -2124,7 +2136,7 @@ class DocumentTemplate(models.Model):
def clean(self):
if self.for_labels and not self.label_per_page:
raise ValidationError(
- _("For label template, you must provide " "number of label per page.")
+ _("For label template, you must provide number of label per page.")
)
def generate_label_template(self):
diff --git a/ishtar_common/utils.py b/ishtar_common/utils.py
index bca7ce181..d4453ff5a 100644
--- a/ishtar_common/utils.py
+++ b/ishtar_common/utils.py
@@ -1446,6 +1446,14 @@ def clean_session_cache(session):
cache.set(cache_key_list, [], settings.CACHE_TIMEOUT)
+def sanitize_filepath(filepath):
+ #TODO: python3-pathvalidate
+ # from pathvalidate import sanitize_filepath
+ # filepath -> sanitize_filepath(filepath)
+ keep_characters = (" ", ".", "_", "-", "/")
+ return "".join(c for c in filepath if c.isalnum() or c in keep_characters).rstrip()
+
+
def get_field_labels_from_path(model, path):
"""
:param model: base model
diff --git a/ishtar_common/views.py b/ishtar_common/views.py
index 5b675eb52..a6c3b373d 100644
--- a/ishtar_common/views.py
+++ b/ishtar_common/views.py
@@ -91,6 +91,10 @@ from ishtar_common.utils import (
from ishtar_common.widgets import JQueryAutoComplete
from ishtar_common import tasks
+convert_document = None
+if settings.USE_LIBREOFFICE:
+ from ishtar_common.libreoffice import convert_document
+
from .views_item import (
CURRENT_ITEM_KEYS,
CURRENT_ITEM_KEYS_DICT,
@@ -1535,10 +1539,19 @@ class GenerateView(IshtarMixin, LoginRequiredMixin, View):
document = self.publish(tpl, objects)
if not document:
return HttpResponse(content_type="text/plain")
+ base_extension = tpl.template.name.split(".")[-1].lower()
+ extension = tpl.export_format
+ if not extension:
+ extension = base_extension
+ if not settings.USE_LIBREOFFICE and extension not in ("ods", "odt"):
+ return HttpResponseBadRequest("Invalid format type - need LibreOffice daemon") # bad configuration
+ content_type = models.EXPORT_FORMATS_CONTENT_TYPE.get(
+ extension, "application/vnd.oasis.opendocument.text"
+ )
+ if tpl.export_format and convert_document:
+ document = convert_document(document, tpl.export_format)
with open(document, "rb") as f:
- response = HttpResponse(
- f.read(), content_type="application/vnd.oasis.opendocument.text"
- )
+ response = HttpResponse(f.read(), content_type=content_type)
response["Content-Disposition"] = "attachment; filename={}".format(
document.split(os.sep)[-1]
)