ParamManagerScripts/backend/script_groups/EmailCrono/models/mensaje_email.py

145 lines
5.4 KiB
Python

# models/mensaje_email.py
import re
import hashlib
from datetime import datetime
from email.utils import parseaddr, parsedate_to_datetime
class MensajeEmail:
def __init__(self, remitente, fecha, contenido, subject=None, adjuntos=None):
self.remitente = self._estandarizar_remitente(remitente)
self.fecha = self._estandarizar_fecha(fecha)
self.subject = subject if subject else 'Sin Asunto'
self.contenido = self._limpiar_contenido(contenido)
self.adjuntos = adjuntos if adjuntos else []
self.hash = self._generar_hash()
def _formatear_subject_para_link(self, subject):
"""
Formatea el subject para usarlo como ancla en links de Obsidian
Remueve caracteres especiales y espacios múltiples
"""
if not subject:
return "Sin-Asunto"
# Eliminar caracteres especiales y reemplazar espacios con guiones
formatted = re.sub(r'[^\w\s-]', '', subject)
formatted = re.sub(r'\s+', '-', formatted.strip())
return formatted
def _limpiar_contenido(self, contenido):
if not contenido:
return ""
# Eliminar líneas de metadatos
lines = contenido.split('\n')
cleaned_lines = []
for line in lines:
# Skip metadata lines
if line.strip().startswith(('Da: ', 'Inviato: ', 'A: ', 'From: ', 'Sent: ', 'To: ')) or line.strip().startswith('Oggetto: '):
continue
# Limpiar espacios múltiples dentro de cada línea, pero mantener la línea completa
cleaned_line = re.sub(r' +', ' ', line)
cleaned_lines.append(cleaned_line)
# Unir las líneas preservando los saltos de línea
text = '\n'.join(cleaned_lines)
# Limpiar la combinación específica de CRLF+NBSP+CRLF
text = re.sub(r'\r?\n\xa0\r?\n', '\n', text)
# Reemplazar CRLF por LF
text = text.replace('\r\n', '\n')
# Reemplazar CR por LF
text = text.replace('\r', '\n')
# Reemplazar 3 o más saltos de línea por dos
text = re.sub(r'\n{3,}', '\n\n', text)
# Eliminar espacios al inicio y final del texto completo
return text.strip()
def to_markdown(self):
# Hash con caracteres no título
hash_line = f"+ {self.hash}\n\n"
# Subject como título
subject_line = f"### {self.subject if self.subject else 'Sin Asunto'}\n\n"
# Fecha en formato legible
fecha_formato = self.fecha.strftime('%d-%m-%Y')
fecha_line = f"- {fecha_formato}\n\n"
# Contenido del mensaje
md = f"{hash_line}{subject_line}{fecha_line}"
md += self.contenido + "\n\n"
# Adjuntos si existen
if self.adjuntos:
md += "### Adjuntos\n"
for adj in self.adjuntos:
md += f"- [[{adj}]]\n"
md += "---\n\n"
return md
def get_index_entry(self):
"""
Genera una entrada de lista para el índice
"""
fecha_formato = self.fecha.strftime('%d-%m-%Y')
subject_link = self._formatear_subject_para_link(self.subject)
return f"- {fecha_formato} - {self.remitente} - [[cronologia#{self.subject}|{subject_link}]]"
def _estandarizar_remitente(self, remitente):
if 'Da:' in remitente:
remitente = remitente.split('Da:')[1].split('Inviato:')[0]
elif 'From:' in remitente:
remitente = remitente.split('From:')[1].split('Sent:')[0]
nombre, email = parseaddr(remitente)
if not nombre and email:
nombre = email.split('@')[0]
elif not nombre and not email:
nombre_match = re.search(r'([A-Za-z\s]+)\s*<', remitente)
if nombre_match:
nombre = nombre_match.group(1)
else:
return "Remitente Desconocido"
nombre = re.sub(r'[<>:"/\\|?*]', '', nombre.strip())
nombre = nombre.encode('ascii', 'ignore').decode('ascii')
return nombre
def _estandarizar_fecha(self, fecha):
if isinstance(fecha, str):
try:
return parsedate_to_datetime(fecha)
except:
return datetime.now()
return fecha
def _generar_hash(self):
"""
Genera un hash único para el mensaje basado en una combinación de campos
que identifican únicamente el mensaje
"""
# Limpiar y normalizar el contenido para el hash
# Para el hash, sí normalizamos completamente los espacios
contenido_hash = re.sub(r'\s+', ' ', self.contenido).strip()
# Normalizar el subject
subject_normalizado = re.sub(r'\s+', ' ', self.subject if self.subject else '').strip()
# Crear una cadena con los elementos clave del mensaje
elementos_hash = [
self.remitente.strip(),
self.fecha.strftime('%Y%m%d%H%M'), # Solo hasta minutos para permitir pequeñas variaciones
subject_normalizado,
contenido_hash[:500] # Usar solo los primeros 500 caracteres del contenido normalizado
]
# Unir todos los elementos con un separador único
texto_hash = '|'.join(elementos_hash)
# Generar el hash
return hashlib.md5(texto_hash.encode()).hexdigest()