alpha v0.0971
This commit is contained in:
104
app.py
104
app.py
@@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
from flask import Flask, render_template, request, redirect, url_for, flash, Response, jsonify, session, send_from_directory
|
from flask import Flask, render_template, request, redirect, url_for, flash, Response, jsonify, session, send_from_directory, send_file
|
||||||
try:
|
try:
|
||||||
import psycopg
|
import psycopg
|
||||||
except ModuleNotFoundError:
|
except ModuleNotFoundError:
|
||||||
@@ -16,6 +16,13 @@ import re
|
|||||||
import os
|
import os
|
||||||
import json
|
import json
|
||||||
import sys
|
import sys
|
||||||
|
from database_maintenance import (
|
||||||
|
DatabaseMaintenanceBusy,
|
||||||
|
DatabaseMaintenanceError,
|
||||||
|
DatabaseMaintenanceManager,
|
||||||
|
InvalidBackupFile,
|
||||||
|
PostgreSqlToolNotFound,
|
||||||
|
)
|
||||||
from handlers import computers as computers_handlers
|
from handlers import computers as computers_handlers
|
||||||
from handlers import projectors as projectors_handlers
|
from handlers import projectors as projectors_handlers
|
||||||
from routes.projectors import _normalize_board_fields
|
from routes.projectors import _normalize_board_fields
|
||||||
@@ -79,6 +86,7 @@ APP_PORT = _integer_setting(APPLICATION_SETTINGS, "port", 5050)
|
|||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
app.secret_key = "secret"
|
app.secret_key = "secret"
|
||||||
app.config["DB_INITIALIZED"] = False
|
app.config["DB_INITIALIZED"] = False
|
||||||
|
database_maintenance = DatabaseMaintenanceManager(DB_CONFIG)
|
||||||
CLIENT_AGENT_TOKEN = "change-me-client-token"
|
CLIENT_AGENT_TOKEN = "change-me-client-token"
|
||||||
CLIENT_TEST_OFFLINE_AFTER_SECONDS = 35
|
CLIENT_TEST_OFFLINE_AFTER_SECONDS = 35
|
||||||
|
|
||||||
@@ -2640,6 +2648,100 @@ def logout():
|
|||||||
return redirect(url_for("login"))
|
return redirect(url_for("login"))
|
||||||
|
|
||||||
|
|
||||||
|
def database_admin_api(view):
|
||||||
|
@wraps(view)
|
||||||
|
def wrapper(*args, **kwargs):
|
||||||
|
if "user" not in session:
|
||||||
|
return jsonify(ok=False, error="Требуется авторизация."), 401
|
||||||
|
if session.get("role") != "admin":
|
||||||
|
return jsonify(ok=False, error="Требуются права администратора."), 403
|
||||||
|
return view(*args, **kwargs)
|
||||||
|
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
|
def _database_size_bytes():
|
||||||
|
conn = get_conn()
|
||||||
|
try:
|
||||||
|
cur = conn.cursor()
|
||||||
|
cur.execute("SELECT pg_database_size(current_database())")
|
||||||
|
row = cur.fetchone()
|
||||||
|
return int(row[0] or 0) if row else 0
|
||||||
|
finally:
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/api/database/backup/start", methods=["POST"])
|
||||||
|
@database_admin_api
|
||||||
|
def database_backup_start():
|
||||||
|
try:
|
||||||
|
try:
|
||||||
|
database_size = _database_size_bytes()
|
||||||
|
except Exception:
|
||||||
|
database_size = 0
|
||||||
|
job_id = database_maintenance.start_backup(
|
||||||
|
session.get("user"),
|
||||||
|
estimated_database_size=database_size,
|
||||||
|
)
|
||||||
|
return jsonify(ok=True, job_id=job_id), 202
|
||||||
|
except (DatabaseMaintenanceBusy, PostgreSqlToolNotFound) as exc:
|
||||||
|
return jsonify(ok=False, error=str(exc)), 409
|
||||||
|
except DatabaseMaintenanceError as exc:
|
||||||
|
return jsonify(ok=False, error=str(exc)), 400
|
||||||
|
except Exception:
|
||||||
|
app.logger.exception("Failed to start a database backup")
|
||||||
|
return jsonify(ok=False, error="Не удалось запустить резервное копирование."), 500
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/api/database/restore/start", methods=["POST"])
|
||||||
|
@database_admin_api
|
||||||
|
def database_restore_start():
|
||||||
|
uploaded_file = request.files.get("backup_file")
|
||||||
|
if not uploaded_file or not uploaded_file.filename:
|
||||||
|
return jsonify(ok=False, error="Выберите файл резервной копии."), 400
|
||||||
|
try:
|
||||||
|
job_id = database_maintenance.start_restore(
|
||||||
|
session.get("user"),
|
||||||
|
uploaded_file,
|
||||||
|
uploaded_file.filename,
|
||||||
|
)
|
||||||
|
return jsonify(ok=True, job_id=job_id), 202
|
||||||
|
except DatabaseMaintenanceBusy as exc:
|
||||||
|
return jsonify(ok=False, error=str(exc)), 409
|
||||||
|
except (InvalidBackupFile, PostgreSqlToolNotFound, DatabaseMaintenanceError) as exc:
|
||||||
|
return jsonify(ok=False, error=str(exc)), 400
|
||||||
|
except Exception:
|
||||||
|
app.logger.exception("Failed to start a database restore")
|
||||||
|
return jsonify(ok=False, error="Не удалось запустить восстановление базы данных."), 500
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/api/database/jobs/<job_id>")
|
||||||
|
@database_admin_api
|
||||||
|
def database_job_status(job_id):
|
||||||
|
job = database_maintenance.get_job(job_id, session.get("user"))
|
||||||
|
if not job:
|
||||||
|
return jsonify(ok=False, error="Операция не найдена."), 404
|
||||||
|
if job.get("kind") == "restore" and job.get("status") == "success":
|
||||||
|
app.config["DB_INITIALIZED"] = False
|
||||||
|
return jsonify(ok=True, job=job)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/api/database/backup/<job_id>/download")
|
||||||
|
@database_admin_api
|
||||||
|
def database_backup_download(job_id):
|
||||||
|
backup = database_maintenance.get_backup_download(job_id, session.get("user"))
|
||||||
|
if not backup:
|
||||||
|
return jsonify(ok=False, error="Файл резервной копии не найден."), 404
|
||||||
|
path, filename = backup
|
||||||
|
return send_file(
|
||||||
|
path,
|
||||||
|
mimetype="application/octet-stream",
|
||||||
|
as_attachment=True,
|
||||||
|
download_name=filename,
|
||||||
|
conditional=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@app.route("/network")
|
@app.route("/network")
|
||||||
@login_required
|
@login_required
|
||||||
def network():
|
def network():
|
||||||
|
|||||||
Reference in New Issue
Block a user