ERP5Site.py 50 KB
Newer Older
1
##############################################################################
Jean-Paul Smets's avatar
Jean-Paul Smets committed
2 3 4 5 6 7 8 9 10 11 12
#
# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
13 14
"""
  Portal class
Jean-Paul Smets's avatar
Jean-Paul Smets committed
15 16 17
"""

import Globals
18
import AccessControl
Jean-Paul Smets's avatar
Jean-Paul Smets committed
19
from Globals import package_home
20

21
from ZPublisher import BeforeTraverse
Jean-Paul Smets's avatar
Jean-Paul Smets committed
22 23 24 25
from AccessControl import ClassSecurityInfo
from Products.CMFDefault.Portal import CMFSite, PortalGenerator
from Products.CMFCore.utils import getToolByName, _getAuthenticatedUser
from Products.ERP5Type import Permissions, PropertySheet, Constraint, Interface
Jean-Paul Smets's avatar
Jean-Paul Smets committed
26
from Products.ERP5Type.Document.Folder import FolderMixIn
27
from Products.ERP5Type.Document import addFolder
Jean-Paul Smets's avatar
Jean-Paul Smets committed
28
from Acquisition import aq_base, aq_parent, aq_inner, aq_acquire
29
from Products.ERP5Type import allowClassTool
30
from Products.ERP5Type.Cache import CachingMethod
31 32
from Products.ERP5Type.ERP5Type import ERP5TypeInformation
from Products.ERP5.Document.BusinessTemplate import BusinessTemplate
33

34
import ERP5Defaults
Jean-Paul Smets's avatar
Jean-Paul Smets committed
35

36
from zLOG import LOG, INFO
Sebastien Robin's avatar
Sebastien Robin committed
37
from string import join
Jean-Paul Smets's avatar
Jean-Paul Smets committed
38
import os
39 40
MARKER = []

41

Jean-Paul Smets's avatar
Jean-Paul Smets committed
42
# Site Creation DTML
43 44
manage_addERP5SiteForm = Globals.HTMLFile('dtml/addERP5Site', globals())
manage_addERP5SiteForm.__name__ = 'addERP5Site'
Jean-Paul Smets's avatar
Jean-Paul Smets committed
45 46

# ERP5Site Constructor
47 48 49
def manage_addERP5Site(self,
                       id,
                       title='ERP5',
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
                       description='',
                       create_userfolder=1,
                       create_activities=1,
                       email_from_address='postmaster@localhost',
                       email_from_name='Portal Administrator',
                       validate_email=0,
                       erp5_sql_connection_type='Z MySQL Database Connection',
                       erp5_sql_connection_string='test test',
                       erp5_sql_deferred_connection_type = \
                           'Z MySQL Deferred Database Connection',
                       erp5_sql_deferred_connection_string = 'test test',
                       cmf_activity_sql_connection_type= \
                           'Z MySQL Database Connection',
                       cmf_activity_sql_connection_string='test test',
                       light_install=0,
                       reindex=1,
                       RESPONSE=None):
  '''
  Adds a portal instance.
  '''
70
  gen = ERP5Generator()
71
  id = str(id).strip()
72 73
  p = gen.create(self,
                 id,
74 75 76 77 78 79 80 81 82 83
                 create_userfolder,
                 erp5_sql_connection_type,
                 erp5_sql_connection_string,
                 erp5_sql_deferred_connection_type,
                 erp5_sql_deferred_connection_string,
                 cmf_activity_sql_connection_type,
                 cmf_activity_sql_connection_string,
                 create_activities=create_activities,
                 light_install=light_install,
                 reindex=reindex)
84 85
  gen.setupDefaultProperties(p,
                             title,
86
                             description,
87
                             email_from_address,
88 89
                             email_from_name,
                             validate_email)
90
  if RESPONSE is not None:
91 92
    RESPONSE.redirect(p.absolute_url())

93 94 95 96 97 98 99 100 101 102 103 104 105 106 107

class ReferCheckerBeforeTraverseHook:
  """This before traverse hook checks the HTTP_REFERER argument in the request
  and refuses access to anything else that portal_url.

  This is enabled by calling the method enableRefererCheck on the portal.
  """
  handle = '_erp5_referer_check'

  def __call__(self, container, request):
    """Checks the request contains a valid referrer.
    """
    response = request.RESPONSE
    http_url = request.get('ACTUAL_URL', '').strip()
    http_referer = request.get('HTTP_REFERER', '').strip()
108

109 110 111 112 113 114 115
    user_password = request._authUserPW()
    if user_password:
      user = container.acl_users.getUserById(user_password[0]) or\
              container.aq_parent.acl_users.getUserById(user_password[0])
      # Manager can do anything
      if user is not None and 'Manager' in user.getRoles():
        return
116

117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
    portal_url = container.portal_url.getPortalObject().absolute_url()
    if http_referer != '':
      # if HTTP_REFERER is set, user can acces the object if referer is ok
      if http_referer.startswith(portal_url):
        return
      LOG('HTTP_REFERER_CHECK : BAD REFERER !', INFO,
          'request : "%s", referer : "%s"' % (http_url, http_referer))
      response.unauthorized()
    else:
      # no HTTP_REFERER, we only allow to reach portal_url
      for i in ('/', '/index_html', '/login_form', '/view'):
        if http_url.endswith(i):
          http_url = http_url[:-len(i)]
          break
      if len(http_url) == 0 or not portal_url.startswith(http_url):
        LOG('HTTP_REFERER_CHECK : NO REFERER !', INFO,
            'request : "%s"' % http_url)
        response.unauthorized()

136
class ERP5Site(FolderMixIn, CMFSite):
137
  """
138 139
  The *only* function this class should have is to help in the setup
  of a new ERP5.  It should not assist in the functionality at all.
140
  """
141
  meta_type = 'ERP5 Site'
142
  constructors = (manage_addERP5SiteForm, manage_addERP5Site, )
143 144 145 146 147
  uid = 0
  last_id = 0
  icon = 'portal.gif'

  _properties = (
148
      { 'id':'title',
149
        'type':'string'},
150
      { 'id':'description',
151 152
        'type':'text'},
      )
153 154 155 156 157 158 159 160 161
  title = ''
  description = ''

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

  security.declareProtected(Permissions.View, 'view')
  def view(self):
162 163 164 165 166
    """
      Returns the default view.
      Implemented for consistency
    """
    return self.index_html()
167

168 169 170 171 172 173 174
  security.declareProtected(Permissions.ManagePortal, 'enableRefererCheck')
  def enableRefererCheck(self):
    """Enable a ReferCheckerBeforeTraverseHook to check users have valid
    HTTP_REFERER
    """
    BeforeTraverse.registerBeforeTraverse(self,
                                        ReferCheckerBeforeTraverseHook(),
175 176 177
                                        ReferCheckerBeforeTraverseHook.handle,
                             # we want to be registered _after_ CookieCrumbler
                                        100)
