HH/apps/integrations/authentication.py
ismail 7369d08012
All checks were successful
Build and Push Docker Image / build (push) Successful in 4m14s
feat: unified reference numbers + feedback modules QA audit
Reference numbers (unified scheme PREFIX-YYYYMM-HOSP-NNNN, e.g. CMP-202606-HHN-0001):
- new ReferenceSequence model + generate_reference() helper (apps/core)
- Complaint/Inquiry/Observation/Appreciation/Suggestion emit unified refs via save()
- prefix-based auto-routing in public track API (CMP/INQ/OBS trackable; APR/SGT internal-only)
- removed legacy CMP-/INQ- generators in ui_views, integrations, px_sources
- migrations: core.0003_referencesequence, appreciation.0006, feedback.0008, observations.0012
- unit tests (format, sanitization, monthly reset, 40-thread concurrency)

QA audit:
- isolated E2E hospital sandbox mirroring HH-N + 10 role users (create_e2e_isolated_env)
- feedback-modules-audit.spec.ts + audit helper (headed, run-to-completion)
- reports/feedback-modules-qa-report.md

Also bundles accumulated in-progress work across complaints, observations,
organizations, templates, and other modules.
2026-06-14 14:29:23 +03:00

47 lines
1.3 KiB
Python

"""
External API key authentication for DRF.
"""
import logging
from rest_framework import authentication, exceptions
logger = logging.getLogger("apps.integrations")
class ExternalAPIKeyAuthentication(authentication.BaseAuthentication):
"""
Authenticate requests using an API key passed via X-API-Key header.
Sets `request.api_key` on successful authentication for downstream use.
"""
HEADER_NAME = "HTTP_X_API_KEY"
def authenticate(self, request):
raw_key = request.META.get(self.HEADER_NAME)
if not raw_key:
raise exceptions.AuthenticationFailed("API key required. Provide X-API-Key header.")
from .models import ExternalAPIKey
# Look up by prefix to avoid scanning all keys
prefix = raw_key[:8]
candidates = ExternalAPIKey.objects.filter(
key_prefix=prefix,
is_active=True,
)
for api_key in candidates:
if api_key.verify(raw_key):
# Rate limit check
# (simple per-key check; could be enhanced with cache)
api_key.record_usage()
request.api_key = api_key
return (None, api_key)
raise exceptions.AuthenticationFailed("Invalid or expired API key.")
def authenticate_header(self, request):
return "X-API-Key"