Skip to content

Commit a622199

Browse files
committed
[MIG] ai_oca_bridge: Migration to 19.0
- Domain handling migrated to `odoo.fields.Domain` (AND helpers, safe empty defaults) and user group access checks updated to new `group_ids` API. - Async response URLs now built with `odoo.tools.urls.urljoin` and chatter tracking disabled in tests via a new mixin to avoid noisy metadata. - JS/web tests now create bridge records dynamically (no hardcoded mock data) and fake test model registration updated for Odoo 19 registry APIs; inactive bridge uses `action_archive`. - Message/action tests now share computed domains for clarity and resilience under the new Domain API. * Change _ to self.env._, more info at odoo/odoo#174844 * Work around charget AttributeError * Import ValidationError from odoo.exceptions instead of models * Rename webRecord to record * Use new way of popover * Test for response content
1 parent b4f3aa2 commit a622199

19 files changed

Lines changed: 214 additions & 150 deletions

File tree

ai_oca_bridge/README.rst

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,13 @@ AI OCA Bridge
2121
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
2222
:alt: License: AGPL-3
2323
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fai-lightgray.png?logo=github
24-
:target: https://github.com/OCA/ai/tree/18.0/ai_oca_bridge
24+
:target: https://github.com/OCA/ai/tree/19.0/ai_oca_bridge
2525
:alt: OCA/ai
2626
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
27-
:target: https://translation.odoo-community.org/projects/ai-18-0/ai-18-0-ai_oca_bridge
27+
:target: https://translation.odoo-community.org/projects/ai-19-0/ai-19-0-ai_oca_bridge
2828
:alt: Translate me on Weblate
2929
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
30-
:target: https://runboat.odoo-community.org/builds?repo=OCA/ai&target_branch=18.0
30+
:target: https://runboat.odoo-community.org/builds?repo=OCA/ai&target_branch=19.0
3131
:alt: Try me on Runboat
3232

3333
|badge1| |badge2| |badge3| |badge4| |badge5|
@@ -159,7 +159,7 @@ Bug Tracker
159159
Bugs are tracked on `GitHub Issues <https://github.com/OCA/ai/issues>`_.
160160
In case of trouble, please check there if your issue has already been reported.
161161
If you spotted it first, help us to smash it by providing a detailed and welcomed
162-
`feedback <https://github.com/OCA/ai/issues/new?body=module:%20ai_oca_bridge%0Aversion:%2018.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
162+
`feedback <https://github.com/OCA/ai/issues/new?body=module:%20ai_oca_bridge%0Aversion:%2019.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
163163

164164
Do not contact contributors directly about support or help with technical issues.
165165

@@ -200,6 +200,6 @@ OCA, or the Odoo Community Association, is a nonprofit organization whose
200200
mission is to support the collaborative development of Odoo features and
201201
promote its widespread use.
202202

203-
This module is part of the `OCA/ai <https://github.com/OCA/ai/tree/18.0/ai_oca_bridge>`_ project on GitHub.
203+
This module is part of the `OCA/ai <https://github.com/OCA/ai/tree/19.0/ai_oca_bridge>`_ project on GitHub.
204204

205205
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