178

179 180 181 182
  def _disableRefererCheck(self):
    """Disable the HTTP_REFERER check."""
    BeforeTraverse.unregisterBeforeTraverse(self,
                                        ReferCheckerBeforeTraverseHook.handle)
183

184
  def hasObject(self, id):
185
    """
186
    Check if the portal has an id.
Jean-Paul Smets's avatar
Jean-Paul Smets committed
187
    """
188
    return id in self.objectIds()
189

190
  security.declareProtected(Permissions.AccessContentsInformation,
191
                            'getPortalObject')
192 193
  def getPortalObject(self):
    return self
Jean-Paul Smets's avatar
Jean-Paul Smets committed
194

195
  security.declareProtected(Permissions.AccessContentsInformation,
196
                            'getTitle')
197 198 199 200 201
  def getTitle(self):
    """
      Return the title.
    """
    return self.title
202

203 204 205 206 207 208
  security.declareProtected(Permissions.AccessContentsInformation, 'getUid')
  def getUid(self):
    """
      Returns the UID of the object. Eventually reindexes
      the object in order to make sure there is a UID
      (useful for import / export).
Jean-Paul Smets's avatar
Jean-Paul Smets committed
209

210 211 212
      WARNING : must be updates for circular references issues
    """
    return getattr(self, 'uid', 0)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
213

214
  security.declareProtected(Permissions.AccessContentsInformation,
215
                            'getParentUid')
216 217 218 219 220
  def getParentUid(self):
    """
      A portal has no parent
    """
    return self.getUid()
Jean-Paul Smets's avatar
Jean-Paul Smets committed
221

222 223 224 225
  # Required to allow content creation outside folders
  security.declareProtected(Permissions.View, 'getIdGroup')
  def getIdGroup(self):
    return None
Jean-Paul Smets's avatar
Jean-Paul Smets committed
226

227 228 229 230
  # Required to allow content creation outside folders
  security.declareProtected(Permissions.ModifyPortalContent, 'setLastId')
  def setLastId(self, id):
    self.last_id = id
Jean-Paul Smets's avatar
Jean-Paul Smets committed
231

232 233
  security.declareProtected(Permissions.AccessContentsInformation, 'getUrl')
  def getUrl(self, REQUEST=None):
234 235 236 237
    """
      Returns the absolute path of an object
    """
    return join(self.getPhysicalPath(),'/')
Sebastien Robin's avatar
Sebastien Robin committed
238

239 240 241 242 243
  # Old name - for compatibility
  security.declareProtected(Permissions.AccessContentsInformation, 'getPath')
  getPath = getUrl

  security.declareProtected(Permissions.AccessContentsInformation, 'searchFolder')
244 245 246 247 248 249 250 251
  def searchFolder(self, **kw):
    """
      Search the content of a folder by calling
      the portal_catalog.
    """
    if not kw.has_key('parent_uid'):
      kw['parent_uid'] = self.uid
    kw2 = {}
252 253 254
    # Remove useless matter before calling the
    # catalog. In particular, consider empty
    # strings as None values
255
    for cname in kw.keys():
256
      if kw[cname] not in ('', None):
257
        kw2[cname] = kw[cname]
258 259
    # The method to call to search the folder
    # content has to be called z_search_folder
260 261 262 263 264 265 266 267 268 269 270 271
    method = self.portal_catalog.searchResults
    return method(**kw2)

  security.declareProtected(Permissions.AccessContentsInformation, 'countFolder')
  def countFolder(self, **kw):
    """
      Count the content of a folder by calling
      the portal_catalog.
    """
    if not kw.has_key('parent_uid'):
      kw['parent_uid'] = self.uid
    kw2 = {}
272 273 274
    # Remove useless matter before calling the
    # catalog. In particular, consider empty
    # strings as None values
275
    for cname in kw.keys():
276
      if kw[cname] not in ('', None):
277
        kw2[cname] = kw[cname]
278 279
    # The method to call to search the folder
    # content has to be called z_search_folder
280 281 282 283 284 285 286 287 288 289
    method = self.portal_catalog.countResults
    return method(**kw2)

  # Proxy methods for security reasons
  def getOwnerInfo(self):
    return self.owner_info()

  security.declarePublic('getOrderedGlobalActionList')
  def getOrderedGlobalActionList(self, action_list):
    """
290 291
    Returns a dictionnary of actions, sorted by type of object

292
    This should absolutely be rewritten by using clean
293
    concepts to separate worklists XXX
294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315
    """
    sorted_workflow_actions = {}
    sorted_global_actions = []
    other_global_actions = []
    for action in action_list:
      action['disabled'] = 0
      if action.has_key('workflow_title'):
        if not sorted_workflow_actions.has_key(action['workflow_title']):
          sorted_workflow_actions[action['workflow_title']] = []
        sorted_workflow_actions[action['workflow_title']].append(action)
      else:
        other_global_actions.append(action)
    workflow_title_list = sorted_workflow_actions.keys()
    workflow_title_list.sort()
    for key in workflow_title_list:
      sorted_global_actions.append({'title': key, 'disabled': 1})
      sorted_global_actions.extend(sorted_workflow_actions[key])
    sorted_global_actions.append({'title': 'Others', 'disabled': 1})
    sorted_global_actions.extend(other_global_actions)
    return sorted_global_actions

  def setupDefaultProperties(self, p, title, description,
316 317 318
                             email_from_address, email_from_name,
                             validate_email
                             ):
319
    CMFSite.setupDefaultProperties(self, p, title, description,
320 321
                           email_from_address, email_from_name,
                           validate_email)
322

323 324 325
  # Portal methods are based on the concept of having portal-specific
  # parameters for customization. In the past, we used global parameters,
  # but it was not very good because it was very difficult
326
  # to customize the settings for each portal site.
327 328
  def _getPortalConfiguration(self, id):
    """
329
    Get a portal-specific configuration.
330

331 332
    Current implementation is using properties in a portal object.
    If not found, try to get a default value for backward compatibility.
333

334 335
    This implementation can be improved by gathering information
    from appropriate places, such as portal_types, portal_categories
336
    and portal_workflow.
337 338 339
    """
    if self.hasProperty(id):
      return self.getProperty(id)
340

341 342
    # Fall back to the default.
    return getattr(ERP5Defaults, id, None)
343

344
  def _getPortalGroupedTypeList(self, group):
345
    """
346
    Return a list of portal types classified to a specific group.
347 348 349 350 351 352 353 354
    """
    def getTypeList(group):
      type_list = []
      for pt in self.portal_types.objectValues():
        if group in getattr(pt, 'group_list', ()):
          type_list.append(pt.getId())
      return tuple(type_list)

355
    getTypeList = CachingMethod(getTypeList,
356
                                id=('_getPortalGroupedTypeList', group),
357
                                cache_duration=3600)
