From 58ea5e7b43a301fe0228bb73db3a62e09e0c72da Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Tue, 16 May 2023 08:23:56 +0000 Subject: [PATCH] [IMP] http.py: do not inject context by default in JSON routes Before this revision, when you pass `context` in the arguments of a JSON routes, this one gets automatically injected in the environment context. This is not the case for regular HTTP routes. It makes sense to propagate the context for the JSONRPC protocol, JSON routes used by the backend, such as `call_kw`, but it doesn't make sense to pass this context automatically for any other kind of routes, such as front-end routes or routes used by custom Javascript widgets. This change brings a more unified behavior for routes of types HTTP and JSON. In addition, most developers were not aware of this "feautre", that passing `context` in the arguments of a JSON route leaded to the injection of this context in the environment context. This is actually reflected by the diff size this changes required, only a dozens of routes needed to be adapted, to manually add the context in their route arguments and to inject it in their environment context. closes odoo/odoo#121726 X-original-commit: a7a5655631e6d5b05fd2ba3d0c80617aae6d9cfe Related: odoo/enterprise#41229 Signed-off-by: Denis Ledoux (dle) --- addons/account/controllers/onboarding.py | 12 +++++++++-- addons/auth_totp/tests/test_totp.py | 1 - addons/lunch/controllers/main.py | 20 ++++++++++++++----- addons/mail/controllers/thread.py | 4 +++- addons/onboarding/controllers/onboarding.py | 4 +++- addons/sale/controllers/onboarding.py | 6 +++++- addons/web/controllers/action.py | 4 +++- addons/web/controllers/dataset.py | 8 ++++++-- .../addons/test_http/tests/test_echo_reply.py | 2 +- odoo/http.py | 7 ++----- 10 files changed, 48 insertions(+), 20 deletions(-) diff --git a/addons/account/controllers/onboarding.py b/addons/account/controllers/onboarding.py index 688cda338a0..240d7aef2f6 100644 --- a/addons/account/controllers/onboarding.py +++ b/addons/account/controllers/onboarding.py @@ -5,11 +5,15 @@ from odoo.http import request class OnboardingController(http.Controller): @http.route('/account/account_invoice_onboarding', auth='user', type='json') - def account_invoice_onboarding(self): + def account_invoice_onboarding(self, context=None): """ Returns the `banner` for the account invoice onboarding panel. It can be empty if the user has closed it or if he doesn't have the permission to see it. """ + # Forward `allowed_company_ids` in the context + # so `request.env.company` returns the company selected in the dropdown + if context: + request.update_context(**context) company = request.env.company if not request.env.is_admin() or \ company.account_invoice_onboarding_state == 'closed': @@ -23,10 +27,14 @@ class OnboardingController(http.Controller): } @http.route('/account/account_dashboard_onboarding', auth='user', type='json') - def account_dashboard_onboarding(self): + def account_dashboard_onboarding(self, context=None): """ Returns the `banner` for the account dashboard onboarding panel. It can be empty if the user has closed it or if he doesn't have the permission to see it. """ + # Forward `allowed_company_ids` in the context + # so `request.env.company` returns the company selected in the dropdown + if context: + request.update_context(**context) company = request.env.company if not request.env.is_admin() or \ diff --git a/addons/auth_totp/tests/test_totp.py b/addons/auth_totp/tests/test_totp.py index 7f9791b732d..d0b2b1dc34c 100644 --- a/addons/auth_totp/tests/test_totp.py +++ b/addons/auth_totp/tests/test_totp.py @@ -109,7 +109,6 @@ class TestTOTP(HttpCase): "db": get_db_name(), "login": "demo", "password": "demo", - "context": {}, }, } response = self.url_open("/web/session/authenticate", data=json.dumps(payload), headers=headers) diff --git a/addons/lunch/controllers/main.py b/addons/lunch/controllers/main.py index 825778d8410..592fbf89ea5 100644 --- a/addons/lunch/controllers/main.py +++ b/addons/lunch/controllers/main.py @@ -10,7 +10,9 @@ from odoo.tools import float_round, float_repr class LunchController(http.Controller): @http.route('/lunch/infos', type='json', auth='user') - def infos(self, user_id=None): + def infos(self, user_id=None, context=None): + if context: + request.update_context(**context) self._check_user_impersonification(user_id) user = request.env['res.users'].browse(user_id) if user_id else request.env.user @@ -36,7 +38,9 @@ class LunchController(http.Controller): return infos @http.route('/lunch/trash', type='json', auth='user') - def trash(self, user_id=None): + def trash(self, user_id=None, context=None): + if context: + request.update_context(**context) self._check_user_impersonification(user_id) user = request.env['res.users'].browse(user_id) if user_id else request.env.user @@ -46,7 +50,9 @@ class LunchController(http.Controller): lines.unlink() @http.route('/lunch/pay', type='json', auth='user') - def pay(self, user_id=None): + def pay(self, user_id=None, context=None): + if context: + request.update_context(**context) self._check_user_impersonification(user_id) user = request.env['res.users'].browse(user_id) if user_id else request.env.user @@ -64,7 +70,9 @@ class LunchController(http.Controller): return {'message': request.env['ir.qweb']._render('lunch.lunch_payment_dialog', {})} @http.route('/lunch/user_location_set', type='json', auth='user') - def set_user_location(self, location_id=None, user_id=None): + def set_user_location(self, location_id=None, user_id=None, context=None): + if context: + request.update_context(**context) self._check_user_impersonification(user_id) user = request.env['res.users'].browse(user_id) if user_id else request.env.user @@ -72,7 +80,9 @@ class LunchController(http.Controller): return True @http.route('/lunch/user_location_get', type='json', auth='user') - def get_user_location(self, user_id=None): + def get_user_location(self, user_id=None, context=None): + if context: + request.update_context(**context) self._check_user_impersonification(user_id) user = request.env['res.users'].browse(user_id) if user_id else request.env.user diff --git a/addons/mail/controllers/thread.py b/addons/mail/controllers/thread.py index 5c0f1eb9c53..9ce9ed0c014 100644 --- a/addons/mail/controllers/thread.py +++ b/addons/mail/controllers/thread.py @@ -61,7 +61,9 @@ class ThreadController(http.Controller): return {"attachment_ids", "body", "message_type", "partner_ids", "subtype_xmlid", "parent_id"} @http.route("/mail/message/post", methods=["POST"], type="json", auth="public") - def mail_message_post(self, thread_model, thread_id, post_data): + def mail_message_post(self, thread_model, thread_id, post_data, context=None): + if context: + request.update_context(**context) thread = request.env[thread_model]._get_from_request_or_raise(request, int(thread_id)) if "body" in post_data: post_data["body"] = Markup(post_data["body"]) # contains HTML such as @mentions diff --git a/addons/onboarding/controllers/onboarding.py b/addons/onboarding/controllers/onboarding.py index 7459b051294..7fdf6403aa0 100644 --- a/addons/onboarding/controllers/onboarding.py +++ b/addons/onboarding/controllers/onboarding.py @@ -9,10 +9,12 @@ from odoo.http import request class OnboardingController(http.Controller): @http.route('/onboarding/', auth='user', type='json') - def get_onboarding_data(self, route_name=None): + def get_onboarding_data(self, route_name=None, context=None): if not request.env.user.has_group('base.group_system'): return {} + if context: + request.update_context(**context) onboarding = request.env['onboarding.onboarding'].search([('route_name', '=', route_name)]) if onboarding: try: diff --git a/addons/sale/controllers/onboarding.py b/addons/sale/controllers/onboarding.py index a6a7e60790e..2d90f083a4a 100644 --- a/addons/sale/controllers/onboarding.py +++ b/addons/sale/controllers/onboarding.py @@ -6,11 +6,15 @@ from odoo.http import request, route, Controller class OnboardingController(Controller): @route('/sales/sale_quotation_onboarding_panel', auth='user', type='json') - def sale_quotation_onboarding(self): + def sale_quotation_onboarding(self, context=None): """ Returns the `banner` for the sale onboarding panel. It can be empty if the user has closed it or if he doesn't have the permission to see it. """ + # Forward `allowed_company_ids` in the context + # so `request.env.company` returns the company selected in the dropdown + if context: + request.update_context(**context) company = request.env.company if not request.env.is_admin() or \ company.sale_quotation_onboarding_state == 'closed': diff --git a/addons/web/controllers/action.py b/addons/web/controllers/action.py index 402a0ca216a..979a1ae2dfa 100644 --- a/addons/web/controllers/action.py +++ b/addons/web/controllers/action.py @@ -39,7 +39,9 @@ class Action(Controller): return value @route('/web/action/run', type='json', auth="user") - def run(self, action_id): + def run(self, action_id, context=None): + if context: + request.update_context(**context) action = request.env['ir.actions.server'].browse([action_id]) result = action.run() return clean_action(result, env=action.env) if result else False diff --git a/addons/web/controllers/dataset.py b/addons/web/controllers/dataset.py index 2c6b1432c27..a5df8d06a94 100644 --- a/addons/web/controllers/dataset.py +++ b/addons/web/controllers/dataset.py @@ -16,7 +16,9 @@ _logger = logging.getLogger(__name__) class DataSet(http.Controller): @http.route('/web/dataset/search_read', type='json', auth="user") - def search_read(self, model, fields=False, offset=0, limit=False, domain=None, sort=None): + def search_read(self, model, fields=False, offset=0, limit=False, domain=None, sort=None, context=None): + if context: + request.update_context(**context) return request.env[model].web_search_read(domain, fields, offset=offset, limit=limit, order=sort) def _call_kw(self, model, method, args, kwargs): @@ -35,7 +37,7 @@ class DataSet(http.Controller): return False @http.route('/web/dataset/resequence', type='json', auth="user") - def resequence(self, model, ids, field='sequence', offset=0): + def resequence(self, model, ids, field='sequence', offset=0, context=None): """ Re-sequences a number of records in the model, by their ids The re-sequencing starts at the first model of ``ids``, the sequence @@ -49,6 +51,8 @@ class DataSet(http.Controller): starting the resequencing from an arbitrary number, defaults to ``0`` """ + if context: + request.update_context(**context) m = request.env[model] if not m.fields_get([field]): return False diff --git a/odoo/addons/test_http/tests/test_echo_reply.py b/odoo/addons/test_http/tests/test_echo_reply.py index 291c5f9aee9..e98230909f3 100644 --- a/odoo/addons/test_http/tests/test_echo_reply.py +++ b/odoo/addons/test_http/tests/test_echo_reply.py @@ -171,5 +171,5 @@ class TestHttpEchoReplyJsonWithDB(TestHttpBase): res = self.db_url_open("/test_http/echo-json-context", data=payload, headers=CT_JSON) self.assertEqual(res.status_code, 200) self.assertEqual(res.text, '{"jsonrpc": "2.0", "id": 0, "result": ' - f'{{"lang": "en_US", "tz": false, "uid": {self.jackoneill.id}, "name": "Thor"}}' + f'{{"lang": "en_US", "tz": false, "uid": {self.jackoneill.id}}}' '}') diff --git a/odoo/http.py b/odoo/http.py index a828750c04e..2ba32a74840 100644 --- a/odoo/http.py +++ b/odoo/http.py @@ -1897,13 +1897,13 @@ class JsonRPCDispatcher(Dispatcher): Successful request:: - --> {"jsonrpc": "2.0", "method": "call", "params": {"context": {}, "arg1": "val1" }, "id": null} + --> {"jsonrpc": "2.0", "method": "call", "params": {"arg1": "val1" }, "id": null} <-- {"jsonrpc": "2.0", "result": { "res1": "val1" }, "id": null} Request producing a error:: - --> {"jsonrpc": "2.0", "method": "call", "params": {"context": {}, "arg1": "val1" }, "id": null} + --> {"jsonrpc": "2.0", "method": "call", "params": {"arg1": "val1" }, "id": null} <-- {"jsonrpc": "2.0", "error": {"code": 1, "message": "End user error message.", "data": {"code": "codestring", "debug": "traceback" } }, "id": null} @@ -1914,9 +1914,6 @@ class JsonRPCDispatcher(Dispatcher): raise BadRequest("Invalid JSON data") from exc self.request.params = dict(self.jsonrequest.get('params', {}), **args) - ctx = self.request.params.pop('context', None) - if ctx is not None and self.request.db: - self.request.update_context(**ctx) if self.request.db: result = self.request.registry['ir.http']._dispatch(endpoint)