From 63c154310a1fbf11d6fa51496e97ac1d00defead Mon Sep 17 00:00:00 2001 From: Florian Mounier Date: Mon, 12 Oct 2026 13:47:44 +0200 Subject: [PATCH] [ADD] fastapi_mail_tracking --- fastapi_mail_tracking/README.rst | 93 ++++ fastapi_mail_tracking/__init__.py | 1 + fastapi_mail_tracking/__manifest__.py | 20 + fastapi_mail_tracking/models/__init__.py | 1 + fastapi_mail_tracking/models/mail_thread.py | 53 +++ fastapi_mail_tracking/pyproject.toml | 3 + fastapi_mail_tracking/readme/CONTRIBUTORS.md | 1 + fastapi_mail_tracking/readme/DESCRIPTION.md | 5 + fastapi_mail_tracking/readme/USAGE.md | 1 + .../static/description/index.html | 433 ++++++++++++++++++ fastapi_mail_tracking/tests/__init__.py | 1 + .../tests/test_fastapi_mail_tracking.py | 69 +++ 12 files changed, 681 insertions(+) create mode 100644 fastapi_mail_tracking/README.rst create mode 100644 fastapi_mail_tracking/__init__.py create mode 100644 fastapi_mail_tracking/__manifest__.py create mode 100644 fastapi_mail_tracking/models/__init__.py create mode 100644 fastapi_mail_tracking/models/mail_thread.py create mode 100644 fastapi_mail_tracking/pyproject.toml create mode 100644 fastapi_mail_tracking/readme/CONTRIBUTORS.md create mode 100644 fastapi_mail_tracking/readme/DESCRIPTION.md create mode 100644 fastapi_mail_tracking/readme/USAGE.md create mode 100644 fastapi_mail_tracking/static/description/index.html create mode 100644 fastapi_mail_tracking/tests/__init__.py create mode 100644 fastapi_mail_tracking/tests/test_fastapi_mail_tracking.py diff --git a/fastapi_mail_tracking/README.rst b/fastapi_mail_tracking/README.rst new file mode 100644 index 000000000..369783335 --- /dev/null +++ b/fastapi_mail_tracking/README.rst @@ -0,0 +1,93 @@ +===================== +Fastapi Mail Tracking +===================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:db0471868f9c2ceaf3bc5f512a3111834829dd61c01737c792b3bd2cb176e2aa + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Frest--framework-lightgray.png?logo=github + :target: https://github.com/OCA/rest-framework/tree/18.0/fastapi_mail_tracking + :alt: OCA/rest-framework +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/rest-framework-18-0/rest-framework-18-0-fastapi_mail_tracking + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/rest-framework&target_branch=18.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module sets the author of tracking notifications messages to the +FastAPI authenticated partner. + +It also adds a message subtype corresponding to the current FastAPI +endpoint to link the changes to the endpoint. + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +Activation is automatic. + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +------- + +* Akretion + +Contributors +------------ + +- Florian Mounier florian.mounier@akretion.com + +Maintainers +----------- + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +.. |maintainer-paradoxxxzero| image:: https://github.com/paradoxxxzero.png?size=40px + :target: https://github.com/paradoxxxzero + :alt: paradoxxxzero + +Current `maintainer `__: + +|maintainer-paradoxxxzero| + +This module is part of the `OCA/rest-framework `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/fastapi_mail_tracking/__init__.py b/fastapi_mail_tracking/__init__.py new file mode 100644 index 000000000..0650744f6 --- /dev/null +++ b/fastapi_mail_tracking/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/fastapi_mail_tracking/__manifest__.py b/fastapi_mail_tracking/__manifest__.py new file mode 100644 index 000000000..3b9dd0d54 --- /dev/null +++ b/fastapi_mail_tracking/__manifest__.py @@ -0,0 +1,20 @@ +# Copyright 2026 Akretion (http://www.akretion.com). +# @author Florian Mounier +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + "name": "Fastapi Mail Tracking", + "version": "18.0.1.0.0", + "author": "Akretion, Odoo Community Association (OCA)", + "summary": "Use authenticated partner as author of changes in the chatter " + "and use an endpoint subtype.", + "depends": [ + "mail", + "fastapi_endpoint_context", + ], + "website": "https://github.com/OCA/rest-framework", + "data": [], + "maintainers": ["paradoxxxzero"], + "installable": True, + "license": "AGPL-3", +} diff --git a/fastapi_mail_tracking/models/__init__.py b/fastapi_mail_tracking/models/__init__.py new file mode 100644 index 000000000..b70a9f2d0 --- /dev/null +++ b/fastapi_mail_tracking/models/__init__.py @@ -0,0 +1 @@ +from . import mail_thread diff --git a/fastapi_mail_tracking/models/mail_thread.py b/fastapi_mail_tracking/models/mail_thread.py new file mode 100644 index 000000000..f95182663 --- /dev/null +++ b/fastapi_mail_tracking/models/mail_thread.py @@ -0,0 +1,53 @@ +# Copyright 2026 Akretion (http://www.akretion.com). +# @author Florian Mounier +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import models + + +class MailThread(models.AbstractModel): + _inherit = "mail.thread" + + def _message_compute_author( + self, author_id=None, email_from=None, raise_on_email=True + ): + # Use fastapi authenticated partner as author + if self.env.context.get("authenticated_partner_id"): + author_id = self.env.context["authenticated_partner_id"] + + author_id, email_from = super()._message_compute_author( + author_id, email_from, raise_on_email + ) + return author_id, email_from + + def _get_tracking_fastapi_subtype_description(self): + endpoint = ( + self.env["fastapi.endpoint"] + .sudo() + .browse(self.env.context["fastapi_endpoint_id"]) + ) + + return f"Via {endpoint.name}" + + def _track_subtype(self, init_values): + if self.env.context.get("fastapi_app"): + # Get or create the subtype for the FastAPI app + subtype = ( + self.env["mail.message.subtype"] + .sudo() + .search([("name", "=", self.env.context["fastapi_app"])], limit=1) + ) + if not subtype: + description = self._get_tracking_fastapi_subtype_description() + subtype = ( + self.env["mail.message.subtype"] + .sudo() + .create( + { + "name": self.env.context["fastapi_app"], + "description": description, + } + ) + ) + return subtype + return super()._track_subtype(init_values) diff --git a/fastapi_mail_tracking/pyproject.toml b/fastapi_mail_tracking/pyproject.toml new file mode 100644 index 000000000..4231d0ccc --- /dev/null +++ b/fastapi_mail_tracking/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/fastapi_mail_tracking/readme/CONTRIBUTORS.md b/fastapi_mail_tracking/readme/CONTRIBUTORS.md new file mode 100644 index 000000000..328a37da8 --- /dev/null +++ b/fastapi_mail_tracking/readme/CONTRIBUTORS.md @@ -0,0 +1 @@ +- Florian Mounier diff --git a/fastapi_mail_tracking/readme/DESCRIPTION.md b/fastapi_mail_tracking/readme/DESCRIPTION.md new file mode 100644 index 000000000..9f7c31cb0 --- /dev/null +++ b/fastapi_mail_tracking/readme/DESCRIPTION.md @@ -0,0 +1,5 @@ +This module sets the author of tracking notifications messages to the FastAPI +authenticated partner. + +It also adds a message subtype corresponding to the current FastAPI endpoint to link the +changes to the endpoint. diff --git a/fastapi_mail_tracking/readme/USAGE.md b/fastapi_mail_tracking/readme/USAGE.md new file mode 100644 index 000000000..8a163b1af --- /dev/null +++ b/fastapi_mail_tracking/readme/USAGE.md @@ -0,0 +1 @@ +Activation is automatic. diff --git a/fastapi_mail_tracking/static/description/index.html b/fastapi_mail_tracking/static/description/index.html new file mode 100644 index 000000000..0c91bff33 --- /dev/null +++ b/fastapi_mail_tracking/static/description/index.html @@ -0,0 +1,433 @@ + + + + + +Fastapi Mail Tracking + + + +
+

