"""Authenticated catalog endpoints; writes inherit the application origin guard.""" from typing import Annotated from fastapi import APIRouter, Depends, Query, Request from ..schemas import JobOutput from ..security import require_auth from .contracts import ( CatalogFilters, CatalogJobInput, CatalogPage, CollectionOutput, EntryOutput, NoteInput, NoteOutput, Scope, ) from .platform import platform_options, validate_platform_scope from .service import Catalog router = APIRouter(prefix="/api/v1/catalog", tags=["catalog"], dependencies=[Depends(require_auth)]) @router.get("/scopes") async def scopes(request: Request): return await platform_options(request.app.state.runner.client) @router.get("/datasets", response_model=CatalogPage) async def datasets(request: Request, filters: Annotated[CatalogFilters, Query()]): async with request.app.state.sessions() as db: return await Catalog(db).search(filters) @router.get("/datasets/{dataset_id}", response_model=EntryOutput) async def detail(request: Request, dataset_id: str, scope: Annotated[Scope, Query()]): async with request.app.state.sessions() as db: return await Catalog(db).detail(scope, dataset_id) @router.get("/datasets/{dataset_id}/fields", response_model=CatalogPage) async def fields(request: Request, dataset_id: str, filters: Annotated[CatalogFilters, Query()]): async with request.app.state.sessions() as db: return await Catalog(db).search(filters, dataset_id) @router.get("/datasets/{dataset_id}/fields/{field_id}", response_model=EntryOutput) async def field(request: Request, dataset_id: str, field_id: str, scope: Annotated[Scope, Query()]): async with request.app.state.sessions() as db: return await Catalog(db).detail(scope, dataset_id, field_id) @router.patch("/datasets/{dataset_id}/research", response_model=NoteOutput) async def note(request: Request, dataset_id: str, scope: Annotated[Scope, Query()], body: NoteInput): async with request.app.state.sessions.begin() as db: return await Catalog(db).save_note(scope, dataset_id, "", body) @router.patch("/datasets/{dataset_id}/fields/{field_id}/research", response_model=NoteOutput) async def field_note( request: Request, dataset_id: str, field_id: str, scope: Annotated[Scope, Query()], body: NoteInput ): async with request.app.state.sessions.begin() as db: return await Catalog(db).save_note(scope, dataset_id, field_id, body) @router.post("/sync-jobs", status_code=202, response_model=JobOutput) async def sync(request: Request, body: CatalogJobInput): await validate_platform_scope(request.app.state.runner.client, body.scope) async with request.app.state.sessions.begin() as db: result = await Catalog(db).create_job(body) request.app.state.runner.wake.set() return result @router.get("/datasets/{dataset_id}/collection", response_model=CollectionOutput) async def collection(request: Request, dataset_id: str, scope: Annotated[Scope, Query()]): async with request.app.state.sessions() as db: return await Catalog(db).collection(scope, dataset_id)