From decf8d395048c2ec819f028e3fb2e41deb11aadc Mon Sep 17 00:00:00 2001 From: Arnaud Fontaine <arnaud.fontaine@nexedi.com> Date: Fri, 21 Aug 2020 12:47:57 +0900 Subject: [PATCH] ZODB Components: Migrate ContributionTool from filesystem. --- product/ERP5/__init__.py | 3 +- .../document.erp5.Document.py | 2 +- .../tool.erp5.ContributionTool.py} | 66 +---------- .../tool.erp5.ContributionTool.xml | 110 ++++++++++++++++++ .../bt/template_tool_component_id_list | 1 + product/ERP5Type/ZopePatch.py | 1 + product/ERP5Type/patches/urllib_opener.py | 89 ++++++++++++++ 7 files changed, 207 insertions(+), 65 deletions(-) rename product/ERP5/{Tool/ContributionTool.py => bootstrap/erp5_core/ToolComponentTemplateItem/portal_components/tool.erp5.ContributionTool.py} (91%) create mode 100644 product/ERP5/bootstrap/erp5_core/ToolComponentTemplateItem/portal_components/tool.erp5.ContributionTool.xml create mode 100644 product/ERP5Type/patches/urllib_opener.py diff --git a/product/ERP5/__init__.py b/product/ERP5/__init__.py index 75f9ba7bc2..9d38d4288a 100644 --- a/product/ERP5/__init__.py +++ b/product/ERP5/__init__.py @@ -43,7 +43,7 @@ product_path = package_home( globals() ) # Define object classes and tools from Tool import CategoryTool, IdTool, TemplateTool,\ AlarmTool,\ - TrashTool, ContributionTool,\ + TrashTool,\ SolverTool import ERP5Site from Document import PythonScript, SQLMethod @@ -56,7 +56,6 @@ portal_tools = ( CategoryTool.CategoryTool, TemplateTool.TemplateTool, AlarmTool.AlarmTool, TrashTool.TrashTool, - ContributionTool.ContributionTool, SolverTool.SolverTool, ) content_classes = () diff --git a/product/ERP5/bootstrap/erp5_core/DocumentTemplateItem/portal_components/document.erp5.Document.py b/product/ERP5/bootstrap/erp5_core/DocumentTemplateItem/portal_components/document.erp5.Document.py index 8ed2ae6fb0..317074e2e7 100644 --- a/product/ERP5/bootstrap/erp5_core/DocumentTemplateItem/portal_components/document.erp5.Document.py +++ b/product/ERP5/bootstrap/erp5_core/DocumentTemplateItem/portal_components/document.erp5.Document.py @@ -37,7 +37,7 @@ from Products.ERP5Type import Permissions, PropertySheet from Products.ERP5Type.XMLObject import XMLObject from Products.ERP5Type.Utils import deprecated, guessEncodingFromText from Products.ERP5Type.TransactionalVariable import getTransactionalVariable -from Products.ERP5.Tool.ContributionTool import MAX_REPEAT +from erp5.component.tool.ContributionTool import MAX_REPEAT from Products.ZSQLCatalog.SQLCatalog import Query, NegatedQuery from AccessControl import Unauthorized import zope.interface diff --git a/product/ERP5/Tool/ContributionTool.py b/product/ERP5/bootstrap/erp5_core/ToolComponentTemplateItem/portal_components/tool.erp5.ContributionTool.py similarity index 91% rename from product/ERP5/Tool/ContributionTool.py rename to product/ERP5/bootstrap/erp5_core/ToolComponentTemplateItem/portal_components/tool.erp5.ContributionTool.py index cdbdfdd282..65951067af 100644 --- a/product/ERP5/Tool/ContributionTool.py +++ b/product/ERP5/bootstrap/erp5_core/ToolComponentTemplateItem/portal_components/tool.erp5.ContributionTool.py @@ -29,7 +29,6 @@ import cStringIO import re -import socket import urllib2, urllib import urlparse from cgi import parse_header @@ -48,67 +47,9 @@ from AccessControl import Unauthorized from DateTime import DateTime import warnings -# Install openers -import dircache -import mimetypes, mimetools -from email.utils import formatdate -class DirectoryFileHandler(urllib2.FileHandler): - """ - Extends the file handler to provide an HTML - representation of local directories. - """ - - # Use local file or FTP depending on form of URL - def file_open(self, req): - url = req.get_selector() - if url[:2] == '//' and url[2:3] != '/': - req.type = 'ftp' - return self.parent.open(req) - else: - return self.open_local_file(req) - - # not entirely sure what the rules are here - def open_local_file(self, req): - host = req.get_host() - file = req.get_selector() - localfile = urllib2.url2pathname(file) - stats = os.stat(localfile) - size = stats.st_size - modified = formatdate(stats.st_mtime, usegmt=True) - mtype = mimetypes.guess_type(file)[0] - headers = mimetools.Message(cStringIO.StringIO( - 'Content-type: %s\nContent-length: %d\nLast-modified: %s\n' % - (mtype or 'text/plain', size, modified))) - if host: - host, port = urllib.splitport(host) - if not host or \ - (not port and socket.gethostbyname(host) in self.get_names()): - try: - file_list = dircache.listdir(localfile) - s = cStringIO.StringIO() - s.write('<html><head><base href="%s"/></head><body>' % ('file:' + file)) - s.write('<p>Directory Content:</p>') - for f in file_list: - s.write('<p><a href="%s">%s</a></p>\n' % (urllib.quote(f), f)) - s.write('</body></html>') - s.seek(0) - headers = mimetools.Message(cStringIO.StringIO( - 'Content-type: %s\nContent-length: %d\nLast-modified: %s\n' % - ('text/html', size, modified))) - return urllib2.addinfourl(s, headers, 'file:' + file) - except OSError: - return urllib2.addinfourl(open(localfile, 'rb'), - headers, 'file:'+file) - raise urllib2.URLError('file not on local host') -opener = urllib2.build_opener(DirectoryFileHandler) -urllib2.install_opener(opener) - # Global parameters -TEMP_NEW_OBJECT_KEY = '_v_new_object' MAX_REPEAT = 10 -_marker = [] # Create a new marker object. - class ContributionTool(BaseTool): """ ContributionTool provides an abstraction layer to unify the contribution @@ -254,7 +195,7 @@ class ContributionTool(BaseTool): filename=filename, content_type=content_type) if not (container is None or container.isModuleType() or container.getTypeInfo().allowType(portal_type)): - portal_type = 'Embedded File' + portal_type = 'Embedded File' if container is None: # If the portal_type was provided, we can go faster @@ -410,6 +351,7 @@ class ContributionTool(BaseTool): return self.getPropertyDictFromFilename(filename) # WebDAV virtual folder support + # pylint: disable=arguments-differ,redefined-builtin def _setObject(self, id, ob, portal_type=None, user_login=None, container=None, discover_metadata=True, filename=None, input_parameter_dict=None): @@ -607,7 +549,7 @@ class ContributionTool(BaseTool): try: url = content.asURL() file_object, filename, content_type = self._openURL(url) - except urllib2.URLError, error: + except urllib2.URLError: if repeat == 0 or not batch_mode: # XXX - Call the extendBadURLList method,--NOT Implemented-- raise @@ -656,7 +598,7 @@ class ContributionTool(BaseTool): elif document.getCrawlingDepth() > 0: # If this is an index document, stop crawling if crawling_depth is 0 document.activate().crawlContent() - except urllib2.HTTPError, error: + except urllib2.HTTPError: if repeat == 0 or not batch_mode: # here we must call the extendBadURLList method,--NOT Implemented-- # which had to add this url to bad URL list, so next time we avoid diff --git a/product/ERP5/bootstrap/erp5_core/ToolComponentTemplateItem/portal_components/tool.erp5.ContributionTool.xml b/product/ERP5/bootstrap/erp5_core/ToolComponentTemplateItem/portal_components/tool.erp5.ContributionTool.xml new file mode 100644 index 0000000000..41a8942035 --- /dev/null +++ b/product/ERP5/bootstrap/erp5_core/ToolComponentTemplateItem/portal_components/tool.erp5.ContributionTool.xml @@ -0,0 +1,110 @@ +<?xml version="1.0"?> +<ZopeData> + <record id="1" aka="AAAAAAAAAAE="> + <pickle> + <global name="Tool Component" module="erp5.portal_type"/> + </pickle> + <pickle> + <dictionary> + <item> + <key> <string>default_reference</string> </key> + <value> <string>ContributionTool</string> </value> + </item> + <item> + <key> <string>default_source_reference</string> </key> + <value> <string>Products.ERP5.Tool.ContributionTool</string> </value> + </item> + <item> + <key> <string>description</string> </key> + <value> + <none/> + </value> + </item> + <item> + <key> <string>id</string> </key> + <value> <string>tool.erp5.ContributionTool</string> </value> + </item> + <item> + <key> <string>portal_type</string> </key> + <value> <string>Tool Component</string> </value> + </item> + <item> + <key> <string>sid</string> </key> + <value> + <none/> + </value> + </item> + <item> + <key> <string>text_content_error_message</string> </key> + <value> + <tuple/> + </value> + </item> + <item> + <key> <string>text_content_warning_message</string> </key> + <value> + <tuple/> + </value> + </item> + <item> + <key> <string>version</string> </key> + <value> <string>erp5</string> </value> + </item> + <item> + <key> <string>workflow_history</string> </key> + <value> + <persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent> + </value> + </item> + </dictionary> + </pickle> + </record> + <record id="2" aka="AAAAAAAAAAI="> + <pickle> + <global name="PersistentMapping" module="Persistence.mapping"/> + </pickle> + <pickle> + <dictionary> + <item> + <key> <string>data</string> </key> + <value> + <dictionary> + <item> + <key> <string>component_validation_workflow</string> </key> + <value> + <persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent> + </value> + </item> + </dictionary> + </value> + </item> + </dictionary> + </pickle> + </record> + <record id="3" aka="AAAAAAAAAAM="> + <pickle> + <global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/> + </pickle> + <pickle> + <dictionary> + <item> + <key> <string>_log</string> </key> + <value> + <list> + <dictionary> + <item> + <key> <string>action</string> </key> + <value> <string>validate</string> </value> + </item> + <item> + <key> <string>validation_state</string> </key> + <value> <string>validated</string> </value> + </item> + </dictionary> + </list> + </value> + </item> + </dictionary> + </pickle> + </record> +</ZopeData> diff --git a/product/ERP5/bootstrap/erp5_core/bt/template_tool_component_id_list b/product/ERP5/bootstrap/erp5_core/bt/template_tool_component_id_list index 07e43f184d..a0b0e927ef 100644 --- a/product/ERP5/bootstrap/erp5_core/bt/template_tool_component_id_list +++ b/product/ERP5/bootstrap/erp5_core/bt/template_tool_component_id_list @@ -2,6 +2,7 @@ tool.erp5.AcknowledgementTool tool.erp5.BuilderTool tool.erp5.CallableTool tool.erp5.ContributionRegistryTool +tool.erp5.ContributionTool tool.erp5.DeliveryTool tool.erp5.DiffTool tool.erp5.DomainTool diff --git a/product/ERP5Type/ZopePatch.py b/product/ERP5Type/ZopePatch.py index 86f9e9ba4c..d1a1061cb8 100644 --- a/product/ERP5Type/ZopePatch.py +++ b/product/ERP5Type/ZopePatch.py @@ -91,6 +91,7 @@ from Products.ERP5Type.patches import MimetypesRegistry from Products.ERP5Type.patches import users from Products.ERP5Type.patches import Publish from Products.ERP5Type.patches import WSGITask +from Products.ERP5Type.patches import urllib_opener # These symbols are required for backward compatibility from Products.ERP5Type.patches.PropertyManager import ERP5PropertyManager diff --git a/product/ERP5Type/patches/urllib_opener.py b/product/ERP5Type/patches/urllib_opener.py new file mode 100644 index 0000000000..24ebc02afc --- /dev/null +++ b/product/ERP5Type/patches/urllib_opener.py @@ -0,0 +1,89 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Copyright (c) 2007 Nexedi SARL and Contributors. All Rights Reserved. +# Jean-Paul Smets <jp@nexedi.com> +# +# WARNING: This program as such is intended to be used by professional +# programmers who take the whole responsability 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 +# garantees 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 +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +############################################################################## + +# Install openers +# -> testTemplateTool.TestTemplateTool.test_getBusinessTemplateUrl +import urllib +import urllib2 +import cStringIO +import socket +import os +import dircache +import mimetypes, mimetools +from email.utils import formatdate +class DirectoryFileHandler(urllib2.FileHandler): + """ + Extends the file handler to provide an HTML + representation of local directories. + """ + + # Use local file or FTP depending on form of URL + def file_open(self, req): + url = req.get_selector() + if url[:2] == '//' and url[2:3] != '/': + req.type = 'ftp' + return self.parent.open(req) + else: + return self.open_local_file(req) + + # not entirely sure what the rules are here + def open_local_file(self, req): + host = req.get_host() + file = req.get_selector() + localfile = urllib2.url2pathname(file) + stats = os.stat(localfile) + size = stats.st_size + modified = formatdate(stats.st_mtime, usegmt=True) + mtype = mimetypes.guess_type(file)[0] + headers = mimetools.Message(cStringIO.StringIO( + 'Content-type: %s\nContent-length: %d\nLast-modified: %s\n' % + (mtype or 'text/plain', size, modified))) + if host: + host, port = urllib.splitport(host) + if not host or \ + (not port and socket.gethostbyname(host) in self.get_names()): + try: + file_list = dircache.listdir(localfile) + s = cStringIO.StringIO() + s.write('<html><head><base href="%s"/></head><body>' % ('file:' + file)) + s.write('<p>Directory Content:</p>') + for f in file_list: + s.write('<p><a href="%s">%s</a></p>\n' % (urllib.quote(f), f)) + s.write('</body></html>') + s.seek(0) + headers = mimetools.Message(cStringIO.StringIO( + 'Content-type: %s\nContent-length: %d\nLast-modified: %s\n' % + ('text/html', size, modified))) + return urllib2.addinfourl(s, headers, 'file:' + file) + except OSError: + return urllib2.addinfourl(open(localfile, 'rb'), + headers, 'file:'+file) + raise urllib2.URLError('file not on local host') +opener = urllib2.build_opener(DirectoryFileHandler) +urllib2.install_opener(opener) -- 2.30.9