From 2a79bf497863ac3b1172c649a6d829161f4ef7bc Mon Sep 17 00:00:00 2001 From: imperosol Date: Sat, 25 Oct 2025 21:45:27 +0200 Subject: [PATCH] feat: api route to get api client infos --- api/api.py | 16 ++++++++++++++++ api/models.py | 38 ++++++++++++++++---------------------- api/schemas.py | 14 ++++++++++++++ 3 files changed, 46 insertions(+), 22 deletions(-) create mode 100644 api/api.py create mode 100644 api/schemas.py diff --git a/api/api.py b/api/api.py new file mode 100644 index 00000000..0475822e --- /dev/null +++ b/api/api.py @@ -0,0 +1,16 @@ +from ninja_extra import ControllerBase, api_controller, route + +from api.auth import ApiKeyAuth +from api.schemas import ApiClientSchema + + +@api_controller("/client") +class ApiClientController(ControllerBase): + @route.get( + "/me", + auth=[ApiKeyAuth()], + response=ApiClientSchema, + url_name="api-client-infos", + ) + def get_client_info(self): + return self.context.request.auth diff --git a/api/models.py b/api/models.py index 36e20287..4c802b55 100644 --- a/api/models.py +++ b/api/models.py @@ -2,6 +2,8 @@ from typing import Iterable from django.contrib.auth.models import Permission from django.db import models +from django.db.models import Q +from django.utils.functional import cached_property from django.utils.translation import gettext_lazy as _ from django.utils.translation import pgettext_lazy @@ -29,8 +31,6 @@ class ApiClient(models.Model): created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) - _perm_cache: set[str] | None = None - class Meta: verbose_name = _("api client") verbose_name_plural = _("api clients") @@ -38,29 +38,23 @@ class ApiClient(models.Model): def __str__(self): return self.name + @cached_property + def all_permissions(self) -> set[str]: + permissions = ( + Permission.objects.filter( + Q(group__group__in=self.groups.all()) | Q(clients=self) + ) + .values_list("content_type__app_label", "codename") + .order_by() + ) + return {f"{content_type}.{name}" for content_type, name in permissions} + def has_perm(self, perm: str): """Return True if the client has the specified permission.""" + return perm in self.all_permissions - if self._perm_cache is None: - group_permissions = ( - Permission.objects.filter(group__group__in=self.groups.all()) - .values_list("content_type__app_label", "codename") - .order_by() - ) - client_permissions = self.client_permissions.values_list( - "content_type__app_label", "codename" - ).order_by() - self._perm_cache = { - f"{content_type}.{name}" - for content_type, name in (*group_permissions, *client_permissions) - } - return perm in self._perm_cache - - def has_perms(self, perm_list): - """ - Return True if the client has each of the specified permissions. If - object is passed, check if the client has all required perms for it. - """ + def has_perms(self, perm_list: Iterable[str]) -> bool: + """Return True if the client has each of the specified permissions.""" if not isinstance(perm_list, Iterable) or isinstance(perm_list, str): raise ValueError("perm_list must be an iterable of permissions.") return all(self.has_perm(perm) for perm in perm_list) diff --git a/api/schemas.py b/api/schemas.py new file mode 100644 index 00000000..376e90a9 --- /dev/null +++ b/api/schemas.py @@ -0,0 +1,14 @@ +from ninja import ModelSchema +from pydantic import Field + +from api.models import ApiClient +from core.schemas import SimpleUserSchema + + +class ApiClientSchema(ModelSchema): + class Meta: + model = ApiClient + fields = ["id", "name"] + + owner: SimpleUserSchema + permissions: list[str] = Field(alias="all_permissions")