diff --git a/ChangeLog.rst b/ChangeLog.rst index a7ca9808d5..9440b1beeb 100644 --- a/ChangeLog.rst +++ b/ChangeLog.rst @@ -14,6 +14,9 @@ Note worthy changes specification will be served dynamically, over at ``/_allauth/openapi.yaml``, ``/_allauth/openapi.json`` and ``/_allauth/docs``. +- Headless: added a new setting, ``HEADLESS_CLIENTS`` which you can use to limit + the types of API clientsx (app/browser). + 65.3.1 (2025-12-25) ******************* diff --git a/allauth/headless/app_settings.py b/allauth/headless/app_settings.py index d35d346d6b..5b22d7712d 100644 --- a/allauth/headless/app_settings.py +++ b/allauth/headless/app_settings.py @@ -1,3 +1,6 @@ +from typing import Tuple + + class AppSettings: def __init__(self, prefix): self.prefix = prefix @@ -27,6 +30,10 @@ def TOKEN_STRATEGY(self): def SERVE_SPECIFICATION(self): return self._setting("SERVE_SPECIFICATION", False) + @property + def CLIENTS(self) -> Tuple[str]: + return tuple(self._setting("CLIENTS", ("browser", "app"))) + @property def FRONTEND_URLS(self): return self._setting("FRONTEND_URLS", {}) diff --git a/allauth/headless/spec/internal/schema.py b/allauth/headless/spec/internal/schema.py index d874736a96..d8d60b49b2 100644 --- a/allauth/headless/spec/internal/schema.py +++ b/allauth/headless/spec/internal/schema.py @@ -3,6 +3,8 @@ from django.urls import resolve, reverse from django.urls.exceptions import Resolver404 +from allauth.headless import app_settings + def get_schema() -> dict: import yaml @@ -18,13 +20,14 @@ def get_schema() -> dict: spec["info"]["description"] = description chroot(spec) + pin_client(spec) used_tags = drop_unused_paths(spec) drop_unused_tags(spec, used_tags) drop_unused_tag_groups(spec, used_tags) return spec -def chroot(spec): +def chroot(spec: dict) -> None: url = reverse("headless:openapi_yaml") root = url.rpartition("/")[0] paths = spec["paths"].items() @@ -34,12 +37,23 @@ def chroot(spec): spec["paths"][new_path] = path_spec -def drop_unused_paths(spec): +def pin_client(spec: dict) -> None: + if len(app_settings.CLIENTS) != 1: + return + client = app_settings.CLIENTS[0] + paths = spec["paths"].items() + spec["paths"] = {} + for path, path_spec in paths: + new_path = path.replace("{client}", client) + spec["paths"][new_path] = path_spec + + +def drop_unused_paths(spec: dict) -> set: paths = spec["paths"] used_tags = set() for path, path_spec in list(paths.items()): found_path = False - for client in ["browser", "app"]: + for client in app_settings.CLIENTS: try: resolve(path.replace("{client}", client)) found_path = True @@ -54,7 +68,7 @@ def drop_unused_paths(spec): return used_tags -def drop_unused_tags(spec, used_tags): +def drop_unused_tags(spec: dict, used_tags: set) -> None: tags = spec["tags"] spec["tags"] = [] for tag in tags: @@ -63,7 +77,7 @@ def drop_unused_tags(spec, used_tags): spec["tags"].append(tag) -def drop_unused_tag_groups(spec, used_tags): +def drop_unused_tag_groups(spec: dict, used_tags: set) -> None: tag_groups = spec["x-tagGroups"] spec["x-tagGroups"] = [] for tag_group in tag_groups: diff --git a/allauth/headless/urls.py b/allauth/headless/urls.py index 821faf9649..a3e78c6ac5 100644 --- a/allauth/headless/urls.py +++ b/allauth/headless/urls.py @@ -62,19 +62,24 @@ def build_urlpatterns(client): app_name = "headless" -urlpatterns = [ - path( - "browser/", - include( - (build_urlpatterns(Client.BROWSER), "headless"), - namespace="browser", - ), - ), - path( - "app/", - include((build_urlpatterns(Client.APP), "headless"), namespace="app"), - ), -] +urlpatterns = [] +if Client.BROWSER in app_settings.CLIENTS: + urlpatterns.append( + path( + "browser/", + include( + (build_urlpatterns(Client.BROWSER), "headless"), + namespace="browser", + ), + ) + ) +if Client.APP in app_settings.CLIENTS: + urlpatterns.append( + path( + "app/", + include((build_urlpatterns(Client.APP), "headless"), namespace="app"), + ) + ) if app_settings.SERVE_SPECIFICATION: urlpatterns.append( diff --git a/docs/headless/configuration.rst b/docs/headless/configuration.rst index f353886de2..a5cf23a64d 100644 --- a/docs/headless/configuration.rst +++ b/docs/headless/configuration.rst @@ -7,6 +7,10 @@ Available settings: Specifies the adapter class to use, allowing you to alter certain default behaviour. +``HEADLESS_CLIENTS`` (default: ``("app", "browser")``) + Specificies the supported types of clients for the API. Setting this to + e.g. `("app",)` will remove all `"browser"` related endpoints. + ``HEADLESS_FRONTEND_URLS`` (default: ``{}``) Email confirmation and password reset mails contain links that by default point to the views from the ``allauth.account`` app. In case you need to point these to your own frontend