Commit 35fc526d authored by Jérome Perrin's avatar Jérome Perrin

Fix a broken case of Worklist calculation when using security_uid columns

See discussion in https://www.erp5.com/group_section/forum/Worklists-with-security-uid-columns-wa7gzLN6NG

See merge request nexedi/erp5!1712
parents b51e56e0 840066ac
......@@ -255,6 +255,34 @@ class TestWorklist(TestWorkflowMixin):
self.worklist_int_variable_id,
])
def test_edit_worklist_view(self):
"""Checks we can view and edit worklist.
"""
def check_visible(worklist):
self.clearCache()
worklist.view()
workflow_value = self.getWorkflowTool()[self.checked_workflow]
# edit reference first
worklist_value = workflow_value.newContent(portal_type='Worklist')
check_visible(worklist_value)
worklist_value.setReference(self.worklist_assignor_id)
check_visible(worklist_value)
worklist_value.setActionName('Test (%(count)s)')
worklist_value.setAction('/')
worklist_value.setActionType('global')
check_visible(worklist_value)
# edit reference last
worklist_value = workflow_value.newContent(portal_type='Worklist')
check_visible(worklist_value)
worklist_value.setActionName('Test (%(count)s)')
worklist_value.setAction('/')
worklist_value.setActionType('global')
check_visible(worklist_value)
worklist_value.setReference(self.worklist_owner_id)
check_visible(worklist_value)
def test_01_permission(self, quiet=0, run=run_all_test):
"""
Test the permission of the building module.
......
......@@ -27,82 +27,60 @@
#
##############################################################################
import unittest
from six.moves import urllib
from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
class TestERP5CatalogSecurityUidOptimization(ERP5TypeTestCase):
"""
TestERP5CatalogSecurityUidOptimization tests security_uid optmization.
It is in a different test than TestERP5Catalog as it requires erp5_security_uid_innodb_catalog
bt5 to be installed in advance.
XXX: Inherit from TestERP5Catalog so we test default and security_uid optmization with same tests.
"""
business_template_list = ['erp5_security_uid_innodb_catalog',
'erp5_full_text_mroonga_catalog','erp5_base']
def getBusinessTemplateList(self):
return self.business_template_list
class SecurityUidOptimizationTestCase(ERP5TypeTestCase):
def afterSetUp(self):
self.login()
portal = self.getPortal()
group = portal.portal_categories.group
# this test is expected to run on an empty site
self.assertFalse(self.portal.person_module.contentValues())
group = self.portal.portal_categories.group
if 'g1' not in group.objectIds():
group.newContent(portal_type='Category', id='g1', codification='GROUP1')
if 'g2' not in group.objectIds():
group.newContent(portal_type='Category', id='g2', codification='GROUP2')
local_role_group = self.portal.portal_categories.local_role_group
if 'Alternate' not in local_role_group.objectIds():
local_role_group.newContent(
portal_type='Category',
reference='Alternate',
id='Alternate')
if 'Other' not in local_role_group.objectIds():
local_role_group.newContent(
portal_type='Category',
reference='Other',
id='Other')
def beforeTearDown(self):
self.abort()
for portal_type in (
self.portal.portal_types.Organisation,
self.portal.portal_types.Person,
):
portal_type.manage_delObjects(ids=[
ri.getId() for ri in portal_type.contentValues(
portal_type='Role Information')])
for module in (
self.portal.organisation_module,
self.portal.person_module,
):
if list(module.objectIds()):
module.manage_delObjects(ids=list(module.objectIds()))
self.tic()
class TestSecurityUidOptimizationCatalog(SecurityUidOptimizationTestCase):
def test_local_roles_group_id_on_role_information(self):
def test_search_catalog(self):
"""Test usage of local_roles_group_id when searching catalog.
"""
sql_connection = self.getSQLConnection()
sql_catalog = self.portal.portal_catalog.getSQLCatalog()
# Add a catalog table (uid, alternate_security_uid)
sql_connection.manage_test(
"""DROP TABLE IF EXISTS alternate_roles_and_users""")
sql_connection.manage_test("""
CREATE TABLE alternate_roles_and_users (
`uid` BIGINT UNSIGNED NOT NULL,
`alternate_security_uid` INT UNSIGNED) """)
# make it a search table
current_sql_search_tables = sql_catalog.sql_search_tables
sql_catalog.sql_search_tables = sql_catalog.sql_search_tables + [
'alternate_roles_and_users']
# Configure sql method to insert this table
sql_catalog.newContent(portal_type='SQL Method',
id='z_catalog_alternate_roles_and_users_list',
title='',
connection_id='erp5_sql_connection',
arguments_src="\n".join(['uid', 'alternate_security_uid']),
src="""REPLACE INTO alternate_roles_and_users VALUES
<dtml-in prefix="loop" expr="_.range(_.len(uid))">
( <dtml-sqlvar expr="uid[loop_item]" type="int">,
<dtml-sqlvar expr="alternate_security_uid[loop_item]" type="int" optional>
)<dtml-unless sequence-end>,</dtml-unless>
</dtml-in>""")
current_sql_catalog_object_list = sql_catalog.sql_catalog_object_list
sql_catalog.sql_catalog_object_list = \
current_sql_catalog_object_list + \
('z_catalog_alternate_roles_and_users_list',)
# configure Alternate local roles group id to go in alternate_security_uid
current_sql_catalog_security_uid_columns =\
sql_catalog.sql_catalog_security_uid_columns
sql_catalog.sql_catalog_security_uid_columns = (
' | security_uid',
'Alternate | alternate_security_uid', )
# add category
self.portal.portal_categories.local_role_group.newContent(
portal_type='Category',
reference = 'Alternate',
id = 'Alternate')
# configure security on person, each user will be able to see his own
# person thanks to an Auditor role on "Alternate" local roles group id.
self.portal.portal_types.Person.newContent(
......@@ -118,113 +96,276 @@ CREATE TABLE alternate_roles_and_users (
role_category_list=('group/g1', ),
role_base_category='group',
local_role_group_value=self.portal.portal_categories.local_role_group.Alternate)
self.tic()
# create persons and users
user1 = self.portal.person_module.newContent(portal_type='Person',
reference='user1')
user1_id = user1.Person_getUserId()
user1.newContent(portal_type='Assignment', group='g1').open()
user1.newContent(portal_type='ERP5 Login', reference='user1').validate()
user1.updateLocalRolesOnSecurityGroups()
self.assertEqual(user1.__ac_local_roles__.get(user1_id), ['Auditor'])
self.assertEqual(user1.__ac_local_roles__.get('GROUP1'), ['Unknown'])
user2 = self.portal.person_module.newContent(portal_type='Person',
reference='user2')
user2_id = user2.Person_getUserId()
user2.newContent(portal_type='Assignment', group='g1').open()
user2.newContent(portal_type='ERP5 Login', reference='user2').validate()
user2.updateLocalRolesOnSecurityGroups()
self.assertEqual(user2.__ac_local_roles__.get(user2_id), ['Auditor'])
self.assertEqual(user2.__ac_local_roles__.get('GROUP1'), ['Unknown'])
self.tic()
# security_uid_dict in catalog contains entries for user1 and user2:
user1_alternate_security_uid = sql_catalog.security_uid_dict[
('Alternate', ('user:' + user1_id, 'user:' + user1_id + ':Auditor'))]
user2_alternate_security_uid = sql_catalog.security_uid_dict[
('Alternate', ('user:' + user2_id, 'user:' + user2_id + ':Auditor'))]
# those entries are in alternate security table
alternate_roles_and_users = sql_connection.manage_test(
"SELECT uid, alternate_security_uid from alternate_roles_and_users "
"WHERE alternate_security_uid is not null"
).dictionaries()
self.assertIn(dict(uid=user1.getUid(),
alternate_security_uid=user1_alternate_security_uid),
alternate_roles_and_users)
self.assertIn(dict(uid=user2.getUid(),
alternate_security_uid=user2_alternate_security_uid),
alternate_roles_and_users)
# low level check of the security query of a logged in user
self.loginByUserName('user1')
security_query = self.portal.portal_catalog.getSecurityQuery()
# XXX: this test is introspecting too much, but there is currently no
# obvious better way.
# security_query can be:
# - None if caller is superuser (must not be the case here)
# - a SimpleQuery if caller has no view permissions at all (must not be
# the case here)
# - a ComplexQuery containing SimpleQueries detailing security conditions
# (this is what is expected here)
alternate_security_query, = [
q for q in security_query.query_list
if q.column == 'alternate_security_uid'
]
self.assertEqual(user1_alternate_security_uid,
alternate_security_query.value)
# high level check that that logged in user can see document
self.assertEqual([user1],
[o.getObject() for o in self.portal.portal_catalog(portal_type='Person')])
# also with local_roles= argument which is used in worklists
self.assertEqual([user1],
[o.getObject() for o in self.portal.portal_catalog(portal_type='Person',
local_roles='Auditor')])
# searches still work for other users
self.loginByUserName('user2')
self.assertEqual([user2],
[o.getObject() for o in self.portal.portal_catalog(portal_type='Person')])
self.login()
self.assertSameSet([user1, user2],
[o.getObject() for o in
self.portal.portal_catalog(portal_type='Person')])
# portal types that acquire roles properly acquire the local role group
# id mapping
self.assertTrue(self.portal.portal_types.Career.getTypeAcquireLocalRole())
career = user1.newContent(portal_type='Career')
self.tic()
alternate_roles_and_users = sql_connection.manage_test(
"SELECT uid, alternate_security_uid from alternate_roles_and_users "
"WHERE alternate_security_uid is not null"
).dictionaries()
self.assertIn(dict(uid=career.getUid(),
alternate_security_uid=user1_alternate_security_uid),
alternate_roles_and_users)
self.loginByUserName('user1')
self.assertEqual([career],
[o.getObject() for o in self.portal.portal_catalog(portal_type='Career')])
self.loginByUserName('user2')
self.assertEqual([],
[o.getObject() for o in self.portal.portal_catalog(portal_type='Career')])
class TestSecurityUidOptimizationWorklist(SecurityUidOptimizationTestCase):
def assertWorklistCount(self, username, expected_count_by_worklist_id):
self.loginByUserName(username)
self.portal.portal_workflow.refreshWorklistCache()
self.portal.portal_caches.clearAllCache()
worklist_info_by_worklist_id = {
r['worklist_id']: r
for r in self.portal.portal_workflow.listActions(object=self.portal)
if r['category'] == 'global'
and r['workflow_id'] == 'security_uid_test_simulation_workflow'}
self.assertEqual(
{
worklist_id: worklist_info['count']
for (worklist_id, worklist_info)
in worklist_info_by_worklist_id.items()},
expected_count_by_worklist_id,
)
for worklist_info in worklist_info_by_worklist_id.values():
search_kw = {
k.replace(':list', ''): v
for (k, v)
in dict(urllib.parse.parse_qs(urllib.parse.urlparse(worklist_info['url']).query)).items()}
search_kw.pop('reset', None)
self.assertEqual(
len(self.portal.portal_catalog(**search_kw)),
worklist_info['count'])
def test_worklists(self):
# Persons
# g1 Assignee uses default security_uid
# => security_uid_invalidated, security_uid_or_alternate_security_uid_draft
# g2 Assignor uses alternate_security_uid
# => alternate_security_uid_validated, security_uid_or_alternate_security_uid_draft
self.portal.portal_types.Person.newContent(
portal_type='Role Information',
role_name='Assignee',
role_category_list=('group/g1', ),
role_base_category='group',
)
self.portal.portal_types.Person.newContent(
portal_type='Role Information',
role_name='Assignor',
role_category_list=('group/g2', ),
role_base_category='group',
local_role_group_value=self.portal.portal_categories.local_role_group.Alternate,
)
user_g1 = self.portal.person_module.newContent(
portal_type='Person',
user_id='user_g1')
user_g1.newContent(portal_type='Assignment', group='g1').open()
user_g1.newContent(portal_type='ERP5 Login', reference='user_g1').validate()
user_g2 = self.portal.person_module.newContent(
portal_type='Person',
user_id='user_g2')
user_g2.newContent(portal_type='Assignment', group='g2').open()
user_g2.newContent(portal_type='ERP5 Login', reference='user_g2').validate()
user_g1_g2 = self.portal.person_module.newContent(
portal_type='Person',
user_id='user_g1_g2')
user_g1_g2.newContent(portal_type='Assignment', group='g1').open()
user_g1_g2.newContent(portal_type='Assignment', group='g2').open()
user_g1_g2.newContent(portal_type='ERP5 Login', reference='user_g1_g2').validate()
self.tic()
try:
# create two persons and users
user1 = self.portal.person_module.newContent(portal_type='Person',
reference='user1')
user1_id = user1.Person_getUserId()
user1.newContent(portal_type='Assignment', group='g1').open()
user1.newContent(portal_type='ERP5 Login', reference='user1').validate()
user1.updateLocalRolesOnSecurityGroups()
self.assertEqual(user1.__ac_local_roles__.get(user1_id), ['Auditor'])
self.assertEqual(user1.__ac_local_roles__.get('GROUP1'), ['Unknown'])
user2 = self.portal.person_module.newContent(portal_type='Person',
reference='user2')
user2_id = user2.Person_getUserId()
user2.newContent(portal_type='Assignment', group='g1').open()
user2.newContent(portal_type='ERP5 Login', reference='user2').validate()
user2.updateLocalRolesOnSecurityGroups()
self.assertEqual(user2.__ac_local_roles__.get(user2_id), ['Auditor'])
self.assertEqual(user2.__ac_local_roles__.get('GROUP1'), ['Unknown'])
self.tic()
self.portal.person_module.newContent(portal_type='Person', first_name='validated').validate()
invalidated = self.portal.person_module.newContent(portal_type='Person', first_name='invalidated')
invalidated.validate()
invalidated.invalidate()
# create documents owned by users, for Owner worklists
self.portal.person_module.manage_permission(
'Add portal content', ['Authenticated'])
self.loginByUserName('user_g2')
self.portal.person_module.newContent(portal_type='Person', first_name='draft')
self.tic()
# security_uid_dict in catalog contains entries for user1 and user2:
user1_alternate_security_uid = sql_catalog.security_uid_dict[
('Alternate', ('user:' + user1_id, 'user:' + user1_id + ':Auditor'))]
user2_alternate_security_uid = sql_catalog.security_uid_dict[
('Alternate', ('user:' + user2_id, 'user:' + user2_id + ':Auditor'))]
# those entries are in alternate security table
alternate_roles_and_users = sql_connection.manage_test(
"SELECT * from alternate_roles_and_users").dictionaries()
self.assertIn(dict(uid=user1.getUid(),
alternate_security_uid=user1_alternate_security_uid),
alternate_roles_and_users)
self.assertIn(dict(uid=user2.getUid(),
alternate_security_uid=user2_alternate_security_uid),
alternate_roles_and_users)
# low level check of the security query of a logged in user
self.loginByUserName('user1')
security_query = self.portal.portal_catalog.getSecurityQuery()
# XXX: this test is introspecting too much, but there is currently no
# obvious better way.
# security_query can be:
# - None if caller is superuser (must not be the case here)
# - a SimpleQuery if caller has no view permissions at all (must not be
# the case here)
# - a ComplexQuery containing SimpleQueries detailing security conditions
# (this is what is expected here)
alternate_security_query, = [
q for q in security_query.query_list
if q.column == 'alternate_security_uid'
]
self.assertEqual(user1_alternate_security_uid,
alternate_security_query.value)
# high level check that that logged in user can see document
self.assertEqual([user1],
[o.getObject() for o in self.portal.portal_catalog(portal_type='Person')])
# also with local_roles= argument which is used in worklists
self.assertEqual([user1],
[o.getObject() for o in self.portal.portal_catalog(portal_type='Person',
local_roles='Auditor')])
# searches still work for other users
self.loginByUserName('user2')
self.assertEqual([user2],
[o.getObject() for o in self.portal.portal_catalog(portal_type='Person')])
self.login()
self.assertSameSet([user1, user2],
[o.getObject() for o in
self.portal.portal_catalog(portal_type='Person')])
# portal types that acquire roles properly acquire the local role group
# id mapping
self.assertTrue(self.portal.portal_types.Career.getTypeAcquireLocalRole())
career = user1.newContent(portal_type='Career')
self.assertWorklistCount(
'user_g1',
{
'security_uid_invalidated': 1,
'security_uid_or_alternate_security_uid_draft': 4, # 3 users + 1 draft
}
)
self.assertWorklistCount(
'user_g2',
{
'viewable_owner': 1,
'alternate_security_uid_validated': 1,
'security_uid_or_alternate_security_uid_draft': 4,
}
)
self.assertWorklistCount(
'user_g1_g2',
{
'alternate_security_uid_validated': 1,
'security_uid_invalidated': 1,
'security_uid_or_alternate_security_uid_draft': 4,
}
)
def test_worklist_exclusionlist_collision(self):
# non-regression test for an issue with multiple local role group
self.portal.portal_types.Organisation.newContent(
portal_type='Role Information',
role_name='Assignee',
role_category_list=('group/g1', ),
role_base_category='group',
local_role_group_value=self.portal.portal_categories.local_role_group.Alternate,
)
self.portal.portal_types.Organisation.newContent(
portal_type='Role Information',
role_name='Assignor',
role_category_list=('group/g2', ),
role_base_category='group',
local_role_group_value=self.portal.portal_categories.local_role_group.Alternate,
)
self.portal.portal_types.Person.newContent(
portal_type='Role Information',
role_name='Assignee',
role_category_list=('group/g1', ),
role_base_category='group',
local_role_group_value=self.portal.portal_categories.local_role_group.Other,
)
self.portal.portal_types.Person.newContent(
portal_type='Role Information',
role_name='Assignor',
role_category_list=('group/g2', ),
role_base_category='group',
local_role_group_value=self.portal.portal_categories.local_role_group.Alternate,
)
self.portal.portal_types.Currency.newContent(
portal_type='Role Information',
role_name='Assignor',
role_category_list=('group/g1', ),
role_base_category='group',
local_role_group_value=self.portal.portal_categories.local_role_group.Alternate,
)
self.portal.currency_module.newContent(portal_type='Currency')
collision_worklist = self.portal.portal_workflow.security_uid_test_simulation_workflow.newContent(
portal_type='Worklist',
reference='collision_worklist',
action_name='collision_worklist',
action_type='global',
action='/?portal_type:list=%(portal_type)s&local_roles:list=%(local_roles)s&validation_state=%(validation_state)s'
)
collision_worklist.setCriterion('portal_type', ('Organisation',))
collision_worklist.setCriterion('local_roles', ('Assignee', 'Assignor'))
collision_worklist.setCriterion('validation_state', ('draft',))
def remove_worklist():
self.portal.portal_workflow.security_uid_test_simulation_workflow.manage_delObjects(
[collision_worklist.getId()])
self.tic()
self.addCleanup(remove_worklist)
alternate_roles_and_users = sql_connection.manage_test(
"SELECT * from alternate_roles_and_users").dictionaries()
self.assertIn(dict(uid=career.getUid(),
alternate_security_uid=user1_alternate_security_uid),
alternate_roles_and_users)
self.loginByUserName('user1')
self.assertEqual([career],
[o.getObject() for o in self.portal.portal_catalog(portal_type='Career')])
self.loginByUserName('user2')
self.assertEqual([],
[o.getObject() for o in self.portal.portal_catalog(portal_type='Career')])
finally:
# restore catalog configuration
sql_catalog.sql_search_tables = current_sql_search_tables
sql_catalog.sql_catalog_object_list = current_sql_catalog_object_list
sql_catalog.sql_catalog_security_uid_columns =\
current_sql_catalog_security_uid_columns
self.portal.portal_types.Person.manage_delObjects(
[role.getId() for role in
self.portal.portal_types.Person.contentValues(
portal_type='Role Information')])
user_g1 = self.portal.person_module.newContent(
portal_type='Person',
user_id='user_g1')
user_g1.newContent(portal_type='Assignment', group='g1').open()
user_g1.newContent(portal_type='ERP5 Login', reference='user_g1').validate()
self.tic()
self.portal.organisation_module.newContent(portal_type='Organisation')
self.portal.organisation_module.newContent(portal_type='Organisation').validate()
self.tic()
def test_suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestERP5CatalogSecurityUidOptimization))
return suite
self.assertWorklistCount(
'user_g1',
{
collision_worklist.getReference(): 1,
# Worklist from business template
'security_uid_or_alternate_security_uid_draft': 1,
}
)
erp5_full_text_mroonga_catalog
erp5_base
\ No newline at end of file
erp5_base
erp5_worklist_sql
erp5_security_uid_innodb_catalog_test
\ No newline at end of file
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="SQL Method" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>allow_simple_one_argument_traversal</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>arguments_src</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>cache_time_</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>class_file_</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>class_name_</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>connection_hook</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>connection_id</string> </key>
<value> <string>erp5_sql_connection</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>z0_drop_alternate_roles_and_users</string> </value>
</item>
<item>
<key> <string>max_cache_</string> </key>
<value> <int>100</int> </value>
</item>
<item>
<key> <string>max_rows_</string> </key>
<value> <int>1000</int> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>SQL Method</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>z0_drop_alternate_roles_and_users</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
DELETE FROM alternate_roles_and_users
WHERE <dtml-sqltest uid op=eq type=int multiple>
\ No newline at end of file
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="SQL Method" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>allow_simple_one_argument_traversal</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>arguments_src</string> </key>
<value> <string>uid</string> </value>
</item>
<item>
<key> <string>cache_time_</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>class_file_</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>class_name_</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>connection_hook</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>connection_id</string> </key>
<value> <string>erp5_sql_connection</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>z0_uncatalog_alternate_roles_and_users</string> </value>
</item>
<item>
<key> <string>max_cache_</string> </key>
<value> <int>100</int> </value>
</item>
<item>
<key> <string>max_rows_</string> </key>
<value> <int>1000</int> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>SQL Method</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>z0_uncatalog_alternate_roles_and_users</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<catalog_method>
<item key="sql_catalog_object_list" type="int">
<value>1</value>
</item>
</catalog_method>
REPLACE INTO alternate_roles_and_users
(`uid`, `alternate_security_uid`, `other_security_uid` )
VALUES
<dtml-in prefix="loop" expr="_.range(_.len(uid))">
( <dtml-sqlvar expr="uid[loop_item]" type="int">,
<dtml-sqlvar expr="alternate_security_uid[loop_item]" type="int" optional>,
<dtml-sqlvar expr="other_security_uid[loop_item]" type="int" optional>
)<dtml-unless sequence-end>,</dtml-unless>
</dtml-in>
\ No newline at end of file
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="SQL Method" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>allow_simple_one_argument_traversal</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>arguments_src</string> </key>
<value> <string>uid\n
alternate_security_uid\n
other_security_uid</string> </value>
</item>
<item>
<key> <string>class_file_</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>class_name_</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>connection_id</string> </key>
<value> <string>erp5_sql_connection</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>z_catalog_alternate_roles_and_users_list</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>z_catalog_alternate_roles_and_users_list</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
CREATE TABLE alternate_roles_and_users (
`uid` BIGINT UNSIGNED NOT NULL,
`alternate_security_uid` INT UNSIGNED,
`other_security_uid` INT UNSIGNED,
PRIMARY KEY (`uid`)
)
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="SQL Method" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>allow_simple_one_argument_traversal</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>arguments_src</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>cache_time_</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>class_file_</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>class_name_</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>connection_hook</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>connection_id</string> </key>
<value> <string>erp5_sql_connection</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>z_create_alternate_roles_and_users</string> </value>
</item>
<item>
<key> <string>max_cache_</string> </key>
<value> <int>100</int> </value>
</item>
<item>
<key> <string>max_rows_</string> </key>
<value> <int>1000</int> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>SQL Method</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>z_create_alternate_roles_and_users</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<key_list>
<key>alternate_roles_and_users</key>
</key_list>
\ No newline at end of file
<key_list>
<key>Alternate | alternate_security_uid</key>
<key>Other | other_security_uid</key>
</key_list>
\ No newline at end of file
<workflow_chain>
<chain>
<type>Organisation</type>
<workflow>security_uid_test_simulation_workflow</workflow>
</chain>
<chain>
<type>Person</type>
<workflow>security_uid_test_simulation_workflow</workflow>
</chain>
</workflow_chain>
\ No newline at end of file
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Folder" module="OFS.Folder"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_local_properties</string> </key>
<value>
<tuple>
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>business_template_skin_layer_priority</string> </value>
</item>
<item>
<key> <string>type</string> </key>
<value> <string>float</string> </value>
</item>
</dictionary>
</tuple>
</value>
</item>
<item>
<key> <string>_objects</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>business_template_skin_layer_priority</string> </key>
<value> <float>51.0</float> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>erp5_security_uid_innodb_catalog_test</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
return ['alternate_security_uid', 'other_security_uid', 'security_uid', 'simulation_state', 'validation_state', 'portal_type', 'owner', 'viewable_owner', 'parent_uid', 'title', 'opportunity_state', 'causality_state', 'invoice_state', 'payment_state', 'event_state', 'immobilisation_state', 'reference', 'grouping_reference', 'source_reference', 'destination_reference', 'string_index', 'int_index', 'float_index', 'has_cell_content', 'creation_date', 'modification_date']
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="_reconstructor" module="copy_reg"/>
</klass>
<tuple>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
<global name="object" module="__builtin__"/>
<none/>
</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>_params</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Base_getWorklistTableColumnIDList</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
DROP TABLE IF EXISTS worklist_cache
<dtml-var sql_delimiter>
CREATE TABLE `worklist_cache` (
`count` INT UNSIGNED NOT NULL,
`owner` VARCHAR(32) DEFAULT '',
`viewable_owner` VARCHAR(32) NOT NULL DEFAULT '',
`security_uid` INT UNSIGNED NOT NULL,
`alternate_security_uid` INT UNSIGNED,
`other_security_uid` INT UNSIGNED,
`portal_type` VARCHAR(255) NOT NULL,
`validation_state` VARCHAR(255) NULL,
`simulation_state` VARCHAR(255) NULL,
`parent_uid` BIGINT UNSIGNED default '0',
`title` varchar(255) default '',
`opportunity_state` varchar(255) default '',
`causality_state` varchar(255) default '',
`invoice_state` varchar(255) default '',
`payment_state` varchar(255) default '',
`event_state` varchar(255) default '',
`immobilisation_state` varchar(255) default '',
`reference` varchar(255) binary default '',
`grouping_reference` varchar(255) default '',
`source_reference` varchar(255) default '',
`destination_reference` varchar(255) default '',
`string_index` varchar(255),
`int_index` INT,
`float_index` real,
`has_cell_content` bool,
`creation_date` datetime,
`modification_date` datetime,
KEY `portal_simulation_security` (`portal_type`, `simulation_state`, `security_uid`),
KEY `portal_simulation_owner` (`portal_type`, `simulation_state`, `viewable_owner`),
KEY `portal_validation_security` (`portal_type`, `validation_state`, `security_uid`),
KEY `portal_validation_owner` (`portal_type`, `validation_state`, `viewable_owner`)
) ENGINE=InnoDB
\ No newline at end of file
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="SQL" module="Products.ZSQLMethods.SQL"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_col</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>arguments_src</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>connection_id</string> </key>
<value> <string>erp5_sql_connection</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Base_zCreateWorklistTable</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
INSERT INTO
worklist_cache
(`count`, `owner`, `viewable_owner`, `security_uid`, `alternate_security_uid`, `other_security_uid`, `portal_type`, `validation_state`, `simulation_state`, `parent_uid`, `title`,`opportunity_state`, `causality_state`, `invoice_state`, `payment_state`, `event_state`, `immobilisation_state`, `reference`, `grouping_reference`,
`source_reference`, `destination_reference`, `string_index`, `int_index`, `float_index`, `has_cell_content`, `creation_date`,
`modification_date`)
VALUES
<dtml-in prefix="loop" expr="_.range(_.len(count))">
(
<dtml-sqlvar expr="count[loop_item]" type="int">,
<dtml-sqlvar expr="owner[loop_item]" type="string" optional>,
<dtml-sqlvar expr="viewable_owner[loop_item]" type="string" optional>,
<dtml-sqlvar expr="security_uid[loop_item]" type="int">,
<dtml-sqlvar expr="alternate_security_uid[loop_item]" type="int" optional>,
<dtml-sqlvar expr="other_security_uid[loop_item]" type="int" optional>,
<dtml-sqlvar expr="portal_type[loop_item]" type="string">,
<dtml-sqlvar expr="validation_state[loop_item]" type="string" optional>,
<dtml-sqlvar expr="simulation_state[loop_item]" type="string" optional>,
<dtml-sqlvar expr="parent_uid[loop_item]" type="int" optional>,
<dtml-sqlvar expr="title[loop_item]" type="string" optional>,
<dtml-sqlvar expr="opportunity_state[loop_item]" type="string" optional>,
<dtml-sqlvar expr="causality_state[loop_item]" type="string" optional>,
<dtml-sqlvar expr="invoice_state[loop_item]" type="string" optional>,
<dtml-sqlvar expr="payment_state[loop_item]" type="string" optional>,
<dtml-sqlvar expr="event_state[loop_item]" type="string" optional>,
<dtml-sqlvar expr="immobilisation_state[loop_item]" type="string" optional>,
<dtml-sqlvar expr="reference[loop_item]" type="string" optional>,
<dtml-sqlvar expr="grouping_reference[loop_item]" type="string" optional>,
<dtml-sqlvar expr="source_reference[loop_item]" type="string" optional>,
<dtml-sqlvar expr="destination_reference[loop_item]" type="string" optional>,
<dtml-sqlvar expr="string_index[loop_item]" type="string" optional>,
<dtml-sqlvar expr="int_index[loop_item]" type="int" optional>,
<dtml-sqlvar expr="float_index[loop_item]" type="float" optional>,
<dtml-sqlvar expr="has_cell_content[loop_item]" type="int" optional>,
<dtml-sqlvar expr="creation_date[loop_item]" type="datetime" optional>,
<dtml-sqlvar expr="modification_date[loop_item]" type="datetime" optional>
)
<dtml-if sequence-end><dtml-else>,</dtml-if>
</dtml-in>
\ No newline at end of file
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="SQL" module="Products.ZSQLMethods.SQL"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>arguments_src</string> </key>
<value> <string>count\n
security_uid\n
alternate_security_uid\n
other_security_uid\n
portal_type\n
simulation_state\n
validation_state\n
owner\n
viewable_owner\n
parent_uid\n
title\n
opportunity_state\n
causality_state\n
invoice_state\n
payment_state\n
event_state\n
immobilisation_state\n
reference\n
grouping_reference\n
source_reference\n
destination_reference\n
string_index\n
int_index\n
float_index\n
has_cell_content\n
creation_date\n
modification_date</string> </value>
</item>
<item>
<key> <string>connection_id</string> </key>
<value> <string>erp5_sql_connection</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Base_zInsertIntoWorklistTable</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Workflow" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_count</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>_local_properties</string> </key>
<value>
<tuple>
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>jsplumb_graph</string> </value>
</item>
<item>
<key> <string>type</string> </key>
<value> <string>string</string> </value>
</item>
</dictionary>
</tuple>
</value>
</item>
<item>
<key> <string>_mt_index</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>_tree</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>source/portal_workflow/security_uid_test_simulation_workflow/state_draft</string>
</tuple>
</value>
</item>
<item>
<key> <string>comment</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>default_reference</string> </key>
<value> <string>validation_workflow</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string>Dummy workflow to check worklists with erp5_security_uid_innodb_catalog_test</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>security_uid_test_simulation_workflow</string> </value>
</item>
<item>
<key> <string>jsplumb_graph</string> </key>
<value> <string>{"class_definition":{},"graph":{"node":{"state_deleted":{"coordinate":{"top":0.949081048508587,"left":0.9496606334841629},"path":"/erp5/portal_workflow/validation_workflow/state_deleted","_class":"workflow.state","name":"Deleted","is_initial_state":false},"state_invalidated":{"coordinate":{"top":0.949081048508587,"left":0.5264423076923077},"path":"/erp5/portal_workflow/validation_workflow/state_invalidated","_class":"workflow.state","name":"Invalidated","is_initial_state":false},"state_validated":{"coordinate":{"top":0.1385959626393492,"left":0.3545673076923077},"path":"/erp5/portal_workflow/validation_workflow/state_validated","_class":"workflow.state","name":"Validated","is_initial_state":false},"state_draft":{"coordinate":{"top":0.41578788791804766,"left":0.025240384615384616},"path":"/erp5/portal_workflow/validation_workflow/state_draft","_class":"workflow.state","name":"Draft","is_initial_state":true}},"edge":{"transition_to_state_invalidated":{"source":"state_invalidated","destination":"state_invalidated","_class":"workflow.transition","name_path_dict":{"Delete Action":"/erp5/portal_workflow/validation_workflow/transition_delete_action","Validate Action":"/erp5/portal_workflow/validation_workflow/transition_validate_action"}},"state_draft_transition_validate":{"name":"Validate","description":"Validates a document in ERP5","destination":"state_validated","source":"state_draft","path":"/erp5/portal_workflow/validation_workflow/transition_validate","_class":"workflow.transition","transition_id":"transition_validate","actbox_url":null},"state_draft_transition_invalidate":{"name":"Invalidate","description":"This action invalidates a document in ERP5","destination":"state_invalidated","source":"state_draft","path":"/erp5/portal_workflow/validation_workflow/transition_invalidate","_class":"workflow.transition","transition_id":"transition_invalidate","actbox_url":null},"state_validated_transition_invalidate":{"name":"Invalidate","description":"This action invalidates a document in ERP5","destination":"state_invalidated","source":"state_validated","path":"/erp5/portal_workflow/validation_workflow/transition_invalidate","_class":"workflow.transition","transition_id":"transition_invalidate","actbox_url":null},"state_invalidated_transition_delete":{"name":"Delete","description":"Delete a document in ERP5","destination":"state_deleted","source":"state_invalidated","path":"/erp5/portal_workflow/validation_workflow/transition_delete","_class":"workflow.transition","transition_id":"transition_delete","actbox_url":null},"state_invalidated_transition_validate":{"name":"Validate","description":"Validates a document in ERP5","destination":"state_validated","source":"state_invalidated","path":"/erp5/portal_workflow/validation_workflow/transition_validate","_class":"workflow.transition","transition_id":"transition_validate","actbox_url":null},"transition_to_state_validated":{"source":"state_validated","destination":"state_validated","_class":"workflow.transition","name_path_dict":{"Invalidate Action":"/erp5/portal_workflow/validation_workflow/transition_invalidate_action"}},"state_draft_transition_delete":{"name":"Delete","description":"Delete a document in ERP5","destination":"state_deleted","source":"state_draft","path":"/erp5/portal_workflow/validation_workflow/transition_delete","_class":"workflow.transition","transition_id":"transition_delete","actbox_url":null},"transition_to_state_draft":{"source":"state_draft","destination":"state_draft","_class":"workflow.transition","name_path_dict":{"Invalidate Action":"/erp5/portal_workflow/validation_workflow/transition_invalidate_action","Delete Action":"/erp5/portal_workflow/validation_workflow/transition_delete_action","Validate Action":"/erp5/portal_workflow/validation_workflow/transition_validate_action"}}}}}</string> </value>
</item>
<item>
<key> <string>language</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>manager_bypass</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Workflow</string> </value>
</item>
<item>
<key> <string>state_variable</string> </key>
<value> <string>simulation_state</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Security UID Test Simulation Workflow</string> </value>
</item>
<item>
<key> <string>workflow_managed_permission</string> </key>
<value>
<tuple>
<string>Access contents information</string>
<string>Modify portal content</string>
<string>View</string>
<string>Add portal content</string>
</tuple>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="Length" module="BTrees.Length"/>
</pickle>
<pickle> <int>0</int> </pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="OOBTree" module="BTrees.OOBTree"/>
</pickle>
<pickle>
<none/>
</pickle>
</record>
<record id="4" aka="AAAAAAAAAAQ=">
<pickle>
<global name="OOBTree" module="BTrees.OOBTree"/>
</pickle>
<pickle>
<none/>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Workflow State" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>acquire_permission</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string>Default state of the document</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>state_draft</string> </value>
</item>
<item>
<key> <string>index</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Workflow State</string> </value>
</item>
<item>
<key> <string>state_permission_role_list_dict</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>state_type</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Draft</string> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>cell</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>Access contents information</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Auditor</string>
<string>Author</string>
<string>Manager</string>
<string>Owner</string>
</tuple>
</value>
</item>
<item>
<key> <string>Add portal content</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Author</string>
<string>Manager</string>
<string>Owner</string>
</tuple>
</value>
</item>
<item>
<key> <string>Modify portal content</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Author</string>
<string>Manager</string>
<string>Owner</string>
</tuple>
</value>
</item>
<item>
<key> <string>View</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Auditor</string>
<string>Author</string>
<string>Manager</string>
<string>Owner</string>
</tuple>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="4" aka="AAAAAAAAAAQ=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <int>0</int> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAU=</string> </persistent>
</value>
</item>
<item>
<key> <int>1</int> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAY=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="5" aka="AAAAAAAAAAU=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>Access contents information</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>Add portal content</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>Modify portal content</string> </key>
<value> <int>2</int> </value>
</item>
<item>
<key> <string>View</string> </key>
<value> <int>3</int> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="6" aka="AAAAAAAAAAY=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>Anonymous</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>Assignee</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>Assignor</string> </key>
<value> <int>2</int> </value>
</item>
<item>
<key> <string>Associate</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>Auditor</string> </key>
<value> <int>4</int> </value>
</item>
<item>
<key> <string>Authenticated</string> </key>
<value> <int>5</int> </value>
</item>
<item>
<key> <string>Author</string> </key>
<value> <int>6</int> </value>
</item>
<item>
<key> <string>Manager</string> </key>
<value> <int>7</int> </value>
</item>
<item>
<key> <string>Member</string> </key>
<value> <int>8</int> </value>
</item>
<item>
<key> <string>Owner</string> </key>
<value> <int>9</int> </value>
</item>
<item>
<key> <string>Reviewer</string> </key>
<value> <int>10</int> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Workflow Variable" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>automatic_update</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>for_catalog</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>variable_action</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Workflow Variable</string> </value>
</item>
<item>
<key> <string>status_included</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>variable_default_expression</string> </key>
<value> <string>transition/getReference|nothing</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Workflow Variable" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>automatic_update</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>for_catalog</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>variable_actor</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Workflow Variable</string> </value>
</item>
<item>
<key> <string>status_included</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>variable_default_expression</string> </key>
<value> <string>user/getIdOrUserName</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Workflow Variable" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>automatic_update</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>for_catalog</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>variable_comment</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Workflow Variable</string> </value>
</item>
<item>
<key> <string>status_included</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>variable_default_expression</string> </key>
<value> <string>python:state_change.kwargs.get(\'comment\',\'\')</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Workflow Variable" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>automatic_update</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>for_catalog</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>variable_error_message</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Workflow Variable</string> </value>
</item>
<item>
<key> <string>status_included</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value>
<none/>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Workflow Variable" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>automatic_update</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>for_catalog</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>variable_history</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Workflow Variable</string> </value>
</item>
<item>
<key> <string>status_included</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>variable_default_expression</string> </key>
<value> <string>state_change/getHistory</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Workflow Variable" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>automatic_update</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>for_catalog</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>variable_portal_type</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Workflow Variable</string> </value>
</item>
<item>
<key> <string>status_included</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value>
<none/>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Workflow Variable" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>automatic_update</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>for_catalog</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>variable_time</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Workflow Variable</string> </value>
</item>
<item>
<key> <string>status_included</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>variable_default_expression</string> </key>
<value> <string>state_change/getDateTime</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Workflow Variable" 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>group_list</string> </value>
</item>
<item>
<key> <string>type</string> </key>
<value> <string>lines</string> </value>
</item>
</dictionary>
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>permission_list</string> </value>
</item>
<item>
<key> <string>type</string> </key>
<value> <string>lines</string> </value>
</item>
</dictionary>
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>role_list</string> </value>
</item>
<item>
<key> <string>type</string> </key>
<value> <string>lines</string> </value>
</item>
</dictionary>
</tuple>
</value>
</item>
<item>
<key> <string>automatic_update</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>for_catalog</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>group_list</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>variable_validation_state</string> </value>
</item>
<item>
<key> <string>permission_list</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Workflow Variable</string> </value>
</item>
<item>
<key> <string>role_list</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>status_included</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>validation_state</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Worklist" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_identity_criterion</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>_range_criterion</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>action</string> </key>
<value> <string encoding="cdata"><![CDATA[
person_module/view?validation_state=validated&local_roles=%(local_roles)s&reset=1
]]></string> </value>
</item>
<item>
<key> <string>action_name</string> </key>
<value> <string>Security UID Test Worklist Matching alternate_security_uid (%(count)s)</string> </value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>action_type/global</string>
</tuple>
</value>
</item>
<item>
<key> <string>comment</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>criterion_property</string> </key>
<value>
<tuple>
<string>local_roles</string>
<string>portal_type</string>
<string>validation_state</string>
</tuple>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>guard_expression</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>guard_group</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>guard_permission</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>icon</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>worklist_alternate_security_uid_validated</string> </value>
</item>
<item>
<key> <string>int_index</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>membership_criterion_category</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Worklist</string> </value>
</item>
<item>
<key> <string>string_index</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>test_method_id</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>title</string> </key>
<value>
<none/>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>local_roles</string> </key>
<value>
<list>
<string>Assignor</string>
</list>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value>
<list>
<string>Person</string>
</list>
</value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value>
<list>
<string>validated</string>
</list>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary/>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Worklist" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_identity_criterion</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>_range_criterion</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>action</string> </key>
<value> <string encoding="cdata"><![CDATA[
person_module/view?portal_type=Person&validation_state=invalidated&local_roles:list=%(local_roles)s&reset=1
]]></string> </value>
</item>
<item>
<key> <string>action_name</string> </key>
<value> <string>Security UID Test Worklist Matching security_uid (%(count)s)</string> </value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>action_type/global</string>
</tuple>
</value>
</item>
<item>
<key> <string>comment</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>criterion_property</string> </key>
<value>
<tuple>
<string>local_roles</string>
<string>portal_type</string>
<string>validation_state</string>
</tuple>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>guard_expression</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>guard_group</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>guard_permission</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>icon</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>worklist_security_uid_invalidated</string> </value>
</item>
<item>
<key> <string>int_index</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>membership_criterion_category</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Worklist</string> </value>
</item>
<item>
<key> <string>string_index</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>test_method_id</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>title</string> </key>
<value>
<none/>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>local_roles</string> </key>
<value>
<list>
<string>Assignee</string>
</list>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value>
<list>
<string>Person</string>
</list>
</value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value>
<list>
<string>invalidated</string>
</list>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary/>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Worklist" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_identity_criterion</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>_range_criterion</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>action</string> </key>
<value> <string encoding="cdata"><![CDATA[
person_module/view?portal_type=Person&validation_state=draft&local_roles:list=%(local_roles)s&reset=1
]]></string> </value>
</item>
<item>
<key> <string>action_name</string> </key>
<value> <string>Security UID Test Worklist Matching security_uid Or alternate_security_uid (%(count)s)</string> </value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>action_type/global</string>
</tuple>
</value>
</item>
<item>
<key> <string>comment</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>criterion_property</string> </key>
<value>
<tuple>
<string>local_roles</string>
<string>portal_type</string>
<string>validation_state</string>
</tuple>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>guard_expression</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>guard_group</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>guard_permission</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>icon</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>worklist_security_uid_or_alternate_security_uid_draft</string> </value>
</item>
<item>
<key> <string>int_index</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>membership_criterion_category</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Worklist</string> </value>
</item>
<item>
<key> <string>string_index</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>test_method_id</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>title</string> </key>
<value>
<none/>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>local_roles</string> </key>
<value>
<list>
<string>Assignee</string>
<string>Assignor</string>
</list>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value>
<list>
<string>Person</string>
</list>
</value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value>
<list>
<string>draft</string>
</list>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary/>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Worklist" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_identity_criterion</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>_range_criterion</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>action</string> </key>
<value> <string encoding="cdata"><![CDATA[
organisation_module/view?validation_state=validated&local_roles:list=%(local_roles)s&reset=1
]]></string> </value>
</item>
<item>
<key> <string>action_name</string> </key>
<value> <string>Security UID Test Worklist Matching security_uid (%(count)s)</string> </value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>action_type/global</string>
</tuple>
</value>
</item>
<item>
<key> <string>comment</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>criterion_property</string> </key>
<value>
<tuple>
<string>local_roles</string>
<string>portal_type</string>
<string>validation_state</string>
</tuple>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>guard_expression</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>guard_group</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>guard_permission</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>icon</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>worklist_security_uid_validated_organisation</string> </value>
</item>
<item>
<key> <string>int_index</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>membership_criterion_category</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Worklist</string> </value>
</item>
<item>
<key> <string>string_index</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>test_method_id</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>title</string> </key>
<value>
<none/>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>local_roles</string> </key>
<value>
<list>
<string>Assignor</string>
</list>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value>
<list>
<string>Organisation</string>
</list>
</value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value>
<list>
<string>validated</string>
</list>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary/>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Worklist" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_identity_criterion</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>_range_criterion</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>action</string> </key>
<value> <string encoding="cdata"><![CDATA[
person_module/view?portal_type=Person&validation_state=draft&local_roles:list=%(local_roles)s&reset=1
]]></string> </value>
</item>
<item>
<key> <string>action_name</string> </key>
<value> <string>Security UID Test Worklist Matching Viewable Owner (%(count)s)</string> </value>
</item>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>action_type/global</string>
</tuple>
</value>
</item>
<item>
<key> <string>comment</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>criterion_property</string> </key>
<value>
<tuple>
<string>local_roles</string>
<string>portal_type</string>
<string>validation_state</string>
</tuple>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>guard_expression</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>guard_group</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>guard_permission</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>icon</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>worklist_viewable_owner</string> </value>
</item>
<item>
<key> <string>int_index</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>membership_criterion_category</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Worklist</string> </value>
</item>
<item>
<key> <string>string_index</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>test_method_id</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>title</string> </key>
<value>
<none/>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>local_roles</string> </key>
<value>
<list>
<string>Owner</string>
</list>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value>
<list>
<string>Person</string>
</list>
</value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value>
<list>
<string>draft</string>
</list>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary/>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
Test configuration for erp5_security_uid_innodb_catalog
\ No newline at end of file
erp5_mysql_innodb/z0_drop_alternate_roles_and_users
erp5_mysql_innodb/z0_uncatalog_alternate_roles_and_users
erp5_mysql_innodb/z_catalog_alternate_roles_and_users_list
erp5_mysql_innodb/z_create_alternate_roles_and_users
\ No newline at end of file
Alternate | alternate_security_uid
Other | other_security_uid
\ No newline at end of file
Organisation | security_uid_test_simulation_workflow
Person | security_uid_test_simulation_workflow
\ No newline at end of file
erp5_security_uid_innodb_catalog_test
\ No newline at end of file
security_uid_test_simulation_workflow
\ No newline at end of file
erp5_security_uid_innodb_catalog_test
\ No newline at end of file
......@@ -28,6 +28,7 @@
"""
Most of the code in this file has been taken from patches/WorkflowTool.py
"""
from collections import defaultdict
import re
import warnings
from six import string_types as basestring
......@@ -662,23 +663,31 @@ WorkflowTool.security.declarePrivate('getWorkflowById')
InitializeClass(WorkflowTool)
class ExclusionList(list):
class ExclusionSequence(object):
def __repr__(self):
return '<%s %s>' % (
self.__class__.__name__,
super(ExclusionSequence, self).__repr__())
class ExclusionList(ExclusionSequence, list):
"""
This is a dummy subclass of list.
It is only used to detect wether contained values must be negated.
It is not to be used outside of the scope of this document nor outside
of the scope of worklist criterion handling.
"""
pass
class ExclusionTuple(tuple):
class ExclusionTuple(ExclusionSequence, tuple):
"""
This is a dummy subclass of tuple.
It is only used to detect wether contained values must be negated.
It is not to be used outside of the scope of this document nor outside
of the scope of worklist criterion handling.
"""
pass
def getValidCriterionDict(worklist_match_dict, sql_catalog,
workflow_worklist_key):
......@@ -755,6 +764,8 @@ def groupWorklistListByCondition(worklist_dict, sql_catalog,
metadata_dict = {}
for workflow_id, worklist in six.iteritems(worklist_dict):
for worklist_id, worklist_match_dict in six.iteritems(worklist):
if not worklist_id:
continue
workflow_worklist_key = '/'.join((workflow_id, worklist_id))
if getSecurityUidDictAndRoleColumnDict is None:
valid_criterion_dict, metadata = getValidCriterionDict(
......@@ -962,21 +973,17 @@ def sumCatalogResultByWorklist(grouped_worklist_dict, catalog_result):
It is better to avoid reading multiple times the catalog result from
flexibility point of view: if it must ever be changed into a cursor, this
code will keep working nicely without needing to rewind the cursor.
This code assumes that all worklists have the same set of criterion ids,
and that when a criterion id is associated with an ExclusionList it is
also true for all worklists.
"""
worklist_result_dict = {}
if len(catalog_result) > 0:
# Transtype all worklist definitions where needed
criterion_id_list = []
criterion_id_list_by_worklist_dict = defaultdict(list)
class_dict = {name: _sql_cast_dict.get(x['type'], _sql_cast_fallback)
for name, x in six.iteritems(catalog_result.data_dictionary())}
for criterion_dict in six.itervalues(grouped_worklist_dict):
for worklist_id, criterion_dict in six.iteritems(grouped_worklist_dict):
for criterion_id, criterion_value_list in six.iteritems(criterion_dict):
if type(criterion_value_list) is not ExclusionList:
criterion_id_list.append(criterion_id)
criterion_id_list_by_worklist_dict[worklist_id].append(criterion_id)
expected_class = class_dict[criterion_id]
if type(criterion_value_list[0]) is not expected_class:
criterion_dict[criterion_id] = frozenset([expected_class(x) for x in criterion_value_list])
......@@ -987,7 +994,7 @@ def sumCatalogResultByWorklist(grouped_worklist_dict, catalog_result):
result_count = int(result_line[COUNT_COLUMN_TITLE])
for worklist_id, criterion_dict in six.iteritems(grouped_worklist_dict):
is_candidate = True
for criterion_id in criterion_id_list:
for criterion_id in criterion_id_list_by_worklist_dict[worklist_id]:
criterion_value_set = criterion_dict[criterion_id]
if result_line[criterion_id] not in criterion_value_set:
is_candidate = False
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment