Files
BanGUI/backend/app/mappers/blocklist_mappers.py
Lukas 0d5882b32f Fix HIGH priority issues: unbounded queries, rate limiting, health checks
Issue #3 - Unbounded Query Results (OOM):
- get_all_archived_history() now uses keyset pagination with bounded max_rows (50k default)
- Added 'id' field to records from get_archived_history() and get_archived_history_keyset()
- Protocol signature updated with page_size, max_rows, last_ban_id params

Issue #7 - Docker Health Check Fails:
- Added curl to Dockerfile.backend runtime image
- HEALTHCHECK now uses 'curl -f http://localhost:8000/api/health'
- compose.prod.yml: increased start_period to 40s, timeout to 10s
- Frontend healthcheck proxies to backend /api/health

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-01 21:47:36 +02:00

142 lines
4.2 KiB
Python

"""Blocklist response mappers.
Convert domain models (from blocklist_service) to response models (for HTTP API).
This is the mapping layer at the router boundary, ensuring the service layer
remains independent of HTTP response shapes.
"""
from __future__ import annotations
from app.models.blocklist import (
BlocklistSource,
ImportLogEntry,
ImportLogListResponse,
ImportRunResult,
ImportSourceResult,
PreviewResponse,
ScheduleConfig,
ScheduleFrequency,
ScheduleInfo,
)
from app.models.blocklist_domain import (
DomainBlocklistSource,
DomainImportLogEntry,
DomainImportLogList,
DomainImportRunResult,
DomainImportSourceResult,
DomainPreviewResult,
DomainScheduleConfig,
DomainScheduleFrequency,
DomainScheduleInfo,
)
from app.utils.pagination import create_pagination_metadata
def map_domain_blocklist_source_to_response(
domain: DomainBlocklistSource,
) -> BlocklistSource:
"""Convert domain blocklist source to response model."""
return BlocklistSource(
id=domain.id,
name=domain.name,
url=domain.url,
enabled=domain.enabled,
created_at=domain.created_at,
updated_at=domain.updated_at,
)
def map_domain_import_log_entry_to_response(
domain: DomainImportLogEntry,
) -> ImportLogEntry:
"""Convert domain import log entry to response model."""
return ImportLogEntry(
id=domain.id,
source_id=domain.source_id,
source_url=domain.source_url,
timestamp=domain.timestamp,
ips_imported=domain.ips_imported,
ips_skipped=domain.ips_skipped,
errors=domain.errors,
)
def map_domain_import_log_list_to_response(
domain_list: DomainImportLogList,
) -> ImportLogListResponse:
"""Convert domain import log list to response model."""
return ImportLogListResponse(
items=[map_domain_import_log_entry_to_response(i) for i in domain_list.items],
pagination=create_pagination_metadata(
domain_list.total, domain_list.page, domain_list.page_size
),
)
def map_domain_schedule_frequency_to_response(
domain: DomainScheduleFrequency,
) -> ScheduleFrequency:
"""Convert domain schedule frequency to response model."""
return ScheduleFrequency(domain.value)
def map_domain_schedule_config_to_response(
domain: DomainScheduleConfig,
) -> ScheduleConfig:
"""Convert domain schedule config to response model."""
return ScheduleConfig(
frequency=map_domain_schedule_frequency_to_response(domain.frequency),
interval_hours=domain.interval_hours,
hour=domain.hour,
minute=domain.minute,
day_of_week=domain.day_of_week,
)
def map_domain_schedule_info_to_response(domain: DomainScheduleInfo) -> ScheduleInfo:
"""Convert domain schedule info to response model."""
return ScheduleInfo(
config=map_domain_schedule_config_to_response(domain.config),
next_run_at=domain.next_run_at,
last_run_at=domain.last_run_at,
last_run_errors=domain.last_run_errors,
)
def map_domain_preview_result_to_response(domain: DomainPreviewResult) -> PreviewResponse:
"""Convert domain preview result to response model."""
return PreviewResponse(
entries=domain.entries,
total_lines=domain.total_lines,
valid_count=domain.valid_count,
skipped_count=domain.skipped_count,
)
def map_domain_import_source_result_to_response(
domain: DomainImportSourceResult,
) -> ImportSourceResult:
"""Convert domain import source result to response model."""
return ImportSourceResult(
source_id=domain.source_id,
source_url=domain.source_url,
ips_imported=domain.ips_imported,
ips_skipped=domain.ips_skipped,
error=domain.error,
)
def map_domain_import_run_result_to_response(
domain: DomainImportRunResult,
) -> ImportRunResult:
"""Convert domain import run result to response model."""
return ImportRunResult(
results=[
map_domain_import_source_result_to_response(r) for r in domain.results
],
total_imported=domain.total_imported,
total_skipped=domain.total_skipped,
errors_count=domain.errors_count,
)