Skip to content

Commit 336fcd6

Browse files
committed
[T-7772][ADD] model_access_restriction
1 parent 2b651c5 commit 336fcd6

19 files changed

+1019
-0
lines changed

model_access_restriction/README.rst

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
========================
2+
Model Access Restriction
3+
========================
4+
5+
..
6+
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
7+
!! This file is generated by oca-gen-addon-readme !!
8+
!! changes will be overwritten. !!
9+
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
10+
!! source digest: sha256:6337b5f5fe7be747949769f4c064d9a6ca5495d905fa33e50b868be80bde4557
11+
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
12+
13+
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
14+
:target: https://odoo-community.org/page/development-status
15+
:alt: Beta
16+
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
17+
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
18+
:alt: License: AGPL-3
19+
.. |badge3| image:: https://img.shields.io/badge/github-sygel--technology%2Fsy--server--backend-lightgray.png?logo=github
20+
:target: https://github.com/sygel-technology/sy-server-backend/tree/15.0/model_access_restriction
21+
:alt: sygel-technology/sy-server-backend
22+
23+
|badge1| |badge2| |badge3|
24+
25+
This module adds a new model to configure Odoo permissions, the "Model
26+
Access Restrictions"
27+
28+
This model allows to restrict the access to a model for all users except
29+
the ones that belong to at least one group of a list of allowed groups.
30+
31+
While Odoo's default access rules provide permissions, and having one
32+
already gives you access, these new rules remove them, and failing to
33+
comply with one restricts your access.
34+
35+
**Table of contents**
36+
37+
.. contents::
38+
:local:
39+
40+
Configuration
41+
=============
42+
43+
To configure this module, you need to:
44+
45+
- Go to Settings / Technical / Security / Model Access Restrictions
46+
- Create a new access restriction
47+
- Select the model to restrict the access
48+
- Select the operations the rule applies to. If the operation is not
49+
selected the restriction won't apply to that operation which means
50+
users will access the model as always.
51+
- Select the groups that will have access to the model. The rest of
52+
groups will have the access disabled.
53+
54+
Known issues / Roadmap
55+
======================
56+
57+
- Read and write permissions are not implemented yet. It is commented
58+
and should be easy.
59+
60+
Bug Tracker
61+
===========
62+
63+
Bugs are tracked on `GitHub Issues <https://github.com/sygel-technology/sy-server-backend/issues>`_.
64+
In case of trouble, please check there if your issue has already been reported.
65+
If you spotted it first, help us to smash it by providing a detailed and welcomed
66+
`feedback <https://github.com/sygel-technology/sy-server-backend/issues/new?body=module:%20model_access_restriction%0Aversion:%2015.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
67+
68+
Do not contact contributors directly about support or help with technical issues.
69+
70+
Credits
71+
=======
72+
73+
Authors
74+
-------
75+
76+
* Sygel
77+
78+
Contributors
79+
------------
80+
81+
- Alberto Martínez [email protected]
82+
- Manuel Regidor [email protected]
83+
- Valentin Vinagre [email protected]
84+
- Harald Panten [email protected]
85+
86+
Maintainers
87+
-----------
88+
89+
This module is part of the `sygel-technology/sy-server-backend <https://github.com/sygel-technology/sy-server-backend/tree/15.0/model_access_restriction>`_ project on GitHub.
90+
91+
You are welcome to contribute.

model_access_restriction/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
2+
3+
from . import models
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Copyright 2025 Alberto Martínez <[email protected]>
2+
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
3+
{
4+
"name": "Model Access Restriction",
5+
"summary": "New type of access rule to restrict permissions based on groups",
6+
"version": "15.0.1.0.0",
7+
"category": "Tools",
8+
"website": "https://github.com/sygel-technology/sy-server-backend",
9+
"author": "Sygel, Odoo Community Association (OCA)",
10+
"license": "AGPL-3",
11+
"application": False,
12+
"installable": True,
13+
"depends": [
14+
"base",
15+
],
16+
"data": [
17+
"security/ir.model.access.csv",
18+
"views/ir_model_access_restriction_views.xml",
19+
],
20+
}

