Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
erp5
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Georgios Dagkakis
erp5
Commits
6bf9e694
Commit
6bf9e694
authored
Jan 26, 2013
by
Julien Muchembled
Browse files
Options
Browse Files
Download
Plain Diff
Merge support for ZODB indexing of category related documents
parents
a7780bc6
7865c58d
Changes
15
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
662 additions
and
323 deletions
+662
-323
product/CMFCategory/CategoryTool.py
product/CMFCategory/CategoryTool.py
+248
-176
product/CMFCategory/tests/testCMFCategory.py
product/CMFCategory/tests/testCMFCategory.py
+136
-61
product/ERP5/Document/BusinessTemplate.py
product/ERP5/Document/BusinessTemplate.py
+2
-1
product/ERP5/Tool/CategoryTool.py
product/ERP5/Tool/CategoryTool.py
+5
-48
product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/BaseCategory_validateRelatedLocallyIndexed.xml
.../erp5_core/BaseCategory_validateRelatedLocallyIndexed.xml
+69
-0
product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/BaseCategory_view.xml
...TemplateItem/portal_skins/erp5_core/BaseCategory_view.xml
+1
-0
product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/BaseCategory_view/my_related_locally_indexed.xml
...rp5_core/BaseCategory_view/my_related_locally_indexed.xml
+124
-0
product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Base_zSearchRelatedObjectsByCategoryList.xml
...ns/erp5_core/Base_zSearchRelatedObjectsByCategoryList.xml
+2
-6
product/ERP5/bootstrap/erp5_core/bt/revision
product/ERP5/bootstrap/erp5_core/bt/revision
+1
-1
product/ERP5/bootstrap/erp5_property_sheets/PropertySheetTemplateItem/portal_property_sheets/BaseCategory/related_locally_indexed_property.xml
..._sheets/BaseCategory/related_locally_indexed_property.xml
+58
-0
product/ERP5/bootstrap/erp5_property_sheets/bt/revision
product/ERP5/bootstrap/erp5_property_sheets/bt/revision
+1
-1
product/ERP5/tests/testResource.py
product/ERP5/tests/testResource.py
+5
-6
product/ERP5Type/Accessor/Value.py
product/ERP5Type/Accessor/Value.py
+2
-3
product/ERP5Type/Base.py
product/ERP5Type/Base.py
+2
-8
product/ERP5Type/tests/testERP5Type.py
product/ERP5Type/tests/testERP5Type.py
+6
-12
No files found.
product/CMFCategory/CategoryTool.py
View file @
6bf9e694
...
...
@@ -30,7 +30,8 @@
"""
\
ERP portal_categories tool.
"""
from
collections
import
deque
from
BTrees.OOBTree
import
OOTreeSet
from
OFS.Folder
import
Folder
from
Products.CMFCore.utils
import
UniqueObject
from
Products.ERP5Type.Globals
import
InitializeClass
,
DTMLFile
...
...
@@ -40,9 +41,11 @@ from Acquisition import aq_base, aq_inner
from
Products.ERP5Type
import
Permissions
from
Products.ERP5Type.Base
import
Base
from
Products.ERP5Type.Cache
import
getReadOnlyTransactionCache
from
Products.ERP5Type.TransactionalVariable
import
getTransactionalVariable
from
Products.CMFCategory
import
_dtmldir
from
Products.CMFCore.PortalFolder
import
ContentFilter
from
Products.CMFCategory.Renderer
import
Renderer
from
Products.CMFCategory.Category
import
Category
,
BaseCategory
from
OFS.Traversable
import
NotFound
import
types
...
...
@@ -55,6 +58,34 @@ _marker = object()
class
CategoryError
(
Exception
):
pass
class
RelatedIndex
():
# persistent.Persistent can be added
# without breaking compatibility
def
__repr__
(
self
):
try
:
contents
=
', '
.
join
(
'%s=%r'
%
(
k
,
list
(
v
))
for
(
k
,
v
)
in
self
.
__dict__
.
iteritems
())
except
Exception
:
contents
=
'...'
return
'<%s(%s) at 0x%x>'
%
(
self
.
__class__
.
__name__
,
contents
,
id
(
self
))
def
__nonzero__
(
self
):
return
any
(
self
.
__dict__
.
itervalues
())
def
add
(
self
,
base
,
relative_url
):
try
:
getattr
(
self
,
base
).
add
(
relative_url
)
except
AttributeError
:
setattr
(
self
,
base
,
OOTreeSet
((
relative_url
,)))
def
remove
(
self
,
base
,
relative_url
):
try
:
getattr
(
self
,
base
).
remove
(
relative_url
)
except
(
AttributeError
,
KeyError
):
pass
class
CategoryTool
(
UniqueObject
,
Folder
,
Base
):
"""
The CategoryTool object is the placeholder for all methods
...
...
@@ -308,38 +339,34 @@ class CategoryTool( UniqueObject, Folder, Base ):
such as site/group/a/b/c/b1/c1 where b and b1 are both children
categories of a.
relative_url -- a single relative url of a list of
relative urls
relative_url -- a single relative url or a list of relative urls
strict -- if set to 1, only return uids of parents, not
relative_url
"""
uid_
dict
=
{}
uid_
set
=
set
()
if
isinstance
(
relative_url
,
str
):
relative_url
=
(
relative_url
,)
for
path
in
relative_url
:
try
:
o
=
self
.
getCategoryValue
(
path
,
base_category
=
base_category
)
if
o
is
not
None
:
my_base_category
=
self
.
getBaseCategoryId
(
path
)
bo
=
self
.
get
(
my_base_category
,
None
)
if
bo
is
not
None
:
bo_uid
=
int
(
bo
.
getUid
())
uid_dict
[(
int
(
o
.
uid
),
bo_uid
,
1
)]
=
1
# Strict Membership
if
o
.
meta_type
==
'CMF Category'
or
o
.
meta_type
==
'CMF Base Category'
:
if
base_category
is
None
:
my_base_category
=
self
.
getBaseCategoryId
(
path
)
else
:
my_base_category
=
base_category
bo_uid
=
self
[
my_base_category
].
getUid
()
uid_set
.
add
((
o
.
getUid
(),
bo_uid
,
1
))
# Strict Membership
if
not
strict
:
while
o
.
portal_type
==
'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
==
'CMF Category'
:
o
=
o
.
aq_parent
# We want acquisition here without aq_inner
uid_dict
[(
int
(
o
.
uid
),
bo_uid
,
0
)]
=
1
# Non Strict Membership
o
=
o
.
aq_parent
# We want acquisition here without aq_inner
uid_set
.
add
((
o
.
getUid
(),
bo_uid
,
0
))
# Non Strict Membership
except
(
KeyError
,
AttributeError
):
LOG
(
'WARNING: CategoriesTool'
,
0
,
'Unable to find uid for %s'
%
path
)
return
uid_dict
.
keys
()
security
.
declareProtected
(
Permissions
.
AccessContentsInformation
,
'getUids'
)
getUids
=
getCategoryParentUidList
return
list
(
uid_set
)
# cast to list for <dtml-in>
security
.
declareProtected
(
Permissions
.
AccessContentsInformation
,
'getCategoryChildUidList'
)
def
getCategoryChildUidList
(
self
,
relative_url
,
base_category
=
None
,
strict
=
0
):
...
...
@@ -631,90 +658,58 @@ class CategoryTool( UniqueObject, Folder, Base ):
portal_type
=
(
portal_type
,)
spec
=
portal_type
self
.
_cleanupCategories
(
context
)
if
isinstance
(
category_list
,
str
):
category_list
=
(
category_list
,
)
elif
category_list
is
None
:
category_list
=
()
elif
isinstance
(
category_list
,
(
list
,
tuple
)):
pass
else
:
__traceback_info__
=
(
base_category_list
,
category_list
)
raise
TypeError
(
'Category must be of string, tuple of string '
'or list of string type.'
)
if
isinstance
(
base_category_list
,
str
):
base_category_list
=
(
base_category_list
,
)
# Build the ckecked_permission filter
if
checked_permission
is
not
None
:
checkPermission
=
self
.
portal_membership
.
checkPermission
def
permissionFilter
(
obj
):
if
checkPermission
(
checked_permission
,
obj
):
return
0
else
:
return
1
new_category_list
=
[]
default_
dict
=
{}
spec_len
=
len
(
spec
)
new_category_list
=
deque
()
default_
base_category_set
=
set
()
default_category_set
=
set
(
)
for
path
in
self
.
_getCategoryList
(
context
):
my_base_id
=
self
.
getBaseCategoryId
(
path
)
if
my_base_id
not
in
base_category_list
:
# Keep each membership which is not in the
# specified list of base_category ids
new_category_list
.
append
(
path
)
else
:
keep_it
=
0
if
spec_len
!=
0
or
(
checked_permission
is
not
None
):
if
my_base_id
in
base_category_list
:
if
spec
or
checked_permission
is
not
None
:
obj
=
self
.
unrestrictedTraverse
(
path
,
None
)
if
obj
is
not
None
:
if
spec_len
!=
0
:
# If spec is (), then we should keep nothing
# Everything will be replaced
# If spec is not (), Only keep this if not in our spec
my_type
=
obj
.
portal_type
keep_it
=
(
my_type
not
in
spec
)
if
(
not
keep_it
)
and
(
checked_permission
is
not
None
):
keep_it
=
permissionFilter
(
obj
)
if
keep_it
:
new_category_list
.
append
(
path
)
elif
keep_default
:
# We must remember the default value
# for each replaced category
if
not
default_dict
.
has_key
(
my_base_id
):
default_dict
[
my_base_id
]
=
path
# We now create a list of default category values
default_new_category_list
=
[]
for
path
in
default_dict
.
values
():
if
base
or
len
(
base_category_list
)
>
1
:
if
path
in
category_list
:
default_new_category_list
.
append
(
path
)
# If spec is (), then we should keep nothing
# Everything will be replaced
# If spec is not (), Only keep this if not in our spec
if
(
spec
and
obj
.
portal_type
not
in
spec
)
or
not
(
checked_permission
is
None
or
checkPermission
(
checked_permission
,
obj
)):
new_category_list
.
append
(
path
)
continue
# We must remember the default value for each replaced category
if
keep_default
and
my_base_id
not
in
default_base_category_set
:
default_base_category_set
.
add
(
my_base_id
)
default_category_set
.
add
(
path
)
else
:
if
path
[
len
(
base_category_list
[
0
])
+
1
:]
in
category_list
:
default_new_category_list
.
append
(
path
)
# Keep each membership which is not in the
# specified list of base_category ids
new_category_list
.
append
(
path
)
# Before we append new category values (except default values)
# We must make sure however that multiple links are possible
default_path_found
=
{}
base
=
''
if
base
or
len
(
base_category_list
)
>
1
\
else
base_category_list
[
0
]
+
'/'
for
path
in
category_list
:
if
not
path
in
(
''
,
None
):
if
base
or
len
(
base_category_list
)
>
1
:
# Only keep path which are member of base_category_list
if
self
.
getBaseCategoryId
(
path
)
in
base_category_list
:
if
path
not
in
default_new_category_list
or
default_path_found
.
has_key
(
path
):
default_path_found
[
path
]
=
1
new_category_list
.
append
(
path
)
if
path
not
in
(
''
,
None
):
if
base
:
path
=
base
+
path
elif
self
.
getBaseCategoryId
(
path
)
not
in
base_category_list
:
continue
if
path
in
default_category_set
:
default_category_set
.
remove
(
path
)
new_category_list
.
appendleft
(
path
)
else
:
new_path
=
'%s/%s'
%
(
base_category_list
[
0
],
path
)
if
new_path
not
in
default_new_category_list
:
new_category_list
.
append
(
new_path
)
# LOG("CategoryTool, setCategoryMembership", 0 ,
# 'new_category_list: %s' % str(new_category_list))
# LOG("CategoryTool, setCategoryMembership", 0 ,
# 'default_new_category_list: %s' % str(default_new_category_list))
self
.
_setCategoryList
(
context
,
tuple
(
default_new_category_list
+
new_category_list
))
new_category_list
.
append
(
path
)
self
.
_setCategoryList
(
context
,
new_category_list
)
security
.
declareProtected
(
Permissions
.
AccessContentsInformation
,
'setDefaultCategoryMembership'
)
...
...
@@ -739,7 +734,6 @@ class CategoryTool( UniqueObject, Folder, Base ):
to filter the object on
"""
self
.
_cleanupCategories
(
context
)
if
isinstance
(
default_category
,
(
tuple
,
list
)):
default_category
=
default_category
[
0
]
category_list
=
self
.
getCategoryMembershipList
(
context
,
base_category
,
...
...
@@ -1182,35 +1176,28 @@ class CategoryTool( UniqueObject, Folder, Base ):
"""
if
getattr
(
aq_base
(
context
),
'isCategory'
,
0
):
return
context
.
isAcquiredMemberOf
(
category
)
for
c
in
self
.
_
getAcquiredCategoryList
(
context
):
for
c
in
self
.
getAcquiredCategoryList
(
context
):
if
c
.
find
(
category
)
>=
0
:
return
1
return
0
security
.
declareProtected
(
Permissions
.
AccessContentsInformation
,
'getCategoryList'
)
def
getCategoryList
(
self
,
context
):
self
.
_cleanupCategories
(
context
)
return
self
.
_getCategoryList
(
context
)
security
.
declareProtected
(
Permissions
.
AccessContentsInformation
,
'_getCategoryList'
)
def
_getCategoryList
(
self
,
context
):
if
getattr
(
aq_base
(
context
),
'categories'
,
_marker
)
is
not
_marker
:
if
isinstance
(
context
.
categories
,
tuple
):
result
=
list
(
context
.
categories
)
elif
isinstance
(
context
.
categories
,
list
):
result
=
context
.
categories
else
:
result
=
[]
result
=
getattr
(
aq_base
(
context
),
'categories'
,
None
)
if
result
is
not
None
:
result
=
list
(
result
)
elif
isinstance
(
context
,
dict
):
re
sult
=
list
(
context
.
get
(
'categories'
,
[]
))
re
turn
list
(
context
.
get
(
'categories'
,
()
))
else
:
result
=
[]
if
getattr
(
context
,
'isCategory'
,
0
):
category_url
=
context
.
getRelativeUrl
()
if
category_url
not
in
result
:
result
.
append
(
c
ontext
.
getRelativeUrl
()
)
# Pure category is member of itself
result
.
append
(
c
ategory_url
)
# Pure category is member of itself
return
result
_getCategoryList
=
getCategoryList
security
.
declareProtected
(
Permissions
.
ModifyPortalContent
,
'setCategoryList'
)
def
setCategoryList
(
self
,
context
,
value
):
self
.
_setCategoryList
(
context
,
value
)
...
...
@@ -1218,45 +1205,39 @@ class CategoryTool( UniqueObject, Folder, Base ):
security
.
declareProtected
(
Permissions
.
ModifyPortalContent
,
'_setCategoryList'
)
def
_setCategoryList
(
self
,
context
,
value
):
context
.
categories
=
tuple
(
value
)
old
=
set
(
getattr
(
aq_base
(
context
),
'categories'
,
()))
context
.
categories
=
value
=
tuple
(
value
)
if
context
.
isTempDocument
():
return
value
=
set
(
value
)
relative_url
=
context
.
getRelativeUrl
()
for
edit
,
value
in
(
"remove"
,
old
-
value
),
(
"add"
,
value
-
old
):
for
path
in
value
:
base
=
self
.
getBaseCategoryId
(
path
)
try
:
if
self
[
base
].
isRelatedLocallyIndexed
():
path
=
self
.
_removeDuplicateBaseCategoryIdInCategoryPath
(
base
,
path
)
ob
=
aq_base
(
self
.
unrestrictedTraverse
(
path
))
try
:
related
=
ob
.
_related_index
except
AttributeError
:
if
edit
is
"remove"
:
continue
related
=
ob
.
_related_index
=
RelatedIndex
()
getattr
(
related
,
edit
)(
base
,
relative_url
)
except
KeyError
:
pass
security
.
declareProtected
(
Permissions
.
AccessContentsInformation
,
'getAcquiredCategoryList'
)
def
getAcquiredCategoryList
(
self
,
context
):
"""
Returns the list of acquired categories
"""
self
.
_cleanupCategories
(
context
)
return
self
.
_getAcquiredCategoryList
(
context
)
security
.
declareProtected
(
Permissions
.
AccessContentsInformation
,
'_getAcquiredCategoryList'
)
def
_getAcquiredCategoryList
(
self
,
context
):
result
=
self
.
getAcquiredCategoryMembershipList
(
context
,
base_category
=
self
.
getBaseCategoryList
(
context
=
context
))
append
=
result
.
append
non_acquired
=
self
.
_getCategoryList
(
context
)
for
c
in
non_acquired
:
for
c
in
self
.
_getCategoryList
(
context
):
# Make sure all local categories are considered
if
c
not
in
result
:
append
(
c
)
if
getattr
(
context
,
'isCategory'
,
0
):
append
(
context
.
getRelativeUrl
())
# Pure category is member of itself
result
.
append
(
c
)
return
result
security
.
declareProtected
(
Permissions
.
ModifyPortalContent
,
'_cleanupCategories'
)
def
_cleanupCategories
(
self
,
context
):
# Make sure _cleanupCategories does not modify objects each time it is called
# or we get many conflicts
requires_update
=
0
categories
=
[]
append
=
categories
.
append
if
getattr
(
context
,
'categories'
,
_marker
)
is
not
_marker
:
for
cat
in
self
.
_getCategoryList
(
context
):
if
isinstance
(
cat
,
str
):
append
(
cat
)
else
:
requires_update
=
1
if
requires_update
:
self
.
setCategoryList
(
context
,
tuple
(
categories
))
# Catalog related methods
def
updateRelatedCategory
(
self
,
category
,
previous_category_url
,
new_category_url
):
new_category
=
re
.
sub
(
'^%s$'
%
...
...
@@ -1349,7 +1330,6 @@ class CategoryTool( UniqueObject, Folder, Base ):
security
.
declareProtected
(
Permissions
.
AccessContentsInformation
,
'getRelatedValueList'
)
def
getRelatedValueList
(
self
,
context
,
base_category_list
=
None
,
spec
=
(),
filter
=
None
,
base
=
1
,
checked_permission
=
None
,
**
kw
):
"""
This methods returns the list of objects related to the context
...
...
@@ -1359,65 +1339,158 @@ class CategoryTool( UniqueObject, Folder, Base ):
portal_type
=
kw
.
get
(
'portal_type'
)
if
isinstance
(
portal_type
,
str
):
portal_type
=
[
portal_type
]
if
spec
is
():
# We do not want to care about spec
spec
=
None
portal_type
=
portal_type
,
# Base Category may not be related, besides sub categories
if
context
.
getPortalType
()
==
'Base Category'
:
category_list
=
[
context
.
getRelativeUrl
()]
relative_url
=
context
.
getRelativeUrl
()
local_index_dict
=
{}
if
isinstance
(
context
,
BaseCategory
):
category_list
=
relative_url
,
else
:
category_list
=
[]
if
isinstance
(
base_category_list
,
str
):
base_category_list
=
[
base_category_list
]
base_category_list
=
base_category_list
,
elif
base_category_list
is
()
or
base_category_list
is
None
:
base_category_list
=
self
.
getBaseCategoryList
()
category_list
=
[]
for
base_category
in
base_category_list
:
category_list
.
append
(
"%s/%s"
%
(
base_category
,
context
.
getRelativeUrl
()))
sql_kw
=
{}
for
sql_key
in
(
'limit'
,
'order_by_expression'
):
# XXX-JPS it would be better to use Catalog API
if
sql_key
in
kw
:
sql_kw
[
sql_key
]
=
kw
[
sql_key
]
brain_result
=
self
.
Base_zSearchRelatedObjectsByCategoryList
(
category_list
=
category_list
,
portal_type
=
portal_type
,
strict_membership
=
strict_membership
,
**
sql_kw
)
if
self
[
base_category
].
isRelatedLocallyIndexed
():
category
=
base_category
+
'/'
local_index_dict
[
base_category
]
=
''
\
if
relative_url
.
startswith
(
category
)
else
category
else
:
category_list
.
append
(
"%s/%s"
%
(
base_category
,
relative_url
))
search
=
self
.
getPortalObject
().
Base_zSearchRelatedObjectsByCategoryList
if
local_index_dict
:
# For some base categories, lookup indexes in ZODB.
recurse
=
isinstance
(
context
,
Category
)
and
not
strict_membership
result_dict
=
{}
def
check_local
():
r
=
set
(
getattr
(
related
,
base_category
,
()))
r
.
difference_update
(
result_dict
)
for
r
in
r
:
try
:
ob
=
self
.
unrestrictedTraverse
(
r
)
if
category
in
aq_base
(
ob
).
categories
:
result_dict
[
r
]
=
ob
continue
# Do not add 'r' to result_dict, because 'ob' may be linked in
# another way.
except
(
AttributeError
,
KeyError
):
result_dict
[
r
]
=
None
related
.
remove
(
base_category
,
r
)
tv
=
getTransactionalVariable
().
setdefault
(
'CategoriesTool.getRelatedValueList'
,
{})
try
:
related
=
aq_base
(
context
).
_related_index
except
AttributeError
:
related
=
RelatedIndex
()
include_self
=
False
for
base_category
,
category
in
local_index_dict
.
iteritems
():
if
not
category
:
# Categories are member of themselves.
include_self
=
True
result_dict
[
relative_url
]
=
context
category
+=
relative_url
if
tv
.
get
(
category
,
-
1
)
<
recurse
:
# Update local index with results from catalog for backward
# compatibility. But no need to do it several times in the same
# transaction.
for
r
in
search
(
category_list
=
category
,
portal_type
=
None
,
strict_membership
=
strict_membership
):
r
=
r
.
relative_url
# relative_url is empty if object is deleted (but not yet
# unindexed). Nothing specific to do in such case because
# category tool won't match.
try
:
ob
=
self
.
unrestrictedTraverse
(
r
)
categories
=
aq_base
(
ob
).
categories
except
(
AttributeError
,
KeyError
):
result_dict
[
r
]
=
None
continue
if
category
in
categories
:
related
.
add
(
base_category
,
r
)
result_dict
[
r
]
=
ob
elif
recurse
:
for
p
in
categories
:
if
p
.
startswith
(
category
+
'/'
):
try
:
o
=
self
.
unrestrictedTraverse
(
p
)
p
=
aq_base
(
o
).
_related_index
except
KeyError
:
continue
except
AttributeError
:
p
=
o
.
_related_index
=
RelatedIndex
()
result_dict
[
r
]
=
ob
p
.
add
(
base_category
,
r
)
tv
[
category
]
=
recurse
# Get and check all objects referenced by local index for the base
# category that is currently considered.
check_local
()
# Modify context only if it's worth it.
if
related
and
not
hasattr
(
aq_base
(
context
),
'_related_index'
):
context
.
_related_index
=
related
# In case of non-strict membership search, include all objects that
# are linked to a subobject of context.
if
recurse
:
r
=
[
context
]
while
r
:
for
ob
in
r
.
pop
().
objectValues
():
r
.
append
(
ob
)
relative_url
=
ob
.
getRelativeUrl
()
if
include_self
:
result_dict
[
relative_url
]
=
ob
try
:
related
=
aq_base
(
ob
).
_related_index
except
AttributeError
:
continue
for
base_category
,
category
in
local_index_dict
.
iteritems
():
category
+=
relative_url
check_local
()
# Filter out objects that are not of requested portal type.
result
=
[
ob
for
ob
in
result_dict
.
itervalues
()
if
ob
is
not
None
and
(
not
portal_type
or
ob
.
getPortalType
()
in
portal_type
)]
# Finish with base categories that are only indexed in catalog,
# making sure we don't return duplicate values.
if
category_list
:
for
r
in
search
(
category_list
=
category_list
,
portal_type
=
portal_type
,
strict_membership
=
strict_membership
):
if
r
.
relative_url
not
in
result_dict
:
try
:
result
.
append
(
self
.
unrestrictedTraverse
(
r
.
path
))
except
KeyError
:
pass
result
=
[]
if
checked_permission
is
None
:
# No permission to check
for
b
in
brain_result
:
o
=
b
.
getObject
()
if
o
is
not
None
:
result
.
append
(
o
)
else
:
# Check permissions on object
if
isinstance
(
checked_permission
,
str
):
checked_permission
=
(
checked_permission
,
)
checkPermission
=
self
.
portal_membership
.
checkPermission
for
b
in
brain_result
:
obj
=
b
.
getObject
()
if
obj
is
not
None
:
for
permission
in
checked_permission
:
if
not
checkPermission
(
permission
,
obj
):
break
result
.
append
(
obj
)
# Catalog-only search.
result
=
[]
for
r
in
search
(
category_list
=
category_list
,
portal_type
=
portal_type
,
strict_membership
=
strict_membership
):
try
:
result
.
append
(
self
.
unrestrictedTraverse
(
r
.
path
))
except
KeyError
:
pass
return
result
# XXX missing filter and **kw stuff
#return self.search_category(category_list=category_list,
# portal_type=spec)
# future implementation with brains, much more efficient
if
checked_permission
is
None
:
return
result
# Check permissions on object
if
isinstance
(
checked_permission
,
str
):
checked_permission
=
checked_permission
,
checkPermission
=
self
.
portal_membership
.
checkPermission
def
check
(
ob
):
for
permission
in
checked_permission
:
if
checkPermission
(
permission
,
ob
):
return
True
return
filter
(
check
,
result
)
security
.
declareProtected
(
Permissions
.
AccessContentsInformation
,
'getRelatedPropertyList'
)
def
getRelatedPropertyList
(
self
,
context
,
base_category_list
=
None
,
property_name
=
None
,
spec
=
(),
filter
=
None
,
base
=
1
,
property_name
=
None
,
checked_permission
=
None
,
**
kw
):
"""
This methods returns the list of property_name on objects
...
...
@@ -1426,8 +1499,7 @@ class CategoryTool( UniqueObject, Folder, Base ):
result
=
[]
for
o
in
self
.
getRelatedValueList
(
context
=
context
,
base_category_list
=
base_category_list
,
spec
=
spec
,
filter
=
filter
,
base
=
base
,
base_category_list
=
base_category_list
,
checked_permission
=
checked_permission
,
**
kw
):
result
.
append
(
o
.
getProperty
(
property_name
,
None
))
return
result
...
...
product/CMFCategory/tests/testCMFCategory.py
View file @
6bf9e694
...
...
@@ -26,6 +26,7 @@
#
##############################################################################
from
collections
import
deque
import
unittest
from
Products.ERP5Type.tests.ERP5TypeTestCase
import
ERP5TypeTestCase
...
...
@@ -42,6 +43,30 @@ class TestCMFCategory(ERP5TypeTestCase):
region2
=
'europe/west/germany'
region_list
=
[
region1
,
region2
]
category_dict
=
dict
(
region
=
dict
(
acquisition_base_category_list
=
(
'subordination'
,
'parent'
),
acquisition_portal_type_list
=
"python: ['Address', 'Organisation', 'Person']"
,
acquisition_mask_value
=
1
,
acquisition_object_id_list
=
[
'default_address'
],
contents
=
(
'europe'
,
(
'west'
,
(
'france'
,
'germany'
))),
),
subordination
=
dict
(
acquisition_portal_type_list
=
"python: ['Career', 'Organisation']"
,
acquisition_object_id_list
=
[
'default_career'
],
),
gender
=
dict
(
fallback_base_category_list
=
[
'subordination'
],
),
resource
=
dict
(
),
test0
=
dict
(
),
test1
=
dict
(
contents
=
(
'a'
,
(
'ab'
,
'ac'
,
(
'acd'
,))),
),
)
def
getTitle
(
self
):
return
"CMFCategory"
...
...
@@ -74,16 +99,44 @@ class TestCMFCategory(ERP5TypeTestCase):
portal
=
self
.
portal
self
.
validateRules
()
portal_categories
=
self
.
getCategoriesTool
()
for
name
,
kw
in
self
.
category_dict
.
iteritems
():
try
:
bc
=
portal_categories
[
name
]
except
KeyError
:
bc
=
portal_categories
.
newContent
(
name
)
edit_kw
=
dict
(
acquisition_copy_value
=
0
,
acquisition_append_value
=
0
,
acquisition_mask_value
=
0
,
acquisition_portal_type_list
=
"python: []"
,
related_locally_indexed
=
0
)
edit_kw
.
update
(
kw
)
queue
=
deque
(((
bc
,
edit_kw
.
pop
(
'contents'
,
())),))
bc
.
edit
(
**
edit_kw
)
while
queue
:
parent
,
contents
=
queue
.
popleft
()
for
x
in
contents
:
if
type
(
x
)
is
str
:
try
:
category
=
parent
[
x
]
except
KeyError
:
category
=
parent
.
newContent
(
x
)
else
:
queue
.
append
((
category
,
x
))
# This test creates Person inside Person and Organisation inside
# Organisation, so we modifiy type informations to allow anything inside
# Person and Organisation (we'll cleanup on teardown)
self
.
getTypesTool
().
getTypeInfo
(
'Person'
).
filter_content_types
=
0
organisation_ti
=
self
.
getTypesTool
().
getTypeInfo
(
'Organisation'
)
organisation_ti
.
filter_content_types
=
0
# we also enable 'destination' category on organisations
self
.
_organisation_categories
=
organisation_ti
.
getTypeBaseCategoryList
()
organisation_ti
.
_setTypeBaseCategoryList
(
self
.
_organisation_categories
+
[
'destination'
,
'resource'
])
# Organisation, so we modify type informations to allow anything inside
# Person and Organisation (we'll cleanup on teardown).
self
.
_original_categories
=
{}
for
portal_type
,
categories
in
(
(
'Person'
,
[]),
(
'Organisation'
,
[
'destination'
,
'resource'
])):
ti
=
self
.
getTypesTool
().
getTypeInfo
(
portal_type
)
ti
.
filter_content_types
=
0
self
.
_original_categories
[
portal_type
]
=
x
=
ti
.
getTypeBaseCategoryList
()
x
+=
'test0'
,
'test1'
ti
.
_setTypeBaseCategoryList
(
x
+
categories
)
# Make persons.
person_module
=
self
.
getPersonModule
()
...
...
@@ -109,62 +162,14 @@ class TestCMFCategory(ERP5TypeTestCase):
sale_packing_list_module
=
portal
.
sale_packing_list_module
if
self
.
id1
not
in
sale_packing_list_module
.
objectIds
():
sale_packing_list_module
.
newContent
(
id
=
self
.
id1
)
# This set the acquisition for region
for
bc
in
(
'region'
,
):
if
not
hasattr
(
portal_categories
,
bc
):
portal_categories
.
newContent
(
portal_type
=
'Base Category'
,
id
=
bc
)
portal_categories
[
bc
].
setAcquisitionBaseCategoryList
((
'subordination'
,
'parent'
))
portal_categories
[
bc
].
setAcquisitionPortalTypeList
(
"python: ['Address', 'Organisation', 'Person']"
)
portal_categories
[
bc
].
setAcquisitionMaskValue
(
1
)
portal_categories
[
bc
].
setAcquisitionCopyValue
(
0
)
portal_categories
[
bc
].
setAcquisitionAppendValue
(
0
)
portal_categories
[
bc
].
setAcquisitionObjectIdList
([
'default_address'
])
if
not
'europe'
in
portal_categories
[
bc
].
objectIds
():
portal_categories
[
bc
].
newContent
(
id
=
'europe'
,
portal_type
=
'Category'
)
big_region
=
portal_categories
[
bc
][
'europe'
]
# Now we have to include by hand no categories
if
not
'west'
in
big_region
.
objectIds
():
big_region
.
newContent
(
id
=
'west'
,
portal_type
=
'Category'
)
region
=
big_region
[
'west'
]
if
not
'france'
in
region
.
objectIds
():
region
.
newContent
(
id
=
'france'
,
portal_type
=
'Category'
)
if
not
'germany'
in
region
.
objectIds
():
region
.
newContent
(
id
=
'germany'
,
portal_type
=
'Category'
)
for
bc
in
(
'subordination'
,
):
if
not
hasattr
(
portal_categories
,
bc
):
portal_categories
.
newContent
(
portal_type
=
'Base Category'
,
id
=
bc
)
portal_categories
[
bc
].
setAcquisitionPortalTypeList
(
"python: ['Career', 'Organisation']"
)
portal_categories
[
bc
].
setAcquisitionMaskValue
(
0
)
portal_categories
[
bc
].
setAcquisitionCopyValue
(
0
)
portal_categories
[
bc
].
setAcquisitionAppendValue
(
0
)
portal_categories
[
bc
].
setAcquisitionObjectIdList
([
'default_career'
])
for
bc
in
(
'gender'
,
):
if
not
hasattr
(
portal_categories
,
bc
):
portal_categories
.
newContent
(
portal_type
=
'Base Category'
,
id
=
bc
)
portal_categories
[
bc
].
setAcquisitionPortalTypeList
(
"python: []"
)
portal_categories
[
bc
].
setAcquisitionMaskValue
(
0
)
portal_categories
[
bc
].
setAcquisitionCopyValue
(
0
)
portal_categories
[
bc
].
setAcquisitionAppendValue
(
0
)
portal_categories
[
bc
].
setFallbackBaseCategoryList
([
'subordination'
])
for
bc
in
(
'resource'
,
):
if
not
hasattr
(
portal_categories
,
bc
):
portal_categories
.
newContent
(
portal_type
=
'Base Category'
,
id
=
bc
)
portal_categories
[
bc
].
setAcquisitionPortalTypeList
(
"python: []"
)
portal_categories
[
bc
].
setAcquisitionMaskValue
(
0
)
portal_categories
[
bc
].
setAcquisitionCopyValue
(
0
)
portal_categories
[
bc
].
setAcquisitionAppendValue
(
0
)
def
beforeTearDown
(
self
):
"""Clean up."""
# categories
for
bc
in
(
'region'
,
'subordination'
,
'gender'
,
'resource'
):
bc_obj
=
self
.
getPortal
().
portal_categories
[
bc
]
bc_obj
.
manage_delObjects
()
# type informations
self
.
getTypesTool
().
getTypeInfo
(
'Person'
).
filter_content_types
=
1
organisation_ti
=
self
.
getTypesTool
().
getTypeInfo
(
'Organisation'
)
organisation_
ti
.
filter_content_types
=
1
organisation_ti
=
self
.
_organisation_categories
for
portal_type
,
categories
in
self
.
_original_categories
.
iteritems
():
ti
=
self
.
getTypesTool
().
getTypeInfo
(
portal_type
)
ti
.
filter_content_types
=
1
ti
.
_setTypeBaseCategoryList
(
categories
)
def
login
(
self
):
uf
=
self
.
portal
.
acl_users
...
...
@@ -1075,6 +1080,76 @@ class TestCMFCategory(ERP5TypeTestCase):
# Check indexation
self
.
tic
()
def
test_setCategoryMemberShip
(
self
):
person
=
self
.
getPersonModule
().
newContent
(
portal_type
=
'Person'
)
category_tool
=
self
.
getCategoriesTool
()
bc
=
category_tool
.
newContent
()
bc
.
newContent
(
'a'
)
bc
.
newContent
(
'b'
)
base
=
(
bc
.
id
+
'/'
).
__add__
def
get
(
*
args
,
**
kw
):
return
category_tool
.
getCategoryMembershipList
(
person
,
*
args
,
**
kw
)
def
_set
(
*
args
,
**
kw
):
return
category_tool
.
_setCategoryMembership
(
person
,
*
args
,
**
kw
)
_set
(
bc
.
id
,
list
(
'aa'
))
self
.
assertEqual
(
get
(
bc
.
id
),
list
(
'aa'
))
_set
(
bc
.
id
,
list
(
'baa'
))
self
.
assertEqual
(
get
(
bc
.
id
),
list
(
'aba'
))
_set
(
bc
.
id
,
map
(
base
,
'bb'
),
1
)
self
.
assertEqual
(
get
(
bc
.
id
),
list
(
'bb'
))
_set
(
bc
.
id
,
map
(
base
,
'abb'
),
1
)
self
.
assertEqual
(
get
(
bc
.
id
),
list
(
'bab'
))
_set
(
bc
.
id
,
())
def
test_relatedIndex
(
self
):
category_tool
=
self
.
getCategoriesTool
()
newOrganisation
=
self
.
getOrganisationModule
().
newContent
organisation
=
newOrganisation
()
other_organisation
=
newOrganisation
(
destination_value
=
organisation
)
person
=
self
.
getPersonModule
().
newContent
(
test0_value
=
organisation
,
test1
=
'a/ac/acd'
)
self
.
tic
()
get
=
organisation
.
getTest0RelatedValueList
a
=
category_tool
.
test1
.
a
def
check
():
self
.
assertEqual
([
person
,
other_organisation
],
category_tool
.
getRelatedValueList
(
organisation
))
self
.
assertEqual
([
person
],
get
())
self
.
assertEqual
([
person
],
get
(
portal_type
=
'Person'
))
self
.
assertEqual
([],
get
(
portal_type
=
'Organisation'
))
self
.
assertEqual
([
person
],
a
.
getTest1RelatedValueList
(
portal_type
=
'Person'
))
self
.
assertEqual
([
a
],
a
.
getTest1RelatedValueList
(
strict_membership
=
True
))
self
.
assertEqual
([
person
],
a
.
ac
.
acd
.
getTest1RelatedValueList
(
portal_type
=
'Person'
,
strict_membership
=
True
))
category_tool
.
test0
.
_setRelatedLocallyIndexed
(
True
)
category_tool
.
test1
.
_setRelatedLocallyIndexed
(
True
)
check
()
related_list
=
sorted
(
a
.
getTest1RelatedList
())
self
.
assertTrue
(
person
.
getRelativeUrl
()
in
related_list
)
self
.
assertEqual
(
related_list
,
sorted
(
x
.
getRelativeUrl
()
for
x
in
self
.
portal
.
portal_catalog
(
test1_uid
=
a
.
getUid
())))
related
=
organisation
.
_related_index
self
.
assertTrue
(
related
)
self
.
assertEqual
([
person
.
getRelativeUrl
()],
list
(
related
.
test0
))
person
.
unindexObject
()
self
.
tic
()
category_tool
.
test0
.
_setRelatedLocallyIndexed
(
False
)
self
.
assertEqual
([],
get
())
category_tool
.
test0
.
_setRelatedLocallyIndexed
(
True
)
check
()
person
.
categories
=
tuple
(
x
for
x
in
person
.
categories
if
not
x
.
startswith
(
'test0/'
))
self
.
assertEqual
([],
get
())
self
.
assertFalse
(
related
)
self
.
assertEqual
([],
list
(
related
.
test0
))
related
=
a
.
ac
.
acd
.
_related_index
.
test1
self
.
assertEqual
(
list
(
related
),
[
person
.
getRelativeUrl
()])
person
.
_setTest1Value
(
a
)
self
.
assertEqual
(
list
(
related
),
[])
def
test_suite
():
suite
=
unittest
.
TestSuite
()
suite
.
addTest
(
unittest
.
makeSuite
(
TestCMFCategory
))
...
...
product/ERP5/Document/BusinessTemplate.py
View file @
6bf9e694
...
...
@@ -544,7 +544,8 @@ class BaseTemplateItem(Implicit, Persistent):
klass
=
obj
.
__class__
classname
=
klass
.
__name__
attr_set
=
set
((
'_dav_writelocks'
,
'_filepath'
,
'_owner'
,
'last_id'
,
'uid'
,
attr_set
=
set
((
'_dav_writelocks'
,
'_filepath'
,
'_owner'
,
'_related_index'
,
'last_id'
,
'uid'
,
'__ac_local_roles__'
,
'__ac_local_roles_group_id_dict__'
))
if
export
:
if
not
keep_workflow_history
:
...
...
product/ERP5/Tool/CategoryTool.py
View file @
6bf9e694
...
...
@@ -40,6 +40,7 @@ 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
...
...
@@ -84,54 +85,10 @@ class CategoryTool(CopyContainer, CMFCategoryTool, BaseTool):
def
hasContent
(
self
,
id
):
return
id
in
self
.
objectIds
()
security
.
declareProtected
(
Permissions
.
AccessContentsInformation
,
'getCategoryParentUidList'
)
def
getCategoryParentUidList
(
self
,
relative_url
,
base_category
=
None
,
strict
=
0
):
"""
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.
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
:
my_base_category
=
self
.
getBaseCategoryId
(
path
)
else
:
my_base_category
=
base_category
bo
=
getattr
(
self
,
my_base_category
,
None
)
if
bo
is
not
None
:
bo_uid
=
bo
.
getUid
()
uid_dict
[(
o
.
getUid
(),
bo_uid
,
1
)]
=
1
# Strict membership
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'
:
o
=
o
.
aq_parent
# We want acquisition here without aq_inner
uid_dict
[(
o
.
getUid
(),
bo_uid
,
0
)]
=
1
# Non strict
except
(
TypeError
,
KeyError
):
LOG
(
'WARNING: CategoriesTool'
,
0
,
'Unable to find uid for %s'
%
path
)
return
uid_dict
.
keys
()
security
.
declareProtected
(
Permissions
.
AccessContentsInformation
,
'getUids'
)
getUids
=
getCategoryParentUidList
@
caching_instance_method
(
id
=
'portal_categories.getBaseCategoryDict'
,
cache_factory
=
'erp5_content_long'
,
cache_id_generator
=
lambda
m
,
*
a
,
**
k
:
m
)
@
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.
...
...
product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/BaseCategory_validateRelatedLocallyIndexed.xml
0 → 100644
View file @
6bf9e694
<?xml version="1.0"?>
<ZopeData>
<record
id=
"1"
aka=
"AAAAAAAAAAE="
>
<pickle>
<global
name=
"PythonScript"
module=
"Products.PythonScripts.PythonScript"
/>
</pickle>
<pickle>
<dictionary>
<item>
<key>
<string>
Script_magic
</string>
</key>
<value>
<int>
3
</int>
</value>
</item>
<item>
<key>
<string>
_bind_names
</string>
</key>
<value>
<object>
<klass>
<global
name=
"NameAssignments"
module=
"Shared.DC.Scripts.Bindings"
/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key>
<string>
_asgns
</string>
</key>
<value>
<dictionary>
<item>
<key>
<string>
name_container
</string>
</key>
<value>
<string>
container
</string>
</value>
</item>
<item>
<key>
<string>
name_context
</string>
</key>
<value>
<string>
context
</string>
</value>
</item>
<item>
<key>
<string>
name_m_self
</string>
</key>
<value>
<string>
script
</string>
</value>
</item>
<item>
<key>
<string>
name_subpath
</string>
</key>
<value>
<string>
traverse_subpath
</string>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key>
<string>
_body
</string>
</key>
<value>
<string>
return not (value and (\n
request.other[\'field_my_acquisition_object_id_list\'] or\n
request.other[\'field_my_acquisition_base_category_list\']))\n
</string>
</value>
</item>
<item>
<key>
<string>
_params
</string>
</key>
<value>
<string>
value, request
</string>
</value>
</item>
<item>
<key>
<string>
id
</string>
</key>
<value>
<string>
BaseCategory_validateRelatedLocallyIndexed
</string>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/BaseCategory_view.xml
View file @
6bf9e694
...
...
@@ -105,6 +105,7 @@
<key>
<string>
right
</string>
</key>
<value>
<list>
<string>
my_related_locally_indexed
</string>
<string>
my_acquisition_copy_value
</string>
<string>
my_acquisition_mask_value
</string>
<string>
my_acquisition_append_value
</string>
...
...
product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/BaseCategory_view/my_related_locally_indexed.xml
0 → 100644
View file @
6bf9e694
<?xml version="1.0"?>
<ZopeData>
<record
id=
"1"
aka=
"AAAAAAAAAAE="
>
<pickle>
<global
name=
"ProxyField"
module=
"Products.ERP5Form.ProxyField"
/>
</pickle>
<pickle>
<dictionary>
<item>
<key>
<string>
delegated_list
</string>
</key>
<value>
<list>
<string>
external_validator
</string>
<string>
title
</string>
</list>
</value>
</item>
<item>
<key>
<string>
delegated_message_list
</string>
</key>
<value>
<list>
<string>
external_validator_failed
</string>
</list>
</value>
</item>
<item>
<key>
<string>
id
</string>
</key>
<value>
<string>
my_related_locally_indexed
</string>
</value>
</item>
<item>
<key>
<string>
message_values
</string>
</key>
<value>
<dictionary>
<item>
<key>
<string>
external_validator_failed
</string>
</key>
<value>
<string>
Local index is incompatible with category acquision.
</string>
</value>
</item>
</dictionary>
</value>
</item>
<item>
<key>
<string>
overrides
</string>
</key>
<value>
<dictionary>
<item>
<key>
<string>
field_id
</string>
</key>
<value>
<string></string>
</value>
</item>
<item>
<key>
<string>
form_id
</string>
</key>
<value>
<string></string>
</value>
</item>
<item>
<key>
<string>
target
</string>
</key>
<value>
<string></string>
</value>
</item>
</dictionary>
</value>
</item>
<item>
<key>
<string>
tales
</string>
</key>
<value>
<dictionary>
<item>
<key>
<string>
field_id
</string>
</key>
<value>
<string></string>
</value>
</item>
<item>
<key>
<string>
form_id
</string>
</key>
<value>
<string></string>
</value>
</item>
<item>
<key>
<string>
target
</string>
</key>
<value>
<string></string>
</value>
</item>
</dictionary>
</value>
</item>
<item>
<key>
<string>
values
</string>
</key>
<value>
<dictionary>
<item>
<key>
<string>
external_validator
</string>
</key>
<value>
<persistent>
<string
encoding=
"base64"
>
AAAAAAAAAAI=
</string>
</persistent>
</value>
</item>
<item>
<key>
<string>
field_id
</string>
</key>
<value>
<string>
my_checkbox
</string>
</value>
</item>
<item>
<key>
<string>
form_id
</string>
</key>
<value>
<string>
Base_viewFieldLibrary
</string>
</value>
</item>
<item>
<key>
<string>
target
</string>
</key>
<value>
<string>
Click to edit the target
</string>
</value>
</item>
<item>
<key>
<string>
title
</string>
</key>
<value>
<string>
Index Related Documents Locally
</string>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record
id=
"2"
aka=
"AAAAAAAAAAI="
>
<pickle>
<global
name=
"Method"
module=
"Products.Formulator.MethodField"
/>
</pickle>
<pickle>
<dictionary>
<item>
<key>
<string>
method_name
</string>
</key>
<value>
<string>
BaseCategory_validateRelatedLocallyIndexed
</string>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Base_zSearchRelatedObjectsByCategoryList.xml
View file @
6bf9e694
...
...
@@ -58,15 +58,11 @@ order_by_expression</string> </value>
<key>
<string>
src
</string>
</key>
<value>
<string
encoding=
"cdata"
>
<![CDATA[
SELECT DISTINCT catalog.uid,
catalog.path
, portal_type\n
SELECT DISTINCT catalog.uid,
path, relative_url
, portal_type\n
FROM catalog, category\n
WHERE catalog.uid = category.uid\n
<dtml-if portal_type>
\n
AND\n
(
<dtml-in
portal_type
>
\n
<dtml-unless
sequence-start
>
OR
</dtml-unless>
\n
catalog.portal_type=\'
<dtml-var
sequence-item
>
\'\n
</dtml-in>
)\n
AND
<dtml-sqltest
portal_type
type=
"string"
multiple
>
\n
</dtml-if>
\n
AND (
<dtml-var
"portal_categories.buildSQLSelector(category_list)"
>
)\n
<dtml-if
strict_membership
>
\n
...
...
product/ERP5/bootstrap/erp5_core/bt/revision
View file @
6bf9e694
41060
\ No newline at end of file
41061
\ No newline at end of file
product/ERP5/bootstrap/erp5_property_sheets/PropertySheetTemplateItem/portal_property_sheets/BaseCategory/related_locally_indexed_property.xml
0 → 100644
View file @
6bf9e694
<?xml version="1.0"?>
<ZopeData>
<record
id=
"1"
aka=
"AAAAAAAAAAE="
>
<pickle>
<global
name=
"Standard Property"
module=
"erp5.portal_type"
/>
</pickle>
<pickle>
<dictionary>
<item>
<key>
<string>
_local_properties
</string>
</key>
<value>
<tuple>
<dictionary>
<item>
<key>
<string>
id
</string>
</key>
<value>
<string>
mode
</string>
</value>
</item>
<item>
<key>
<string>
type
</string>
</key>
<value>
<string>
string
</string>
</value>
</item>
</dictionary>
</tuple>
</value>
</item>
<item>
<key>
<string>
categories
</string>
</key>
<value>
<tuple>
<string>
elementary_type/boolean
</string>
</tuple>
</value>
</item>
<item>
<key>
<string>
description
</string>
</key>
<value>
<string>
Determines if related values should be indexed on target documents (i.e. in ZODB) in addition to catalog.\n
This is incompatible with category acquisition.
</string>
</value>
</item>
<item>
<key>
<string>
id
</string>
</key>
<value>
<string>
related_locally_indexed_property
</string>
</value>
</item>
<item>
<key>
<string>
mode
</string>
</key>
<value>
<string>
w
</string>
</value>
</item>
<item>
<key>
<string>
portal_type
</string>
</key>
<value>
<string>
Standard Property
</string>
</value>
</item>
<item>
<key>
<string>
property_default
</string>
</key>
<value>
<string>
python: 0
</string>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
product/ERP5/bootstrap/erp5_property_sheets/bt/revision
View file @
6bf9e694
56
\ No newline at end of file
57
\ No newline at end of file
product/ERP5/tests/testResource.py
View file @
6bf9e694
...
...
@@ -862,20 +862,19 @@ class TestResource(ERP5TypeTestCase):
self
.
tic
()
# Test the cases
for
product
,
variation
,
node
,
base_price
in
test_case_list
:
categories
=
[]
if
node
is
not
None
:
self
.
logMessage
(
"Check product %s with destination section %s"
%
\
(
product
.
getTitle
(),
node
.
getTitle
()),
tab
=
1
)
self
.
assertEquals
(
base_price
,
product
.
getPrice
(
categories
=
[
'destination_section/%s'
%
node
.
getRelativeUrl
(),
variation
]))
categories
.
append
(
'destination_section/'
+
node
.
getRelativeUrl
())
else
:
self
.
logMessage
(
"Check product %s without destination section"
%
\
product
.
getTitle
(),
tab
=
1
)
self
.
assertEquals
(
base_price
,
product
.
getPrice
(
categories
=
[
variation
]))
if
variation
:
categories
.
append
(
variation
)
self
.
assertEqual
(
base_price
,
product
.
getPrice
(
categories
=
categories
))
# The following test tests Movement.getPrice, which is based on the movement
...
...
product/ERP5Type/Accessor/Value.py
View file @
6bf9e694
...
...
@@ -48,8 +48,7 @@ class SetSetter(BaseSetter):
def
__call__
(
self
,
instance
,
*
args
,
**
kw
):
if
self
.
_warning
:
LOG
(
"ERP5Type Deprecated Setter Id:"
,
0
,
self
.
_id
)
value
=
set
(
args
[
0
])
instance
.
_setValue
(
self
.
_key
,
value
,
instance
.
_setValue
(
self
.
_key
,
set
(
args
[
0
]),
spec
=
kw
.
get
(
'spec'
,()),
filter
=
kw
.
get
(
'filter'
,
None
),
portal_type
=
kw
.
get
(
'portal_type'
,()),
...
...
@@ -451,7 +450,7 @@ class UidSetSetter(BaseSetter):
def
__call__
(
self
,
instance
,
*
args
,
**
kw
):
if
self
.
_warning
:
LOG
(
"ERP5Type Deprecated Getter Id:"
,
0
,
self
.
_id
)
instance
.
_setValueUidList
(
self
.
_key
,
args
[
0
]
,
instance
.
_setValueUidList
(
self
.
_key
,
set
(
args
[
0
])
,
spec
=
kw
.
get
(
'spec'
,()),
filter
=
kw
.
get
(
'filter'
,
None
),
portal_type
=
kw
.
get
(
'portal_type'
,()),
...
...
product/ERP5Type/Base.py
View file @
6bf9e694
...
...
@@ -2013,11 +2013,8 @@ class Base( CopyContainer,
checked_permission
=
None
):
# We must do an ordered list so we can not use the previous method
# self._setValue(id, self.portal_catalog.getObjectList(uids), spec=spec)
references
=
[]
if
type
(
uids
)
not
in
(
type
(()),
type
([])):
uids
=
[
uids
]
for
uid
in
uids
:
references
.
append
(
self
.
portal_catalog
.
getObject
(
uid
))
references
=
map
(
self
.
getPortalObject
().
portal_catalog
.
getObject
,
(
uids
,)
if
isinstance
(
uids
,
(
int
,
long
))
else
uids
)
self
.
_setValue
(
id
,
references
,
spec
=
spec
,
filter
=
filter
,
portal_type
=
portal_type
,
keep_default
=
keep_default
,
checked_permission
=
checked_permission
)
...
...
@@ -2178,9 +2175,6 @@ class Base( CopyContainer,
"""
return
self
.
_getCategoryTool
().
getAcquiredCategoryList
(
self
)
def
_getAcquiredCategoryList
(
self
):
return
self
.
_getCategoryTool
().
_getAcquiredCategoryList
(
self
)
security
.
declareProtected
(
Permissions
.
ModifyPortalContent
,
'setCategoryList'
)
def
setCategoryList
(
self
,
path_list
):
self
.
portal_categories
.
setCategoryList
(
self
,
path_list
)
...
...
product/ERP5Type/tests/testERP5Type.py
View file @
6bf9e694
...
...
@@ -722,27 +722,21 @@ class TestERP5Type(PropertySheetTestCase, LogInterceptor):
self
.
assertEquals
(
person
.
getDefaultRegion
(),
'alpha'
)
person
.
setRegionUid
(
alpha
.
getUid
())
self
.
assertEquals
(
person
.
getRegion
(),
'alpha'
)
person
.
setRegionUidList
([
alpha
.
getUid
(),
alph
a
.
getUid
()])
self
.
assertEquals
(
person
.
getRegionList
(),
[
'
alpha'
,
'alph
a'
])
person
.
setRegionUidList
([
beta
.
getUid
(),
bet
a
.
getUid
()])
self
.
assertEquals
(
person
.
getRegionList
(),
[
'
beta'
,
'bet
a'
])
person
.
setRegionUidSet
([
alpha
.
getUid
(),
alpha
.
getUid
()])
self
.
assertEquals
(
person
.
getRegion
Se
t
(),
[
'alpha'
])
self
.
assertEquals
(
person
.
getRegion
Lis
t
(),
[
'alpha'
])
person
.
setRegionUidList
([
alpha
.
getUid
(),
beta
.
getUid
(),
alpha
.
getUid
()])
self
.
assertEquals
(
person
.
getRegionList
(),
[
'alpha'
,
'beta'
,
'alpha'
])
person
.
setRegionUidSet
([
alpha
.
getUid
(),
beta
.
getUid
(),
alpha
.
getUid
()])
result
=
person
.
getRegionSet
()
result
.
sort
()
self
.
assertEquals
(
result
,
[
'alpha'
,
'beta'
])
self
.
assertEquals
(
sorted
(
person
.
getRegionSet
()),
[
'alpha'
,
'beta'
])
person
.
setDefaultRegionUid
(
beta
.
getUid
())
self
.
assertEquals
(
person
.
getDefaultRegion
(),
'beta'
)
result
=
person
.
getRegionSet
()
result
.
sort
()
self
.
assertEquals
(
result
,
[
'alpha'
,
'beta'
])
self
.
assertEquals
(
sorted
(
person
.
getRegionSet
()),
[
'alpha'
,
'beta'
])
self
.
assertEquals
(
person
.
getRegionList
(),
[
'beta'
,
'alpha'
])
person
.
setDefaultRegionUid
(
alpha
.
getUid
())
self
.
assertEquals
(
person
.
getDefaultRegion
(),
'alpha'
)
result
=
person
.
getRegionSet
()
result
.
sort
()
self
.
assertEquals
(
result
,
[
'alpha'
,
'beta'
])
self
.
assertEquals
(
sorted
(
person
.
getRegionSet
()),
[
'alpha'
,
'beta'
])
self
.
assertEquals
(
person
.
getRegionList
(),
[
'alpha'
,
'beta'
])
# Test accessor on documents rather than on categories
person
.
setDefaultRegionUid
(
person
.
getUid
())
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment