Преглед на файлове

fix: corrections review — bugs critiques et mineurs

- app.py: destinations manquant dans render_template sur erreurs de validation
- transfer.py: créer keys/ avant ssh-keygen (crash première destination)
- db_dump.py: supprimer import mort (db, Job, Run)
- scheduler.py: logger un warning si expression cron invalide
- job_form.html: supprimer label obsolète "(Phase 2)"

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Cédric Hansen преди 1 ден
родител
ревизия
3ce633d497
променени са 5 файла, в които са добавени 10 реда и са изтрити 6 реда
  1. 6 3
      sources/app.py
  2. 0 2
      sources/jobs/db_dump.py
  3. 1 0
      sources/jobs/transfer.py
  4. 2 0
      sources/scheduler.py
  5. 1 1
      sources/templates/job_form.html

+ 6 - 3
sources/app.py

@@ -218,7 +218,8 @@ def _save_job(job):
 
     if not name:
         flash("Le nom est requis.", "error")
-        return render_template("job_form.html", job=job, ynh_apps=_get_ynh_apps())
+        return render_template("job_form.html", job=job, ynh_apps=_get_ynh_apps(),
+                               destinations=Destination.query.filter_by(enabled=True).all())
 
     cfg = {}
     if job_type == "ynh_app":
@@ -229,13 +230,15 @@ def _save_job(job):
         dbname = f.get("db_database", "").strip()
         if not dbname:
             flash("Le nom de la base de données est requis.", "error")
-            return render_template("job_form.html", job=job, ynh_apps=_get_ynh_apps())
+            return render_template("job_form.html", job=job, ynh_apps=_get_ynh_apps(),
+                                   destinations=Destination.query.filter_by(enabled=True).all())
         cfg = {"database": dbname}
     elif job_type == "custom_dir":
         source_path = f.get("source_path", "").strip().rstrip("/")
         if not source_path or not source_path.startswith("/"):
             flash("Le chemin source doit être un chemin absolu (ex: /opt/monapp).", "error")
-            return render_template("job_form.html", job=job, ynh_apps=_get_ynh_apps())
+            return render_template("job_form.html", job=job, ynh_apps=_get_ynh_apps(),
+                                   destinations=Destination.query.filter_by(enabled=True).all())
         excludes = [e.strip() for e in f.get("excludes", "").splitlines() if e.strip()]
         restore_cfg = {}
         user_name = f.get("restore_user_name", "").strip()

+ 0 - 2
sources/jobs/db_dump.py

@@ -6,8 +6,6 @@ import tempfile
 import time
 from datetime import datetime
 
-from db import db, Job, Run
-
 
 def run_db_dump(job, instance, backup_dir):
     """Point d'entrée commun mysql et postgresql."""

+ 1 - 0
sources/jobs/transfer.py

@@ -6,6 +6,7 @@ import subprocess
 def generate_key(dest_name, data_dir):
     """Génère une paire de clés ed25519 pour cette destination si elle n'existe pas encore."""
     key_name = f"dest_{_slugify(dest_name)}_ed25519"
+    os.makedirs(os.path.join(data_dir, "keys"), exist_ok=True)
     key_path = os.path.join(data_dir, "keys", key_name)
     if not os.path.exists(key_path):
         subprocess.run(

+ 2 - 0
sources/scheduler.py

@@ -23,10 +23,12 @@ def _execute_job(job_id):
 
 
 def schedule_job(job):
+    import logging
     job_key = f"job_{job.id}"
     try:
         trigger = CronTrigger.from_crontab(job.cron_expr)
     except Exception:
+        logging.warning(f"Job #{job.id} « {job.name} » : expression cron invalide « {job.cron_expr} » — job non planifié.")
         return
     if scheduler.get_job(job_key):
         scheduler.reschedule_job(job_key, trigger=trigger)

+ 1 - 1
sources/templates/job_form.html

@@ -29,7 +29,7 @@
                 class="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500">
           {% for val, label in [('ynh_app','Application YunoHost'), ('ynh_system','Système YunoHost'),
                                 ('mysql','MySQL'), ('postgresql','PostgreSQL'),
-                                ('custom_dir','Répertoire custom (Phase 2)')] %}
+                                ('custom_dir','Répertoire custom')] %}
             <option value="{{ val }}"
               {% if job and job.type == val %}selected{% endif %}
               >