2025-11-28 17:39:54 +08:00
|
|
|
import threading
|
|
|
|
|
|
|
|
|
|
from flask import Blueprint, flash, redirect, render_template, request, url_for, current_app
|
|
|
|
|
from flask_login import current_user, login_required
|
|
|
|
|
|
|
|
|
|
from app.extensions import db, scheduler
|
|
|
|
|
from app.forms import ApiConfigForm
|
|
|
|
|
from app.models import ApiConfig
|
|
|
|
|
from app.services.api_executor import execute_api_by_id
|
|
|
|
|
from app.services.scheduler import SchedulerService
|
|
|
|
|
|
|
|
|
|
apis_bp = Blueprint("apis", __name__, url_prefix="/apis")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _scheduler_service() -> SchedulerService:
|
|
|
|
|
return SchedulerService(scheduler)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@apis_bp.route("", methods=["GET"])
|
|
|
|
|
@login_required
|
|
|
|
|
def list_apis():
|
|
|
|
|
name = request.args.get("name")
|
|
|
|
|
enabled = request.args.get("enabled")
|
|
|
|
|
query = ApiConfig.query
|
|
|
|
|
if name:
|
|
|
|
|
query = query.filter(ApiConfig.name.ilike(f"%{name}%"))
|
|
|
|
|
if enabled in {"0", "1"}:
|
|
|
|
|
query = query.filter(ApiConfig.enabled == (enabled == "1"))
|
|
|
|
|
apis = query.order_by(ApiConfig.updated_at.desc()).all()
|
|
|
|
|
return render_template("apis/list.html", apis=apis)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@apis_bp.route("/new", methods=["GET", "POST"])
|
|
|
|
|
@login_required
|
|
|
|
|
def create_api():
|
|
|
|
|
form = ApiConfigForm()
|
|
|
|
|
if form.validate_on_submit():
|
|
|
|
|
api = ApiConfig(
|
|
|
|
|
name=form.name.data,
|
|
|
|
|
description=form.description.data,
|
|
|
|
|
url=form.url.data,
|
|
|
|
|
http_method=form.http_method.data,
|
|
|
|
|
headers=form.headers.data,
|
|
|
|
|
query_params=form.query_params.data,
|
|
|
|
|
body=form.body.data,
|
|
|
|
|
schedule_type=form.schedule_type.data,
|
|
|
|
|
schedule_expression=form.schedule_expression.data,
|
|
|
|
|
timeout_seconds=form.timeout_seconds.data,
|
|
|
|
|
retry_times=form.retry_times.data,
|
|
|
|
|
retry_interval_seconds=form.retry_interval_seconds.data,
|
|
|
|
|
enabled=form.enabled.data,
|
|
|
|
|
created_by=current_user.id,
|
|
|
|
|
)
|
|
|
|
|
db.session.add(api)
|
|
|
|
|
db.session.commit()
|
|
|
|
|
if api.enabled:
|
|
|
|
|
_scheduler_service().add_job_for_api(api)
|
|
|
|
|
flash("API 配置已创建", "success")
|
|
|
|
|
return redirect(url_for("apis.list_apis"))
|
|
|
|
|
return render_template("apis/form.html", form=form, api=None)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@apis_bp.route("/<int:api_id>/edit", methods=["GET", "POST"])
|
|
|
|
|
@login_required
|
|
|
|
|
def edit_api(api_id: int):
|
|
|
|
|
api = ApiConfig.query.get_or_404(api_id)
|
|
|
|
|
form = ApiConfigForm(obj=api)
|
|
|
|
|
if form.validate_on_submit():
|
|
|
|
|
form.populate_obj(api)
|
|
|
|
|
db.session.commit()
|
|
|
|
|
if api.enabled:
|
|
|
|
|
_scheduler_service().reschedule_job_for_api(api)
|
|
|
|
|
else:
|
|
|
|
|
_scheduler_service().remove_job_for_api(api.id)
|
|
|
|
|
flash("API 配置已更新", "success")
|
|
|
|
|
return redirect(url_for("apis.list_apis"))
|
|
|
|
|
return render_template("apis/form.html", form=form, api=api)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@apis_bp.route("/<int:api_id>/toggle", methods=["POST"])
|
|
|
|
|
@login_required
|
|
|
|
|
def toggle_api(api_id: int):
|
|
|
|
|
api = ApiConfig.query.get_or_404(api_id)
|
|
|
|
|
api.enabled = not api.enabled
|
|
|
|
|
db.session.commit()
|
|
|
|
|
svc = _scheduler_service()
|
|
|
|
|
if api.enabled:
|
|
|
|
|
svc.add_job_for_api(api)
|
|
|
|
|
flash("API 已启用并加入调度", "success")
|
|
|
|
|
else:
|
|
|
|
|
svc.remove_job_for_api(api.id)
|
|
|
|
|
flash("API 已停用并移除调度", "info")
|
|
|
|
|
return redirect(url_for("apis.list_apis"))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@apis_bp.route("/<int:api_id>/delete", methods=["POST"])
|
|
|
|
|
@login_required
|
|
|
|
|
def delete_api(api_id: int):
|
|
|
|
|
api = ApiConfig.query.get_or_404(api_id)
|
|
|
|
|
db.session.delete(api)
|
|
|
|
|
db.session.commit()
|
|
|
|
|
_scheduler_service().remove_job_for_api(api_id)
|
|
|
|
|
flash("API 配置已删除", "info")
|
|
|
|
|
return redirect(url_for("apis.list_apis"))
|
|
|
|
|
|
|
|
|
|
|
2025-11-28 18:43:11 +08:00
|
|
|
@apis_bp.route("/<int:api_id>/copy", methods=["POST"])
|
|
|
|
|
@login_required
|
|
|
|
|
def copy_api(api_id: int):
|
|
|
|
|
src = ApiConfig.query.get_or_404(api_id)
|
|
|
|
|
new_api = ApiConfig(
|
|
|
|
|
name=f"{src.name}-副本",
|
|
|
|
|
description=src.description,
|
|
|
|
|
url=src.url,
|
|
|
|
|
http_method=src.http_method,
|
|
|
|
|
headers=src.headers,
|
|
|
|
|
query_params=src.query_params,
|
|
|
|
|
body=src.body,
|
|
|
|
|
schedule_type=src.schedule_type,
|
|
|
|
|
schedule_expression=src.schedule_expression,
|
|
|
|
|
timeout_seconds=src.timeout_seconds,
|
|
|
|
|
retry_times=src.retry_times,
|
|
|
|
|
retry_interval_seconds=src.retry_interval_seconds,
|
|
|
|
|
enabled=False, # 复制后默认不启用,避免未确认即自动调度
|
|
|
|
|
created_by=current_user.id,
|
|
|
|
|
)
|
|
|
|
|
db.session.add(new_api)
|
|
|
|
|
db.session.commit()
|
|
|
|
|
flash("已复制为新配置,请查看并启用。", "success")
|
|
|
|
|
return redirect(url_for("apis.edit_api", api_id=new_api.id))
|
|
|
|
|
|
|
|
|
|
|
2025-11-28 17:39:54 +08:00
|
|
|
@apis_bp.route("/<int:api_id>/run", methods=["POST"])
|
|
|
|
|
@login_required
|
|
|
|
|
def run_now(api_id: int):
|
|
|
|
|
api = ApiConfig.query.get_or_404(api_id)
|
|
|
|
|
|
|
|
|
|
app_obj = current_app._get_current_object()
|
|
|
|
|
threading.Thread(target=execute_api_by_id, args=(api.id, app_obj), daemon=True).start()
|
|
|
|
|
flash("已触发立即执行,稍后在日志中查看结果。", "success")
|
|
|
|
|
return redirect(url_for("apis.list_apis"))
|