Files
非法操作andautofix-ci[bot] 163062847b refactor(api): relocate trigger plugin runtime (#45966)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-11-11 09:43:32 +00:00

167 lines
6.5 KiB
Python

from dataclasses import asdict
from datetime import datetime
from http import HTTPStatus
from uuid import UUID
from flask_restx import Resource
from pydantic import BaseModel, field_validator
from configs import dify_config
from controllers.common.rbac import PlainApp, RBACCheck
from controllers.common.schema import query_params_from_model, register_response_schema_models, register_schema_models
from controllers.console import console_ns
from controllers.console.app.error import AppNotFoundError, AppTriggerNotFoundError, WebhookTriggerNotFoundError
from controllers.console.flask_admission import console_account_admission
from controllers.console.wraps import RBACPermission, model_validate
from enums.account import TenantAccountRole
from extensions.ext_application_services import application_services
from fields.base import ResponseModel
from libs.external_api import error_responses
from libs.helper import dump_response
from machinery.context import RequestContext
from models.enums import AppTriggerType
from models.utils.trigger_endpoint import generate_webhook_trigger_endpoint
from services.app.console_service import ConsoleAppNotFoundError
from services.trigger.app_trigger_store import (
AppTriggerNotFoundError as AppTriggerMissing,
)
from services.trigger.app_trigger_store import (
AppTriggerRecord,
)
from services.trigger.app_trigger_store import (
WebhookTriggerNotFoundError as WebhookTriggerMissing,
)
class WebhookTriggerQuery(BaseModel):
node_id: str
class ParserEnable(BaseModel):
trigger_id: str
enable_trigger: bool
class WorkflowTriggerResponse(ResponseModel):
id: str
trigger_type: str
title: str
node_id: str
provider_name: str
icon: str
status: str
created_at: datetime | None = None
updated_at: datetime | None = None
@field_validator("id", "trigger_type", "title", "node_id", "provider_name", "icon", "status", mode="before")
@classmethod
def _normalize_string_fields(cls, value: object) -> str:
if isinstance(value, str):
return value
return str(value)
class WorkflowTriggerListResponse(ResponseModel):
data: list[WorkflowTriggerResponse]
class WebhookTriggerResponse(ResponseModel):
id: str
webhook_id: str
webhook_url: str
webhook_debug_url: str
node_id: str
created_at: datetime | None = None
@field_validator("id", "webhook_id", "webhook_url", "webhook_debug_url", "node_id", mode="before")
@classmethod
def _normalize_string_fields(cls, value: object) -> str:
if isinstance(value, str):
return value
return str(value)
register_schema_models(console_ns, WebhookTriggerQuery, ParserEnable)
register_response_schema_models(
console_ns,
WorkflowTriggerResponse,
WorkflowTriggerListResponse,
WebhookTriggerResponse,
)
def _with_trigger_icon(trigger: AppTriggerRecord) -> dict[str, object]:
icon = ""
if trigger.trigger_type == AppTriggerType.TRIGGER_PLUGIN:
icon = (
dify_config.CONSOLE_API_URL
+ "/console/api/workspaces/current/tool-provider/builtin/"
+ (trigger.provider_name or "")
+ "/icon"
)
return {**asdict(trigger), "icon": icon}
@console_ns.route("/apps/<uuid:app_id>/workflows/triggers/webhook")
class WebhookTriggerApi(Resource):
@error_responses(AppNotFoundError, WebhookTriggerNotFoundError)
@console_ns.doc(params=query_params_from_model(WebhookTriggerQuery))
@console_ns.response(HTTPStatus.OK, "Success", console_ns.models[WebhookTriggerResponse.__name__])
@console_account_admission(rbac_checks=[RBACCheck(RBACPermission.APP_VIEW_LAYOUT, PlainApp())])
@model_validate(WebhookTriggerQuery)
def get(self, req_data: WebhookTriggerQuery, context: RequestContext, app_id: UUID) -> dict[str, object]:
"""Get webhook trigger for a node"""
try:
webhook = application_services().apps.triggers.get_webhook(context, str(app_id), req_data.node_id)
except ConsoleAppNotFoundError as error:
raise AppNotFoundError(str(error)) from error
except WebhookTriggerMissing as error:
raise WebhookTriggerNotFoundError(str(error)) from error
return dump_response(
WebhookTriggerResponse,
{
**asdict(webhook),
"webhook_url": generate_webhook_trigger_endpoint(webhook.webhook_id),
"webhook_debug_url": generate_webhook_trigger_endpoint(webhook.webhook_id, debug=True),
},
)
@console_ns.route("/apps/<uuid:app_id>/triggers")
class AppTriggersApi(Resource):
@error_responses(AppNotFoundError)
@console_ns.response(HTTPStatus.OK, "Success", console_ns.models[WorkflowTriggerListResponse.__name__])
@console_account_admission(rbac_checks=[RBACCheck(RBACPermission.APP_VIEW_LAYOUT, PlainApp())])
def get(self, context: RequestContext, app_id: UUID) -> dict[str, object]:
"""Get app triggers list"""
try:
triggers = application_services().apps.triggers.list_triggers(context, str(app_id))
except ConsoleAppNotFoundError as error:
raise AppNotFoundError(str(error)) from error
return dump_response(
WorkflowTriggerListResponse, {"data": [_with_trigger_icon(trigger) for trigger in triggers]}
)
@console_ns.route("/apps/<uuid:app_id>/trigger-enable")
class AppTriggerEnableApi(Resource):
@error_responses(AppNotFoundError, AppTriggerNotFoundError)
@console_ns.expect(console_ns.models[ParserEnable.__name__])
@console_ns.response(HTTPStatus.OK, "Success", console_ns.models[WorkflowTriggerResponse.__name__])
@console_account_admission(
allowed_roles=frozenset({TenantAccountRole.OWNER, TenantAccountRole.ADMIN, TenantAccountRole.EDITOR}),
rbac_checks=[RBACCheck(RBACPermission.APP_EDIT, PlainApp())],
)
@model_validate(ParserEnable)
def post(self, req_data: ParserEnable, context: RequestContext, app_id: UUID) -> dict[str, object]:
"""Update app trigger (enable/disable)"""
try:
trigger = application_services().apps.triggers.set_enabled(
context, str(app_id), req_data.trigger_id, enabled=req_data.enable_trigger
)
except ConsoleAppNotFoundError as error:
raise AppNotFoundError(str(error)) from error
except AppTriggerMissing as error:
raise AppTriggerNotFoundError(str(error)) from error
return dump_response(WorkflowTriggerResponse, _with_trigger_icon(trigger))