Implemented full schedule management system with API endpoints and user interface for creating, editing, and managing scheduled scans. API Implementation: - Implemented all 6 schedules API endpoints (list, get, create, update, delete, trigger) - Added comprehensive error handling and validation - Integrated with ScheduleService and SchedulerService - Added manual trigger endpoint for on-demand execution Schedule Management UI: - Created schedules list page with stats cards and enable/disable toggles - Built schedule creation form with cron expression builder and quick templates - Implemented schedule edit page with execution history - Added "Schedules" navigation link to main menu - Real-time validation and human-readable cron descriptions Config File Path Resolution: - Fixed config file path handling to support relative filenames - Updated validators.py to resolve relative paths to /app/configs/ - Modified schedule_service.py, scan_service.py, and scan_job.py for consistency - Ensures UI can use simple filenames while backend uses absolute paths Scheduler Integration: - Completed scheduled scan execution in scheduler_service.py - Added cron job management with APScheduler - Implemented automatic schedule loading on startup - Updated run times after each execution Testing: - Added comprehensive API integration tests (test_schedule_api.py) - 22+ test cases covering all endpoints and workflows Progress: Phase 3 Steps 1-4 complete (36% - 5/14 days) Next: Step 5 - Enhanced Dashboard with Charts
125 lines
2.7 KiB
Python
125 lines
2.7 KiB
Python
"""
|
|
Main web routes for SneakyScanner.
|
|
|
|
Provides dashboard and scan viewing pages.
|
|
"""
|
|
|
|
import logging
|
|
|
|
from flask import Blueprint, current_app, redirect, render_template, url_for
|
|
|
|
from web.auth.decorators import login_required
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
bp = Blueprint('main', __name__)
|
|
|
|
|
|
@bp.route('/')
|
|
def index():
|
|
"""
|
|
Root route - redirect to dashboard.
|
|
|
|
Returns:
|
|
Redirect to dashboard
|
|
"""
|
|
return redirect(url_for('main.dashboard'))
|
|
|
|
|
|
@bp.route('/dashboard')
|
|
@login_required
|
|
def dashboard():
|
|
"""
|
|
Dashboard page - shows recent scans and statistics.
|
|
|
|
Returns:
|
|
Rendered dashboard template
|
|
"""
|
|
# TODO: Phase 5 - Add dashboard stats and recent scans
|
|
return render_template('dashboard.html')
|
|
|
|
|
|
@bp.route('/scans')
|
|
@login_required
|
|
def scans():
|
|
"""
|
|
Scans list page - shows all scans with pagination.
|
|
|
|
Returns:
|
|
Rendered scans list template
|
|
"""
|
|
# TODO: Phase 5 - Implement scans list page
|
|
return render_template('scans.html')
|
|
|
|
|
|
@bp.route('/scans/<int:scan_id>')
|
|
@login_required
|
|
def scan_detail(scan_id):
|
|
"""
|
|
Scan detail page - shows full scan results.
|
|
|
|
Args:
|
|
scan_id: Scan ID to display
|
|
|
|
Returns:
|
|
Rendered scan detail template
|
|
"""
|
|
# TODO: Phase 5 - Implement scan detail page
|
|
return render_template('scan_detail.html', scan_id=scan_id)
|
|
|
|
|
|
@bp.route('/schedules')
|
|
@login_required
|
|
def schedules():
|
|
"""
|
|
Schedules list page - shows all scheduled scans.
|
|
|
|
Returns:
|
|
Rendered schedules list template
|
|
"""
|
|
return render_template('schedules.html')
|
|
|
|
|
|
@bp.route('/schedules/create')
|
|
@login_required
|
|
def create_schedule():
|
|
"""
|
|
Create new schedule form page.
|
|
|
|
Returns:
|
|
Rendered schedule create template with available config files
|
|
"""
|
|
import os
|
|
|
|
# Get list of available config files
|
|
configs_dir = '/app/configs'
|
|
config_files = []
|
|
|
|
try:
|
|
if os.path.exists(configs_dir):
|
|
config_files = [f for f in os.listdir(configs_dir) if f.endswith('.yaml')]
|
|
config_files.sort()
|
|
except Exception as e:
|
|
logger.error(f"Error listing config files: {e}")
|
|
|
|
return render_template('schedule_create.html', config_files=config_files)
|
|
|
|
|
|
@bp.route('/schedules/<int:schedule_id>/edit')
|
|
@login_required
|
|
def edit_schedule(schedule_id):
|
|
"""
|
|
Edit existing schedule form page.
|
|
|
|
Args:
|
|
schedule_id: Schedule ID to edit
|
|
|
|
Returns:
|
|
Rendered schedule edit template
|
|
"""
|
|
from flask import flash
|
|
|
|
# Note: Schedule data is loaded via AJAX in the template
|
|
# This just renders the page with the schedule_id in the URL
|
|
return render_template('schedule_edit.html', schedule_id=schedule_id)
|