[ENH] Add option 'Readonly User' to all models

pull/2620/head
Kitti U 2021-09-05 14:30:09 +07:00 committed by Saran440
parent b70360140d
commit caf810e0ee
5 changed files with 88 additions and 20 deletions

View File

@ -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")
)

View File

@ -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

View File

@ -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.

View File

@ -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"}
)

View File

@ -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>