[Erp5-report] r37133 ivan - in /erp5/trunk/products/ERP5: Document/ interfaces/ mixin/
nobody at svn.erp5.org
nobody at svn.erp5.org
Thu Jul 15 15:13:46 CEST 2010
Author: ivan
Date: Thu Jul 15 15:13:44 2010
New Revision: 37133
URL: http://svn.erp5.org?rev=37133&view=rev
Log:
Introduce IExtensibleTraverSable and its implementation for Document & OOoDocument classes.
Added:
erp5/trunk/products/ERP5/interfaces/extensible_traversable.py
erp5/trunk/products/ERP5/mixin/extensible_traversable.py
Modified:
erp5/trunk/products/ERP5/Document/Document.py
erp5/trunk/products/ERP5/Document/WebSection.py
Modified: erp5/trunk/products/ERP5/Document/Document.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/Document/Document.py?rev=37133&r1=37132&r2=37133&view=diff
==============================================================================
--- erp5/trunk/products/ERP5/Document/Document.py [utf8] (original)
+++ erp5/trunk/products/ERP5/Document/Document.py [utf8] Thu Jul 15 15:13:44 2010
@@ -59,6 +59,7 @@ from Products.ERP5.mixin.cached_converta
from Products.ERP5.mixin.text_convertable import TextConvertableMixin
from Products.ERP5.mixin.downloadable import DownloadableMixin
from Products.ERP5.mixin.document import DocumentMixin
+from Products.ERP5.mixin.extensible_traversable import DocumentExtensibleTraversableMixIn
_MARKER = []
VALID_ORDER_KEY_LIST = ('user_login', 'content', 'file_name', 'input')
@@ -128,129 +129,6 @@ class DocumentProxyError(Exception):pass
class NotConvertedError(Exception):pass
allow_class(NotConvertedError)
-class PermanentURLMixIn(ExtensibleTraversableMixIn):
- """
- Provides access to documents through their permanent URL.
- This class must be inherited by all document classes so
- that documents displayed outside a Web Site / Web Section
- can also use the permanent URL principle.
- """
-
- # Declarative security
- security = ClassSecurityInfo()
-
- def _forceIdentification(self, request):
- # force identification (usable for extensible content)
- cache = getReadOnlyTransactionCache(self)
- if cache is not None:
- key = ('__bobo_traverse__', self, 'user')
- try:
- user = cache[key]
- except KeyError:
- user = _MARKER
- else:
- user = _MARKER
- old_user = getSecurityManager().getUser()
- if user is _MARKER:
- user = None # By default, do nothing
- if old_user is None or old_user.getUserName() == 'Anonymous User':
- user_folder = getattr(self.getPortalObject(), 'acl_users', None)
- if user_folder is not None:
- try:
- if request.get('PUBLISHED', _MARKER) is _MARKER:
- # request['PUBLISHED'] is required by validate
- request['PUBLISHED'] = self
- has_published = False
- else:
- has_published = True
- try:
- user = user_folder.validate(request)
- except AttributeError:
- # This kind of error happens with unrestrictedTraverse,
- # because the request object is a fake, and it is just
- # a dict object.
- user = None
- if not has_published:
- try:
- del request.other['PUBLISHED']
- except AttributeError:
- # The same here as above. unrestrictedTraverse provides
- # just a plain dict, so request.other does not exist.
- del request['PUBLISHED']
- except:
- LOG("ERP5 WARNING",0,
- "Failed to retrieve user in __bobo_traverse__ of WebSection %s" % self.getPath(),
- error=sys.exc_info())
- user = None
- if user is not None and user.getUserName() == 'Anonymous User':
- user = None # If the user which is connected is anonymous,
- # do not try to change SecurityManager
- if cache is not None:
- cache[key] = user
-
- old_manager = None
- if user is not None:
- # We need to perform identification
- old_manager = getSecurityManager()
- newSecurityManager(get_request(), user)
-
- return old_manager, user
-
- ### Extensible content
- def _getExtensibleContent(self, request, name):
- # Permanent URL traversal
- old_manager, user = self._forceIdentification(request)
- # Next get the document per name
- portal = self.getPortalObject()
- document = self.getDocumentValue(name=name, portal=portal)
- # restore original security context if there's a logged in user
- if user is not None:
- setSecurityManager(old_manager)
- if document is not None:
- document = aq_base(document.asContext(id=name, # Hide some properties to permit locating the original
- original_container=document.getParentValue(),
- original_id=document.getId(),
- editable_absolute_url=document.absolute_url()))
- return document.__of__(self)
-
- # no document found for current user, still such document may exists
- # in some cases user (like Anonymous) can not view document according to portal catalog
- # but we may ask him to login if such a document exists
- isAuthorizationForced = getattr(self, 'isAuthorizationForced', None)
- if isAuthorizationForced is not None and isAuthorizationForced():
- if unrestricted_apply(self.getDocumentValue, (name, portal)) is not None:
- # force user to login as specified in Web Section
- raise Unauthorized
-
- security.declareProtected(Permissions.View, 'getDocumentValue')
- def getDocumentValue(self, name=None, portal=None, **kw):
- """
- Return the default document with the given
- name. The name parameter may represent anything
- such as a document reference, an identifier,
- etc.
-
- If name is not provided, the method defaults
- to returning the default document by calling
- getDefaultDocumentValue.
-
- kw parameters can be useful to filter content
- (ex. force a given validation state)
-
- This method must be implemented through a
- portal type dependent script:
- WebSection_getDocumentValue
- """
- if name is None:
- return self.getDefaultDocumentValue()
-
- method = self._getTypeBasedMethod('getDocumentValue',
- fallback_script_id='WebSection_getDocumentValue')
-
- document = method(name, portal=portal, **kw)
- if document is not None:
- return document.__of__(self)
-
class DocumentProxyMixin:
"""
Provides access to documents referenced by the follow_up field
@@ -329,7 +207,7 @@ class UpdateMixIn:
return method()
-class Document(PermanentURLMixIn, XMLObject, UrlMixIn, CachedConvertableMixin,
+class Document(DocumentExtensibleTraversableMixIn, XMLObject, UrlMixIn, CachedConvertableMixin,
SnapshotMixin, UpdateMixIn, TextConvertableMixin,
DownloadableMixin, DocumentMixin):
"""Document is an abstract class with all methods related to document
Modified: erp5/trunk/products/ERP5/Document/WebSection.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/Document/WebSection.py?rev=37133&r1=37132&r2=37133&view=diff
==============================================================================
--- erp5/trunk/products/ERP5/Document/WebSection.py [utf8] (original)
+++ erp5/trunk/products/ERP5/Document/WebSection.py [utf8] Thu Jul 15 15:13:44 2010
@@ -30,8 +30,8 @@
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet
from Products.ERP5.Document.Domain import Domain
-from Products.ERP5.Document.Document import PermanentURLMixIn
-from Acquisition import aq_base, aq_inner
+from Products.ERP5.mixin.extensible_traversable import DocumentExtensibleTraversableMixIn as PermanentURLMixIn
+from Acquisition import aq_base, aq_inner
from Products.ERP5Type.UnrestrictedMethod import unrestricted_apply
from AccessControl import Unauthorized
from OFS.Traversable import NotFound
Added: erp5/trunk/products/ERP5/interfaces/extensible_traversable.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/interfaces/extensible_traversable.py?rev=37133&view=auto
==============================================================================
--- erp5/trunk/products/ERP5/interfaces/extensible_traversable.py (added)
+++ erp5/trunk/products/ERP5/interfaces/extensible_traversable.py [utf8] Thu Jul 15 15:13:44 2010
@@ -0,0 +1,53 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Copyright (c) 2009 Nexedi SA and Contributors. All Rights Reserved.
+# Ivan Tyagov <ivan at 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.
+#
+##############################################################################
+
+from zope.interface import Interface
+
+class ILegacyExtensibleTraversable(Interface):
+ """
+ Extensible Traversable legacy interface specification
+ """
+
+ def _getExtensibleContent(request, name):
+ """
+ Return extensible subcontent of context document during traversal.
+ """
+
+class IExtensibleTraversable(ILegacyExtensibleTraversable):
+ """
+ Extensible Traversable interface specification
+
+ IExtensibleTraversable provides methods so a document may become a container for extensible content
+ during traversal.
+ """
+
+ def getExtensibleContent(request, name):
+ """
+ Return extensible subcontent of context document during traversal.
+ """
\ No newline at end of file
Added: erp5/trunk/products/ERP5/mixin/extensible_traversable.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/mixin/extensible_traversable.py?rev=37133&view=auto
==============================================================================
--- erp5/trunk/products/ERP5/mixin/extensible_traversable.py (added)
+++ erp5/trunk/products/ERP5/mixin/extensible_traversable.py [utf8] Thu Jul 15 15:13:44 2010
@@ -0,0 +1,208 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Copyright (c) 2009 Nexedi SA and Contributors. All Rights Reserved.
+# Ivan Tyagov <ivan at 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.
+#
+##############################################################################
+
+from zLOG import LOG
+from Acquisition import aq_base
+from Products.ERP5Type.Globals import get_request
+from AccessControl import Unauthorized
+from Products.ERP5Type.ExtensibleTraversable import ExtensibleTraversableMixIn
+from Products.ERP5Type.Cache import getReadOnlyTransactionCache
+from AccessControl import ClassSecurityInfo, getSecurityManager
+from AccessControl.SecurityManagement import newSecurityManager, setSecurityManager
+from Products.ERP5Type import Permissions
+from Products.CMFCore.utils import getToolByName, _setCacheHeaders, _ViewEmulator
+from OFS.Image import File as OFSFile
+from warnings import warn
+
+
+# XXX: these duplicate ones in ERP5.Document
+_MARKER = []
+EMBEDDED_FORMAT = '_embedded'
+class ConversionError(Exception):pass
+class DocumentProxyError(Exception):pass
+class NotConvertedError(Exception):pass
+
+class BaseExtensibleTraversableMixIn(ExtensibleTraversableMixIn):
+ """
+ This class provides a generic base mixin implementation of IExtensibleTraversable.
+
+ Provides access to documents through their permanent URL.
+ This class shoulf be used as a base mixin class using which can be used create
+ "extensible" mixin classes.
+ """
+
+ def _getExtensibleContent(self, request, name):
+ """
+ Legacy API
+ """
+ warn("_getExtensibleContent() function is deprecated. Use getExtensibleContent() instead.", \
+ DeprecationWarning, stacklevel=2)
+ return self.getExtensibleContent(request, name)
+
+ # Declarative security
+ security = ClassSecurityInfo()
+
+ def _forceIdentification(self, request):
+ # force identification (usable for extensible content)
+ cache = getReadOnlyTransactionCache(self)
+ if cache is not None:
+ key = ('__bobo_traverse__', self, 'user')
+ try:
+ user = cache[key]
+ except KeyError:
+ user = _MARKER
+ else:
+ user = _MARKER
+ old_user = getSecurityManager().getUser()
+ if user is _MARKER:
+ user = None # By default, do nothing
+ if old_user is None or old_user.getUserName() == 'Anonymous User':
+ user_folder = getattr(self.getPortalObject(), 'acl_users', None)
+ if user_folder is not None:
+ try:
+ if request.get('PUBLISHED', _MARKER) is _MARKER:
+ # request['PUBLISHED'] is required by validate
+ request['PUBLISHED'] = self
+ has_published = False
+ else:
+ has_published = True
+ try:
+ user = user_folder.validate(request)
+ except AttributeError:
+ # This kind of error happens with unrestrictedTraverse,
+ # because the request object is a fake, and it is just
+ # a dict object.
+ user = None
+ if not has_published:
+ try:
+ del request.other['PUBLISHED']
+ except AttributeError:
+ # The same here as above. unrestrictedTraverse provides
+ # just a plain dict, so request.other does not exist.
+ del request['PUBLISHED']
+ except:
+ LOG("ERP5 WARNING",0,
+ "Failed to retrieve user in __bobo_traverse__ of WebSection %s" % self.getPath(),
+ error=sys.exc_info())
+ user = None
+ if user is not None and user.getUserName() == 'Anonymous User':
+ user = None # If the user which is connected is anonymous,
+ # do not try to change SecurityManager
+ if cache is not None:
+ cache[key] = user
+
+ old_manager = None
+ if user is not None:
+ # We need to perform identification
+ old_manager = getSecurityManager()
+ newSecurityManager(get_request(), user)
+
+ return old_manager, user
+
+ security.declareProtected(Permissions.View, 'getDocumentValue')
+ def getDocumentValue(self, name=None, portal=None, **kw):
+ """
+ Return the default document with the given
+ name. The name parameter may represent anything
+ such as a document reference, an identifier,
+ etc.
+
+ If name is not provided, the method defaults
+ to returning the default document by calling
+ getDefaultDocumentValue.
+
+ kw parameters can be useful to filter content
+ (ex. force a given validation state)
+
+ This method must be implemented through a
+ portal type dependent script:
+ WebSection_getDocumentValue
+ """
+ if name is None:
+ return self.getDefaultDocumentValue()
+
+ method = self._getTypeBasedMethod('getDocumentValue',
+ fallback_script_id='WebSection_getDocumentValue')
+
+ document = method(name, portal=portal, **kw)
+ if document is not None:
+ return document.__of__(self)
+
+class DocumentExtensibleTraversableMixIn(BaseExtensibleTraversableMixIn):
+ """
+ This class provides a implementation of IExtensibleTraversable for Document classed based documents.
+ """
+
+ def getExtensibleContent(self, request, name):
+ old_manager, user = self._forceIdentification(request)
+ # Next get the document per name
+ portal = self.getPortalObject()
+ document = self.getDocumentValue(name=name, portal=portal)
+ # restore original security context if there's a logged in user
+ if user is not None:
+ setSecurityManager(old_manager)
+ if document is not None:
+ document = aq_base(document.asContext(id=name, # Hide some properties to permit locating the original
+ original_container=document.getParentValue(),
+ original_id=document.getId(),
+ editable_absolute_url=document.absolute_url()))
+ return document.__of__(self)
+
+ # no document found for current user, still such document may exists
+ # in some cases user (like Anonymous) can not view document according to portal catalog
+ # but we may ask him to login if such a document exists
+ isAuthorizationForced = getattr(self, 'isAuthorizationForced', None)
+ if isAuthorizationForced is not None and isAuthorizationForced():
+ if unrestricted_apply(self.getDocumentValue, (name, portal)) is not None:
+ # force user to login as specified in Web Section
+ raise Unauthorized
+
+class OOoDocumentExtensibleTraversableMixIn(BaseExtensibleTraversableMixIn):
+ """
+ This class provides a implementation of IExtensibleTraversable for OOoDocument classed based documents.
+ """
+
+ def getExtensibleContent(self, request, name):
+ # Be sure that html conversion is done,
+ # as it is required to extract extensible content
+ old_manager, user = self._forceIdentification(request)
+ web_cache_kw = {'name': name,
+ 'format': EMBEDDED_FORMAT}
+ try:
+ self._convert(format='html')
+ _setCacheHeaders(_ViewEmulator().__of__(self), web_cache_kw)
+ mime, data = self.getConversion(format=EMBEDDED_FORMAT, file_name=name)
+ document = OFSFile(name, name, data, content_type=mime).__of__(self.aq_parent)
+ except (NotConvertedError, ConversionError, KeyError):
+ document = DocumentExtensibleTraversableMixIn._getExtensibleContent(self, request, name)
+ # restore original security context if there's a logged in user
+ if user is not None:
+ setSecurityManager(old_manager)
+ return document
+
\ No newline at end of file
More information about the Erp5-report
mailing list