From cfbe2a7fe025cbf476f3ba1ada33ef3dcdcdbd35 Mon Sep 17 00:00:00 2001 From: CREDO23 Date: Wed, 27 May 2026 15:30:45 +0200 Subject: [PATCH] feat(automations): expose POST /automations/{id}/run --- surfsense_backend/app/routes/__init__.py | 2 + .../app/routes/automations_routes.py | 55 +++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 surfsense_backend/app/routes/automations_routes.py diff --git a/surfsense_backend/app/routes/__init__.py b/surfsense_backend/app/routes/__init__.py index ec4d1650f..1d3ca2141 100644 --- a/surfsense_backend/app/routes/__init__.py +++ b/surfsense_backend/app/routes/__init__.py @@ -7,6 +7,7 @@ from .agent_revert_route import router as agent_revert_router from .airtable_add_connector_route import ( router as airtable_add_connector_router, ) +from .automations_routes import router as automations_router from .chat_comments_routes import router as chat_comments_router from .circleback_webhook_route import router as circleback_webhook_router from .clickup_add_connector_route import router as clickup_add_connector_router @@ -119,3 +120,4 @@ router.include_router(youtube_router) # YouTube playlist resolution router.include_router(prompts_router) router.include_router(memory_router) # User personal memory (memory.md style) router.include_router(team_memory_router) # Search-space team memory +router.include_router(automations_router) # Automations (manual run-now) diff --git a/surfsense_backend/app/routes/automations_routes.py b/surfsense_backend/app/routes/automations_routes.py new file mode 100644 index 000000000..02c019625 --- /dev/null +++ b/surfsense_backend/app/routes/automations_routes.py @@ -0,0 +1,55 @@ +"""Routes for automations. v1: manual ``Run now``.""" + +from __future__ import annotations + +from typing import Any + +from fastapi import APIRouter, Body, Depends, HTTPException +from sqlalchemy import select +from sqlalchemy.ext.asyncio import AsyncSession + +from app.automations.dispatch import DispatchError, dispatch_manual_run +from app.automations.persistence.models.automation import Automation +from app.db import Permission, User, get_async_session +from app.users import current_active_user +from app.utils.rbac import check_permission + +router = APIRouter() + + +@router.post("/automations/{automation_id}/run") +async def run_automation_now( + automation_id: int, + payload: dict[str, Any] | None = Body(default=None), + session: AsyncSession = Depends(get_async_session), + user: User = Depends(current_active_user), +) -> dict[str, Any]: + """Fire an automation manually. Returns the new run id and status.""" + search_space_id = ( + await session.execute( + select(Automation.search_space_id).where(Automation.id == automation_id) + ) + ).scalar_one_or_none() + if search_space_id is None: + raise HTTPException( + status_code=404, detail=f"automation {automation_id} not found" + ) + + await check_permission( + session, + user, + search_space_id, + Permission.AUTOMATIONS_EXECUTE.value, + "You don't have permission to execute automations in this search space", + ) + + try: + run = await dispatch_manual_run( + session=session, + automation_id=automation_id, + payload=payload, + ) + except DispatchError as exc: + raise HTTPException(status_code=422, detail=str(exc)) from exc + + return {"run_id": run.id, "status": run.status.value}