111 lines
3.4 KiB
Python
111 lines
3.4 KiB
Python
"""Webhook configuration CRUD + test notification."""
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
from datetime import datetime, timezone
|
|
from typing import List
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.database import get_db
|
|
from app.models.webhook_config import WebhookConfig
|
|
from app.schemas.webhook import WebhookCreate, WebhookUpdate, WebhookResponse
|
|
from app.services.webhook_service import send_test_notification
|
|
from app.utils.auth import get_current_user
|
|
|
|
router = APIRouter(prefix="/api/webhooks", tags=["webhooks"])
|
|
|
|
MASK = "***"
|
|
|
|
|
|
def _to_response(w: WebhookConfig) -> WebhookResponse:
|
|
return WebhookResponse(
|
|
id=w.id,
|
|
name=w.name,
|
|
type=w.type,
|
|
url=w.url,
|
|
secret_masked=MASK if w.secret else "",
|
|
enabled=w.enabled,
|
|
events=json.loads(w.events_json or "[]"),
|
|
created_at=w.created_at,
|
|
updated_at=w.updated_at,
|
|
)
|
|
|
|
|
|
@router.get("", response_model=List[WebhookResponse])
|
|
def list_webhooks(db: Session = Depends(get_db), _=Depends(get_current_user)):
|
|
return [_to_response(w) for w in db.query(WebhookConfig).order_by(WebhookConfig.id).all()]
|
|
|
|
|
|
@router.post("", response_model=WebhookResponse, status_code=201)
|
|
def create_webhook(
|
|
body: WebhookCreate,
|
|
db: Session = Depends(get_db),
|
|
_=Depends(get_current_user),
|
|
):
|
|
w = WebhookConfig(
|
|
name=body.name,
|
|
type=body.type,
|
|
url=body.url,
|
|
secret=body.secret,
|
|
enabled=body.enabled,
|
|
events_json=json.dumps(body.events, ensure_ascii=False),
|
|
)
|
|
db.add(w)
|
|
db.commit()
|
|
db.refresh(w)
|
|
return _to_response(w)
|
|
|
|
|
|
@router.get("/{wid}", response_model=WebhookResponse)
|
|
def get_webhook(wid: int, db: Session = Depends(get_db), _=Depends(get_current_user)):
|
|
w = db.query(WebhookConfig).filter(WebhookConfig.id == wid).first()
|
|
if not w:
|
|
raise HTTPException(404, "webhook not found")
|
|
return _to_response(w)
|
|
|
|
|
|
@router.put("/{wid}", response_model=WebhookResponse)
|
|
def update_webhook(
|
|
wid: int,
|
|
body: WebhookUpdate,
|
|
db: Session = Depends(get_db),
|
|
_=Depends(get_current_user),
|
|
):
|
|
w = db.query(WebhookConfig).filter(WebhookConfig.id == wid).first()
|
|
if not w:
|
|
raise HTTPException(404, "webhook not found")
|
|
data = body.model_dump(exclude_none=True)
|
|
if "events" in data:
|
|
w.events_json = json.dumps(data.pop("events"), ensure_ascii=False)
|
|
if "secret" in data:
|
|
if data["secret"] != MASK: # only update if not mask placeholder
|
|
w.secret = data.pop("secret")
|
|
else:
|
|
data.pop("secret")
|
|
for k, v in data.items():
|
|
setattr(w, k, v)
|
|
w.updated_at = datetime.now(timezone.utc)
|
|
db.commit()
|
|
db.refresh(w)
|
|
return _to_response(w)
|
|
|
|
|
|
@router.delete("/{wid}", status_code=204)
|
|
def delete_webhook(wid: int, db: Session = Depends(get_db), _=Depends(get_current_user)):
|
|
w = db.query(WebhookConfig).filter(WebhookConfig.id == wid).first()
|
|
if not w:
|
|
raise HTTPException(404, "webhook not found")
|
|
db.delete(w)
|
|
db.commit()
|
|
|
|
|
|
@router.post("/{wid}/test")
|
|
def test_webhook(wid: int, db: Session = Depends(get_db), _=Depends(get_current_user)):
|
|
w = db.query(WebhookConfig).filter(WebhookConfig.id == wid).first()
|
|
if not w:
|
|
raise HTTPException(404, "webhook not found")
|
|
ok, msg = send_test_notification(db, w)
|
|
return {"success": ok, "message": msg}
|