358 359 360
    return getTypeList(group)

  def _getPortalGroupedCategoryList(self, group):
361
    """
362
    Return a list of base categories classified to a specific group.
363 364 365 366 367 368 369 370
    """
    def getCategoryList(group):
      category_list = []
      for bc in self.portal_categories.objectValues():
        if group in bc.getCategoryTypeList():
          category_list.append(bc.getId())
      return tuple(category_list)

371 372
    getCategoryList = CachingMethod(
                            getCategoryList,
373
                            id=('_getPortalGroupedCategoryList', group),
374
                            cache_duration=3600)
375 376 377
    return getCategoryList(group)

  def _getPortalGroupedStateList(self, group):
378
    """
379
    Return a list of workflow states classified to a specific group.
380 381 382 383 384 385 386 387 388 389
    """
    def getStateList(group):
      state_dict = {}
      for wf in self.portal_workflow.objectValues():
        if getattr(wf, 'states', None):
          for state in wf.states.objectValues():
            if group in getattr(state, 'type_list', ()):
              state_dict[state.getId()] = None
      return tuple(state_dict.keys())

390
    getStateList = CachingMethod(getStateList,
391
                                 id=('_getPortalGroupedStateList', group),
392
                                 cache_duration=3600)
393 394
    return getStateList(group)

395 396
  security.declareProtected(Permissions.AccessContentsInformation,
                            'getPortalDefaultSectionCategory')
397 398
  def getPortalDefaultSectionCategory(self):
    """
399
    Return a default section category. This method is deprecated.
400 401 402 403
    """
    LOG('ERP5Site', 0, 'getPortalDefaultSectionCategory is deprecated;'+
        ' use portal_preferences.getPreferredSectionCategory instead.')
    section_category = self.portal_preferences.getPreferredSectionCategory()
404

405 406 407 408
    # XXX This is only for backward-compatibility.
    if not section_category:
      section_category = self._getPortalConfiguration(
                                'portal_default_section_category')
409

410
    return section_category
411

412 413 414 415 416 417
  security.declareProtected(Permissions.AccessContentsInformation,
                            'getPortalResourceTypeList')
  def getPortalResourceTypeList(self):
    """
      Return resource types.
    """
418 419 420
    return self._getPortalGroupedTypeList('resource') or \
           self._getPortalConfiguration('portal_resource_type_list')

421 422 423 424 425 426 427
  security.declareProtected(Permissions.AccessContentsInformation,
                            'getPortalSubVariationTypeList')
  def getPortalSubVariationTypeList(self):
    """
      Return resource types.
    """
    return self._getPortalGroupedTypeList('sub_variation')
428

429 430 431 432 433 434 435
  security.declareProtected(Permissions.AccessContentsInformation,
                            'getPortalSubVariationBaseCategoryList')
  def getPortalSubVariationBaseCategoryList(self):
    """
      Return variation base categories.
    """
    return self._getPortalGroupedCategoryList('sub_variation')
436

437 438 439 440 441 442
  security.declareProtected(Permissions.AccessContentsInformation,
                            'getPortalVariationTypeList')
  def getPortalVariationTypeList(self):
    """
      Return variation types.
    """
443 444 445
    return self._getPortalGroupedTypeList('variation') or \
           self._getPortalConfiguration('portal_variation_type_list')

446 447 448 449 450 451
  security.declareProtected(Permissions.AccessContentsInformation,
                            'getPortalNodeTypeList')
  def getPortalNodeTypeList(self):
    """
      Return node types.
    """
452 453 454
    return self._getPortalGroupedTypeList('node') or \
           self._getPortalConfiguration('portal_node_type_list')

455 456 457 458 459 460
  security.declareProtected(Permissions.AccessContentsInformation,
                            'getPortalPaymentNodeTypeList')
  def getPortalPaymentNodeTypeList(self):
    """
      Return payment node types.
    """
461 462 463
    return self._getPortalGroupedTypeList('payment_node') or \
           self._getPortalConfiguration('portal_payment_node_type_list')

464 465 466 467 468 469
  security.declareProtected(Permissions.AccessContentsInformation,
                            'getPortalInvoiceTypeList')
  def getPortalInvoiceTypeList(self):
    """
      Return invoice types.
    """
470 471 472
    return self._getPortalGroupedTypeList('invoice') or \
           self._getPortalConfiguration('portal_invoice_type_list')

473 474 475 476 477 478
  security.declareProtected(Permissions.AccessContentsInformation,
                            'getPortalOrderTypeList')
  def getPortalOrderTypeList(self):
    """
      Return order types.
    """
479 480 481
    return self._getPortalGroupedTypeList('order') or \
           self._getPortalConfiguration('portal_order_type_list')

482 483 484 485 486 487
  security.declareProtected(Permissions.AccessContentsInformation,
                            'getPortalDeliveryTypeList')
  def getPortalDeliveryTypeList(self):
    """
      Return delivery types.
    """
488 489 490
    return self._getPortalGroupedTypeList('delivery') or \
           self._getPortalConfiguration('portal_delivery_type_list')

491 492 493 494 495 496
  security.declareProtected(Permissions.AccessContentsInformation,
                            'getPortalTransformationTypeList')
  def getPortalTransformationTypeList(self):
    """
      Return transformation types.
    """
497 498 499
    return self._getPortalGroupedTypeList('transformation') or \
           self._getPortalConfiguration('portal_transformation_type_list')

500 501 502 503 504 505
  security.declareProtected(Permissions.AccessContentsInformation,
                            'getPortalVariationBaseCategoryList')
  def getPortalVariationBaseCategoryList(self):
    """
      Return variation base categories.
    """
506 507 508
    return self._getPortalGroupedCategoryList('variation') or \
           self._getPortalConfiguration('portal_variation_base_category_list')

509 510 511 512 513 514
  security.declareProtected(Permissions.AccessContentsInformation,
                            'getPortalOptionBaseCategoryList')
  def getPortalOptionBaseCategoryList(self):
    """
      Return option base categories.
    """
515 516 517
    return self._getPortalGroupedCategoryList('option') or \
           self._getPortalConfiguration('portal_option_base_category_list')

518 519 520 521 522 523
  security.declareProtected(Permissions.AccessContentsInformation,
                            'getPortalInvoiceMovementTypeList')
  def getPortalInvoiceMovementTypeList(self):
    """
      Return invoice movement types.
    """
524 525 526
    return self._getPortalGroupedTypeList('invoice_movement') or \
           self._getPortalConfiguration('portal_invoice_movement_type_list')

527 528 529 530 531 532
  security.declareProtected(Permissions.AccessContentsInformation,
                            'getPortalOrderMovementTypeList')
  def getPortalOrderMovementTypeList(self):
    """
      Return order movement types.
    """