Fastapi Mail Tracking

+ + +

Beta License: AGPL-3 OCA/rest-framework Translate me on Weblate Try me on Runboat

+

This module sets the author of tracking notifications messages to the +FastAPI authenticated partner.

+

It also adds a message subtype corresponding to the current FastAPI +endpoint to link the changes to the endpoint.

+

Table of contents

+ +
+

Usage

+

Activation is automatic.

+
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +feedback.

+

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

+
+
+

Credits

+
+

Authors

+
    +
  • Akretion
  • +
+
+ +
+

Maintainers

+

This module is maintained by the OCA.

+ +Odoo Community Association + +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

Current maintainer:

+

paradoxxxzero

+

This module is part of the OCA/rest-framework project on GitHub.

+

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

+
+
+
+ + diff --git a/fastapi_mail_tracking/tests/__init__.py b/fastapi_mail_tracking/tests/__init__.py new file mode 100644 index 000000000..5eb842066 --- /dev/null +++ b/fastapi_mail_tracking/tests/__init__.py @@ -0,0 +1 @@ +from . import test_fastapi_mail_tracking diff --git a/fastapi_mail_tracking/tests/test_fastapi_mail_tracking.py b/fastapi_mail_tracking/tests/test_fastapi_mail_tracking.py new file mode 100644 index 000000000..b55b3b45c --- /dev/null +++ b/fastapi_mail_tracking/tests/test_fastapi_mail_tracking.py @@ -0,0 +1,69 @@ +# Copyright 2026 Akretion (http://www.akretion.com). +# @author Florian Mounier +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + + +import os +import unittest +from typing import Annotated + +from odoo.tests.common import HttpCase + +from odoo.addons.base.models.res_partner import Partner +from odoo.addons.fastapi.dependencies import ( + authenticated_partner, +) +from odoo.addons.fastapi.routers import demo_router + +from fastapi import Depends + + +# Extend the demo router to have an endpoint that changes a partner name +@demo_router.post("/demo/change_partner_name") +async def change_partner_name( + data: dict, + partner: Annotated[Partner, Depends(authenticated_partner)], +) -> dict: + partner.name = data.get("name") + return {"name": partner.name} + + +@unittest.skipIf(os.getenv("SKIP_HTTP_CASE"), "EndpointHttpCase skipped") +class FastAPIHttpCase(HttpCase): + @classmethod + def setUpClass(cls) -> None: + super().setUpClass() + cls.env = cls.env( + context=dict( + cls.env.context, + tracking_disable=False, + ) + ) + cls.fastapi_demo_app = cls.env.ref("fastapi.fastapi_endpoint_demo") + cls.fastapi_demo_app.demo_auth_method = "api_key" + cls.fastapi_demo_app._handle_registry_sync() + cls.endpoint = cls.env.ref("fastapi.fastapi_endpoint_demo") + + cls.demo_user = cls.env.ref("fastapi.my_demo_app_user") + cls.partner = cls.demo_user.partner_id + + def test_change_partner_name(self) -> None: + route = "/fastapi_demo/demo/change_partner_name" + messages = self.partner.message_ids + response = self.url_open( + route, + timeout=20, + data='{"name": "New Name"}', + headers={ + "API-KEY": "my_demo_app_user", + "Content-Type": "application/json", + }, + ) + self.assertEqual(response.status_code, 200, response.text) + self.assertEqual(self.partner.name, "New Name") + + message = self.partner.message_ids - messages + self.assertEqual(len(message), 1) + self.assertEqual(message.author_id, self.partner) + self.assertEqual(message.subtype_id.name, "demo") + self.assertEqual(message.subtype_id.description, "Via Fastapi Demo Endpoint")