From a02069be3599adf7c9f4d4eff58af5649794ade8 Mon Sep 17 00:00:00 2001 From: Maksym Yankin Date: Mon, 24 Aug 2026 10:57:46 +0300 Subject: [PATCH 1/3] [IMP] webservice_server_env: preserve data on install --- webservice_server_env/__init__.py | 2 +- webservice_server_env/__manifest__.py | 1 + webservice_server_env/hooks.py | 51 +++++++++++++++------------ 3 files changed, 30 insertions(+), 24 deletions(-) diff --git a/webservice_server_env/__init__.py b/webservice_server_env/__init__.py index 071962a3..1a9a001c 100644 --- a/webservice_server_env/__init__.py +++ b/webservice_server_env/__init__.py @@ -1,2 +1,2 @@ from . import models -from .hooks import uninstall_hook +from .hooks import post_init_hook, uninstall_hook diff --git a/webservice_server_env/__manifest__.py b/webservice_server_env/__manifest__.py index ae315cb6..db9a1c10 100644 --- a/webservice_server_env/__manifest__.py +++ b/webservice_server_env/__manifest__.py @@ -14,6 +14,7 @@ "author": "Creu Blanca, Camptocamp, Odoo Community Association (OCA)", "website": "https://github.com/OCA/web-api", "depends": ["web", "webservice", "server_environment"], + "post_init_hook": "post_init_hook", "uninstall_hook": "uninstall_hook", "auto_install": True, } diff --git a/webservice_server_env/hooks.py b/webservice_server_env/hooks.py index 4eeb39d5..b860e489 100644 --- a/webservice_server_env/hooks.py +++ b/webservice_server_env/hooks.py @@ -3,32 +3,37 @@ from odoo.addons.server_environment.uninstall import restore_env_managed_columns +ENV_MANAGED_FIELDS = [ + "protocol", + "url", + "auth_type", + "username", + "password", + "api_key", + "api_key_header", + "content_type", + "oauth2_flow", + "oauth2_scope", + "oauth2_clientid", + "oauth2_client_secret", + "oauth2_authorization_url", + "oauth2_token_url", + "oauth2_audience", + "oauth2_token_method", + "oauth2_client_auth_method", + "oauth2_client_auth_header", + "oauth2_client_auth_value", +] -def uninstall_hook(env): - """Restore database columns dropped by server.env.mixin. - When the module is uninstalled, the columns managed by the server - environment mixin must be restored and repopulated with current values, - so the database remains usable. - """ +def post_init_hook(env): + env["webservice.backend"]._preserve_not_env_managed_data(ENV_MANAGED_FIELDS) + + +def uninstall_hook(env): + """Restore database columns dropped by server.env.mixin.""" restore_env_managed_columns( env, "webservice.backend", - [ - "protocol", - "url", - "auth_type", - "username", - "password", - "api_key", - "api_key_header", - "content_type", - "oauth2_flow", - "oauth2_scope", - "oauth2_clientid", - "oauth2_client_secret", - "oauth2_authorization_url", - "oauth2_token_url", - "oauth2_audience", - ], + ENV_MANAGED_FIELDS, ) From 8caab1c995ebffa23b3b1ed90899c316de5ffac5 Mon Sep 17 00:00:00 2001 From: Simone Orsi Date: Mon, 31 Aug 2026 12:58:26 +0200 Subject: [PATCH 2/3] [FIX] webservice: reset oauth2_flow regardless of server_environment PR#146 split server_environment out of `webservice` into the optional `webservice_server_env` module, but the logic resetting `oauth2_flow` when `auth_type` is no longer "oauth2" only lived in `webservice_server_env`'s `_compute_server_env` override. Without `server_environment` installed, switching a backend's `auth_type` away from "oauth2" (via the UI or a plain write) silently left a stale `oauth2_flow`, which `_get_adapter_protocol` would then still factor into the selected component. Add an `_onchange_auth_type` plus `create`/`write` overrides on `webservice.backend` itself so the reset is guaranteed unconditionally, independent of `server_environment`. `webservice_server_env`'s own override is unchanged and still covers its own case (env-var-driven values). --- webservice/models/webservice_backend.py | 24 ++++++++++ webservice/tests/test_oauth2.py | 61 +++++++++++++++++++++++++ 2 files changed, 85 insertions(+) diff --git a/webservice/models/webservice_backend.py b/webservice/models/webservice_backend.py index e7301306..3b7f6916 100644 --- a/webservice/models/webservice_backend.py +++ b/webservice/models/webservice_backend.py @@ -167,6 +167,30 @@ def _valid_field_parameter(self, field, name): extra_params = ("auth_type",) return name in extra_params or super()._valid_field_parameter(field, name) + @api.onchange("auth_type") + def _onchange_auth_type(self): + # Keep `oauth2_flow` in sync in the UI as the user edits `auth_type`, + # regardless of whether `server_environment` is installed (see + # `create`/`write` below for the same guarantee on any other write). + if self.auth_type != "oauth2": + self.oauth2_flow = False + + @api.model_create_multi + def create(self, vals_list): + records = super().create(vals_list) + records.filtered( + lambda r: r.auth_type != "oauth2" and r.oauth2_flow + ).oauth2_flow = False + return records + + def write(self, vals): + res = super().write(vals) + if "auth_type" in vals: + self.filtered( + lambda r: r.auth_type != "oauth2" and r.oauth2_flow + ).oauth2_flow = False + return res + def call(self, method, *args, **kwargs): _logger.debug("backend %s: call %s %s %s", self.name, method, args, kwargs) response = getattr(self._get_adapter(), method)(*args, **kwargs) diff --git a/webservice/tests/test_oauth2.py b/webservice/tests/test_oauth2.py index 388d1548..1288cda8 100644 --- a/webservice/tests/test_oauth2.py +++ b/webservice/tests/test_oauth2.py @@ -374,3 +374,64 @@ def test_fetch_token_from_auth(self): json.loads(responses.calls[0].response.content.decode())["access_token"], ) self.assertEqual("cool_token", token["access_token"]) + + +class TestWebServiceOauth2FlowReset(CommonWebService): + """``oauth2_flow`` must be reset on any write, not only via the UI. + + This is a plain ORM-level guarantee independent of ``server_environment`` + (see ``webservice_server_env`` for the extra guarantee that applies when + that module is installed). + """ + + @classmethod + def _setup_records(cls): + res = super()._setup_records() + cls.url = "https://localhost.demo.odoo/" + cls.webservice = cls.env["webservice.backend"].create( + { + "name": "WebService OAuth2", + "tech_name": "test_oauth2_reset", + "auth_type": "oauth2", + "protocol": "http", + "url": cls.url, + "oauth2_flow": "backend_application", + "content_type": "application/xml", + "oauth2_clientid": "some_client_id", + "oauth2_client_secret": "shh_secret", + "oauth2_token_url": f"{cls.url}oauth2/token", + "oauth2_audience": cls.url, + } + ) + return res + + def test_write_resets_oauth2_flow_when_auth_type_changes(self): + self.webservice.write({"auth_type": "none"}) + self.assertFalse(self.webservice.oauth2_flow) + + def test_write_keeps_oauth2_flow_when_auth_type_stays_oauth2(self): + self.webservice.write({"oauth2_client_secret": "new_secret"}) + self.assertEqual(self.webservice.oauth2_flow, "backend_application") + + def test_create_resets_oauth2_flow_for_non_oauth2_auth_type(self): + ws = self.env["webservice.backend"].create( + { + "name": "WebService No Auth", + "tech_name": "test_oauth2_reset_create", + "auth_type": "none", + "protocol": "http", + "url": self.url, + # Inconsistent on purpose: no `create`/`write` should ever + # leave this set together with a non-oauth2 `auth_type`. + "oauth2_flow": "backend_application", + } + ) + self.assertFalse(ws.oauth2_flow) + + def test_onchange_resets_oauth2_flow(self): + ws = self.webservice.new( + {"auth_type": "oauth2", "oauth2_flow": "backend_application"} + ) + ws.auth_type = "none" + ws._onchange_auth_type() + self.assertFalse(ws.oauth2_flow) From 9d7f7df5c66ac3498b4355ebfe7c9974d93466ec Mon Sep 17 00:00:00 2001 From: Maksym Yankin Date: Mon, 24 Aug 2026 10:59:21 +0300 Subject: [PATCH 3/3] dont merge test-requirements --- test-requirements.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 test-requirements.txt diff --git a/test-requirements.txt b/test-requirements.txt new file mode 100644 index 00000000..da9f588b --- /dev/null +++ b/test-requirements.txt @@ -0,0 +1 @@ +odoo-addon-server_environment @ git+https://github.com/OCA/server-env.git@refs/pull/288/head#subdirectory=server_environment