""" 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 """ 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', '.yml'))] config_files.sort() except Exception as e: logger.error(f"Error listing config files: {e}") return render_template('dashboard.html', config_files=config_files) @bp.route('/scans') @login_required def scans(): """ Scans list page - shows all scans with pagination. Returns: Rendered scans list template """ 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', '.yml'))] config_files.sort() except Exception as e: logger.error(f"Error listing config files: {e}") return render_template('scans.html', config_files=config_files) @bp.route('/scans/') @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('/scans//compare/') @login_required def compare_scans(scan_id1, scan_id2): """ Scan comparison page - shows differences between two scans. Args: scan_id1: First (older) scan ID scan_id2: Second (newer) scan ID Returns: Rendered comparison template """ return render_template('scan_compare.html', scan_id1=scan_id1, scan_id2=scan_id2) @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//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) @bp.route('/configs') @login_required def configs(): """ Configuration files list page - shows all config files. Returns: Rendered configs list template """ return render_template('configs.html') @bp.route('/configs/upload') @login_required def upload_config(): """ Config upload page - allows CIDR/YAML upload. Returns: Rendered config upload template """ return render_template('config_upload.html') @bp.route('/configs/edit/') @login_required def edit_config(filename): """ Config edit page - allows editing YAML configuration. Args: filename: Config filename to edit Returns: Rendered config edit template """ from web.services.config_service import ConfigService from flask import flash, redirect try: config_service = ConfigService() config_data = config_service.get_config(filename) return render_template( 'config_edit.html', filename=config_data['filename'], content=config_data['content'] ) except FileNotFoundError: flash(f"Config file '{filename}' not found", 'error') return redirect(url_for('main.configs')) except Exception as e: logger.error(f"Error loading config for edit: {e}") flash(f"Error loading config: {str(e)}", 'error') return redirect(url_for('main.configs'))