533 534 535
    return self._getPortalGroupedTypeList('order_movement') or \
           self._getPortalConfiguration('portal_order_movement_type_list')

536 537 538 539 540 541
  security.declareProtected(Permissions.AccessContentsInformation,
                            'getPortalDeliveryMovementTypeList')
  def getPortalDeliveryMovementTypeList(self):
    """
      Return delivery movement types.
    """
542 543 544
    return self._getPortalGroupedTypeList('delivery_movement') or \
           self._getPortalConfiguration('portal_delivery_movement_type_list')

545
  security.declareProtected(Permissions.AccessContentsInformation,
546
                            'getPortalSupplyTypeList')
547 548 549 550
  def getPortalSupplyTypeList(self):
    """
      Return supply types.
    """
551 552 553
    return self._getPortalGroupedTypeList('supply') or \
           self._getPortalConfiguration('portal_supply_type_list')

554
  security.declareProtected(Permissions.AccessContentsInformation,
555 556 557 558 559 560 561 562 563 564 565 566 567 568 569
                              'getPortalDocumentTypeList')
  def getPortalDocumentTypeList(self):
    """
      Return document types.
    """
    return self._getPortalGroupedTypeList('dms_document')

  security.declareProtected(Permissions.AccessContentsInformation,
                            'getPortalWebDocumentTypeList')
  def getPortalWebDocumentTypeList(self):
    """
      Return web page types.
    """
    return self._getPortalGroupedTypeList('web_document')

570
  security.declareProtected(Permissions.AccessContentsInformation,
571
                            'getPortalSupplyPathTypeList')
572 573 574 575
  def getPortalSupplyPathTypeList(self):
    """
      Return supply movement types.
    """
576 577 578
    return self._getPortalGroupedTypeList('supply_path') or \
           self._getPortalConfiguration('portal_supply_path_type_list')

579 580 581 582 583 584 585
  security.declareProtected(Permissions.AccessContentsInformation,
                            'getPortalAcquisitionMovementTypeList')
  def getPortalAcquisitionMovementTypeList(self):
    """
      Return acquisition movement types.
    """
    return tuple(list(self.getPortalOrderMovementTypeList()) +
586 587 588
                 list(self.getPortalDeliveryMovementTypeList()) +
                 list(self.getPortalInvoiceMovementTypeList()))

589 590 591 592 593 594 595
  security.declareProtected(Permissions.AccessContentsInformation,
                            'getPortalMovementTypeList')
  def getPortalMovementTypeList(self):
    """
      Return movement types.
    """
    return tuple(list(self.getPortalOrderMovementTypeList()) +
596 597
                 list(self.getPortalDeliveryMovementTypeList()) +
                 list(self.getPortalInvoiceMovementTypeList()) +
598
                 ['Simulation Movement'])
599

600 601 602 603 604 605
  security.declareProtected(Permissions.AccessContentsInformation,
                            'getPortalSimulatedMovementTypeList')
  def getPortalSimulatedMovementTypeList(self):
    """
      Return simulated movement types.
    """
606
    return tuple([x for x in self.getPortalMovementTypeList() \
607
                  if x not in self.getPortalContainerTypeList()])
608

609 610 611 612 613 614
  security.declareProtected(Permissions.AccessContentsInformation,
                            'getPortalContainerTypeList')
  def getPortalContainerTypeList(self):
    """
      Return container types.
    """
615 616 617
    return self._getPortalGroupedTypeList('container') or \
           self._getPortalConfiguration('portal_container_type_list')

618 619 620 621 622 623
  security.declareProtected(Permissions.AccessContentsInformation,
                            'getPortalContainerLineTypeList')
  def getPortalContainerLineTypeList(self):
    """
      Return container line types.
    """
624 625 626
    return self._getPortalGroupedTypeList('container_line') or \
           self._getPortalConfiguration('portal_container_line_type_list')

627 628 629 630 631 632
  security.declareProtected(Permissions.AccessContentsInformation,
                            'getPortalItemTypeList')
  def getPortalItemTypeList(self):
    """
      Return item types.
    """
633 634 635
    return self._getPortalGroupedTypeList('item') or \
           self._getPortalConfiguration('portal_item_type_list')

636 637 638 639 640 641
  security.declareProtected(Permissions.AccessContentsInformation,
                            'getPortalDiscountTypeList')
  def getPortalDiscountTypeList(self):
    """
      Return discount types.
    """
642 643 644
    return self._getPortalGroupedTypeList('discount') or \
           self._getPortalConfiguration('portal_discount_type_list')

645 646 647 648 649 650
  security.declareProtected(Permissions.AccessContentsInformation,
                            'getPortalAlarmTypeList')
  def getPortalAlarmTypeList(self):
    """
      Return alarm types.
    """
651 652 653
    return self._getPortalGroupedTypeList('alarm') or \
           self._getPortalConfiguration('portal_alarm_type_list')

654 655 656 657 658 659
  security.declareProtected(Permissions.AccessContentsInformation,
                            'getPortalPaymentConditionTypeList')
  def getPortalPaymentConditionTypeList(self):
    """
      Return payment condition types.
    """
660 661 662
    return self._getPortalGroupedTypeList('payment_condition') or \
           self._getPortalConfiguration('portal_payment_condition_type_list')

663 664 665 666 667 668
  security.declareProtected(Permissions.AccessContentsInformation,
                            'getPortalBalanceTransactionLineTypeList')
  def getPortalBalanceTransactionLineTypeList(self):
    """
      Return balance transaction line types.
    """
669
    return self._getPortalGroupedTypeList('balance_transaction_line') or \
670 671
           self._getPortalConfiguration(
                  'portal_balance_transaction_line_type_list')
672

673 674 675 676 677 678
  security.declareProtected(Permissions.AccessContentsInformation,
                            'getPortalCurrentInventoryStateList')
  def getPortalCurrentInventoryStateList(self):
    """
      Return current inventory states.
    """
679 680 681
    return self._getPortalGroupedStateList('current_inventory') or \
           self._getPortalConfiguration('portal_current_inventory_state_list')

682 683 684 685 686 687
  security.declareProtected(Permissions.AccessContentsInformation,
                            'getPortalDraftOrderStateList')
  def getPortalDraftOrderStateList(self):
    """
      Return draft order states.
    """
688 689 690
    return self._getPortalGroupedStateList('draft_order') or \
           self._getPortalConfiguration('portal_draft_order_state_list')

691 692 693 694 695 696
  security.declareProtected(Permissions.AccessContentsInformation,
                            'getPortalPlannedOrderStateList')
  def getPortalPlannedOrderStateList(self):
    """
      Return planned order states.
    """
697 698 699
    return self._getPortalGroupedStateList('planned_order') or \
           self._getPortalConfiguration('portal_planned_order_state_list')

