Commit 66f398f5 authored by Jérome Perrin's avatar Jérome Perrin

Only show groups from user assignments in report dialogs

Because most of the times we configure roles so that users assigned to a group can only see documents from this group, it's a better default that in reports they can only select the groups they are affected to (and the sub categories of these groups).

For more complex security configurations, the script `Base_getDialogSectionCategoryItemList` can be customised.

See merge request nexedi/erp5!1136
parents 9dd1ca85 64ec4b8e
Pipeline #9947 passed with stage
......@@ -269,7 +269,7 @@
<dictionary>
<item>
<key> <string>_text</string> </key>
<value> <string>python:here.Base_getPreferredCategoryChildItemList(here.portal_categories.group, base=True)</string> </value>
<value> <string>context/Base_getDialogSectionCategoryItemList</string> </value>
</item>
</dictionary>
</pickle>
......
......@@ -1784,7 +1784,93 @@ class TestERP5Base(ERP5TypeTestCase):
except KeyError:
pass
def test_suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestERP5Base))
return suite
class Base_getDialogSectionCategoryItemListTest(ERP5TypeTestCase):
"""tests for Base_getDialogSectionCategoryItemList script.
Users, if they are persons, can only select groups that are "included" in their
assignments.
"""
def afterSetUp(self):
super(ERP5TypeTestCase, self).afterSetUp()
self.user_id = self.id()
self.portal.acl_users.zodb_roles.doAssignRoleToPrincipal(self.user_id, 'Auditor')
self.person = self.portal.person_module.newContent(
portal_type='Person',
user_id=self.user_id,
)
group_base_category = self.portal.portal_categories.group
group_base_category.manage_delObjects(list(group_base_category.objectIds()))
main_group = group_base_category.newContent(
id='main_group',
title='Main Group',
int_index=1,
)
main_group.newContent(
id='sub_group',
title='Sub Group',
int_index=1,
)
main_group.newContent(
id='another_sub_group',
title='Another Sub Group',
int_index=2,
)
main_group = group_base_category.newContent(
id='main_group_2',
title='Another Top Level Group',
int_index=2,
)
# XXX group categories are cached
self.portal.portal_caches.clearAllCache()
def test_person_on_main_group(self):
self.person.newContent(portal_type='Assignment', group='main_group').open()
self.tic()
self.login(self.user_id)
self.assertEqual(
self.portal.Base_getDialogSectionCategoryItemList(), [
['', ''],
['Main Group', 'group/main_group'],
['Main Group/Sub Group', 'group/main_group/sub_group'],
[
'Main Group/Another Sub Group',
'group/main_group/another_sub_group'
],
])
def test_person_on_sub_group_user(self):
self.person.newContent(portal_type='Assignment', group='main_group/sub_group').open()
self.tic()
self.login(self.user_id)
self.assertEqual(
self.portal.Base_getDialogSectionCategoryItemList(), [
['', ''],
['Main Group/Sub Group', 'group/main_group/sub_group'],
])
def test_only_valid_assignments_are_considered(self):
self.person.newContent(portal_type='Assignment', group='main_group/sub_group').open()
self.person.newContent(portal_type='Assignment', group='main_group', stop_date=DateTime(1970, 1, 1)).open()
self.person.newContent(portal_type='Assignment', group='main_group') # left as draft
self.tic()
self.login(self.user_id)
self.assertEqual(
self.portal.Base_getDialogSectionCategoryItemList(), [
['', ''],
['Main Group/Sub Group', 'group/main_group/sub_group'],
])
def test_non_person_user(self):
self.assertEqual(
self.portal.Base_getDialogSectionCategoryItemList(), [
['', ''],
['Main Group', 'group/main_group'],
['Main Group/Sub Group', 'group/main_group/sub_group'],
[
'Main Group/Another Sub Group',
'group/main_group/another_sub_group'
],
['Another Top Level Group', 'group/main_group_2'],
])
......@@ -9,12 +9,7 @@
<item>
<key> <string>delegated_list</string> </key>
<value>
<list>
<string>required</string>
<string>title</string>
<string>default</string>
<string>items</string>
</list>
<list/>
</value>
</item>
<item>
......@@ -55,12 +50,6 @@
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>default</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
......@@ -69,12 +58,6 @@
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>items</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
......@@ -88,54 +71,20 @@
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_list_field</string> </value>
<value> <string>my_dialog_mode_section_category</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <int>1</int> </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>Section Category</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="TALESMethod" module="Products.Formulator.TALESField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_text</string> </key>
<value> <string>preferences/getPreferredSectionCategory</string> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="TALESMethod" module="Products.Formulator.TALESField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_text</string> </key>
<value> <string>python: here.portal_categories.group.getCategoryChildIndentedTitleItemList(base=1)</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
"""Return the section_category the user can select in reports.
By default, if the current user is a person, only the groups for which the user
has open assignment can be selected.
"""
portal = context.getPortalObject()
group_title_item_list = portal.Base_getPreferredCategoryChildItemList(
portal.portal_categories.group,
base=True,
)
user = portal.portal_membership.getAuthenticatedMember().getUserValue()
if getattr(user, 'getPortalType', lambda: None)() != 'Person':
return group_title_item_list
allowed_group_set = {
a.getGroup(base=True)
for a in user.Person_getAvailableAssignmentValueList()
}
allowed_group_set = {g for g in allowed_group_set if g}
filtered_group_title_item_list = [['', '']]
for group_title, group_relative_url in group_title_item_list:
if group_relative_url and any(
allowed_group for allowed_group in allowed_group_set
if group_relative_url.startswith(allowed_group + '/')
or group_relative_url == allowed_group):
filtered_group_title_item_list.append([group_title, group_relative_url])
return filtered_group_title_item_list
<?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>_params</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Base_getDialogSectionCategoryItemList</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -164,6 +164,7 @@
<string>my_core_mode_required_text_content_validator</string>
<string>my_view_mode_id</string>
<string>my_honeypot_field</string>
<string>my_dialog_mode_section_category</string>
</list>
</value>
</item>
......
<?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>default</string>
<string>items</string>
<string>required</string>
<string>title</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>my_dialog_mode_section_category</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</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>default</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<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>items</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>required</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_list_field</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>items</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>required</string> </key>
<value> <int>1</int> </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>Section Category</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="TALESMethod" module="Products.Formulator.TALESField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_text</string> </key>
<value> <string>preferences/getPreferredSectionCategory</string> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="TALESMethod" module="Products.Formulator.TALESField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_text</string> </key>
<value> <string>context/Base_getDialogSectionCategoryItemList</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
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