Skip to content

Commit 9144d81

Browse files
[IMP] base_duplicate_security_group: add duplicate restriction for list view
The security group restriction was only applied to the form view duplicate button, leaving a security gap: users without the "Duplicate" permission could still duplicate records by selecting them in list view and using the "Duplicate" action. This patch extends the protection to list view by patching ListController to disable the duplicate action for users without permission. Tours and HttpCase tests verify both allowed and forbidden scenarios. The refactoring extracts the permission check into a common disableDuplicate() function to ensure consistency across both form and list views.
1 parent 3a30e49 commit 9144d81

7 files changed

Lines changed: 79 additions & 21 deletions

File tree

base_duplicate_security_group/README.rst

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,18 @@ of the duplicate records function or not.
3939
Configuration
4040
=============
4141

42-
To allow users to duplicate records from the form view dropdown:
42+
To allow users to duplicate records from the user interface:
4343

4444
1. Go to Settings > Users > Groups.
4545
2. Search for the *Duplicate records* group.
4646
3. Add or remove the users that are allowed or not to duplicate records
4747
via UI.
4848

49+
This restriction applies to:
50+
51+
- **Form view**: Duplicate button in the Action menu
52+
- **List view**: Duplicate action when selecting records
53+
4954
Bug Tracker
5055
===========
5156

