diff --git a/base_model_restrict_update/models/ir_model_access.py b/base_model_restrict_update/models/ir_model_access.py index e5da3aa46..8ba3bb5a8 100644 --- a/base_model_restrict_update/models/ir_model_access.py +++ b/base_model_restrict_update/models/ir_model_access.py @@ -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") + ) diff --git a/base_model_restrict_update/models/res_users.py b/base_model_restrict_update/models/res_users.py index 0c3ce733d..e3bfc2cb3 100644 --- a/base_model_restrict_update/models/res_users.py +++ b/base_model_restrict_update/models/res_users.py @@ -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 diff --git a/base_model_restrict_update/readme/CONFIGURE.rst b/base_model_restrict_update/readme/CONFIGURE.rst index 5ac08602f..850b0ad86 100644 --- a/base_model_restrict_update/readme/CONFIGURE.rst +++ b/base_model_restrict_update/readme/CONFIGURE.rst @@ -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. diff --git a/base_model_restrict_update/tests/test_base_model_restrict_update.py b/base_model_restrict_update/tests/test_base_model_restrict_update.py index fa3bfd86c..b098c0881 100644 --- a/base_model_restrict_update/tests/test_base_model_restrict_update.py +++ b/base_model_restrict_update/tests/test_base_model_restrict_update.py @@ -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"} + ) diff --git a/base_model_restrict_update/views/res_users_views.xml b/base_model_restrict_update/views/res_users_views.xml index 1d16942ee..aa0f5a1e8 100644 --- a/base_model_restrict_update/views/res_users_views.xml +++ b/base_model_restrict_update/views/res_users_views.xml @@ -12,6 +12,7 @@ type="object" class="oe_stat_button" icon="fa-pencil" + attrs="{'invisible': [('is_readonly_user', '=', True)]}" > +