mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-05 07:27:15 +08:00
refactor: 推进后端分层架构治理
This commit is contained in:
+61
-189
@@ -1,34 +1,34 @@
|
||||
import json
|
||||
from datetime import datetime
|
||||
from typing import List, Any, Optional
|
||||
|
||||
from fastapi import Depends
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app import schemas
|
||||
from app.schemas.response import Response as _SchemaResponse
|
||||
from app.schemas.workflow import NameValueOption as _SchemaNameValueOption
|
||||
from app.schemas.workflow import PluginWorkflowActionGroup as _SchemaPluginWorkflowActionGroup
|
||||
from app.schemas.workflow import Workflow as _SchemaWorkflow
|
||||
from app.schemas.workflow import WorkflowActionDefinition as _SchemaWorkflowActionDefinition
|
||||
from app.schemas.workflow import WorkflowShare as _SchemaWorkflowShare
|
||||
from app.api.response import ResponseAPIRouter
|
||||
from app.application.workflow import WorkflowDefinitionCommand, WorkflowMutationCommand
|
||||
from app.chain.workflow import WorkflowChain
|
||||
from app.runtime.config import global_vars
|
||||
from app.runtime.extensions.plugin_manager import PluginManager
|
||||
from app.workflow import WorkFlowManager
|
||||
from app.db import get_async_db, get_db
|
||||
from app.db.models import Workflow, User
|
||||
from app.db.oper.systemconfig import SystemConfigOper
|
||||
from app.api.deps import get_current_active_manage_user, get_current_active_manage_user_async
|
||||
from app.db import get_async_db
|
||||
from app.db.models import User
|
||||
from app.api.deps import (
|
||||
get_current_active_manage_user,
|
||||
get_current_active_manage_user_async,
|
||||
get_workflow_definition_command,
|
||||
get_workflow_mutation_command,
|
||||
)
|
||||
from app.db.oper.workflow import WorkflowOper
|
||||
from app.adapters.external.server import MoviePilotServerHelper
|
||||
from app.scheduler import Scheduler
|
||||
from app.schemas.types import EventType, EVENT_TYPE_NAMES
|
||||
|
||||
router = ResponseAPIRouter()
|
||||
|
||||
WORKFLOW_TRIGGER_TIMER = "timer"
|
||||
WORKFLOW_TRIGGER_EVENT = "event"
|
||||
WORKFLOW_TRIGGER_MANUAL = "manual"
|
||||
|
||||
|
||||
@router.get("/", summary="所有工作流", response_model=List[schemas.Workflow])
|
||||
@router.get("/", summary="所有工作流", response_model=List[_SchemaWorkflow])
|
||||
async def list_workflows(
|
||||
db: AsyncSession = Depends(get_async_db),
|
||||
_: User = Depends(get_current_active_manage_user_async),
|
||||
@@ -39,32 +39,23 @@ async def list_workflows(
|
||||
return await WorkflowOper(db).async_list()
|
||||
|
||||
|
||||
@router.post("/", summary="创建工作流", response_model=schemas.Response[None])
|
||||
@router.post("/", summary="创建工作流", response_model=_SchemaResponse[None])
|
||||
async def create_workflow(
|
||||
workflow: schemas.Workflow,
|
||||
db: AsyncSession = Depends(get_async_db),
|
||||
workflow: _SchemaWorkflow,
|
||||
command: WorkflowDefinitionCommand = Depends(get_workflow_definition_command),
|
||||
_: User = Depends(get_current_active_manage_user_async),
|
||||
) -> Any:
|
||||
"""
|
||||
创建工作流
|
||||
"""
|
||||
if workflow.name and await WorkflowOper(db).async_get_by_name(workflow.name):
|
||||
return schemas.Response(success=False, message="已存在相同名称的工作流")
|
||||
if not workflow.add_time:
|
||||
workflow.add_time = datetime.strftime(datetime.now(), "%Y-%m-%d %H:%M:%S")
|
||||
if not workflow.state:
|
||||
workflow.state = "P"
|
||||
if not workflow.trigger_type:
|
||||
workflow.trigger_type = "timer"
|
||||
workflow_obj = Workflow(**workflow.model_dump())
|
||||
await workflow_obj.async_create(db)
|
||||
return schemas.Response(success=True, message="创建工作流成功")
|
||||
result = await command.create(workflow.model_dump(exclude={"id"}))
|
||||
return _SchemaResponse(success=result.success, message=result.message)
|
||||
|
||||
|
||||
@router.get(
|
||||
"/plugin/actions",
|
||||
summary="查询插件动作",
|
||||
response_model=List[schemas.PluginWorkflowActionGroup],
|
||||
response_model=List[_SchemaPluginWorkflowActionGroup],
|
||||
)
|
||||
def list_plugin_actions(
|
||||
plugin_id: str = None, _: User = Depends(get_current_active_manage_user)
|
||||
@@ -78,7 +69,7 @@ def list_plugin_actions(
|
||||
@router.get(
|
||||
"/actions",
|
||||
summary="所有动作",
|
||||
response_model=List[schemas.WorkflowActionDefinition],
|
||||
response_model=List[_SchemaWorkflowActionDefinition],
|
||||
)
|
||||
async def list_actions(_: User = Depends(get_current_active_manage_user_async)) -> Any:
|
||||
"""
|
||||
@@ -90,7 +81,7 @@ async def list_actions(_: User = Depends(get_current_active_manage_user_async))
|
||||
@router.get(
|
||||
"/event_types",
|
||||
summary="获取所有事件类型",
|
||||
response_model=List[schemas.NameValueOption],
|
||||
response_model=List[_SchemaNameValueOption],
|
||||
)
|
||||
async def get_event_types(_: User = Depends(get_current_active_manage_user_async)) -> Any:
|
||||
"""
|
||||
@@ -105,15 +96,15 @@ async def get_event_types(_: User = Depends(get_current_active_manage_user_async
|
||||
]
|
||||
|
||||
|
||||
@router.post("/share", summary="分享工作流", response_model=schemas.Response[None])
|
||||
@router.post("/share", summary="分享工作流", response_model=_SchemaResponse[None])
|
||||
async def workflow_share(
|
||||
workflow: schemas.WorkflowShare, _: User = Depends(get_current_active_manage_user_async)
|
||||
workflow: _SchemaWorkflowShare, _: User = Depends(get_current_active_manage_user_async)
|
||||
) -> Any:
|
||||
"""
|
||||
分享工作流
|
||||
"""
|
||||
if not workflow.id or not workflow.share_title or not workflow.share_user:
|
||||
return schemas.Response(
|
||||
return _SchemaResponse(
|
||||
success=False, message="请填写工作流ID、分享标题和分享人"
|
||||
)
|
||||
|
||||
@@ -123,10 +114,10 @@ async def workflow_share(
|
||||
share_comment=workflow.share_comment or "",
|
||||
share_user=workflow.share_user or "",
|
||||
)
|
||||
return schemas.Response(success=state, message=errmsg)
|
||||
return _SchemaResponse(success=state, message=errmsg)
|
||||
|
||||
|
||||
@router.delete("/share/{share_id}", summary="删除分享", response_model=schemas.Response[None])
|
||||
@router.delete("/share/{share_id}", summary="删除分享", response_model=_SchemaResponse[None])
|
||||
async def workflow_share_delete(
|
||||
share_id: int, _: User = Depends(get_current_active_manage_user_async)
|
||||
) -> Any:
|
||||
@@ -134,74 +125,24 @@ async def workflow_share_delete(
|
||||
删除分享
|
||||
"""
|
||||
state, errmsg = await MoviePilotServerHelper.async_workflow_share_delete_by_id(share_id=share_id)
|
||||
return schemas.Response(success=state, message=errmsg)
|
||||
return _SchemaResponse(success=state, message=errmsg)
|
||||
|
||||
|
||||
@router.post("/fork", summary="复用工作流", response_model=schemas.Response[None])
|
||||
@router.post("/fork", summary="复用工作流", response_model=_SchemaResponse[None])
|
||||
async def workflow_fork(
|
||||
workflow: schemas.WorkflowShare,
|
||||
db: AsyncSession = Depends(get_async_db),
|
||||
workflow: _SchemaWorkflowShare,
|
||||
command: WorkflowDefinitionCommand = Depends(get_workflow_definition_command),
|
||||
_: User = Depends(get_current_active_manage_user_async),
|
||||
) -> Any:
|
||||
"""
|
||||
复用工作流
|
||||
"""
|
||||
if not workflow.name:
|
||||
return schemas.Response(success=False, message="工作流名称不能为空")
|
||||
|
||||
# 解析JSON数据,添加错误处理
|
||||
try:
|
||||
actions = json.loads(workflow.actions or "[]")
|
||||
except json.JSONDecodeError:
|
||||
return schemas.Response(success=False, message="actions字段JSON格式错误")
|
||||
|
||||
try:
|
||||
flows = json.loads(workflow.flows or "[]")
|
||||
except json.JSONDecodeError:
|
||||
return schemas.Response(success=False, message="flows字段JSON格式错误")
|
||||
|
||||
try:
|
||||
context = json.loads(workflow.context or "{}")
|
||||
except json.JSONDecodeError:
|
||||
return schemas.Response(success=False, message="context字段JSON格式错误")
|
||||
|
||||
try:
|
||||
event_conditions = json.loads(workflow.event_conditions or "{}") if workflow.event_conditions else {}
|
||||
except json.JSONDecodeError:
|
||||
return schemas.Response(success=False, message="event_conditions字段JSON格式错误")
|
||||
|
||||
share_id = workflow.id
|
||||
# 创建工作流
|
||||
workflow_dict = {
|
||||
"name": workflow.name,
|
||||
"description": workflow.description,
|
||||
"timer": workflow.timer,
|
||||
"trigger_type": workflow.trigger_type or WORKFLOW_TRIGGER_TIMER,
|
||||
"event_type": workflow.event_type,
|
||||
"event_conditions": event_conditions,
|
||||
"actions": actions,
|
||||
"flows": flows,
|
||||
"context": context,
|
||||
"state": "P", # 默认暂停状态
|
||||
}
|
||||
|
||||
# 检查名称是否重复
|
||||
workflow_oper = WorkflowOper(db)
|
||||
if await workflow_oper.async_get_by_name(workflow_dict["name"]):
|
||||
return schemas.Response(success=False, message="已存在相同名称的工作流")
|
||||
|
||||
# 创建新工作流
|
||||
workflow_obj = await Workflow(**workflow_dict).async_create(db)
|
||||
|
||||
# 更新复用次数
|
||||
if workflow_obj and share_id:
|
||||
await MoviePilotServerHelper.async_workflow_fork_by_id(share_id=share_id)
|
||||
|
||||
return schemas.Response(success=True, message="复用成功")
|
||||
result = await command.fork(workflow.model_dump(), share_id=workflow.id)
|
||||
return _SchemaResponse(success=result.success, message=result.message)
|
||||
|
||||
|
||||
@router.get(
|
||||
"/shares", summary="查询分享的工作流", response_model=List[schemas.WorkflowShare]
|
||||
"/shares", summary="查询分享的工作流", response_model=List[_SchemaWorkflowShare]
|
||||
)
|
||||
async def workflow_shares(
|
||||
name: Optional[str] = None,
|
||||
@@ -216,7 +157,7 @@ async def workflow_shares(
|
||||
|
||||
|
||||
@router.post(
|
||||
"/{workflow_id}/run", summary="执行工作流", response_model=schemas.Response[None]
|
||||
"/{workflow_id}/run", summary="执行工作流", response_model=_SchemaResponse[None]
|
||||
)
|
||||
def run_workflow(
|
||||
workflow_id: int,
|
||||
@@ -228,96 +169,56 @@ def run_workflow(
|
||||
"""
|
||||
state, errmsg = WorkflowChain().process(workflow_id, from_begin=from_begin)
|
||||
if not state:
|
||||
return schemas.Response(success=False, message=errmsg)
|
||||
return schemas.Response(success=True)
|
||||
return _SchemaResponse(success=False, message=errmsg)
|
||||
return _SchemaResponse(success=True)
|
||||
|
||||
|
||||
@router.post(
|
||||
"/{workflow_id}/start", summary="启用工作流", response_model=schemas.Response[None]
|
||||
"/{workflow_id}/start", summary="启用工作流", response_model=_SchemaResponse[None]
|
||||
)
|
||||
def start_workflow(
|
||||
workflow_id: int,
|
||||
db: Session = Depends(get_db),
|
||||
command: WorkflowMutationCommand = Depends(get_workflow_mutation_command),
|
||||
_: User = Depends(get_current_active_manage_user),
|
||||
) -> Any:
|
||||
"""
|
||||
启用工作流
|
||||
"""
|
||||
workflow = WorkflowOper(db).get(workflow_id)
|
||||
if not workflow:
|
||||
return schemas.Response(success=False, message="工作流不存在")
|
||||
trigger_type = workflow.trigger_type or WORKFLOW_TRIGGER_TIMER
|
||||
if trigger_type == WORKFLOW_TRIGGER_TIMER and not workflow.timer:
|
||||
return schemas.Response(success=False, message="定时工作流缺少定时器配置")
|
||||
if trigger_type not in {
|
||||
WORKFLOW_TRIGGER_TIMER,
|
||||
WORKFLOW_TRIGGER_EVENT,
|
||||
WORKFLOW_TRIGGER_MANUAL,
|
||||
}:
|
||||
return schemas.Response(success=False, message="工作流触发类型不支持")
|
||||
# 先更新状态,事件触发注册会重新读取工作流并跳过暂停状态。
|
||||
workflow.update_state(db, workflow_id, "W")
|
||||
if trigger_type == WORKFLOW_TRIGGER_TIMER:
|
||||
# 添加定时任务
|
||||
Scheduler().update_workflow_job(workflow)
|
||||
elif trigger_type == WORKFLOW_TRIGGER_EVENT:
|
||||
# 事件触发:添加到事件触发器
|
||||
WorkFlowManager().load_workflow_events(workflow_id)
|
||||
return schemas.Response(success=True)
|
||||
result = command.start(workflow_id)
|
||||
return _SchemaResponse(success=result.success, message=result.message)
|
||||
|
||||
|
||||
@router.post(
|
||||
"/{workflow_id}/pause", summary="停用工作流", response_model=schemas.Response[None]
|
||||
"/{workflow_id}/pause", summary="停用工作流", response_model=_SchemaResponse[None]
|
||||
)
|
||||
def pause_workflow(
|
||||
workflow_id: int,
|
||||
db: Session = Depends(get_db),
|
||||
command: WorkflowMutationCommand = Depends(get_workflow_mutation_command),
|
||||
_: User = Depends(get_current_active_manage_user),
|
||||
) -> Any:
|
||||
"""
|
||||
停用工作流
|
||||
"""
|
||||
workflow = WorkflowOper(db).get(workflow_id)
|
||||
if not workflow:
|
||||
return schemas.Response(success=False, message="工作流不存在")
|
||||
# 根据触发类型进行不同处理
|
||||
if workflow.trigger_type == WORKFLOW_TRIGGER_TIMER:
|
||||
# 定时触发:移除定时任务
|
||||
Scheduler().remove_workflow_job(workflow)
|
||||
elif workflow.trigger_type == WORKFLOW_TRIGGER_EVENT:
|
||||
# 事件触发:从事件触发器中移除
|
||||
WorkFlowManager().remove_workflow_event(workflow_id, workflow.event_type)
|
||||
# 停止工作流
|
||||
global_vars.stop_workflow(workflow_id)
|
||||
# 更新状态
|
||||
workflow.update_state(db, workflow_id, "P")
|
||||
return schemas.Response(success=True)
|
||||
result = command.pause(workflow_id)
|
||||
return _SchemaResponse(success=result.success, message=result.message)
|
||||
|
||||
|
||||
@router.post(
|
||||
"/{workflow_id}/reset", summary="重置工作流", response_model=schemas.Response[None]
|
||||
"/{workflow_id}/reset", summary="重置工作流", response_model=_SchemaResponse[None]
|
||||
)
|
||||
async def reset_workflow(
|
||||
workflow_id: int,
|
||||
db: AsyncSession = Depends(get_async_db),
|
||||
command: WorkflowDefinitionCommand = Depends(get_workflow_definition_command),
|
||||
_: User = Depends(get_current_active_manage_user_async),
|
||||
) -> Any:
|
||||
"""
|
||||
重置工作流
|
||||
"""
|
||||
workflow = await WorkflowOper(db).async_get(workflow_id)
|
||||
if not workflow:
|
||||
return schemas.Response(success=False, message="工作流不存在")
|
||||
# 停止工作流
|
||||
global_vars.stop_workflow(workflow_id)
|
||||
# 重置工作流
|
||||
await Workflow.async_reset(db, workflow_id, reset_count=True)
|
||||
# 删除缓存
|
||||
SystemConfigOper().delete(f"WorkflowCache-{workflow_id}")
|
||||
return schemas.Response(success=True)
|
||||
result = await command.reset(workflow_id)
|
||||
return _SchemaResponse(success=result.success, message=result.message)
|
||||
|
||||
|
||||
@router.get("/{workflow_id}", summary="工作流详情", response_model=schemas.Workflow)
|
||||
@router.get("/{workflow_id}", summary="工作流详情", response_model=_SchemaWorkflow)
|
||||
async def get_workflow(
|
||||
workflow_id: int,
|
||||
db: AsyncSession = Depends(get_async_db),
|
||||
@@ -329,56 +230,27 @@ async def get_workflow(
|
||||
return await WorkflowOper(db).async_get(workflow_id)
|
||||
|
||||
|
||||
@router.put("/{workflow_id}", summary="更新工作流", response_model=schemas.Response[None])
|
||||
@router.put("/{workflow_id}", summary="更新工作流", response_model=_SchemaResponse[None])
|
||||
def update_workflow(
|
||||
workflow: schemas.Workflow,
|
||||
db: Session = Depends(get_db),
|
||||
workflow: _SchemaWorkflow,
|
||||
command: WorkflowMutationCommand = Depends(get_workflow_mutation_command),
|
||||
_: User = Depends(get_current_active_manage_user),
|
||||
) -> Any:
|
||||
"""
|
||||
更新工作流
|
||||
"""
|
||||
if not workflow.id:
|
||||
return schemas.Response(success=False, message="工作流ID不能为空")
|
||||
workflow_oper = WorkflowOper(db)
|
||||
wf = workflow_oper.get(workflow.id)
|
||||
if not wf:
|
||||
return schemas.Response(success=False, message="工作流不存在")
|
||||
if not wf.trigger_type:
|
||||
workflow.trigger_type = "timer"
|
||||
wf.update(db, workflow.model_dump())
|
||||
# 更新后的工作流对象
|
||||
updated_workflow = workflow_oper.get(workflow.id)
|
||||
scheduler = Scheduler()
|
||||
scheduler.remove_workflow_job(updated_workflow)
|
||||
if not updated_workflow.trigger_type or updated_workflow.trigger_type == WORKFLOW_TRIGGER_TIMER:
|
||||
if updated_workflow.timer:
|
||||
scheduler.update_workflow_job(updated_workflow)
|
||||
# 更新事件注册
|
||||
WorkFlowManager().update_workflow_event(updated_workflow)
|
||||
return schemas.Response(success=True, message="更新成功")
|
||||
result = command.update(workflow.model_dump())
|
||||
return _SchemaResponse(success=result.success, message=result.message)
|
||||
|
||||
|
||||
@router.delete("/{workflow_id}", summary="删除工作流", response_model=schemas.Response[None])
|
||||
@router.delete("/{workflow_id}", summary="删除工作流", response_model=_SchemaResponse[None])
|
||||
def delete_workflow(
|
||||
workflow_id: int,
|
||||
db: Session = Depends(get_db),
|
||||
command: WorkflowMutationCommand = Depends(get_workflow_mutation_command),
|
||||
_: User = Depends(get_current_active_manage_user),
|
||||
) -> Any:
|
||||
"""
|
||||
删除工作流
|
||||
"""
|
||||
workflow = WorkflowOper(db).get(workflow_id)
|
||||
if not workflow:
|
||||
return schemas.Response(success=False, message="工作流不存在")
|
||||
if not workflow.trigger_type or workflow.trigger_type == WORKFLOW_TRIGGER_TIMER:
|
||||
# 定时触发:删除定时任务
|
||||
Scheduler().remove_workflow_job(workflow)
|
||||
elif workflow.trigger_type == WORKFLOW_TRIGGER_EVENT:
|
||||
# 事件触发:从事件触发器中移除
|
||||
WorkFlowManager().remove_workflow_event(workflow_id, workflow.event_type)
|
||||
# 删除工作流
|
||||
Workflow.delete(db, workflow_id)
|
||||
# 删除缓存
|
||||
SystemConfigOper().delete(f"WorkflowCache-{workflow_id}")
|
||||
return schemas.Response(success=True, message="删除成功")
|
||||
result = command.delete(workflow_id)
|
||||
return _SchemaResponse(success=result.success, message=result.message)
|
||||
|
||||
Reference in New Issue
Block a user