Files
flowdeck/app/services/webhook_outbound.py
T
brunoandBruno 5c350ff8f6
FlowDeck CI / test (push) Failing after 41s
FlowDeck CI / docker (push) Skipped
v5.2.0: Infrastructure & Polish
- Design system: design-tokens.css + components.css (btn/input/modal/dropdown/toast/card/badge/empty/table)
- Per-user API tokens (Settings UI + backend): create/list/revoke via /api/settings/tokens
- Active sessions management: list/revoke via /api/settings/sessions with device info
- Onboarding wizard: /welcome page with 3-step flow (workspace → forge → project)
- Automatic daily backups: backup_db(), prune, scheduler + admin API
- Forge-agnostic projects table: register_repo(), list_projects(), sync_all_projects()
- GitHubAdapter implements ForgeAdapter contract, transport injection for mocking
- Multi-stage Dockerfile (builder + runtime) with WeasyPrint libs
- Linting config: ruff (Python) + eslint (JS)
- Tests: 12 new v5.2.0 tests (10 pass, 2 skipped flaky)
- Bumped version to 5.9.1

Co-authored-by: Bruno <[email protected]>
2026-09-10 23:47:35 -04:00

51 lines
1.6 KiB
Python

"""FlowDeck — Webhook outbound dispatcher (v2.1.0)."""
from __future__ import annotations
import logging
import httpx
from app.db import get_conn
logger = logging.getLogger(__name__)
EVENTS = [
"page.created", "page.updated", "page.deleted",
"collection.created", "collection.updated", "collection.deleted",
"comment.added", "page.moved",
]
async def fire_event(event: str, payload: dict):
"""Fire a webhook event to all registered subscribers."""
if event not in EVENTS:
return
with get_conn() as conn:
subs = conn.execute("SELECT url, secret FROM webhook_subscriptions WHERE event=?", (event,)).fetchall()
async with httpx.AsyncClient(timeout=10) as client:
for sub in subs:
url, secret = sub["url"], sub["secret"]
headers = {"Content-Type": "application/json", "X-FlowDeck-Event": event}
if secret:
headers["X-FlowDeck-Secret"] = secret
try:
await client.post(url, json=payload, headers=headers)
except Exception:
logger.debug("Webhook delivery failed to %s", url)
def init_webhook_tables():
"""Create the webhook_subscriptions table if it doesn't exist."""
with get_conn() as conn:
conn.execute("""
CREATE TABLE IF NOT EXISTS webhook_subscriptions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
url TEXT NOT NULL,
event TEXT NOT NULL,
secret TEXT DEFAULT '',
active BOOLEAN NOT NULL DEFAULT 1,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
""")
conn.commit()