初始化提交
This commit is contained in:
+182
@@ -0,0 +1,182 @@
|
||||
# ///
|
||||
# callback.py
|
||||
# 描述:回调接口,用于重置和检测节点微信状态
|
||||
# 作者:AI Generated
|
||||
# 创建日期:2026-04-05
|
||||
# ///
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from pydantic import BaseModel
|
||||
from typing import Optional, Dict, Any
|
||||
|
||||
from services.node_manager import node_manager
|
||||
from services.log_service import log_service
|
||||
from database_service import get_db_service
|
||||
from utils import require_api_key
|
||||
|
||||
|
||||
router = APIRouter(prefix="/callback", tags=["回调接口"])
|
||||
|
||||
|
||||
class NodeResetRequest(BaseModel):
|
||||
node_id: str
|
||||
|
||||
|
||||
class NodeCallbackRequest(BaseModel):
|
||||
node_id: str
|
||||
|
||||
|
||||
async def sync_node_from_db(node_id: str) -> bool:
|
||||
db_service = get_db_service()
|
||||
if not db_service:
|
||||
return False
|
||||
node = db_service.get_node(node_id)
|
||||
if not node:
|
||||
return False
|
||||
existing = node_manager.nodes.get(node_id)
|
||||
if existing:
|
||||
existing.api_url = node.api_url
|
||||
existing.api_key = node.api_key
|
||||
else:
|
||||
await node_manager.add_node(
|
||||
node_id=node.node_id,
|
||||
name=node.name,
|
||||
api_url=node.api_url,
|
||||
api_key=node.api_key,
|
||||
description=node.description or "",
|
||||
group=node.group or "default"
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
@router.post("/node/reset", summary="重置节点微信状态")
|
||||
async def reset_node_wechat_status(request: NodeResetRequest, _=Depends(require_api_key)) -> Dict[str, Any]:
|
||||
"""
|
||||
重置节点的微信状态为online
|
||||
通过发送消息到文件传输助手来检测微信是否正常
|
||||
如果发送成功,则重置状态为online
|
||||
"""
|
||||
node_id = request.node_id
|
||||
await sync_node_from_db(node_id)
|
||||
node = await node_manager.get_node(node_id)
|
||||
if not node:
|
||||
raise HTTPException(status_code=404, detail=f"Node '{node_id}' not found")
|
||||
|
||||
await node_manager.call_node_api(node_id, "/api/wechat/initialize", method="POST")
|
||||
|
||||
result = await node_manager.call_node_api(
|
||||
node_id,
|
||||
"/api/message/send",
|
||||
method="POST",
|
||||
data={"receiver": "文件传输助手", "message": "WXAuto Center 状态检测消息"}
|
||||
)
|
||||
|
||||
if result.get("success"):
|
||||
node.wechat_status = "online"
|
||||
db_service = get_db_service()
|
||||
if db_service:
|
||||
db_service.update_node(node_id, wechat_status="online")
|
||||
log_service.success(f"Node {node_id} WeChat status reset to online", "Callback")
|
||||
return {
|
||||
"success": True,
|
||||
"message": "WeChat status reset",
|
||||
"data": {
|
||||
"node_id": node_id,
|
||||
"wechat_status": "online",
|
||||
"check_result": "success"
|
||||
}
|
||||
}
|
||||
else:
|
||||
node.wechat_status = "offline"
|
||||
db_service = get_db_service()
|
||||
if db_service:
|
||||
db_service.update_node(node_id, wechat_status="offline")
|
||||
error_msg = result.get("error", "Unknown error")
|
||||
log_service.error(f"Node {node_id} WeChat status check failed: {error_msg}", "Callback")
|
||||
return {
|
||||
"success": False,
|
||||
"message": "WeChat status check failed",
|
||||
"data": {
|
||||
"node_id": node_id,
|
||||
"wechat_status": "offline",
|
||||
"check_result": "failed",
|
||||
"error": error_msg
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@router.post("/node/check", summary="检测节点微信状态")
|
||||
async def check_node_wechat_status(request: NodeCallbackRequest, _=Depends(require_api_key)) -> Dict[str, Any]:
|
||||
"""
|
||||
检测节点的微信状态
|
||||
通过发送消息到文件传输助手来检测微信是否正常
|
||||
返回检测结果
|
||||
"""
|
||||
node_id = request.node_id
|
||||
await sync_node_from_db(node_id)
|
||||
node = await node_manager.get_node(node_id)
|
||||
if not node:
|
||||
raise HTTPException(status_code=404, detail=f"Node '{node_id}' not found")
|
||||
|
||||
await node_manager.call_node_api(node_id, "/api/wechat/initialize", method="POST")
|
||||
|
||||
result = await node_manager.call_node_api(
|
||||
node_id,
|
||||
"/api/message/send",
|
||||
method="POST",
|
||||
data={"receiver": "文件传输助手", "message": "WXAuto Center 状态检测消息"}
|
||||
)
|
||||
|
||||
if result.get("success"):
|
||||
node.wechat_status = "online"
|
||||
db_service = get_db_service()
|
||||
if db_service:
|
||||
db_service.update_node(node_id, wechat_status="online")
|
||||
return {
|
||||
"success": True,
|
||||
"message": "WeChat is normal",
|
||||
"data": {
|
||||
"node_id": node_id,
|
||||
"wechat_status": "online",
|
||||
"api_status": node.status
|
||||
}
|
||||
}
|
||||
else:
|
||||
node.wechat_status = "offline"
|
||||
db_service = get_db_service()
|
||||
if db_service:
|
||||
db_service.update_node(node_id, wechat_status="offline")
|
||||
return {
|
||||
"success": False,
|
||||
"message": "WeChat is abnormal",
|
||||
"data": {
|
||||
"node_id": node_id,
|
||||
"wechat_status": "offline",
|
||||
"api_status": node.status,
|
||||
"error": result.get("error", "Unknown error")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@router.get("/node/{node_id}/status", summary="获取节点回调状态")
|
||||
async def get_node_callback_status(node_id: str, _=Depends(require_api_key)) -> Dict[str, Any]:
|
||||
"""
|
||||
获取节点的当前状态,用于回调确认
|
||||
"""
|
||||
node = await node_manager.get_node(node_id)
|
||||
if not node:
|
||||
raise HTTPException(status_code=404, detail=f"Node '{node_id}' not found")
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"data": {
|
||||
"node_id": node.node_id,
|
||||
"name": node.name,
|
||||
"api_url": node.api_url,
|
||||
"api_status": node.status,
|
||||
"wechat_status": node.wechat_status,
|
||||
"is_healthy": node.is_healthy,
|
||||
"enabled": node.enabled,
|
||||
"group": node.group
|
||||
}
|
||||
}
|
||||
+176
@@ -0,0 +1,176 @@
|
||||
# ///
|
||||
# external.py
|
||||
# 描述:外部扩展接口,供其他程序调用中控系统
|
||||
# 作者:AI Generated
|
||||
# 创建日期:2026-04-05
|
||||
# ///
|
||||
|
||||
from fastapi import APIRouter, HTTPException, Depends
|
||||
from typing import List, Optional, Dict, Any
|
||||
from pydantic import BaseModel
|
||||
|
||||
from services.node_manager import node_manager
|
||||
from plugins.base import PluginRegistry
|
||||
from utils import require_external_key
|
||||
|
||||
|
||||
router = APIRouter(prefix="/external", tags=["外部扩展接口"])
|
||||
|
||||
|
||||
class ExternalMessageRequest(BaseModel):
|
||||
node_id: str
|
||||
who: str
|
||||
msg: str
|
||||
msg_type: str = "text"
|
||||
|
||||
|
||||
class DataTriggerRequest(BaseModel):
|
||||
node_id: str
|
||||
source: str
|
||||
event: str
|
||||
data: Dict[str, Any]
|
||||
auto_send: bool = True
|
||||
target: Optional[str] = None
|
||||
|
||||
|
||||
class PluginExecuteRequest(BaseModel):
|
||||
plugin_name: str
|
||||
action: str
|
||||
params: Dict[str, Any] = {}
|
||||
|
||||
|
||||
async def sync_node_from_db(node_id: str) -> bool:
|
||||
from database_service import get_db_service
|
||||
db_service = get_db_service()
|
||||
if not db_service:
|
||||
return False
|
||||
node = db_service.get_node(node_id)
|
||||
if not node:
|
||||
return False
|
||||
existing = node_manager.nodes.get(node_id)
|
||||
if existing:
|
||||
existing.api_url = node.api_url
|
||||
existing.api_key = node.api_key
|
||||
else:
|
||||
await node_manager.add_node(
|
||||
node_id=node.node_id,
|
||||
name=node.name,
|
||||
api_url=node.api_url,
|
||||
api_key=node.api_key,
|
||||
description=node.description or "",
|
||||
group=node.group or "default"
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
@router.post("/send", summary="外部接口-发送消息")
|
||||
async def external_send_message(request: ExternalMessageRequest,
|
||||
_=Depends(require_external_key)) -> Dict[str, Any]:
|
||||
await sync_node_from_db(request.node_id)
|
||||
result = await node_manager.send_message(
|
||||
node_id=request.node_id,
|
||||
who=request.who,
|
||||
msg=request.msg,
|
||||
msg_type=request.msg_type
|
||||
)
|
||||
return result
|
||||
|
||||
|
||||
@router.post("/trigger", summary="外部接口-触发数据处理")
|
||||
async def external_trigger(request: DataTriggerRequest,
|
||||
_=Depends(require_external_key)) -> Dict[str, Any]:
|
||||
plugin = PluginRegistry.get(request.source)
|
||||
if not plugin:
|
||||
raise HTTPException(status_code=404, detail=f"Plugin '{request.source}' not found")
|
||||
|
||||
if not plugin.enabled:
|
||||
raise HTTPException(status_code=400, detail=f"Plugin '{request.source}' is disabled")
|
||||
|
||||
execute_result = plugin.execute({
|
||||
"event": request.event,
|
||||
"data": request.data
|
||||
})
|
||||
|
||||
if request.auto_send and request.target:
|
||||
await sync_node_from_db(request.node_id)
|
||||
msg = request.data.get("message", str(request.data))
|
||||
send_result = await node_manager.send_message(
|
||||
node_id=request.node_id,
|
||||
who=request.target,
|
||||
msg=msg
|
||||
)
|
||||
execute_result["send_result"] = send_result
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"plugin_result": execute_result,
|
||||
"data_triggered": True
|
||||
}
|
||||
|
||||
|
||||
@router.post("/plugin/execute", summary="外部接口-执行插件")
|
||||
async def execute_plugin(request: PluginExecuteRequest,
|
||||
_=Depends(require_external_key)) -> Dict[str, Any]:
|
||||
plugin = PluginRegistry.get(request.plugin_name)
|
||||
if not plugin:
|
||||
raise HTTPException(status_code=404, detail=f"Plugin '{request.plugin_name}' not found")
|
||||
|
||||
if not plugin.enabled:
|
||||
raise HTTPException(status_code=400, detail=f"Plugin '{request.plugin_name}' is disabled")
|
||||
|
||||
result = plugin.execute(request.params)
|
||||
return {"success": True, "result": result}
|
||||
|
||||
|
||||
@router.get("/plugins", summary="外部接口-获取可用插件列表")
|
||||
async def get_plugins(_=Depends(require_external_key)) -> Dict[str, Any]:
|
||||
plugins = PluginRegistry.get_all()
|
||||
enabled_plugins = [p for p in plugins if p.enabled]
|
||||
return {
|
||||
"success": True,
|
||||
"plugins": [p.get_info() for p in enabled_plugins],
|
||||
"count": len(enabled_plugins)
|
||||
}
|
||||
|
||||
|
||||
@router.get("/nodes", summary="外部接口-获取可用节点")
|
||||
async def get_available_nodes(_=Depends(require_external_key)) -> Dict[str, Any]:
|
||||
from database_service import get_db_service
|
||||
db_service = get_db_service()
|
||||
if db_service:
|
||||
nodes = db_service.get_enabled_nodes()
|
||||
return {"success": True, "nodes": [n.to_dict() for n in nodes], "count": len(nodes)}
|
||||
nodes = await node_manager.get_enabled_nodes()
|
||||
return {"success": True, "nodes": [n.to_dict() for n in nodes], "count": len(nodes)}
|
||||
|
||||
|
||||
@router.post("/ai/process", summary="外部接口-AI处理消息")
|
||||
async def ai_process_message(
|
||||
input_text: str,
|
||||
context: Optional[Dict[str, Any]] = None,
|
||||
model: Optional[str] = None,
|
||||
_=Depends(require_external_key)
|
||||
) -> Dict[str, Any]:
|
||||
ai_plugin = PluginRegistry.get("simple_ai_agent")
|
||||
if not ai_plugin or not ai_plugin.enabled:
|
||||
raise HTTPException(status_code=400, detail="AI agent not available")
|
||||
|
||||
if model:
|
||||
ai_plugin.model = model
|
||||
|
||||
result = ai_plugin.process(input_text, context or {})
|
||||
return {"success": True, "result": result}
|
||||
|
||||
|
||||
@router.post("/webhook/{event}", summary="外部接口-Webhook接收")
|
||||
async def receive_webhook(event: str,
|
||||
payload: Dict[str, Any],
|
||||
_=Depends(require_external_key)) -> Dict[str, Any]:
|
||||
webhook_plugin = PluginRegistry.get("webhook_trigger")
|
||||
if webhook_plugin and webhook_plugin.enabled:
|
||||
result = webhook_plugin.execute({
|
||||
"event": event,
|
||||
"data": payload
|
||||
})
|
||||
return {"success": True, "result": result}
|
||||
return {"success": True, "message": "Webhook received", "event": event}
|
||||
+148
@@ -0,0 +1,148 @@
|
||||
# ///
|
||||
# messages.py
|
||||
# 描述:消息发送API路由
|
||||
# 作者:AI Generated
|
||||
# 创建日期:2026-04-05
|
||||
# ///
|
||||
|
||||
from fastapi import APIRouter, HTTPException, Depends
|
||||
from typing import List, Dict, Any
|
||||
from pydantic import BaseModel
|
||||
|
||||
from services.node_manager import node_manager
|
||||
from utils import require_api_key, check_node_health
|
||||
|
||||
|
||||
router = APIRouter(prefix="/messages", tags=["消息管理"])
|
||||
|
||||
|
||||
class SendMessageRequest(BaseModel):
|
||||
node_id: str
|
||||
who: str
|
||||
msg: str
|
||||
msg_type: str = "text"
|
||||
|
||||
|
||||
class SendGroupMessageRequest(BaseModel):
|
||||
node_id: str
|
||||
group_name: str
|
||||
msg: str
|
||||
msg_type: str = "text"
|
||||
|
||||
|
||||
class BatchMessageRequest(BaseModel):
|
||||
messages: List[Dict[str, Any]]
|
||||
|
||||
|
||||
async def sync_node_from_db(node_id: str) -> bool:
|
||||
from database_service import get_db_service
|
||||
db_service = get_db_service()
|
||||
if not db_service:
|
||||
return False
|
||||
node = db_service.get_node(node_id)
|
||||
if not node:
|
||||
return False
|
||||
existing = node_manager.nodes.get(node_id)
|
||||
if existing:
|
||||
existing.api_url = node.api_url
|
||||
existing.api_key = node.api_key
|
||||
else:
|
||||
await node_manager.add_node(
|
||||
node_id=node.node_id,
|
||||
name=node.name,
|
||||
api_url=node.api_url,
|
||||
api_key=node.api_key,
|
||||
description=node.description or "",
|
||||
group=node.group or "default"
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
@router.post("/send", summary="发送消息")
|
||||
async def send_message(request: SendMessageRequest,
|
||||
_=Depends(require_api_key)) -> Dict[str, Any]:
|
||||
await sync_node_from_db(request.node_id)
|
||||
await check_node_health(request.node_id)
|
||||
|
||||
result = await node_manager.send_message(
|
||||
node_id=request.node_id,
|
||||
who=request.who,
|
||||
msg=request.msg,
|
||||
msg_type=request.msg_type
|
||||
)
|
||||
return result
|
||||
|
||||
|
||||
@router.post("/send_group", summary="发送群消息")
|
||||
async def send_group_message(request: SendGroupMessageRequest,
|
||||
_=Depends(require_api_key)) -> Dict[str, Any]:
|
||||
await sync_node_from_db(request.node_id)
|
||||
await check_node_health(request.node_id)
|
||||
|
||||
result = await node_manager.send_message_to_group(
|
||||
node_id=request.node_id,
|
||||
group_name=request.group_name,
|
||||
msg=request.msg,
|
||||
msg_type=request.msg_type
|
||||
)
|
||||
return result
|
||||
|
||||
|
||||
@router.post("/batch", summary="批量发送消息")
|
||||
async def batch_send(request: BatchMessageRequest,
|
||||
_=Depends(require_api_key)) -> Dict[str, Any]:
|
||||
results = []
|
||||
for msg_item in request.messages:
|
||||
node_id = msg_item.get("node_id")
|
||||
who = msg_item.get("who")
|
||||
msg = msg_item.get("msg")
|
||||
msg_type = msg_item.get("msg_type", "text")
|
||||
|
||||
if not all([node_id, who, msg]):
|
||||
results.append({
|
||||
"success": False,
|
||||
"error": "Missing required fields",
|
||||
"item": msg_item
|
||||
})
|
||||
continue
|
||||
|
||||
is_healthy, reason = await node_manager.is_node_healthy(node_id)
|
||||
if not is_healthy:
|
||||
results.append({
|
||||
"success": False,
|
||||
"error": f"Node not healthy: {reason}",
|
||||
"node_id": node_id,
|
||||
"who": who
|
||||
})
|
||||
continue
|
||||
|
||||
result = await node_manager.send_message(node_id, who, msg, msg_type)
|
||||
results.append({"node_id": node_id, "who": who, "result": result})
|
||||
|
||||
return {"success": True, "results": results, "total": len(results)}
|
||||
|
||||
|
||||
@router.post("/template/{node_id}/{who}", summary="发送模板消息")
|
||||
async def send_template_message(node_id: str, who: str,
|
||||
template: str,
|
||||
params: Dict[str, str],
|
||||
_=Depends(require_api_key)) -> Dict[str, Any]:
|
||||
await check_node_health(node_id)
|
||||
|
||||
try:
|
||||
msg = template.format(**params)
|
||||
except KeyError as e:
|
||||
raise HTTPException(status_code=400, detail=f"Missing template parameter: {e}")
|
||||
|
||||
result = await node_manager.send_message(node_id, who, msg)
|
||||
return result
|
||||
|
||||
|
||||
@router.get("/history/{node_id}/{chat_name}", summary="获取消息历史")
|
||||
async def get_message_history(node_id: str, chat_name: str,
|
||||
limit: int = 50,
|
||||
_=Depends(require_api_key)) -> Dict[str, Any]:
|
||||
await check_node_health(node_id)
|
||||
|
||||
result = await node_manager.get_messages(node_id, chat_name, limit)
|
||||
return result
|
||||
+201
@@ -0,0 +1,201 @@
|
||||
# ///
|
||||
# nodes.py
|
||||
# 描述:节点管理API路由
|
||||
# 作者:AI Generated
|
||||
# 创建日期:2026-04-05
|
||||
# ///
|
||||
|
||||
from fastapi import APIRouter, HTTPException, Depends
|
||||
from typing import List, Optional, Dict, Any
|
||||
from pydantic import BaseModel
|
||||
|
||||
from services.node_manager import node_manager
|
||||
from config import save_config_to_file, get_settings, NodeConfig
|
||||
from utils import require_api_key
|
||||
|
||||
|
||||
router = APIRouter(prefix="/nodes", tags=["节点管理"])
|
||||
|
||||
|
||||
class NodeAddRequest(BaseModel):
|
||||
node_id: str
|
||||
name: str
|
||||
api_url: str
|
||||
api_key: str
|
||||
description: str = ""
|
||||
group: str = "default"
|
||||
|
||||
|
||||
class NodeUpdateRequest(BaseModel):
|
||||
name: Optional[str] = None
|
||||
api_url: Optional[str] = None
|
||||
api_key: Optional[str] = None
|
||||
description: Optional[str] = None
|
||||
group: Optional[str] = None
|
||||
enabled: Optional[bool] = None
|
||||
|
||||
|
||||
def save_nodes_config():
|
||||
nodes_data = node_manager.to_config()
|
||||
get_settings().nodes = [NodeConfig(**n) for n in nodes_data]
|
||||
save_config_to_file()
|
||||
|
||||
|
||||
@router.get("/", summary="获取所有节点")
|
||||
async def get_nodes(group: Optional[str] = None, _=Depends(require_api_key)) -> Dict[str, Any]:
|
||||
from database_service import get_db_service
|
||||
db_service = get_db_service()
|
||||
if db_service:
|
||||
nodes = db_service.get_all_nodes()
|
||||
result_nodes = [n.to_dict() for n in nodes]
|
||||
return {"success": True, "data": result_nodes, "count": len(result_nodes)}
|
||||
|
||||
if group:
|
||||
nodes = await node_manager.get_nodes_by_group(group)
|
||||
else:
|
||||
nodes = await node_manager.get_all_nodes()
|
||||
|
||||
result_nodes = []
|
||||
for node in nodes:
|
||||
node_dict = node.to_dict()
|
||||
result_nodes.append(node_dict)
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"data": result_nodes,
|
||||
"count": len(result_nodes)
|
||||
}
|
||||
|
||||
|
||||
@router.get("/{node_id}", summary="获取指定节点信息")
|
||||
async def get_node(node_id: str, _=Depends(require_api_key)) -> Dict[str, Any]:
|
||||
from database_service import get_db_service
|
||||
db_service = get_db_service()
|
||||
if db_service:
|
||||
node = db_service.get_node(node_id)
|
||||
if node:
|
||||
return {"success": True, "data": node.to_dict()}
|
||||
node = await node_manager.get_node(node_id)
|
||||
if not node:
|
||||
raise HTTPException(status_code=404, detail=f"Node '{node_id}' not found")
|
||||
return {"success": True, "data": node.to_dict()}
|
||||
|
||||
|
||||
@router.post("/", summary="添加节点")
|
||||
async def add_node(request: NodeAddRequest, _=Depends(require_api_key)) -> Dict[str, Any]:
|
||||
from database_service import get_db_service
|
||||
db_service = get_db_service()
|
||||
if db_service:
|
||||
db_service.add_node(
|
||||
node_id=request.node_id,
|
||||
name=request.name,
|
||||
api_url=request.api_url,
|
||||
api_key=request.api_key,
|
||||
description=request.description or "",
|
||||
group=request.group or "default"
|
||||
)
|
||||
|
||||
success = await node_manager.add_node(
|
||||
node_id=request.node_id,
|
||||
name=request.name,
|
||||
api_url=request.api_url,
|
||||
api_key=request.api_key,
|
||||
description=request.description,
|
||||
group=request.group
|
||||
)
|
||||
if not success:
|
||||
raise HTTPException(status_code=400, detail=f"Node '{request.node_id}' already exists")
|
||||
save_nodes_config()
|
||||
return {"success": True, "message": f"Node '{request.node_id}' added successfully"}
|
||||
|
||||
|
||||
@router.put("/{node_id}", summary="更新节点信息")
|
||||
async def update_node(node_id: str, request: NodeUpdateRequest,
|
||||
_=Depends(require_api_key)) -> Dict[str, Any]:
|
||||
update_data = request.model_dump(exclude_unset=True)
|
||||
|
||||
from database_service import get_db_service
|
||||
db_service = get_db_service()
|
||||
if db_service:
|
||||
db_service.update_node(node_id, **update_data)
|
||||
|
||||
success = await node_manager.update_node(node_id, **update_data)
|
||||
if not success:
|
||||
raise HTTPException(status_code=404, detail=f"Node '{node_id}' not found")
|
||||
save_nodes_config()
|
||||
return {"success": True, "message": f"Node '{node_id}' updated successfully"}
|
||||
|
||||
|
||||
@router.delete("/{node_id}", summary="删除节点")
|
||||
async def delete_node(node_id: str, _=Depends(require_api_key)) -> Dict[str, Any]:
|
||||
from database_service import get_db_service
|
||||
db_service = get_db_service()
|
||||
if db_service:
|
||||
db_service.delete_node(node_id)
|
||||
|
||||
success = await node_manager.remove_node(node_id)
|
||||
if not success:
|
||||
raise HTTPException(status_code=404, detail=f"Node '{node_id}' not found")
|
||||
save_nodes_config()
|
||||
return {"success": True, "message": f"Node '{node_id}' deleted successfully"}
|
||||
|
||||
|
||||
@router.get("/{node_id}/status", summary="检查节点状态")
|
||||
async def check_node_status(node_id: str, _=Depends(require_api_key)) -> Dict[str, Any]:
|
||||
api_status = await node_manager.check_node_status(node_id)
|
||||
is_healthy, health_msg = await node_manager.is_node_healthy(node_id)
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"data": {
|
||||
"node_id": node_id,
|
||||
"api_status": api_status,
|
||||
"is_healthy": is_healthy,
|
||||
"health_message": health_msg
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@router.post("/{node_id}/enable", summary="启用节点")
|
||||
async def enable_node(node_id: str, _=Depends(require_api_key)) -> Dict[str, Any]:
|
||||
from database_service import get_db_service
|
||||
db_service = get_db_service()
|
||||
if db_service:
|
||||
db_service.update_node(node_id, enabled=True)
|
||||
success = await node_manager.update_node(node_id, enabled=True)
|
||||
if not success:
|
||||
raise HTTPException(status_code=404, detail=f"Node '{node_id}' not found")
|
||||
save_nodes_config()
|
||||
return {"success": True, "message": f"Node '{node_id}' enabled"}
|
||||
|
||||
|
||||
@router.post("/{node_id}/disable", summary="禁用节点")
|
||||
async def disable_node(node_id: str, _=Depends(require_api_key)) -> Dict[str, Any]:
|
||||
from database_service import get_db_service
|
||||
db_service = get_db_service()
|
||||
if db_service:
|
||||
db_service.update_node(node_id, enabled=False)
|
||||
success = await node_manager.update_node(node_id, enabled=False)
|
||||
if not success:
|
||||
raise HTTPException(status_code=404, detail=f"Node '{node_id}' not found")
|
||||
save_nodes_config()
|
||||
return {"success": True, "message": f"Node '{node_id}' disabled"}
|
||||
|
||||
|
||||
@router.get("/{node_id}/friends", summary="获取节点好友列表")
|
||||
async def get_friends(node_id: str, _=Depends(require_api_key)) -> Dict[str, Any]:
|
||||
result = await node_manager.get_friends_list(node_id)
|
||||
return result
|
||||
|
||||
|
||||
@router.get("/{node_id}/groups", summary="获取节点群列表")
|
||||
async def get_groups(node_id: str, _=Depends(require_api_key)) -> Dict[str, Any]:
|
||||
result = await node_manager.get_groups_list(node_id)
|
||||
return result
|
||||
|
||||
|
||||
@router.get("/{node_id}/messages/{chat_name}", summary="获取聊天消息")
|
||||
async def get_messages(node_id: str, chat_name: str, limit: int = 20,
|
||||
_=Depends(require_api_key)) -> Dict[str, Any]:
|
||||
result = await node_manager.get_messages(node_id, chat_name, limit)
|
||||
return result
|
||||
+412
@@ -0,0 +1,412 @@
|
||||
# ///
|
||||
# plugins.py
|
||||
# 描述:插件管理API路由
|
||||
# 作者:AI Generated
|
||||
# 创建日期:2026-04-05
|
||||
# ///
|
||||
|
||||
from fastapi import APIRouter, HTTPException, Depends
|
||||
from typing import List, Optional, Dict, Any
|
||||
from pydantic import BaseModel
|
||||
|
||||
from plugins.base import PluginRegistry, PluginType
|
||||
from utils import require_api_key
|
||||
from database_service import get_db_service
|
||||
|
||||
|
||||
router = APIRouter(prefix="/plugins", tags=["插件管理"])
|
||||
|
||||
|
||||
class PluginConfigRequest(BaseModel):
|
||||
name: str
|
||||
config: Dict[str, Any]
|
||||
|
||||
|
||||
def _sync_plugin_from_db(plugin_name: str):
|
||||
db_service = get_db_service()
|
||||
if not db_service:
|
||||
return
|
||||
plugin_config = db_service.get_plugin_config(plugin_name)
|
||||
plugin = PluginRegistry.get(plugin_name)
|
||||
if not plugin:
|
||||
return
|
||||
if plugin_config:
|
||||
import json
|
||||
plugin.initialize(json.loads(plugin_config.config_json) if plugin_config.config_json else {})
|
||||
if plugin_config.enabled:
|
||||
plugin.enable()
|
||||
else:
|
||||
plugin.disable()
|
||||
|
||||
|
||||
@router.get("/", summary="获取所有插件")
|
||||
async def get_plugins(_=Depends(require_api_key)) -> Dict[str, Any]:
|
||||
import json
|
||||
plugins = PluginRegistry.get_all()
|
||||
result = []
|
||||
for p in plugins:
|
||||
info = p.get_info()
|
||||
db_service = get_db_service()
|
||||
if db_service:
|
||||
pc = db_service.get_plugin_config(p.plugin_name)
|
||||
if pc:
|
||||
info["config"] = json.loads(pc.config_json) if pc.config_json else {}
|
||||
info["enabled"] = pc.enabled
|
||||
result.append(info)
|
||||
return {
|
||||
"success": True,
|
||||
"plugins": result,
|
||||
"count": len(result)
|
||||
}
|
||||
|
||||
|
||||
@router.get("/hotloaded", summary="获取热加载插件列表")
|
||||
async def get_hotloaded_plugins(_=Depends(require_api_key)) -> Dict[str, Any]:
|
||||
try:
|
||||
from plugins.plugin_loader import hot_plugin_loader
|
||||
plugins = hot_plugin_loader.get_loaded_plugins()
|
||||
return {
|
||||
"success": True,
|
||||
"plugins": plugins,
|
||||
"count": len(plugins),
|
||||
"plugin_dir": hot_plugin_loader.plugin_dir
|
||||
}
|
||||
except Exception as e:
|
||||
return {"success": False, "error": str(e)}
|
||||
|
||||
|
||||
@router.post("/hotreload", summary="手动触发插件热重载")
|
||||
async def trigger_hot_reload(_=Depends(require_api_key)) -> Dict[str, Any]:
|
||||
try:
|
||||
from plugins.plugin_loader import hot_plugin_loader
|
||||
hot_plugin_loader.scan_and_load_plugins()
|
||||
plugins = hot_plugin_loader.get_loaded_plugins()
|
||||
return {
|
||||
"success": True,
|
||||
"message": "Hot reload triggered",
|
||||
"plugins": plugins
|
||||
}
|
||||
except Exception as e:
|
||||
return {"success": False, "error": str(e)}
|
||||
|
||||
|
||||
@router.get("/type/{plugin_type}", summary="按类型获取插件")
|
||||
async def get_plugins_by_type(plugin_type: str, _=Depends(require_api_key)) -> Dict[str, Any]:
|
||||
try:
|
||||
ptype = PluginType(plugin_type)
|
||||
except ValueError:
|
||||
raise HTTPException(status_code=400, detail=f"Invalid plugin type: {plugin_type}")
|
||||
|
||||
plugins = PluginRegistry.get_by_type(ptype)
|
||||
return {
|
||||
"success": True,
|
||||
"plugins": [p.get_info() for p in plugins],
|
||||
"count": len(plugins)
|
||||
}
|
||||
|
||||
|
||||
@router.get("/custom/list", summary="列出自定义插件文件")
|
||||
async def list_custom_plugins(_=Depends(require_api_key)) -> Dict[str, Any]:
|
||||
try:
|
||||
import os
|
||||
custom_dir = "/app/plugins/custom"
|
||||
if not os.path.exists(custom_dir):
|
||||
return {"success": True, "plugins": [], "count": 0}
|
||||
|
||||
files = []
|
||||
for f in os.listdir(custom_dir):
|
||||
if f.endswith('.py') and not f.startswith('_'):
|
||||
filepath = os.path.join(custom_dir, f)
|
||||
stat = os.stat(filepath)
|
||||
files.append({
|
||||
"name": f,
|
||||
"size": stat.st_size,
|
||||
"modified": stat.st_mtime,
|
||||
"path": filepath
|
||||
})
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"plugins": files,
|
||||
"count": len(files),
|
||||
"directory": custom_dir
|
||||
}
|
||||
except Exception as e:
|
||||
return {"success": False, "error": str(e)}
|
||||
|
||||
|
||||
@router.post("/custom/create", summary="创建自定义插件文件")
|
||||
async def create_custom_plugin(name: str, code: str, _=Depends(require_api_key)) -> Dict[str, Any]:
|
||||
try:
|
||||
import os
|
||||
custom_dir = "/app/plugins/custom"
|
||||
os.makedirs(custom_dir, exist_ok=True)
|
||||
|
||||
safe_name = name.replace("..", "").replace("/", "").replace("\\", "")
|
||||
if not safe_name.endswith(".py"):
|
||||
safe_name += ".py"
|
||||
|
||||
filepath = os.path.join(custom_dir, safe_name)
|
||||
with open(filepath, 'w') as f:
|
||||
f.write(code)
|
||||
|
||||
from plugins.plugin_loader import hot_plugin_loader
|
||||
hot_plugin_loader.scan_and_load_plugins()
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"message": f"Plugin {safe_name} created",
|
||||
"path": filepath
|
||||
}
|
||||
except Exception as e:
|
||||
return {"success": False, "error": str(e)}
|
||||
|
||||
|
||||
@router.delete("/custom/{plugin_name}", summary="删除自定义插件")
|
||||
async def delete_custom_plugin(plugin_name: str, _=Depends(require_api_key)) -> Dict[str, Any]:
|
||||
try:
|
||||
import os
|
||||
custom_dir = "/app/plugins/custom"
|
||||
|
||||
safe_name = plugin_name.replace("..", "").replace("/", "").replace("\\", "")
|
||||
if not safe_name.endswith(".py"):
|
||||
safe_name += ".py"
|
||||
|
||||
filepath = os.path.join(custom_dir, safe_name)
|
||||
if os.path.exists(filepath):
|
||||
os.remove(filepath)
|
||||
|
||||
from plugins.plugin_loader import hot_plugin_loader
|
||||
hot_plugin_loader.scan_and_load_plugins()
|
||||
|
||||
return {"success": True, "message": f"Plugin {safe_name} deleted"}
|
||||
else:
|
||||
return {"success": False, "error": "Plugin file not found"}
|
||||
except Exception as e:
|
||||
return {"success": False, "error": str(e)}
|
||||
|
||||
|
||||
@router.get("/custom/{plugin_name}/download", summary="下载自定义插件源码")
|
||||
async def download_custom_plugin(plugin_name: str, _=Depends(require_api_key)) -> Dict[str, Any]:
|
||||
try:
|
||||
import os
|
||||
custom_dir = "/app/plugins/custom"
|
||||
|
||||
safe_name = plugin_name.replace("..", "").replace("/", "").replace("\\", "")
|
||||
if not safe_name.endswith(".py"):
|
||||
safe_name += ".py"
|
||||
|
||||
filepath = os.path.join(custom_dir, safe_name)
|
||||
if os.path.exists(filepath):
|
||||
with open(filepath, 'r') as f:
|
||||
code = f.read()
|
||||
return {
|
||||
"success": True,
|
||||
"name": safe_name,
|
||||
"code": code
|
||||
}
|
||||
else:
|
||||
return {"success": False, "error": "Plugin file not found"}
|
||||
except Exception as e:
|
||||
return {"success": False, "error": str(e)}
|
||||
|
||||
|
||||
@router.get("/{plugin_name}", summary="获取插件详情")
|
||||
async def get_plugin(plugin_name: str, _=Depends(require_api_key)) -> Dict[str, Any]:
|
||||
import json
|
||||
plugin = PluginRegistry.get(plugin_name)
|
||||
if not plugin:
|
||||
raise HTTPException(status_code=404, detail=f"Plugin '{plugin_name}' not found")
|
||||
info = plugin.get_info()
|
||||
db_service = get_db_service()
|
||||
if db_service:
|
||||
pc = db_service.get_plugin_config(plugin_name)
|
||||
if pc:
|
||||
info["config"] = json.loads(pc.config_json) if pc.config_json else {}
|
||||
info["enabled"] = pc.enabled
|
||||
return {"success": True, "plugin": info}
|
||||
|
||||
|
||||
@router.post("/{plugin_name}/enable", summary="启用插件")
|
||||
async def enable_plugin(plugin_name: str, _=Depends(require_api_key)) -> Dict[str, Any]:
|
||||
plugin = PluginRegistry.get(plugin_name)
|
||||
if not plugin:
|
||||
raise HTTPException(status_code=404, detail=f"Plugin '{plugin_name}' not found")
|
||||
PluginRegistry.enable(plugin_name)
|
||||
db_service = get_db_service()
|
||||
if db_service:
|
||||
pc = db_service.get_plugin_config(plugin_name)
|
||||
if pc:
|
||||
db_service.update_plugin_enabled(plugin_name, True)
|
||||
else:
|
||||
db_service.save_plugin_config(plugin_name, plugin.config or {}, True)
|
||||
return {"success": True, "message": f"Plugin '{plugin_name}' enabled"}
|
||||
|
||||
|
||||
@router.post("/{plugin_name}/disable", summary="禁用插件")
|
||||
async def disable_plugin(plugin_name: str, _=Depends(require_api_key)) -> Dict[str, Any]:
|
||||
plugin = PluginRegistry.get(plugin_name)
|
||||
if not plugin:
|
||||
raise HTTPException(status_code=404, detail=f"Plugin '{plugin_name}' not found")
|
||||
PluginRegistry.disable(plugin_name)
|
||||
db_service = get_db_service()
|
||||
if db_service:
|
||||
pc = db_service.get_plugin_config(plugin_name)
|
||||
if pc:
|
||||
db_service.update_plugin_enabled(plugin_name, False)
|
||||
else:
|
||||
db_service.save_plugin_config(plugin_name, plugin.config or {}, False)
|
||||
return {"success": True, "message": f"Plugin '{plugin_name}' disabled"}
|
||||
|
||||
|
||||
@router.put("/{plugin_name}/config", summary="更新插件配置")
|
||||
async def update_plugin_config(plugin_name: str,
|
||||
request: PluginConfigRequest,
|
||||
_=Depends(require_api_key)) -> Dict[str, Any]:
|
||||
plugin = PluginRegistry.get(plugin_name)
|
||||
if not plugin:
|
||||
raise HTTPException(status_code=404, detail=f"Plugin '{plugin_name}' not found")
|
||||
|
||||
success = plugin.initialize(request.config)
|
||||
if not success:
|
||||
raise HTTPException(status_code=400, detail=f"Failed to initialize plugin '{plugin_name}'")
|
||||
|
||||
db_service = get_db_service()
|
||||
if db_service:
|
||||
pc = db_service.get_plugin_config(plugin_name)
|
||||
enabled = pc.enabled if pc else False
|
||||
db_service.save_plugin_config(plugin_name, request.config, enabled)
|
||||
|
||||
return {"success": True, "message": f"Plugin '{plugin_name}' config updated"}
|
||||
|
||||
|
||||
@router.post("/{plugin_name}/execute", summary="执行插件")
|
||||
async def execute_plugin(plugin_name: str,
|
||||
request: Optional[Dict[str, Any]] = None,
|
||||
_=Depends(require_api_key)) -> Dict[str, Any]:
|
||||
plugin = PluginRegistry.get(plugin_name)
|
||||
if not plugin:
|
||||
raise HTTPException(status_code=404, detail=f"Plugin '{plugin_name}' not found")
|
||||
|
||||
if not plugin.enabled:
|
||||
return {"success": False, "error": f"Plugin '{plugin_name}' is disabled"}
|
||||
|
||||
params = request or {}
|
||||
result = plugin.execute(params)
|
||||
return {"success": True, "result": result}
|
||||
|
||||
|
||||
@router.get("/{plugin_name}/logs", summary="获取插件日志")
|
||||
async def get_plugin_logs(
|
||||
plugin_name: str,
|
||||
lines: int = 100,
|
||||
level: Optional[str] = None,
|
||||
_=Depends(require_api_key)
|
||||
) -> Dict[str, Any]:
|
||||
try:
|
||||
import logging
|
||||
import os
|
||||
|
||||
plugin = PluginRegistry.get(plugin_name)
|
||||
if not plugin:
|
||||
raise HTTPException(status_code=404, detail=f"Plugin '{plugin_name}' not found")
|
||||
|
||||
log_dir = "/app/data/logs"
|
||||
if not os.path.exists(log_dir):
|
||||
os.makedirs(log_dir, exist_ok=True)
|
||||
|
||||
log_file = os.path.join(log_dir, f"{plugin_name}.log")
|
||||
app_log = os.path.join(log_dir, "app.log")
|
||||
|
||||
all_logs = []
|
||||
|
||||
if os.path.exists(log_file):
|
||||
with open(log_file, 'r', encoding='utf-8') as f:
|
||||
all_logs.extend(f.readlines())
|
||||
|
||||
if os.path.exists(app_log):
|
||||
with open(app_log, 'r', encoding='utf-8') as f:
|
||||
for line in f:
|
||||
if plugin_name in line or f"[{plugin_name}]" in line:
|
||||
all_logs.append(line)
|
||||
|
||||
filtered_logs = []
|
||||
for line in all_logs:
|
||||
if level:
|
||||
if level.upper() in line.upper():
|
||||
filtered_logs.append(line.strip())
|
||||
else:
|
||||
filtered_logs.append(line.strip())
|
||||
|
||||
filtered_logs = filtered_logs[-lines:] if len(filtered_logs) > lines else filtered_logs
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"plugin_name": plugin_name,
|
||||
"log_file": log_file,
|
||||
"count": len(filtered_logs),
|
||||
"logs": filtered_logs
|
||||
}
|
||||
except Exception as e:
|
||||
return {"success": False, "error": str(e)}
|
||||
|
||||
|
||||
@router.get("/{plugin_name}/schema", summary="获取插件配置表单Schema")
|
||||
async def get_plugin_schema(plugin_name: str, _=Depends(require_api_key)) -> Dict[str, Any]:
|
||||
try:
|
||||
plugin = PluginRegistry.get(plugin_name)
|
||||
if not plugin:
|
||||
raise HTTPException(status_code=404, detail=f"Plugin '{plugin_name}' not found")
|
||||
|
||||
schema = None
|
||||
if hasattr(plugin, 'get_config_schema'):
|
||||
schema = plugin.get_config_schema()
|
||||
elif hasattr(plugin, 'config_schema'):
|
||||
schema = plugin.config_schema
|
||||
|
||||
if schema:
|
||||
if callable(schema):
|
||||
schema = schema()
|
||||
if hasattr(schema, 'to_form_schema'):
|
||||
return {
|
||||
"success": True,
|
||||
"schema": schema.to_form_schema(),
|
||||
"has_form": True
|
||||
}
|
||||
return {
|
||||
"success": True,
|
||||
"schema": schema,
|
||||
"has_form": True
|
||||
}
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"schema": None,
|
||||
"has_form": False,
|
||||
"message": "此插件暂无表单配置"
|
||||
}
|
||||
except Exception as e:
|
||||
return {"success": False, "error": str(e)}
|
||||
|
||||
|
||||
@router.post("/{plugin_name}/logs/clear", summary="清空插件日志")
|
||||
async def clear_plugin_logs(plugin_name: str, _=Depends(require_api_key)) -> Dict[str, Any]:
|
||||
try:
|
||||
import os
|
||||
|
||||
plugin = PluginRegistry.get(plugin_name)
|
||||
if not plugin:
|
||||
raise HTTPException(status_code=404, detail=f"Plugin '{plugin_name}' not found")
|
||||
|
||||
log_file = f"/app/data/logs/{plugin_name}.log"
|
||||
|
||||
if os.path.exists(log_file):
|
||||
with open(log_file, 'w') as f:
|
||||
f.write("")
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"message": f"Plugin '{plugin_name}' logs cleared"
|
||||
}
|
||||
except Exception as e:
|
||||
return {"success": False, "error": str(e)}
|
||||
+137
@@ -0,0 +1,137 @@
|
||||
# ///
|
||||
# webhook.py
|
||||
# 描述:Webhook管理API路由
|
||||
# 作者:AI Generated
|
||||
# 创建日期:2026-04-06
|
||||
# ///
|
||||
|
||||
from fastapi import APIRouter, HTTPException, Depends
|
||||
from typing import List, Dict, Any
|
||||
from pydantic import BaseModel
|
||||
|
||||
from database_service import get_db_service
|
||||
from utils import require_api_key
|
||||
|
||||
|
||||
router = APIRouter(prefix="/webhook", tags=["Webhook管理"])
|
||||
|
||||
|
||||
class WebhookAddRequest(BaseModel):
|
||||
name: str
|
||||
url: str
|
||||
format: str = "bark"
|
||||
event_types: List[str] = []
|
||||
|
||||
|
||||
class WebhookUpdateRequest(BaseModel):
|
||||
name: str = None
|
||||
url: str = None
|
||||
format: str = None
|
||||
enabled: bool = None
|
||||
event_types: List[str] = None
|
||||
|
||||
|
||||
@router.get("/", summary="获取所有Webhook")
|
||||
async def get_webhooks(_=Depends(require_api_key)) -> Dict[str, Any]:
|
||||
db_service = get_db_service()
|
||||
if not db_service:
|
||||
raise HTTPException(status_code=500, detail="Database not available")
|
||||
|
||||
webhooks = db_service.get_all_webhooks()
|
||||
return {
|
||||
"success": True,
|
||||
"data": [w.to_dict() for w in webhooks],
|
||||
"count": len(webhooks)
|
||||
}
|
||||
|
||||
|
||||
@router.get("/{webhook_id}", summary="获取指定Webhook")
|
||||
async def get_webhook(webhook_id: int, _=Depends(require_api_key)) -> Dict[str, Any]:
|
||||
db_service = get_db_service()
|
||||
if not db_service:
|
||||
raise HTTPException(status_code=500, detail="Database not available")
|
||||
|
||||
webhook = db_service.get_webhook(webhook_id)
|
||||
if not webhook:
|
||||
raise HTTPException(status_code=404, detail=f"Webhook {webhook_id} not found")
|
||||
|
||||
return {"success": True, "data": webhook.to_dict()}
|
||||
|
||||
|
||||
@router.post("/", summary="添加Webhook")
|
||||
async def add_webhook(request: WebhookAddRequest,
|
||||
_=Depends(require_api_key)) -> Dict[str, Any]:
|
||||
db_service = get_db_service()
|
||||
if not db_service:
|
||||
raise HTTPException(status_code=500, detail="Database not available")
|
||||
|
||||
success = db_service.add_webhook(
|
||||
name=request.name,
|
||||
url=request.url,
|
||||
format=request.format,
|
||||
event_types=request.event_types
|
||||
)
|
||||
|
||||
if not success:
|
||||
raise HTTPException(status_code=400, detail="Failed to add webhook")
|
||||
|
||||
return {"success": True, "message": "Webhook added successfully"}
|
||||
|
||||
|
||||
@router.put("/{webhook_id}", summary="更新Webhook")
|
||||
async def update_webhook(webhook_id: int,
|
||||
request: WebhookUpdateRequest,
|
||||
_=Depends(require_api_key)) -> Dict[str, Any]:
|
||||
db_service = get_db_service()
|
||||
if not db_service:
|
||||
raise HTTPException(status_code=500, detail="Database not available")
|
||||
|
||||
update_data = request.model_dump(exclude_unset=True)
|
||||
success = db_service.update_webhook(webhook_id, **update_data)
|
||||
|
||||
if not success:
|
||||
raise HTTPException(status_code=404, detail=f"Webhook {webhook_id} not found")
|
||||
|
||||
return {"success": True, "message": "Webhook updated successfully"}
|
||||
|
||||
|
||||
@router.delete("/{webhook_id}", summary="删除Webhook")
|
||||
async def delete_webhook(webhook_id: int,
|
||||
_=Depends(require_api_key)) -> Dict[str, Any]:
|
||||
db_service = get_db_service()
|
||||
if not db_service:
|
||||
raise HTTPException(status_code=500, detail="Database not available")
|
||||
|
||||
success = db_service.delete_webhook(webhook_id)
|
||||
if not success:
|
||||
raise HTTPException(status_code=404, detail=f"Webhook {webhook_id} not found")
|
||||
|
||||
return {"success": True, "message": "Webhook deleted successfully"}
|
||||
|
||||
|
||||
@router.post("/{webhook_id}/enable", summary="启用Webhook")
|
||||
async def enable_webhook(webhook_id: int,
|
||||
_=Depends(require_api_key)) -> Dict[str, Any]:
|
||||
db_service = get_db_service()
|
||||
if not db_service:
|
||||
raise HTTPException(status_code=500, detail="Database not available")
|
||||
|
||||
success = db_service.update_webhook(webhook_id, enabled=True)
|
||||
if not success:
|
||||
raise HTTPException(status_code=404, detail=f"Webhook {webhook_id} not found")
|
||||
|
||||
return {"success": True, "message": "Webhook enabled"}
|
||||
|
||||
|
||||
@router.post("/{webhook_id}/disable", summary="禁用Webhook")
|
||||
async def disable_webhook(webhook_id: int,
|
||||
_=Depends(require_api_key)) -> Dict[str, Any]:
|
||||
db_service = get_db_service()
|
||||
if not db_service:
|
||||
raise HTTPException(status_code=500, detail="Database not available")
|
||||
|
||||
success = db_service.update_webhook(webhook_id, enabled=False)
|
||||
if not success:
|
||||
raise HTTPException(status_code=404, detail=f"Webhook {webhook_id} not found")
|
||||
|
||||
return {"success": True, "message": "Webhook disabled"}
|
||||
Reference in New Issue
Block a user