"""辰正时态 API(设计 §10)。 挂载于 /api/v1/time。事件不走 REST(走 EventStore 订阅)。路由薄层:参数校验 → 调 service → 转响应;session 由 service 自管(deps.py 惯例)。 """ from fastapi import APIRouter, Depends, Request from app.api.v1.deps import get_current_user, get_event_store from app.core.config import settings from app.schemas.auth import CurrentUser from app.schemas.time import ( AcquaintanceResponse, AnniversaryCreateRequest, AnniversaryResponse, AnniversaryUpdateRequest, SnapshotResponse, TimeConfigResponse, ) from app.services.time_sense import ( create_anniversary_for_active, delete_anniversary_or_404, get_acquaintance_for_active, get_anniversary_or_404, get_live_snapshot, list_anniversaries_for_active, update_anniversary_or_404, ) router = APIRouter(prefix="/time", tags=["time"]) @router.get("/snapshot", response_model=SnapshotResponse) async def get_snapshot( request: Request, current_user: CurrentUser = Depends(get_current_user) ) -> SnapshotResponse: """当前 TemporalSnapshot + ModulationFactors + context_text。""" result = await get_live_snapshot(get_event_store(request), owner_scope=current_user.owner_scope) return SnapshotResponse( snapshot=result.snapshot, factors=result.factors, context_text=result.context_text, ) @router.get("/anniversaries", response_model=list[AnniversaryResponse]) async def list_anniversaries_api( current_user: CurrentUser = Depends(get_current_user), ) -> list[AnniversaryResponse]: items = await list_anniversaries_for_active(owner_scope=current_user.owner_scope) return [AnniversaryResponse.model_validate(a) for a in items] @router.post("/anniversaries", response_model=AnniversaryResponse, status_code=201) async def create_anniversary_api( payload: AnniversaryCreateRequest, current_user: CurrentUser = Depends(get_current_user) ) -> AnniversaryResponse: created = await create_anniversary_for_active(payload, owner_scope=current_user.owner_scope) return AnniversaryResponse.model_validate(created) @router.get("/anniversaries/{anniv_id}", response_model=AnniversaryResponse) async def get_anniversary_api( anniv_id: str, current_user: CurrentUser = Depends(get_current_user) ) -> AnniversaryResponse: return AnniversaryResponse.model_validate( await get_anniversary_or_404(anniv_id, owner_scope=current_user.owner_scope) ) @router.patch("/anniversaries/{anniv_id}", response_model=AnniversaryResponse) async def update_anniversary_api( anniv_id: str, payload: AnniversaryUpdateRequest, current_user: CurrentUser = Depends(get_current_user), ) -> AnniversaryResponse: return AnniversaryResponse.model_validate( await update_anniversary_or_404(anniv_id, payload, owner_scope=current_user.owner_scope) ) @router.delete("/anniversaries/{anniv_id}", status_code=204) async def delete_anniversary_api( anniv_id: str, current_user: CurrentUser = Depends(get_current_user) ) -> None: await delete_anniversary_or_404(anniv_id, owner_scope=current_user.owner_scope) @router.get("/acquaintance", response_model=AcquaintanceResponse) async def get_acquaintance_api( request: Request, current_user: CurrentUser = Depends(get_current_user) ) -> AcquaintanceResponse: acq = await get_acquaintance_for_active( get_event_store(request), owner_scope=current_user.owner_scope ) return AcquaintanceResponse(total_days=acq.total_days, natural_language=acq.natural_language) @router.get("/config", response_model=TimeConfigResponse) async def get_time_config_api( current_user: CurrentUser = Depends(get_current_user), # noqa: ARG001 ) -> TimeConfigResponse: return TimeConfigResponse( user_timezone=settings.user_timezone, home_timezone=settings.home_timezone, default_city=settings.default_city, offline_active_minutes=settings.offline_active_minutes, offline_short_absence_minutes=settings.offline_short_absence_minutes, offline_long_absence_minutes=settings.offline_long_absence_minutes, offline_reunion_impact_minutes=settings.offline_reunion_impact_minutes, care_enabled=settings.care_enabled, jetlag_threshold_minutes=settings.jetlag_threshold_minutes, )