Enhancement: Enhanced Swagger UI authorization dialog: registered a custom OpenApiAuthenticationExtension for ApiKeyAuthentication so drf-spectacular now generates an ApiKeyAuth (apiKey) entry alongside jwtAuth. Both entries include descriptive text linking to the relevant endpoints (/api/accounts/token/, /api/accounts/api-keys/generate/, /api/accounts/api-keys/revoke/).

This commit is contained in:
SergeantPanda 2026-04-10 18:29:13 -05:00
parent f83523cfa2
commit e861fca092
3 changed files with 38 additions and 11 deletions

View file

@ -48,6 +48,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
- Enhanced Swagger UI authorization dialog: registered a custom `OpenApiAuthenticationExtension` for `ApiKeyAuthentication` so drf-spectacular now generates an `ApiKeyAuth (apiKey)` entry alongside `jwtAuth`. Both entries include descriptive text linking to the relevant endpoints (`/api/accounts/token/`, `/api/accounts/api-keys/generate/`, `/api/accounts/api-keys/revoke/`).
- Refactored frontend form components (`AccountInfoModal`, `AssignChannelNumbers`, `Channel`, `ChannelBatch`, `ChannelGroup`, `Connection`, `CronBuilder`, `DummyEPG`, and `EPG`) to extract business logic into dedicated utility modules under `src/utils/forms/`. Each extracted module is covered by unit tests. Mantine compound component references (`Table.Tbody`, `Popover.Target`, `Accordion.Item`, etc.) have been updated to use flat named imports. — Thanks [@nick4810](https://github.com/nick4810)
- Improved the EPG BOM fix from v0.22.1: replaced the `lstrip(b'\xef\xbb\xbf')` / `startswith` approach with `start.find(b'<?xml')`, which locates the XML declaration regardless of any leading bytes BOM, whitespace, or other encoding markers without needing to know what those bytes are.
- Dependency updates:

View file

@ -1,9 +1,46 @@
from rest_framework import authentication
from rest_framework import exceptions
from django.conf import settings
from drf_spectacular.extensions import OpenApiAuthenticationExtension
from .models import User
class JWTAuthenticationScheme(OpenApiAuthenticationExtension):
target_class = "rest_framework_simplejwt.authentication.JWTAuthentication"
name = "jwtAuth"
def get_security_definition(self, auto_schema):
return {
"type": "http",
"scheme": "bearer",
"bearerFormat": "JWT",
"description": (
"JWT Bearer authentication.\n\n"
"Obtain a token pair via `POST /api/accounts/token/` using your username and password, "
"then paste the **access token** here — Swagger adds the `Bearer ` prefix automatically.\n\n"
"Access tokens expire after 30 minutes. Refresh using `POST /api/accounts/token/refresh/`."
),
}
class ApiKeyAuthenticationScheme(OpenApiAuthenticationExtension):
target_class = "apps.accounts.authentication.ApiKeyAuthentication"
name = "ApiKeyAuth"
def get_security_definition(self, auto_schema):
return {
"type": "apiKey",
"in": "header",
"name": "X-API-Key",
"description": (
"API key authentication.\n\n"
"Pass your personal API key in the `X-API-Key` request header. "
"Keys can be generated via `POST /api/accounts/api-keys/generate/` "
"and revoked via `POST /api/accounts/api-keys/revoke/`."
),
}
class ApiKeyAuthentication(authentication.BaseAuthentication):
"""
Accepts header `Authorization: ApiKey <key>` or `X-API-Key: <key>`.

View file

@ -280,17 +280,6 @@ SPECTACULAR_SETTINGS = {
"DESCRIPTION": "API documentation for Dispatcharr",
"VERSION": "1.0.0",
"SERVE_INCLUDE_SCHEMA": False,
"SECURITY": [{"BearerAuth": []}],
"COMPONENTS": {
"securitySchemes": {
"BearerAuth": {
"type": "http",
"scheme": "bearer",
"bearerFormat": "JWT",
"description": "Enter your JWT access token. The 'Bearer ' prefix is added automatically.",
}
}
},
}
LANGUAGE_CODE = "en-us"