纳入 FastAPI 后端、Vue 管理端、MCP 桥接与文档;通过 .gitignore 排除本地数据库与构建产物。 Co-authored-by: Cursor <cursoragent@cursor.com>
409 lines
8.2 KiB
Python
409 lines
8.2 KiB
Python
from typing import Any, Literal
|
|
|
|
from pydantic import BaseModel, Field
|
|
|
|
|
|
class ApiBase(BaseModel):
|
|
name: str
|
|
folder_path: str = ""
|
|
method: str = "GET"
|
|
url: str
|
|
headers: dict[str, Any] = Field(default_factory=dict)
|
|
body: dict[str, Any] = Field(default_factory=dict)
|
|
query: dict[str, Any] = Field(default_factory=dict)
|
|
path_params: dict[str, Any] = Field(default_factory=dict)
|
|
timeout_seconds: float = 10.0
|
|
|
|
|
|
class ApiCreate(ApiBase):
|
|
pass
|
|
|
|
|
|
class ApiUpdate(ApiBase):
|
|
pass
|
|
|
|
|
|
class ApiOut(ApiBase):
|
|
id: int
|
|
creator_id: int = 0
|
|
creator_name: str = ""
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
class WorkflowPayload(BaseModel):
|
|
nodes: list[dict[str, Any]] = Field(default_factory=list)
|
|
edges: list[dict[str, Any]] = Field(default_factory=list)
|
|
variables: dict[str, Any] = Field(default_factory=dict)
|
|
|
|
|
|
class WorkflowBase(BaseModel):
|
|
name: str
|
|
folder_path: str = ""
|
|
definition: WorkflowPayload = Field(default_factory=WorkflowPayload)
|
|
default_headers: dict[str, Any] = Field(default_factory=dict)
|
|
|
|
|
|
class WorkflowCreate(WorkflowBase):
|
|
pass
|
|
|
|
|
|
class WorkflowUpdate(WorkflowBase):
|
|
pass
|
|
|
|
|
|
class WorkflowOut(WorkflowBase):
|
|
id: int
|
|
creator_id: int = 0
|
|
creator_name: str = ""
|
|
last_run: dict[str, Any] | None = None
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
class ReplayRunRequest(BaseModel):
|
|
base_url: str = ""
|
|
fail_fast: bool = True
|
|
|
|
|
|
class MockDataBase(BaseModel):
|
|
name: str
|
|
data: dict[str, Any] = Field(default_factory=dict)
|
|
|
|
|
|
class MockDataCreate(MockDataBase):
|
|
pass
|
|
|
|
|
|
class MockDataOut(MockDataBase):
|
|
id: int
|
|
creator_id: int = 0
|
|
creator_name: str = ""
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
class McpToolBase(BaseModel):
|
|
name: str
|
|
enabled: bool = True
|
|
config: dict[str, Any] = Field(default_factory=dict)
|
|
|
|
|
|
class McpToolCreate(McpToolBase):
|
|
pass
|
|
|
|
|
|
class McpToolOut(McpToolBase):
|
|
id: int
|
|
creator_id: int = 0
|
|
creator_name: str = ""
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
class SshCommandPreset(BaseModel):
|
|
name: str
|
|
command: str
|
|
description: str = ""
|
|
|
|
|
|
class SshProfileBase(BaseModel):
|
|
name: str
|
|
host: str
|
|
port: int = 22
|
|
username: str
|
|
auth_type: Literal["key", "password"] = "key"
|
|
key_path: str = ""
|
|
presets: list[SshCommandPreset] = Field(default_factory=list)
|
|
|
|
|
|
class SshProfileCreate(SshProfileBase):
|
|
pass
|
|
|
|
|
|
class SshProfileUpdate(SshProfileBase):
|
|
pass
|
|
|
|
|
|
class SshProfileOut(SshProfileBase):
|
|
id: int
|
|
creator_id: int = 0
|
|
creator_name: str = ""
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
class SshExecuteRequest(BaseModel):
|
|
command: str = ""
|
|
preset_name: str = ""
|
|
password: str = ""
|
|
timeout_seconds: float = 20.0
|
|
|
|
|
|
class SshExecuteResponse(BaseModel):
|
|
ok: bool
|
|
command: str
|
|
stdout: str = ""
|
|
stderr: str = ""
|
|
exit_status: int = 0
|
|
|
|
|
|
class SshShortcutBase(BaseModel):
|
|
name: str
|
|
command: str
|
|
description: str = ""
|
|
|
|
|
|
class SshShortcutCreate(SshShortcutBase):
|
|
pass
|
|
|
|
|
|
class SshShortcutUpdate(SshShortcutBase):
|
|
pass
|
|
|
|
|
|
class SshShortcutOut(SshShortcutBase):
|
|
id: int
|
|
creator_id: int = 0
|
|
creator_name: str = ""
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
class SshScriptBase(BaseModel):
|
|
profile_id: int
|
|
name: str
|
|
description: str = ""
|
|
source_type: Literal["inline", "file"] = "inline"
|
|
content: str = ""
|
|
|
|
|
|
class SshScriptCreate(SshScriptBase):
|
|
pass
|
|
|
|
|
|
class SshScriptUpdate(BaseModel):
|
|
name: str
|
|
description: str = ""
|
|
content: str = ""
|
|
|
|
|
|
class SshScriptOut(SshScriptBase):
|
|
id: int
|
|
storage_path: str = ""
|
|
creator_id: int = 0
|
|
creator_name: str = ""
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
class SshTreeScriptNode(BaseModel):
|
|
id: int
|
|
name: str
|
|
description: str = ""
|
|
source_type: Literal["inline", "file"] = "inline"
|
|
storage_path: str = ""
|
|
|
|
|
|
class SshTreeProfileNode(BaseModel):
|
|
id: int
|
|
name: str
|
|
host: str
|
|
port: int = 22
|
|
username: str
|
|
auth_type: Literal["key", "password"] = "key"
|
|
key_path: str = ""
|
|
scripts: list[SshTreeScriptNode] = Field(default_factory=list)
|
|
|
|
|
|
class LoginRequest(BaseModel):
|
|
username: str
|
|
password: str
|
|
|
|
|
|
class CurrentUserOut(BaseModel):
|
|
id: int
|
|
username: str
|
|
display_name: str
|
|
role: Literal["superadmin", "user"]
|
|
|
|
|
|
class LoginResponse(BaseModel):
|
|
token: str
|
|
user: CurrentUserOut
|
|
|
|
|
|
class UserCreate(BaseModel):
|
|
username: str
|
|
password: str
|
|
display_name: str = ""
|
|
role: Literal["superadmin", "user"] = "user"
|
|
|
|
|
|
class UserUpdate(BaseModel):
|
|
display_name: str = ""
|
|
role: Literal["superadmin", "user"] = "user"
|
|
is_active: bool = True
|
|
password: str = ""
|
|
|
|
|
|
class UserOut(BaseModel):
|
|
id: int
|
|
username: str
|
|
display_name: str
|
|
role: Literal["superadmin", "user"]
|
|
is_active: bool
|
|
|
|
|
|
class UserApiKeyCreate(BaseModel):
|
|
expires_at: str | None = None
|
|
|
|
|
|
class UserApiKeyOut(BaseModel):
|
|
id: int
|
|
key_prefix: str
|
|
key_hint: str
|
|
masked_key: str = ""
|
|
expires_at: str | None = None
|
|
is_active: bool = True
|
|
created_at: str = ""
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
class UserApiKeyCreateResponse(UserApiKeyOut):
|
|
api_key: str
|
|
|
|
|
|
class RunWorkflowRequest(BaseModel):
|
|
workflow_id: int
|
|
base_url: str = ""
|
|
fail_fast: bool = True
|
|
|
|
|
|
class NodeExecutionResult(BaseModel):
|
|
node_id: str
|
|
node_type: str
|
|
status: Literal["success", "failed", "skipped"]
|
|
output: dict[str, Any] = Field(default_factory=dict)
|
|
error: str | None = None
|
|
|
|
|
|
class RunWorkflowResponse(BaseModel):
|
|
status: Literal["success", "failed"]
|
|
variables: dict[str, Any]
|
|
results: list[NodeExecutionResult]
|
|
run_id: int | None = None
|
|
workflow_id: int | None = None
|
|
batch_id: int | None = None
|
|
|
|
|
|
class WorkflowBatchCreate(BaseModel):
|
|
name: str = ""
|
|
base_url: str = ""
|
|
fail_fast: bool = True
|
|
workflow_ids: list[int] = Field(default_factory=list)
|
|
|
|
|
|
class WorkflowBatchUpdate(BaseModel):
|
|
name: str | None = None
|
|
base_url: str | None = None
|
|
fail_fast: bool | None = None
|
|
workflow_ids: list[int] | None = None
|
|
|
|
|
|
class RunWorkflowBatchRequest(BaseModel):
|
|
"""快捷:创建批次并立即执行(兼容旧调用)。"""
|
|
workflow_ids: list[int] = Field(default_factory=list)
|
|
name: str = ""
|
|
base_url: str = ""
|
|
fail_fast: bool = True
|
|
|
|
|
|
class WorkflowBatchRunItem(BaseModel):
|
|
workflow_id: int
|
|
workflow_name: str = ""
|
|
run_id: int | None = None
|
|
status: str = "pending"
|
|
error: str | None = None
|
|
|
|
|
|
class RunWorkflowBatchResponse(BaseModel):
|
|
batch_id: int
|
|
status: Literal["draft", "running", "success", "failed", "partial"]
|
|
items: list[WorkflowBatchRunItem]
|
|
|
|
|
|
class WorkflowBatchOut(BaseModel):
|
|
id: int
|
|
name: str = ""
|
|
status: Literal["draft", "running", "success", "failed", "partial"]
|
|
triggered_by: str = ""
|
|
creator_id: int = 0
|
|
creator_name: str = ""
|
|
base_url: str = ""
|
|
fail_fast: bool = True
|
|
workflow_ids: list[int] = Field(default_factory=list)
|
|
summary: dict[str, Any] = Field(default_factory=dict)
|
|
created_at: str | None = None
|
|
finished_at: str | None = None
|
|
runs: list[dict[str, Any]] = Field(default_factory=list)
|
|
|
|
|
|
class LokiLogLinkOut(BaseModel):
|
|
enabled: bool = False
|
|
explore_url: str = ""
|
|
logql: str = ""
|
|
time_from: str = ""
|
|
time_to: str = ""
|
|
method: str = ""
|
|
url: str = ""
|
|
hint: str = ""
|
|
|
|
|
|
class RunNodeRequest(BaseModel):
|
|
workflow_id: int
|
|
node_id: str
|
|
base_url: str = ""
|
|
|
|
|
|
class RunNodeResponse(BaseModel):
|
|
status: Literal["success", "failed"]
|
|
variables: dict[str, Any]
|
|
result: NodeExecutionResult
|
|
|
|
|
|
class FolderMoveRequest(BaseModel):
|
|
target: Literal["apis", "workflows"]
|
|
from_path: str
|
|
to_path: str
|
|
|
|
|
|
class McpInvokeRequest(BaseModel):
|
|
tool: str
|
|
arguments: dict[str, Any] = Field(default_factory=dict)
|
|
api_key: str | None = Field(
|
|
default=None,
|
|
description="Optional sto- API key when Authorization header is unavailable",
|
|
)
|
|
|
|
|
|
class McpInvokeBatchRequest(BaseModel):
|
|
calls: list[McpInvokeRequest] = Field(default_factory=list)
|
|
stop_on_error: bool = True
|
|
|
|
|
|
class McpInvokeResponse(BaseModel):
|
|
ok: bool
|
|
tool: str
|
|
data: dict[str, Any] = Field(default_factory=dict)
|
|
error: str | None = None
|