from domain.reports import Report from application.ports.report_repository import ReportRepository from application.ports.user_repository import UserRepository from infrastructure.adapters.rabbitmq.sender import send_to_queue from infrastructure.adapters.rabbitmq.messages import ReportMessage, ReportEventType from datetime import datetime from typing import List, Optional, Dict, Any from uuid import uuid4 class CreateReport: """Use case para crear un nuevo reporte - envía mensaje a RabbitMQ""" def __init__(self, repo: ReportRepository, user_repo: UserRepository): if not isinstance(repo, ReportRepository): raise TypeError("repo must implement ReportRepository") if not isinstance(user_repo, UserRepository): raise TypeError("user_repo must implement UserRepository") self.repo = repo self.user_repo = user_repo def execute(self, id_usuario: int, tipo_reporte: int, descripcion: str, ubicacion: Optional[str] = None, lat: Optional[float] = None, lng: Optional[float] = None, image_filename: Optional[str] = None) -> Dict[str, Any]: """ Sends a create report message to RabbitMQ. Valida previamente: - Usuario existe - Descripción no está vacía - Tipo de reporte válido Returns: Dictionary with status and message """ # Validación: descripción requerida if not descripcion or not descripcion.strip(): return { "status": "error", "message": "La descripción del reporte es requerida" } # Validación: tipo de reporte válido (1-5) if tipo_reporte < 1 or tipo_reporte > 5: return { "status": "error", "message": "El tipo de reporte debe estar entre 1 y 5" } # Validación: usuario existe (CRÍTICO) try: user = self.user_repo.find_by_id(id_usuario) if not user: return { "status": "error", "message": f"Usuario con ID {id_usuario} no existe" } except Exception as e: return { "status": "error", "message": f"Error al validar usuario: {str(e)}" } id_reporte = str(uuid4()) fecha_creacion = datetime.now() # Create message object message = ReportMessage( event_type=ReportEventType.CREATE, id_reporte=id_reporte, id_usuario=id_usuario, tipo_reporte=tipo_reporte, descripcion=descripcion.strip(), ubicacion=ubicacion, lat=lat, lng=lng, image_filename=image_filename, visibilidad=50.0, # Visibilidad inicial neutral fecha_creacion=fecha_creacion.isoformat() ) # Send to RabbitMQ success = send_to_queue("reports_queue", message.to_dict()) if success: return { "status": "queued", "message": "Reporte enviado a cola para procesamiento", "id_reporte": id_reporte } else: return { "status": "error", "message": "Error al enviar reporte a la cola de procesamiento" } class GetReportById: """Use case para obtener un reporte por ID""" def __init__(self, repo: ReportRepository): if not isinstance(repo, ReportRepository): raise TypeError("repo must implement ReportRepository") self.repo = repo def execute(self, report_id: str) -> Optional[Report]: return self.repo.find_by_id(report_id) class GetReportsByUser: """Use case para obtener todos los reportes de un usuario""" def __init__(self, repo: ReportRepository): if not isinstance(repo, ReportRepository): raise TypeError("repo must implement ReportRepository") self.repo = repo def execute(self, user_id: int) -> List[Report]: return self.repo.find_by_user_id(user_id) class ListAllReports: """Use case para obtener todos los reportes""" def __init__(self, repo: ReportRepository): if not isinstance(repo, ReportRepository): raise TypeError("repo must implement ReportRepository") self.repo = repo def execute(self) -> List[Report]: return self.repo.find_all() class UpdateReportVisibility: """Use case para actualizar la visibilidad de un reporte basado en votación comunitaria - envía mensaje a RabbitMQ""" def __init__(self, repo: ReportRepository, user_repo: UserRepository): if not isinstance(repo, ReportRepository): raise TypeError("repo must implement ReportRepository") self.repo = repo self.user_repo = user_repo def execute(self, report_id: str, new_visibility: float, penalize_author: bool = False) -> Dict[str, Any]: """ Sends an update report visibility message to RabbitMQ. Valida previamente: - Reporte existe - Visibilidad en rango válido (0-100) Returns: Dictionary with status and message """ # Validación: reporte existe try: report = self.repo.find_by_id(report_id) if not report: return { "status": "error", "message": f"Reporte con ID {report_id} no existe" } except Exception as e: return { "status": "error", "message": f"Error al buscar reporte: {str(e)}" } # Validar rango de visibilidad if new_visibility < 0 or new_visibility > 100: return { "status": "error", "message": "La visibilidad debe estar entre 0 y 100" } # Create message object message = ReportMessage( event_type=ReportEventType.UPDATE_VISIBILITY, id_reporte=report_id, visibilidad=new_visibility, penalize_author=penalize_author ) # Send to RabbitMQ success = send_to_queue("reports_queue", message.to_dict()) if success: return { "status": "queued", "message": "Actualización de visibilidad enviada a cola para procesamiento", "report_id": report_id, "new_visibility": new_visibility } else: return { "status": "error", "message": "Error al enviar actualización de visibilidad a la cola de procesamiento" } class GetShadowbannedReports: """Use case para obtener reportes shadowbaneados (baja visibilidad)""" def __init__(self, repo: ReportRepository): if not isinstance(repo, ReportRepository): raise TypeError("repo must implement ReportRepository") self.repo = repo def execute(self, visibility_threshold: float = 20) -> List[Report]: return self.repo.find_shadowbanned(visibility_threshold) class DeleteReport: """Use case para eliminar un reporte - envía mensaje a RabbitMQ""" def __init__(self, repo: ReportRepository): if not isinstance(repo, ReportRepository): raise TypeError("repo must implement ReportRepository") self.repo = repo def execute(self, report_id: str) -> Dict[str, Any]: """ Sends a delete report message to RabbitMQ. Valida previamente: - Reporte existe Returns: Dictionary with status and message """ # Validación: reporte existe try: report = self.repo.find_by_id(report_id) if not report: return { "status": "error", "message": f"Reporte con ID {report_id} no existe" } except Exception as e: return { "status": "error", "message": f"Error al buscar reporte: {str(e)}" } # Create message object message = ReportMessage( event_type=ReportEventType.DELETE, id_reporte=report_id ) # Send to RabbitMQ success = send_to_queue("reports_queue", message.to_dict()) if success: return { "status": "queued", "message": f"Reporte {report_id} enviado a cola para eliminación", "id_reporte": report_id } else: return { "status": "error", "message": "Error al enviar eliminación del reporte a la cola de procesamiento" }