"""插件域路由(WP-07)。""" from typing import Annotated, Any from fastapi import APIRouter, Depends, Request from sqlalchemy import select from app.auth.dependencies import get_current_user, require_state_change from app.conversations.routes import _domain_of from app.db.session import DbSession from app.models import Plugin, PluginVersion, User from app.plugins import service router = APIRouter(prefix="/v1/plugins", tags=["plugins"]) def _plugin_out(p: Plugin) -> dict[str, Any]: return { "name": p.name, "kind": p.kind, "status": p.status, "publisher_domain_id": p.publisher_domain_id, } def _version_out(v: PluginVersion) -> dict[str, Any]: return { "id": v.id, "plugin_name": v.plugin_name, "version": v.version, "manifest": v.manifest, "content_hash": v.content_hash, "status": v.status, } def _installation_out(i: Any) -> dict[str, Any]: return { "id": i.id, "plugin_name": i.plugin_name, "version_id": i.version_id, "enabled": i.enabled, "granted_permissions": i.granted_permissions, } @router.post("/versions", status_code=201) async def publish( db: DbSession, user: Annotated[User, Depends(require_state_change)], request: Request, body: dict[str, Any], ) -> dict[str, Any]: domain = await _domain_of(db, user) _, pv = await service.publish_version( db, domain.id, body, getattr(request.state, "trace_id", None) ) return _version_out(pv) @router.get("") async def list_plugins( db: DbSession, user: Annotated[User, Depends(get_current_user)] ) -> dict[str, Any]: rows = list( ( await db.scalars( select(Plugin).where(Plugin.status == "published").limit(50) ) ).all() ) return {"data": [_plugin_out(p) for p in rows]} @router.post("/{name}/withdrawals") async def withdraw( name: str, db: DbSession, user: Annotated[User, Depends(require_state_change)], request: Request, ) -> dict[str, Any]: domain = await _domain_of(db, user) plugin = await service.withdraw( db, domain.id, name, getattr(request.state, "trace_id", None) ) return _plugin_out(plugin) @router.post("/{name}/installations", status_code=201) async def install( name: str, db: DbSession, user: Annotated[User, Depends(require_state_change)], request: Request, body: dict[str, str], ) -> dict[str, Any]: domain = await _domain_of(db, user) installation = await service.install( db, domain.id, name, body.get("version", ""), getattr(request.state, "trace_id", None), ) return _installation_out(installation) inst_router = APIRouter(prefix="/v1/plugin-installations", tags=["plugins"]) @inst_router.post("/{installation_id}/enablings", status_code=201) async def enable( installation_id: str, db: DbSession, user: Annotated[User, Depends(require_state_change)], request: Request, body: dict[str, Any], ) -> dict[str, Any]: domain = await _domain_of(db, user) installation = await service.enable( db, domain.id, installation_id, body.get("granted_permissions", []), getattr(request.state, "trace_id", None), ) return _installation_out(installation) @inst_router.post("/{installation_id}/upgrades", status_code=201) async def upgrade( installation_id: str, db: DbSession, user: Annotated[User, Depends(require_state_change)], request: Request, body: dict[str, Any], ) -> dict[str, Any]: domain = await _domain_of(db, user) installation = await service.upgrade( db, domain.id, installation_id, body.get("version", ""), body.get("granted_permissions"), getattr(request.state, "trace_id", None), ) return _installation_out(installation) invoke_router = APIRouter(prefix="/v1/plugins", tags=["plugins"]) @invoke_router.post("/{name}/invocations") async def invoke( name: str, db: DbSession, user: Annotated[User, Depends(require_state_change)], request: Request, body: dict[str, Any], ) -> dict[str, Any]: domain = await _domain_of(db, user) return await service.invoke( db, domain.id, name, body.get("input", {}), body.get("run_id"), getattr(request.state, "trace_id", None), )