From b2392011900825bbc0d4d5e2456cd669595e2565 Mon Sep 17 00:00:00 2001 From: Nicolas Lempereur Date: Fri, 27 Dec 2019 16:34:37 +0000 Subject: [PATCH] [FIX] *: avoid muting res.users().context_get return Some code modify return of res.users().context_get, but this is a cached method so this will unexpectedly affects totally unrelated code. For example, changing the company with the company switcher could add `allowed_company_ids` inside the cache, then it will be cached until the server is restarted, even if we change company again inbetween. Added test failed with: "NotImplementedError: '__setitem__' not supported on frozendict" on the line with `User = User.with_context(context)` where User already contained `allowed_company_ids` in its context. note: in this forward-port, context_get is also changed to return frozendict and prevent being able to have an unexpected issue by code that modify context_get returns. opw-2158340 closes #42465 closes odoo/odoo#42723 X-original-commit: 5d69885c1cd6921b3de00aae7e0ed6fff243ff95 Signed-off-by: Nicolas Lempereur (nle) --- odoo/addons/base/models/res_users.py | 6 ++--- .../test_new_api/tests/test_company_checks.py | 24 +++++++++++++++++++ odoo/http.py | 2 +- odoo/tests/common.py | 2 +- 4 files changed, 29 insertions(+), 5 deletions(-) diff --git a/odoo/addons/base/models/res_users.py b/odoo/addons/base/models/res_users.py index 0eefb630525..718a62c12aa 100644 --- a/odoo/addons/base/models/res_users.py +++ b/odoo/addons/base/models/res_users.py @@ -21,7 +21,7 @@ from odoo.exceptions import AccessDenied, AccessError, UserError, ValidationErro from odoo.http import request from odoo.osv import expression from odoo.service.db import check_super -from odoo.tools import partition, collections, lazy_property +from odoo.tools import partition, collections, frozendict, lazy_property _logger = logging.getLogger(__name__) @@ -577,10 +577,10 @@ class Users(models.Model): # use read() to not read other fields: this must work while modifying # the schema of models res.users or res.partner values = user.read(list(name_to_key), load=False)[0] - return { + return frozendict({ key: values[name] for name, key in name_to_key.items() - } + }) @api.model def action_get(self): diff --git a/odoo/addons/test_new_api/tests/test_company_checks.py b/odoo/addons/test_new_api/tests/test_company_checks.py index 04b1df46846..5b391a3578f 100644 --- a/odoo/addons/test_new_api/tests/test_company_checks.py +++ b/odoo/addons/test_new_api/tests/test_company_checks.py @@ -2,6 +2,7 @@ from odoo.exceptions import UserError, AccessError from odoo.tests import common +from odoo.tools import frozendict class TestCompanyCheck(common.TransactionCase): @@ -192,3 +193,26 @@ class TestCompanyCheck(common.TransactionCase): with self.assertRaises(AccessError): form.address_id.name form.save() + + def test_company_sticky_with_context(self): + context = frozendict({'nothing_to_see_here': True}) + companies_1 = frozendict({'allowed_company_ids': [1]}) + companies_2 = frozendict({'allowed_company_ids': [2]}) + + User = self.env['res.users'].with_context(context) + self.assertEqual(User.env.context, context) + + User = User.with_context(**companies_1) + self.assertEqual(User.env.context, dict(context, **companies_1)) + + # 'allowed_company_ids' is replaced if present in keys + User = User.with_context(**companies_2) + self.assertEqual(User.env.context, dict(context, **companies_2)) + + # 'allowed_company_ids' is replaced if present in new context + User = User.with_context(companies_1) + self.assertEqual(User.env.context, companies_1) + + # 'allowed_company_ids' is sticky + User = User.with_context(context) + self.assertEqual(User.env.context, dict(context, **companies_1)) diff --git a/odoo/http.py b/odoo/http.py index 222a2eeabb4..9962f8a47b1 100644 --- a/odoo/http.py +++ b/odoo/http.py @@ -1062,7 +1062,7 @@ class OpenERPSession(werkzeug.contrib.sessions.Session): :returns: the new context """ assert self.uid, "The user needs to be logged-in to initialize his context" - self.context = request.env['res.users'].context_get() or {} + self.context = dict(request.env['res.users'].context_get() or {}) self.context['uid'] = self.uid self._fix_lang(self.context) return self.context diff --git a/odoo/tests/common.py b/odoo/tests/common.py index f6eec4d2a9a..3539e067d97 100644 --- a/odoo/tests/common.py +++ b/odoo/tests/common.py @@ -1133,7 +1133,7 @@ class HttpCase(TransactionCase): session.uid = uid session.login = user session.session_token = uid and security.compute_session_token(session, env) - session.context = env['res.users'].context_get() or {} + session.context = dict(env['res.users'].context_get() or {}) session.context['uid'] = uid session._fix_lang(session.context)