workflows: make it possible to replace odt images with variables (#16259)
This uses the "name" attribute of an image (in LibreOffice, double click on the picture and go to the options tab to set it). It must be set to a Python expression, prefixed with = (e.g. =form_var_image_raw). The expression should return a wcs-file-like object (must have a get_content() method). The replacement image mime type should be the same as the original one.
This commit is contained in:
parent
330e1788a7
commit
6ec13787dd
Binary file not shown.
|
@ -5,10 +5,12 @@ import StringIO
|
|||
import time
|
||||
import urllib2
|
||||
import urlparse
|
||||
import zipfile
|
||||
|
||||
import mock
|
||||
|
||||
from quixote import cleanup, get_response
|
||||
from quixote.http_request import Upload as QuixoteUpload
|
||||
from wcs.qommon.http_request import HTTPRequest
|
||||
from qommon.form import *
|
||||
|
||||
|
@ -34,7 +36,7 @@ from wcs.wf.register_comment import RegisterCommenterWorkflowStatusItem
|
|||
from wcs.wf.remove import RemoveWorkflowStatusItem
|
||||
from wcs.wf.roles import AddRoleWorkflowStatusItem, RemoveRoleWorkflowStatusItem
|
||||
from wcs.wf.wscall import WebserviceCallStatusItem
|
||||
from wcs.wf.export_to_model import transform_to_pdf
|
||||
from wcs.wf.export_to_model import ExportToModel, transform_to_pdf
|
||||
from wcs.wf.geolocate import GeolocateWorkflowStatusItem
|
||||
from wcs.wf.backoffice_fields import SetBackofficeFieldsWorkflowStatusItem
|
||||
from wcs.wf.redirect_to_url import RedirectToUrlWorkflowStatusItem
|
||||
|
@ -1892,6 +1894,42 @@ def test_transform_to_pdf():
|
|||
assert outstream is not False
|
||||
assert outstream.read(10).startswith('%PDF-')
|
||||
|
||||
def test_export_to_model_image(pub):
|
||||
formdef = FormDef()
|
||||
formdef.name = 'baz'
|
||||
formdef.fields = [
|
||||
FileField(id='3', label='File', type='file', varname='image'),
|
||||
]
|
||||
formdef.store()
|
||||
|
||||
upload = PicklableUpload('test.jpeg', 'image/jpeg')
|
||||
image_data = open(os.path.join(os.path.dirname(__file__), 'image-with-gps-data.jpeg')).read()
|
||||
upload.receive([image_data])
|
||||
|
||||
formdata = formdef.data_class()()
|
||||
formdata.data = {'3': upload}
|
||||
formdata.just_created()
|
||||
formdata.store()
|
||||
pub.substitutions.feed(formdata)
|
||||
|
||||
item = ExportToModel()
|
||||
item.method = 'non-interactive'
|
||||
template_filename = os.path.join(os.path.dirname(__file__), 'template-with-image.odt')
|
||||
template = open(template_filename).read()
|
||||
upload = QuixoteUpload('/foo/template.odt', content_type='application/octet-stream')
|
||||
upload.fp = StringIO.StringIO()
|
||||
upload.fp.write(template)
|
||||
upload.fp.seek(0)
|
||||
item.model_file = UploadedFile(pub.app_dir, None, upload)
|
||||
item.attach_to_history = True
|
||||
|
||||
item.perform(formdata)
|
||||
|
||||
zfile = zipfile.ZipFile(formdata.evolution[-1].parts[0].filename, mode='r')
|
||||
zinfo = zfile.getinfo('Pictures/10000000000000320000003276E9D46581B55C88.jpg')
|
||||
# check the image has been replaced by the one from the formdata
|
||||
assert zinfo.file_size == len(image_data)
|
||||
|
||||
def test_global_timeouts(pub):
|
||||
FormDef.wipe()
|
||||
Workflow.wipe()
|
||||
|
|
|
@ -45,9 +45,15 @@ from wcs.portfolio import has_portfolio, push_document
|
|||
|
||||
OO_TEXT_NS = 'urn:oasis:names:tc:opendocument:xmlns:text:1.0'
|
||||
OO_OFFICE_NS = 'urn:oasis:names:tc:opendocument:xmlns:office:1.0'
|
||||
OO_DRAW_NS = 'urn:oasis:names:tc:opendocument:xmlns:drawing:1.0'
|
||||
XLINK_NS = 'http://www.w3.org/1999/xlink'
|
||||
USER_FIELD_DECL = '{%s}user-field-decl' % OO_TEXT_NS
|
||||
USER_FIELD_GET = '{%s}user-field-get' % OO_TEXT_NS
|
||||
STRING_VALUE = '{%s}string-value' % OO_OFFICE_NS
|
||||
DRAW_FRAME = '{%s}frame' % OO_DRAW_NS
|
||||
DRAW_NAME = '{%s}name' % OO_DRAW_NS
|
||||
DRAW_IMAGE = '{%s}image' % OO_DRAW_NS
|
||||
XLINK_HREF = '{%s}href' % XLINK_NS
|
||||
NAME = '{%s}name' % OO_TEXT_NS
|
||||
|
||||
try:
|
||||
|
@ -82,13 +88,26 @@ def transform_opendocument(instream, outstream, process):
|
|||
'''
|
||||
zin = zipfile.ZipFile(instream, mode='r')
|
||||
zout = zipfile.ZipFile(outstream, mode='w')
|
||||
new_images = {}
|
||||
assert 'content.xml' in zin.namelist()
|
||||
for filename in zin.namelist():
|
||||
# first pass to process meta.xml and content.xml
|
||||
if filename not in ('meta.xml', 'content.xml'):
|
||||
continue
|
||||
content = zin.read(filename)
|
||||
root = ET.fromstring(content)
|
||||
process(root, new_images)
|
||||
content = ET.tostring(root)
|
||||
zout.writestr(filename, content)
|
||||
|
||||
for filename in zin.namelist():
|
||||
# second pass to copy/replace other files
|
||||
if filename in ('meta.xml', 'content.xml'):
|
||||
root = ET.fromstring(content)
|
||||
process(root)
|
||||
content = ET.tostring(root)
|
||||
continue
|
||||
if filename in new_images:
|
||||
content = new_images[filename].get_content()
|
||||
else:
|
||||
content = zin.read(filename)
|
||||
zout.writestr(filename, content)
|
||||
zout.close()
|
||||
|
||||
|
@ -385,7 +404,9 @@ class ExportToModel(WorkflowStatusItem):
|
|||
'template: %s') % str(e))
|
||||
|
||||
def apply_od_template_to_formdata(self, formdata):
|
||||
def process_root(root):
|
||||
context_variables = get_publisher().substitutions.get_context_variables()
|
||||
|
||||
def process_root(root, new_images):
|
||||
# cache for keeping computed user-field-decl value around
|
||||
user_field_values = {}
|
||||
|
||||
|
@ -405,6 +426,18 @@ class ExportToModel(WorkflowStatusItem):
|
|||
node.attrib[NAME] in user_field_values):
|
||||
node.text = user_field_values[node.attrib[NAME]]
|
||||
|
||||
if node.tag == DRAW_FRAME:
|
||||
name = node.attrib.get(DRAW_NAME)
|
||||
if not name.startswith('='):
|
||||
continue
|
||||
# variable image
|
||||
try:
|
||||
variable_image = self.compute(name)
|
||||
except:
|
||||
continue
|
||||
image = [x for x in node.getchildren() if x.tag == DRAW_IMAGE][0]
|
||||
new_images[image.attrib.get(XLINK_HREF)] = variable_image
|
||||
|
||||
for attr in ('text', 'tail'):
|
||||
if not getattr(node, attr):
|
||||
continue
|
||||
|
|
Loading…
Reference in New Issue