demo / notification_service.py
VeuReu's picture
Upload 9 files
1a61999
raw
history blame
10.8 kB
"""
Servicio de notificaciones por email para validación interna
Este módulo gestiona el envío de correos a los validadores internos
con la información del vídeo para su revisión regulatoria.
"""
import os
import json
import base64
from typing import Dict, Any, List, Optional
from datetime import datetime
from dataclasses import dataclass
# Imports para email (comentados hasta configuración)
# import smtplib
# from email.mime.text import MIMEText
# from email.mime.multipart import MIMEMultipart
# from email.mime.base import MIMEBase
# from email import encoders
@dataclass
class ValidationRequest:
"""Solicitud de validación para envío por email"""
document_id: str
user_email: str
user_name: str
video_title: str
video_hash: str
timestamp: str
video_url: str
consent_data: Dict[str, Any]
class EmailNotificationService:
"""Servicio de notificaciones por email para validadores"""
def __init__(self):
# Configuración SMTP (comentada hasta despliegue)
self.smtp_server = os.getenv("SMTP_SERVER", "smtp.gmail.com")
self.smtp_port = int(os.getenv("SMTP_PORT", "587"))
self.sender_email = os.getenv("SENDER_EMAIL", "[email protected]")
self.sender_password = os.getenv("SENDER_PASSWORD", "")
# Lista de validadores internos
self.validators = self._load_validators()
def _load_validators(self) -> List[str]:
"""Carga lista de validadores desde configuración"""
# En producción, esto vendría de base de datos o config
default_validators = [
"[email protected]",
"[email protected]",
"[email protected]"
]
# Permitir sobreescribir por variable de entorno
env_validators = os.getenv("VALIDATOR_EMAILS", "")
if env_validators:
return [email.strip() for email in env_validators.split(",")]
return default_validators
def _generate_validation_email(self, request: ValidationRequest) -> str:
"""Genera contenido del email de validación"""
approval_link = f"https://veureu-demo.hf.space/validate?doc_id={request.document_id}&action=approve"
rejection_link = f"https://veureu-demo.hf.space/validate?doc_id={request.document_id}&action=reject"
email_content = f"""
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Solicitud de Validación - Veureu</title>
</head>
<body style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;">
<div style="background-color: #f8f9fa; padding: 20px; border-radius: 8px;">
<h1 style="color: #1f6feb; text-align: center;">🔐 Solicitud de Validación Regulatoria</h1>
<div style="background-color: white; padding: 20px; border-radius: 6px; margin: 20px 0;">
<h2 style="color: #333;">📋 Información del Envío</h2>
<table style="width: 100%; border-collapse: collapse;">
<tr>
<td style="padding: 8px; border-bottom: 1px solid #ddd;"><strong>Usuario:</strong></td>
<td style="padding: 8px; border-bottom: 1px solid #ddd;">{request.user_name} ({request.user_email})</td>
</tr>
<tr>
<td style="padding: 8px; border-bottom: 1px solid #ddd;"><strong>Vídeo:</strong></td>
<td style="padding: 8px; border-bottom: 1px solid #ddd;">{request.video_title}</td>
</tr>
<tr>
<td style="padding: 8px; border-bottom: 1px solid #ddd;"><strong>Hash:</strong></td>
<td style="padding: 8px; border-bottom: 1px solid #ddd;"><code>{request.video_hash[:32]}...</code></td>
</tr>
<tr>
<td style="padding: 8px; border-bottom: 1px solid #ddd;"><strong>Timestamp:</strong></td>
<td style="padding: 8px; border-bottom: 1px solid #ddd;">{request.timestamp}</td>
</tr>
<tr>
<td style="padding: 8px; border-bottom: 1px solid #ddd;"><strong>ID Documento:</strong></td>
<td style="padding: 8px; border-bottom: 1px solid #ddd;"><code>{request.document_id}</code></td>
</tr>
</table>
</div>
<div style="background-color: #fff3cd; padding: 15px; border-radius: 6px; margin: 20px 0; border-left: 4px solid #ffc107;">
<h3 style="color: #856404; margin-top: 0;">✅ Consentimientos Aceptados</h3>
<ul style="color: #856404; margin: 0;">
<li>Derechos sobre el vídeo: {'✅' if request.consent_data.get('rights') else '❌'}</li>
<li>Consentimiento biométrico: {'✅' if request.consent_data.get('biometric') else '❌'}</li>
<li>Contenido permitido: {'✅' if request.consent_data.get('content') else '❌'}</li>
<li>Privacidad y datos: {'✅' if request.consent_data.get('privacy') else '❌'}</li>
</ul>
</div>
<div style="background-color: #d1ecf1; padding: 15px; border-radius: 6px; margin: 20px 0; border-left: 4px solid #17a2b8;">
<h3 style="color: #0c5460; margin-top: 0;">🎥 Acceso al Vídeo</h3>
<p style="color: #0c5460; margin: 0;">Puedes revisar el vídeo en el siguiente enlace:</p>
<p style="margin: 10px 0;"><a href="{request.video_url}" style="background-color: #17a2b8; color: white; padding: 10px 20px; text-decoration: none; border-radius: 4px; display: inline-block;">📹 Ver Vídeo</a></p>
</div>
<div style="text-align: center; margin: 30px 0;">
<h3 style="color: #333;">🔍 Decisión de Validación</h3>
<p style="color: #666;">Por favor, revisa el contenido y toma una decisión:</p>
<div style="display: flex; justify-content: center; gap: 20px; margin: 20px 0;">
<a href="{approval_link}" style="background-color: #28a745; color: white; padding: 12px 24px; text-decoration: none; border-radius: 6px; font-weight: bold;">
✅ APROBAR
</a>
<a href="{rejection_link}" style="background-color: #dc3545; color: white; padding: 12px 24px; text-decoration: none; border-radius: 6px; font-weight: bold;">
❌ RECHAZAR
</a>
</div>
<p style="color: #666; font-size: 12px; margin-top: 20px;">
Esta decisión quedará registrada en AWS QLDB para cumplimiento normativo (AI Act, GDPR).
</p>
</div>
<div style="background-color: #f8f9fa; padding: 15px; border-radius: 6px; margin: 20px 0; text-align: center; color: #666; font-size: 12px;">
<p>Este es un mensaje automático del sistema de validación regulatoria de Veureu.</p>
<p>Para consultas, contacta a [email protected]</p>
</div>
</div>
</body>
</html>
"""
return email_content
def send_validation_request(self, request: ValidationRequest) -> bool:
"""
Envía solicitud de validación a todos los validadores
Returns:
True si éxito, False si error
"""
try:
subject = f"🔐 Validación Regulatoria - {request.video_title}"
html_content = self._generate_validation_email(request)
# Código comentado hasta configuración SMTP
"""
# Configurar mensaje
msg = MIMEMultipart('alternative')
msg['Subject'] = subject
msg['From'] = self.sender_email
msg['To'] = ', '.join(self.validators)
# Adjuntar contenido HTML
html_part = MIMEText(html_content, 'html')
msg.attach(html_part)
# Enviar email
with smtplib.SMTP(self.smtp_server, self.smtp_port) as server:
server.starttls()
server.login(self.sender_email, self.sender_password)
server.send_message(msg)
"""
# Temporal: logging simulado
print(f"[EMAIL - SIMULATED] Enviando solicitud de validación:")
print(f"[EMAIL - SIMULATED] Para: {', '.join(self.validators)}")
print(f"[EMAIL - SIMULATED] Asunto: {subject}")
print(f"[EMAIL - SIMULATED] Documento: {request.document_id}")
print(f"[EMAIL - SIMULATED] Usuario: {request.user_email}")
print(f"[EMAIL - SIMULATED] Vídeo: {request.video_title}")
return True
except Exception as e:
print(f"[EMAIL ERROR] Error enviando validación: {e}")
return False
def send_decision_notification(self, validator_email: str,
decision: str,
document_id: str,
comments: str = "") -> bool:
"""
Envía notificación de decisión tomada por validador
Returns:
True si éxito, False si error
"""
try:
subject = f"🔍 Decisión de Validación - {decision.upper()}"
content = f"""
Se ha registrado una decisión de validación:
Validador: {validator_email}
Documento: {document_id}
Decisión: {decision}
Comentarios: {comments}
Timestamp: {datetime.now().isoformat()}
Esta decisión ha quedado registrada en AWS QLDB.
"""
# Código comentado hasta configuración SMTP
"""
msg = MIMEText(content)
msg['Subject'] = subject
msg['From'] = self.sender_email
msg['To'] = '[email protected]'
with smtplib.SMTP(self.smtp_server, self.smtp_port) as server:
server.starttls()
server.login(self.sender_email, self.sender_password)
server.send_message(msg)
"""
# Temporal: logging simulado
print(f"[EMAIL - SIMULATED] Notificación de decisión enviada:")
print(f"[EMAIL - SIMULATED] Validador: {validator_email}")
print(f"[EMAIL - SIMULATED] Decisión: {decision}")
print(f"[EMAIL - SIMULATED] Documento: {document_id}")
return True
except Exception as e:
print(f"[EMAIL ERROR] Error enviando notificación: {e}")
return False
# Instancia global
notification_service = EmailNotificationService()