WebSite.py 7.83 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
from Acquisition import ImplicitAcquisitionWrapper, aq_base, aq_inner
Jean-Paul Smets's avatar
Jean-Paul Smets committed
29
from AccessControl import ClassSecurityInfo
30

31
from Products.ERP5.Document.WebSection import WebSection, WEBSECTION_KEY
32
from Products.ERP5Type import Permissions, PropertySheet, Constraint, Interface, Cache
33
from Products.ERP5Type.Cache import CachingMethod
34

Jean-Paul Smets's avatar
Jean-Paul Smets committed
35
from Globals import get_request
36
from Persistence import Persistent
37
from ZPublisher import BeforeTraverse
Jean-Paul Smets's avatar
Jean-Paul Smets committed
38 39 40

from zLOG import LOG

41 42
WEBSITE_KEY = 'web_site_value'

43
class WebSiteTraversalHook(Persistent):
44 45 46 47 48 49
  """
    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 .
50 51 52 53 54
  """

  def _physicalPathToVirtualPath(self, path):
    """
      Remove the path to the VirtualRoot from a physical path
55
      and add the path to the WebSite if any
56 57 58 59
    """
    if type(path) is type(''):
      path = path.split( '/')

60 61 62
    # Every Web Section acts as a mini site though layout for document editing is the root layout
    #website_path = self._v_request.get(WEBSECTION_KEY, self._v_request.get(WEBSITE_KEY, None))
    # Only consider Web Site for absolute_url
63 64 65
    request = getattr(self, '_v_request', None)
    if request is None: request = self._v_request = get_request()
    website_path = request.get(WEBSITE_KEY, None) 
66 67 68 69 70 71 72 73 74 75 76
    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:
77 78
        if i >= path_len:
          break
79 80 81 82 83 84
        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:]
85
    rpp = request.other.get('VirtualRootPhysicalPath', ('', ))
86 87 88 89 90 91
    i = 0
    for name in rpp[:len(path)]:
      if path[i] == name:
        i = i + 1
      else:
        break
92 93 94 95
    #if self._v_request.has_key(DOCUMENT_NAME_KEY):
    #  # Replace the last id of the path with the name which
    #  # was used to lookup the document
    #  path = path[:-1] + (self._v_request[DOCUMENT_NAME_KEY],)
96
    return path[i:]
97

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

106
class WebSite(WebSection):
Jean-Paul Smets's avatar
Jean-Paul Smets committed
107
    """
108 109
      The Web Site root class is specialises WebSection
      by defining a global webmaster user.
Jean-Paul Smets's avatar
Jean-Paul Smets committed
110 111
    """
    # CMF Type Definition
112 113
    meta_type       = 'ERP5 Web Site'
    portal_type     = 'Web Site'
Jean-Paul Smets's avatar
Jean-Paul Smets committed
114
    isPortalContent = 1
115
    isRADContent    = 1
Jean-Paul Smets's avatar
Jean-Paul Smets committed
116 117 118 119 120 121 122 123 124 125

    # Declarative security
    security = ClassSecurityInfo()
    security.declareObjectProtected(Permissions.AccessContentsInformation)

    # Default Properties
    property_sheets = ( PropertySheet.Base
                      , PropertySheet.XMLObject
                      , PropertySheet.CategoryCore
                      , PropertySheet.DublinCore
126
                      , PropertySheet.WebSection
127
                      , PropertySheet.Predicate
Jean-Paul Smets's avatar
Jean-Paul Smets committed
128 129
                      )

130
    web_section_key = WEBSITE_KEY
131

132 133 134 135 136 137 138
    security.declareProtected(Permissions.AccessContentsInformation, 'getWebSiteValue')
    def getWebSiteValue(self):
        """
          Returns the current web site (ie. self) though containment acquisition
        """
        return self

139
    # Virtual Hosting Support
140 141 142 143
    security.declarePrivate( 'manage_beforeDelete' )
    def manage_beforeDelete(self, item, container):
      if item is self:
        handle = self.meta_type + '/' + self.getId()
144
        BeforeTraverse.unregisterBeforeTraverse(item, handle)
145
      WebSection.manage_beforeDelete(self, item, container)
146 147 148 149 150

    security.declarePrivate( 'manage_afterAdd' )
    def manage_afterAdd(self, item, container):
      if item is self:
        handle = self.meta_type + '/' + self.getId()
151
        BeforeTraverse.registerBeforeTraverse(item, WebSiteTraversalHook(), handle)
152
      WebSection.manage_afterAdd(self, item, container)
153

154
    security.declareProtected(Permissions.AccessContentsInformation, 'getPermanentURLList')
155 156 157 158 159 160 161 162 163
    def getPermanentURLList(self, document):
      """
        Return a list of URLs which exist in the site for
        a given document. This could be implemented either
        by keep a history of documents which have been
        accessed or by parsing all WebSections and listing
        all documents in each of them to build a reverse
        mapping of getPermanentURL
      """
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
      return map(lambda x:x.getPermanentURL(document), self.getWebSectionValueList())

    security.declareProtected(Permissions.AccessContentsInformation, 'getWebSectionValueList')
    def getWebSectionValueList(self, document):
      """
        Returns a list of sections which a given document is
        part of.

        This could be implemented either by testing all sections
        and building a cache or by using the predicate API
        to find which sections apply.
      """
      def getWebSectionUidList(section):
        result = [section.getUid()]
        for o in section.contentValues(portal_type='Web Section'):
          result.extend(getWebSectionUidList(o))
        return result

      _getWebSectionUidList = CachingMethod(getWebSectionUidList,
                         id='WebSite._getWebSectionUidList',
                         cache_factory='erp5_content_medium')

      section_list = self.portal_domains.searchPredicateList(document, 
                        portal_type='Web Section',
                        uid=_getWebSectionUidList(self))

      section_dict = {}

      for section in section_list:
        section_dict[section.getPhysicalPath()] = section

      # Eliminate path
      for section in section_list:
        path = section.getPhysicalPath()
        for i in range(0, len(path)-1):
          sub_path = path[0:i]
          if section_dict.has_key(sub_path):
            del section_dict[sub_path]

      section_list = section_dict.values()

      # Sort by Index
      section_list.sort(lambda x,y: cmp(x.getIntIndex(), y.getIntIndex()))

      return section_list