feat: add scheduled scans (cron-like recurring scans)
- New `scheduled_scans` table with daily/weekly/monthly frequencies - asyncio background scheduler loop checks for due schedules every 60s - 6 REST endpoints: CRUD + toggle enabled + run-now - `scheduled_scan_id` FK added to scans table; migrated automatically - Frontend: Schedules page (list + create form), Schedules nav link, "Scheduled" badge on ScanDetails when scan was triggered by a schedule Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -167,6 +167,29 @@ def _migrate_add_routes_unique_index(conn, verbose=True):
|
||||
print(" ✅ Migration complete: uq_routes_scan_dest index created")
|
||||
|
||||
|
||||
def _migrate_add_scheduled_scan_id_to_scans(conn, verbose=True):
|
||||
"""
|
||||
Migration: add scheduled_scan_id column to scans table.
|
||||
|
||||
Existing rows get NULL (manual scans). New column has no inline FK
|
||||
declaration because SQLite's ALTER TABLE ADD COLUMN doesn't support it;
|
||||
the relationship is enforced at the application level.
|
||||
"""
|
||||
cursor = conn.execute("PRAGMA table_info(scans)")
|
||||
columns = [row[1] for row in cursor.fetchall()]
|
||||
if 'scheduled_scan_id' in columns:
|
||||
return # Already migrated
|
||||
|
||||
if verbose:
|
||||
print(" 🔄 Migrating scans table: adding scheduled_scan_id column...")
|
||||
|
||||
conn.execute("ALTER TABLE scans ADD COLUMN scheduled_scan_id INTEGER")
|
||||
conn.commit()
|
||||
|
||||
if verbose:
|
||||
print(" ✅ Migration complete: scheduled_scan_id column added to scans")
|
||||
|
||||
|
||||
def initialize_database(db_path=None, verbose=True):
|
||||
"""
|
||||
Initialize or migrate the database.
|
||||
@@ -212,6 +235,7 @@ def initialize_database(db_path=None, verbose=True):
|
||||
# Apply migrations before running schema
|
||||
_migrate_relax_country_constraint(conn, verbose)
|
||||
_migrate_add_routes_unique_index(conn, verbose)
|
||||
_migrate_add_scheduled_scan_id_to_scans(conn, verbose)
|
||||
|
||||
# Load and execute schema
|
||||
schema_sql = load_schema()
|
||||
|
||||
Reference in New Issue
Block a user