Skip to main content

routa_server/api/
webhooks.rs

1//! Webhooks API - /api/webhooks
2//!
3//! REST endpoints for managing webhook configurations and handling incoming webhook events.
4//! In the desktop mode, webhooks are stored in-memory as config stubs.
5//!
6//! GET/POST/PUT/DELETE /api/webhooks/configs     - Manage webhook configurations
7//! GET/POST            /api/webhooks/github       - List / handle GitHub webhook events
8//! GET/POST/DELETE     /api/webhooks/register     - Register / unregister webhooks
9//! GET                 /api/webhooks/webhook-logs - List webhook delivery logs
10
11use axum::{extract::Query, routing::get, Json, Router};
12use serde::Deserialize;
13
14use crate::state::AppState;
15
16pub fn router() -> Router<AppState> {
17    Router::new()
18        .route(
19            "/configs",
20            get(list_configs)
21                .post(create_config)
22                .put(update_config)
23                .delete(delete_config),
24        )
25        .route(
26            "/github",
27            get(list_github_webhooks).post(handle_github_event),
28        )
29        .route(
30            "/register",
31            get(list_registrations)
32                .post(register_webhook)
33                .delete(unregister_webhook),
34        )
35        .route("/webhook-logs", get(list_logs))
36}
37
38// ─── Configs ──────────────────────────────────────────────────────────────────
39
40#[derive(Debug, Deserialize)]
41#[serde(rename_all = "camelCase")]
42#[allow(dead_code)]
43struct WebhookQuery {
44    workspace_id: Option<String>,
45    limit: Option<usize>,
46}
47
48async fn list_configs(Query(_q): Query<WebhookQuery>) -> Json<serde_json::Value> {
49    Json(serde_json::json!({ "configs": [] }))
50}
51
52async fn create_config(Json(body): Json<serde_json::Value>) -> Json<serde_json::Value> {
53    Json(serde_json::json!({
54        "config": body,
55        "message": "Webhook config created (desktop mode: ephemeral)"
56    }))
57}
58
59async fn update_config(Json(body): Json<serde_json::Value>) -> Json<serde_json::Value> {
60    Json(serde_json::json!({
61        "config": body,
62        "message": "Webhook config updated (desktop mode: ephemeral)"
63    }))
64}
65
66async fn delete_config() -> Json<serde_json::Value> {
67    Json(serde_json::json!({ "deleted": true }))
68}
69
70// ─── GitHub Webhooks ─────────────────────────────────────────────────────────
71
72async fn list_github_webhooks() -> Json<serde_json::Value> {
73    Json(serde_json::json!({ "webhooks": [] }))
74}
75
76async fn handle_github_event(Json(body): Json<serde_json::Value>) -> Json<serde_json::Value> {
77    let event_type = body
78        .get("type")
79        .or_else(|| body.get("action"))
80        .and_then(|v| v.as_str())
81        .unwrap_or("unknown");
82    Json(serde_json::json!({
83        "processed": true,
84        "eventType": event_type,
85        "message": "GitHub webhook event received",
86    }))
87}
88
89// ─── Registrations ────────────────────────────────────────────────────────────
90
91async fn list_registrations() -> Json<serde_json::Value> {
92    Json(serde_json::json!({ "registrations": [] }))
93}
94
95async fn register_webhook(Json(body): Json<serde_json::Value>) -> Json<serde_json::Value> {
96    Json(serde_json::json!({
97        "registered": true,
98        "webhook": body,
99    }))
100}
101
102async fn unregister_webhook() -> Json<serde_json::Value> {
103    Json(serde_json::json!({ "unregistered": true }))
104}
105
106// ─── Logs ─────────────────────────────────────────────────────────────────────
107
108async fn list_logs(Query(_q): Query<WebhookQuery>) -> Json<serde_json::Value> {
109    Json(serde_json::json!({ "logs": [] }))
110}