"""Initiative (Vorhaben) API — AP0.5.""" from __future__ import annotations from typing import Literal, Optional from capabilities import require_capability from fastapi import APIRouter, Depends, HTTPException from pydantic import BaseModel, Field from services import actions as action_service from services import initiatives as initiative_service from tenant_context import TenantContext router = APIRouter(prefix="/api/initiatives", tags=["initiatives"]) class InitiativeCreateRequest(BaseModel): title: str = Field(min_length=1, max_length=255) goal: str = "" status: Literal["active", "paused", "completed", "archived"] = "active" priority: Literal["low", "normal", "high"] = "normal" owner_actor_id: Optional[str] = None class InitiativeUpdateRequest(BaseModel): title: Optional[str] = Field(default=None, min_length=1, max_length=255) goal: Optional[str] = None status: Optional[Literal["active", "paused", "completed", "archived"]] = None priority: Optional[Literal["low", "normal", "high"]] = None owner_actor_id: Optional[str] = None class ActionCreateRequest(BaseModel): title: str = Field(min_length=1, max_length=255) description: str = "" status: Literal["open", "in_progress", "blocked", "done", "discarded"] = "open" priority: Literal["low", "normal", "high"] = "normal" assigned_actor_ids: list[str] = Field(default_factory=list) @router.get("") def list_initiatives( ctx: TenantContext = Depends(require_capability("kairo.initiative.read")), ): return initiative_service.list_initiatives(tenant_id=ctx.tenant_id) @router.post("", status_code=201) def create_initiative( body: InitiativeCreateRequest, ctx: TenantContext = Depends(require_capability("kairo.initiative.manage")), ): owner_actor_id = body.owner_actor_id or ctx.actor_id if not owner_actor_id: raise HTTPException(status_code=400, detail="Kein Actor im TenantContext") try: return initiative_service.create_initiative( tenant_id=ctx.tenant_id, title=body.title, goal=body.goal, status=body.status, priority=body.priority, owner_actor_id=owner_actor_id, user_id=ctx.user_id, ) except ValueError as exc: raise HTTPException(status_code=400, detail=str(exc)) from exc @router.get("/{initiative_id}") def get_initiative( initiative_id: str, ctx: TenantContext = Depends(require_capability("kairo.initiative.read")), ): item = initiative_service.get_initiative( tenant_id=ctx.tenant_id, initiative_id=initiative_id ) if not item: raise HTTPException(status_code=404, detail="Vorhaben nicht gefunden") return item @router.patch("/{initiative_id}") def update_initiative( initiative_id: str, body: InitiativeUpdateRequest, ctx: TenantContext = Depends(require_capability("kairo.initiative.manage")), ): try: item = initiative_service.update_initiative( tenant_id=ctx.tenant_id, initiative_id=initiative_id, user_id=ctx.user_id, title=body.title, goal=body.goal, status=body.status, priority=body.priority, owner_actor_id=body.owner_actor_id, ) except ValueError as exc: raise HTTPException(status_code=400, detail=str(exc)) from exc if not item: raise HTTPException(status_code=404, detail="Vorhaben nicht gefunden") return item @router.delete("/{initiative_id}", status_code=204) def delete_initiative( initiative_id: str, ctx: TenantContext = Depends(require_capability("kairo.initiative.manage")), ): if not initiative_service.delete_initiative( tenant_id=ctx.tenant_id, initiative_id=initiative_id, user_id=ctx.user_id, ): raise HTTPException(status_code=404, detail="Vorhaben nicht gefunden") @router.get("/{initiative_id}/actions") def list_initiative_actions( initiative_id: str, ctx: TenantContext = Depends(require_capability("kairo.action.read")), ): if not initiative_service.get_initiative( tenant_id=ctx.tenant_id, initiative_id=initiative_id ): raise HTTPException(status_code=404, detail="Vorhaben nicht gefunden") return action_service.list_actions_for_initiative( tenant_id=ctx.tenant_id, initiative_id=initiative_id ) @router.post("/{initiative_id}/actions", status_code=201) def create_initiative_action( initiative_id: str, body: ActionCreateRequest, ctx: TenantContext = Depends(require_capability("kairo.action.manage")), ): try: return action_service.create_action( tenant_id=ctx.tenant_id, initiative_id=initiative_id, title=body.title, description=body.description, status=body.status, priority=body.priority, assigned_actor_ids=body.assigned_actor_ids, user_id=ctx.user_id, ) except ValueError as exc: detail = str(exc) if detail == "Initiative nicht gefunden": raise HTTPException(status_code=404, detail=detail) from exc raise HTTPException(status_code=400, detail=detail) from exc