Los clientes escriben a soporte@ desde su correo de siempre. Hasta ahora eso solo llegaba si un proveedor (SendGrid/Mailgun) nos hacía POST; si nadie lo configuraba, los correos quedaban sin leer en el buzón. Ahora el cron entra al buzón cada 2 minutos, baja los no leídos, abre ticket (o los engancha al hilo si son respuesta) y los marca como leídos. La lógica de ingesta se movió a services para que webhook e IMAP se comporten igual. La contraseña del buzón se guarda cifrada (AES-GCM con APP_KEY) y no vuelve al navegador. De paso, dos bugs que impedían guardar la configuración: el formulario mandaba id=0 (gorm.Model serializa "ID"), así que cada guardado creaba una fila nueva en vez de editar la que se usa; y Updates con struct ignoraba los booleanos en false, así que desactivar algo no tenía efecto. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
81 lines
2.1 KiB
Go
81 lines
2.1 KiB
Go
package services
|
|
|
|
import (
|
|
"testing"
|
|
)
|
|
|
|
func TestExtractEmailSimple(t *testing.T) {
|
|
tests := []struct {
|
|
input string
|
|
want string
|
|
}{
|
|
{"user@example.com", "user@example.com"},
|
|
{"<user@example.com>", "user@example.com"},
|
|
{"John Doe <john@example.com>", "john@example.com"},
|
|
{"\"John Doe\" <john@example.com>", "john@example.com"},
|
|
{" spaced@example.com ", "spaced@example.com"},
|
|
{"", ""},
|
|
{"<onlybrackets>", "onlybrackets"},
|
|
}
|
|
for _, tt := range tests {
|
|
got := ExtraerEmail(tt.input)
|
|
if got != tt.want {
|
|
t.Errorf("ExtraerEmail(%q) = %q, want %q", tt.input, got, tt.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestExtractNameSimple(t *testing.T) {
|
|
tests := []struct {
|
|
input string
|
|
want string
|
|
}{
|
|
{"John Doe <john@example.com>", "John Doe"},
|
|
{"<user@example.com>", ""},
|
|
{"user@example.com", ""},
|
|
{" Spaces Here <spaces@example.com>", "Spaces Here"},
|
|
{"\"Quoted Name\" <q@example.com>", "\"Quoted Name\""},
|
|
{"", ""},
|
|
}
|
|
for _, tt := range tests {
|
|
got := ExtraerNombre(tt.input)
|
|
if got != tt.want {
|
|
t.Errorf("ExtraerNombre(%q) = %q, want %q", tt.input, got, tt.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestExtractEmailRealWorld(t *testing.T) {
|
|
inputs := []struct {
|
|
full string
|
|
mail string
|
|
name string
|
|
}{
|
|
{"María López <maria@example.com>", "maria@example.com", "María López"},
|
|
{"soporte@u-s.app", "soporte@u-s.app", ""},
|
|
{"Cliente Final <cliente+tag@dominio.co>", "cliente+tag@dominio.co", "Cliente Final"},
|
|
{"", "", ""},
|
|
}
|
|
for _, tt := range inputs {
|
|
gotMail := ExtraerEmail(tt.full)
|
|
gotName := ExtraerNombre(tt.full)
|
|
if gotMail != tt.mail {
|
|
t.Errorf("ExtraerEmail(%q) = %q, want %q", tt.full, gotMail, tt.mail)
|
|
}
|
|
if gotName != tt.name {
|
|
t.Errorf("ExtraerNombre(%q) = %q, want %q", tt.full, gotName, tt.name)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestExtractEmailEdgeCases(t *testing.T) {
|
|
// Formato RFC 5322 con nombre y ángulos
|
|
if got := ExtraerEmail("a<b@c.com>"); got != "b@c.com" {
|
|
t.Errorf("ExtraerEmail('a<b@c.com>') = %q, want 'b@c.com'", got)
|
|
}
|
|
// Múltiples brackets — usa el último par
|
|
if got := ExtraerEmail("<a><b@c.com>"); got != "b@c.com" {
|
|
t.Errorf("ExtraerEmail('<a><b@c.com>') = %q, want 'b@c.com'", got)
|
|
}
|
|
}
|