700 701 702 703 704 705
  security.declareProtected(Permissions.AccessContentsInformation,
                            'getPortalReservedInventoryStateList')
  def getPortalReservedInventoryStateList(self):
    """
      Return reserved inventory states.
    """
706
    return self._getPortalGroupedStateList('reserved_inventory') or \
707
        self._getPortalConfiguration('portal_reserved_inventory_state_list')
708

709 710 711 712 713 714
  security.declareProtected(Permissions.AccessContentsInformation,
                            'getPortalFutureInventoryStateList')
  def getPortalFutureInventoryStateList(self):
    """
      Return future inventory states.
    """
715 716 717
    return self._getPortalGroupedStateList('future_inventory') or \
           self._getPortalConfiguration('portal_future_inventory_state_list')

718
  security.declareProtected(Permissions.AccessContentsInformation,
719
                          'getPortalUpdatableAmortisationTransactionStateList')
720 721
  def getPortalUpdatableAmortisationTransactionStateList(self):
    """
722
      Return states when Amortisation Transaction can be updated
723
      by amortisation_transaction_builder.
724
    """
725 726
    return self._getPortalConfiguration(
        'portal_updatable_amortisation_transaction_state_list')
727

728 729 730 731 732 733
  security.declareProtected(Permissions.AccessContentsInformation,
                            'getPortalColumnBaseCategoryList')
  def getPortalColumnBaseCategoryList(self):
    """
      Return column base categories.
    """
734 735 736
    return self._getPortalGroupedCategoryList('column') or \
           self._getPortalConfiguration('portal_column_base_category_list')

737 738 739 740 741 742
  security.declareProtected(Permissions.AccessContentsInformation,
                            'getPortalLineBaseCategoryList')
  def getPortalLineBaseCategoryList(self):
    """
      Return line base categories.
    """
743 744 745
    return self._getPortalGroupedCategoryList('line') or \
           self._getPortalConfiguration('portal_line_base_category_list')

746 747 748 749 750 751
  security.declareProtected(Permissions.AccessContentsInformation,
                            'getPortalTabBaseCategoryList')
  def getPortalTabBaseCategoryList(self):
    """
      Return tab base categories.
    """
752 753 754
    return self._getPortalGroupedCategoryList('tab') or \
           self._getPortalConfiguration('portal_tab_base_category_list')

755 756 757 758
  def getPortalDefaultGapRoot(self):
    """
      Return the Accounting Plan to use by default (return the root node)
    """
759
    LOG('ERP5Site', 0,
760 761 762
        'getPortalDefaultGapRoot is deprecated; ' \
        'use portal_preferences.getPreferredAccountingTransactionGap instead.')

763 764
    return self.portal_preferences.getPreferredAccountingTransactionGap() or \
           self._getPortalConfiguration('portal_default_gap_root')
765

766 767 768 769
  def getPortalAccountingMovementTypeList(self) :
    """
      Return accounting movement type list.
    """
770
    return self._getPortalGroupedTypeList('accounting_movement') or \
771
        self._getPortalConfiguration('portal_accounting_movement_type_list')
772

773 774 775 776
  def getPortalAccountingTransactionTypeList(self) :
    """
      Return accounting transaction movement type list.
    """
777
    return self._getPortalGroupedTypeList('accounting_transaction') or \
778
      self._getPortalConfiguration('portal_accounting_transaction_type_list')
779

780 781 782 783
  def getPortalAssignmentBaseCategoryList(self):
    """
      Return List of category values to generate security groups.
    """
784
    return self._getPortalGroupedCategoryList('assignment') or \
785
        self._getPortalConfiguration('portal_assignment_base_category_list')
786

787 788
  security.declareProtected(Permissions.AccessContentsInformation,
                            'getPortalTicketTypeList')
789 790 791 792 793
  def getPortalTicketTypeList(self):
    """
    Return ticket types.
    """
    return self._getPortalGroupedTypeList('ticket')
794

795 796
  security.declareProtected(Permissions.AccessContentsInformation,
                            'getPortalEventTypeList')
797 798 799 800 801
  def getPortalEventTypeList(self):
    """
    Return event types.
    """
    return self._getPortalGroupedTypeList('event')
802

803 804
  security.declareProtected(Permissions.AccessContentsInformation,
                            'getDefaultModuleId')
805 806 807 808 809 810 811 812 813 814
  def getDefaultModuleId(self, portal_type, default=MARKER):
    """
      Return default module id where a object with portal_type can
      be created.
    """
    # Very dummy method, but it works with today name convention.
    module_name = portal_type.lower().replace(' ','_')
    portal_object = self
    if not hasattr(portal_object, module_name):
      module_name += '_module'
815
      if not hasattr(portal_object, module_name):
816 817 818
        if default is not MARKER:
          return default
        LOG('ERP5Site, getDefaultModuleId', 0,
819 820 821 822
            'Unable to find default module for portal_type: %s' % \
                portal_type)
        raise ValueError, 'Unable to find module for portal_type: %s' % \
                          portal_type
823 824
    return module_name

825 826
  security.declareProtected(Permissions.AccessContentsInformation,
                            'getDefaultModule')
827 828 829 830 831
  def getDefaultModule(self, portal_type):
    """
      Return default module where a object with portal_type can be created
    """
    return getattr(self, self.getDefaultModuleId(portal_type), None)
832

833 834 835 836 837 838 839 840 841
  security.declareProtected(Permissions.AddPortalContent, 'newContent')
  def newContent(self, id=None, portal_type=None, immediate_reindex=0, **kw):
    """
      Creates a new content
    """
    if id is None:
      raise ValueError, 'The id should not be None'
    if portal_type is None:
      raise ValueError, 'The portal_type should not be None'
842 843 844 845
    self.portal_types.constructContent(type_name=portal_type,
                                       container=self,
                                       id=id,
                                       ) # **kw) removed due to CMF bug
846
    new_instance = self[id]
847 848 849 850
    if kw is not None:
      new_instance._edit(force_update=1, **kw)
    if immediate_reindex:
      new_instance.immediateReindexObject()
851 852 853 854
    return new_instance

  def log(self,description,content):
    """
855
    Put a log message
856
    """
857 858
    LOG(description, 0, content)

859

Jean-Paul Smets's avatar
Jean-Paul Smets committed
860 861 862 863
Globals.InitializeClass(ERP5Site)

class ERP5Generator(PortalGenerator):

864
  klass = ERP5Site
865

866 867 868 869 870 871 872
  def getBootstrapDirectory(self):
    """
      Return the name of the bootstrap directory
    """
    product_path = package_home(globals())
    return os.path.join(product_path, 'bootstrap')

873 874 875
  def create(self,
             parent,
             id,
876
             create_userfolder,
877
             erp5_sql_connection_type,
878 879 880 881 882 883 884 885
             erp5_sql_connection_string,
             erp5_sql_deferred_connection_type,
             erp5_sql_deferred_connection_string,
             cmf_activity_sql_connection_type,
             cmf_activity_sql_connection_string,
             create_activities=1,
             reindex=1,
             **kw):
