gendesign/backend/app/api/v1/admin_jobs.py
lekss361 389fd31fad
refactor(admin): extract _check_token into shared AdminTokenAuth dep (#133)
Per audit batch #127 P2 hygiene (issue #128).

## Problem

Identical `_check_token` function в 3 admin files:
- backend/app/api/v1/admin_scrape.py:37-44
- backend/app/api/v1/admin_leads.py:26-33
- backend/app/api/v1/admin_jobs.py:24-31

## Fix

New `backend/app/core/deps.py` с `verify_admin_token` + Annotated alias:
```python
AdminTokenAuth = Annotated[None, Depends(verify_admin_token)]
```

Заменено в 27 endpoints (18 admin_scrape + 6 admin_leads + 3 admin_jobs):
- Removed local `_check_token` definitions
- `_: None = Depends(_check_token)` → `_: AdminTokenAuth`
- Removed unused imports (`Header`, `HTTPException`, `settings` где не используется)

## Semantics preserved

Все 3 original implementations были identical (503 if env missing + 401 if
mismatch, same header `X-Admin-Token`, same env `SCRAPE_ADMIN_TOKEN`).

Минор: 503 detail text unified to `"admin disabled — set SCRAPE_ADMIN_TOKEN"`
(в оригинале три разные строки — `"admin scrape disabled..."` etc).
Cosmetic — detail в HTTP 503 не парсится клиентским кодом.

## Tests

`uv run pytest tests/ -x -k admin` → 64/64 passed.

## Vault

`code/patterns/Pattern_Admin_Token_Dependency_May14.md` — created.

Closes #128
Refs: #127

Co-authored-by: lekss361 <claudestars@proton.me>
2026-05-14 23:45:44 +03:00

76 lines
2.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Admin API для централизованных настроек Celery-job'ов.
GET /api/v1/admin/jobs/settings — список всех job_settings
GET /api/v1/admin/jobs/settings/{type} — одна строка по job_type
PUT /api/v1/admin/jobs/settings/{type} — PATCH-style update
Auth: X-Admin-Token header (тот же токен что у admin_scrape endpoints).
"""
from __future__ import annotations
from typing import Annotated, Any
from fastapi import APIRouter, Depends
from sqlalchemy.orm import Session
from app.core.db import get_db
from app.core.deps import AdminTokenAuth
from app.schemas.job_settings import JobSettingRead, JobSettingUpdate
router = APIRouter()
@router.get("/settings", response_model=list[JobSettingRead])
def list_job_settings(
db: Annotated[Session, Depends(get_db)],
_: AdminTokenAuth,
) -> Any:
"""Список всех job_settings (все job_type)."""
from app.services.job_settings import get_all
return get_all(db)
@router.get("/settings/{job_type}", response_model=JobSettingRead)
def get_job_setting(
job_type: str,
db: Annotated[Session, Depends(get_db)],
_: AdminTokenAuth,
) -> Any:
"""Настройки одного job_type. Возвращает fallback defaults если строки нет в БД."""
from app.services.job_settings import get_one
return get_one(job_type, db)
@router.put("/settings/{job_type}", response_model=JobSettingRead)
def update_job_setting(
job_type: str,
payload: JobSettingUpdate,
db: Annotated[Session, Depends(get_db)],
_: AdminTokenAuth,
) -> Any:
"""PATCH-style update: передавать только изменяемые поля.
После изменения cron_schedule нужен restart beat-контейнера.
Остальные поля (rate_ms, extra_config, enabled) применяются динамически.
cron_schedule='' устанавливает NULL (manual-only режим).
rate_ms=0 устанавливает NULL (no throttle).
"""
from app.services.job_settings import update
result = update(
job_type,
db,
enabled=payload.enabled,
queue_name=payload.queue_name,
cron_schedule=payload.cron_schedule,
rate_ms=payload.rate_ms,
max_retries=payload.max_retries,
max_concurrency=payload.max_concurrency,
extra_config=payload.extra_config,
updated_by="admin-ui",
)
return result