Files
mirror/app/routes/apply.py
T
2026-06-03 17:33:19 +03:30

177 lines
5.9 KiB
Python

from flask import Blueprint, flash, jsonify, redirect, render_template, request, url_for
from flask_login import login_required
from app.extensions import db
from app.guides import GUIDES
from app.models import ApplyLog, Profile, Setting, SystemState
from app.models import utcnow
from app.services.applier import apply_profile, confirm_apply, get_system_status, restore_initial, rollback_apply
from app.services.backup import list_backups, restore_backup
apply_bp = Blueprint("apply", __name__, url_prefix="/apply")
@apply_bp.route("/")
@login_required
def index():
profiles = Profile.query.order_by(Profile.name).all()
state = SystemState.query.first()
pending = None
if state and state.pending_apply_log_id:
pending = ApplyLog.query.get(state.pending_apply_log_id)
recent_logs = ApplyLog.query.order_by(ApplyLog.started_at.desc()).limit(10).all()
return render_template(
"apply/index.html",
profiles=profiles,
pending=pending,
recent_logs=recent_logs,
guide=GUIDES.get("profiles", {}),
)
@apply_bp.route("/profile/<int:profile_id>", methods=["POST"])
@login_required
def apply(profile_id):
profile = Profile.query.get_or_404(profile_id)
rollback_minutes = int(request.form.get("rollback_minutes", Setting.get("rollback_minutes", "15") or "15"))
log = apply_profile(profile, rollback_minutes=rollback_minutes)
if log.status == "failed":
flash("اعمال پروفایل با خطا مواجه شد. جزئیات را بررسی کنید.", "danger")
else:
flash(
f"پروفایل اعمال شد. {rollback_minutes} دقیقه برای تست دارید — سپس rollback خودکار انجام می‌شود.",
"warning",
)
return redirect(url_for("apply.status", log_id=log.id))
@apply_bp.route("/status/<int:log_id>")
@login_required
def status(log_id):
log = ApplyLog.query.get_or_404(log_id)
details = log.get_details()
remaining_seconds = 0
if log.rollback_at and not log.confirmed:
remaining_seconds = max(0, int((log.rollback_at - utcnow()).total_seconds()))
return render_template(
"apply/status.html",
log=log,
details=details,
remaining_seconds=remaining_seconds,
)
@apply_bp.route("/confirm/<int:log_id>", methods=["POST"])
@login_required
def confirm(log_id):
confirm_apply(log_id)
flash("تغییرات تأیید و ثبت شد.", "success")
return redirect(url_for("main.dashboard"))
@apply_bp.route("/rollback/<int:log_id>", methods=["POST"])
@login_required
def rollback(log_id):
result = rollback_apply(log_id)
if result.get("success"):
flash("تنظیمات قبلی بازگردانده شد.", "info")
else:
flash(result.get("error", "خطا در rollback"), "danger")
return redirect(url_for("main.dashboard"))
@apply_bp.route("/api/pending/<int:log_id>")
@login_required
def pending_api(log_id):
log = ApplyLog.query.get_or_404(log_id)
remaining = 0
if log.rollback_at and not log.confirmed:
remaining = max(0, int((log.rollback_at - utcnow()).total_seconds()))
return jsonify(
{
"status": log.status,
"confirmed": log.confirmed,
"remaining_seconds": remaining,
}
)
restore_bp = Blueprint("restore", __name__, url_prefix="/restore")
@restore_bp.route("/")
@login_required
def index():
backups = list_backups()
state = SystemState.query.first()
return render_template(
"restore/index.html",
backups=backups,
state=state,
guide=GUIDES.get("restore", {}),
)
@restore_bp.route("/initial", methods=["POST"])
@login_required
def restore_initial_view():
result = restore_initial()
if result.get("success"):
flash("تنظیمات اولیه بازگردانده شد.", "success")
else:
flash(result.get("error", "خطا"), "danger")
return redirect(url_for("restore.index"))
@restore_bp.route("/backup", methods=["POST"])
@login_required
def restore_backup_view():
path = request.form.get("backup_path", "").strip()
if not path:
flash("مسیر backup انتخاب نشده.", "danger")
return redirect(url_for("restore.index"))
result = restore_backup(path)
if result.get("success"):
flash("backup بازگردانده شد.", "success")
else:
flash(result.get("error", "خطا"), "danger")
return redirect(url_for("restore.index"))
settings_bp = Blueprint("settings", __name__, url_prefix="/settings")
@settings_bp.route("/", methods=["GET", "POST"])
@login_required
def index():
if request.method == "POST":
for key in (
"auto_switch_dns",
"auto_switch_apt",
"auto_switch_docker",
"auto_switch_github",
"auto_switch_pip",
"auto_switch_npm",
):
Setting.set(key, "true" if request.form.get(key) == "on" else "false")
Setting.set("rollback_minutes", request.form.get("rollback_minutes", "15"))
Setting.set("auto_test_interval_minutes", request.form.get("auto_test_interval_minutes", "30"))
Setting.set("max_switches_per_day", request.form.get("max_switches_per_day", "3"))
Setting.set(
"rollback_on_all_fail",
"true" if request.form.get("rollback_on_all_fail") == "on" else "false",
)
flash("تنظیمات ذخیره شد.", "success")
return redirect(url_for("settings.index"))
settings = {key: Setting.get(key) for key in (
"auto_switch_dns", "auto_switch_apt", "auto_switch_docker",
"auto_switch_github", "auto_switch_pip", "auto_switch_npm",
"rollback_minutes", "auto_test_interval_minutes",
"max_switches_per_day", "rollback_on_all_fail",
)}
return render_template("settings/index.html", settings=settings, guide=GUIDES.get("settings", {}))