From 9d9f83c7a36d0a82f400f2eadfe570a4d8082020 Mon Sep 17 00:00:00 2001 From: Georgios Dagkakis <georgios.dagkakis@nexedi.com> Date: Mon, 22 Feb 2016 17:18:54 +0000 Subject: [PATCH] BusinessTemplates: Allow export of files like Python Script, Web Page, Web Script etc. separately from the xml --- product/ERP5/Document/BusinessTemplate.py | 390 ++++++-- product/ERP5/Tool/TemplateTool.py | 68 +- product/ERP5/tests/testBusinessTemplate.py | 4 - .../testBusinessTemplateTwoFileExport.py | 944 ++++++++++++++++++ 4 files changed, 1293 insertions(+), 113 deletions(-) create mode 100644 product/ERP5/tests/testBusinessTemplateTwoFileExport.py diff --git a/product/ERP5/Document/BusinessTemplate.py b/product/ERP5/Document/BusinessTemplate.py index 7c285c0e63..5778478af6 100644 --- a/product/ERP5/Document/BusinessTemplate.py +++ b/product/ERP5/Document/BusinessTemplate.py @@ -62,7 +62,7 @@ from Products.ERP5Type.Utils import readLocalTest, \ from Products.ERP5Type.Utils import convertToUpperCase from Products.ERP5Type import Permissions, PropertySheet, interfaces from Products.ERP5Type.XMLObject import XMLObject -from Products.ERP5Type.dynamic.lazy_class import ERP5BaseBroken +from Products.ERP5Type.dynamic.lazy_class import ERP5BaseBroken, InitGhostBase from Products.ERP5Type.dynamic.portal_type_class import synchronizeDynamicModules from Products.ERP5Type.Core.PropertySheet import PropertySheet as PropertySheetDocument from Products.ERP5Type.TransactionalVariable import getTransactionalVariable @@ -102,6 +102,12 @@ try: except TypeError: pass cache_database = threading.local() +from mimetypes import guess_extension +from mimetypes import MimeTypes +from Products.MimetypesRegistry.common import MimeTypeException +import base64 +import binascii +import imghdr # those attributes from CatalogMethodTemplateItem are kept for # backward compatibility @@ -686,19 +692,279 @@ class ObjectTemplateItem(BaseTemplateItem): if id != '': self._archive["%s/%s" % (tool_id, id)] = None - def export(self, context, bta, **kw): + def getClassNameAndExportedExtensionDict(self): + class_name_and_exported_extension_dict = { + "Web Page": {"extension": None, "exported_property_type": "text_content"}, + "Web Style": {"extension": None, "exported_property_type": "text_content"}, + "Web Script": {"extension": None, "exported_property_type": "text_content"}, + "ZopePageTemplate": {"extension": ".zpt", "exported_property_type": "_text"}, + "OOoTemplate": {"extension": ".oot", "exported_property_type": "_text"}, + "Extension Component": {"extension": ".py", "exported_property_type": "text_content"}, + "Test Component": {"extension": ".py", "exported_property_type": "text_content"}, + "Document Component": {"extension": ".py", "exported_property_type": "text_content"}, + "PythonScript": {"extension": ".py", "exported_property_type": "_body"}, + "Image": {"extension": None, "exported_property_type": "data"}, + "File": {"extension": None, "exported_property_type": "data"}, + "DTMLMethod": {"extension": None, "exported_property_type": "raw"}, + "SQL": {"extension": '.sql', "exported_property_type": "src"}, + "Spreadsheet": {"extension": None, "exported_property_type": "data"}, + "PDF": {"extension": '.pdf', "exported_property_type": "data"} + } + return class_name_and_exported_extension_dict + + def getPropertyAndExtensionExportedSeparatelyDict(self, document, key): + """Returns a dictionary with one element in the type of + {exported_property_type: extension} + + exported_property_type is the key of the document where the actual data + exists. E.g. for a Extension Component this is 'text_content', while for a + PythonScript it is'_body'. + + The extension can be default for some Portal Types, e.g. for PythonScript it + is always '.py', but for others like File guessExtensionOfDocument is used + to identify it. + """ + class_name = document.__class__.__name__ + class_name_and_exported_extension_dict = self.getClassNameAndExportedExtensionDict() + if class_name in class_name_and_exported_extension_dict.keys(): + extension = class_name_and_exported_extension_dict[class_name]["extension"] + exported_property_type = class_name_and_exported_extension_dict[class_name]["exported_property_type"] + if extension: + return {exported_property_type: extension} + else: + extension = self.guessExtensionOfDocument(document, key, exported_property_type) + if extension: + # if the obtained extension was .xml, change it to ._xml so that it + # would not conflict with th .xml metadata document + if extension == '.xml': + extension = '._xml' + return {exported_property_type: extension} + return {} + + def getMimetypesRegistryLookupResultOfContenType(self, content_type): + """Returns a lookup in mimetypes_registry based on the content_type""" + mimetypes_registry = self.getPortalObject().mimetypes_registry + try: + return mimetypes_registry.lookup(content_type) + except MimeTypeException: + return + + def guessExtensionOfDocument(self, document, key, exported_property_type=None): + """Guesses and returns the extension of an ERP5 document. + + The process followed is: + 1. Try to guess extension by content type + 2. Try to guess extension by the id of the document + 3. Try to guess extension by the title of the document + 4. Try to guess extension by the reference of the document + 5. In the case of an image, try to guess extension by Base64 representation + + In case everything fails then: + - '.bin' is returned for binary files + - '.txt' is returned for text + """ + # XXX Zope items like DTMLMethod would not + # implement getContentType method + extension = None + binary = 'not_identified' + if hasattr(document, 'getContentType'): + content_type = document.getContentType() + lookup_result = self.getMimetypesRegistryLookupResultOfContenType(content_type) + if lookup_result: + # return first registered Extension (if any) + if lookup_result[0].extensions: + extension = lookup_result[0].extensions[0] + # If there is no extension return the first registered Glob (if any) + elif lookup_result[0].globs: + extension = str(lookup_result[0].globs[0]).replace('*', '') + if hasattr(lookup_result[0], 'binary'): + binary = lookup_result[0].binary + if extension: + if not extension.startswith('.'): + extension = '.'+extension + return extension + # Try to guess the extension based on the id of the document + mime = MimeTypes() + mime_type = mime.guess_type(key) + if mime_type[0]: + extension = guess_extension(mime_type[0]) + return extension + # Try to guess the extension based on the reference of the document + mime = MimeTypes() + if hasattr(document, 'getReference'): + reference = document.getReference() + if reference: + mime_type = mime.guess_type(reference) + if mime_type[0]: + extension = guess_extension(mime_type[0]) + return extension + # Try to guess the extension based on the title of the document + if hasattr(document, 'title'): + mime_type = mime.guess_type(document.title) + if mime_type[0]: + extension = guess_extension(mime_type[0]) + return extension + # Try to get type of image from its base64 encoding + if exported_property_type == 'data': + # XXX maybe decoding the whole file just for the extension is an overkill + data = str(document.__dict__.get('data')) + try: + decoded_data = base64.decodestring(data) + for test in imghdr.tests: + extension = test(decoded_data, None) + if extension: + return '.'+extension + except binascii.Error: + LOG('BusinessTemplate ', 0, 'data is not base 64') + # in case we could not read binary flag from mimetypes_registry then return + # '.bin' for all the Portal Types where exported_property_type is data + # (File, Image, Spreadsheet). Otherwise, return .bin if binary was returned + # as 1. + if (binary == 'not_identified' and exported_property_type == 'data') or \ + binary == 1: + return '.bin' + # in all other cases return .txt + return '.txt' + + def export(self, context, bta, catalog_method_template_item = 0, **kw): """ Export the business template : fill the BusinessTemplateArchive with objects exported as XML, hierarchicaly organised. """ if len(self._objects.keys()) == 0: return - path = self.__class__.__name__ + path = self.__class__.__name__+ '/' for key, obj in self._objects.iteritems(): - # export object in xml - f = StringIO() - XMLExportImport.exportXML(obj._p_jar, obj._p_oid, f) - bta.addObject(f, key, path=path) + class_name=obj.__class__.__name__ + property_and_extension_exported_separately_dict = self.getPropertyAndExtensionExportedSeparatelyDict(obj, key) + # Back compatibility with filesystem Documents + if isinstance(obj, str): + if not key.startswith(path): + key = path + key + bta.addObject(obj, name=key, ext='.py') + else: + if property_and_extension_exported_separately_dict: + for record_id, record in property_and_extension_exported_separately_dict.iteritems(): + extension = record + exported_property_type = record_id + if hasattr(obj, exported_property_type): + exported_property = getattr(obj, exported_property_type) + if isinstance(exported_property, unicode): + exported_property = str(exported_property.encode('utf-8')) + elif not isinstance(exported_property, str): + exported_property = str(exported_property) + + reset_output_encoding = False + if hasattr(obj, 'output_encoding'): + reset_output_encoding = True + output_encoding = obj.output_encoding + obj = obj._getCopy(context) + + f = StringIO(exported_property) + bta.addObject(f, key, path=path, ext=extension) + + # since we get the obj from context we should + # again remove useless properties + obj = self.removeProperties(obj, 1, keep_workflow_history = True) + + # in case the related Portal Type does not exist, the object may be broken. + # So we cannot delattr, but we can delet the het of its its broken state + if isinstance(obj, ERP5BaseBroken): + del obj.__Broken_state__[exported_property_type] + if reset_output_encoding: + self._objects[obj_key].__Broken_state__['output_encoding'] = output_encoding + obj._p_changed = 1 + else: + delattr(obj, exported_property_type) + if reset_output_encoding: + obj.output_encoding = output_encoding + transaction.savepoint(optimistic=True) + + f = StringIO() + XMLExportImport.exportXML(obj._p_jar, obj._p_oid, f) + bta.addObject(f, key, path=path) + + if catalog_method_template_item: + # add all datas specific to catalog inside one file + xml_data = self.generateXml(key) + bta.addObject(xml_data, key + '.catalog_keys', path=path) + + def _importFile(self, file_name, file_obj, catalog_method_template_item = 0): + transactional_variable = getTransactionalVariable() + obj_key, file_ext = os.path.splitext(file_name) + # id() for installing several bt5 in the same transaction + transactional_variable_obj_key = "%s-%s" % (id(self), obj_key) + if file_ext != '.xml': + # if the document has not been migrated yet (its class is file and + # it is not in portal_components) use legacy importer + if issubclass(self.__class__, FilesystemDocumentTemplateItem) and file_obj.name.rsplit(os.path.sep, 2)[-2] != 'portal_components': + FilesystemDocumentTemplateItem._importFile(self, file_name, file_obj) + else: + # For ZODB Components: if .xml have been processed before, set the + # source code property, otherwise store it in a transactional variable + # so that it can be set once the .xml has been processed + file_obj_content = file_obj.read() + try: + obj = self._objects[obj_key] + except KeyError: + transactional_variable[transactional_variable_obj_key] = file_obj_content + else: + obj_class_name = obj.__class__.__name__ + exported_property_type = self.getClassNameAndExportedExtensionDict()[obj_class_name]['exported_property_type'] + # if we have instance of InitGhostBase, 'unghost' it so we can + # identify if it is broken + if isinstance(self._objects[obj_key], InitGhostBase): + self._objects[obj_key].__class__.loadClass() + # in case the Portal Type does not exist, the object may be broken. + # So we cannot setattr, but we can change the attribute in its broken state + if isinstance(self._objects[obj_key], ERP5BaseBroken): + self._objects[obj_key].__Broken_state__[exported_property_type] = file_obj_content + self._objects[obj_key]._p_changed = 1 + else: + setattr(self._objects[obj_key], exported_property_type, file_obj_content) + self._objects[obj_key] = self.removeProperties(self._objects[obj_key], 1, keep_workflow_history = True) + else: + connection = self.getConnection(self.aq_parent) + __traceback_info__ = 'Importing %s' % file_name + if hasattr(cache_database, 'db') and isinstance(file_obj, file): + obj = connection.importFile(self._compileXML(file_obj)) + else: + # FIXME: Why not use the importXML function directly? Are there any BT5s + # with actual .zexp files on the wild? + obj = connection.importFile(file_obj, customImporters=customImporters) + self._objects[obj_key] = obj + + if transactional_variable.get(transactional_variable_obj_key, None) != None: + obj_class_name = obj.__class__.__name__ + exported_property_type = self.getClassNameAndExportedExtensionDict()[obj_class_name]['exported_property_type'] + # if we have instance of InitGhostBase, 'unghost' it so we can + # identify if it is broken + if isinstance(self._objects[obj_key], InitGhostBase): + self._objects[obj_key].__class__.loadClass() + # in case the related Portal Type does not exist, the object may be broken. + # So we cannot setattr, but we can change the attribute in its broken state + if isinstance(self._objects[obj_key], ERP5BaseBroken): + self._objects[obj_key].__Broken_state__[exported_property_type] = transactional_variable[transactional_variable_obj_key] + self._objects[obj_key]._p_changed = 1 + else: + setattr(self._objects[obj_key], exported_property_type, transactional_variable[transactional_variable_obj_key]) + self._objects[obj_key] = self.removeProperties(self._objects[obj_key], 1, keep_workflow_history = True) + + # When importing a Business Template, there is no way to determine if it + # has been already migrated or not in __init__() when it does not + # already exist, therefore BaseTemplateItem.__init__() is called which + # does not set _archive with portal_components/ like + # ObjectTemplateItem.__init__() + # XXX - the above comment is a bit unclear, + # still not sure if this is handled correctly + if file_obj.name.rsplit(os.path.sep, 2)[-2] == 'portal_components': + self._archive[obj_key] = None + try: + del self._archive[obj_key[len('portal_components/'):]] + except KeyError: + pass + if catalog_method_template_item: + self.removeProperties(obj, 0) def build_sub_objects(self, context, id_list, url, **kw): # XXX duplicates code from build @@ -820,21 +1086,6 @@ class ObjectTemplateItem(BaseTemplateItem): return connection obj = obj.aq_parent - def _importFile(self, file_name, file_obj): - # import xml file - if not file_name.endswith('.xml'): - LOG('Business Template', 0, 'Skipping file "%s"' % (file_name, )) - return - connection = self.getConnection(self.aq_parent) - __traceback_info__ = 'Importing %s' % file_name - if hasattr(cache_database, 'db') and isinstance(file_obj, file): - obj = connection.importFile(self._compileXML(file_obj)) - else: - # FIXME: Why not use the importXML function directly? Are there any BT5s - # with actual .zexp files on the wild? - obj = connection.importFile(file_obj, customImporters=customImporters) - self._objects[file_name[:-4]] = obj - def preinstall(self, context, installed_item, **kw): modified_object_list = {} upgrade_list = [] @@ -2718,19 +2969,7 @@ class CatalogMethodTemplateItem(ObjectTemplateItem): if catalog is None: LOG('BusinessTemplate, export', 0, 'no SQL catalog was available') return - - if len(self._objects.keys()) == 0: - return - path = self.__class__.__name__ - for key in self._objects.keys(): - obj = self._objects[key] - # export object in xml - f=StringIO() - XMLExportImport.exportXML(obj._p_jar, obj._p_oid, f) - bta.addObject(f, key, path=path) - # add all datas specific to catalog inside one file - xml_data = self.generateXml(key) - bta.addObject(xml_data, key + '.catalog_keys', path=path) + ObjectTemplateItem.export(self, context, bta, catalog_method_template_item=1) def install(self, context, trashbin, **kw): ObjectTemplateItem.install(self, context, trashbin, **kw) @@ -2887,14 +3126,9 @@ class CatalogMethodTemplateItem(ObjectTemplateItem): else: # new style key self._method_properties.setdefault(id, PersistentMapping())[key] = 1 - elif file_name.endswith('.xml'): - # just import xml object - connection = self.getConnection(self.aq_parent) - obj = connection.importFile(file, customImporters=customImporters) - self.removeProperties(obj, 0) - self._objects[file_name[:-4]] = obj else: - LOG('Business Template', 0, 'Skipping file "%s"' % (file_name, )) + ObjectTemplateItem._importFile(self, file_name, file, catalog_method_template_item=1) + class ActionTemplateItem(ObjectTemplateItem): @@ -3968,74 +4202,14 @@ class DocumentTemplateItem(FilesystemToZodbTemplateItem): wf_history.pop('comment', None) obj.workflow_history[wf_id] = WorkflowHistoryList([wf_history]) - + + # XXX temporary should be eliminated from here def _importFile(self, file_name, file_obj): - """ - This will be called once for non-migrated Document and twice for ZODB - Components (for .xml (metadata) and .py (source code)). This code MUST - consider both bt5 folder (everything is on the FS) and tarball (where in - case of ZODB Components, .xml may have been processed before .py and vice - versa. - """ - tv = getTransactionalVariable() - obj_key, file_ext = os.path.splitext(file_name) - # id() for installing several bt5 in the same transaction - tv_obj_key = "%s-%s" % (id(self), obj_key) - if file_ext == '.py': - # If this Document has not been migrated yet (eg not matching - # "portal_components/XXX.py"), use legacy importer - if file_obj.name.rsplit(os.path.sep, 2)[-2] != 'portal_components': - FilesystemDocumentTemplateItem._importFile(self, file_name, file_obj) - # For ZODB Components: if .xml have been processed before, set the - # source code property, otherwise store it in a transactional variable - # so that it can be set once the .xml has been processed - else: - text_content = file_obj.read() - try: - obj = self._objects[obj_key] - except KeyError: - tv[tv_obj_key] = text_content - else: - obj.text_content = text_content - elif file_ext == '.xml': - ObjectTemplateItem._importFile(self, file_name, file_obj) - self._objects[obj_key].text_content = tv.get(tv_obj_key, None) - - # When importing a Business Template, there is no way to determine if it - # has been already migrated or not in __init__() when it does not - # already exist, therefore BaseTemplateItem.__init__() is called which - # does not set _archive with portal_components/ like - # ObjectTemplateItem.__init__() - self._archive[obj_key] = None - del self._archive[obj_key[len('portal_components/'):]] - else: - LOG('Business Template', 0, 'Skipping file "%s"' % file_name) - + ObjectTemplateItem._importFile(self, file_name, file_obj) + + # XXX temporary should be eliminated from here def export(self, context, bta, **kw): - """ - Export a Document as two files for ZODB Components, one for metadata - (.xml) and the other for the Python source code (.py) - """ - path = self.__class__.__name__ + '/' - for key, obj in self._objects.iteritems(): - # Back compatibility with filesystem Documents - if isinstance(obj, str): - if not key.startswith(path): - key = path + key - bta.addObject(obj, name=key, ext='.py') - else: - obj = obj._getCopy(context) - - f = StringIO(obj.text_content) - bta.addObject(f, key, path=path, ext='.py') - - del obj.text_content - transaction.savepoint(optimistic=True) - - # export object in xml - f = StringIO() - XMLExportImport.exportXML(obj._p_jar, obj._p_oid, f) - bta.addObject(f, key, path=path) + ObjectTemplateItem.export(self, context, bta, **kw) def getTemplateIdList(self): """ diff --git a/product/ERP5/Tool/TemplateTool.py b/product/ERP5/Tool/TemplateTool.py index 0b552d92e9..dc75196ba3 100644 --- a/product/ERP5/Tool/TemplateTool.py +++ b/product/ERP5/Tool/TemplateTool.py @@ -62,7 +62,7 @@ from zLOG import LOG, INFO, WARNING from base64 import decodestring import subprocess import time - +from distutils.dir_util import copy_tree WIN = os.name == 'nt' @@ -461,6 +461,72 @@ class TemplateTool (BaseTool): """ return self.getFilteredDiff(diff).toHTML() + def _cleanUpTemplateFolder(self, folder_path): + for file_object in os.listdir(folder_path): + file_object_path = os.path.join(folder_path, file_object) + if os.path.isfile(file_object_path): + os.unlink(file_object_path) + else: + shutil.rmtree(file_object_path) + + def _importAndReExportBusinessTemplate(self, template_path): + """ + Imports the template that is in the template_path and exports it to the + same path. + + We want to clean this directory, i.e. remove all files before + the export. Because this is called as activity though, it could cause + the following problem: + - Activity imports the template + - Activity removes all files from template_path + - Activity fails in export. + Then the folder contents will be changed, so when retrying the + activity may succeed without the user understanding that files were + erased. For this reason export is done in 3 steps: + - First to a temporary directory + - If there was no error delete contents of template_path + - Copy the contents of the temporary directory to the template_path + """ + import_template = self.download(url=template_path) + export_dir = mkdtemp() + try: + import_template.export(path=export_dir, local=True) + self._cleanUpTemplateFolder(template_path) + copy_tree(export_dir, template_path) + except: + raise + finally: + shutil.rmtree(export_dir) + + security.declareProtected( 'Import/Export objects', 'importAndReExportBusinessTemplatesFromPath' ) + def importAndReExportBusinessTemplatesFromPath(self, repository_list, REQUEST=None, **kw): + """ + Migrate business templates to new format where files like .py or .html + are exported seprately than the xml. + """ + repository_list = filter(bool, repository_list) + + if REQUEST is None: + REQUEST = getattr(self, 'REQUEST', None) + + if len(repository_list) == 0 and REQUEST: + ret_url = self.absolute_url() + REQUEST.RESPONSE.redirect("%s?portal_status_message=%s" + % (ret_url, 'No repository was defined')) + + for repository in repository_list: + repository = repository.rstrip('\n') + repository = repository.rstrip('\r') + for business_template_id in os.listdir(repository): + template_path = os.path.join(repository, business_template_id) + if os.path.isfile(template_path): + LOG(business_template_id,0,'is file, so it is skipped') + else: + if not os.path.exists((os.path.join(template_path, 'bt'))): + LOG(business_template_id,0,'has no bt sub-folder, so it is skipped') + else: + self.activate(activity='SQLQueue')._importAndReExportBusinessTemplate(template_path) + security.declareProtected(Permissions.ManagePortal, 'getFilteredDiff') def getFilteredDiff(self, diff): """ diff --git a/product/ERP5/tests/testBusinessTemplate.py b/product/ERP5/tests/testBusinessTemplate.py index 9b7a619e65..b099c0773c 100644 --- a/product/ERP5/tests/testBusinessTemplate.py +++ b/product/ERP5/tests/testBusinessTemplate.py @@ -7546,10 +7546,6 @@ class TestDocumentTemplateItem(BusinessTemplateMixin): self.assertNotEqual(wf_history_dict.get('actor'), None) self.assertNotEqual(wf_history_dict.get('comment'), None) - def stepRemoveZodbDocument(self, sequence=None, **kw): - self.getPortalObject().portal_components.deleteContent( - sequence['document_id']) - def stepCheckZodbDocumentExistsAndValidated(self, sequence=None, **kw): component = getattr(self.getPortalObject().portal_components, sequence['document_id'], None) diff --git a/product/ERP5/tests/testBusinessTemplateTwoFileExport.py b/product/ERP5/tests/testBusinessTemplateTwoFileExport.py new file mode 100644 index 0000000000..98690ffb05 --- /dev/null +++ b/product/ERP5/tests/testBusinessTemplateTwoFileExport.py @@ -0,0 +1,944 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Copyright (c) 2005 Nexedi SARL and Contributors. All Rights Reserved. +# Aurelien Calonne <aurel@nexedi.com> +# +# WARNING: This program as such is intended to be used by professional +# programmers who take the whole responsibility of assessing all potential +# consequences resulting from its eventual inadequacies and bugs +# End users who are looking for a ready-to-use solution with commercial +# guarantees and support are strongly adviced to contract a Free Software +# Service Company +# +# This program is Free Software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +############################################################################## + +from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase +from App.config import getConfiguration +import shutil +import os +import tempfile + +class TestBusinessTemplateTwoFileExport(ERP5TypeTestCase): + """ + Test export and import of business templates with files (e.g. Web Script) + + - Create a template + + - Create a file + + - Build and export the template + + - Check that the expected files are exported + + - Import the exported template and install it + + - Check that the files are imported properly + """ + + def getBusinessTemplateList(self): + return ['erp5_core_proxy_field_legacy', + 'erp5_property_sheets', + 'erp5_jquery', + 'erp5_full_text_mroonga_catalog', + 'erp5_base', + 'erp5_core', + 'erp5_ingestion_mysql_innodb_catalog', + 'erp5_ingestion', + 'erp5_xhtml_style', + 'erp5_web', + 'erp5_hal_json_style', + 'erp5_dms', + 'erp5_web_renderjs_ui' + ] + + def afterSetUp(self): + self.cfg = getConfiguration() + self.export_dir = tempfile.mkdtemp() + self.template_tool = self.getTemplateTool() + self.template = self._createNewBusinessTemplate(self.template_tool) + + def beforeTearDown(self): + export_dir_path = os.path.join(self.cfg.instancehome, self.export_dir) + if os.path.exists(export_dir_path): + shutil.rmtree(self.export_dir) + + def _createNewBusinessTemplate(self, template_tool): + template = template_tool.newContent(portal_type='Business Template') + self.assertTrue(template.getBuildingState() == 'draft') + self.assertTrue(template.getInstallationState() == 'not_installed') + template.edit(title ='test_template', + version='1.0', + description='bt for unit_test') + return template + + def _buildAndExportBusinessTemplate(self): + self.tic() + self.template.build() + self.tic() + + self.template.export(path=self.export_dir, local=True) + self.tic() + + def _importBusinessTemplate(self): + template_id = self.template.getId() + template_path = os.path.join(self.cfg.instancehome, self.export_dir) + self.template_tool.manage_delObjects(template_id) + + import_template = self.template_tool.download(url='file:'+template_path) + + self.assertFalse(import_template is None) + self.assertEqual(import_template.getPortalType(), 'Business Template') + + return import_template + + def _exportAndReImport(self, xml_document_path, + file_document_path, data, removed_property_list): + + self._buildAndExportBusinessTemplate() + self.assertTrue(os.path.exists(xml_document_path)) + self.assertTrue(os.path.exists(file_document_path)) + test_file=open(file_document_path,'r+') + self.assertEqual(test_file.read(), data) + test_file.close() + xml_file=open(xml_document_path,'r+') + xml_file_content = xml_file.read() + xml_file.close() + for exported_property in removed_property_list: + self.assertFalse('<string>'+exported_property+'</string>' in xml_file_content) + + import_template = self._importBusinessTemplate() + return import_template + + def test_twoFileImportExportForTestDocument(self): + """Test Business Template Import And Export With Test Document""" + test_component_kw = {"title": "foo", + "text_content": "def dummy(): pass", + "portal_type": "Test Component"} + + test_document_page = self.portal.portal_components.newContent(**test_component_kw) + test_component_kw['id'] = test_component_id = test_document_page.getId() + + self.template.edit(template_test_id_list=['portal_components/'+test_component_id,]) + + test_component_path = os.path.join(self.cfg.instancehome, self.export_dir, + 'TestTemplateItem', 'portal_components', + test_component_id) + import_template = self._exportAndReImport( + test_component_path + ".xml", + test_component_path +".py", + test_component_kw["text_content"], + ['text_content']) + + self.portal.portal_components.manage_delObjects([test_component_id]) + + import_template.install() + + test_page = self.portal.portal_components[test_component_id] + + for property_id, property_value in test_component_kw.iteritems(): + self.assertEqual(test_page.getProperty(property_id), property_value) + + def test_twoFileImportExportForWebPage(self): + """Test Business Template Import And Export With Web Page""" + html_document_kw = {"title": "foo", "text_content": "<html></html>", + "portal_type": "Web Page"} + html_page = self.portal.web_page_module.newContent(**html_document_kw) + js_document_kw = {"title": "foo.js", "text_content": "// JavaScript", + "portal_type": "Web Script"} + js_page = self.portal.web_page_module.newContent(**js_document_kw) + css_document_kw = {"title": "foo.css", "text_content": "<style></style>", + "portal_type": "Web Style"} + css_page = self.portal.web_page_module.newContent(**css_document_kw) + html_document_kw['id'] = html_file_id = html_page.getId() + js_document_kw['id'] = js_file_id = js_page.getId() + css_document_kw['id'] = css_file_id = css_page.getId() + + self.template.edit(template_path_list=['web_page_module/'+html_file_id, + 'web_page_module/'+js_file_id, + 'web_page_module/'+css_file_id,]) + + self._buildAndExportBusinessTemplate() + + web_page_module_path = os.path.join(self.cfg.instancehome, self.export_dir, + 'PathTemplateItem', 'web_page_module') + + for web_file in [(html_file_id, '.html', html_document_kw), + (js_file_id, '.js', js_document_kw), + (css_file_id, '.css', css_document_kw)]: + xml_document_path = os.path.join(web_page_module_path, web_file[0]+'.xml') + file_document_path = os.path.join(web_page_module_path, + web_file[0]+web_file[1]) + self.assertTrue(os.path.exists(xml_document_path)) + self.assertTrue(os.path.exists(file_document_path)) + file_content=open(file_document_path,'r+') + self.assertEqual(file_content.read(), web_file[2]["text_content"]) + xml_file=open(xml_document_path,'r+') + self.assertFalse('<string>text_content</string>' in xml_file.read()) + + import_template = self._importBusinessTemplate() + + self.portal.web_page_module.manage_delObjects([html_file_id]) + self.portal.web_page_module.manage_delObjects([js_file_id]) + self.portal.web_page_module.manage_delObjects([css_file_id]) + + import_template.install() + + for web_file in [(html_file_id, html_document_kw), + (js_file_id, js_document_kw), + (css_file_id, css_document_kw)]: + web_page = self.portal.web_page_module[web_file[0]] + for property_id, property_value in web_file[1].iteritems(): + self.assertEqual(web_page.getProperty(property_id), property_value) + + def test_twoFileImportExportForPythonScript(self): + """Test Business Template Import And Export With PythonScript""" + skin_folder_id = 'dummy_test_folder' + if skin_folder_id in self.portal.portal_skins.objectIds(): + self.portal.portal_skins.manage_delObjects([skin_folder_id]) + + self.portal.portal_skins.manage_addProduct['OFSP'].manage_addFolder(skin_folder_id) + skin_folder = self.portal.portal_skins[skin_folder_id] + + python_script_id = 'dummy_test_script' + if python_script_id in skin_folder.objectIds(): + skin_folder.manage_delObjects([python_script_id]) + skin_folder.manage_addProduct['PythonScripts'].manage_addPythonScript(id=python_script_id) + python_script = skin_folder[python_script_id] + python_script.ZPythonScript_edit('', "context.setTitle('foo')") + + python_script_kw = {"_body": "context.setTitle('foo')\n",} + + self.template.edit(template_skin_id_list=[skin_folder_id+'/'+python_script_id,]) + + python_script_path = os.path.join(self.cfg.instancehome, self.export_dir, + 'SkinTemplateItem', 'portal_skins',skin_folder_id,python_script_id) + + + import_template = self._exportAndReImport( + python_script_path+".xml", + python_script_path+".py", + python_script_kw["_body"], + ['_body','_code']) + + self.portal.portal_skins[skin_folder_id].manage_delObjects([python_script_id]) + + import_template.install() + + python_script_page = self.portal.portal_skins[skin_folder_id][python_script_id] + + python_script_content = python_script_page.read() + self.assertTrue(python_script_content.endswith(python_script_kw['_body'])) + + def _checkTwoFileImportExportForImageInImageModule(self, + image_document_kw, + extension): + image_page = self.portal.image_module.newContent(**image_document_kw) + image_document_kw['id'] = image_file_id = image_page.getId() + + self.template.edit(template_path_list=['image_module/'+image_file_id,]) + + + image_document_path = os.path.join(self.cfg.instancehome, self.export_dir, + 'PathTemplateItem', 'image_module',image_file_id) + + import_template = self._exportAndReImport( + image_document_path+".xml", + image_document_path+extension, + image_document_kw["data"], + ['data']) + + self.portal.image_module.manage_delObjects([image_file_id]) + + import_template.install() + + image_page = self.portal.image_module[image_file_id] + for property_id, property_value in image_document_kw.iteritems(): + self.assertEqual(image_page.getProperty(property_id), property_value) + + + def test_twoFileImportExportForImageIdentifyingTypeByBase64(self): + """ + Test Business Template Import And Export With Image In Image Module + where extension is found by Base64 representation + """ + image_data = """iVBORw0KGgoAAAANSUhEUgAAAAUA +AAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO +9TXL0Y4OHwAAAABJRU5ErkJggg==""" + image_document_kw = {"title": "foo", "data": image_data, + "portal_type": "Image"} + + self._checkTwoFileImportExportForImageInImageModule(image_document_kw, '.png') + + + def test_twoFileImportExportForImageIdentifyingTypeByContentType(self): + """ + Test Business Template Import And Export With Image In Image Module + where extension (.pjpg) is found by content_type + """ + image_data = """MalformedBase64HereiVBORw0KGgoAAAANSUhEUgAAAAUA +AAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO +9TXL0Y4OHwAAAABJRU5ErkJggg==""" + image_document_kw = {"title": "foo", "data": image_data, + "portal_type": "Image", "content_type": "image/jpeg"} + + self._checkTwoFileImportExportForImageInImageModule(image_document_kw, + '.pjpg') + + def test_twoFileImportExportForImageNotIdentifyingType(self): + """ + Test Business Template Import And Export With Image In Image Module + where extension is not identified, so it is exported as '.bin' + """ + image_data = """MalformedBase64HereiVBORw0KGgoAAAANSUhEUgAAAAUA +AAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO +9TXL0Y4OHwAAAABJRU5ErkJggg==""" + image_document_kw = {"title": "foo", "data": image_data, + "portal_type": "Image"} + + self._checkTwoFileImportExportForImageInImageModule(image_document_kw, + '.bin') + + def _checkTwoFileImportExportForDocumentInDocumentModule(self, + file_document_kw, + extension): + file_page = self.portal.document_module.newContent(**file_document_kw) + file_document_kw['id'] = file_id = file_page.getId() + + self.template.edit(template_path_list=['document_module/'+file_id,]) + + file_document_path = os.path.join(self.cfg.instancehome, self.export_dir, + 'PathTemplateItem', 'document_module', + file_id) + + import_template = self._exportAndReImport( + file_document_path+".xml", + file_document_path+extension, + file_document_kw["data"], + ['data']) + + self.portal.document_module.manage_delObjects([file_id]) + + import_template.install() + + file_page = self.portal.document_module[file_id] + + for property_id, property_value in file_document_kw.iteritems(): + self.assertEqual(getattr(file_page, property_id), property_value) + + def test_twoFileImportExportForFileIdentifyingTypeByContentTypeJS(self): + """ + Test Business Template Import And Export With File + where extension (.js) is identified by the content_type + """ + file_content = "a test file" + file_content_type = "text/javascript" + file_title = "foo" + + file_document_kw = {"title": file_title, "data": file_content, + "content_type": file_content_type, + "portal_type": "File"} + + self._checkTwoFileImportExportForDocumentInDocumentModule(file_document_kw, + '.js') + + def test_twoFileImportExportForFileIdentifyingTypeByContentTypeObj(self): + """ + Test Business Template Import And Export With File + where extension (.obj) is identified by the content_type + """ + file_content = "a test file" + file_content_type = "application/octet-stream" + file_title = "foo" + file_document_kw = {"title": file_title, "data": file_content, + "content_type": file_content_type, + "portal_type": "File"} + + self._checkTwoFileImportExportForDocumentInDocumentModule(file_document_kw, + '.obj') + + def test_twoFileImportExportForFileIdentifyingTypeByContentTypeEpub(self): + """ + Test Business Template Import And Export With File + where extension (.epub) is identified by the content_type + """ + file_content = "a test file" + file_content_type = "application/epub+zip" + file_title = "foo" + file_document_kw = {"title": file_title, "data": file_content, + "content_type": file_content_type, + "portal_type": "File"} + + self._checkTwoFileImportExportForDocumentInDocumentModule(file_document_kw, + '.epub') + + def test_twoFileImportExportForFileIdentifyingTypeByTitleJS(self): + """ + Test Business Template Import And Export With File + where extension (.js) is identified by the title + """ + file_content = "a test file" + file_title = "foo.js" + file_document_kw = {"title": file_title, "data": file_content, + "portal_type": "File"} + + self._checkTwoFileImportExportForDocumentInDocumentModule(file_document_kw, + '.js') + + def test_twoFileImportExportForFileIdentifyingTypeByReferenceJS(self): + """ + Test Business Template Import And Export With File + where extension (.js) is identified by the reference + """ + file_content = "<script> ... </script>" + file_title = "foo" + file_document_kw = {"title": file_title, "data": file_content, + "default_reference": file_title+".js", + "portal_type": "File"} + + self._checkTwoFileImportExportForDocumentInDocumentModule(file_document_kw, + '.js') + + def test_twoFileImportExportForFileNotIdentifyingTypeEmptyContentType(self): + """ + Test Business Template Import And Export With File + where extension is not identified, so it is exported as .bin + """ + file_content = "a test file" + file_content_type = None + file_title = "foo" + file_document_kw = {"title": file_title, "data": file_content, + "content_type": file_content_type, + "portal_type": "File"} + + self._checkTwoFileImportExportForDocumentInDocumentModule(file_document_kw, + '.bin') + + def test_twoFileImportExportForFileNotIdentifyingTypeBinaryContentType(self): + """ + Test Business Template Import And Export With File + where extension is not identified by content_type (video/wavelet) + but it is identified as binary in the mimetypes_registry so it is + exported as .bin. + """ + file_content = "a test file" + file_content_type = 'video/wavelet' + file_title = "foo" + file_document_kw = {"title": file_title, "data": file_content, + "content_type": file_content_type, + "portal_type": "File"} + + self._checkTwoFileImportExportForDocumentInDocumentModule(file_document_kw, + '.bin') + + def test_twoFileImportExportForFileNotIdentifyingTypeNonBinaryContentType(self): + """ + Test Business Template Import And Export With File + where extension is not identified by content_type (text/x-uri) + but it is identified as non-binary in the mimetypes_registry so it is + exported as .txt. + """ + file_content = "a test file" + file_content_type = 'text/x-uri' + file_title = "foo" + file_document_kw = {"title": file_title, "data": file_content, + "content_type": file_content_type, + "portal_type": "File"} + + self._checkTwoFileImportExportForDocumentInDocumentModule(file_document_kw, + '.txt') + + def test_twoFileImportExportForFileIdentifyingTypeByTitleXML(self): + """ + Test Business Template Import And Export With File in portal skins + where extension (.xml, exported as ._xml to avoid conflict with the meta-data file) + is identified by the title + """ + file_content = """<person> +<name>John</name> +<surname>Doe</surname> +</person> + """ + file_title = "foo.xml" + file_content_type = None + file_document_kw = {"title": file_title, "data": file_content, + "content_type": file_content_type, + "portal_type": "File"} + + self._checkTwoFileImportExportForDocumentInDocumentModule(file_document_kw, + '._xml') + + def test_twoFileImportExportForFileInPortalSkinsIdentifyingTypeByTitleXML(self): + """ + Test Business Template Import And Export With File in portal skins + where extension (.xml, exported as ._xml to avoid conflict with the meta-data file) + is identified by the title + """ + file_content = """<person> +<name>John</name> +<surname>Doe</surname> +</person> + """ + file_title = "foo.xml" + file_document_kw = {"title": file_title, "data": file_content,} + + + skin_folder_id = 'dummy_test_folder' + if skin_folder_id in self.portal.portal_skins.objectIds(): + self.portal.portal_skins.manage_delObjects([skin_folder_id]) + + self.portal.portal_skins.manage_addProduct['OFSP'].\ + manage_addFolder(skin_folder_id) + skin_folder = self.portal.portal_skins[skin_folder_id] + + test_file_id = 'dummy_file_id' + if test_file_id in self.portal.objectIds(): + self.portal.manage_delObjects([test_file_id]) + + skin_folder.manage_addProduct['OFSP'].manage_addFile(id=test_file_id) + zodb_file = skin_folder._getOb(test_file_id) + zodb_file.manage_edit(title=file_title, + content_type='', + filedata=file_content) + + self.template.edit(template_skin_id_list=[skin_folder_id+'/'+test_file_id,]) + + file_document_path = os.path.join(self.cfg.instancehome, self.export_dir, + 'SkinTemplateItem', 'portal_skins', + skin_folder_id,test_file_id) + + import_template = self._exportAndReImport( + file_document_path+".xml", + file_document_path+"._xml", + file_document_kw["data"], + ['data']) + + self.portal.portal_skins[skin_folder_id].manage_delObjects([test_file_id]) + + import_template.install() + + file_page = self.portal.portal_skins[skin_folder_id][test_file_id] + + for property_id, property_value in file_document_kw.iteritems(): + self.assertEqual(getattr(file_page, property_id), property_value) + + def test_twoFileImportExportForPDF(self): + """Test Business Template Import And Export With A PDF Document""" + pdf_data = """pdf content, maybe should update for base64 sample""" + + pdf_document_kw = {"title": "foo.pdf", "data": pdf_data, + "portal_type": "PDF"} + + self._checkTwoFileImportExportForDocumentInDocumentModule(pdf_document_kw, + '.pdf') + + def test_twoFileImportExportForCatalogMethodInCatalog(self): + """Test Business Template Import And Export With Catalog Method In Catalog""" + catalog_tool = self.getCatalogTool() + catalog = catalog_tool.getSQLCatalog() + catalog_id = catalog.id + + self.assertTrue(catalog is not None) + method_id = "z_another_dummy_method" + if method_id in catalog.objectIds(): + catalog.manage_delObjects([method_id]) + + method_document_kw = {'id': method_id, 'title': 'dummy_method_title', + 'connection_id': 'erp5_sql_connection', + 'arguments_src': 'args', 'src': 'dummy_method_template'} + + addSQLMethod = catalog.manage_addProduct['ZSQLMethods'].manage_addZSQLMethod + addSQLMethod(id=method_id, title='dummy_method_title', + connection_id='erp5_sql_connection', + template='dummy_method_template', + arguments = 'args' + ) + zsql_method = catalog._getOb(method_id, None) + self.assertTrue(zsql_method is not None) + + self.template.edit(template_catalog_method_id_list=[catalog_id+'/'+method_id]) + self._buildAndExportBusinessTemplate() + + method_document_path = os.path.join(self.cfg.instancehome, self.export_dir, + 'CatalogMethodTemplateItem', + 'portal_catalog', + catalog_id, method_id) + + import_template = self._exportAndReImport( + method_document_path + ".xml", + method_document_path +".sql", + 'dummy_method_template', + ['src']) + + catalog.manage_delObjects([method_id]) + + import_template.install() + + method_page = catalog[method_id] + + for property_id, property_value in method_document_kw.iteritems(): + self.assertEqual(getattr(method_page, property_id), property_value) + + def test_twoFileImportExportForCatalogMethodInPortalSkins(self): + """Test Business Template Import And Export With Catalog Method In Portal Skins""" + + method_id = "z_another_dummy_method" + method_document_kw = {'id': method_id, 'title': 'dummy_method_title', + 'connection_id': 'erp5_sql_connection', + 'arguments_src': 'args', 'src': 'dummy_method_template'} + + skin_folder_id = 'dummy_test_folder' + if skin_folder_id in self.portal.portal_skins.objectIds(): + self.portal.portal_skins.manage_delObjects([skin_folder_id]) + + self.portal.portal_skins.manage_addProduct['OFSP'].\ + manage_addFolder(skin_folder_id) + skin_folder = self.portal.portal_skins[skin_folder_id] + + if method_id in self.portal.objectIds(): + self.portal.manage_delObjects([method_id]) + + addSQLMethod = skin_folder.manage_addProduct['ZSQLMethods'].manage_addZSQLMethod + addSQLMethod(id=method_id, title='dummy_method_title', + connection_id='erp5_sql_connection', + template='dummy_method_template', + arguments = 'args' + ) + + self.template.edit(template_skin_id_list=[skin_folder_id+'/'+method_id,]) + + method_document_path = os.path.join(self.cfg.instancehome, self.export_dir, + 'SkinTemplateItem', 'portal_skins', + skin_folder_id, method_id) + import_template = self._exportAndReImport( + method_document_path+".xml", + method_document_path+".sql", + 'dummy_method_template', + ['src']) + + self.portal.portal_skins[skin_folder_id].manage_delObjects([method_id]) + + import_template.install() + + method_page = skin_folder[method_id] + + for property_id, property_value in method_document_kw.iteritems(): + self.assertEqual(getattr(method_page, property_id), property_value) + + def test_twoFileImportExportForZopePageTemplate(self): + """Test Business Template Import And Export With ZopePageTemplate""" + skin_folder_id = 'dummy_test_folder' + if skin_folder_id in self.portal.portal_skins.objectIds(): + self.portal.portal_skins.manage_delObjects([skin_folder_id]) + + self.portal.portal_skins.manage_addProduct['OFSP'].\ + manage_addFolder(skin_folder_id) + skin_folder = self.portal.portal_skins[skin_folder_id] + + page_template_id = 'dummy_page_template' + if page_template_id in skin_folder.objectIds(): + skin_folder.manage_delObjects([page_template_id]) + page_template_text = '<html></html>' + page_template_kw = {"id": page_template_id, + "_text": page_template_text, + "content_type": "text/html", + "output_encoding": "utf-8"} + skin_folder.manage_addProduct['PageTemplates'].\ + manage_addPageTemplate(id=page_template_id, + text=page_template_text) + + self.template.edit(template_skin_id_list=[skin_folder_id+'/'+page_template_id,]) + + page_template_path = os.path.join(self.cfg.instancehome, self.export_dir, + 'SkinTemplateItem', 'portal_skins',skin_folder_id,page_template_id) + + import_template = self._exportAndReImport( + page_template_path+".xml", + page_template_path+".zpt", + page_template_kw['_text'], + ['_text']) + + self.portal.portal_skins[skin_folder_id].manage_delObjects([page_template_id]) + + import_template.install() + + page_template_page = self.portal.portal_skins[skin_folder_id][page_template_id] + + for property_id, property_value in page_template_kw.iteritems(): + self.assertEqual(getattr(page_template_page, property_id), property_value) + + def test_twoFileImportExportForDTMLMethodIdentifyingTypeByTitle(self): + """ + Test Business Template Import And Export With DTMLMethod where the + extension is identified by the title + """ + skin_folder_id = 'dummy_test_folder' + if skin_folder_id in self.portal.portal_skins.objectIds(): + self.portal.portal_skins.manage_delObjects([skin_folder_id]) + + self.portal.portal_skins.manage_addProduct['OFSP'].manage_addFolder(skin_folder_id) + skin_folder = self.portal.portal_skins[skin_folder_id] + + dtml_method_id = 'dummy_dtml_method' + dtml_method_title = 'dummy_dtml_method.js' + dtml_method_data = 'dummy content' + + dtml_method_kw = {"__name__": dtml_method_id, + "title": dtml_method_title, + "raw": dtml_method_data} + + if dtml_method_id in skin_folder.objectIds(): + skin_folder.manage_delObjects([dtml_method_id]) + + skin_folder.manage_addProduct['DTMLMethods'].\ + manage_addDTMLMethod(id = dtml_method_id, + title = dtml_method_title) + dtml_method = skin_folder[dtml_method_id] + dtml_method.manage_edit(data=dtml_method_data, title = dtml_method_title) + + self.template.edit(template_skin_id_list=[skin_folder_id+'/'+dtml_method_id,]) + + dtml_method_path = os.path.join(self.cfg.instancehome, + self.export_dir, + 'SkinTemplateItem', + 'portal_skins', + skin_folder_id,dtml_method_id) + + import_template = self._exportAndReImport( + dtml_method_path+".xml", + dtml_method_path+".js", + dtml_method_kw['raw'], + ['raw']) + + self.portal.portal_skins[skin_folder_id].manage_delObjects([dtml_method_id]) + + import_template.install() + + dtml_method_page = self.portal.portal_skins[skin_folder_id][dtml_method_id] + + for property_id, property_value in dtml_method_kw.iteritems(): + self.assertEqual(getattr(dtml_method_page, property_id), property_value) + + def test_twoFileImportExportForDTMLMethodNotIdentifyingType(self): + """ + Test Business Template Import And Export With DTMLMethod where the + extension is not identified, so it is exported as '.txt' + """ + skin_folder_id = 'dummy_test_folder' + if skin_folder_id in self.portal.portal_skins.objectIds(): + self.portal.portal_skins.manage_delObjects([skin_folder_id]) + + self.portal.portal_skins.manage_addProduct['OFSP'].\ + manage_addFolder(skin_folder_id) + skin_folder = self.portal.portal_skins[skin_folder_id] + + dtml_method_id = 'dummy_dtml_method' + dtml_method_title = 'dummy_dtml_method' + dtml_method_data = 'dummy content' + + dtml_method_kw = {"__name__": dtml_method_id, + "title": dtml_method_title, + "raw": dtml_method_data} + + if dtml_method_id in skin_folder.objectIds(): + skin_folder.manage_delObjects([dtml_method_id]) + + skin_folder.manage_addProduct['DTMLMethods'].\ + manage_addDTMLMethod(id = dtml_method_id, + title = dtml_method_title) + dtml_method = skin_folder[dtml_method_id] + dtml_method.manage_edit(data=dtml_method_data, title = dtml_method_title) + + self.template.edit(template_skin_id_list=[skin_folder_id+'/'+dtml_method_id,]) + + dtml_method_path = os.path.join(self.cfg.instancehome, self.export_dir, + 'SkinTemplateItem', 'portal_skins', + skin_folder_id,dtml_method_id) + + import_template = self._exportAndReImport( + dtml_method_path+".xml", + dtml_method_path+".txt", + dtml_method_kw['raw'], + ['raw']) + + self.portal.portal_skins[skin_folder_id].manage_delObjects([dtml_method_id]) + + import_template.install() + + dtml_method_page = self.portal.portal_skins[skin_folder_id][dtml_method_id] + + for property_id, property_value in dtml_method_kw.iteritems(): + self.assertEqual(getattr(dtml_method_page, property_id), property_value) + + def test_twoFileImportExportForOOoTemplate(self): + """Test Business Template Import And Export With OOoTemplate""" + skin_folder_id = 'dummy_test_folder' + if skin_folder_id in self.portal.portal_skins.objectIds(): + self.portal.portal_skins.manage_delObjects([skin_folder_id]) + + self.portal.portal_skins.manage_addProduct['OFSP'].\ + manage_addFolder(skin_folder_id) + skin_folder = self.portal.portal_skins[skin_folder_id] + + OOo_template_id = 'dummy_OOo_template' + OOo_template_data = 'dummy OOotemplate content' + + OOo_template_kw = {"id": OOo_template_id, + "_text": OOo_template_data, + "output_encoding": "utf-8", + "content_type": "text/html"} + + if OOo_template_id in skin_folder.objectIds(): + skin_folder.manage_delObjects([OOo_template_id]) + + addOOoTemplate =skin_folder.manage_addProduct['ERP5OOo'].addOOoTemplate + addOOoTemplate(id=OOo_template_id, title=OOo_template_data) + + self.template.edit(template_skin_id_list=[skin_folder_id+'/'+OOo_template_id,]) + + OOo_template_path = os.path.join(self.cfg.instancehome, self.export_dir, + 'SkinTemplateItem', 'portal_skins', + skin_folder_id, OOo_template_id) + + import_template = self._exportAndReImport( + OOo_template_path+".xml", + OOo_template_path+".oot", + OOo_template_kw['_text'], + ['_text']) + + self.portal.portal_skins[skin_folder_id].manage_delObjects([OOo_template_id]) + + import_template.install() + + OOo_template_page = self.portal.portal_skins[skin_folder_id][OOo_template_id] + + for property_id, property_value in OOo_template_kw.iteritems(): + self.assertEqual(getattr(OOo_template_page, property_id), property_value) + + def test_twoFileImportExportForSpreadsheetNotIdentifyingType(self): + """ + Test Business Template Import And Export With Spreadsheed where the + extension is not identified, so it is exported as '.bin' + """ + # XXX addding a dummy string in data leads to 'NotConvertedError' + spreadsheet_data = '' + + spreadsheet_document_kw = {"title": "foo", "data": spreadsheet_data, + "portal_type": "Spreadsheet"} + + self._checkTwoFileImportExportForDocumentInDocumentModule(spreadsheet_document_kw, + '.bin') + + def test_twoFileImportExportForSpreadsheetIdentifyingTypeByContentType(self): + """ + Test Business Template Import And Export With Spreadsheed where the + extension is identified by content_type, so it is exported as '.ods' + """ + # XXX addding a dummy string in data leads to 'NotConvertedError' + spreadsheet_data = '' + + spreadsheet_document_kw = {"title": "foo", "data": spreadsheet_data, + "portal_type": "Spreadsheet", + "content_type": "application/vnd.oasis.opendocument.spreadsheet"} + + self._checkTwoFileImportExportForDocumentInDocumentModule(spreadsheet_document_kw, + '.ods') + + def test_twoFileImportExportForSpreadsheetIdentifyingTypeByTitle(self): + """ + Test Business Template Import And Export With Spreadsheed where the + extension is identified by title, so it is exported as '.xlsx' + """ + # XXX addding a dummy string in data leads to 'NotConvertedError' + spreadsheet_data = '' + + spreadsheet_document_kw = {"title": "foo.xlsx", "data": spreadsheet_data, + "portal_type": "Spreadsheet"} + + self._checkTwoFileImportExportForDocumentInDocumentModule(spreadsheet_document_kw, + '.xlsx') + + def test_templateFolderIsCleanedUpInImportEndReexport(self): + """ + Test that when TemplateTool.importAndReExportBusinessTemplatesFromPath is + invoked the template folder is cleaned. + + 1. Create a bt and export it in a temporary folder + 2. Add to the folder a text file + 3. Add to the folder a sub-folder + 4. Add to the sub-folder a second text file + 5. Add a third file to portal_templates folder + 6. Invoke TemplateTool.importAndReExportBusinessTemplatesFromPath in the + template folder + 7. Assert that only the template elements are present + """ + test_component_kw = {"title": "foo", + "text_content": "def dummy(): pass", + "portal_type": "Test Component"} + + test_document_page = self.portal.\ + portal_components.newContent(**test_component_kw) + test_component_kw['id'] = test_component_id = test_document_page.getId() + + self.template.edit(template_test_id_list=['portal_components/'+test_component_id,]) + + test_component_path = os.path.join(self.cfg.instancehome, self.export_dir, + 'TestTemplateItem', 'portal_components', + test_component_id) + + self._buildAndExportBusinessTemplate() + + self.assertTrue(os.path.exists(os.path.join(self.export_dir, 'bt'))) + self.assertTrue(os.path.exists(test_component_path+'.xml')) + self.assertTrue(os.path.exists(test_component_path+'.py')) + + # create a text file in the root + text_file_name = "text_file.txt" + text_file_path = os.path.join(self.export_dir, text_file_name) + text_file = open(text_file_path, "w") + text_file.close() + self.assertTrue(os.path.exists(text_file_path)) + # create a sub_folder + sub_folder_name = "subfolder" + sub_folder_path = os.path.join(self.export_dir, sub_folder_name) + os.mkdir(sub_folder_path) + self.assertTrue(os.path.exists(sub_folder_path)) + # create another text file in the subfolder + text_file_in_sub_folder_name = "text_file_in_sub_folder.txt" + text_file_in_sub_folder_path = os.path.join(self.export_dir, + text_file_in_sub_folder_name) + text_file_in_sub_folder = open(text_file_in_sub_folder_path, "w") + text_file_in_sub_folder.close() + self.assertTrue(os.path.exists(text_file_in_sub_folder_path)) + # create another text file inside portal components + text_file_in_portal_components_name = "text_file_in_sub_folder.txt" + text_file_in_portal_components_path = os.path.join(self.export_dir, + text_file_in_portal_components_name) + text_file_in_portal_components = open(text_file_in_sub_folder_path, "w") + text_file_in_portal_components.close() + self.assertTrue(os.path.exists(text_file_in_portal_components_path)) + # invoke importAndReExportBusinessTemplatesFromPath + self.template_tool.importAndReExportBusinessTemplatesFromPath(repository_list=['/tmp']) + self.tic() + # assert that unrelated objects were deleted + self.assertFalse(os.path.exists(text_file_path)) + self.assertFalse(os.path.exists(sub_folder_path)) + self.assertFalse(os.path.exists(text_file_in_sub_folder_path)) + self.assertFalse(os.path.exists(text_file_in_portal_components_path)) + # assert that related objects exist + self.assertTrue(os.path.exists(os.path.join(self.export_dir, 'bt'))) + self.assertTrue(os.path.exists(test_component_path+'.xml')) + self.assertTrue(os.path.exists(test_component_path+'.py')) -- 2.30.9