diff --git a/product/ERP5/Document/WebSection.py b/product/ERP5/Document/WebSection.py index 4dd0e0aa450550cdf5d1d57fa0e0ff9762b30f4e..e0f7211f335f470253417e1e73645983cd2ed1a2 100644 --- a/product/ERP5/Document/WebSection.py +++ b/product/ERP5/Document/WebSection.py @@ -1,6 +1,15 @@ ############################################################################## # +# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved. # Copyright (c) 2002-2006 Nexedi SARL and Contributors. All Rights Reserved. +# Copyright (c) 2006-2007 Nexedi SA and Contributors. All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. # # WARNING: This program as such is intended to be used by professional # programmers who take the whole responsability of assessing all potential @@ -9,20 +18,6 @@ # 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 AccessControl import ClassSecurityInfo @@ -37,44 +32,13 @@ from Products.ERP5Type.Base import TempBase from Globals import get_request from zLOG import LOG, WARNING +import sys from Products.ERP5Type.Cache import getReadOnlyTransactionCache # Global keys used for URL generation WEBSECTION_KEY = 'web_section_value' -WEBSITE_USER = 'web_site_user' - -Domain_getattr = Domain.inheritedAttribute('__getattr__') - -# We use a request key (CACHE_KEY) to store access attributes and prevent infinite recursion -# We define a couple of reserved names for which we are not -# going to try to do acquisition -CACHE_KEY = 'web_site_aq_cache' -DOCUMENT_NAME_KEY = 'web_section_document_name' -reserved_name_dict = { 'getApplicableLayout' : 1, - 'getWebmaster' : 1, - 'getContainerLayout': 1, - 'isWebMode' : 1, - 'getLayout' : 1, - 'Localizer' : 1, - 'field_render' : 1, - 'getListItemUrl' : 1, - 'getLocalPropertyManager' : 1, - 'getOrderedGlobalActionList' : 1, - 'allow_discussion' : 1, - 'im_func' : 1, - 'im_self' : 1, - 'ListBox_asHTML' : 1, - 'id' : 1, - 'method_id' : 1, - 'role_map' : 1, - 'func_defaults': 1, - '_v_section_webmaster': 1, - 'priority': 1, - 'to_processing_date': 1, - 'categories': 1, - } -reserved_name_dict_init = 0 +MARKER = [] class WebSection(Domain): """ @@ -129,17 +93,14 @@ class WebSection(Domain): web_section_key = WEBSECTION_KEY - def _aq_dynamic(self, name): + security.declareProtected(Permissions.View, '__bobo_traverse__') + def __bobo_traverse__(self, request, name): """ - Try to find a suitable document based on the - web site local naming policies as defined by - the getDocumentValue method + If no subobject is found through Folder API + then try to lookup the object by invoking getDocumentValue """ - global reserved_name_dict_init - global reserved_name_dict - request = self.REQUEST # Register current web site physical path for later URL generation - if not request.has_key(self.web_section_key): + if request.get(self.web_section_key, MARKER) is MARKER: request[self.web_section_key] = self.getPhysicalPath() # Normalize web parameter in the request # Fix common user mistake and transform '1' string to boolean @@ -149,66 +110,83 @@ class WebSection(Domain): request.set(web_param, True) else: request.set(web_param, False) - # First let us call the super method - dynamic = Domain._aq_dynamic(self, name) - if dynamic is not None: - return dynamic - # Do some optimisation here for names which can not be names of documents - if reserved_name_dict.has_key(name) \ - or name.endswith('_getDocumentValue') \ - or name.startswith('_') or name.startswith('portal_')\ - or name.startswith('aq_') or name.startswith('selection_') \ - or name.startswith('sort-') or name.startswith('WebSite_') \ - or name.startswith('WebSection_') or name.startswith('Base_'): - return None - if not reserved_name_dict_init: - # Feed reserved_name_dict_init with skin names - portal = self.getPortalObject() - for skin_folder in portal.portal_skins.objectValues(): - for id in skin_folder.objectIds(): - reserved_name_dict[id] = 1 - for id in portal.objectIds(): - reserved_name_dict[id] = 1 - reserved_name_dict_init = 1 - #LOG('aq_dynamic name',0, name) - if not request.has_key(CACHE_KEY): - request[CACHE_KEY] = {} - elif request[CACHE_KEY].has_key(name): - return request[CACHE_KEY][name] + + # Normal traversal + try: + return getattr(self, name) + except AttributeError: + pass + try: - portal = self.getPortalObject() - # Use the webmaster identity to find documents - if request[CACHE_KEY].has_key(WEBSITE_USER): - user = request[CACHE_KEY][WEBSITE_USER] # Retrieve user from request cache - else: - # Cache webmaster for faster lookup - if not hasattr(aq_base(self), '_v_section_webmaster'): - self._v_section_webmaster = self.getWebmaster() - user = portal.acl_users.getUserById(self._v_section_webmaster) - request[CACHE_KEY][WEBSITE_USER] = user # Cache user per request - if user is not None: - old_manager = getSecurityManager() - newSecurityManager(get_request(), user) - else: - LOG('WebSection _aq_dynamic', WARNING, 'No user defined for %s.' - 'This will prevent accessing object through their permanent URL' % self.getWebmaster()) - #LOG('Lookup', 0, str(name)) - document = self.getDocumentValue(name=name, portal=portal) - request[CACHE_KEY][name] = document - if user is not None: - setSecurityManager(old_manager) - except: - # Cleanup non recursion dict in case of exception - if request[CACHE_KEY].has_key(name): - del request[CACHE_KEY][name] - raise + return self[name] + except KeyError: + pass + + # Permanent URL traversal + # First we must get the logged user by forcing identification + cache = getReadOnlyTransactionCache(self) + # LOG('getReadOnlyTransactionCache', 0, repr(cache)) # Currently, it is always None + 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 = getToolByName(self, 'acl_users', None) + if user_folder is not None: + try: + if request.get('PUBLISHED', MARKER) is MARKER: + # request['PUBLISHED'] is required by validate + request.other['PUBLISHED'] = self + has_published = False + else: + has_published = True + user = user_folder.validate(request) + if not has_published: + del request.other['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 + if user is not None: + # We need to perform identification + old_manager = getSecurityManager() + newSecurityManager(get_request(), user) + # Next get the document per name + portal = self.getPortalObject() + document = self.getDocumentValue(name=name, portal=portal) + # Last, cleanup everything + if user is not None: + setSecurityManager(old_manager) if document is not None: - request[DOCUMENT_NAME_KEY] = name - document = aq_base(document.asContext(id=name, # Hide some properties to permit location the original + 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 + return document.__of__(self) + + # Not found section + method = request.get('REQUEST_METHOD', 'GET') + if not method in ('GET', 'POST'): + return NullResource(self, name, request).__of__(self) + # Waaa. unrestrictedTraverse calls us with a fake REQUEST. + # There is proabably a better fix for this. + try: + request.RESPONSE.notFoundError("%s\n%s" % (name, method)) + except AttributeError: + raise KeyError, name security.declareProtected(Permissions.AccessContentsInformation, 'getWebSectionValue') def getWebSectionValue(self): @@ -303,7 +281,7 @@ class WebSection(Domain): fallback_script_id='WebSection_getDocumentValue') if cache is not None: - if not cache.has_key(key): cache[key] = method + if cache.get(key, MARKER) is MARKER: cache[key] = method return method(name, portal=portal, **kw) diff --git a/product/ERP5/PropertySheet/WebSection.py b/product/ERP5/PropertySheet/WebSection.py index 535effb4e4ba8c07a75e811aca88daa490fd307f..5e6d399d9f95de4f40a7740e4e1c3473de872355 100644 --- a/product/ERP5/PropertySheet/WebSection.py +++ b/product/ERP5/PropertySheet/WebSection.py @@ -53,17 +53,6 @@ class WebSection: 'acquisition_accessor_id' : 'getContentLayout', 'acquisition_depends' : None, 'mode' : '' }, - { 'id' : 'webmaster', - 'description' : 'ID of a user which has complete access to all documents in the site.', - 'type' : 'string', - 'default' : None, - 'acquisition_base_category' : ('parent',), - 'acquisition_portal_type' : ('Web Section', 'Web Site'), - 'acquisition_copy_value' : 0, - 'acquisition_mask_value' : 1, - 'acquisition_accessor_id' : 'getWebmaster', - 'acquisition_depends' : None, - 'mode' : '' }, { 'id' : 'visible', 'description' : 'Defines visibility of current section.', 'type' : 'boolean',