Добавил поддержку webhook

This commit is contained in:
brusnitsyn
2026-06-16 16:03:49 +09:00
parent 17f4d4307f
commit 6ef045ca88
2 changed files with 157 additions and 2 deletions

View File

@@ -10,6 +10,8 @@ except ImportError:
HTTPException = None
BaseModel = object
from sqlalchemy import text
from .config import Config
from .queue import migration_queue
from .table_config_repository import TableConfigRepository
@@ -45,6 +47,16 @@ class ScheduleRequest(BaseModel):
initial_force_full: bool = False
class WebhookCreate(BaseModel):
url: str
secret: Optional[str] = None
label: Optional[str] = None
class WebhookToggle(BaseModel):
active: bool
def create_app():
"""Создание FastAPI приложения."""
if FastAPI is None:
@@ -57,12 +69,29 @@ def create_app():
from sqlalchemy import create_engine
config = Config()
_shared['engine'] = create_engine(
engine = create_engine(
config.POSTGRES_CONNECTION_STRING,
pool_pre_ping=True,
pool_recycle=1800,
)
_shared['engine'] = engine
_shared['config'] = config
schema = f'"{config.REPLICATOR_SCHEMA}"'
with engine.connect() as conn:
conn.execute(text(f'CREATE SCHEMA IF NOT EXISTS {schema}'))
conn.execute(text(f"""
CREATE TABLE IF NOT EXISTS {schema}.webhook_subscriptions (
id SERIAL PRIMARY KEY,
url TEXT NOT NULL,
secret TEXT,
label TEXT,
active BOOLEAN NOT NULL DEFAULT true,
created_at TIMESTAMP NOT NULL DEFAULT now()
)
"""))
conn.commit()
if Config.START_API_WORKER:
migration_queue.start()
@@ -169,6 +198,62 @@ def create_app():
return {"status": "scheduled", "schedule": schedule}
# -----------------------------------------------------------------------
# Webhooks
# -----------------------------------------------------------------------
_WEBHOOKS_TABLE = f'"{Config.REPLICATOR_SCHEMA}".webhook_subscriptions'
@api.get("/webhooks")
def list_webhooks():
with _shared['engine'].connect() as conn:
rows = conn.execute(
text(f"SELECT id, url, secret, label, active, created_at FROM {_WEBHOOKS_TABLE} ORDER BY id")
).mappings().all()
return [dict(r) for r in rows]
@api.post("/webhooks", status_code=201)
def create_webhook(body: WebhookCreate):
with _shared['engine'].connect() as conn:
row = conn.execute(
text(f"""
INSERT INTO {_WEBHOOKS_TABLE} (url, secret, label)
VALUES (:url, :secret, :label)
RETURNING id, url, secret, label, active, created_at
"""),
{'url': body.url, 'secret': body.secret, 'label': body.label},
).mappings().first()
conn.commit()
return dict(row)
@api.patch("/webhooks/{webhook_id}")
def toggle_webhook(webhook_id: int, body: WebhookToggle):
with _shared['engine'].connect() as conn:
row = conn.execute(
text(f"""
UPDATE {_WEBHOOKS_TABLE}
SET active = :active
WHERE id = :id
RETURNING id, url, secret, label, active, created_at
"""),
{'active': body.active, 'id': webhook_id},
).mappings().first()
conn.commit()
if not row:
raise HTTPException(status_code=404, detail="Webhook not found")
return dict(row)
@api.delete("/webhooks/{webhook_id}", status_code=204)
def delete_webhook(webhook_id: int):
with _shared['engine'].connect() as conn:
result = conn.execute(
text(f"DELETE FROM {_WEBHOOKS_TABLE} WHERE id = :id"),
{'id': webhook_id},
)
conn.commit()
if result.rowcount == 0:
raise HTTPException(status_code=404, detail="Webhook not found")
return api