Commit 7891adc6 authored by Jean-Paul Smets's avatar Jean-Paul Smets

Reimplemented permanent URLs as it should have been: with __bobo_traverse__....

Reimplemented permanent URLs as it should have been: with __bobo_traverse__. We do not need anylonger with this to specify the webmaster as we did. Security is taken into account to access permanent URL documents. One remaining issue: support of transactional cache in __bobo_traverse__.

git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@19219 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent bff3ece0
############################################################################## ##############################################################################
# #
# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
# Copyright (c) 2002-2006 Nexedi SARL 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 # WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential # programmers who take the whole responsability of assessing all potential
...@@ -9,20 +18,6 @@ ...@@ -9,20 +18,6 @@
# garantees and support are strongly adviced to contract a Free Software # garantees and support are strongly adviced to contract a Free Software
# Service Company # 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 from AccessControl import ClassSecurityInfo
...@@ -37,44 +32,13 @@ from Products.ERP5Type.Base import TempBase ...@@ -37,44 +32,13 @@ from Products.ERP5Type.Base import TempBase
from Globals import get_request from Globals import get_request
from zLOG import LOG, WARNING from zLOG import LOG, WARNING
import sys
from Products.ERP5Type.Cache import getReadOnlyTransactionCache from Products.ERP5Type.Cache import getReadOnlyTransactionCache
# Global keys used for URL generation # Global keys used for URL generation
WEBSECTION_KEY = 'web_section_value' WEBSECTION_KEY = 'web_section_value'
WEBSITE_USER = 'web_site_user' MARKER = []
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
class WebSection(Domain): class WebSection(Domain):
""" """
...@@ -129,17 +93,14 @@ class WebSection(Domain): ...@@ -129,17 +93,14 @@ class WebSection(Domain):
web_section_key = WEBSECTION_KEY 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 If no subobject is found through Folder API
web site local naming policies as defined by then try to lookup the object by invoking getDocumentValue
the getDocumentValue method
""" """
global reserved_name_dict_init
global reserved_name_dict
request = self.REQUEST
# Register current web site physical path for later URL generation # 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() request[self.web_section_key] = self.getPhysicalPath()
# Normalize web parameter in the request # Normalize web parameter in the request
# Fix common user mistake and transform '1' string to boolean # Fix common user mistake and transform '1' string to boolean
...@@ -149,66 +110,83 @@ class WebSection(Domain): ...@@ -149,66 +110,83 @@ class WebSection(Domain):
request.set(web_param, True) request.set(web_param, True)
else: else:
request.set(web_param, False) request.set(web_param, False)
# First let us call the super method
dynamic = Domain._aq_dynamic(self, name) # Normal traversal
if dynamic is not None: try:
return dynamic return getattr(self, name)
# Do some optimisation here for names which can not be names of documents except AttributeError:
if reserved_name_dict.has_key(name) \ pass
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]
try: try:
portal = self.getPortalObject() return self[name]
# Use the webmaster identity to find documents except KeyError:
if request[CACHE_KEY].has_key(WEBSITE_USER): pass
user = request[CACHE_KEY][WEBSITE_USER] # Retrieve user from request cache
else: # Permanent URL traversal
# Cache webmaster for faster lookup # First we must get the logged user by forcing identification
if not hasattr(aq_base(self), '_v_section_webmaster'): cache = getReadOnlyTransactionCache(self)
self._v_section_webmaster = self.getWebmaster() # LOG('getReadOnlyTransactionCache', 0, repr(cache)) # Currently, it is always None
user = portal.acl_users.getUserById(self._v_section_webmaster) if cache is not None:
request[CACHE_KEY][WEBSITE_USER] = user # Cache user per request key = ('__bobo_traverse__', self, 'user')
if user is not None: try:
old_manager = getSecurityManager() user = cache[key]
newSecurityManager(get_request(), user) except KeyError:
else: user = MARKER
LOG('WebSection _aq_dynamic', WARNING, 'No user defined for %s.' else:
'This will prevent accessing object through their permanent URL' % self.getWebmaster()) user = MARKER
#LOG('Lookup', 0, str(name)) old_user = getSecurityManager().getUser()
document = self.getDocumentValue(name=name, portal=portal) if user is MARKER:
request[CACHE_KEY][name] = document user = None # By default, do nothing
if user is not None: if old_user is None or old_user.getUserName() == 'Anonymous User':
setSecurityManager(old_manager) user_folder = getToolByName(self, 'acl_users', None)
except: if user_folder is not None:
# Cleanup non recursion dict in case of exception try:
if request[CACHE_KEY].has_key(name): if request.get('PUBLISHED', MARKER) is MARKER:
del request[CACHE_KEY][name] # request['PUBLISHED'] is required by validate
raise 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: if document is not None:
request[DOCUMENT_NAME_KEY] = name document = aq_base(document.asContext(id=name, # Hide some properties to permit locating the original
document = aq_base(document.asContext(id=name, # Hide some properties to permit location the original
original_container=document.getParentValue(), original_container=document.getParentValue(),
original_id=document.getId(), original_id=document.getId(),
editable_absolute_url=document.absolute_url())) 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') security.declareProtected(Permissions.AccessContentsInformation, 'getWebSectionValue')
def getWebSectionValue(self): def getWebSectionValue(self):
...@@ -303,7 +281,7 @@ class WebSection(Domain): ...@@ -303,7 +281,7 @@ class WebSection(Domain):
fallback_script_id='WebSection_getDocumentValue') fallback_script_id='WebSection_getDocumentValue')
if cache is not None: 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) return method(name, portal=portal, **kw)
......
...@@ -53,17 +53,6 @@ class WebSection: ...@@ -53,17 +53,6 @@ class WebSection:
'acquisition_accessor_id' : 'getContentLayout', 'acquisition_accessor_id' : 'getContentLayout',
'acquisition_depends' : None, 'acquisition_depends' : None,
'mode' : '' }, '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', { 'id' : 'visible',
'description' : 'Defines visibility of current section.', 'description' : 'Defines visibility of current section.',
'type' : 'boolean', 'type' : 'boolean',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment