CategoryTool.py 7.4 KB
Newer Older
Jean-Paul Smets's avatar
Jean-Paul Smets committed
1 2 3
##############################################################################
#
# Copyright (c) 2002 Nexedi SARL and Contributors. All Rights Reserved.
Jean-Paul Smets's avatar
Jean-Paul Smets committed
4
#                    Jean-Paul Smets-Solanes <jp@nexedi.com>
Jean-Paul Smets's avatar
Jean-Paul Smets committed
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
#
# 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.
#
##############################################################################

"""\
ERP portal_categories tool.
"""

33
from Products.CMFCategory.CategoryTool import CategoryTool as CMFCategoryTool
34
from Products.ERP5Type.Tool.BaseTool import BaseTool
35 36 37 38 39
from Products.BTreeFolder2.BTreeFolder2 import BTreeFolder2
from AccessControl import ClassSecurityInfo
from Globals import InitializeClass, DTMLFile, PersistentMapping
from OFS.Folder import Folder as OFS_Folder
from Products.ERP5Type import Permissions
40
from Products.CMFCore.PortalFolder import PortalFolder
Sebastien Robin's avatar
Sebastien Robin committed
41
from Products.ERP5Type.CopySupport import CopyContainer
42 43
from Products.CMFCore.utils import getToolByName
from Products.ERP5Type.Document import newTempBase
44
from Products.ERP5Type.Cache import CachingMethod
Jean-Paul Smets's avatar
Jean-Paul Smets committed
45 46 47

from zLOG import LOG

Sebastien Robin's avatar
Sebastien Robin committed
48
class CategoryTool(CopyContainer, CMFCategoryTool, BaseTool):
Jean-Paul Smets's avatar
Jean-Paul Smets committed
49 50 51 52 53 54 55
    """
      The CategoryTool object is the placeholder for all methods
      and algorithms related to categories and relations in ERP5.
    """

    id              = 'portal_categories'
    meta_type       = 'ERP5 Categories'
56
    portal_type     = 'Category Tool'
Jean-Paul Smets's avatar
Jean-Paul Smets committed
57 58 59 60 61 62 63 64
    allowed_types   = ( 'ERP5 Base Category',)

    # Declarative Security
    security = ClassSecurityInfo()

    # Filter content (ZMI))
    def filtered_meta_types(self, user=None):
        # Filters the list of available meta types.
65
        #all = CMFCategoryTool.inheritedAttribute('filtered_meta_types')(self)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
66 67 68 69 70 71
        meta_types = []
        for meta_type in self.all_meta_types():
            if meta_type['name'] in self.allowed_types:
                meta_types.append(meta_type)
        return meta_types

72 73
    # patch, so that we are able to add the BaseCategory
    allowedContentTypes = BaseTool.allowedContentTypes
74
    getVisibleAllowedContentTypeList = BaseTool.getVisibleAllowedContentTypeList
75

76 77 78 79 80
    # patch, so that we are able to rename base categories
    _verifyObjectPaste = PortalFolder._verifyObjectPaste

    all_meta_types = BaseTool.all_meta_types

Sebastien Robin's avatar
Sebastien Robin committed
81 82 83 84
    security.declareProtected(Permissions.View, 'hasContent')
    def hasContent(self,id):
      return id in self.objectIds()

Jean-Paul Smets's avatar
Jean-Paul Smets committed
85 86 87
    security.declareProtected(Permissions.AccessContentsInformation, 'getCategoryParentUidList')
    def getCategoryParentUidList(self, relative_url, base_category = None, strict=0):
      """
88 89 90 91 92 93 94
        Returns the uids of all categories provided in categorie. This
        method can support relative_url such as site/group/a/b/c which
        base category is site yet use categories defined in group.

        It is also able to use acquisition to create complex categories
        such as site/group/a/b/c/b1/c1 where b and b1 are both children
        categories of a.
Jean-Paul Smets's avatar
Jean-Paul Smets committed
95 96 97 98 99 100 101 102 103 104 105 106 107 108

        relative_url -- a single relative url of a list of
                        relative urls

        strict       -- if set to 1, only return uids of parents, not
                        relative_url
      """
      uid_dict = {}
      if type(relative_url) is type('a'): relative_url = (relative_url,)
      for path in relative_url:
        try:
          o = self.getCategoryValue(path, base_category=base_category)
          if o is not None:
            if base_category is None:
109
              my_base_category = self.getBaseCategoryId(path)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
110
            else:
111 112
              my_base_category = base_category
            bo = getattr(self, my_base_category, None)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
113
            if bo is not None:
114 115
              bo_uid = bo.getUid()
              uid_dict[(o.getUid(), bo_uid, 1)] = 1 # Strict membership
Jean-Paul Smets's avatar
Jean-Paul Smets committed
116 117 118 119 120 121 122
              if o.meta_type == 'ERP5 Category' or o.meta_type == 'ERP5 Base Category' or \
                o.meta_type == 'CMF Category' or o.meta_type == 'CMF Base Category':
                # This goes up in the category tree
                # XXX we should also go up in some other cases....
                # ie. when some documents act as categories
                if not strict:
                  while o.meta_type == 'ERP5 Category' or o.meta_type == 'CMF Category':
123
                    o = o.aq_parent # We want acquisition here without aq_inner
124
                    uid_dict[(o.getUid(), bo_uid, 0)] = 1 # Non strict
Yoshinori Okuji's avatar
Yoshinori Okuji committed
125
        except (TypeError, KeyError):
Jean-Paul Smets's avatar
Jean-Paul Smets committed
126 127 128 129 130 131
          LOG('WARNING: CategoriesTool',0, 'Unable to find uid for %s' % path)
      return uid_dict.keys()

    security.declareProtected(Permissions.AccessContentsInformation, 'getUids')
    getUids = getCategoryParentUidList

132 133 134 135 136 137 138 139
    def getBaseCategoryDict(self):
      """
        Cached method to which resturns a dict with category names as keys, and None as values.
        This allows to search for an element existence in the list faster.
        ie: if x in self.getPortalObject().portal_categories.getBaseCategoryDict()
      """
      def getBaseCategoryDict(self):
        return dict.fromkeys(self.getBaseCategoryList(), None)
Aurel's avatar
Aurel committed
140
      return CachingMethod(getBaseCategoryDict, 'portal_categories.getBaseCategoryDict', cache_factory='erp5_core_long')(self)
141

142 143 144 145 146
    def updateRelatedContent(self, context,
                             previous_category_url, new_category_url):
      """See CMFCategory.CategoryTool.updateRelatedContent

      This method also update all predicates membership
147
      """
148 149 150
      CMFCategoryTool.updateRelatedContent(self,
                                           context,previous_category_url,
                                           new_category_url)
151 152

      # We also need to udpate all predicates membership
153 154
      domain_tool = getToolByName(context, 'portal_domains')
      portal_catalog = getToolByName(context, 'portal_catalog')
155 156 157 158 159 160
      kw = {}
      kw['predicate_category.category_uid'] = context.getUid()
      object_list = portal_catalog(**kw)
      for predicate in [x.getObject() for x in object_list]:
        membership_list = []
        for category in predicate.getMembershipCriterionCategoryList():
161 162 163
          new_category = self.updateRelatedCategory(category,
                                                    previous_category_url,
                                                    new_category_url)
164 165
          membership_list.append(new_category)
        predicate.setMembershipCriterionCategoryList(membership_list)
166 167
      # We do not need to to things recursively since
      # updateRelatedContent is already recursive.
168

Jean-Paul Smets's avatar
Jean-Paul Smets committed
169
InitializeClass( CategoryTool )
170