[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 @api.model
@tools.ormcache_context( @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): def check(self, model, mode="read", raise_exception=True):
if self.env.su: if self.env.su:
return True return True
res = super().check(model, mode, raise_exception) res = super().check(model, mode, raise_exception)
self._cr.execute( if mode != "read" and raise_exception:
"SELECT restrict_update FROM ir_model WHERE model = %s", (model,) if self._test_readonly(model) or self._test_restrict_update(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:
raise AccessError( raise AccessError(
_("You are only allowed to read this record. (%s - %s)") _("You are only allowed to read this record. (%s - %s)")
% (model, mode) % (model, mode)
) )
return False
return res 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 # Copyright 2021 Quartile Limited
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). # 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): class ResUsers(models.Model):
@ -11,7 +12,21 @@ class ResUsers(models.Model):
"Unrestrict Model Update", "Unrestrict Model Update",
help="Set to true and the user can update restricted model.", 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): def toggle_unrestrict_model_update(self):
for record in self: for record in self:
record.unrestrict_model_update = not record.unrestrict_model_update 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. 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): def test_01_create_partner(self):
with self.assertRaises(AccessError): 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"} {"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"} {"name": "Test Partner"}
) )
def test_02_update_partner(self): def test_02_update_partner(self):
with self.assertRaises(AccessError): 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"} {"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"} {"name": "Test Partner 2"}
) )
def test_03_unlink_partner(self): def test_03_unlink_partner(self):
test_partner = self.test_partner.sudo().copy() test_partner = self.test_partner.sudo().copy()
with self.assertRaises(AccessError): with self.assertRaises(AccessError):
test_partner.sudo(self.restrict_test_user.id).unlink() test_partner.with_user(self.restrict_test_user.id).unlink()
test_partner.sudo(self.permit_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" type="object"
class="oe_stat_button" class="oe_stat_button"
icon="fa-pencil" icon="fa-pencil"
attrs="{'invisible': [('is_readonly_user', '=', True)]}"
> >
<field <field
name="unrestrict_model_update" name="unrestrict_model_update"
@ -19,6 +20,18 @@
options='{"terminology": {"string_true": "Update Permit", "string_false": "Unpermitted"}}' options='{"terminology": {"string_true": "Update Permit", "string_false": "Unpermitted"}}'
/> />
</button> </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> </div>
</field> </field>
</record> </record>