886 887
    id = str(id)
    portal = self.klass(id=id)
888 889
    # Make sure reindex will not be called until business templates
    # will be installed
890
    setattr(portal, 'isIndexable', 0)
891 892 893
    parent._setObject(id, portal)
    # Return the fully wrapped object.
    p = parent.this()._getOb(id)
894
    p._setProperty('erp5_sql_connection_type',
895
                   erp5_sql_connection_type, 'string')
896
    p._setProperty('erp5_sql_connection_string',
897
                   erp5_sql_connection_string, 'string')
898
    p._setProperty('erp5_sql_deferred_connection_type',
899
                   erp5_sql_deferred_connection_type, 'string')
900
    p._setProperty('erp5_sql_deferred_connection_string',
901
                   erp5_sql_deferred_connection_string, 'string')
902
    p._setProperty('cmf_activity_sql_connection_type',
903
                   cmf_activity_sql_connection_type, 'string')
904
    p._setProperty('cmf_activity_sql_connection_string',
905 906
                   cmf_activity_sql_connection_string, 'string')
    # XXX hardcoded charset
907
    p._setProperty('management_page_charset', 'UTF-8', 'string')
908
    self.setup(p, create_userfolder,
909
               create_activities=create_activities, **kw)
910 911 912 913
    return p

  def setupLastTools(self, p, **kw):
    """
914 915 916
    Set up finals tools
    We want to set the activity tool only at the end to
    make sure that we do not put un the queue the full reindexation
917 918
    """
    # Add Activity Tool
919
    if kw.has_key('create_activities') and int(kw['create_activities'])==1:
920 921 922 923 924 925 926 927 928 929 930
      if not p.hasObject('portal_activities'):
        addTool = p.manage_addProduct['CMFActivity'].manage_addTool
        addTool('CMF Activity Tool', None) # Allow user to select active/passive
      # Initialize Activities
      portal_activities = getToolByName(p, 'portal_activities', None)
      if portal_activities is not None:
        if kw.get('update', 0):
          keep = 1
        else:
          keep = 0
        portal_activities.manageClearActivities(keep=keep)
931

932 933
  def setupTemplateTool(self, p, **kw):
    """
934
    Setup the Template Tool. Security must be set strictly.
935 936 937 938 939 940 941 942 943 944
    """
    addTool = p.manage_addProduct['ERP5'].manage_addTool
    addTool('ERP5 Template Tool', None)
    context = p.portal_templates
    permission_list = context.possible_permissions()
    for permission in permission_list:
      context.manage_permission(permission, ['Manager'], 0)

  def setupTools(self, p,**kw):
    """
945
    Set up initial tools.
946 947 948 949
    """
    if not 'portal_actions' in p.objectIds():
      PortalGenerator.setupTools(self, p)

950
    # It is better to remove portal_catalog
951
    # which is ZCatalog as soon as possible,
952
    # because the API is not the completely same as ERP5Catalog,
953
    # and ZCatalog is useless for ERP5 after all.
954 955
    update = kw.get('update', 0)
    portal_catalog = getToolByName(p, 'portal_catalog', None)
956 957 958
    if portal_catalog is not None and \
       portal_catalog.meta_type != 'ZSQLCatalog' and \
       not update:
959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987
      p._delObject('portal_catalog')

    # Add CMF Report Tool
    if not p.hasObject('portal_report'):
      addTool = p.manage_addProduct['CMFReportTool'].manage_addTool
      addTool('CMF Report Tool', None)

    # Add ERP5 Tools
    addTool = p.manage_addProduct['ERP5'].manage_addTool
    if not p.hasObject('portal_categories'):
      addTool('ERP5 Categories', None)
    if not p.hasObject('portal_rules'):
      addTool('ERP5 Rule Tool', None)
    if not p.hasObject('portal_ids'):
      addTool('ERP5 Id Tool', None)
    if not p.hasObject('portal_simulation'):
      addTool('ERP5 Simulation Tool', None)
    if not p.hasObject('portal_templates'):
      self.setupTemplateTool(p)
    if not p.hasObject('portal_trash'):
      addTool('ERP5 Trash Tool', None)
    if not p.hasObject('portal_alarms'):
      addTool('ERP5 Alarm Tool', None)
    if not p.hasObject('portal_domains'):
      addTool('ERP5 Domain Tool', None)
    if not p.hasObject('portal_deliveries'):
      addTool('ERP5 Delivery Tool', None)
    if not p.hasObject('portal_orders'):
      addTool('ERP5 Order Tool', None)
988 989
    if not p.hasObject('portal_tests'):
      addTool('ERP5 Test Tool', None)
990

991 992 993 994 995 996
    try:
      addTool = p.manage_addProduct['ERP5Subversion'].manage_addTool
      if not p.hasObject('portal_subversion'):
        addTool('ERP5 Subversion Tool', None)
    except AttributeError:
      pass
997

998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012
    # Add ERP5Type Tools
    addTool = p.manage_addProduct['ERP5Type'].manage_addTool
    if not p.hasObject('portal_classes'):
      if allowClassTool():
        addTool('ERP5 Class Tool', None)
      else:
        addTool('ERP5 Dummy Class Tool', None)

    # Add ERP5 SQL Catalog Tool
    addTool = p.manage_addProduct['ERP5Catalog'].manage_addTool
    if not p.hasObject('portal_catalog'):
      addTool('ERP5 Catalog', None)
    # Add Default SQL connection
    if p.erp5_sql_connection_type == 'Z MySQL Database Connection':
      if not p.hasObject('erp5_sql_connection'):
1013 1014
        addSQLConnection = p.manage_addProduct['ZMySQLDA'].\
                                     manage_addZMySQLConnection
1015 1016
        addSQLConnection('erp5_sql_connection',
                         'ERP5 SQL Server Connection',
1017
                         p.erp5_sql_connection_string)
1018 1019
    elif p.erp5_sql_connection_type == 'Z Gadfly':
      pass
1020 1021

    # Add Deferred SQL Connections
1022 1023
    if p.erp5_sql_deferred_connection_type == \
        'Z MySQL Deferred Database Connection':
1024
      if not p.hasObject('erp5_sql_deferred_connection'):
1025 1026
        addSQLConnection = p.manage_addProduct['ZMySQLDDA'].\
            manage_addZMySQLDeferredConnection
1027 1028
        addSQLConnection('erp5_sql_deferred_connection',
                         'ERP5 SQL Server Deferred Connection',
1029
                         p.erp5_sql_deferred_connection_string)
1030 1031 1032 1033
    elif p.erp5_sql_deferred_connection_type == 'Z Gadfly':
      pass

    # Add Activity SQL Connections