ai_oca_bridge/__manifest__.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,17 @@
66
"summary": """
77
Makes a basic configuration to be used as bridge with external AI systems
88
""",
9-
"version": "18.0.2.0.0",
9+
"version": "19.0.1.0.0",
1010
"license": "AGPL-3",
1111
"author": "Dixmit,Odoo Community Association (OCA)",
1212
"website": "https://github.com/OCA/ai",
1313
"category": "AI",
1414
"development_status": "Beta",
15-
"depends": ["mail"],
15+
"depends": [
16+
"base",
17+
"mail",
18+
"web",
19+
],
1620
"data": [
1721
"data/ir_module_category.xml",
1822
"security/ir.model.access.csv",

ai_oca_bridge/controllers/ai.py

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
from odoo import fields, http
77
from odoo.http import request
88
from odoo.tools import consteq
9-
from odoo.tools.translate import _
109

1110

1211
class AIController(http.Controller):
@@ -22,24 +21,27 @@ class AIController(http.Controller):
2221
def ai_process_response(self, execution_id, token):
2322
execution = request.env["ai.bridge.execution"].sudo().browse(execution_id)
2423
if not execution.exists():
25-
return request.make_response(_("Execution not found."), status=404)
24+
return request.make_response(self.env._("Execution not found."), status=404)
2625
if not consteq(execution._generate_token(), token):
2726
return request.make_response(
28-
_("Token is not allowed for this execution."), status=404
27+
self.env._("Token is not allowed for this execution."),
28+
status=404,
2929
)
3030
if (
3131
not execution.expiration_date
3232
or execution.expiration_date < fields.Datetime.now()
3333
):
34-
return request.make_response(_("Execution is expired."), status=404)
34+
return request.make_response(
35+
self.env._("Execution is expired."), status=404
36+
)
37+
try:
38+
charset = request.httprequest.charset
39+
except AttributeError:
40+
charset = "utf-8"
3541
return request.make_response(
3642
json.dumps(
3743
execution._process_response(
38-
json.loads(
39-
request.httprequest.get_data().decode(
40-
request.httprequest.charset
41-
)
42-
)
44+
json.loads(request.httprequest.get_data().decode(charset))
4345
)
4446
),
4547
headers=[

ai_oca_bridge/models/ai_bridge.py

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
import logging
77
from datetime import date, datetime
88

9-
from odoo import _, api, fields, models
9+
from odoo import api, fields, models
10+
from odoo.exceptions import ValidationError
11+
from odoo.fields import Domain
1012
from odoo.tools.safe_eval import safe_eval
1113

1214
_logger = logging.getLogger(__name__)
@@ -172,8 +174,8 @@ def _compute_payload_type(self):
172174
def _check_payload_type_usage_compatibility(self):
173175
for record in self:
174176
if record.usage == "ai_thread_unlink" and record.payload_type != "none":
175-
raise models.ValidationError(
176-
_(
177+
raise ValidationError(
178+
self.env._(
177179
"When usage is 'On Record Deleted', "
178180
"the Payload Type must be 'No payload'."
179181
)
@@ -235,11 +237,11 @@ def _get_info(self):
235237
def execute_ai_bridge(self, res_model, res_id):
236238
self.ensure_one()
237239
if not self.active or (
238-
self.group_ids and not self.env.user.groups_id & self.group_ids
240+
self.group_ids and not self.env.user.group_ids & self.group_ids
239241
):
240242
return {
241-
"body": _("%s is not active.", self.name),
242-
"args": {"type": "warning", "title": _("AI Bridge Inactive")},
243+
"body": self.env._("%s is not active.", self.name),
244+
"args": {"type": "warning", "title": self.env._("AI Bridge Inactive")},
243245
}
244246
record = self.env[res_model].browse(res_id).exists()
245247
if record:
@@ -260,24 +262,31 @@ def execute_ai_bridge(self, res_model, res_id):
260262
if execution.state == "done":
261263
return {
262264
"notification": {
263-
"body": _("%s executed successfully.", self.name),
264-
"args": {"type": "success", "title": _("AI Bridge Executed")},
265+
"body": self.env._("%s executed successfully.", self.name),
266+
"args": {
267+
"type": "success",
268+
"title": self.env._("AI Bridge Executed"),
269+
},
265270
}
266271
}
267272
return {
268273
"notification": {
269-
"body": _("%s failed.", self.name),
270-
"args": {"type": "danger", "title": _("AI Bridge Failed")},
274+
"body": self.env._("%s failed.", self.name),
275+
"args": {
276+
"type": "danger",
277+
"title": self.env._("AI Bridge Failed"),
278+
},
271279
}
272280
}
273281

274282
def _enabled_for(self, record):
275283
"""Check if the bridge is enabled for the given record."""
276284
self.ensure_one()
277-
domain = safe_eval(self.domain)
278-
if self.group_ids and not self.env.user.groups_id & self.group_ids:
285+
domain_list = safe_eval(self.domain or "[]")
286+
domain = Domain(domain_list)
287+
if self.group_ids and not self.env.user.group_ids & self.group_ids:
279288
return False
280-
if domain:
289+
if domain_list:
281290
return bool(record.filtered_domain(domain))
282291
return True
283292

ai_oca_bridge/models/ai_bridge_execution.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
from io import StringIO
88

99
import requests
10-
from werkzeug import urls
1110

12-
from odoo import _, api, fields, models, tools
11+
from odoo import api, fields, models, tools
12+
from odoo.tools import urls
1313

1414

1515
class AiBridgeExecution(models.Model):
@@ -92,7 +92,7 @@ def _add_extra_payload_fields(self, payload):
9292
seconds=self.ai_bridge_id.async_timeout
9393
)
9494
token = self._generate_token()
95-
payload["_response_url"] = urls.url_join(
95+
payload["_response_url"] = urls.urljoin(
9696
self.get_base_url(), f"/ai/response/{self.id}/{token}"
9797
)
9898
IrParamSudo = self.env["ir.config_parameter"].sudo()
@@ -163,7 +163,7 @@ def _get_auth(self):
163163
self.ai_bridge_id.sudo().auth_password,
164164
)
165165
else:
166-
raise ValueError(_("Unsupported authentication type."))
166+
raise ValueError(self.env._("Unsupported authentication type."))
167167

168168
def _get_headers(self):
169169
"""Return headers for the request."""

ai_oca_bridge/models/base.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import logging
66

77
from odoo import api, models
8+
from odoo.fields import Domain
89

910
_logger = logging.getLogger(__name__)
1011

@@ -46,7 +47,11 @@ def _execute_ai_bridges_for_records(self, records, usage, values=None):
4647
bridges = (
4748
self.env["ai.bridge"]
4849
.sudo()
49-
.search([("model_id", "=", model_id), ("usage", "=", usage)])
50+
.search(
51+
Domain.AND(
52+
[Domain("model_id", "=", model_id), Domain("usage", "=", usage)]
53+
)
54+
)
5055
)
5156
for bridge in bridges:
5257
# If this is a write, and the bridge has trigger fields configured,
@@ -73,7 +78,12 @@ def _prepare_execution_ai_bridges_unlink(self, records):
7378

7479
model_id = self.env["ir.model"]._get_id(records._name)
7580
bridges = self.env["ai.bridge"].search(
76-
[("model_id", "=", model_id), ("usage", "=", "ai_thread_unlink")]
81+
Domain.AND(
82+
[
83+
Domain("model_id", "=", model_id),
84+
Domain("usage", "=", "ai_thread_unlink"),
85+
]
86+
)
7787
)
7888

7989
executions = self.env["ai.bridge.execution"]

ai_oca_bridge/models/mail_thread.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from lxml import etree
55

66
from odoo import api, fields, models
7+
from odoo.fields import Domain
78
from odoo.tools.misc import frozendict
89

910

@@ -21,10 +22,16 @@ def _compute_ai_bridge_info(self):
2122

2223
def _get_ai_bridge_info(self):
2324
self.ensure_one()
24-
model_id = self.env["ir.model"].sudo().search([("model", "=", self._name)]).id
25+
model_id = (
26+
self.env["ir.model"].sudo().search(Domain("model", "=", self._name)).id
27+
)
2528
return (
2629
self.env["ai.bridge"]
27-
.search([("model_id", "=", model_id), ("usage", "=", "thread")])
30+
.search(
31+
Domain.AND(
32+
[Domain("model_id", "=", model_id), Domain("usage", "=", "thread")]
33+
)
34+
)
2835
.filtered(lambda r: r._enabled_for(self))
2936
)
3037

ai_oca_bridge/static/description/index.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,7 @@ <h1>AI OCA Bridge</h1>
374374
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
375375
!! source digest: sha256:c702d03816331f686ec7f037a5bbef08e513f54645bfdb51d11b15bcd5db77f2
376376
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
377-
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/license-AGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/ai/tree/18.0/ai_oca_bridge"><img alt="OCA/ai" src="https://img.shields.io/badge/github-OCA%2Fai-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/ai-18-0/ai-18-0-ai_oca_bridge"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/ai&amp;target_branch=18.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
377+
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/license-AGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/ai/tree/19.0/ai_oca_bridge"><img alt="OCA/ai" src="https://img.shields.io/badge/github-OCA%2Fai-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/ai-19-0/ai-19-0-ai_oca_bridge"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/ai&amp;target_branch=19.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
378378
<p>This module is used to create a bridge between Odoo and other AI systems
379379
like n8n.</p>
380380
<p><strong>Table of contents</strong></p>
@@ -512,7 +512,7 @@ <h2><a class="toc-backref" href="#toc-entry-13">Bug Tracker</a></h2>
512512
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/ai/issues">GitHub Issues</a>.
513513
In case of trouble, please check there if your issue has already been reported.
514514
If you spotted it first, help us to smash it by providing a detailed and welcomed
515-
<a class="reference external" href="https://github.com/OCA/ai/issues/new?body=module:%20ai_oca_bridge%0Aversion:%2018.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
515+
<a class="reference external" href="https://github.com/OCA/ai/issues/new?body=module:%20ai_oca_bridge%0Aversion:%2019.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
516516
<p>Do not contact contributors directly about support or help with technical issues.</p>
517517
</div>
518518
<div class="section" id="credits">
@@ -550,7 +550,7 @@ <h3><a class="toc-backref" href="#toc-entry-17">Maintainers</a></h3>
550550
<p>OCA, or the Odoo Community Association, is a nonprofit organization whose
551551
mission is to support the collaborative development of Odoo features and
552552
promote its widespread use.</p>
553-
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/ai/tree/18.0/ai_oca_bridge">OCA/ai</a> project on GitHub.</p>
553+
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/ai/tree/19.0/ai_oca_bridge">OCA/ai</a> project on GitHub.</p>
554554
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
555555
</div>
556556
</div>

ai_oca_bridge/static/src/components/chatter/chatter.esm.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ patch(Chatter.prototype, {
55
async onClickAiBridge(aiBridge) {
66
let saved = true;
77

8-
if (this.props.webRecord && this.props.webRecord.save) {
8+
if (this.props.record && this.props.record.save) {
99
try {
10-
await this.props.webRecord.save();
10+
await this.props.record.save();
1111
} catch (error) {
1212
saved = false;
1313
console.error("Error saving record:", error);
@@ -18,8 +18,8 @@ patch(Chatter.prototype, {
1818
return;
1919
}
2020

21-
const model = this.props.webRecord.resModel;
22-
const id = this.props.webRecord.resId;
21+
const model = this.props.record.resModel;
22+
const id = this.props.record.resId;
2323

2424
const result = await this.env.services.orm.call(
2525
"ai.bridge",

ai_oca_bridge/static/src/components/chatter_topbar/chatter_topbar.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
<xpath expr="//div/div/div/button" position="before">
99
<ChatterAITopbar
1010
record="this"
11-
t-if="props.webRecord and props.webRecord.data.ai_bridge_info and props.webRecord.data.ai_bridge_info.length > 0"
11+
t-if="props.record and props.record.data.ai_bridge_info and props.record.data.ai_bridge_info.length > 0"
1212
/>
1313
</xpath>
1414
</t>

0 commit comments

Comments
 (0)