Skip to content

Commit 78fe996

Browse files
authored
Merge pull request #200 from OpenSPP/fix/989-area-filtering-program-cr
fix(spp_area,spp_programs,spp_change_request_v2): apply area filtering for Programs and Change Requests (#989)
2 parents 4a98bdb + de69ff2 commit 78fe996

15 files changed

Lines changed: 222 additions & 18 deletions

File tree

spp_area/README.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,17 @@ Dependencies
140140
Changelog
141141
=========
142142

143+
19.0.2.0.1
144+
~~~~~~~~~~
145+
146+
- fix(security): add a global ``ir.rule`` on ``res.partner`` that
147+
filters registrants by ``area_id`` for users with ``center_area_ids``
148+
set (OP#989). Replaces the limited ``search_read`` /
149+
``web_search_read`` override in ``models/registrant.py`` which missed
150+
``name_search`` (Many2one dropdowns), ``search_count``,
151+
``read_group``, and related-field traversal. The rule's conditional
152+
domain is a no-op for users without center areas (global roles).
153+
143154
19.0.2.0.0
144155
~~~~~~~~~~
145156

spp_area/__manifest__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"name": "OpenSPP Area Management",
77
"summary": "Establishes direct associations between OpenSPP registrants, beneficiary groups, and their corresponding geographical administrative areas. It validates registrant-area linkages against official area types, ensuring data integrity and enabling targeted program delivery and analysis.",
88
"category": "OpenSPP/Core",
9-
"version": "19.0.2.0.0",
9+
"version": "19.0.2.0.1",
1010
"sequence": 1,
1111
"author": "OpenSPP.org",
1212
"website": "https://github.com/OpenSPP/OpenSPP2",
@@ -33,6 +33,7 @@
3333
"security/privileges.xml",
3434
"security/groups.xml",
3535
"security/ir.model.access.csv",
36+
"security/rules.xml",
3637
"wizard/area_import_language_wizard_views.xml",
3738
"views/area_base.xml",
3839
"views/area_tag.xml",

spp_area/readme/HISTORY.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
### 19.0.2.0.1
2+
3+
- fix(security): add a global `ir.rule` on `res.partner` that filters registrants by `area_id` for users with `center_area_ids` set (OP#989). Replaces the limited `search_read` / `web_search_read` override in `models/registrant.py` which missed `name_search` (Many2one dropdowns), `search_count`, `read_group`, and related-field traversal. The rule's conditional domain is a no-op for users without center areas (global roles).
4+
15
### 19.0.2.0.0
26

37
- Initial migration to OpenSPP2

spp_area/security/rules.xml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<!--
3+
Part of OpenSPP. See LICENSE file for full copyright and licensing details.
4+
5+
Area-based row-level filtering for registrants (OP#989).
6+
7+
Replaces / strengthens the `_prepare_domain` override in models/registrant.py
8+
which only catches `search_read` / `web_search_read`. An ir.rule applies to
9+
every ORM read path automatically: `search`, `search_count`, `read_group`,
10+
`name_search` (Many2one dropdowns), `read`, and related-field traversal.
11+
12+
The rule is scoped to `is_registrant = True` only — non-registrant contacts
13+
(users' own partners, admins, companies, system bots, mail followers) must
14+
remain readable, otherwise every record using `message_partner_ids` /
15+
`message_follower_ids` blows up for local users with `center_area_ids`.
16+
17+
The conditional domain makes the rule a no-op for users without
18+
`center_area_ids` (global roles).
19+
-->
20+
<odoo noupdate="1">
21+
<record id="rule_res_partner_area_filter" model="ir.rule">
22+
<field name="name">Registrants: visible only within user's center areas</field>
23+
<field name="model_id" ref="base.model_res_partner" />
24+
<field
25+
name="domain_force"
26+
>['|', ('is_registrant', '=', False), ('area_id', 'child_of', user.center_area_ids.ids)] if user.center_area_ids else []</field>
27+
<field name="global" eval="True" />
28+
<field name="perm_read" eval="True" />
29+
<field name="perm_write" eval="True" />
30+
<field name="perm_create" eval="True" />
31+
<field name="perm_unlink" eval="True" />
32+
</record>
33+
</odoo>

spp_area/static/description/index.html

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,18 @@ <h2><a class="toc-backref" href="#toc-entry-1">Changelog</a></h2>
537537
</div>
538538
</div>
539539
<div class="section" id="section-1">
540+
<h1>19.0.2.0.1</h1>
541+
<ul class="simple">
542+
<li>fix(security): add a global <tt class="docutils literal">ir.rule</tt> on <tt class="docutils literal">res.partner</tt> that
543+
filters registrants by <tt class="docutils literal">area_id</tt> for users with <tt class="docutils literal">center_area_ids</tt>
544+
set (OP#989). Replaces the limited <tt class="docutils literal">search_read</tt> /
545+
<tt class="docutils literal">web_search_read</tt> override in <tt class="docutils literal">models/registrant.py</tt> which missed
546+
<tt class="docutils literal">name_search</tt> (Many2one dropdowns), <tt class="docutils literal">search_count</tt>,
547+
<tt class="docutils literal">read_group</tt>, and related-field traversal. The rule’s conditional
548+
domain is a no-op for users without center areas (global roles).</li>
549+
</ul>
550+
</div>
551+
<div class="section" id="section-2">
540552
<h1>19.0.2.0.0</h1>
541553
<ul class="simple">
542554
<li>Initial migration to OpenSPP2</li>

spp_change_request_v2/README.rst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -853,6 +853,18 @@ Before declaring a new CR type complete:
853853
Changelog
854854
=========
855855

856+
19.0.2.0.5
857+
~~~~~~~~~~
858+
859+
- fix(security): add a global ``ir.rule`` on ``spp.change.request`` that
860+
filters by ``registrant_id.area_id`` against the user's
861+
``center_area_ids`` (OP#989 round-2). The earlier ``_prepare_domain``
862+
override only caught ``search_read`` / ``web_search_read`` and missed
863+
the registrant Many2one picker (which uses ``name_search`` →
864+
``_search``), so users could still select out-of-area registrants. The
865+
conditional domain is a no-op for users with no center areas (global
866+
roles).
867+
856868
19.0.2.0.3
857869
~~~~~~~~~~
858870

spp_change_request_v2/__manifest__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "OpenSPP Change Request V2",
3-
"version": "19.0.2.0.3",
3+
"version": "19.0.2.0.5",
44
"sequence": 50,
55
"category": "OpenSPP",
66
"summary": "Configuration-driven change request system with UX improvements, conflict detection and duplicate prevention",
@@ -13,6 +13,7 @@
1313
"mail",
1414
"spp_base_common",
1515
"spp_registry",
16+
"spp_area",
1617
"spp_security",
1718
"spp_approval",
1819
"spp_event_data",
@@ -24,6 +25,7 @@
2425
"security/privileges.xml",
2526
"security/groups.xml",
2627
"security/rules.xml",
28+
"security/area_filter_rules.xml",
2729
"security/ir.model.access.csv",
2830
# Views (loaded before data that references them)
2931
"views/dms_file_views.xml",

spp_change_request_v2/readme/HISTORY.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
### 19.0.2.0.5
2+
3+
- fix(security): add a global `ir.rule` on `spp.change.request` that filters by `registrant_id.area_id` against the user's `center_area_ids` (OP#989 round-2). The earlier `_prepare_domain` override only caught `search_read` / `web_search_read` and missed the registrant Many2one picker (which uses `name_search``_search`), so users could still select out-of-area registrants. The conditional domain is a no-op for users with no center areas (global roles).
4+
15
### 19.0.2.0.3
26

37
- fix: add HTML escaping to all computed Html fields with `sanitize=False` to prevent stored XSS (#50)
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<!--
3+
Part of OpenSPP. See LICENSE file for full copyright and licensing details.
4+
5+
Area-based row-level filtering for change requests (OP#989).
6+
7+
QA round 1 surfaced that the original `_prepare_domain` override on
8+
`spp.change.request` only caught `search_read` / `web_search_read`. The
9+
registrant picker on the CR form (a Many2one widget) calls `name_search` ->
10+
`_search` and bypasses the override. An ir.rule applies to every ORM read
11+
path automatically, including `name_search`, `search_count`, `read_group`,
12+
and related-field traversal.
13+
14+
Mirrors the conditional domain pattern from `spp_area/security/rules.xml`
15+
so users without `center_area_ids` (global roles) are unaffected. The
16+
module now depends on `spp_area` directly so `user.center_area_ids`
17+
can be referenced without defensive guards.
18+
-->
19+
<odoo noupdate="1">
20+
<record id="rule_spp_change_request_area_filter" model="ir.rule">
21+
<field
22+
name="name"
23+
>Change Request: visible only within user's center areas</field>
24+
<field name="model_id" ref="model_spp_change_request" />
25+
<field
26+
name="domain_force"
27+
>[('registrant_id.area_id', 'child_of', user.center_area_ids.ids)] if user.center_area_ids else []</field>
28+
<field name="global" eval="True" />
29+
<field name="perm_read" eval="True" />
30+
<field name="perm_write" eval="True" />
31+
<field name="perm_create" eval="True" />
32+
<field name="perm_unlink" eval="True" />
33+
</record>
34+
</odoo>

spp_change_request_v2/static/description/index.html

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1339,26 +1339,39 @@ <h2>Changelog</h2>
13391339
</div>
13401340
</div>
13411341
<div class="section" id="section-1">
1342+
<h1>19.0.2.0.5</h1>
1343+
<ul class="simple">
1344+
<li>fix(security): add a global <tt class="docutils literal">ir.rule</tt> on <tt class="docutils literal">spp.change.request</tt> that
1345+
filters by <tt class="docutils literal">registrant_id.area_id</tt> against the user’s
1346+
<tt class="docutils literal">center_area_ids</tt> (OP#989 round-2). The earlier <tt class="docutils literal">_prepare_domain</tt>
1347+
override only caught <tt class="docutils literal">search_read</tt> / <tt class="docutils literal">web_search_read</tt> and missed
1348+
the registrant Many2one picker (which uses <tt class="docutils literal">name_search</tt>
1349+
<tt class="docutils literal">_search</tt>), so users could still select out-of-area registrants. The
1350+
conditional domain is a no-op for users with no center areas (global
1351+
roles).</li>
1352+
</ul>
1353+
</div>
1354+
<div class="section" id="section-2">
13421355
<h1>19.0.2.0.3</h1>
13431356
<ul class="simple">
13441357
<li>fix: add HTML escaping to all computed Html fields with
13451358
<tt class="docutils literal">sanitize=False</tt> to prevent stored XSS (#50)</li>
13461359
</ul>
13471360
</div>
1348-
<div class="section" id="section-2">
1361+
<div class="section" id="section-3">
13491362
<h1>19.0.2.0.2</h1>
13501363
<ul class="simple">
13511364
<li>fix: fix batch approval wizard line deletion (#130)</li>
13521365
</ul>
13531366
</div>
1354-
<div class="section" id="section-3">
1367+
<div class="section" id="section-4">
13551368
<h1>19.0.2.0.1</h1>
13561369
<ul class="simple">
13571370
<li>fix: skip field types before getattr and isolate detail prefetch
13581371
(#129)</li>
13591372
</ul>
13601373
</div>
1361-
<div class="section" id="section-4">
1374+
<div class="section" id="section-5">
13621375
<h1>19.0.2.0.0</h1>
13631376
<ul class="simple">
13641377
<li>Initial migration to OpenSPP2</li>

0 commit comments

Comments
 (0)