WebSite.py 9.23 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
WEBSITE_KEY = 'web_site_value'
42
WEBSITE_LANGUAGE_KEY = 'web_site_language'
43

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

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

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

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

111 112
    # If a skin selection is defined in this web site, change the skin now.
    skin_selection_name = container.getSkinSelectionName()
113
    if skin_selection_name: # XXX missing support to portal_skin parameter
114 115
      container.getPortalObject().changeSkin(skin_selection_name)

116 117 118 119 120 121
    # Set default language if any
    default_language = container.getDefaultAvailableLanguage()
    if default_language:
      if request.get('AcceptLanguage') is not None:
        request['AcceptLanguage'].set(default_language, 80)

122
class WebSite(WebSection):
Jean-Paul Smets's avatar
Jean-Paul Smets committed
123
    """
124 125
      The Web Site root class is specialises WebSection
      by defining a global webmaster user.
Jean-Paul Smets's avatar
Jean-Paul Smets committed
126 127
    """
    # CMF Type Definition
128 129
    meta_type       = 'ERP5 Web Site'
    portal_type     = 'Web Site'
Jean-Paul Smets's avatar
Jean-Paul Smets committed
130
    isPortalContent = 1
131
    isRADContent    = 1
Jean-Paul Smets's avatar
Jean-Paul Smets committed
132 133 134 135 136 137 138 139 140 141

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

    # Default Properties
    property_sheets = ( PropertySheet.Base
                      , PropertySheet.XMLObject
                      , PropertySheet.CategoryCore
                      , PropertySheet.DublinCore
142
                      , PropertySheet.WebSection
143
                      , PropertySheet.WebSite
144
                      , PropertySheet.Predicate
Jean-Paul Smets's avatar
Jean-Paul Smets committed
145 146
                      )

147
    web_section_key = WEBSITE_KEY
148

149 150 151 152 153 154 155
    security.declareProtected(Permissions.AccessContentsInformation, 'getWebSiteValue')
    def getWebSiteValue(self):
        """
          Returns the current web site (ie. self) though containment acquisition
        """
        return self

156 157 158 159 160 161 162 163
    # Static Language Selection support
    def _getExtensibleContent(self, request, name):
      language_list = self.getAvailableLanguageList()
      if language_list:
        # 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:
164 165
          if request.get('AcceptLanguage') is not None:
            request['AcceptLanguage'].set(name, 100)
166 167
            request.set(WEBSITE_LANGUAGE_KEY, name)
          return self.asContext(id=name)
168
      return WebSection._getExtensibleContent(self, request, name)
169

170
    # Virtual Hosting Support
171 172 173 174
    security.declarePrivate( 'manage_beforeDelete' )
    def manage_beforeDelete(self, item, container):
      if item is self:
        handle = self.meta_type + '/' + self.getId()
175
        BeforeTraverse.unregisterBeforeTraverse(item, handle)
176
      WebSection.manage_beforeDelete(self, item, container)
177 178 179 180 181

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

185
    security.declareProtected(Permissions.AccessContentsInformation, 'getPermanentURLList')
186 187 188 189 190 191 192 193 194
    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
      """
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
      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()))

239
      return section_list