1034 1035
    if p.cmf_activity_sql_connection_type == 'Z MySQL Database Connection':
      if not p.hasObject('cmf_activity_sql_connection'):
1036 1037
        addSQLConnection = p.manage_addProduct['ZMySQLDA'].\
                                     manage_addZMySQLConnection
1038 1039
        addSQLConnection('cmf_activity_sql_connection',
                         'CMF Activity SQL Server Connection',
1040
                         p.cmf_activity_sql_connection_string)
1041 1042
    elif p.cmf_activity_sql_connection_type == 'Z Gadfly':
      pass
1043

1044
    portal_catalog = getToolByName(p, 'portal_catalog')
1045 1046
    if (not update) and (not portal_catalog.getSQLCatalog('erp5_mysql')):
      # Add a default SQL Catalog
1047
      portal_catalog.addDefaultSQLMethods()
1048 1049
      if (p.erp5_sql_connection_type is not None):
        portal_catalog.manage_catalogClear()
1050
      # TODO: Replace previous lines with the commented below
1051 1052 1053 1054 1055 1056 1057
      # (not working actually).
      # The goal is to delete addDefaultSQLMethods() method and duplicated zsql
      # method from /ERP5Catalog/sql/mysql_erp5.
      #addSQLCatalog = portal_catalog.manage_addProduct['ZSQLCatalog']\
      #                                .manage_addSQLCatalog
      #addSQLCatalog('erp5_mysql', '')
      #portal_catalog.default_sql_catalog_id = 'erp5_mysql'
1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075

    # Add ERP5Form Tools
    addTool = p.manage_addProduct['ERP5Form'].manage_addTool
    if not p.hasObject('portal_selections'):
      addTool('ERP5 Selections', None)
    if not p.hasObject('portal_preferences'):
      addTool('ERP5 Preference Tool', None)

    # Add ERP5SyncML Tools
    addTool = p.manage_addProduct['ERP5SyncML'].manage_addTool
    if not p.hasObject('portal_synchronizations'):
      addTool('ERP5 Synchronizations', None)

    # Add Message Catalog
    if not 'Localizer' in p.objectIds():
      addLocalizer = p.manage_addProduct['Localizer'].manage_addLocalizer
      addLocalizer('', ('en',))
    localizer = getToolByName(p, 'Localizer')
1076 1077
    addMessageCatalog = localizer.manage_addProduct['Localizer']\
                                      .manage_addMessageCatalog
1078 1079 1080
    if 'erp5_ui' not in localizer.objectIds():
      if 'default' in localizer.objectIds():
        localizer.manage_delObjects('default')
1081 1082 1083
      addMessageCatalog('default', 'ERP5 Localized Messages', ('en',))
      addMessageCatalog('erp5_ui', 'ERP5 Localized Interface', ('en',))
      addMessageCatalog('erp5_content', 'ERP5 Localized Content', ('en',))
1084 1085 1086 1087


  def setupMembersFolder(self, p):
    """
1088
    ERP5 is not a CMS
1089 1090 1091 1092 1093
    """
    pass

  def setupDefaultSkins(self, p):
    from Products.CMFCore.DirectoryView import addDirectoryViews
1094
    from Products.CMFDefault  import cmfdefault_globals
1095
    from Products.CMFActivity import cmfactivity_globals
1096
    from Products.FCKeditor   import fckeditor_globals
1097 1098 1099
    ps = getToolByName(p, 'portal_skins')
    addDirectoryViews(ps, 'skins', cmfdefault_globals)
    addDirectoryViews(ps, 'skins', cmfactivity_globals)
1100
    addDirectoryViews(ps, 'skins', fckeditor_globals)
1101 1102
    ps.manage_addProduct['OFSP'].manage_addFolder(id='external_method')
    ps.manage_addProduct['OFSP'].manage_addFolder(id='custom')
1103
    # Set the 'custom' layer a high priority, so it remains the first
1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130
    #   layer when installing new business templates.
    ps['custom'].manage_addProperty("business_template_skin_layer_priority", 100.0, "float")
    skin_folder_list = [ 'custom'
                       , 'fckeditor'
                       , 'external_method'
                       , 'activity'
                       , 'zpt_content'
                       , 'zpt_generic'
                       , 'zpt_control'
                       , 'content'
                       , 'generic'
                       , 'control'
                       , 'Images'
                       ]
    skin_folders = ', '.join(skin_folder_list)
    ps.addSkinSelection( 'View'
                       , skin_folders
                       , make_default = 1
                       )
    ps.addSkinSelection( 'Print'
                       , skin_folders
                       , make_default = 0
                       )
    ps.addSkinSelection( 'CSV'
                       , skin_folders
                       , make_default = 0
                       )
1131 1132 1133 1134
    p.setupCurrentSkin()

  def setupWorkflow(self, p):
    """
1135
    Set up workflows for business templates
1136 1137 1138
    """
    tool = getToolByName(p, 'portal_workflow', None)
    if tool is None:
Jérome Perrin's avatar
Jérome Perrin committed
1139
      return
1140
    for wf_id in ('business_template_building_workflow',
1141
                  'business_template_installation_workflow'):
1142 1143 1144
      if wf_id in tool.objectIds():
        tool.manage_delObjects([wf_id])
    bootstrap_dir = self.getBootstrapDirectory()
1145 1146 1147
    business_template_building_workflow = os.path.join(
                                 bootstrap_dir,
                                 'business_template_building_workflow.xml')
1148
    tool._importObjectFromFile(business_template_building_workflow)
1149 1150 1151
    business_template_installation_workflow = os.path.join(
                                 bootstrap_dir,
                                 'business_template_installation_workflow.xml')
1152 1153
    tool._importObjectFromFile(business_template_installation_workflow)
    tool.setChainForPortalTypes( ( 'Business Template', ),
1154 1155
                                 ( 'business_template_building_workflow',
                                   'business_template_installation_workflow' ) )
1156 1157 1158 1159 1160 1161 1162 1163

  def setupIndex(self, p, **kw):
    # Make sure all tools and folders have been indexed
    if kw.has_key('reindex') and kw['reindex']==0:
      return
    skins_tool = getToolByName(p, 'portal_skins', None)
    if skins_tool is None:
      return
1164
    # When no SQL connection was define on the site,
1165 1166 1167 1168 1169 1170
    # we don't want to make it crash
    if p.erp5_sql_connection_type is not None:
      setattr(p, 'isIndexable', 1)
      portal_catalog = p.portal_catalog
      portal_catalog.manage_catalogClear()
      skins_tool["erp5_core"].ERP5Site_reindexAll()
1171

