############################################################################## # # Copyright (c) 2002-2006 Nexedi SARL and Contributors. All Rights Reserved. # # 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 Acquisition import ImplicitAcquisitionWrapper, aq_base, aq_inner from AccessControl import ClassSecurityInfo from AccessControl.User import emergency_user from AccessControl.SecurityManagement import getSecurityManager, newSecurityManager, setSecurityManager from Products.CMFCore.utils import getToolByName from Products.ERP5.Document.Domain import Domain from Products.ERP5Type import Permissions, PropertySheet, Constraint, Interface, Cache from Products.ERP5Type.Base import TempBase from Products.CMFCore.utils import UniqueObject, _checkPermission, _getAuthenticatedUser from Globals import get_request from Persistence import Persistent from ZPublisher import BeforeTraverse from zLOG import LOG WEBSITE_KEY = 'web_site_value' class WebSiteTraversalHook(Persistent): """ This is used by WebSite to rewrite URLs in such way that once a user gets into a Web Site object, all documents referenced by the web site are accessed through the web site rather than directly. We inherit for persistent, so that pickle mechanism ignores _v_request . """ def _physicalPathToVirtualPath(self, path): """ Remove the path to the VirtualRoot from a physical path and add the path to the WebSite is any """ if type(path) is type(''): path = path.split( '/') website_path = self._v_request.get(WEBSITE_KEY, None) if website_path: website_path = tuple(website_path) # Make sure all path are tuples path = tuple(path) # Make sure all path are tuples # Search for the common part index # XXX more testing should be added to check # if the URL is the kind of URL which is a Web Site # XXX more support required for ignore_layout common_index = 0 i = 0 path_len = len(path) for name in website_path: if i >= path_len: break if path[i] == name: common_index = i i += 1 # Insert the web site path after the common part of the path if path_len > common_index + 1: path = website_path + path[common_index + 1:] rpp = self._v_request.other.get('VirtualRootPhysicalPath', ('', )) i = 0 for name in rpp[:len(path)]: if path[i] == name: i = i + 1 else: break return path[i:] def __call__(self, container, request): """ Each time we are traversed, we patch the request instance with our rewritted version of physicalPathToVirtualPath """ self._v_request = request request.physicalPathToVirtualPath = self._physicalPathToVirtualPath Domain_getattr = Domain.inheritedAttribute('__getattr__') # Use a request key to store access attributes and prevent infinite recursion CACHE_KEY = 'web_site_aq_cache' class WebSite(Domain): """ A Web Site root class. This class is used by ERP5 Commerce to define the root of an eCommerce site. WARNING: - Z Catalog Search permission must be set for Anonymous TODO: - accelerate document lookup by caching acceptable keys - fix missing REQUEST information in aq_dynamic documents """ # CMF Type Definition meta_type = 'ERP5 Web Site' portal_type = 'Web Site' isPortalContent = 1 isRADContent = 1 # Declarative security security = ClassSecurityInfo() security.declareObjectProtected(Permissions.AccessContentsInformation) # Default Properties property_sheets = ( PropertySheet.Base , PropertySheet.XMLObject , PropertySheet.CategoryCore , PropertySheet.DublinCore , PropertySheet.WebSite ) def _aq_dynamic(self, name): """ Try to find a suitable document based on the web site local naming policies as defined by the WebSite_getDocumentValue script """ request = self.REQUEST # Normalize web parameter in the request # Fix common user mistake and transform '1' string to boolean for web_param in ['ignore_layout', 'editable_mode']: if hasattr(request, web_param): if getattr(request, web_param, None) in ('1', 1, True): request.set(web_param, True) else: request.set(web_param, False) # Register current web site physical path for later URL generation if not request.has_key(WEBSITE_KEY): request[WEBSITE_KEY] = self.getPhysicalPath() # 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 name.startswith('_') or name.startswith('portal_')\ or name.startswith('aq_') or name.startswith('selection_') \ or name.startswith('sort-') or name == 'getLayout' \ or name == 'getListItemUrl' or name.startswith('WebSite_'): return None if not request.has_key(CACHE_KEY): request[CACHE_KEY] = {} elif request[CACHE_KEY].has_key(name): return request[CACHE_KEY][name] try: portal = self.getPortalObject() # Use the webmaster identity to find documents user = portal.acl_users.getUserById(self.getWebmaster()) if user is not None: old_manager = getSecurityManager() newSecurityManager(get_request(), user) document = self.WebSite_getDocumentValue(portal, name) 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 document security.declarePrivate( 'manage_beforeDelete' ) def manage_beforeDelete(self, item, container): if item is self: handle = self.meta_type + '/' + self.getId() BeforeTraverse.unregisterBeforeTraverse(item, handle) Domain.manage_beforeDelete(self, item, container) security.declarePrivate( 'manage_afterAdd' ) def manage_afterAdd(self, item, container): if item is self: handle = self.meta_type + '/' + self.getId() BeforeTraverse.registerBeforeTraverse(item, WebSiteTraversalHook(), handle) Domain.manage_afterAdd(self, item, container)