[FIX] ir_rule: invalid user context propagation
Create two models, `object` and `category`. The object have a Many2One to the category. Override the `search` on the category so it returns a subset of the records if a context key is present. Create an IR Rule on object with the following pseudo-domain: `categ_id in category.search([])`. Search on object with the context key present. Even if the context should only be applied to category, it is applied to object too thus there are some object missing. When evaluating the domain of IR Rules, the current user is propagated with the current environment context. API calls triggered by the domain are called with the given context, possibly populating the cache with different records than it would normally does without the context (i.e. at `addons/point_of_sale/models/account_journal.py#L19-L23`). Following requests do use that invalid cache thus return invalid results. Forcing an empty context on the user used during the evaluation of the context ensures the IR Rules are working as they should and is future-proof (cf `load_company` v13 context key) opw-2041667 closes #35123 closes #35125 closes odoo/odoo#35667 Signed-off-by: Julien Castiaux <Julien00859@users.noreply.github.com> Co-authored-by: Hugo Adan <hugo@vauxoo.com>
This commit is contained in:
co-authored by
Hugo Adan
parent
0458337bc3
commit
855447fc77
@@ -42,7 +42,9 @@ class IrRule(models.Model):
|
||||
def _eval_context(self):
|
||||
"""Returns a dictionary to use as evaluation context for
|
||||
ir.rule domains."""
|
||||
return {'user': self.env.user, 'time': time}
|
||||
# use an empty context for 'user' to make the domain evaluation
|
||||
# independent from the context
|
||||
return {'user': self.env.user.with_context({}), 'time': time}
|
||||
|
||||
@api.depends('groups')
|
||||
def _compute_global(self):
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_test_access_right_some_obj,access_test_access_right_some_obj,model_test_access_right_some_obj,,1,1,1,1
|
||||
access_test_access_right_container,access_test_access_right_container,model_test_access_right_container,,1,1,1,1
|
||||
access_test_access_right_obj_categ,access_test_access_right_obj_categ,model_test_access_right_obj_categ,,1,1,1,1
|
||||
|
||||
|
@@ -7,9 +7,21 @@ class SomeObj(models.Model):
|
||||
_name = 'test_access_right.some_obj'
|
||||
|
||||
val = fields.Integer()
|
||||
categ_id = fields.Many2one('test_access_right.obj_categ')
|
||||
|
||||
|
||||
class Container(models.Model):
|
||||
_name = 'test_access_right.container'
|
||||
|
||||
some_ids = fields.Many2many('test_access_right.some_obj', 'test_access_right_rel', 'container_id', 'some_id')
|
||||
|
||||
|
||||
class ObjCateg(models.Model):
|
||||
_name = 'test_access_right.obj_categ'
|
||||
|
||||
name = fields.Char(required=True)
|
||||
|
||||
def search(self, args, **kwargs):
|
||||
if self.env.context.get('only_media'):
|
||||
args += [('name', '=', 'Media')]
|
||||
return super(ObjCateg, self).search(args, **kwargs)
|
||||
|
||||
@@ -8,10 +8,11 @@ class TestRules(TransactionCase):
|
||||
def setUp(self):
|
||||
super(TestRules, self).setUp()
|
||||
|
||||
self.id1 = self.env['test_access_right.some_obj']\
|
||||
.create({'val': 1}).id
|
||||
self.id2 = self.env['test_access_right.some_obj']\
|
||||
.create({'val': -1}).id
|
||||
ObjCateg = self.env['test_access_right.obj_categ']
|
||||
SomeObj = self.env['test_access_right.some_obj']
|
||||
self.categ1 = ObjCateg.create({'name': 'Food'}).id
|
||||
self.id1 = SomeObj.create({'val': 1, 'categ_id': self.categ1}).id
|
||||
self.id2 = SomeObj.create({'val': -1, 'categ_id': self.categ1}).id
|
||||
# create a global rule forbidding access to records with a negative
|
||||
# (or zero) val
|
||||
self.env['ir.rule'].create({
|
||||
@@ -19,6 +20,13 @@ class TestRules(TransactionCase):
|
||||
'model_id': self.browse_ref('test_access_rights.model_test_access_right_some_obj').id,
|
||||
'domain_force': "[('val', '>', 0)]"
|
||||
})
|
||||
# create a global rule that forbid access to records without
|
||||
# categories, the search is part of the test
|
||||
self.env['ir.rule'].create({
|
||||
'name': 'See all categories',
|
||||
'model_id': self.browse_ref('test_access_rights.model_test_access_right_some_obj').id,
|
||||
'domain_force': "[('categ_id', 'in', user.env['test_access_right.obj_categ'].search([]).ids)]"
|
||||
})
|
||||
|
||||
def test_basic_access(self):
|
||||
env = self.env(user=self.browse_ref('base.public_user'))
|
||||
@@ -56,3 +64,25 @@ class TestRules(TransactionCase):
|
||||
container_user.write({'some_ids': [(5,)]})
|
||||
self.assertItemsEqual(container_user.some_ids.ids, [])
|
||||
self.assertItemsEqual(container_admin.some_ids.ids, [self.id2])
|
||||
|
||||
def test_no_context_in_ir_rules(self):
|
||||
""" The context should not impact the ir rules. """
|
||||
env = self.env(user=self.browse_ref('base.public_user'))
|
||||
ObjCateg = self.env['test_access_right.obj_categ']
|
||||
SomeObj = self.env['test_access_right.some_obj']
|
||||
|
||||
# validate the effect of context on category search, there are
|
||||
# no existing media category
|
||||
self.assertTrue(ObjCateg.search([]))
|
||||
self.assertFalse(ObjCateg.with_context(only_media=True).search([]))
|
||||
|
||||
# record1 is food and is accessible with an empy context
|
||||
ObjCateg.clear_caches()
|
||||
records = SomeObj.search([('id', '=', self.id1)])
|
||||
self.assertTrue(records)
|
||||
|
||||
# it should also be accessible as the context is not used when
|
||||
# searching for SomeObjs
|
||||
ObjCateg.clear_caches()
|
||||
records = SomeObj.with_context(only_media=True).search([('id', '=', self.id1)])
|
||||
self.assertTrue(records)
|
||||
|
||||
Reference in New Issue
Block a user