Změny:
Nový DB helper bez ORM: app/db/scheduled_scripts.py
Nové route/UI: app/routes/scheduled_scripts.py
Router registrovaný v app/main.py
Menu doplněné v app/templates/layout.py
Job filtr rozšířený o run_script v app/routes/jobs.py
Implementováno:
GET /portal/scheduled-scripts
GET /portal/scheduled-scripts/{id}
GET/POST /portal/scheduled-scripts/new
GET/POST /portal/scheduled-scripts/{id}/edit
POST /portal/scheduled-scripts/{id}/run-now
POST /portal/scheduled-scripts/{id}/toggle
POST /portal/scheduled-scripts/{id}/delete
Ruční spuštění vytváří run_script job přes existující create_job(...) se source="portal_manual" a payloadem podle zadání. Mazání je blokované, pokud is_running = 1. Validace script_name, schedule_type a timeout_seconds je v route vrstvě.
Audit eventy jsou přidané:
scheduled_script.created
scheduled_script.updated
scheduled_script.deleted
scheduled_script.enabled
scheduled_script.disabled
scheduled_script.run_now
This commit is contained in:
@@ -0,0 +1,172 @@
|
||||
from typing import Any
|
||||
|
||||
from app.db.database import get_connection
|
||||
from app.db.migrations import run_migrations
|
||||
|
||||
|
||||
def get_scheduled_scripts():
|
||||
run_migrations()
|
||||
con = get_connection()
|
||||
|
||||
rows = con.execute(
|
||||
"""
|
||||
SELECT
|
||||
id,
|
||||
name,
|
||||
description,
|
||||
script_name,
|
||||
schedule_type,
|
||||
schedule_time,
|
||||
timeout_seconds,
|
||||
COALESCE(is_enabled, 1) AS is_enabled,
|
||||
COALESCE(is_running, 0) AS is_running,
|
||||
last_run_at,
|
||||
last_status,
|
||||
last_job_id,
|
||||
last_error_text,
|
||||
next_run_at,
|
||||
created_at,
|
||||
updated_at
|
||||
FROM scheduled_scripts
|
||||
ORDER BY name
|
||||
"""
|
||||
).fetchall()
|
||||
|
||||
con.close()
|
||||
return [dict(row) for row in rows]
|
||||
|
||||
|
||||
def get_scheduled_script(script_id: int):
|
||||
run_migrations()
|
||||
con = get_connection()
|
||||
|
||||
row = con.execute(
|
||||
"""
|
||||
SELECT
|
||||
id,
|
||||
name,
|
||||
description,
|
||||
script_name,
|
||||
schedule_type,
|
||||
schedule_time,
|
||||
timeout_seconds,
|
||||
COALESCE(is_enabled, 1) AS is_enabled,
|
||||
COALESCE(is_running, 0) AS is_running,
|
||||
last_run_at,
|
||||
last_status,
|
||||
last_job_id,
|
||||
last_error_text,
|
||||
next_run_at,
|
||||
created_at,
|
||||
updated_at
|
||||
FROM scheduled_scripts
|
||||
WHERE id = ?
|
||||
""",
|
||||
(script_id,),
|
||||
).fetchone()
|
||||
|
||||
con.close()
|
||||
return dict(row) if row else None
|
||||
|
||||
|
||||
def create_scheduled_script(metadata: dict[str, Any]) -> int:
|
||||
run_migrations()
|
||||
con = get_connection()
|
||||
|
||||
cur = con.execute(
|
||||
"""
|
||||
INSERT INTO scheduled_scripts (
|
||||
name,
|
||||
description,
|
||||
script_name,
|
||||
schedule_type,
|
||||
schedule_time,
|
||||
timeout_seconds,
|
||||
is_enabled,
|
||||
is_running,
|
||||
created_at,
|
||||
updated_at
|
||||
)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, 0, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
|
||||
""",
|
||||
(
|
||||
metadata.get("name"),
|
||||
metadata.get("description") or None,
|
||||
metadata.get("script_name"),
|
||||
metadata.get("schedule_type"),
|
||||
metadata.get("schedule_time") or None,
|
||||
metadata.get("timeout_seconds"),
|
||||
1 if metadata.get("is_enabled") else 0,
|
||||
),
|
||||
)
|
||||
script_id = cur.lastrowid
|
||||
con.commit()
|
||||
con.close()
|
||||
return script_id
|
||||
|
||||
|
||||
def update_scheduled_script(script_id: int, metadata: dict[str, Any]) -> None:
|
||||
run_migrations()
|
||||
con = get_connection()
|
||||
|
||||
con.execute(
|
||||
"""
|
||||
UPDATE scheduled_scripts
|
||||
SET name = ?,
|
||||
description = ?,
|
||||
schedule_type = ?,
|
||||
schedule_time = ?,
|
||||
timeout_seconds = ?,
|
||||
is_enabled = ?,
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
WHERE id = ?
|
||||
""",
|
||||
(
|
||||
metadata.get("name"),
|
||||
metadata.get("description") or None,
|
||||
metadata.get("schedule_type"),
|
||||
metadata.get("schedule_time") or None,
|
||||
metadata.get("timeout_seconds"),
|
||||
1 if metadata.get("is_enabled") else 0,
|
||||
script_id,
|
||||
),
|
||||
)
|
||||
|
||||
con.commit()
|
||||
con.close()
|
||||
|
||||
|
||||
def set_scheduled_script_enabled(script_id: int, is_enabled: bool) -> None:
|
||||
run_migrations()
|
||||
con = get_connection()
|
||||
|
||||
con.execute(
|
||||
"""
|
||||
UPDATE scheduled_scripts
|
||||
SET is_enabled = ?,
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
WHERE id = ?
|
||||
""",
|
||||
(1 if is_enabled else 0, script_id),
|
||||
)
|
||||
|
||||
con.commit()
|
||||
con.close()
|
||||
|
||||
|
||||
def delete_scheduled_script(script_id: int) -> bool:
|
||||
run_migrations()
|
||||
con = get_connection()
|
||||
|
||||
cur = con.execute(
|
||||
"""
|
||||
DELETE FROM scheduled_scripts
|
||||
WHERE id = ?
|
||||
AND COALESCE(is_running, 0) = 0
|
||||
""",
|
||||
(script_id,),
|
||||
)
|
||||
deleted = cur.rowcount == 1
|
||||
con.commit()
|
||||
con.close()
|
||||
return deleted
|
||||
Reference in New Issue
Block a user