Files
Magent/backend/app/routers/identities.py
T
Assclaw 6e473fd0a7
Magent CI/CD / verify (push) Canceled after 9m3s
Magent CI/CD / deploy-prod (push) Canceled after 0s
Magent CI/CD / deploy-beta (push) Canceled after 0s
Unify user management and add reviewed identity repairs
2026-09-10 16:06:30 +12:00

76 lines
2.8 KiB
Python

from fastapi import APIRouter, Depends, Response
from pydantic import BaseModel, ConfigDict, Field, field_validator
from ..auth import require_admin
from ..services.identity_review import confirm_identities, review_identities, resolve_identity, repair_identity
router = APIRouter(prefix="/admin/identities", tags=["admin"], dependencies=[Depends(require_admin)])
class Confirmation(BaseModel):
model_config = ConfigDict(extra="forbid")
revision: str = Field(pattern=r"^[a-f0-9]{64}$")
user_ids: list[int] = Field(min_length=1, max_length=3000)
@field_validator("user_ids")
@classmethod
def unique_positive_ids(cls, value):
if any(user_id <= 0 for user_id in value) or len(set(value)) != len(value):
raise ValueError("Choose unique positive user IDs")
return value
@router.get("")
async def review(response: Response):
response.headers["Cache-Control"] = "no-store"
report, _, _ = await review_identities()
return report
@router.post("/confirm")
async def confirm(payload: Confirmation, response: Response, admin: dict = Depends(require_admin)):
response.headers["Cache-Control"] = "no-store"
return await confirm_identities(payload.revision, payload.user_ids, admin)
class Resolution(BaseModel):
model_config = ConfigDict(extra="forbid")
user_id: int = Field(gt=0, strict=True)
jellyfin_user_id: str = Field(pattern=r"^[a-f0-9]{32}$")
class ResolutionConfirmation(Resolution):
revision: str = Field(pattern=r"^[a-f0-9]{64}$")
@router.post("/resolve/check")
async def check_resolution(payload: Resolution, response: Response):
response.headers["Cache-Control"] = "no-store"
return await resolve_identity(payload.user_id, payload.jellyfin_user_id)
@router.post("/resolve/confirm")
async def confirm_resolution(payload: ResolutionConfirmation, response: Response, admin: dict = Depends(require_admin)):
response.headers["Cache-Control"] = "no-store"
return await resolve_identity(payload.user_id, payload.jellyfin_user_id, payload.revision, admin)
class RepairResolution(Resolution):
create_seerr: bool = Field(default=False, strict=True)
class RepairConfirmation(RepairResolution):
revision: str = Field(pattern=r'^[a-f0-9]{64}$')
@router.post('/repair/check')
async def check_repair(payload: RepairResolution, response: Response):
response.headers['Cache-Control'] = 'no-store'
return await repair_identity(payload.user_id, payload.jellyfin_user_id, create_seerr=payload.create_seerr)
@router.post('/repair/confirm')
async def confirm_repair(payload: RepairConfirmation, response: Response, admin: dict = Depends(require_admin)):
response.headers['Cache-Control'] = 'no-store'
return await repair_identity(payload.user_id, payload.jellyfin_user_id, payload.revision, admin, payload.create_seerr)