From caaa7fcb1d465c61a3f8c7fc2030f6b2708f1f02 Mon Sep 17 00:00:00 2001
From: Mmequignon
Date: Wed, 28 Feb 2024 13:11:48 +0100
Subject: [PATCH 1/5] Add fastapi_auth_api_key
---
fastapi_auth_api_key/README.rst | 0
fastapi_auth_api_key/__init__.py | 1 +
fastapi_auth_api_key/__manifest__.py | 20 +
fastapi_auth_api_key/dependencies.py | 60 +++
fastapi_auth_api_key/models/__init__.py | 1 +
.../models/fastapi_endpoint.py | 10 +
fastapi_auth_api_key/readme/CONTRIBUTORS.rst | 1 +
fastapi_auth_api_key/readme/DESCRIPTION.rst | 1 +
fastapi_auth_api_key/readme/USAGE.rst | 33 ++
.../static/description/index.html | 369 ++++++++++++++++++
fastapi_auth_api_key/tests/__init__.py | 1 +
.../test_fastapi_api_key_dependencies.py | 88 +++++
.../views/fastapi_endpoint.xml | 17 +
13 files changed, 602 insertions(+)
create mode 100644 fastapi_auth_api_key/README.rst
create mode 100644 fastapi_auth_api_key/__init__.py
create mode 100644 fastapi_auth_api_key/__manifest__.py
create mode 100644 fastapi_auth_api_key/dependencies.py
create mode 100644 fastapi_auth_api_key/models/__init__.py
create mode 100644 fastapi_auth_api_key/models/fastapi_endpoint.py
create mode 100644 fastapi_auth_api_key/readme/CONTRIBUTORS.rst
create mode 100644 fastapi_auth_api_key/readme/DESCRIPTION.rst
create mode 100644 fastapi_auth_api_key/readme/USAGE.rst
create mode 100644 fastapi_auth_api_key/static/description/index.html
create mode 100644 fastapi_auth_api_key/tests/__init__.py
create mode 100644 fastapi_auth_api_key/tests/test_fastapi_api_key_dependencies.py
create mode 100644 fastapi_auth_api_key/views/fastapi_endpoint.xml
diff --git a/fastapi_auth_api_key/README.rst b/fastapi_auth_api_key/README.rst
new file mode 100644
index 000000000..e69de29bb
diff --git a/fastapi_auth_api_key/__init__.py b/fastapi_auth_api_key/__init__.py
new file mode 100644
index 000000000..0650744f6
--- /dev/null
+++ b/fastapi_auth_api_key/__init__.py
@@ -0,0 +1 @@
+from . import models
diff --git a/fastapi_auth_api_key/__manifest__.py b/fastapi_auth_api_key/__manifest__.py
new file mode 100644
index 000000000..1735c59be
--- /dev/null
+++ b/fastapi_auth_api_key/__manifest__.py
@@ -0,0 +1,20 @@
+# Copyright 2024 Camptocamp SA
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
+
+{
+ "name": "Fastapi Auth Api Key",
+ "version": "16.0.1.0.0",
+ "category": "Others",
+ "website": "https://github.com/OCA/rest-framework",
+ "author": "Camptocamp, Odoo Community Association (OCA)",
+ "maintainers": ["mmequignon"],
+ "license": "AGPL-3",
+ "installable": True,
+ "depends": [
+ "fastapi",
+ "auth_api_key_group",
+ ],
+ "data": [
+ "views/fastapi_endpoint.xml",
+ ],
+}
diff --git a/fastapi_auth_api_key/dependencies.py b/fastapi_auth_api_key/dependencies.py
new file mode 100644
index 000000000..3b71e6d58
--- /dev/null
+++ b/fastapi_auth_api_key/dependencies.py
@@ -0,0 +1,60 @@
+# Copyright 2024 Camptocamp SA
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
+
+from typing_extensions import Annotated
+
+from odoo import SUPERUSER_ID
+from odoo.api import Environment
+from odoo.exceptions import ValidationError
+
+from odoo.addons.auth_api_key.models.auth_api_key import AuthApiKey
+from odoo.addons.base.models.res_partner import Partner
+from odoo.addons.fastapi.dependencies import fastapi_endpoint, odoo_env
+from odoo.addons.fastapi.models.fastapi_endpoint import FastapiEndpoint
+
+from fastapi import Depends, status
+from fastapi.exceptions import HTTPException
+from fastapi.security import APIKeyHeader
+
+
+def authenticated_auth_api_key(
+ key: Annotated[str, Depends(APIKeyHeader(name="HTTP-API-KEY"))],
+ env: Annotated[Environment, Depends(odoo_env)],
+ endpoint: Annotated[FastapiEndpoint, Depends(fastapi_endpoint)],
+) -> AuthApiKey:
+ if not key:
+ raise HTTPException(
+ status_code=status.HTTP_401_UNAUTHORIZED,
+ detail="No HTTP-API-KEY provided",
+ headers={"WWW-Authenticate": "HTTP-API-KEY"},
+ )
+ admin_env = Environment(env.cr, SUPERUSER_ID, {})
+ try:
+ auth_api_key = admin_env["auth.api.key"]._retrieve_api_key(key)
+ except ValidationError as error:
+ raise HTTPException(
+ status_code=status.HTTP_401_UNAUTHORIZED,
+ detail=error.name,
+ headers={"WWW-Authenticate": "HTTP-API-KEY"},
+ ) from error
+ # Ensure the api key is authorized for the current endpoint.
+ if auth_api_key not in endpoint.sudo().auth_api_key_group_id.auth_api_key_ids:
+ raise HTTPException(
+ status_code=status.HTTP_401_UNAUTHORIZED,
+ detail="Unauthorized",
+ headers={"WWW-Authenticate": "HTTP-API-KEY"},
+ )
+ return auth_api_key
+
+
+def authenticated_partner_by_api_key(
+ auth_api_key: Annotated[AuthApiKey, Depends(authenticated_auth_api_key)]
+) -> Partner:
+ return auth_api_key.user_id.partner_id
+
+
+def authenticated_env_by_auth_api_key(
+ auth_api_key: Annotated[AuthApiKey, Depends(authenticated_auth_api_key)]
+) -> Environment:
+ # set api key id in context
+ return auth_api_key.with_user(auth_api_key.user_id).env
diff --git a/fastapi_auth_api_key/models/__init__.py b/fastapi_auth_api_key/models/__init__.py
new file mode 100644
index 000000000..b825fab92
--- /dev/null
+++ b/fastapi_auth_api_key/models/__init__.py
@@ -0,0 +1 @@
+from . import fastapi_endpoint
diff --git a/fastapi_auth_api_key/models/fastapi_endpoint.py b/fastapi_auth_api_key/models/fastapi_endpoint.py
new file mode 100644
index 000000000..8da7ff66d
--- /dev/null
+++ b/fastapi_auth_api_key/models/fastapi_endpoint.py
@@ -0,0 +1,10 @@
+# Copyright 2024 Camptocamp SA
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
+
+from odoo import fields, models
+
+
+class FastapiEndpoint(models.Model):
+ _inherit = "fastapi.endpoint"
+
+ auth_api_key_group_id = fields.Many2one("auth.api.key.group")
diff --git a/fastapi_auth_api_key/readme/CONTRIBUTORS.rst b/fastapi_auth_api_key/readme/CONTRIBUTORS.rst
new file mode 100644
index 000000000..bca4ee0ca
--- /dev/null
+++ b/fastapi_auth_api_key/readme/CONTRIBUTORS.rst
@@ -0,0 +1 @@
+* Matthieu Méquignon
diff --git a/fastapi_auth_api_key/readme/DESCRIPTION.rst b/fastapi_auth_api_key/readme/DESCRIPTION.rst
new file mode 100644
index 000000000..22e772df2
--- /dev/null
+++ b/fastapi_auth_api_key/readme/DESCRIPTION.rst
@@ -0,0 +1 @@
+Provides `FastAPI` dependencies for Api Key authentication.
diff --git a/fastapi_auth_api_key/readme/USAGE.rst b/fastapi_auth_api_key/readme/USAGE.rst
new file mode 100644
index 000000000..356cb02d2
--- /dev/null
+++ b/fastapi_auth_api_key/readme/USAGE.rst
@@ -0,0 +1,33 @@
+Getting an odoo environment
+===========================
+
+If you need to get an odoo env based on the provided api key, you can use `authenticated_env_by_auth_api_key`.
+
+.. code-block:: python
+
+ @router.get("/example_with_authenticated_env")
+ def example_with_authenticated_env(
+ env: Annotated[Environment, Depends(authenticated_env_by_auth_api_key)],
+ ) -> None:
+ # env.user is the user attached to the provided key
+ pass
+
+Getting the authenticated partner
+=================================
+
+If want to get the partned related to the the provided api key, you can use `authenticated_partner_by_api_key`
+
+.. code-block:: python
+
+ @router.get("/example_with_authenticated_partner")
+ def example_with_authenticated_partner(
+ partner: Annotated[Partner, Depends(authenticated_partner_by_api_key)],
+ ) -> None:
+ # partner is the partner related to the provided key key.user_id.partner_id
+ pass
+
+Configuration
+=============
+
+For this to work, the api key must be defined on the `Endpoint`.
+A new field `auth_api_key_group_id` has been added to the `Endpoint` model.
diff --git a/fastapi_auth_api_key/static/description/index.html b/fastapi_auth_api_key/static/description/index.html
new file mode 100644
index 000000000..ec3643de8
--- /dev/null
+++ b/fastapi_auth_api_key/static/description/index.html
@@ -0,0 +1,369 @@
+
+
+
+
+
+
+README.rst
+
+
+
+
+
+
+
+
+
+
diff --git a/fastapi_auth_api_key/tests/__init__.py b/fastapi_auth_api_key/tests/__init__.py
new file mode 100644
index 000000000..da7258cc3
--- /dev/null
+++ b/fastapi_auth_api_key/tests/__init__.py
@@ -0,0 +1 @@
+from . import test_fastapi_api_key_dependencies
diff --git a/fastapi_auth_api_key/tests/test_fastapi_api_key_dependencies.py b/fastapi_auth_api_key/tests/test_fastapi_api_key_dependencies.py
new file mode 100644
index 000000000..d746e1ccc
--- /dev/null
+++ b/fastapi_auth_api_key/tests/test_fastapi_api_key_dependencies.py
@@ -0,0 +1,88 @@
+from odoo.tests import tagged
+from odoo.tests.common import TransactionCase
+
+from fastapi.exceptions import HTTPException
+
+from ..dependencies import (
+ authenticated_auth_api_key,
+ authenticated_env_by_auth_api_key,
+ authenticated_partner_by_api_key,
+)
+
+
+@tagged("-at_install", "post_install")
+class TestFastapiAuthApiKey(TransactionCase):
+ @classmethod
+ def setUpClass(cls):
+ super().setUpClass()
+ cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True))
+ # Is it valid? We need an env without superpowers
+ demo_user = cls.env.ref("base.partner_demo")
+ cls.demo_env = demo_user.with_user(demo_user).env
+ cls.setUpClassApiKey()
+
+ @classmethod
+ def setUpClassApiKey(cls):
+ user_model = cls.env["res.users"].with_context(no_reset_password=True)
+ cls.authorized_user = user_model.create(
+ {
+ "name": "John Authorized",
+ "login": "johnauth",
+ }
+ )
+ cls.unauthorized_user = user_model.create(
+ {
+ "name": "Bob Unauthorized",
+ "login": "bobunauth",
+ }
+ )
+ api_key_model = cls.env["auth.api.key"]
+ cls.authorized_api_key = api_key_model.create(
+ {
+ "user_id": cls.authorized_user.id,
+ "name": "Authorized api key",
+ "key": "authorized_key",
+ }
+ )
+ cls.unauthorized_api_key = api_key_model.create(
+ {
+ "user_id": cls.unauthorized_user.id,
+ "name": "Unauthorized api key",
+ "key": "unauthorized_key",
+ }
+ )
+ api_key_group_model = cls.env["auth.api.key.group"]
+ cls.authorized_api_key_group = api_key_group_model.create(
+ {
+ "name": "Authorized api key group",
+ "code": "authorized_api_key_group",
+ "auth_api_key_ids": [(6, 0, cls.authorized_api_key.ids)],
+ }
+ )
+
+ def test_authenticated_auth_api_key(self):
+ # An exception is raised when no api key is used
+ with self.assertRaises(HTTPException) as error:
+ authenticated_auth_api_key(False, self.demo_env)
+ self.assertEqual(error.exception.detail, "No HTTP-API-KEY provided")
+ # An exception is raised when no api key record is found
+ with self.assertRaises(HTTPException) as error:
+ authenticated_auth_api_key("404", self.demo_env)
+ self.assertEqual(error.exception.detail, "The key 404 is not allowed")
+ # TODO enable this when we know how to filter keys based
+ # on endpoint's api key group.
+ # An exception is raised when unauthorized api key record is found
+ # with self.assertRaises(HTTPException) as error:
+ # authenticated_auth_api_key("not_authorized", self.demo_env)
+ result_key = authenticated_auth_api_key(
+ self.authorized_api_key.key, self.demo_env
+ )
+ self.assertEqual(result_key, self.authorized_api_key)
+
+ def test_authenticated_partner_by_api_key(self):
+ result_partner = authenticated_partner_by_api_key(self.authorized_api_key)
+ self.assertEqual(result_partner, self.authorized_user.partner_id)
+
+ def test_authenticated_env_by_auth_api_key(self):
+ result_env = authenticated_env_by_auth_api_key(self.authorized_api_key)
+ self.assertEqual(result_env.user, self.authorized_user)
diff --git a/fastapi_auth_api_key/views/fastapi_endpoint.xml b/fastapi_auth_api_key/views/fastapi_endpoint.xml
new file mode 100644
index 000000000..bd8ba2a90
--- /dev/null
+++ b/fastapi_auth_api_key/views/fastapi_endpoint.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+ fastapi.endpoint.form.inherit
+ fastapi.endpoint
+
+
+
+
+
+
+
+
+
From ff3f1ddc8dc32784234149879f162124fc6630f0 Mon Sep 17 00:00:00 2001
From: sonhd91
Date: Fri, 24 May 2024 18:30:22 +0700
Subject: [PATCH 2/5] [IMP] fastapi_auth_api_key: pre-commit auto fixes
---
fastapi_auth_api_key/README.rst | 121 ++++++++++++++++++
.../odoo/addons/fastapi_auth_api_key | 1 +
setup/fastapi_auth_api_key/setup.py | 6 +
3 files changed, 128 insertions(+)
create mode 120000 setup/fastapi_auth_api_key/odoo/addons/fastapi_auth_api_key
create mode 100644 setup/fastapi_auth_api_key/setup.py
diff --git a/fastapi_auth_api_key/README.rst b/fastapi_auth_api_key/README.rst
index e69de29bb..bd0a9aaf7 100644
--- a/fastapi_auth_api_key/README.rst
+++ b/fastapi_auth_api_key/README.rst
@@ -0,0 +1,121 @@
+====================
+Fastapi Auth Api Key
+====================
+
+..
+ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ !! This file is generated by oca-gen-addon-readme !!
+ !! changes will be overwritten. !!
+ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ !! source digest: sha256:a1a8681b1c3e7a13dc83e2e61a1d78ad8c8da1ddb684c8cf563607e96cf4f7e7
+ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+.. |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/16.0/fastapi_auth_api_key
+ :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-16-0/rest-framework-16-0-fastapi_auth_api_key
+ :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=16.0
+ :alt: Try me on Runboat
+
+|badge1| |badge2| |badge3| |badge4| |badge5|
+
+Provides `FastAPI` dependencies for Api Key authentication.
+
+**Table of contents**
+
+.. contents::
+ :local:
+
+Usage
+=====
+
+Getting an odoo environment
+===========================
+
+If you need to get an odoo env based on the provided api key, you can use `authenticated_env_by_auth_api_key`.
+
+.. code-block:: python
+
+ @router.get("/example_with_authenticated_env")
+ def example_with_authenticated_env(
+ env: Annotated[Environment, Depends(authenticated_env_by_auth_api_key)],
+ ) -> None:
+ # env.user is the user attached to the provided key
+ pass
+
+Getting the authenticated partner
+=================================
+
+If want to get the partned related to the the provided api key, you can use `authenticated_partner_by_api_key`
+
+.. code-block:: python
+
+ @router.get("/example_with_authenticated_partner")
+ def example_with_authenticated_partner(
+ partner: Annotated[Partner, Depends(authenticated_partner_by_api_key)],
+ ) -> None:
+ # partner is the partner related to the provided key key.user_id.partner_id
+ pass
+
+Configuration
+=============
+
+For this to work, the api key must be defined on the `Endpoint`.
+A new field `auth_api_key_group_id` has been added to the `Endpoint` model.
+
+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
+~~~~~~~
+
+* Camptocamp
+
+Contributors
+~~~~~~~~~~~~
+
+* Matthieu Méquignon
+
+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-mmequignon| image:: https://github.com/mmequignon.png?size=40px
+ :target: https://github.com/mmequignon
+ :alt: mmequignon
+
+Current `maintainer `__:
+
+|maintainer-mmequignon|
+
+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/setup/fastapi_auth_api_key/odoo/addons/fastapi_auth_api_key b/setup/fastapi_auth_api_key/odoo/addons/fastapi_auth_api_key
new file mode 120000
index 000000000..498f5ddb6
--- /dev/null
+++ b/setup/fastapi_auth_api_key/odoo/addons/fastapi_auth_api_key
@@ -0,0 +1 @@
+../../../../fastapi_auth_api_key
\ No newline at end of file
diff --git a/setup/fastapi_auth_api_key/setup.py b/setup/fastapi_auth_api_key/setup.py
new file mode 100644
index 000000000..28c57bb64
--- /dev/null
+++ b/setup/fastapi_auth_api_key/setup.py
@@ -0,0 +1,6 @@
+import setuptools
+
+setuptools.setup(
+ setup_requires=['setuptools-odoo'],
+ odoo_addon=True,
+)
From edbe2ab6d30e9588fbd1afcbf4a8d0ab6bcbf228 Mon Sep 17 00:00:00 2001
From: sonhd91
Date: Fri, 24 May 2024 18:23:29 +0700
Subject: [PATCH 3/5] [MIG] fastapi_auth_api_key: Migration to 17.0
---
fastapi_auth_api_key/README.rst | 71 +++++++++++--------
fastapi_auth_api_key/__manifest__.py | 2 +-
fastapi_auth_api_key/dependencies.py | 4 +-
fastapi_auth_api_key/pyproject.toml | 3 +
fastapi_auth_api_key/readme/CONTRIBUTORS.md | 2 +
fastapi_auth_api_key/readme/CONTRIBUTORS.rst | 1 -
fastapi_auth_api_key/readme/CREDITS.md | 2 +
fastapi_auth_api_key/readme/DESCRIPTION.md | 1 +
fastapi_auth_api_key/readme/DESCRIPTION.rst | 1 -
fastapi_auth_api_key/readme/USAGE.md | 32 +++++++++
fastapi_auth_api_key/readme/USAGE.rst | 33 ---------
.../test_fastapi_api_key_dependencies.py | 22 ++++--
.../views/fastapi_endpoint.xml | 2 +-
13 files changed, 101 insertions(+), 75 deletions(-)
create mode 100644 fastapi_auth_api_key/pyproject.toml
create mode 100644 fastapi_auth_api_key/readme/CONTRIBUTORS.md
delete mode 100644 fastapi_auth_api_key/readme/CONTRIBUTORS.rst
create mode 100644 fastapi_auth_api_key/readme/CREDITS.md
create mode 100644 fastapi_auth_api_key/readme/DESCRIPTION.md
delete mode 100644 fastapi_auth_api_key/readme/DESCRIPTION.rst
create mode 100644 fastapi_auth_api_key/readme/USAGE.md
delete mode 100644 fastapi_auth_api_key/readme/USAGE.rst
diff --git a/fastapi_auth_api_key/README.rst b/fastapi_auth_api_key/README.rst
index bd0a9aaf7..f97f63c53 100644
--- a/fastapi_auth_api_key/README.rst
+++ b/fastapi_auth_api_key/README.rst
@@ -17,18 +17,18 @@ Fastapi Auth Api Key
: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/16.0/fastapi_auth_api_key
+ :target: https://github.com/OCA/rest-framework/tree/17.0/fastapi_auth_api_key
: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-16-0/rest-framework-16-0-fastapi_auth_api_key
+ :target: https://translation.odoo-community.org/projects/rest-framework-17-0/rest-framework-17-0-fastapi_auth_api_key
: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=16.0
+ :target: https://runboat.odoo-community.org/builds?repo=OCA/rest-framework&target_branch=17.0
:alt: Try me on Runboat
|badge1| |badge2| |badge3| |badge4| |badge5|
-Provides `FastAPI` dependencies for Api Key authentication.
+Provides FastAPI dependencies for Api Key authentication.
**Table of contents**
@@ -39,38 +39,40 @@ Usage
=====
Getting an odoo environment
-===========================
+---------------------------
-If you need to get an odoo env based on the provided api key, you can use `authenticated_env_by_auth_api_key`.
+If you need to get an odoo env based on the provided api key, you can
+use authenticated_env_by_auth_api_key.
-.. code-block:: python
+.. code:: python
- @router.get("/example_with_authenticated_env")
- def example_with_authenticated_env(
- env: Annotated[Environment, Depends(authenticated_env_by_auth_api_key)],
- ) -> None:
- # env.user is the user attached to the provided key
- pass
+ @router.get("/example_with_authenticated_env")
+ def example_with_authenticated_env(
+ env: Annotated[Environment, Depends(authenticated_env_by_auth_api_key)],
+ ) -> None:
+ # env.user is the user attached to the provided key
+ pass
Getting the authenticated partner
-=================================
+---------------------------------
-If want to get the partned related to the the provided api key, you can use `authenticated_partner_by_api_key`
+If want to get the partned related to the the provided api key, you can
+use authenticated_partner_by_api_key
-.. code-block:: python
+.. code:: python
- @router.get("/example_with_authenticated_partner")
- def example_with_authenticated_partner(
- partner: Annotated[Partner, Depends(authenticated_partner_by_api_key)],
- ) -> None:
- # partner is the partner related to the provided key key.user_id.partner_id
- pass
+ @router.get("/example_with_authenticated_partner")
+ def example_with_authenticated_partner(
+ partner: Annotated[Partner, Depends(authenticated_partner_by_api_key)],
+ ) -> None:
+ # partner is the partner related to the provided key key.user_id.partner_id
+ pass
Configuration
-=============
+-------------
-For this to work, the api key must be defined on the `Endpoint`.
-A new field `auth_api_key_group_id` has been added to the `Endpoint` model.
+For this to work, the api key must be defined on the Endpoint. A new
+field auth_api_key_group_id has been added to the Endpoint model.
Bug Tracker
===========
@@ -78,7 +80,7 @@ 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 `_.
+`feedback `_.
Do not contact contributors directly about support or help with technical issues.
@@ -86,17 +88,24 @@ Credits
=======
Authors
-~~~~~~~
+-------
* Camptocamp
Contributors
-~~~~~~~~~~~~
+------------
-* Matthieu Méquignon
+- Matthieu Méquignon
+- Son Ho
+
+Other credits
+-------------
+
+The migration of this module from 16.0 to 17.0 was financially supported
+by Camptocamp
Maintainers
-~~~~~~~~~~~
+-----------
This module is maintained by the OCA.
@@ -116,6 +125,6 @@ Current `maintainer `__:
|maintainer-mmequignon|
-This module is part of the `OCA/rest-framework `_ project on GitHub.
+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_auth_api_key/__manifest__.py b/fastapi_auth_api_key/__manifest__.py
index 1735c59be..539efdcc1 100644
--- a/fastapi_auth_api_key/__manifest__.py
+++ b/fastapi_auth_api_key/__manifest__.py
@@ -3,7 +3,7 @@
{
"name": "Fastapi Auth Api Key",
- "version": "16.0.1.0.0",
+ "version": "17.0.1.0.0",
"category": "Others",
"website": "https://github.com/OCA/rest-framework",
"author": "Camptocamp, Odoo Community Association (OCA)",
diff --git a/fastapi_auth_api_key/dependencies.py b/fastapi_auth_api_key/dependencies.py
index 3b71e6d58..aa1838ab0 100644
--- a/fastapi_auth_api_key/dependencies.py
+++ b/fastapi_auth_api_key/dependencies.py
@@ -1,7 +1,7 @@
# Copyright 2024 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
-from typing_extensions import Annotated
+from typing import Annotated
from odoo import SUPERUSER_ID
from odoo.api import Environment
@@ -34,7 +34,7 @@ def authenticated_auth_api_key(
except ValidationError as error:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
- detail=error.name,
+ detail=error.args,
headers={"WWW-Authenticate": "HTTP-API-KEY"},
) from error
# Ensure the api key is authorized for the current endpoint.
diff --git a/fastapi_auth_api_key/pyproject.toml b/fastapi_auth_api_key/pyproject.toml
new file mode 100644
index 000000000..4231d0ccc
--- /dev/null
+++ b/fastapi_auth_api_key/pyproject.toml
@@ -0,0 +1,3 @@
+[build-system]
+requires = ["whool"]
+build-backend = "whool.buildapi"
diff --git a/fastapi_auth_api_key/readme/CONTRIBUTORS.md b/fastapi_auth_api_key/readme/CONTRIBUTORS.md
new file mode 100644
index 000000000..a6f2fed34
--- /dev/null
+++ b/fastapi_auth_api_key/readme/CONTRIBUTORS.md
@@ -0,0 +1,2 @@
+- Matthieu Méquignon \<\>
+- Son Ho \<\>
diff --git a/fastapi_auth_api_key/readme/CONTRIBUTORS.rst b/fastapi_auth_api_key/readme/CONTRIBUTORS.rst
deleted file mode 100644
index bca4ee0ca..000000000
--- a/fastapi_auth_api_key/readme/CONTRIBUTORS.rst
+++ /dev/null
@@ -1 +0,0 @@
-* Matthieu Méquignon
diff --git a/fastapi_auth_api_key/readme/CREDITS.md b/fastapi_auth_api_key/readme/CREDITS.md
new file mode 100644
index 000000000..7c48f8e03
--- /dev/null
+++ b/fastapi_auth_api_key/readme/CREDITS.md
@@ -0,0 +1,2 @@
+The migration of this module from 16.0 to 17.0 was financially supported
+by Camptocamp
diff --git a/fastapi_auth_api_key/readme/DESCRIPTION.md b/fastapi_auth_api_key/readme/DESCRIPTION.md
new file mode 100644
index 000000000..1e9aa6910
--- /dev/null
+++ b/fastapi_auth_api_key/readme/DESCRIPTION.md
@@ -0,0 +1 @@
+Provides FastAPI dependencies for Api Key authentication.
diff --git a/fastapi_auth_api_key/readme/DESCRIPTION.rst b/fastapi_auth_api_key/readme/DESCRIPTION.rst
deleted file mode 100644
index 22e772df2..000000000
--- a/fastapi_auth_api_key/readme/DESCRIPTION.rst
+++ /dev/null
@@ -1 +0,0 @@
-Provides `FastAPI` dependencies for Api Key authentication.
diff --git a/fastapi_auth_api_key/readme/USAGE.md b/fastapi_auth_api_key/readme/USAGE.md
new file mode 100644
index 000000000..f60799c41
--- /dev/null
+++ b/fastapi_auth_api_key/readme/USAGE.md
@@ -0,0 +1,32 @@
+## Getting an odoo environment
+
+If you need to get an odoo env based on the provided api key, you can
+use authenticated_env_by_auth_api_key.
+
+``` python
+@router.get("/example_with_authenticated_env")
+def example_with_authenticated_env(
+ env: Annotated[Environment, Depends(authenticated_env_by_auth_api_key)],
+) -> None:
+ # env.user is the user attached to the provided key
+ pass
+```
+
+## Getting the authenticated partner
+
+If want to get the partned related to the the provided api key, you can
+use authenticated_partner_by_api_key
+
+``` python
+@router.get("/example_with_authenticated_partner")
+def example_with_authenticated_partner(
+ partner: Annotated[Partner, Depends(authenticated_partner_by_api_key)],
+) -> None:
+ # partner is the partner related to the provided key key.user_id.partner_id
+ pass
+```
+
+## Configuration
+
+For this to work, the api key must be defined on the Endpoint. A new
+field auth_api_key_group_id has been added to the Endpoint model.
diff --git a/fastapi_auth_api_key/readme/USAGE.rst b/fastapi_auth_api_key/readme/USAGE.rst
deleted file mode 100644
index 356cb02d2..000000000
--- a/fastapi_auth_api_key/readme/USAGE.rst
+++ /dev/null
@@ -1,33 +0,0 @@
-Getting an odoo environment
-===========================
-
-If you need to get an odoo env based on the provided api key, you can use `authenticated_env_by_auth_api_key`.
-
-.. code-block:: python
-
- @router.get("/example_with_authenticated_env")
- def example_with_authenticated_env(
- env: Annotated[Environment, Depends(authenticated_env_by_auth_api_key)],
- ) -> None:
- # env.user is the user attached to the provided key
- pass
-
-Getting the authenticated partner
-=================================
-
-If want to get the partned related to the the provided api key, you can use `authenticated_partner_by_api_key`
-
-.. code-block:: python
-
- @router.get("/example_with_authenticated_partner")
- def example_with_authenticated_partner(
- partner: Annotated[Partner, Depends(authenticated_partner_by_api_key)],
- ) -> None:
- # partner is the partner related to the provided key key.user_id.partner_id
- pass
-
-Configuration
-=============
-
-For this to work, the api key must be defined on the `Endpoint`.
-A new field `auth_api_key_group_id` has been added to the `Endpoint` model.
diff --git a/fastapi_auth_api_key/tests/test_fastapi_api_key_dependencies.py b/fastapi_auth_api_key/tests/test_fastapi_api_key_dependencies.py
index d746e1ccc..dde6088ca 100644
--- a/fastapi_auth_api_key/tests/test_fastapi_api_key_dependencies.py
+++ b/fastapi_auth_api_key/tests/test_fastapi_api_key_dependencies.py
@@ -17,8 +17,17 @@ def setUpClass(cls):
super().setUpClass()
cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True))
# Is it valid? We need an env without superpowers
- demo_user = cls.env.ref("base.partner_demo")
+ demo_user = cls.env.ref("base.user_demo")
cls.demo_env = demo_user.with_user(demo_user).env
+ cls.demo_endpoint = cls.env["fastapi.endpoint"].create(
+ {
+ "name": "Test Enpoint",
+ "app": "demo",
+ "root_path": "/path_demo",
+ "demo_auth_method": "api_key",
+ "user_id": demo_user.id,
+ }
+ )
cls.setUpClassApiKey()
@classmethod
@@ -63,19 +72,22 @@ def setUpClassApiKey(cls):
def test_authenticated_auth_api_key(self):
# An exception is raised when no api key is used
with self.assertRaises(HTTPException) as error:
- authenticated_auth_api_key(False, self.demo_env)
+ authenticated_auth_api_key(False, self.demo_env, self.demo_endpoint)
self.assertEqual(error.exception.detail, "No HTTP-API-KEY provided")
# An exception is raised when no api key record is found
with self.assertRaises(HTTPException) as error:
- authenticated_auth_api_key("404", self.demo_env)
- self.assertEqual(error.exception.detail, "The key 404 is not allowed")
+ authenticated_auth_api_key("404", self.demo_env, self.demo_endpoint)
+ self.assertEqual(error.exception.detail, ("The key 404 is not allowed",))
# TODO enable this when we know how to filter keys based
# on endpoint's api key group.
# An exception is raised when unauthorized api key record is found
# with self.assertRaises(HTTPException) as error:
# authenticated_auth_api_key("not_authorized", self.demo_env)
+ self.demo_endpoint.auth_api_key_group_id = (
+ self.authorized_api_key.auth_api_key_group_ids[0]
+ )
result_key = authenticated_auth_api_key(
- self.authorized_api_key.key, self.demo_env
+ self.authorized_api_key.key, self.demo_env, self.demo_endpoint
)
self.assertEqual(result_key, self.authorized_api_key)
diff --git a/fastapi_auth_api_key/views/fastapi_endpoint.xml b/fastapi_auth_api_key/views/fastapi_endpoint.xml
index bd8ba2a90..1005dd501 100644
--- a/fastapi_auth_api_key/views/fastapi_endpoint.xml
+++ b/fastapi_auth_api_key/views/fastapi_endpoint.xml
@@ -8,7 +8,7 @@
fastapi.endpoint
-
+
From 7c7b37c0cbcc150da650047cac762128a8eb95a8 Mon Sep 17 00:00:00 2001
From: Pierre Verkest
Date: Tue, 29 Jul 2025 11:11:20 +0200
Subject: [PATCH 4/5] [REF] fastapi_auth_api_key: review improvements
---
fastapi_auth_api_key/README.rst | 6 +--
fastapi_auth_api_key/__manifest__.py | 2 +-
fastapi_auth_api_key/dependencies.py | 24 +++++++-----
.../models/fastapi_endpoint.py | 5 ++-
.../test_fastapi_api_key_dependencies.py | 39 ++++++++++++-------
.../odoo/addons/fastapi_auth_api_key | 1 -
setup/fastapi_auth_api_key/setup.py | 6 ---
7 files changed, 48 insertions(+), 35 deletions(-)
delete mode 120000 setup/fastapi_auth_api_key/odoo/addons/fastapi_auth_api_key
delete mode 100644 setup/fastapi_auth_api_key/setup.py
diff --git a/fastapi_auth_api_key/README.rst b/fastapi_auth_api_key/README.rst
index f97f63c53..eb824b8ef 100644
--- a/fastapi_auth_api_key/README.rst
+++ b/fastapi_auth_api_key/README.rst
@@ -1,5 +1,5 @@
====================
-Fastapi Auth Api Key
+Fastapi Auth API Key
====================
..
@@ -95,8 +95,8 @@ Authors
Contributors
------------
-- Matthieu Méquignon
-- Son Ho
+- Matthieu Méquignon
+- Son Ho
Other credits
-------------
diff --git a/fastapi_auth_api_key/__manifest__.py b/fastapi_auth_api_key/__manifest__.py
index 539efdcc1..f6136a6fe 100644
--- a/fastapi_auth_api_key/__manifest__.py
+++ b/fastapi_auth_api_key/__manifest__.py
@@ -2,7 +2,7 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
{
- "name": "Fastapi Auth Api Key",
+ "name": "Fastapi Auth API Key",
"version": "17.0.1.0.0",
"category": "Others",
"website": "https://github.com/OCA/rest-framework",
diff --git a/fastapi_auth_api_key/dependencies.py b/fastapi_auth_api_key/dependencies.py
index aa1838ab0..390c93a37 100644
--- a/fastapi_auth_api_key/dependencies.py
+++ b/fastapi_auth_api_key/dependencies.py
@@ -1,9 +1,9 @@
# Copyright 2024 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
-
+import os
from typing import Annotated
-from odoo import SUPERUSER_ID
+from odoo import SUPERUSER_ID, _
from odoo.api import Environment
from odoo.exceptions import ValidationError
@@ -16,17 +16,20 @@
from fastapi.exceptions import HTTPException
from fastapi.security import APIKeyHeader
+HTTP_API_KEY_HEADER = os.environ.get("FASTAPI_AUTH_HTTP_API_KEY_HEADER", "HTTP-API-KEY")
+
def authenticated_auth_api_key(
- key: Annotated[str, Depends(APIKeyHeader(name="HTTP-API-KEY"))],
+ key: Annotated[str, Depends(APIKeyHeader(name=HTTP_API_KEY_HEADER))],
env: Annotated[Environment, Depends(odoo_env)],
endpoint: Annotated[FastapiEndpoint, Depends(fastapi_endpoint)],
) -> AuthApiKey:
if not key:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
- detail="No HTTP-API-KEY provided",
- headers={"WWW-Authenticate": "HTTP-API-KEY"},
+ detail=_("Missing %(HTTP_API_KEY_HEADER)s header")
+ % {"HTTP_API_KEY_HEADER": HTTP_API_KEY_HEADER},
+ headers={"WWW-Authenticate": HTTP_API_KEY_HEADER},
)
admin_env = Environment(env.cr, SUPERUSER_ID, {})
try:
@@ -35,14 +38,17 @@ def authenticated_auth_api_key(
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail=error.args,
- headers={"WWW-Authenticate": "HTTP-API-KEY"},
+ headers={"WWW-Authenticate": HTTP_API_KEY_HEADER},
) from error
# Ensure the api key is authorized for the current endpoint.
- if auth_api_key not in endpoint.sudo().auth_api_key_group_id.auth_api_key_ids:
+ if (
+ endpoint.sudo().auth_api_key_group_id
+ and auth_api_key not in endpoint.sudo().auth_api_key_group_id.auth_api_key_ids
+ ):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
- detail="Unauthorized",
- headers={"WWW-Authenticate": "HTTP-API-KEY"},
+ detail=_("Unauthorized"),
+ headers={"WWW-Authenticate": HTTP_API_KEY_HEADER},
)
return auth_api_key
diff --git a/fastapi_auth_api_key/models/fastapi_endpoint.py b/fastapi_auth_api_key/models/fastapi_endpoint.py
index 8da7ff66d..697717ff5 100644
--- a/fastapi_auth_api_key/models/fastapi_endpoint.py
+++ b/fastapi_auth_api_key/models/fastapi_endpoint.py
@@ -7,4 +7,7 @@
class FastapiEndpoint(models.Model):
_inherit = "fastapi.endpoint"
- auth_api_key_group_id = fields.Many2one("auth.api.key.group")
+ auth_api_key_group_id = fields.Many2one(
+ "auth.api.key.group",
+ help="If not set, all 'auth.api.key' are allowed to access to endpoints",
+ )
diff --git a/fastapi_auth_api_key/tests/test_fastapi_api_key_dependencies.py b/fastapi_auth_api_key/tests/test_fastapi_api_key_dependencies.py
index dde6088ca..54a297f2f 100644
--- a/fastapi_auth_api_key/tests/test_fastapi_api_key_dependencies.py
+++ b/fastapi_auth_api_key/tests/test_fastapi_api_key_dependencies.py
@@ -1,14 +1,14 @@
from odoo.tests import tagged
from odoo.tests.common import TransactionCase
-from fastapi.exceptions import HTTPException
-
-from ..dependencies import (
+from odoo.addons.fastapi_auth_api_key.dependencies import (
authenticated_auth_api_key,
authenticated_env_by_auth_api_key,
authenticated_partner_by_api_key,
)
+from fastapi.exceptions import HTTPException
+
@tagged("-at_install", "post_install")
class TestFastapiAuthApiKey(TransactionCase):
@@ -16,7 +16,6 @@ class TestFastapiAuthApiKey(TransactionCase):
def setUpClass(cls):
super().setUpClass()
cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True))
- # Is it valid? We need an env without superpowers
demo_user = cls.env.ref("base.user_demo")
cls.demo_env = demo_user.with_user(demo_user).env
cls.demo_endpoint = cls.env["fastapi.endpoint"].create(
@@ -68,29 +67,41 @@ def setUpClassApiKey(cls):
"auth_api_key_ids": [(6, 0, cls.authorized_api_key.ids)],
}
)
+ cls.demo_endpoint.auth_api_key_group_id = cls.authorized_api_key_group
- def test_authenticated_auth_api_key(self):
+ def test_authenticated_auth_api_key_no_api_key(self):
# An exception is raised when no api key is used
with self.assertRaises(HTTPException) as error:
authenticated_auth_api_key(False, self.demo_env, self.demo_endpoint)
- self.assertEqual(error.exception.detail, "No HTTP-API-KEY provided")
+ self.assertEqual(error.exception.detail, "Missing HTTP-API-KEY header")
+
+ def test_authenticated_auth_api_key_no_api_key_found(self):
# An exception is raised when no api key record is found
with self.assertRaises(HTTPException) as error:
authenticated_auth_api_key("404", self.demo_env, self.demo_endpoint)
self.assertEqual(error.exception.detail, ("The key 404 is not allowed",))
- # TODO enable this when we know how to filter keys based
- # on endpoint's api key group.
+
+ def test_authenticated_auth_api_key_unauthorized_key(self):
# An exception is raised when unauthorized api key record is found
- # with self.assertRaises(HTTPException) as error:
- # authenticated_auth_api_key("not_authorized", self.demo_env)
- self.demo_endpoint.auth_api_key_group_id = (
- self.authorized_api_key.auth_api_key_group_ids[0]
- )
+ with self.assertRaisesRegex(HTTPException, r"Unauthorized"):
+ authenticated_auth_api_key(
+ "unauthorized_key", self.demo_env, self.demo_endpoint
+ )
+
+ def test_authenticated_auth_api_key(self):
result_key = authenticated_auth_api_key(
- self.authorized_api_key.key, self.demo_env, self.demo_endpoint
+ "authorized_key", self.demo_env, self.demo_endpoint
)
self.assertEqual(result_key, self.authorized_api_key)
+ def test_authenticated_auth_api_key_without_group(self):
+ # test with no group set unauthorized is allow to access
+ self.demo_endpoint.auth_api_key_group_id = False
+ result_key = authenticated_auth_api_key(
+ "unauthorized_key", self.demo_env, self.demo_endpoint
+ )
+ self.assertEqual(result_key, self.unauthorized_api_key)
+
def test_authenticated_partner_by_api_key(self):
result_partner = authenticated_partner_by_api_key(self.authorized_api_key)
self.assertEqual(result_partner, self.authorized_user.partner_id)
diff --git a/setup/fastapi_auth_api_key/odoo/addons/fastapi_auth_api_key b/setup/fastapi_auth_api_key/odoo/addons/fastapi_auth_api_key
deleted file mode 120000
index 498f5ddb6..000000000
--- a/setup/fastapi_auth_api_key/odoo/addons/fastapi_auth_api_key
+++ /dev/null
@@ -1 +0,0 @@
-../../../../fastapi_auth_api_key
\ No newline at end of file
diff --git a/setup/fastapi_auth_api_key/setup.py b/setup/fastapi_auth_api_key/setup.py
deleted file mode 100644
index 28c57bb64..000000000
--- a/setup/fastapi_auth_api_key/setup.py
+++ /dev/null
@@ -1,6 +0,0 @@
-import setuptools
-
-setuptools.setup(
- setup_requires=['setuptools-odoo'],
- odoo_addon=True,
-)
From 4e547bcfe666c4842833e0beb038f6a3f5970ae4 Mon Sep 17 00:00:00 2001
From: Pierre Verkest
Date: Mon, 8 Sep 2025 14:41:20 +0200
Subject: [PATCH 5/5] [FIX] freeze graphql_server
---
graphql_base/README.rst | 28 +++++++++++-----------
graphql_base/__manifest__.py | 2 +-
graphql_base/static/description/index.html | 16 ++++++-------
requirements.txt | 2 +-
4 files changed, 24 insertions(+), 24 deletions(-)
diff --git a/graphql_base/README.rst b/graphql_base/README.rst
index 0b18d4bd2..6721d9a72 100644
--- a/graphql_base/README.rst
+++ b/graphql_base/README.rst
@@ -44,9 +44,9 @@ Usage
To use this module, you need to
-- create your graphene schema
-- create your controller to expose your GraphQL endpoint, and
- optionally a GraphiQL IDE.
+- create your graphene schema
+- create your controller to expose your GraphQL endpoint, and optionally
+ a GraphiQL IDE.
This module does not attempt to expose the whole Odoo object model. This
could be the purpose of another module based on this one. We believe
@@ -56,12 +56,12 @@ exposed and needs to be tested when upgrading Odoo.
To start working with this module, we recommend the following approach:
-- Learn `GraphQL basics `__
-- Learn `graphene `__, the python library
- used to create GraphQL schemas and resolvers.
-- Examine the ``graphql_demo`` module in this repo, copy it, adapt the
- controller to suit your needs (routes, authentication methods).
-- Start building your own schema and resolver.
+- Learn `GraphQL basics `__
+- Learn `graphene `__, the python library
+ used to create GraphQL schemas and resolvers.
+- Examine the ``graphql_demo`` module in this repo, copy it, adapt the
+ controller to suit your needs (routes, authentication methods).
+- Start building your own schema and resolver.
Building your schema
--------------------
@@ -71,11 +71,11 @@ The schema can be built using native graphene types. An
convenience. It is a graphene ``ObjectType`` with a default attribute
resolver which:
-- converts False to None (except for Boolean types), to avoid Odoo's
- weird ``False`` strings being rendered as json ``"false"``;
-- adds the user timezone to Datetime fields;
-- raises an error if an attribute is absent to avoid field name typing
- errors.
+- converts False to None (except for Boolean types), to avoid Odoo's
+ weird ``False`` strings being rendered as json ``"false"``;
+- adds the user timezone to Datetime fields;
+- raises an error if an attribute is absent to avoid field name typing
+ errors.
Creating GraphQL controllers
----------------------------
diff --git a/graphql_base/__manifest__.py b/graphql_base/__manifest__.py
index e4f3a1c38..756f5b763 100644
--- a/graphql_base/__manifest__.py
+++ b/graphql_base/__manifest__.py
@@ -11,7 +11,7 @@
"website": "https://github.com/OCA/rest-framework",
"depends": ["base"],
"data": ["views/graphiql.xml"],
- "external_dependencies": {"python": ["graphene", "graphql_server"]},
+ "external_dependencies": {"python": ["graphene", "graphql_server==3.0.0b7"]},
"development_status": "Production/Stable",
"maintainers": ["sbidoul"],
"installable": True,
diff --git a/graphql_base/static/description/index.html b/graphql_base/static/description/index.html
index b28702051..b55217acd 100644
--- a/graphql_base/static/description/index.html
+++ b/graphql_base/static/description/index.html
@@ -396,8 +396,8 @@
To use this module, you need to
- create your graphene schema
-- create your controller to expose your GraphQL endpoint, and
-optionally a GraphiQL IDE.
+- create your controller to expose your GraphQL endpoint, and optionally
+a GraphiQL IDE.
This module does not attempt to expose the whole Odoo object model. This
could be the purpose of another module based on this one. We believe
@@ -433,24 +433,24 @@
Creating GraphQL controllers<
odoo.addons.graphql_base.GraphQLControllerMixin class to help you
build GraphQL controllers providing GraphiQL and/or GraphQL endpoints.
-from odoo import http
-from odoo.addons.graphql_base import GraphQLControllerMixin
+from odoo import http
+from odoo.addons.graphql_base import GraphQLControllerMixin
-from ..schema import schema
+from ..schema import schema
-class GraphQLController(http.Controller, GraphQLControllerMixin):
+class GraphQLController(http.Controller, GraphQLControllerMixin):
# The GraphiQL route, providing an IDE for developers
@http.route("/graphiql/demo", auth="user")
- def graphiql(self, **kwargs):
+ def graphiql(self, **kwargs):
return self._handle_graphiql_request(schema)
# The graphql route, for applications.
# Note csrf=False: you may want to apply extra security
# (such as origin restrictions) to this route.
@http.route("/graphql/demo", auth="user", csrf=False)
- def graphql(self, **kwargs):
+ def graphql(self, **kwargs):
return self._handle_graphql_request(schema)
diff --git a/requirements.txt b/requirements.txt
index a4ccc4e88..de9981355 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -3,7 +3,7 @@ a2wsgi>=1.10.6
contextvars
fastapi>=0.110.0
graphene
-graphql_server
+graphql_server==3.0.0b7
parse-accept-language
pydantic
python-multipart