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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
##############################################################################
#
# Copyright (c) 2002 Nexedi SARL and Contributors. All Rights Reserved.
# Jean-Paul Smets-Solanes <jp@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility 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
# guarantees 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.
#
##############################################################################
"""\
ERP5 portal_categories tool.
"""
from Products.CMFCategory.CategoryTool import CategoryTool as CMFCategoryTool
from Products.ERP5Type.Tool.BaseTool import BaseTool
from AccessControl import ClassSecurityInfo
from Acquisition import aq_base
from Products.ERP5Type.Globals import InitializeClass
from Products.ERP5Type import Permissions
from Products.ERP5Type.Core.Folder import OFS_HANDLER
from Products.ERP5Type.CopySupport import CopyContainer
from Products.CMFCore.utils import getToolByName
from Products.ERP5Type.Cache import caching_instance_method
from Products.ERP5Type.dynamic import portal_type_class
from zLOG import LOG
class CategoryTool(CopyContainer, CMFCategoryTool, BaseTool):
"""
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'
portal_type = 'Category Tool'
allowed_types = ( 'ERP5 Base Category',)
_folder_handler = OFS_HANDLER
# Declarative Security
security = ClassSecurityInfo()
objectValues = BaseTool.objectValues
# Filter content (ZMI))
def filtered_meta_types(self, user=None):
# Filters the list of available meta types.
#all = CMFCategoryTool.inheritedAttribute('filtered_meta_types')(self)
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
# patch, so that we are able to add the BaseCategory
allowedContentTypes = BaseTool.allowedContentTypes
getVisibleAllowedContentTypeList = BaseTool.getVisibleAllowedContentTypeList
# Override this method to resolve an inheritance problem.
def _verifyObjectPaste(self, *args, **kw):
return BaseTool._verifyObjectPaste(self, *args, **kw)
all_meta_types = BaseTool.all_meta_types
security.declareProtected(Permissions.View, 'hasContent')
def hasContent(self,id):
return id in self.objectIds()
security.declareProtected(Permissions.AccessContentsInformation, 'getBaseCategoryDict')
@caching_instance_method(
id='portal_categories.getBaseCategoryDict',
cache_factory='erp5_content_long',
cache_id_generator=lambda *a: portal_type_class.last_sync)
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()
"""
return dict.fromkeys(self.getBaseCategoryList(), None)
def updateRelatedContent(self, context,
previous_category_url, new_category_url):
"""Updates categories of related objects and predicate membership.
o context: the moved object
o previous_category_url: the related url of this object before
the move
o new_category_url: the related url of the object after the move
TODO: make this method resist to very large updates (ie. long transaction)
"""
portal_catalog = getToolByName(context, 'portal_catalog')
activate_kw = {'tag':'%s_updateRelatedContent' % context.getPath()}
# udpate category related objects
kw = {'category.category_uid': context.getUid(), 'limit': None}
for related_object in portal_catalog(**kw):
related_object = related_object.getObject()
category_list = []
for category in related_object.getCategoryList():
new_category = self.updateRelatedCategory(category,
previous_category_url,
new_category_url)
category_list.append(new_category)
related_object.edit(categories=category_list,
activate_kw=activate_kw)
# udpate all predicates membership
kw = {'predicate_category.category_uid': context.getUid(), 'limit': None}
for predicate in portal_catalog(**kw):
predicate = predicate.getObject()
membership_list = []
for category in predicate.getMembershipCriterionCategoryList():
new_category = self.updateRelatedCategory(category,
previous_category_url,
new_category_url)
membership_list.append(new_category)
predicate.edit(membership_criterion_category_list=membership_list,
activate_kw=activate_kw)
# update related recursively if required
aq_context = aq_base(context)
if getattr(aq_context, 'listFolderContents', None) is not None:
for o in context.listFolderContents():
new_o_category_url = o.getRelativeUrl()
# Relative Url is based on parent new_category_url so we must
# replace new_category_url with previous_category_url to find
# the new category_url for the subobject
previous_o_category_url = self.updateRelatedCategory(
new_o_category_url,
new_category_url,
previous_category_url)
self.updateRelatedContent(o, previous_o_category_url,
new_o_category_url)
InitializeClass( CategoryTool )