basyx's picture
Upload 340 files
3493993 verified
Raw
History Blame Contribute Delete
5.24 kB
from __future__ import annotations
from typing import Annotated
from fastapi import APIRouter, Depends, Header, Query, Request, status
from app.analytics.schemas import (
AnalyticsCapabilities,
AnalyticsOverview,
AnalyticsPostList,
AnalyticsQuery,
AnalyticsSyncList,
AnalyticsSyncRequest,
AnalyticsSyncRunView,
AnalyticsTimeseries,
)
router = APIRouter(prefix="/v1/analytics", tags=["analytics"])
def _identity(request: Request) -> tuple[str, str]:
context = request.state.auth
if not context.workspace_id or not context.user_id:
from fastapi import HTTPException
raise HTTPException(status_code=403, detail="No active workspace membership.")
return context.workspace_id, context.user_id
def _service(request: Request):
service = request.app.state.container.analytics
service.ensure_ready()
return service
@router.get("/capabilities", response_model=list[AnalyticsCapabilities])
async def capabilities(request: Request) -> list[AnalyticsCapabilities]:
return await _service(request).capabilities()
@router.get("/overview", response_model=AnalyticsOverview)
async def overview(
request: Request, query: Annotated[AnalyticsQuery, Depends()]
) -> AnalyticsOverview:
workspace_id, _ = _identity(request)
return await _service(request).overview(workspace_id, query)
@router.get("/timeseries", response_model=AnalyticsTimeseries)
async def timeseries(
request: Request, query: Annotated[AnalyticsQuery, Depends()]
) -> AnalyticsTimeseries:
workspace_id, _ = _identity(request)
return await _service(request).timeseries(workspace_id, query)
@router.get("/platforms", response_model=AnalyticsOverview)
async def platforms(
request: Request, query: Annotated[AnalyticsQuery, Depends()]
) -> AnalyticsOverview:
workspace_id, _ = _identity(request)
return await _service(request).overview(workspace_id, query)
@router.get("/platforms/{provider}", response_model=AnalyticsOverview)
async def platform(
request: Request,
provider: str,
query: Annotated[AnalyticsQuery, Depends()],
) -> AnalyticsOverview:
workspace_id, _ = _identity(request)
query.provider = provider
return await _service(request).overview(workspace_id, query)
@router.get("/posts", response_model=AnalyticsPostList)
async def posts(request: Request, query: Annotated[AnalyticsQuery, Depends()]) -> AnalyticsPostList:
workspace_id, _ = _identity(request)
return await _service(request).posts(workspace_id, query)
@router.get("/posts/{post_id}", response_model=AnalyticsPostList)
async def post(
request: Request,
post_id: str,
query: Annotated[AnalyticsQuery, Depends()],
) -> AnalyticsPostList:
workspace_id, _ = _identity(request)
return await _service(request).post(workspace_id, post_id, query)
@router.get("/projects/{project_id}", response_model=AnalyticsOverview)
async def project(
request: Request,
project_id: str,
query: Annotated[AnalyticsQuery, Depends()],
) -> AnalyticsOverview:
workspace_id, user_id = _identity(request)
await request.app.state.container.projects.get(
workspace_id=workspace_id, user_id=user_id, project_id=project_id
)
query.project_id = project_id
return await _service(request).overview(workspace_id, query)
@router.get("/sync-runs", response_model=AnalyticsSyncList)
async def sync_runs(
request: Request,
offset: int = Query(default=0, ge=0, le=100_000),
limit: int = Query(default=50, ge=1, le=500),
) -> AnalyticsSyncList:
workspace_id, _ = _identity(request)
items = await _service(request).repository.list_syncs(workspace_id, offset=offset, limit=limit)
return AnalyticsSyncList(
items=[_service(request)._sync_view(item) for item in items],
offset=offset,
limit=limit,
)
@router.get("/sync-runs/{run_id}", response_model=AnalyticsSyncRunView)
async def sync_run(request: Request, run_id: str) -> AnalyticsSyncRunView:
workspace_id, _ = _identity(request)
return _service(request)._sync_view(
await _service(request).repository.get_sync(workspace_id, run_id)
)
@router.post("/sync-runs/{run_id}/cancel", response_model=AnalyticsSyncRunView)
async def cancel_sync(request: Request, run_id: str) -> AnalyticsSyncRunView:
workspace_id, _ = _identity(request)
run = await _service(request).repository.cancel_sync(workspace_id, run_id)
await _service(request).audit.record(
workspace_id=workspace_id,
event_type="analytics.sync_cancelled",
metadata={"sync_run_id": run.id},
api_key_id=request.state.auth.api_key_id,
request_id=request.state.request_id,
)
return _service(request)._sync_view(run)
@router.post("/sync", response_model=AnalyticsSyncRunView, status_code=status.HTTP_202_ACCEPTED)
async def sync(
request: Request,
payload: AnalyticsSyncRequest,
idempotency_key: str | None = Header(default=None, alias="Idempotency-Key"),
) -> AnalyticsSyncRunView:
workspace_id, user_id = _identity(request)
if idempotency_key:
payload.idempotency_key = idempotency_key
return await _service(request).create_sync(workspace_id, user_id, payload)