WebSite.py 10 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 28
##############################################################################
#
# 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 AccessControl import ClassSecurityInfo
29

30 31
from Products.ERP5.Document.WebSection import WebSection
from Products.ERP5Type import Permissions, PropertySheet
32
from Products.ERP5Type.Cache import CachingMethod
33

34
from Products.ERP5Type.Globals import get_request
35
from Persistence import Persistent
36
from ZPublisher import BeforeTraverse
37
from ZPublisher.HTTPRequest import HTTPRequest
Jean-Paul Smets's avatar
Jean-Paul Smets committed
38

39
WEBSITE_KEY = 'web_site_value'
40
WEBSITE_LANGUAGE_KEY = 'web_site_language'
41

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

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

59 60 61
    # 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
62 63
    request = getattr(self, '_v_request', None)
    if request is None: request = self._v_request = get_request()
64 65 66
    # In ignore_layout case, we only remove empty element from path
    # XXX more support required for ignore_layout?
    if request.get('ignore_layout', None):
67
      return HTTPRequest.physicalPathToVirtualPath(request, path)
68 69
    website_path = request.get(WEBSITE_KEY, None)
    select_language = request.get(WEBSITE_LANGUAGE_KEY, None)
70 71 72
    if website_path:
      website_path = tuple(website_path)    # Make sure all path are tuples
      path = tuple(path)                    # Make sure all path are tuples
73 74
      if select_language:
        website_path = website_path + (select_language,)      # Add the language part
75 76 77 78 79 80 81
      # 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
      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
        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:
89
        path = website_path + path[common_index + 1:]
90
    rpp = request.other.get('VirtualRootPhysicalPath', ('', ))
91 92 93 94 95 96
    i = 0
    for name in rpp[:len(path)]:
      if path[i] == name:
        i = i + 1
      else:
        break
97 98 99 100
    #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],)
101
    return path[i:]
102

103
  def __call__(self, container, request):
104 105
    """
      Each time we are traversed, we patch the request instance with our
106 107
      own version of physicalPathToVirtualPath and we set a default
      language
108
    """
109
    self._v_request = request
110 111
    request.physicalPathToVirtualPath = self._physicalPathToVirtualPath

112 113
    # If a skin selection is defined in this web site, change the skin now.
    skin_selection_name = container.getSkinSelectionName()
114
    if skin_selection_name and request.get('portal_skin', None) is None:
115 116
      container.getPortalObject().changeSkin(skin_selection_name)

117 118
    # Set default language if any
    default_language = container.getDefaultAvailableLanguage()
119
    if default_language and container.isStaticLanguageSelection():
120 121
      if request.get('AcceptLanguage') is not None:
        request['AcceptLanguage'].set(default_language, 80)
122 123 124 125 126 127 128 129 130
    else:
      accept_language = request.get('AcceptLanguage')
      if accept_language is not None:
        selected_language = accept_language.select_language(
            container.getAvailableLanguageList())
        if selected_language:
          request['AcceptLanguage'].set(selected_language, 80)
        elif default_language:
          request['AcceptLanguage'].set(default_language, 80)
131

132
class WebSite(WebSection):
Jean-Paul Smets's avatar
Jean-Paul Smets committed
133
    """
134 135
      The Web Site root class is specialises WebSection
      by defining a global webmaster user.
Jean-Paul Smets's avatar
Jean-Paul Smets committed
136 137
    """
    # CMF Type Definition
138 139
    meta_type       = 'ERP5 Web Site'
    portal_type     = 'Web Site'
Jean-Paul Smets's avatar
Jean-Paul Smets committed
140 141 142 143 144 145 146 147 148 149

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

    # Default Properties
    property_sheets = ( PropertySheet.Base
                      , PropertySheet.XMLObject
                      , PropertySheet.CategoryCore
                      , PropertySheet.DublinCore
150
                      , PropertySheet.WebSection
151
                      , PropertySheet.WebSite
152
                      , PropertySheet.Predicate
Jean-Paul Smets's avatar
Jean-Paul Smets committed
153 154
                      )

155
    web_section_key = WEBSITE_KEY
156

157 158 159 160 161
    security.declareProtected(Permissions.AccessContentsInformation, 'getWebSiteValue')
    def getWebSiteValue(self):
        """
          Returns the current web site (ie. self) though containment acquisition
        """
162
       
163 164
        return self

165 166 167
    # Static Language Selection support
    def _getExtensibleContent(self, request, name):
      language_list = self.getAvailableLanguageList()
168
      if language_list and self.isStaticLanguageSelection():
169 170 171 172
        # Interprete names which could be a language
        # as a language selection only if language_list
        # was defined or set default language
        if name in language_list:
173 174
          if request.get('AcceptLanguage') is not None:
            request['AcceptLanguage'].set(name, 100)
175 176
            request.set(WEBSITE_LANGUAGE_KEY, name)
          return self.asContext(id=name)
177
      return WebSection.getExtensibleContent(self, request, name)
178

179
    # Virtual Hosting Support
180 181 182 183
    security.declarePrivate( 'manage_beforeDelete' )
    def manage_beforeDelete(self, item, container):
      if item is self:
        handle = self.meta_type + '/' + self.getId()
184
        BeforeTraverse.unregisterBeforeTraverse(item, handle)
185
      WebSection.manage_beforeDelete(self, item, container)
186 187 188 189 190

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

194
    security.declareProtected(Permissions.AccessContentsInformation, 'getPermanentURLList')
195 196 197 198 199 200 201 202 203
    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
      """
204
      return map(lambda x:x.getPermanentURL(document), self.getWebSectionValueList(document))
205 206 207 208 209 210 211 212 213 214 215 216

    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):
217 218 219 220 221
        # Only return visible web section
        if section.isVisible():
          result = [section.getUid()]
        else:
          result = []
222 223 224 225 226 227 228 229
        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')

230 231 232 233 234
      web_section_uid_list = _getWebSectionUidList(self)
      if web_section_uid_list:
        section_list = self.portal_domains.searchPredicateList(document, 
                          portal_type='Web Section',
                          uid=web_section_uid_list)
235

236
        section_dict = {}
237

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

241 242 243
        # Eliminate path
        for section in section_list:
          path = section.getPhysicalPath()
244 245
          for i in range(0, len(path)):
            sub_path = tuple(path[0:i])
246 247
            if section_dict.has_key(sub_path):
              del section_dict[sub_path]
248

249
        section_list = section_dict.values()
250

251 252
        # Sort by Index
        section_list.sort(key=lambda x: x.getIntIndex())
253

254 255 256
        return section_list
      else:
        return []