model_access_restriction/i18n/es.po

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
# Translation of Odoo Server.
2+
# This file contains the translation of the following modules:
3+
# * model_access_restriction
4+
#
5+
msgid ""
6+
msgstr ""
7+
"Project-Id-Version: Odoo Server 15.0+e\n"
8+
"Report-Msgid-Bugs-To: \n"
9+
"POT-Creation-Date: 2025-04-10 08:12+0000\n"
10+
"PO-Revision-Date: 2025-04-10 10:13+0200\n"
11+
"Last-Translator: \n"
12+
"Language-Team: \n"
13+
"Language: es\n"
14+
"MIME-Version: 1.0\n"
15+
"Content-Type: text/plain; charset=UTF-8\n"
16+
"Content-Transfer-Encoding: 8bit\n"
17+
"Plural-Forms: \n"
18+
"X-Generator: Poedit 3.0.1\n"
19+
20+
#. module: model_access_restriction
21+
#: model_terms:ir.ui.view,arch_db:model_access_restriction.view_model_access_restrictions_form
22+
msgid ""
23+
"<i class=\"fa fa-info fa-3x text-info float-left\" role=\"img\" aria-"
24+
"label=\"Info\" title=\"Info\"/>"
25+
msgstr ""
26+
27+
#. module: model_access_restriction
28+
#: model_terms:ir.ui.view,arch_db:model_access_restriction.view_model_access_restrictions_form
29+
msgid "Access Rights"
30+
msgstr "Permisos de acceso"
31+
32+
#. module: model_access_restriction
33+
#: model:ir.model.fields,field_description:model_access_restriction.field_ir_model_access_restriction__active
34+
msgid "Active"
35+
msgstr "Activo"
36+
37+
#. module: model_access_restriction
38+
#: model:ir.model.fields,field_description:model_access_restriction.field_ir_model_access_restriction__groups
39+
#: model_terms:ir.ui.view,arch_db:model_access_restriction.view_model_access_restrictions_form
40+
msgid "Allowed Groups"
41+
msgstr "Grupos permitidos"
42+
43+
#. module: model_access_restriction
44+
#: model:ir.model.fields,field_description:model_access_restriction.field_ir_model_access_restriction__perm_create
45+
msgid "Apply for Create"
46+
msgstr "Aplicar para creación"
47+
48+
#. module: model_access_restriction
49+
#: model:ir.model.fields,field_description:model_access_restriction.field_ir_model_access_restriction__perm_unlink
50+
msgid "Apply for Delete"
51+
msgstr "Aplicar para eliminación"
52+
53+
#. module: model_access_restriction
54+
#: model_terms:ir.ui.view,arch_db:model_access_restriction.view_model_access_restrictions_search
55+
msgid "Archived"
56+
msgstr "Archivado"
57+
58+
#. module: model_access_restriction
59+
#: model:ir.model,name:model_access_restriction.model_base
60+
msgid "Base"
61+
msgstr "Base"
62+
63+
#. module: model_access_restriction
64+
#: model_terms:ir.ui.view,arch_db:model_access_restriction.view_model_access_restrictions_search
65+
msgid "Create Access Right"
66+
msgstr "Permiso de acceso de creacion"
67+
68+
#. module: model_access_restriction
69+
#: model:ir.model.fields,field_description:model_access_restriction.field_ir_model_access_restriction__create_uid
70+
msgid "Created by"
71+
msgstr ""
72+
73+
#. module: model_access_restriction
74+
#: model:ir.model.fields,field_description:model_access_restriction.field_ir_model_access_restriction__create_date
75+
msgid "Created on"
76+
msgstr ""
77+
78+
#. module: model_access_restriction
79+
#: model_terms:ir.ui.view,arch_db:model_access_restriction.view_model_access_restrictions_search
80+
msgid "Delete Access Right"
81+
msgstr "Permiso de acceso de eliminación"
82+
83+
#. module: model_access_restriction
84+
#: model:ir.model.fields,field_description:model_access_restriction.field_ir_model_access_restriction__display_name
85+
msgid "Display Name"
86+
msgstr "Nombre mostrado"
87+
88+
#. module: model_access_restriction
89+
#: model_terms:ir.ui.view,arch_db:model_access_restriction.view_model_access_restrictions_form
90+
msgid "General"
91+
msgstr "General"
92+
93+
#. module: model_access_restriction
94+
#: model_terms:ir.ui.view,arch_db:model_access_restriction.view_model_access_restrictions_search
95+
msgid "Group By"
96+
msgstr "Agrupar por"
97+
98+
#. module: model_access_restriction
99+
#: model:ir.model.fields,field_description:model_access_restriction.field_ir_model_access_restriction__id
100+
msgid "ID"
101+
msgstr ""
102+
103+
#. module: model_access_restriction
104+
#: model_terms:ir.ui.view,arch_db:model_access_restriction.view_model_access_restrictions_form
105+
msgid "Interaction between access records"
106+
msgstr "Interacciones entre registros de acceso"
107+
108+
#. module: model_access_restriction
109+
#: model:ir.model.fields,field_description:model_access_restriction.field_ir_model_access_restriction____last_update
110+
msgid "Last Modified on"
111+
msgstr ""
112+
113+
#. module: model_access_restriction
114+
#: model:ir.model.fields,field_description:model_access_restriction.field_ir_model_access_restriction__write_uid
115+
msgid "Last Updated by"
116+
msgstr ""
117+
118+
#. module: model_access_restriction
119+
#: model:ir.model.fields,field_description:model_access_restriction.field_ir_model_access_restriction__write_date
120+
msgid "Last Updated on"
121+
msgstr ""
122+
123+
#. module: model_access_restriction
124+
#: model:ir.model.fields,field_description:model_access_restriction.field_ir_model_access_restriction__model_id
125+
#: model_terms:ir.ui.view,arch_db:model_access_restriction.view_model_access_restrictions_search
126+
msgid "Model"
127+
msgstr "Modelo"
128+
129+
#. module: model_access_restriction
130+
#: model:ir.actions.act_window,name:model_access_restriction.action_model_access_restrictions
131+
#: model:ir.ui.menu,name:model_access_restriction.menu_action_model_access_restrictions
132+
#: model_terms:ir.ui.view,arch_db:model_access_restriction.view_model_access_restrictions_form
133+
#: model_terms:ir.ui.view,arch_db:model_access_restriction.view_model_access_restrictions_search
134+
msgid "Model Access Restrictions"
135+
msgstr "Restricciones de acceso a modelos"
136+
137+
#. module: model_access_restriction
138+
#: model:ir.model,name:model_access_restriction.model_ir_model_access_restriction
139+
msgid "Model Access Restrictions. Not having one will disable access."
140+
msgstr ""
141+
"Restricciones de acceso a modelos. No cumplir una deshabilitará el acceso."
142+
143+
#. module: model_access_restriction
144+
#: model:ir.model.fields,field_description:model_access_restriction.field_ir_model_access_restriction__name
145+
msgid "Name"
146+
msgstr "Nombre"
147+
148+
#. module: model_access_restriction
149+
#: model_terms:ir.ui.view,arch_db:model_access_restriction.view_model_access_restrictions_form
150+
msgid ""
151+
"Normal access records give permissions. Access restriction records removes "
152+
"permissions, if a user does not have one group of a resctriction the access "
153+
"will be forbidden."
154+
msgstr ""
155+
"Los registros de acceso normales otorgan permisos. Los registros de "
156+
"restricción de acceso los eliminan. Si un usuario no tiene un grupo de "
157+
"restricción, se le prohibirá el acceso."
158+
159+
#. module: model_access_restriction
160+
#: code:addons/model_access_restriction/models/ir_model_access_restriction.py:0
161+
#, python-format
162+
msgid "Restrictions must have at least one group"
163+
msgstr "Las restricciones deben tener al menos un grupo"
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
2+
3+
from . import ir_model_access_restriction
4+
from . import models
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# Copyright 2025 Alberto Martínez <[email protected]>
2+
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
3+
4+
from odoo import _, api, exceptions, fields, models
5+
6+
7+
class IrModelAccessRestriction(models.Model):
8+
_name = "ir.model.access.restriction"
9+
_description = "Model Access Restrictions. Not having one will disable access."
10+
11+
_order = "model_id,name,id"
12+
13+
name = fields.Char(index=True)
14+
active = fields.Boolean(
15+
default=True,
16+
)
17+
model_id = fields.Many2one(
18+
string="Model",
19+
comodel_name="ir.model",
20+
index=True,
21+
required=True,
22+
ondelete="cascade",
23+
)
24+
groups = fields.Many2many(
25+
string="Allowed Groups",
26+
comodel_name="res.groups",
27+
relation="model_access_restriction_group_rel",
28+
column1="model_access_restriction_id",
29+
column2="group_id",
30+
ondelete="restrict",
31+
)
32+
# perm_read = fields.Boolean(string='Apply for Read', default=True)
33+
# perm_write = fields.Boolean(string='Apply for Write', default=True)
34+
perm_create = fields.Boolean(string="Apply for Create", default=True)
35+
perm_unlink = fields.Boolean(string="Apply for Delete", default=True)
36+
37+
def _get_model_restrictions(self, model, operation):
38+
query = """ SELECT r.id
39+
FROM ir_model_access_restriction r JOIN ir_model m ON (r.model_id=m.id)
40+
WHERE m.model=%s AND r.active AND r.perm_{operation}
41+
ORDER BY r.id
42+
""".format(
43+
operation=operation
44+
)
45+
self._cr.execute(query, (model,))
46+
return self.browse(row[0] for row in self._cr.fetchall()).exists()
47+
48+
def _get_passed_restrictions(self, model, operation):
49+
query = """ SELECT r.id
50+
FROM ir_model_access_restriction r
51+
JOIN ir_model m ON (r.model_id=m.id)
52+
WHERE m.model=%s AND r.active AND r.perm_{operation}
53+
AND (r.id IN (
54+
SELECT model_access_restriction_id
55+
FROM model_access_restriction_group_rel rg
56+
JOIN res_groups_users_rel gu ON (rg.group_id=gu.gid)
57+
WHERE gu.uid=%s)
58+
)
59+
ORDER BY r.id
60+
""".format(
61+
operation=operation
62+
)
63+
self._cr.execute(query, (model, self._uid))
64+
return self.browse(row[0] for row in self._cr.fetchall()).exists()
65+
66+
def check_restrictions(self, model, operation):
67+
if operation not in ["create", "unlink"]:
68+
return True
69+
model_restrictions = self._get_model_restrictions(model, operation)
70+
return not model_restrictions or not (
71+
model_restrictions - self._get_passed_restrictions(model, operation)
72+
)
73+
74+
@api.constrains("groups")
75+
def _check_groups(self):
76+
for rec in self:
77+
if not any(rec.groups):
78+
raise exceptions.ValidationError(
79+
_("Restrictions must have at least one group")
80+
)
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Copyright 2025 Alberto Martínez <[email protected]>
2+
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
3+
4+
from odoo import api, models
5+
6+
7+
class Base(models.AbstractModel):
8+
_inherit = "base"
9+
10+
@api.model
11+
def check_access_rights(self, operation, raise_exception=True):
12+
not_access_restrictions = self.env[
13+
"ir.model.access.restriction"
14+
].check_restrictions(self._name, operation)
15+
return not_access_restrictions and super().check_access_rights(
16+
operation, raise_exception
17+
)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
To configure this module, you need to:
2+
3+
- Go to Settings / Technical / Security / Model Access Restrictions
4+
- Create a new access restriction
5+
- Select the model to restrict the access
6+
- Select the operations the rule applies to. If the operation is not selected the restriction won't apply to that operation which means users will access the model as always.
7+
- Select the groups that will have access to the model. The rest of groups will have the access disabled.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
- Alberto Martínez <[email protected]>
2+
- Manuel Regidor <[email protected]>
3+
- Valentin Vinagre <[email protected]>
4+
- Harald Panten <[email protected]>

0 commit comments

Comments
 (0)