WebSite.py 7.22 KB
Newer Older
Jean-Paul Smets's avatar
Jean-Paul Smets committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
##############################################################################
#
# 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.
#
##############################################################################

28 29
from Acquisition import ImplicitAcquisitionWrapper, aq_base, aq_inner

Jean-Paul Smets's avatar
Jean-Paul Smets committed
30
from AccessControl import ClassSecurityInfo
31 32 33
from AccessControl.User import emergency_user
from AccessControl.SecurityManagement import getSecurityManager, newSecurityManager, setSecurityManager

Jean-Paul Smets's avatar
Jean-Paul Smets committed
34 35
from Products.CMFCore.utils import getToolByName
from Products.ERP5.Document.Domain import Domain
36
from Products.ERP5Type import Permissions, PropertySheet, Constraint, Interface, Cache
Jean-Paul Smets's avatar
Jean-Paul Smets committed
37
from Products.ERP5Type.Base import TempBase
38 39 40

from Products.CMFCore.utils import UniqueObject, _checkPermission, _getAuthenticatedUser

Jean-Paul Smets's avatar
Jean-Paul Smets committed
41
from Globals import get_request
42

43
from Persistence import Persistent
44

45
from ZPublisher import BeforeTraverse
Jean-Paul Smets's avatar
Jean-Paul Smets committed
46 47 48

from zLOG import LOG

49 50 51 52


WEBSITE_KEY = 'web_site_value'

53
class WebSiteTraversalHook(Persistent):
54 55 56 57 58 59
  """
    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 .
60 61 62 63 64 65 66 67 68 69
  """

  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( '/')

70
    website_path = self._v_request.get(WEBSITE_KEY, None)
71 72 73 74 75 76 77 78 79 80 81
    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:
82 83
        if i >= path_len:
          break
84 85 86 87 88 89
        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:]
90
    rpp = self._v_request.other.get('VirtualRootPhysicalPath', ('', ))
91 92 93 94 95 96 97
    i = 0
    for name in rpp[:len(path)]:
      if path[i] == name:
        i = i + 1
      else:
        break
    return path[i:]
98

99
  def __call__(self, container, request):
100 101 102 103
    """
      Each time we are traversed, we patch the request instance with our
      rewritted version of physicalPathToVirtualPath
    """
104
    self._v_request = request
105 106
    request.physicalPathToVirtualPath = self._physicalPathToVirtualPath

107 108


Jean-Paul Smets's avatar
Jean-Paul Smets committed
109 110
Domain_getattr = Domain.inheritedAttribute('__getattr__')

111
# Use a request key to store access attributes and prevent infinite recursion
112
CACHE_KEY = 'web_site_aq_cache'
113

Jean-Paul Smets's avatar
Jean-Paul Smets committed
114 115 116 117 118 119 120 121 122 123 124 125 126
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
127 128
    meta_type       = 'ERP5 Web Site'
    portal_type     = 'Web Site'
Jean-Paul Smets's avatar
Jean-Paul Smets committed
129
    isPortalContent = 1
130
    isRADContent    = 1
Jean-Paul Smets's avatar
Jean-Paul Smets committed
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147

    # 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
148
        the WebSite_getDocumentValue script
149
      """
150
      request = self.REQUEST
151
      # Register current web site physical path for later URL generation
152 153
      if not request.has_key(WEBSITE_KEY):
        request[WEBSITE_KEY] = self.getPhysicalPath()
Jean-Paul Smets's avatar
Jean-Paul Smets committed
154 155
      # First let us call the super method
      dynamic = Domain._aq_dynamic(self, name)
156
      if dynamic is not None:
Jean-Paul Smets's avatar
Jean-Paul Smets committed
157
        return dynamic
158
      # Do some optimisation here for names which can not be names of documents
Jean-Paul Smets's avatar
Jean-Paul Smets committed
159 160
      if name.startswith('_') or name.startswith('portal_')\
          or name.startswith('aq_') or name.startswith('selection_') \
161 162
          or name.startswith('sort-') or name == 'getLayout' \
          or name == 'getListItemUrl' or name.startswith('WebSite_'):
Jean-Paul Smets's avatar
Jean-Paul Smets committed
163
        return None
164 165 166 167
      if not request.has_key(CACHE_KEY):
        request[CACHE_KEY] = {}
      elif request[CACHE_KEY].has_key(name):
        return request[CACHE_KEY][name]
Jean-Paul Smets's avatar
Jean-Paul Smets committed
168 169 170 171
      try:
        portal = self.getPortalObject()
        # Use the webmaster identity to find documents
        user = portal.acl_users.getUserById(self.getWebmaster())
172 173 174
        if user is not None:
          old_manager = getSecurityManager()
          newSecurityManager(get_request(), user)
175 176
        document = self.WebSite_getDocumentValue(portal, name)
        request[CACHE_KEY][name] = document
177 178
        if user is not None:
          setSecurityManager(old_manager)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
179 180
      except:
        # Cleanup non recursion dict in case of exception
181 182
        if request[CACHE_KEY].has_key(name):
          del request[CACHE_KEY][name]
Jean-Paul Smets's avatar
Jean-Paul Smets committed
183
        raise
184
      return document
185

186 187 188 189
    security.declarePrivate( 'manage_beforeDelete' )
    def manage_beforeDelete(self, item, container):
      if item is self:
        handle = self.meta_type + '/' + self.getId()
190
        BeforeTraverse.unregisterBeforeTraverse(item, handle)
191 192 193 194 195 196
      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()
197
        BeforeTraverse.registerBeforeTraverse(item, WebSiteTraversalHook(), handle)
198
      Domain.manage_afterAdd(self, item, container)