destinations.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. import threading
  2. from flask import (
  3. Blueprint,
  4. current_app,
  5. flash,
  6. redirect,
  7. render_template,
  8. request,
  9. url_for,
  10. )
  11. from db import db, Destination
  12. bp = Blueprint("dest", __name__)
  13. @bp.route("/destinations")
  14. def destinations_list():
  15. destinations = Destination.query.order_by(Destination.name).all()
  16. return render_template("destinations.html", destinations=destinations)
  17. @bp.route("/destinations/new", methods=["GET", "POST"])
  18. def destination_new():
  19. if request.method == "POST":
  20. return _save_destination(None)
  21. return render_template("destination_form.html", dest=None)
  22. @bp.route("/destinations/<int:dest_id>/edit", methods=["GET", "POST"])
  23. def destination_edit(dest_id):
  24. dest = db.get_or_404(Destination, dest_id)
  25. if request.method == "POST":
  26. return _save_destination(dest)
  27. pub_key = _get_pub_key(dest)
  28. return render_template("destination_form.html", dest=dest, pub_key=pub_key)
  29. @bp.route("/destinations/<int:dest_id>/delete", methods=["POST"])
  30. def destination_delete(dest_id):
  31. dest = db.get_or_404(Destination, dest_id)
  32. db.session.delete(dest)
  33. db.session.commit()
  34. flash(f"Destination « {dest.name} » supprimée.", "success")
  35. return redirect(url_for("dest.destinations_list"))
  36. @bp.route("/destinations/<int:dest_id>/test", methods=["POST"])
  37. def destination_test(dest_id):
  38. dest = db.get_or_404(Destination, dest_id)
  39. from jobs.transfer import test_connection
  40. ok, msg = test_connection(dest, current_app.config["DATA_DIR"])
  41. flash(msg, "success" if ok else "error")
  42. return redirect(url_for("dest.destinations_list"))
  43. @bp.route("/archives/<path:archive_name>/transfer", methods=["POST"])
  44. def archive_transfer(archive_name):
  45. dest_id = request.form.get("destination_id", type=int)
  46. dest = db.get_or_404(Destination, dest_id)
  47. app = current_app._get_current_object()
  48. def _do_transfer():
  49. with app.app_context():
  50. try:
  51. from jobs.transfer import transfer_archive
  52. transfer_archive(archive_name, dest, app.config["YUNOHOST_BACKUP_DIR"],
  53. app.config["DATA_DIR"])
  54. app.logger.info(f"Transfert {archive_name} → {dest.remote_str} OK")
  55. except Exception as exc:
  56. app.logger.error(f"Transfert {archive_name} échoué : {exc}")
  57. threading.Thread(target=_do_transfer, daemon=True).start()
  58. flash(f"Transfert de « {archive_name} » vers {dest.remote_str} démarré.", "success")
  59. return redirect(request.referrer or url_for("jobs.index"))
  60. def _save_destination(dest):
  61. f = request.form
  62. name = f.get("name", "").strip()
  63. host = f.get("host", "").strip()
  64. if not name or not host:
  65. flash("Nom et hôte sont requis.", "error")
  66. return render_template("destination_form.html", dest=dest)
  67. is_new = dest is None
  68. if is_new:
  69. dest = Destination()
  70. db.session.add(dest)
  71. dest.name = name
  72. dest.host = host
  73. dest.port = int(f.get("port", 22) or 22)
  74. dest.user = f.get("user", "root").strip() or "root"
  75. dest.remote_path = f.get("remote_path", "/home/yunohost.backup/archives").strip()
  76. dest.enabled = f.get("enabled") == "1"
  77. db.session.flush()
  78. if not dest.key_name:
  79. from jobs.transfer import generate_key
  80. dest.key_name = generate_key(dest.name, current_app.config["DATA_DIR"])
  81. db.session.commit()
  82. flash(f"Destination « {dest.name} » enregistrée.", "success")
  83. return redirect(url_for("dest.destination_edit", dest_id=dest.id))
  84. def _get_pub_key(dest):
  85. if not dest.key_name:
  86. return None
  87. from jobs.transfer import get_public_key
  88. return get_public_key(dest.key_name, current_app.config["DATA_DIR"])