def convert(self, orig, data, cache=None, filename=None, context=None, **kwargs): data = str(orig) doc = OOOdCommandTransform(context, filename, data, self.inputs[0]) builder = OOoBuilder(doc) content = builder.extract('content.xml') if cache is not None: cache.setData(content) return cache else: stream = OOoDocumentDataStream() stream.setData(content) return stream
def test_01_dynamic(self): """ Test applying stylesheet dynamically, using a Python Script with a stylesheet file name parameter. """ request = self.app.REQUEST addOOoTemplate = self.getPortal().manage_addProduct['ERP5OOo'].addOOoTemplate addOOoTemplate(id='Dynamic_viewAsOdt', title='') Dynamic_viewAsOdt = self.getPortal().Dynamic_viewAsOdt # The stylesheet file 'Test_getODTStyleSheet' is not exist in this site. # So, the 'Base_getODTStyleSheet', a python script creates dynamically # exsited stylesheet file name. self.assertFalse(self.getPortal().hasObject('Test_getODTStyleSheet')) self.assertTrue(self.getPortal().hasObject('Test_getODTStyleSheet_ja')) self.assertTrue(self.getPortal().hasObject('Test_getODTStyleSheet_en')) Dynamic_viewAsOdt.doSettings(request, title='', xml_file_id='content.xml', ooo_stylesheet='Test_getODTStyleSheet', script_name='Base_getODTStyleSheetByLanguage') Dynamic_viewAsOdt.pt_edit(self.content, content_type='application/vnd.oasis.opendocument.text') # 1. test a normal case, language: ja self.getPortal().Localizer.changeLanguage('ja') response = self.publish('/' + self.getPortal().Dynamic_viewAsOdt.absolute_url(1)) self.assertEqual('application/vnd.oasis.opendocument.text', response.getHeader('content-type').split(';')[0]) self.assertEqual('attachment; filename="Dynamic_viewAsOdt.odt"', response.getHeader('content-disposition')) self._validate(response.getBody()) self.assertEqual(200, response.getStatus()) ooo_builder = OOoBuilder(response.getBody()) styles_xml_body = ooo_builder.extract('styles.xml') self.assertTrue(len(styles_xml_body) > 0) # 'Style sheet ja' text is in the odt document header, # and the header is in the 'styles.xml'. self.assertTrue(styles_xml_body.find('Style sheet ja') > 0) # 2. test a normal case, change the language to 'en', # so that the stylesheet changes dynamically. self.getPortal().Localizer = DummyLocalizer() self.getPortal().Localizer.changeLanguage('en') response = self.publish('/' + self.getPortal().Dynamic_viewAsOdt.absolute_url(1)) self._validate(response.getBody()) ooo_builder = OOoBuilder(response.getBody()) styles_xml_body = ooo_builder.extract('styles.xml') self.assertTrue(styles_xml_body.find('Style sheet en') > 0) # 3. test a fail case, reset a not existed stylesheet Dynamic_viewAsOdt.doSettings(request, title='', xml_file_id='content.xml', ooo_stylesheet='NotFound_getODTStyleSheet', script_name='Base_getODTStyleSheet') self.assertFalse(self.getPortal().hasObject('NotFound_getODTStyleSheet')) self.assertFalse(self.getPortal().hasObject('NotFound_getODTStyleSheet_ja')) self.assertFalse(self.getPortal().hasObject('NotFound_getODTStyleSheet_en')) self.getPortal().Localizer.changeLanguage('en') response = self.publish('/' + self.getPortal().Dynamic_viewAsOdt.absolute_url(1)) # then, it is not a zip stream self.assertFalse(response.getBody().startswith('PK')) self.assertEqual(500, response.getStatus())
def test_02_static(self): """ Test applying stylesheet statically, using a stylesheet File object. """ request = self.app.REQUEST addOOoTemplate = self.getPortal().manage_addProduct['ERP5OOo'].addOOoTemplate addOOoTemplate(id='Static_viewAsOdt', title='') Static_viewAsOdt = self.getPortal().Static_viewAsOdt # Test_getODTStyleSheet_ja is statically exist. self.assertTrue(self.getPortal().hasObject('Test_getODTStyleSheet_ja')) Static_viewAsOdt.doSettings(request, title='', xml_file_id='content.xml', ooo_stylesheet='Test_getODTStyleSheet_ja', script_name='') Static_viewAsOdt.pt_edit(self.content, content_type='application/vnd.oasis.opendocument.text') # 1. test a normal case response = self.publish('/' + self.getPortal().Static_viewAsOdt.absolute_url(1)) self.assertEqual(200, response.getStatus()) self.assertEqual('application/vnd.oasis.opendocument.text', response.getHeader('content-type').split(';')[0]) self.assertEqual('attachment; filename="Static_viewAsOdt.odt"', response.getHeader('content-disposition')) self._validate(response.getBody()) ooo_builder = OOoBuilder(response.getBody()) styles_xml_body = ooo_builder.extract('styles.xml') self.assertTrue(len(styles_xml_body) > 0) self.assertTrue(styles_xml_body.find('Style sheet ja') > 0) # 2. test a normal case, change the style sheet self.assertTrue(self.getPortal().hasObject('Test_getODTStyleSheet_en')) Static_viewAsOdt.doSettings(request, title='', xml_file_id='content.xml', ooo_stylesheet='Test_getODTStyleSheet_en', script_name='') response = self.publish('/' + self.getPortal().Static_viewAsOdt.absolute_url(1)) self.assertEqual(200, response.getStatus()) self._validate(response.getBody()) ooo_builder = OOoBuilder(response.getBody()) styles_xml_body = ooo_builder.extract('styles.xml') self.assertTrue(len(styles_xml_body) > 0) self.assertTrue(styles_xml_body.find('Style sheet en') > 0) # 3. test a fail case self.assertFalse(self.getPortal().hasObject('NotFound_getODTStyleSheet')) Static_viewAsOdt.doSettings(request, title='', xml_file_id='content.xml', ooo_stylesheet='NotFound_getODTStyleSheet', script_name='') response = self.publish('/' + self.getPortal().Static_viewAsOdt.absolute_url(1)) self.assertFalse(response.getBody().startswith('PK')) self.assertEqual(500, response.getStatus())
def render(self, extra_context={}): """Render a odf document, form as a content, template as a template. Keyword arguments: extra_context -- a dictionary, expected: 'here' : where it call 'printout_template' : the template object, tipically a OOoTemplate 'container' : the object which has a form printout object 'form' : the form as a content """ here = extra_context['here'] if here is None: raise ValueError('Can not create a ODF Document without a parent acquisition context') form = extra_context['form'] if not extra_context.has_key('printout_template') or \ extra_context['printout_template'] is None: raise ValueError('Can not create a ODF Document without a printout template') odf_template = extra_context['printout_template'] # First, render the Template if it has a pt_render method ooo_document = None if hasattr(odf_template, 'pt_render'): ooo_document = odf_template.pt_render(here, extra_context=extra_context) else: # File object can be a template ooo_document = odf_template # Create a new builder instance ooo_builder = OOoBuilder(ooo_document) self.odf_existent_name_list = ooo_builder.getNameList() # content.xml self._replaceContentXml(ooo_builder, extra_context) # styles.xml self._replaceStylesXml(ooo_builder, extra_context) # meta.xml is not supported yet # ooo_builder = self._replaceMetaXml(ooo_builder=ooo_builder, extra_context=extra_context) # Update the META information ooo_builder.updateManifest() ooo = ooo_builder.render() return ooo
def includeImageList(self, data): """Include Images in ODF archive - data: zipped archive content """ builder = OOoBuilder(data) content = builder.extract('content.xml') xml_doc = etree.XML(content) image_tag_list = xml_doc.xpath('//*[name() = "draw:image"]') SVG_NAMESPACE = 'urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0' XLINK_NAMESPACE = 'http://www.w3.org/1999/xlink' ratio_px_cm = 2.54 / 100. # Flag to enable modification of OOoBuilder odt_content_modified = False for image_tag in image_tag_list: frame = image_tag.getparent() #Try to get image file from ZODB href_attribute_list = image_tag.xpath( './/@*[name() = "xlink:href"]') url = href_attribute_list[0] parse_result = urlparse(unquote(url)) # urlparse return a 6-tuple: scheme, netloc, path, params, query, fragment netloc = parse_result[1] path = parse_result[2] if path and netloc in ('', None): # it makes sense to include only relative to current site images not remote ones which can be taken by OOo # OOo corrupt relative Links inside HTML content during odt conversion # <img src="REF.TO.IMAGE" ... /> become <draw:image xlink:href="../REF.TO.IMAGE" ... /> # So remove "../" added by OOo path = CLEAN_RELATIVE_PATH.sub('', path) # in some cases like Web Page content "/../" can be contained in image URL which will break # restrictedTraverse calls, our best guess is to remove it path = path.replace('/../', '') # remove occurencies of '//' or '///' in path (happens with web pages) and leave # a traversable relative URL path = '/'.join( [x for x in path.split('/') if x.strip() != '']) # retrieve http parameters and use them to convert image query_parameter_string = parse_result[4] image_parameter_dict = dict(parse_qsl(query_parameter_string)) try: image = self.context.restrictedTraverse(path) except (AttributeError, KeyError): #Image not found, this image is probably not hosted by ZODB. Do nothing image = None if image is not None: odt_content_modified = True content_type = image.getContentType() format = image_parameter_dict.pop('format', None) # convert API accepts only a certail range of arguments for key, value in ensure_list( image_parameter_dict.items()): if key not in ( 'format', 'display', 'quality', 'resolution', ): image_parameter_dict.pop(key) if getattr(image, 'convert', None) is not None: # The document support conversion so perform conversion # according given parameters mime, image_data = image.convert( format, **image_parameter_dict) # wrapp converted data into OFSImage in order to compute metadatas # on converted result image = OFSImage(image.getId(), image.getTitle(), image_data) # image should be OFSImage data = str(image.data) width = image.width height = image.height if height: frame.attrib.update({ '{%s}height' % SVG_NAMESPACE: '%.3fcm' % (height * ratio_px_cm) }) if width: frame.attrib.update({ '{%s}width' % SVG_NAMESPACE: '%.3fcm' % (width * ratio_px_cm) }) if not format: mimetype_list = self.context.getPortalObject( ).mimetypes_registry.lookup(content_type) # guess a format with help of mimetypes_registry for mimetype_object in mimetype_list: if mimetype_object.extensions: format = mimetype_object.extensions[0] break elif mimetype_object.globs: format = mimetype_object.globs[0].strip('*.') break new_path = builder.addImage(data, format=format) image_tag.attrib.update( {'{%s}href' % XLINK_NAMESPACE: new_path}) if odt_content_modified: builder.replace( 'content.xml', etree.tostring(xml_doc, encoding='utf-8', xml_declaration=True, pretty_print=False)) return builder.render()
def test_04_ProxyField(self): """ Check it's possible to use an odg document to map proxyfields """ portal = self.getPortal() foo_module = self.portal.foo_module if foo_module._getOb('test1', None) is None: foo_module.newContent(id='test1', portal_type='Foo') test1 = foo_module.test1 test1.setTitle('Foo title!') self.tic() style_dict = { '{urn:oasis:names:tc:opendocument:xmlns:text:1.0}span': { '{urn:oasis:names:tc:opendocument:xmlns:text:1.0}style-name': 'T2' }, '{urn:oasis:names:tc:opendocument:xmlns:text:1.0}p': {} } # test target foo_printout = portal.foo_module.test1.Foo_viewProxyFieldAsODGPrintout original_file_content = self.getODFDocumentFromPrintout(foo_printout) self._validate(original_file_content) # extract content.xml from original odg document original_doc_builder = OOoBuilder(original_file_content) original_content_xml = original_doc_builder.extract("content.xml") # get style of the title in the orignal test document original_document_style_dict = self.getStyleDictFromFieldName( original_content_xml, 'my_title') # check the style is good before the odg generation self.assertEqual(original_document_style_dict, style_dict) request = self.app.REQUEST # 1. Normal case: "my_title" field to the "my_title" reference in the ODF document odf_document = foo_printout.index_html(request) self.assertTrue(odf_document is not None) builder = OOoBuilder(odf_document) content_xml = builder.extract("content.xml") final_document_style_dict = self.getStyleDictFromFieldName( content_xml, 'my_title') # check the style is keept after the odg generation self.assertEqual(final_document_style_dict, style_dict) self.assertTrue(content_xml.find("Foo title!") > 0) self.assertEqual(request.RESPONSE.getHeader('content-type'), 'application/vnd.oasis.opendocument.graphics') self.assertEqual( request.RESPONSE.getHeader('content-disposition'), 'inline;filename="Foo_viewProxyFieldAsODGPrintout.odg"') self._validate(odf_document) # 2. Normal case: change the field value and check again the ODF document test1.setTitle("Changed Title!") #foo_form.my_title.set_value('default', "Changed Title!") odf_document = foo_printout.index_html(request) self.assertTrue(odf_document is not None) builder = OOoBuilder(odf_document) content_xml = builder.extract("content.xml") self.assertTrue(content_xml.find("Changed Title!") > 0) self._validate(odf_document) # 3. False case: change the field name test1.setTitle("you cannot find") # rename id 'my_title' to 'xxx_title', then does not match in the ODF document foo_form = portal.foo_module.test1.Foo_viewProxyField foo_form.manage_renameObject('my_title', 'xxx_title', REQUEST=request) odf_document = foo_printout.index_html(request) self.assertTrue(odf_document is not None) builder = OOoBuilder(odf_document) content_xml = builder.extract("content.xml") self.assertFalse(content_xml.find("you cannot find") > 0) self._validate(odf_document) # put back foo_form.manage_renameObject('xxx_title', 'my_title', REQUEST=request) ## 4. False case: does not set a ODF template self.assertTrue(foo_printout.template == 'Foo_getODGStyleSheet') tmp_template = foo_printout.template foo_printout.template = None self.assertRaises(ValueError, foo_printout.index_html, request) # put back foo_printout.template = tmp_template # 5. Normal case: just call a FormPrintout object request.RESPONSE.setHeader('Content-Type', 'text/html') test1.setTitle("call!") odf_document = foo_printout(request) # call self.assertTrue(odf_document is not None) builder = OOoBuilder(odf_document) content_xml = builder.extract("content.xml") self.assertTrue(content_xml.find("call!") > 0) self.assertEqual(request.RESPONSE.getHeader('content-type'), 'application/vnd.oasis.opendocument.graphics') self._validate(odf_document) # 5. Normal case: utf-8 string test1.setTitle("Français") odf_document = foo_printout(request) self.assertTrue(odf_document is not None) builder = OOoBuilder(odf_document) content_xml = builder.extract("content.xml") self.assertTrue(content_xml.find("Français") > 0) self._validate(odf_document) # 6. Normal case: unicode string test1.setTitle(u'Français test2') odf_document = foo_printout(request) self.assertTrue(odf_document is not None) builder = OOoBuilder(odf_document) content_xml = builder.extract("content.xml") self.assertTrue(content_xml.find("Français test2") > 0) self._validate(odf_document)
def test_03_Image(self): """ Mapping an ImageField to odg document. Check it's possible to use an odg document to map an image with a form.ImageField """ # create a new person request = self.portal.REQUEST person_module = self.portal.getDefaultModule('Person') if person_module._getOb('person1', None) is None: person_module.newContent(id='person1', portal_type='Person') person1 = person_module.person1 # add an image to this person current_dir = os.path.dirname(__file__) parent_dir = os.path.dirname(current_dir) image_path = os.path.join(parent_dir, 'www', 'form_printout_icon.png') file_data = FileUpload(image_path) image = person1.newContent(portal_type='Embedded File') image.edit(file=file_data) foo_printout = image.Foo_viewAsODGPrintout foo_form = image.Foo_view # add an image_field to Foo_view if there is not if foo_form._getOb("image_view", None) is None: foo_form.manage_addField('image_view', 'logo', 'ImageField') image_view_field = foo_form.image_view # set the image on the field image_view_field.values['default'] = image.absolute_url_path() # 01 - Normal image mapping odf_document = foo_printout(request) self.assertTrue(odf_document is not None) self._validate(odf_document) builder = OOoBuilder(odf_document) content_xml = builder.extract("content.xml") content = etree.XML(content_xml) image_element_list = content.xpath('//draw:image', namespaces=content.nsmap) self.assertTrue(len(image_element_list) > 0) # check the image is in the odg file try: image_path = image_element_list[0].get( '{http://www.w3.org/1999/xlink}href') image_data = builder.extract(image_path) except KeyError: self.fail('image %r not found in odg document' % image_path) self.assertEqual(image.getData(), image_data, '%s != %s' % (len(image.getData()), len(image_data))) image_frame_xpath = '//draw:frame[@draw:name="image_view"]' image_frame_list = content.xpath(image_frame_xpath, namespaces=content.nsmap) self.assertTrue(len(image_frame_list) > 0) image_frame = image_frame_list[0] # Check the image size. # as the test image (form_printout_icon.png) is a square, proportions # should be keept, so heigh and width should be same and equal to the # height of the original image in the original odf test document. self.assertEqual( image_frame.attrib['{%s}height' % content.nsmap['svg']], '1.206cm') self.assertEqual( image_frame.attrib['{%s}width' % content.nsmap['svg']], '1.206cm') # 02: No image defined image_view_field.values['default'] = '' odf_document = foo_printout(request) self.assertTrue(odf_document is not None) builder = OOoBuilder(odf_document) content_xml = builder.extract("content.xml") # confirming the image was removed content = etree.XML(content_xml) image_element_list = content.xpath('//draw:image', namespaces=content.nsmap) self.assertFalse(len(image_element_list) > 0) self._validate(odf_document)
def test_02_TextFieldWithMultiLines(self): """ mapping a field containing many lines ('\n') to a textbox """ portal = self.getPortal() # add a description field in the form foo_form = self.portal.foo_module.test1.Foo_view if foo_form._getOb("my_description", None) is None: foo_form.manage_addField('my_description', 'Description', 'TextAreaField') foo_module = self.portal.foo_module if foo_module._getOb('test1', None) is None: foo_module.newContent(id='test1', portal_type='Foo') test1 = foo_module.test1 test1.setDescription('A text a bit more longer\n\nWith a newline !') self.tic() style_dict = { '{urn:oasis:names:tc:opendocument:xmlns:text:1.0}line-break': {}, '{urn:oasis:names:tc:opendocument:xmlns:text:1.0}p': {}, '{urn:oasis:names:tc:opendocument:xmlns:text:1.0}span': { '{urn:oasis:names:tc:opendocument:xmlns:text:1.0}style-name': 'T4' } } # test target foo_printout = portal.foo_module.test1.Foo_viewAsODGPrintout original_file_content = self.getODFDocumentFromPrintout(foo_printout) self._validate(original_file_content) # extract content.xml from original odg document original_doc_builder = OOoBuilder(original_file_content) original_content_xml = original_doc_builder.extract("content.xml") # get style of the title in the orignal test document original_document_style_dict = self.getStyleDictFromFieldName( original_content_xml, 'my_description') # check the style is good before the odg generation self.assertEqual(original_document_style_dict, style_dict) request = self.app.REQUEST # 1. Normal case: "my_title" field to the "my_title" reference in the ODF document odf_document = foo_printout.index_html(request) self.assertTrue(odf_document is not None) # validate the generated document self._validate(odf_document) builder = OOoBuilder(odf_document) content_xml = builder.extract("content.xml") content = etree.XML(content_xml) final_document_style_dict = self.getStyleDictFromFieldName( content_xml, 'my_description') # check the style is keept after the odg generation self.assertEqual(final_document_style_dict, style_dict) # check the two lines are prensent in the generated document self.assertTrue(content_xml.find('A text a bit more longer') > 0) self.assertTrue(content_xml.find('With a newline !') > 0) # check there is two line-break in the element my_description text_xpath = '//draw:frame[@draw:name="my_description"]//text:line-break' node_list = content.xpath(text_xpath, namespaces=content.nsmap) self.assertEqual(len(node_list), 2)