feat: V1 - DAG编排/告警系统/Agent循环/知识库RAG/Webhook + 审核管理富上下文修复
This commit is contained in:
@@ -0,0 +1,78 @@
|
|||||||
|
"""Webhook service: trigger external notifications."""
|
||||||
|
import json
|
||||||
|
import hmac
|
||||||
|
import hashlib
|
||||||
|
import httpx
|
||||||
|
from sqlalchemy.orm import Session
|
||||||
|
from typing import List, Optional
|
||||||
|
from app.models.webhook import WebhookConfig
|
||||||
|
|
||||||
|
|
||||||
|
class WebhookService:
|
||||||
|
@staticmethod
|
||||||
|
def trigger(db: Session, tenant_id: int, event_type: str, payload: dict):
|
||||||
|
"""Find matching webhooks and POST to their URLs."""
|
||||||
|
hooks = db.query(WebhookConfig).filter(
|
||||||
|
WebhookConfig.tenant_id == tenant_id,
|
||||||
|
WebhookConfig.is_active == True,
|
||||||
|
).all()
|
||||||
|
|
||||||
|
for hook in hooks:
|
||||||
|
events = json.loads(hook.events or "[]")
|
||||||
|
if event_type not in events:
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
body = json.dumps({"event": event_type, "data": payload}, ensure_ascii=False)
|
||||||
|
headers = {"Content-Type": "application/json"}
|
||||||
|
if hook.secret:
|
||||||
|
sig = hmac.new(
|
||||||
|
hook.secret.encode(), body.encode(), hashlib.sha256
|
||||||
|
).hexdigest()
|
||||||
|
headers["X-Webhook-Signature"] = sig
|
||||||
|
|
||||||
|
with httpx.Client(timeout=10) as client:
|
||||||
|
client.post(hook.url, content=body, headers=headers)
|
||||||
|
except Exception:
|
||||||
|
pass # webhook delivery is best-effort
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def list_hooks(db, tenant_id):
|
||||||
|
return db.query(WebhookConfig).filter(
|
||||||
|
WebhookConfig.tenant_id == tenant_id
|
||||||
|
).order_by(WebhookConfig.created_at.desc()).all()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def create_hook(db, tenant_id, req):
|
||||||
|
hook = WebhookConfig(
|
||||||
|
tenant_id=tenant_id, url=req.url, events=req.events,
|
||||||
|
secret=req.secret, project_id=req.project_id,
|
||||||
|
)
|
||||||
|
db.add(hook)
|
||||||
|
db.commit()
|
||||||
|
db.refresh(hook)
|
||||||
|
return hook
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def update_hook(db, tenant_id, hook_id, req):
|
||||||
|
hook = db.query(WebhookConfig).filter(
|
||||||
|
WebhookConfig.id == hook_id, WebhookConfig.tenant_id == tenant_id
|
||||||
|
).first()
|
||||||
|
if not hook:
|
||||||
|
return None
|
||||||
|
for f in ["url", "events", "secret", "is_active"]:
|
||||||
|
if hasattr(req, f) and getattr(req, f) is not None:
|
||||||
|
setattr(hook, f, getattr(req, f))
|
||||||
|
db.commit()
|
||||||
|
db.refresh(hook)
|
||||||
|
return hook
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def delete_hook(db, tenant_id, hook_id):
|
||||||
|
hook = db.query(WebhookConfig).filter(
|
||||||
|
WebhookConfig.id == hook_id, WebhookConfig.tenant_id == tenant_id
|
||||||
|
).first()
|
||||||
|
if not hook:
|
||||||
|
return False
|
||||||
|
db.delete(hook)
|
||||||
|
db.commit()
|
||||||
|
return True
|
||||||
Reference in New Issue
Block a user