import threading from flask import ( Blueprint, current_app, flash, redirect, render_template, request, url_for, ) from db import db, Destination bp = Blueprint("dest", __name__) @bp.route("/destinations") def destinations_list(): destinations = Destination.query.order_by(Destination.name).all() return render_template("destinations.html", destinations=destinations) @bp.route("/destinations/new", methods=["GET", "POST"]) def destination_new(): if request.method == "POST": return _save_destination(None) return render_template("destination_form.html", dest=None) @bp.route("/destinations//edit", methods=["GET", "POST"]) def destination_edit(dest_id): dest = db.get_or_404(Destination, dest_id) if request.method == "POST": return _save_destination(dest) pub_key = _get_pub_key(dest) return render_template("destination_form.html", dest=dest, pub_key=pub_key) @bp.route("/destinations//delete", methods=["POST"]) def destination_delete(dest_id): dest = db.get_or_404(Destination, dest_id) db.session.delete(dest) db.session.commit() flash(f"Destination « {dest.name} » supprimée.", "success") return redirect(url_for("dest.destinations_list")) @bp.route("/destinations//test", methods=["POST"]) def destination_test(dest_id): dest = db.get_or_404(Destination, dest_id) from jobs.transfer import test_connection ok, msg = test_connection(dest, current_app.config["DATA_DIR"]) flash(msg, "success" if ok else "error") return redirect(url_for("dest.destinations_list")) @bp.route("/archives//transfer", methods=["POST"]) def archive_transfer(archive_name): dest_id = request.form.get("destination_id", type=int) dest = db.get_or_404(Destination, dest_id) app = current_app._get_current_object() def _do_transfer(): with app.app_context(): try: from jobs.transfer import transfer_archive transfer_archive(archive_name, dest, app.config["YUNOHOST_BACKUP_DIR"], app.config["DATA_DIR"]) app.logger.info(f"Transfert {archive_name} → {dest.remote_str} OK") except Exception as exc: app.logger.error(f"Transfert {archive_name} échoué : {exc}") threading.Thread(target=_do_transfer, daemon=True).start() flash(f"Transfert de « {archive_name} » vers {dest.remote_str} démarré.", "success") return redirect(request.referrer or url_for("jobs.index")) def _save_destination(dest): f = request.form name = f.get("name", "").strip() host = f.get("host", "").strip() if not name or not host: flash("Nom et hôte sont requis.", "error") return render_template("destination_form.html", dest=dest) is_new = dest is None if is_new: dest = Destination() db.session.add(dest) dest.name = name dest.host = host dest.port = int(f.get("port", 22) or 22) dest.user = f.get("user", "root").strip() or "root" dest.remote_path = f.get("remote_path", "/home/yunohost.backup/archives").strip() dest.enabled = f.get("enabled") == "1" db.session.flush() if not dest.key_name: from jobs.transfer import generate_key dest.key_name = generate_key(dest.name, current_app.config["DATA_DIR"]) db.session.commit() flash(f"Destination « {dest.name} » enregistrée.", "success") return redirect(url_for("dest.destination_edit", dest_id=dest.id)) def _get_pub_key(dest): if not dest.key_name: return None from jobs.transfer import get_public_key return get_public_key(dest.key_name, current_app.config["DATA_DIR"])