[ENH] Add option 'Readonly User' to all models
parent
b70360140d
commit
caf810e0ee
|
@ -11,25 +11,56 @@ class IrModelAccess(models.Model):
|
|||
|
||||
@api.model
|
||||
@tools.ormcache_context(
|
||||
"self._uid", "model", "mode", "raise_exception", keys=("lang",)
|
||||
"self.env.uid",
|
||||
"self.env.su",
|
||||
"model",
|
||||
"mode",
|
||||
"raise_exception",
|
||||
keys=("lang",),
|
||||
)
|
||||
def check(self, model, mode="read", raise_exception=True):
|
||||
if self.env.su:
|
||||
return True
|
||||
res = super().check(model, mode, raise_exception)
|
||||
self._cr.execute(
|
||||
"SELECT restrict_update FROM ir_model WHERE model = %s", (model,)
|
||||
)
|
||||
query_res = self._cr.dictfetchone()
|
||||
if (
|
||||
query_res["restrict_update"]
|
||||
and mode != "read"
|
||||
and not self.env.user.unrestrict_model_update
|
||||
):
|
||||
if raise_exception:
|
||||
if mode != "read" and raise_exception:
|
||||
if self._test_readonly(model) or self._test_restrict_update(model):
|
||||
raise AccessError(
|
||||
_("You are only allowed to read this record. (%s - %s)")
|
||||
% (model, mode)
|
||||
)
|
||||
return False
|
||||
return res
|
||||
|
||||
@api.model
|
||||
def _test_readonly(self, model):
|
||||
exclude_models = self._readonly_exclude_models()
|
||||
if model not in exclude_models and self.env.user.is_readonly_user:
|
||||
return True
|
||||
return False
|
||||
|
||||
@api.model
|
||||
def _test_restrict_update(self, model):
|
||||
self.env.cr.execute(
|
||||
"SELECT restrict_update FROM ir_model WHERE model = %s", (model,)
|
||||
)
|
||||
query_res = self.env.cr.dictfetchone()
|
||||
if query_res["restrict_update"] and not self.env.user.unrestrict_model_update:
|
||||
return True
|
||||
return False
|
||||
|
||||
@api.model
|
||||
def _readonly_exclude_models(self):
|
||||
""" Models updtate/create by system, and should be excluded from checking """
|
||||
return (
|
||||
self.sudo()
|
||||
.search(
|
||||
[
|
||||
("group_id", "=", False),
|
||||
"|",
|
||||
("perm_write", "=", True),
|
||||
"|",
|
||||
("perm_create", "=", True),
|
||||
("perm_unlink", "=", True),
|
||||
]
|
||||
)
|
||||
.mapped("model_id.model")
|
||||
)
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
# Copyright 2021 Quartile Limited
|
||||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).
|
||||
|
||||
from odoo import fields, models
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
|
||||
class ResUsers(models.Model):
|
||||
|
@ -11,7 +12,21 @@ class ResUsers(models.Model):
|
|||
"Unrestrict Model Update",
|
||||
help="Set to true and the user can update restricted model.",
|
||||
)
|
||||
is_readonly_user = fields.Boolean(
|
||||
"Ready User",
|
||||
help="Set to true and the user are readonly user on all models",
|
||||
)
|
||||
|
||||
@api.constrains("is_readonly_user")
|
||||
def _check_is_readonly_user(self):
|
||||
for user in self:
|
||||
if self.env.ref("base.group_system") in user.groups_id:
|
||||
raise UserError(_("You cannot set admin user as a readonly user."))
|
||||
|
||||
def toggle_unrestrict_model_update(self):
|
||||
for record in self:
|
||||
record.unrestrict_model_update = not record.unrestrict_model_update
|
||||
|
||||
def toggle_is_readonly_user(self):
|
||||
for record in self:
|
||||
record.is_readonly_user = not record.is_readonly_user
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
Enable the "Update Restrict Model" of specific model to restrict update from unpermitted users.
|
||||
To set an user as a permitted user to update restricted model(s), click on "Grant Update Permit" in user form.
|
||||
To set a user as a permitted user to update restricted model(s), click on "Grant Update Permit" in user form.
|
||||
Optionally, to set a user as readonly user to all models, click on "Readonly User" in user form.
|
||||
|
|
|
@ -33,24 +33,32 @@ class TestBaseModelRestrictUpdate(SavepointCase):
|
|||
|
||||
def test_01_create_partner(self):
|
||||
with self.assertRaises(AccessError):
|
||||
self.env["res.partner"].sudo(self.restrict_test_user.id).create(
|
||||
self.env["res.partner"].with_user(self.restrict_test_user.id).create(
|
||||
{"name": "Test Partner"}
|
||||
)
|
||||
self.env["res.partner"].sudo(self.permit_test_user.id).create(
|
||||
self.env["res.partner"].with_user(self.permit_test_user.id).create(
|
||||
{"name": "Test Partner"}
|
||||
)
|
||||
|
||||
def test_02_update_partner(self):
|
||||
with self.assertRaises(AccessError):
|
||||
self.test_partner.sudo(self.restrict_test_user.id).update(
|
||||
self.test_partner.with_user(self.restrict_test_user.id).update(
|
||||
{"name": "Test Partner 2"}
|
||||
)
|
||||
self.test_partner.sudo(self.permit_test_user.id).update(
|
||||
self.test_partner.with_user(self.permit_test_user.id).update(
|
||||
{"name": "Test Partner 2"}
|
||||
)
|
||||
|
||||
def test_03_unlink_partner(self):
|
||||
test_partner = self.test_partner.sudo().copy()
|
||||
with self.assertRaises(AccessError):
|
||||
test_partner.sudo(self.restrict_test_user.id).unlink()
|
||||
test_partner.sudo(self.permit_test_user.id).unlink()
|
||||
test_partner.with_user(self.restrict_test_user.id).unlink()
|
||||
test_partner.with_user(self.permit_test_user.id).unlink()
|
||||
|
||||
def test_04_readonly_user_update_partner(self):
|
||||
self.permit_test_user.toggle_is_readonly_user()
|
||||
self.assertTrue(self.permit_test_user.is_readonly_user)
|
||||
with self.assertRaises(AccessError):
|
||||
self.test_partner.with_user(self.permit_test_user.id).update(
|
||||
{"name": "Test Partner 2"}
|
||||
)
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
type="object"
|
||||
class="oe_stat_button"
|
||||
icon="fa-pencil"
|
||||
attrs="{'invisible': [('is_readonly_user', '=', True)]}"
|
||||
>
|
||||
<field
|
||||
name="unrestrict_model_update"
|
||||
|
@ -19,6 +20,18 @@
|
|||
options='{"terminology": {"string_true": "Update Permit", "string_false": "Unpermitted"}}'
|
||||
/>
|
||||
</button>
|
||||
<button
|
||||
name="toggle_is_readonly_user"
|
||||
type="object"
|
||||
class="oe_stat_button"
|
||||
icon="fa-ban"
|
||||
>
|
||||
<field
|
||||
name="is_readonly_user"
|
||||
widget="boolean_button"
|
||||
options='{"terminology": {"string_false": "Editable", "string_true": "Readonly"}}'
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</field>
|
||||
</record>
|
||||
|
|
Loading…
Reference in New Issue