""" â’¸AngelaMos | 2025 Handles all Scan model database queries """ from __future__ import annotations from datetime import UTC, datetime from sqlalchemy.orm import ( Session, joinedload, ) from config import settings from models.Scan import Scan class ScanRepository: """ Repository for Scan database operations """ @staticmethod def create_scan(db: Session, user_id: int, target_url: str, commit: bool = True) -> Scan: """ Create a new scan Args: db: Database session user_id: User ID who initiated the scan target_url: Target URL to scan commit: Whether to commit the transaction Returns: Scan: Created scan instance """ scan = Scan( user_id=user_id, target_url=target_url, scan_date=datetime.now(UTC), ) db.add(scan) if commit: db.commit() db.refresh(scan) return scan @staticmethod def get_by_id(db: Session, scan_id: int) -> Scan | None: """ Get scan by ID with test results loaded Args: db: Database session scan_id: Scan ID Returns: Scan | None: Scan instance or None if not found """ return ( db.query(Scan) .options(joinedload(Scan.test_results)) .filter(Scan.id == scan_id) .first() ) @staticmethod def get_by_user( db: Session, user_id: int, skip: int = 0, limit: int | None = None ) -> list[Scan]: """ Get all scans for a user with pagination. Args: db: Database session user_id: User ID skip: Number of records to skip limit: Maximum number of records to return (DEFAULT_PAGINATION_LIMIT) Returns: list[Scan]: List of scans with test results """ if limit is None: limit = settings.DEFAULT_PAGINATION_LIMIT return ( db.query(Scan) .options(joinedload(Scan.test_results)) .filter(Scan.user_id == user_id) .order_by(Scan.scan_date.desc()) .offset(skip) .limit(limit) .all() ) @staticmethod def get_recent(db: Session, limit: int | None = None) -> list[Scan]: """ Get most recent scans across all users. Args: db: Database session limit: Maximum number of scans to return (DEFAULT_PAGINATION_LIMIT) Returns: list[Scan]: List of recent scans """ if limit is None: limit = settings.DEFAULT_PAGINATION_LIMIT return ( db.query(Scan) .options(joinedload(Scan.test_results)) .order_by(Scan.scan_date.desc()) .limit(limit) .all() ) @staticmethod def delete(db: Session, scan_id: int, commit: bool = True) -> bool: """ Delete a scan (cascades to test results). Args: db: Database session scan_id: Scan ID to delete commit: Whether to commit the transaction Returns: bool: True if deleted, False if not found """ scan = ScanRepository.get_by_id(db, scan_id) if scan: db.delete(scan) if commit: db.commit() return True return False @staticmethod def count_by_user(db: Session, user_id: int) -> int: """ Count total scans for a user. Args: db: Database session user_id: User ID Returns: int: Total number of scans """ return db.query(Scan).filter(Scan.user_id == user_id).count()