1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191
  def setupUserFolder(self, p):
    # We use if possible ERP5Security, then NuxUserGroups
    try:
      from Products import ERP5Security
      from Products import PluggableAuthService
    except ImportError:
      ERP5Security = None
      try:
        import Products.NuxUserGroups
        withnuxgroups = 1
      except ImportError:
        withnuxgroups = 0
    if ERP5Security is not None:
      # Use Pluggable Auth Service instead of the standard acl_users.
      p.manage_addProduct['PluggableAuthService'].addPluggableAuthService()
      # Add legacy ZODB support
      p.acl_users.manage_addProduct['PluggableAuthService'].addZODBUserManager('zodb_users')
      p.acl_users.manage_addProduct['PluggableAuthService'].addZODBGroupManager('zodb_groups')
      p.acl_users.manage_addProduct['PluggableAuthService'].addZODBRoleManager('zodb_roles')
      # Add CMF Portal Roles
1192
      #XXX Maybe it will be no longer required once PAS is the standard
1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224
      p.acl_users.zodb_roles.addRole('Member')
      p.acl_users.zodb_roles.addRole('Reviewer')
      # Register ZODB Interface
      p.acl_users.zodb_users.manage_activateInterfaces(('IAuthenticationPlugin',
                                                    'IUserEnumerationPlugin','IUserAdderPlugin'))
      p.acl_users.zodb_groups.manage_activateInterfaces(('IGroupsPlugin',
                                                    'IGroupEnumerationPlugin'))
      p.acl_users.zodb_roles.manage_activateInterfaces(('IRoleEnumerationPlugin',
                                                    'IRolesPlugin', 'IRoleAssignerPlugin'))
      # Add ERP5UserManager
      p.acl_users.manage_addProduct['ERP5Security'].addERP5UserManager('erp5_users')
      p.acl_users.manage_addProduct['ERP5Security'].addERP5GroupManager('erp5_groups')
      p.acl_users.manage_addProduct['ERP5Security'].addERP5RoleManager('erp5_roles')
      # Register ERP5UserManager Interface
      p.acl_users.erp5_users.manage_activateInterfaces(('IAuthenticationPlugin',
                                                        'IUserEnumerationPlugin',))
      p.acl_users.erp5_groups.manage_activateInterfaces(('IGroupsPlugin',))
      p.acl_users.erp5_roles.manage_activateInterfaces(('IRolesPlugin',))
    elif withnuxgroups:
      # NuxUserGroups user folder
      p.manage_addProduct['NuxUserGroups'].addUserFolderWithGroups()
    else:
      # Standard user folder
      PortalGenerator.setupUserFolder(self, p)

  def setupPermissions(self, p):
    permission_dict = {
      'Access Transient Objects'     : ('Manager', 'Anonymous'),
      'Access contents information'  : ('Manager', 'Member', 'Anonymous'),
      'Access future portal content' : ('Manager', 'Reviewer'),
      'Access session data'          : ('Manager', 'Anonymous'),
      'AccessContentsInformation'    : ('Manager', 'Member'),
1225
      'Change local roles'           : ('Manager', ),
1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237
      'Add portal content'           : ('Manager', 'Owner'),
      'Add portal folders'           : ('Manager', 'Owner'),
      'Delete objects'               : ('Manager', 'Owner'),
      'FTP access'                   : ('Manager', 'Owner'),
      'List folder contents'         : ('Manager', 'Member'),
      'List portal members'          : ('Manager', 'Member'),
      'List undoable changes'        : ('Manager', 'Member'),
      'Manage properties'            : ('Manager', 'Owner'),
      'Modify portal content'        : ('Manager', 'Owner'),
      'Reply to item'                : ('Manager', 'Member'),
      'Review portal content'        : ('Manager', 'Reviewer'),
      'Search ZCatalog'              : ('Manager', 'Member'),
1238
      'Set own password'             : ('Manager', ),
1239 1240
      'Set own properties'           : ('Manager', 'Member'),
      'Undo changes'                 : ('Manager', 'Owner'),
1241
      'View'                         : ('Manager', 'Member',
1242
                                        'Owner', 'Anonymous'),
1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253
      'View management screens'      : ('Manager', 'Owner')
    }

    for permission in p.ac_inherited_permissions(1):
      name = permission[0]
      role_list = permission_dict.get(name, ('Manager',))
      p.manage_permission(name, roles=role_list, acquire=0)

  def setup(self, p, create_userfolder, **kw):
    update = kw.get('update', 0)

1254 1255 1256
    if getattr(p, 'setDefaultSorting', None) is not None:
      p.setDefaultSorting('id', 0)

1257 1258 1259 1260 1261
    self.setupTools(p, **kw)

    if not p.hasObject('MailHost'):
      self.setupMailHost(p)

Jérome Perrin's avatar
Jérome Perrin committed
1262 1263
    if create_userfolder and not p.hasObject('acl_users'):
      self.setupUserFolder(p)
1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290

    if not p.hasObject('cookie_authentication'):
      self.setupCookieAuth(p)

    if 'Member' not in getattr(p, '__ac_roles__', ()):
      self.setupRoles(p)

    if not update:
      self.setupPermissions(p)
      self.setupDefaultSkins(p)

    # Finish setup
    if not p.hasObject('Members'):
      self.setupMembersFolder(p)

    # ERP5 Design Choice is that all content should be user defined
    # Content is disseminated through business templates
    self.setupBusinessTemplate(p)

    if not p.hasObject('content_type_registry'):
      self.setupMimetypes(p)
    if not update:
      self.setupWorkflow(p)

    if not update:
      self.setupERP5Core(p,**kw)

1291 1292
    self.setupLastTools(p, **kw)

1293 1294 1295 1296 1297 1298 1299
    # Make sure tools are cleanly indexed with a uid before creating children
    # XXX for some strange reason, member was indexed 5 times
    if not update:
      self.setupIndex(p, **kw)

  def setupBusinessTemplate(self,p):
    """
1300
    Install the portal_type of Business Template
1301 1302 1303 1304 1305 1306 1307 1308 1309
    """
    tool = getToolByName(p, 'portal_types', None)
    if tool is None:
      return
    if 'Business Template' not in tool.objectIds():
      t = BusinessTemplate.factory_type_information
      ti = apply(ERP5TypeInformation, (), t)
      tool._setObject(t['id'], ti)

1310
  def setupERP5Core(self,p,**kw):
1311
    """
1312
    Install the core part of ERP5
1313 1314 1315 1316 1317 1318
    """
    template_tool = getToolByName(p, 'portal_templates', None)
    if template_tool is None:
      return
    if template_tool.getInstalledBusinessTemplate('erp5_core') is None:
      bootstrap_dir = self.getBootstrapDirectory()
1319
      for bt in ('erp5_core', 'erp5_xhtml_style'):
1320 1321 1322 1323 1324 1325 1326
        template = os.path.join(bootstrap_dir, bt)
        if not os.path.exists(template):
          template = os.path.join(bootstrap_dir, '%s.bt5' % bt)

        id = template_tool.generateNewId()
        template_tool.download(template, id=id)
        template_tool[id].install(**kw)