Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions test-requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
odoo-addon-server_environment @ git+https://github.com/OCA/server-env.git@refs/pull/288/head#subdirectory=server_environment
24 changes: 24 additions & 0 deletions webservice/models/webservice_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
61 changes: 61 additions & 0 deletions webservice/tests/test_oauth2.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
2 changes: 1 addition & 1 deletion webservice_server_env/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
from . import models
from .hooks import uninstall_hook
from .hooks import post_init_hook, uninstall_hook
1 change: 1 addition & 0 deletions webservice_server_env/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
51 changes: 28 additions & 23 deletions webservice_server_env/hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
)
Loading