194 lines
6.5 KiB
Python
194 lines
6.5 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, manteniendo
|
|
# 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#"
|
|
f"{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:
|
|
patron_nombre = r"([A-Za-z\s]+)\s*<"
|
|
nombre_match = re.search(patron_nombre, 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 Exception:
|
|
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 (normaliza 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(),
|
|
# Solo hasta minutos para permitir pequeñas variaciones
|
|
self.fecha.strftime("%Y%m%d%H%M"),
|
|
subject_normalizado,
|
|
# Usar solo los primeros 500 caracteres del contenido normalizado
|
|
contenido_hash[:500],
|
|
]
|
|
|
|
# Unir todos los elementos con un separador único
|
|
texto_hash = "|".join(elementos_hash)
|
|
|
|
# Mostrar información de debug para el hash (solo si está habilitado)
|
|
if hasattr(self, "_debug_hash") and self._debug_hash:
|
|
print(" 🔍 Debug Hash:")
|
|
print(" - Remitente: '" + self.remitente.strip() + "'")
|
|
print(" - Fecha: '" + self.fecha.strftime("%Y%m%d%H%M") + "'")
|
|
print(" - Subject: '" + subject_normalizado + "'")
|
|
preview = contenido_hash[:500]
|
|
print(" - Contenido (500 chars): '" + preview + "'")
|
|
print(" - Texto completo hash: '" + texto_hash[:100] + "...'")
|
|
|
|
# Generar el hash
|
|
hash_resultado = hashlib.md5(texto_hash.encode()).hexdigest()
|
|
|
|
return hash_resultado
|
|
|
|
def debug_hash_info(self):
|
|
"""
|
|
Muestra información detallada de cómo se genera el hash de este
|
|
mensaje
|
|
"""
|
|
self._debug_hash = True
|
|
hash_result = self._generar_hash()
|
|
delattr(self, "_debug_hash")
|
|
return hash_result
|