Odoo18-Base/odoo/addons/test_access_rights/tests/test_feedback.py
2025-01-06 10:57:38 +07:00

536 lines
21 KiB
Python

# -*- coding: utf-8 -*-
from odoo import SUPERUSER_ID, Command
from odoo.exceptions import AccessError
from odoo.tests import TransactionCase
from odoo.tools.misc import mute_logger
class Feedback(TransactionCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.group0 = cls.env['res.groups'].create({'name': "Group 0"})
cls.group1 = cls.env['res.groups'].create({'name': "Group 1"})
cls.group2 = cls.env['res.groups'].create({'name': "Group 2"})
cls.user = cls.env['res.users'].create({
'login': 'bob',
'name': "Bob Bobman",
'groups_id': [Command.set([cls.group2.id, cls.env.ref('base.group_user').id])],
})
class TestSudo(Feedback):
""" Test the behavior of method sudo(). """
def test_sudo(self):
record = self.env['test_access_right.some_obj'].create({'val': 5})
user1 = self.user
partner_demo = self.env['res.partner'].create({
'name': 'Marc Demo',
})
user2 = self.env['res.users'].create({
'login': 'demo2',
'password': 'demo2',
'partner_id': partner_demo.id,
'groups_id': [Command.set([self.env.ref('base.group_user').id, self.env.ref('base.group_partner_manager').id])],
})
# with_user(user)
record1 = record.with_user(user1)
self.assertEqual(record1.env.uid, user1.id)
self.assertFalse(record1.env.su)
record2 = record1.with_user(user2)
self.assertEqual(record2.env.uid, user2.id)
self.assertFalse(record2.env.su)
# the superuser is always in superuser mode
record3 = record2.with_user(SUPERUSER_ID)
self.assertEqual(record3.env.uid, SUPERUSER_ID)
self.assertTrue(record3.env.su)
# sudo()
surecord1 = record1.sudo()
self.assertEqual(surecord1.env.uid, user1.id)
self.assertTrue(surecord1.env.su)
surecord2 = record2.sudo()
self.assertEqual(surecord2.env.uid, user2.id)
self.assertTrue(surecord2.env.su)
surecord3 = record3.sudo()
self.assertEqual(surecord3.env.uid, SUPERUSER_ID)
self.assertTrue(surecord3.env.su)
# sudo().sudo()
surecord1 = surecord1.sudo()
self.assertEqual(surecord1.env.uid, user1.id)
self.assertTrue(surecord1.env.su)
# sudo(False)
record1 = surecord1.sudo(False)
self.assertEqual(record1.env.uid, user1.id)
self.assertFalse(record1.env.su)
record2 = surecord2.sudo(False)
self.assertEqual(record2.env.uid, user2.id)
self.assertFalse(record2.env.su)
record3 = surecord3.sudo(False)
self.assertEqual(record3.env.uid, SUPERUSER_ID)
self.assertTrue(record3.env.su)
# sudo().with_user(user)
record2 = surecord1.with_user(user2)
self.assertEqual(record2.env.uid, user2.id)
self.assertFalse(record2.env.su)
class TestACLFeedback(Feedback):
""" Tests that proper feedback is returned on ir.model.access errors
"""
@classmethod
def setUpClass(cls):
super().setUpClass()
ACL = cls.env['ir.model.access']
m = cls.env['ir.model'].search([('model', '=', 'test_access_right.some_obj')])
ACL.search([('model_id', '=', m.id)]).unlink()
ACL.create({
'name': "read",
'model_id': m.id,
'group_id': cls.group1.id,
'perm_read': True,
})
ACL.create({
'name': "create-and-read",
'model_id': m.id,
'group_id': cls.group0.id,
'perm_read': True,
'perm_create': True,
})
cls.record = cls.env['test_access_right.some_obj'].create({'val': 5})
# values are in cache, clear them up for the test
cls.env.flush_all()
cls.env.invalidate_all()
def test_no_groups(self):
""" Operation is never allowed
"""
with self.assertRaises(AccessError) as ctx:
self.record.with_user(self.user).write({'val': 10})
self.assertEqual(
ctx.exception.args[0],
"""You are not allowed to modify 'Object For Test Access Right' (test_access_right.some_obj) records.
No group currently allows this operation.
Contact your administrator to request access if necessary."""
)
def test_one_group(self):
with self.assertRaises(AccessError) as ctx:
self.env(user=self.user)['test_access_right.some_obj'].create({
'val': 1
})
self.assertEqual(
ctx.exception.args[0],
"""You are not allowed to create 'Object For Test Access Right' (test_access_right.some_obj) records.
This operation is allowed for the following groups:\n\t- Group 0
Contact your administrator to request access if necessary."""
)
def test_two_groups(self):
r = self.record.with_user(self.user)
expected = """You are not allowed to access 'Object For Test Access Right' (test_access_right.some_obj) records.
This operation is allowed for the following groups:\n\t- Group 0\n\t- Group 1
Contact your administrator to request access if necessary."""
with self.assertRaises(AccessError) as ctx:
# noinspection PyStatementEffect
r.val
self.assertEqual(ctx.exception.args[0], expected)
with self.assertRaises(AccessError) as ctx:
r.read(['val'])
self.assertEqual(ctx.exception.args[0], expected)
class TestIRRuleFeedback(Feedback):
""" Tests that proper feedback is returned on ir.rule errors
"""
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.env.ref('base.group_user').write({'users': [Command.link(cls.user.id)]})
cls.model = cls.env['ir.model'].search([('model', '=', 'test_access_right.some_obj')])
cls.record = cls.env['test_access_right.some_obj'].create({
'val': 0,
}).with_user(cls.user)
cls.maxDiff = None
def _make_rule(self, name, domain, global_=False, attr='write'):
res = self.env['ir.rule'].create({
'name': name,
'model_id': self.model.id,
'groups': [] if global_ else [Command.link(self.group2.id)],
'domain_force': domain,
'perm_read': False,
'perm_write': False,
'perm_create': False,
'perm_unlink': False,
'perm_' + attr: True,
})
return res
def test_local(self):
self._make_rule('rule 0', '[("val", "=", 42)]')
with self.assertRaises(AccessError) as ctx:
self.record.write({'val': 1})
self.assertEqual(
ctx.exception.args[0],
"""Uh-oh! Looks like you have stumbled upon some top-secret records.
Sorry, %s (id=%s) doesn't have 'write' access to:
- %s (%s)
If you really, really need access, perhaps you can win over your friendly administrator with a batch of freshly baked cookies."""
% (self.user.name, self.user.id, self.record._description, self.record._name))
# debug mode
with self.debug_mode(), self.assertRaises(AccessError) as ctx:
self.record.write({'val': 1})
self.assertEqual(
ctx.exception.args[0],
"""Uh-oh! Looks like you have stumbled upon some top-secret records.
Sorry, %s (id=%s) doesn't have 'write' access to:
- %s, %s (%s: %s)
Blame the following rules:
- rule 0
If you really, really need access, perhaps you can win over your friendly administrator with a batch of freshly baked cookies."""
% (self.user.name, self.user.id, self.record._description, self.record.display_name, self.record._name, self.record.id))
ChildModel = self.env['test_access_right.inherits']
with self.debug_mode(), self.assertRaises(AccessError) as ctx:
ChildModel.with_user(self.user).create({'some_id': self.record.id, 'val': 2})
self.assertEqual(
ctx.exception.args[0],
"""Uh-oh! Looks like you have stumbled upon some top-secret records.
Sorry, %s (id=%s) doesn't have 'write' access to:
- %s, %s (%s: %s)
Blame the following rules:
- rule 0
If you really, really need access, perhaps you can win over your friendly administrator with a batch of freshly baked cookies."""
% (self.user.name, self.user.id, self.record._description, self.record.display_name, self.record._name, self.record.id))
def test_locals(self):
self._make_rule('rule 0', '[("val", "=", 42)]')
self._make_rule('rule 1', '[("val", "=", 78)]')
with self.debug_mode(), self.assertRaises(AccessError) as ctx:
self.record.write({'val': 1})
self.assertEqual(
ctx.exception.args[0],
"""Uh-oh! Looks like you have stumbled upon some top-secret records.
Sorry, %s (id=%s) doesn't have 'write' access to:
- %s, %s (%s: %s)
Blame the following rules:
- rule 0
- rule 1
If you really, really need access, perhaps you can win over your friendly administrator with a batch of freshly baked cookies."""
% (self.user.name, self.user.id, self.record._description, self.record.display_name, self.record._name, self.record.id))
def test_globals_all(self):
self._make_rule('rule 0', '[("val", "=", 42)]', global_=True)
self._make_rule('rule 1', '[("val", "=", 78)]', global_=True)
with self.debug_mode(), self.assertRaises(AccessError) as ctx:
self.record.write({'val': 1})
self.assertEqual(
ctx.exception.args[0],
"""Uh-oh! Looks like you have stumbled upon some top-secret records.
Sorry, %s (id=%s) doesn't have 'write' access to:
- %s, %s (%s: %s)
Blame the following rules:
- rule 0
- rule 1
If you really, really need access, perhaps you can win over your friendly administrator with a batch of freshly baked cookies."""
% (self.user.name, self.user.id, self.record._description, self.record.display_name, self.record._name, self.record.id))
def test_globals_any(self):
""" Global rules are AND-eded together, so when an access fails it
might be just one of the rules, and we want an exact listing
"""
self._make_rule('rule 0', '[("val", "=", 42)]', global_=True)
self._make_rule('rule 1', '[(1, "=", 1)]', global_=True)
with self.debug_mode(), self.assertRaises(AccessError) as ctx:
self.record.write({'val': 1})
self.assertEqual(
ctx.exception.args[0],
"""Uh-oh! Looks like you have stumbled upon some top-secret records.
Sorry, %s (id=%s) doesn't have 'write' access to:
- %s, %s (%s: %s)
Blame the following rules:
- rule 0
If you really, really need access, perhaps you can win over your friendly administrator with a batch of freshly baked cookies."""
% (self.user.name, self.user.id, self.record._description, self.record.display_name, self.record._name, self.record.id))
def test_combination(self):
self._make_rule('rule 0', '[("val", "=", 42)]', global_=True)
self._make_rule('rule 1', '[(1, "=", 1)]', global_=True)
self._make_rule('rule 2', '[(0, "=", 1)]')
self._make_rule('rule 3', '[("val", "=", 55)]')
with self.debug_mode(), self.assertRaises(AccessError) as ctx:
self.record.write({'val': 1})
self.assertEqual(
ctx.exception.args[0],
"""Uh-oh! Looks like you have stumbled upon some top-secret records.
Sorry, %s (id=%s) doesn't have 'write' access to:
- %s, %s (%s: %s)
Blame the following rules:
- rule 0
- rule 2
- rule 3
If you really, really need access, perhaps you can win over your friendly administrator with a batch of freshly baked cookies."""
% (self.user.name, self.user.id, self.record._description, self.record.display_name, self.record._name, self.record.id))
def test_warn_company_no_access(self):
""" If one of the failing rules mentions company_id, add a note that
this might be a multi-company issue, but the user doesn't access to this company
then no information about the company is showed.
"""
self._make_rule('rule 0', "[('company_id', '=', user.company_id.id)]")
self._make_rule('rule 1', '[("val", "=", 0)]', global_=True)
with self.debug_mode(), self.assertRaises(AccessError) as ctx:
self.record.write({'val': 1})
self.assertEqual(
ctx.exception.args[0],
"""Uh-oh! Looks like you have stumbled upon some top-secret records.
Sorry, %s (id=%s) doesn't have 'write' access to:
- %s, %s (%s: %s)
Blame the following rules:
- rule 0
If you really, really need access, perhaps you can win over your friendly administrator with a batch of freshly baked cookies."""
% (self.user.name, self.user.id, self.record._description, self.record.display_name, self.record._name, self.record.id))
def test_warn_company_no_company_field(self):
""" If one of the failing rules mentions company_id, add a note that
this might be a multi-company issue, but the record doesn't have company_id field
then no information about the company is showed.
"""
ChildModel = self.env['test_access_right.child'].sudo()
self.env['ir.rule'].create({
'name': 'rule 0',
'model_id': self.env['ir.model'].search([('model', '=', ChildModel._name)]).id,
'groups': [],
'domain_force': '[("parent_id.company_id", "=", user.company_id.id)]',
'perm_read': True,
})
self.record.sudo().company_id = self.env['res.company'].create({'name': 'Brosse Inc.'})
self.user.sudo().company_ids = [Command.link(self.record.company_id.id)]
child_record = ChildModel.create({'parent_id': self.record.id}).with_user(self.user)
with self.debug_mode(), self.assertRaises(AccessError) as ctx:
_ = child_record.parent_id
self.assertEqual(
ctx.exception.args[0],
"""Uh-oh! Looks like you have stumbled upon some top-secret records.
Sorry, %s (id=%s) doesn't have 'read' access to:
- %s, %s (%s: %s)
Blame the following rules:
- rule 0
If you really, really need access, perhaps you can win over your friendly administrator with a batch of freshly baked cookies."""
% (self.user.name, self.user.id, child_record._description, child_record.display_name, child_record._name, child_record.id))
def test_warn_company_access(self):
""" because of prefetching, read() goes through a different codepath
to apply rules
"""
self.record.sudo().company_id = self.env['res.company'].create({'name': 'Brosse Inc.'})
self.user.sudo().company_ids = [Command.link(self.record.company_id.id)]
self._make_rule('rule 0', "[('company_id', '=', user.company_id.id)]", attr='read')
with self.debug_mode(), self.assertRaises(AccessError) as ctx:
_ = self.record.val
self.assertEqual(
ctx.exception.args[0],
"""Uh-oh! Looks like you have stumbled upon some top-secret records.
Sorry, %s (id=%s) doesn't have 'read' access to:
- %s, %s (%s: %s, company=%s)
Blame the following rules:
- rule 0
If you really, really need access, perhaps you can win over your friendly administrator with a batch of freshly baked cookies.
This seems to be a multi-company issue, you might be able to access the record by switching to the company: %s."""
% (self.user.name, self.user.id, self.record._description, self.record.display_name, self.record._name, self.record.id, self.record.sudo().company_id.display_name, self.record.sudo().company_id.display_name))
p = self.env['test_access_right.inherits'].create({'some_id': self.record.id})
self.env.flush_all()
self.env.invalidate_all()
with self.assertRaisesRegex(
AccessError,
r"Implicitly accessed through 'Object for testing related access rights' \(test_access_right.inherits\)\.",
):
p.with_user(self.user).val
def test_warn_company_access_multi_record(self):
""" Test that AccessError handle correctly several companies """
company_1, company_2 = self.env['res.company'].create([
{'name': 'Brosse Inc.'},
{'name': 'Brosse Inc. 2'},
])
records = self.env["test_access_right.some_obj"].create([
{"val": 1, "company_id": company_1.id},
{"val": 2, "company_id": company_2.id},
])
record_1, record_2 = records
self.user.sudo().company_ids = [Command.link(company_1.id), Command.link(company_2.id)]
self._make_rule('rule 0', "[('company_id', '=', False)]", attr='read')
self.env.invalidate_all()
with self.debug_mode(), self.assertRaises(AccessError) as ctx:
_ = records.with_user(self.user).read(["val"])
self.assertEqual(
ctx.exception.args[0],
f"""Uh-oh! Looks like you have stumbled upon some top-secret records.
Sorry, {self.user.name} (id={self.user.id}) doesn't have 'read' access to:
- {record_1._description}, {record_1.display_name} ({record_1._name}: {record_1.id}, company={record_1.company_id.display_name})
- {record_2._description}, {record_2.display_name} ({record_2._name}: {record_2.id}, company={record_2.company_id.display_name})
Blame the following rules:
- rule 0
If you really, really need access, perhaps you can win over your friendly administrator with a batch of freshly baked cookies.
Note: this might be a multi-company issue. Switching company may help - in Odoo, not in real life!""")
class TestFieldGroupFeedback(Feedback):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.record = cls.env['test_access_right.some_obj'].create({
'val': 0,
}).with_user(cls.user)
cls.inherits_record = cls.env['test_access_right.inherits'].create({
'some_id': cls.record.id,
}).with_user(cls.user)
@mute_logger('odoo.models')
def test_read(self):
self.user.write({
'groups_id': [Command.set([self.env.ref('base.group_user').id])],
})
with self.debug_mode(), self.assertRaises(AccessError) as ctx:
_ = self.record.forbidden
self.assertEqual(
ctx.exception.args[0],
"""You do not have enough rights to access the fields "forbidden" on Object For Test Access Right (test_access_right.some_obj). Please contact your system administrator.
Operation: read
User: %s
Fields:
- forbidden (allowed for groups 'User types / Portal', 'Test Group')"""
% self.user.id
)
with self.debug_mode(), self.assertRaises(AccessError) as ctx:
_ = self.record.forbidden3
self.assertEqual(
ctx.exception.args[0],
"""You do not have enough rights to access the fields "forbidden3" on Object For Test Access Right (test_access_right.some_obj). Please contact your system administrator.
Operation: read
User: %s
Fields:
- forbidden3 (always forbidden)""" % self.user.id
)
@mute_logger('odoo.models')
def test_write(self):
self.user.write({
'groups_id': [Command.set([self.env.ref('base.group_user').id])],
})
with self.debug_mode(), self.assertRaises(AccessError) as ctx:
self.record.write({'forbidden': 1, 'forbidden2': 2})
self.assertEqual(
ctx.exception.args[0],
"""You do not have enough rights to access the fields "forbidden,forbidden2" on Object For Test Access Right (test_access_right.some_obj). Please contact your system administrator.
Operation: write
User: %s
Fields:
- forbidden (allowed for groups 'User types / Portal', 'Test Group')
- forbidden2 (allowed for groups 'Test Group')"""
% self.user.id
)
@mute_logger('odoo.models')
def test_check_field_access_rights_domain(self):
with self.assertRaises(AccessError):
self.record.search([('forbidden3', '=', 58)])
with self.assertRaises(AccessError):
self.record.search([('parent_id.forbidden3', '=', 58)])
with self.assertRaises(AccessError):
self.record.search([('parent_id', 'any', [('forbidden3', '=', 58)])])
with self.assertRaises(AccessError):
self.inherits_record.search([('forbidden3', '=', 58)])
@mute_logger('odoo.models')
def test_check_field_access_rights_order(self):
self.record.search([], order='val')
with self.assertRaises(AccessError):
self.record.search([], order='forbidden3 DESC')
with self.assertRaises(AccessError):
self.record.search([], order='forbidden3')
with self.assertRaises(AccessError):
self.record.search([], order='val DESC, forbidden3 DESC')
@mute_logger('odoo.models')
def test_check_field_access_rights_read_group(self):
self.record._read_group([], ['val'], [])
with self.assertRaises(AccessError):
self.record._read_group([('forbidden3', '=', 58)], ['val'])
with self.assertRaises(AccessError):
self.record._read_group([('parent_id.forbidden3', '=', 58)], ['val'])
with self.assertRaises(AccessError):
self.record._read_group([], ['forbidden3'])
with self.assertRaises(AccessError):
self.record._read_group([], [], ['forbidden3:array_agg'])