package services
import (
"fmt"
"log"
"time"
"github.com/gofiber/fiber/v2"
"github.com/sujit-baniya/fiber-boilerplate/app"
"github.com/sujit-baniya/fiber-boilerplate/utils"
)
func SendPasswordResetEmail(email string, baseURL string) {
resetEmail := fmt.Sprintf("%s-reset-%d", email, time.Now().Unix())
resetLink := GeneratePasswordResetURL(resetEmail, baseURL)
htmlBody := app.Http.Mail.PrepareHtml("emails/password-reset", fiber.Map{
"reset_link": resetLink,
})
if htmlBody == "" {
htmlBody = fmt.Sprintf(`
Restablece tu contraseña haciendo clic aquí: %s
`, resetLink, resetLink)
}
if err := app.Http.Mail.Send(email, "Solicitud de restablecimiento de contraseña - U-site", htmlBody); err != nil {
log.Printf("[MAIL] Error enviando reset a %s: %v", email, err)
} else {
log.Printf("[MAIL] Reset enviado a %s", email)
}
}
func SendConfirmationEmail(email string, baseURL string, nombreUsuario string) {
log.Printf("[MAIL] SendConfirmationEmail → to=%s host=%s port=%d from=%s",
email, app.Http.Mail.Host, app.Http.Mail.Port, app.Http.Mail.FromAddress)
confirmLink := GenerateConfirmURL(nombreUsuario, baseURL)
htmlBody := app.Http.Mail.PrepareHtml("emails/confirm", fiber.Map{
"confirm_link": confirmLink,
})
if htmlBody == "" {
log.Printf("[MAIL] PrepareHtml devolvió cuerpo vacío, usando fallback HTML")
htmlBody = fmt.Sprintf(`Hola %s, confirma tu registro haciendo clic aquí: %s
`,
nombreUsuario, confirmLink, confirmLink)
}
log.Printf("[MAIL] HTML body length: %d bytes", len(htmlBody))
if err := app.Http.Mail.Send(email, "✅ ¡Confirma tu registro en la Oficina Virtual de U-site!", htmlBody); err != nil {
log.Printf("[MAIL] Error enviando confirmación a %s: %v", email, err)
} else {
log.Printf("[MAIL] Confirmación enviada a %s", email)
}
}
// SendUserCredencialesEmail envía al usuario admin su nombre de usuario y un link para establecer contraseña.
func SendUserCredencialesEmail(email, nombre, nombreUsuario string) {
resetEmail := fmt.Sprintf("%s-reset-%d", email, time.Now().Unix())
resetLink := GeneratePasswordResetURL(resetEmail, GetPublicURL())
loginURL := absAppURL("/login")
htmlBody := fmt.Sprintf(`
U
Bienvenido a U-site
Panel de administración
Hola %s,
Tu cuenta ha sido creada. Estos son tus datos de acceso:
Establece tu contraseña haciendo clic en el siguiente botón:
Establecer contraseña
El enlace es válido por 1 hora.
© U-site — Todos los derechos reservados
`, nombre, nombreUsuario, loginURL, loginURL, resetLink)
if err := app.Http.Mail.Send(email, "Bienvenido a U-site — Tus credenciales de acceso", htmlBody); err != nil {
log.Printf("[MAIL] Error enviando credenciales a %s: %v", email, err)
} else {
log.Printf("[MAIL] Credenciales enviadas a %s", email)
}
}
func GenerateConfirmURL(nombreUsuario string, baseURL string) string {
token := utils.Encrypt(nombreUsuario, app.Http.Server.Key)
uri := fmt.Sprintf("%s/do/verify-email?t=%s", baseURL, token)
return uri
}
func GeneratePasswordResetURL(email string, baseURL string) string {
token := utils.Encrypt(email, app.Http.Server.Key)
uri := fmt.Sprintf("%s/reset-password?t=%s", baseURL, token)
return uri
}
// SendPortalPasswordResetEmail envía al usuario del portal un enlace para restablecer su contraseña.
func SendPortalPasswordResetEmail(email, nombre, resetLink string) {
htmlBody := fmt.Sprintf(`
U
Restablecer contraseña
Portal de Clientes · U-site
Hola %s,
Recibimos una solicitud para restablecer la contraseña de tu cuenta. Haz clic en el siguiente botón para continuar:
Restablecer contraseña
Este enlace es válido por 1 hora. Si no solicitaste este cambio, puedes ignorar este mensaje.
© 2025 U-site — Todos los derechos reservados
`, nombre, resetLink)
go func() {
if err := app.Http.Mail.Send(email, "Restablece tu contraseña - Portal U-site", htmlBody, ""); err != nil {
log.Printf("[Portal] Error enviando correo de reseteo a %s: %v", email, err)
}
}()
}
// SendPortalCredentialsEmail envía al usuario del portal su URL de acceso y contraseña inicial.
func SendPortalCredentialsEmail(email, nombre, password string) {
loginURL := absAppURL("/portal/login")
htmlBody := fmt.Sprintf(`
U
Portal de Clientes
Acceso a tu espacio de trabajo
Hola %s,
Tu cuenta en el Portal de Clientes ha sido creada. Usa los siguientes datos para ingresar:
Email: %s
Contraseña: %s
Enlace de acceso: %s
Ingresar al Portal
Si no esperabas este correo, puedes ignorarlo.
`, nombre, email, password, loginURL, loginURL, loginURL)
go func() {
if err := app.Http.Mail.Send(email, "Acceso a tu Portal de Clientes - U-site", htmlBody, ""); err != nil {
log.Printf("[Portal] Error enviando credenciales a %s: %v", email, err)
}
}()
}
// ─── Notificaciones de Tickets ────────────────────────────────────────────────
// SendTicketNuevoAdmin notifica al admin que el cliente abrió un ticket.
func SendTicketNuevoAdmin(adminEmail, proyectoNombre, autorNombre, titulo, descripcion, ticketURL string) {
subject := fmt.Sprintf("🎫 Nuevo ticket: %s", titulo)
htmlBody := fmt.Sprintf(`
🎫
Nuevo ticket de soporte
Proyecto: %s
Cliente: %s
Título: %s
Descripción: %s
Ver ticket
`, proyectoNombre, autorNombre, titulo, descripcion, ticketURL)
go func() {
if err := app.Http.Mail.Send(adminEmail, subject, htmlBody, ""); err != nil {
log.Printf("[Notif] Error enviando ticket nuevo a admin: %v", err)
}
}()
}
// SendTicketRespuestaPortalUser notifica al portal user que el admin respondió.
func SendTicketRespuestaPortalUser(userEmail, userName, proyectoNombre, titulo, respuesta, ticketURL string) {
subject := fmt.Sprintf("💬 Respuesta en tu ticket: %s", titulo)
htmlBody := fmt.Sprintf(`
💬
Hay una respuesta en tu ticket
Proyecto: %s
Hola %s,
El equipo respondió tu ticket "%s":
%s
Ver mi ticket
`, proyectoNombre, userName, titulo, respuesta, ticketURL)
go func() {
if err := app.Http.Mail.Send(userEmail, subject, htmlBody, ""); err != nil {
log.Printf("[Notif] Error enviando respuesta ticket a %s: %v", userEmail, err)
}
}()
}
// SendTicketRespuestaAdmin notifica al admin que el portal user respondió.
func SendTicketRespuestaAdmin(adminEmail, proyectoNombre, autorNombre, titulo, respuesta, ticketURL string) {
subject := fmt.Sprintf("💬 Respuesta de cliente en ticket: %s", titulo)
htmlBody := fmt.Sprintf(`
💬 Respuesta de cliente
Proyecto: %s | Cliente: %s
En el ticket "%s":
%s
Ver ticket
`, proyectoNombre, autorNombre, titulo, respuesta, ticketURL)
go func() {
if err := app.Http.Mail.Send(adminEmail, subject, htmlBody, ""); err != nil {
log.Printf("[Notif] Error enviando respuesta cliente a admin: %v", err)
}
}()
}
// SendTareaAsignadaEmail notifica al usuario asignado sobre una nueva tarea.
func SendTareaAsignadaEmail(toEmail, toName, tareaTitle, prioridad, descripcion, tareaURL string) {
subject := fmt.Sprintf("📋 Nueva tarea asignada: %s", tareaTitle)
htmlBody := fmt.Sprintf(`
📋
Nueva tarea asignada
Prioridad: %s
Hola %s,
Se te asignó la siguiente tarea:
Ver tarea
© U-site — Panel de administración
`, prioridad, toName, tareaTitle, descripcion, tareaURL)
go func() {
if err := app.Http.Mail.Send(toEmail, subject, htmlBody, ""); err != nil {
log.Printf("[Notif] Error enviando tarea asignada a %s: %v", toEmail, err)
}
}()
}
// SendTareaNotifAdmin notifica al admin sobre cambios en tareas (estado, comentarios).
func SendTareaNotifAdmin(adminEmail, titulo, cuerpo, tareaURL string) {
htmlBody := fmt.Sprintf(`
`, titulo, cuerpo, tareaURL)
go func() {
if err := app.Http.Mail.Send(adminEmail, titulo, htmlBody, ""); err != nil {
log.Printf("[Notif] Error enviando notif tarea a admin: %v", err)
}
}()
}
// SendFacturaSubidaPortalUser notifica a un portal user que tiene una nueva factura disponible.
func SendFacturaSubidaPortalUser(toEmail, userName, clienteNombre, numero string, monto float64, moneda, portalURL string) {
go func() {
subject := fmt.Sprintf("Nueva factura disponible: %s", numero)
htmlBody := fmt.Sprintf(`
🧾 Nueva factura disponible
Hola %s,
Tienes una nueva factura disponible para descargar:
Ver en el portal
Este es un mensaje automático.
`, userName, numero, moneda, monto, portalURL)
if err := app.Http.Mail.Send(toEmail, subject, htmlBody, ""); err != nil {
log.Printf("[Notif] Error enviando factura_subida a %s: %v", toEmail, err)
}
}()
}