mirror of https://github.com/langgenius/dify.git
152 lines
5.3 KiB
Python
152 lines
5.3 KiB
Python
import logging
|
|
import secrets
|
|
|
|
from flask_restful import Resource, reqparse
|
|
from sqlalchemy.orm import Session
|
|
from werkzeug.exceptions import BadRequest, Forbidden, NotFound
|
|
|
|
from configs import dify_config
|
|
from controllers.console import api
|
|
from controllers.console.app.wraps import get_app_model
|
|
from controllers.console.wraps import account_initialization_required, setup_required
|
|
from extensions.ext_database import db
|
|
from libs.login import current_user, login_required
|
|
from models.workflow import WorkflowWebhookTrigger
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class WebhookTriggerApi(Resource):
|
|
"""Webhook Trigger API"""
|
|
|
|
@setup_required
|
|
@login_required
|
|
@account_initialization_required
|
|
@get_app_model
|
|
def post(self, app_model):
|
|
"""Create webhook trigger"""
|
|
parser = reqparse.RequestParser()
|
|
parser.add_argument("node_id", type=str, required=True, help="Node ID is required")
|
|
parser.add_argument(
|
|
"triggered_by",
|
|
type=str,
|
|
required=False,
|
|
default="production",
|
|
choices=["debugger", "production"],
|
|
help="triggered_by must be debugger or production",
|
|
)
|
|
args = parser.parse_args()
|
|
|
|
if app_model.mode != "workflow":
|
|
raise BadRequest("Invalid app mode, only workflow can add webhook node")
|
|
|
|
# The role of the current user in the ta table must be admin, owner, or editor
|
|
if not current_user.is_editor:
|
|
raise Forbidden()
|
|
|
|
node_id = args["node_id"]
|
|
triggered_by = args["triggered_by"]
|
|
|
|
with Session(db.engine) as session:
|
|
# Check if webhook trigger already exists for this app, node, and environment
|
|
existing_trigger = (
|
|
session.query(WorkflowWebhookTrigger)
|
|
.filter(
|
|
WorkflowWebhookTrigger.app_id == app_model.id,
|
|
WorkflowWebhookTrigger.node_id == node_id,
|
|
WorkflowWebhookTrigger.triggered_by == triggered_by,
|
|
)
|
|
.first()
|
|
)
|
|
|
|
if existing_trigger:
|
|
raise BadRequest("Webhook trigger already exists for this node and environment")
|
|
|
|
# Generate unique webhook_id
|
|
webhook_id = self._generate_webhook_id(session)
|
|
|
|
# Create new webhook trigger
|
|
webhook_trigger = WorkflowWebhookTrigger(
|
|
app_id=app_model.id,
|
|
node_id=node_id,
|
|
tenant_id=current_user.current_tenant_id,
|
|
webhook_id=webhook_id,
|
|
triggered_by=triggered_by,
|
|
)
|
|
|
|
session.add(webhook_trigger)
|
|
session.commit()
|
|
session.refresh(webhook_trigger)
|
|
|
|
return {
|
|
"id": webhook_trigger.id,
|
|
"webhook_id": webhook_trigger.webhook_id,
|
|
"webhook_url": f"{dify_config.SERVICE_API_URL}/triggers/webhook/{webhook_trigger.webhook_id}",
|
|
"node_id": webhook_trigger.node_id,
|
|
"triggered_by": webhook_trigger.triggered_by,
|
|
"created_at": webhook_trigger.created_at.isoformat(),
|
|
}
|
|
|
|
@setup_required
|
|
@login_required
|
|
@account_initialization_required
|
|
@get_app_model
|
|
def delete(self, app_model):
|
|
"""Delete webhook trigger"""
|
|
parser = reqparse.RequestParser()
|
|
parser.add_argument("node_id", type=str, required=True, help="Node ID is required")
|
|
parser.add_argument(
|
|
"triggered_by",
|
|
type=str,
|
|
required=False,
|
|
default="production",
|
|
choices=["debugger", "production"],
|
|
help="triggered_by must be debugger or production",
|
|
)
|
|
args = parser.parse_args()
|
|
|
|
# The role of the current user in the ta table must be admin, owner, or editor
|
|
if not current_user.is_editor:
|
|
raise Forbidden()
|
|
|
|
node_id = args["node_id"]
|
|
triggered_by = args["triggered_by"]
|
|
|
|
with Session(db.engine) as session:
|
|
# Find webhook trigger
|
|
webhook_trigger = (
|
|
session.query(WorkflowWebhookTrigger)
|
|
.filter(
|
|
WorkflowWebhookTrigger.app_id == app_model.id,
|
|
WorkflowWebhookTrigger.node_id == node_id,
|
|
WorkflowWebhookTrigger.triggered_by == triggered_by,
|
|
WorkflowWebhookTrigger.tenant_id == current_user.current_tenant_id,
|
|
)
|
|
.first()
|
|
)
|
|
|
|
if not webhook_trigger:
|
|
raise NotFound("Webhook trigger not found")
|
|
|
|
session.delete(webhook_trigger)
|
|
session.commit()
|
|
|
|
return {"result": "success"}, 204
|
|
|
|
def _generate_webhook_id(self, session: Session) -> str:
|
|
"""Generate unique 24-character webhook ID"""
|
|
while True:
|
|
# Generate 24-character random string
|
|
webhook_id = secrets.token_urlsafe(18)[:24] # token_urlsafe gives base64url, take first 24 chars
|
|
|
|
# Check if it already exists
|
|
existing = (
|
|
session.query(WorkflowWebhookTrigger).filter(WorkflowWebhookTrigger.webhook_id == webhook_id).first()
|
|
)
|
|
|
|
if not existing:
|
|
return webhook_id
|
|
|
|
|
|
api.add_resource(WebhookTriggerApi, "/apps/<uuid:app_id>/workflows/triggers/webhook")
|