base_duplicate_security_group/__manifest__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
{
44
"name": "Restrict records duplicating",
55
"summary": "Adds a security group to restrict which users can copy records",
6-
"version": "18.0.1.0.0",
6+
"version": "18.0.1.1.0",
77
"development_status": "Beta",
88
"category": "Server tools",
99
"website": "https://github.com/OCA/server-ux",
1010
"author": "Tecnativa, Odoo Community Association (OCA)",
1111
"maintainers": ["chienandalu"],
1212
"license": "AGPL-3",
13-
"depends": ["web_tour"],
13+
"depends": ["web", "web_tour"],
1414
"data": ["security/base_duplicate_security_group_security.xml"],
1515
"assets": {
1616
"web.assets_backend": [
Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
1-
To allow users to duplicate records from the form view dropdown:
1+
To allow users to duplicate records from the user interface:
22

33
1. Go to Settings \> Users \> Groups.
44
2. Search for the *Duplicate records* group.
55
3. Add or remove the users that are allowed or not to duplicate records
66
via UI.
7+
8+
This restriction applies to:
9+
10+
- **Form view**: Duplicate button in the Action menu
11+
- **List view**: Duplicate action when selecting records

base_duplicate_security_group/static/description/index.html

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -387,13 +387,18 @@ <h1 class="title">Restrict records duplicating</h1>
387387
</div>
388388
<div class="section" id="configuration">
389389
<h1><a class="toc-backref" href="#toc-entry-1">Configuration</a></h1>
390-
<p>To allow users to duplicate records from the form view dropdown:</p>
390+
<p>To allow users to duplicate records from the user interface:</p>
391391
<ol class="arabic simple">
392392
<li>Go to Settings &gt; Users &gt; Groups.</li>
393393
<li>Search for the <em>Duplicate records</em> group.</li>
394394
<li>Add or remove the users that are allowed or not to duplicate records
395395
via UI.</li>
396396
</ol>
397+
<p>This restriction applies to:</p>
398+
<ul class="simple">
399+
<li><strong>Form view</strong>: Duplicate button in the Action menu</li>
400+
<li><strong>List view</strong>: Duplicate action when selecting records</li>
401+
</ul>
397402
</div>
398403
<div class="section" id="bug-tracker">
399404
<h1><a class="toc-backref" href="#toc-entry-2">Bug Tracker</a></h1>

base_duplicate_security_group/static/src/js/duplicate.esm.js

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,35 @@
33
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
44
*/
55
import {FormController} from "@web/views/form/form_controller";
6+
import {ListController} from "@web/views/list/list_controller";
67
import {patch} from "@web/core/utils/patch";
78
import {user} from "@web/core/user";
89

10+
const GROUP_DUPLICATE = "base_duplicate_security_group.group_duplicate_records";
11+
912
/**
10-
* Patch FormController to disable duplicate action for users without permission.
13+
* Disable duplicate action for users without permission in both Form and List views.
1114
* If the user has the permission, the internal logic rules will apply.
1215
**/
16+
async function disableDuplicate(controller) {
17+
const hasGroup = await user.hasGroup(GROUP_DUPLICATE);
18+
if (!hasGroup && controller.archInfo.activeActions) {
19+
controller.archInfo.activeActions.duplicate = false;
20+
}
21+
}
22+
23+
// Patch FormController - duplicate button in form view
1324
patch(FormController.prototype, {
1425
async setup() {
1526
await super.setup(...arguments);
16-
const base_group = "base_duplicate_security_group.group_duplicate_records";
17-
const hasGroup = await user.hasGroup(base_group);
18-
if (!hasGroup && this.archInfo.activeActions) {
19-
this.archInfo.activeActions.duplicate = false;
20-
}
27+
await disableDuplicate(this);
28+
},
29+
});
30+
31+
// Patch ListController - duplicate action on selected records
32+
patch(ListController.prototype, {
33+
async setup() {
34+
await super.setup(...arguments);
35+
await disableDuplicate(this);
2136
},
2237
});

base_duplicate_security_group/static/src/js/tour_duplicate.esm.js

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,26 +7,40 @@ import {registry} from "@web/core/registry";
77
const commonSteps = [
88
{
99
trigger: ".o_navbar_apps_menu > button.dropdown-toggle",
10+
run: "click",
1011
},
1112
{
1213
content: "Open the settings menu",
1314
trigger: '[data-menu-xmlid="base.menu_administration"]',
15+
run: "click",
1416
},
1517
{
1618
content: "Open the Users and Companies menu",
17-
trigger: '.dropdown-toggle[data-menu-xmlid="base.menu_users"]',
19+
trigger: '[data-menu-xmlid="base.menu_users"]',
20+
run: "click",
1821
},
1922
{
2023
content: "Open the users menu option",
21-
trigger: '.dropdown-item[data-menu-xmlid="base.menu_action_res_users"]',
24+
trigger: '[data-menu-xmlid="base.menu_action_res_users"]',
25+
run: "click",
26+
},
27+
{
28+
content: "Wait for users list",
29+
trigger: ".o_list_view",
2230
},
2331
{
2432
content: "Choose a user",
25-
trigger: ".o_data_cell:contains('Demo')",
33+
trigger: ".o_data_cell",
34+
run: "click",
2635
},
2736
{
28-
content: "Pull the actions dropdown",
29-
trigger: "button.dropdown-toggle:contains('Action')",
37+
content: "Wait for form view to load",
38+
trigger: ".o_form_view",
39+
},
40+
{
41+
content: "Open Action menu",
42+
trigger: ".o_cp_action_menus button",
43+
run: "click",
3044
},
3145
];
3246

@@ -37,7 +51,11 @@ registry.category("web_tour.tours").add("button_duplicate_ok", {
3751
...commonSteps,
3852
{
3953
content: "We can duplicate",
40-
trigger: "a[role='menuitemcheckbox']:contains('Duplicate')",
54+
trigger:
55+
".dropdown-menu .dropdown-item:contains('Duplicate'), " +
56+
".dropdown-menu button:contains('Duplicate'), " +
57+
".dropdown-menu a:contains('Duplicate')",
58+
run: "click",
4159
},
4260
],
4361
});
@@ -48,8 +66,9 @@ registry.category("web_tour.tours").add("button_duplicate_ko", {
4866
steps: () => [
4967
...commonSteps,
5068
{
69+
content: "We cannot duplicate",
5170
trigger:
52-
".btn-group:not(:has(a[role='menuitemcheckbox']:contains('Duplicate')))",
71+
".dropdown-menu:not(:has(.dropdown-item:contains('Duplicate'))):not(:has(button:contains('Duplicate'))):not(:has(a:contains('Duplicate')))",
5372
},
5473
],
5574
});

base_duplicate_security_group/tests/test_base_duplicate_security_group.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,19 @@
55

66
@tagged("-at_install", "post_install")
77
class TestDuplicateSecurityGroup(HttpCase):
8+
@classmethod
9+
def setUpClass(cls):
10+
super().setUpClass()
11+
cls.group_duplicate = cls.env.ref(
12+
"base_duplicate_security_group.group_duplicate_records"
13+
)
14+
cls.admin_user = cls.env.ref("base.user_admin")
15+
816
def test_duplicate_button(self):
9-
"""Whether or not the duplicate button is available
17+
"""Test duplicate button availability in form view.
1018
The button should be accessible depending on the user permissions."""
1119
self.start_tour("web", "button_duplicate_ok", login="admin")
12-
group = self.env.ref("base_duplicate_security_group.group_duplicate_records")
13-
group.users -= self.env.ref("base.user_admin")
20+
self.group_duplicate.users -= self.admin_user
1421
self.start_tour("web", "button_duplicate_ko", login="admin")
22+
# Restore permissions for other tests
23+
self.group_duplicate.users |= self.admin_user

0 commit comments

Comments
 (0)