系统设置增加备份恢复:凌晨3点自动备份,保留10天,含 env 与复盘图片。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,11 +1,11 @@
|
||||
"""实例系统设置 API:导航开关,env 读写,改密,PM2 重启."""
|
||||
"""实例系统设置 API:导航开关,env 读写,改密,PM2 重启,备份恢复."""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from functools import wraps
|
||||
from typing import Any, Callable
|
||||
|
||||
from flask import jsonify, request, session
|
||||
from flask import jsonify, request, send_file, session
|
||||
|
||||
from lib.env.env_file_lib import apply_env_updates
|
||||
from lib.env.env_ui_manifest import (
|
||||
@@ -83,10 +83,14 @@ def register_instance_settings_routes(
|
||||
exchange_key: str,
|
||||
username: str,
|
||||
password: str,
|
||||
db_path: str | None = None,
|
||||
upload_folder: str | None = None,
|
||||
) -> None:
|
||||
env_path = os.path.join(base_dir, ".env")
|
||||
example_path = os.path.join(base_dir, ".env.example")
|
||||
api_auth = _api_login_required()
|
||||
resolved_db = (db_path or "").strip() or os.path.join(base_dir, "crypto.db")
|
||||
resolved_upload = (upload_folder or "").strip() or os.path.join(base_dir, "static", "images")
|
||||
|
||||
@app.route("/api/settings/display", methods=["GET", "POST"])
|
||||
@api_auth
|
||||
@@ -175,6 +179,71 @@ def register_instance_settings_routes(
|
||||
def api_admin_health():
|
||||
return jsonify({"ok": True, "status": "up"})
|
||||
|
||||
@app.route("/api/settings/backup/list", methods=["GET"])
|
||||
@api_auth
|
||||
def api_settings_backup_list():
|
||||
from lib.instance.backup_lib import backup_dir, backup_keep_days, list_backups
|
||||
|
||||
return jsonify(
|
||||
{
|
||||
"ok": True,
|
||||
"items": list_backups(),
|
||||
"backup_dir": backup_dir(),
|
||||
"keep_days": backup_keep_days(),
|
||||
"auto_hour_bj": 3,
|
||||
"includes": [".env", "database", "options_journal"],
|
||||
}
|
||||
)
|
||||
|
||||
@app.route("/api/settings/backup/create", methods=["POST"])
|
||||
@api_auth
|
||||
def api_settings_backup_create():
|
||||
from lib.instance.backup_lib import create_backup
|
||||
|
||||
try:
|
||||
result = create_backup(
|
||||
base_dir=base_dir,
|
||||
db_path=resolved_db,
|
||||
upload_folder=resolved_upload,
|
||||
label="manual",
|
||||
)
|
||||
return jsonify(result)
|
||||
except Exception as exc:
|
||||
return jsonify({"ok": False, "msg": str(exc) or "备份失败"}), 500
|
||||
|
||||
@app.route("/api/settings/backup/download/<name>", methods=["GET"])
|
||||
@api_auth
|
||||
def api_settings_backup_download(name: str):
|
||||
from lib.instance.backup_lib import backup_path
|
||||
|
||||
path = backup_path(name)
|
||||
if not path or not os.path.isfile(path):
|
||||
return jsonify({"ok": False, "msg": "备份不存在"}), 404
|
||||
return send_file(
|
||||
path,
|
||||
mimetype="application/gzip",
|
||||
as_attachment=True,
|
||||
download_name=os.path.basename(path),
|
||||
)
|
||||
|
||||
@app.route("/api/settings/backup/restore", methods=["POST"])
|
||||
@api_auth
|
||||
def api_settings_backup_restore():
|
||||
from lib.instance.backup_lib import restore_backup
|
||||
|
||||
body = request.get_json(silent=True) or {}
|
||||
name = str(body.get("name") or "").strip()
|
||||
if not name:
|
||||
return jsonify({"ok": False, "msg": "缺少备份文件名"}), 400
|
||||
result = restore_backup(
|
||||
name,
|
||||
base_dir=base_dir,
|
||||
db_path=resolved_db,
|
||||
upload_folder=resolved_upload,
|
||||
)
|
||||
code = 200 if result.get("ok") else 400
|
||||
return jsonify(result), code
|
||||
|
||||
def tab_allowed_fn(tab: str) -> bool:
|
||||
prefs = get_display_prefs(get_db)
|
||||
return tab_allowed(tab, prefs)
|
||||
|
||||
Reference in New Issue
Block a user