fix: connect EmailService to contact form handler
The contact form was logging submissions but never actually sending emails. This commit: - Adds EmailService field to CVHandler - Initializes EmailService in main.go with SMTP config - Calls SendContactForm in HandleContact handler - Updates all test files to pass nil for emailService parameter
This commit is contained in:
@@ -21,7 +21,7 @@ func BenchmarkHome(b *testing.B) {
|
|||||||
b.Fatalf("Failed to create template manager: %v", err)
|
b.Fatalf("Failed to create template manager: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
handler := NewCVHandler(tmplManager, "localhost:8080")
|
handler := NewCVHandler(tmplManager, "localhost:8080", nil)
|
||||||
|
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
@@ -43,7 +43,7 @@ func BenchmarkCVContent(b *testing.B) {
|
|||||||
b.Fatalf("Failed to create template manager: %v", err)
|
b.Fatalf("Failed to create template manager: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
handler := NewCVHandler(tmplManager, "localhost:8080")
|
handler := NewCVHandler(tmplManager, "localhost:8080", nil)
|
||||||
|
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
@@ -65,7 +65,7 @@ func BenchmarkToggleLength(b *testing.B) {
|
|||||||
b.Fatalf("Failed to create template manager: %v", err)
|
b.Fatalf("Failed to create template manager: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
handler := NewCVHandler(tmplManager, "localhost:8080")
|
handler := NewCVHandler(tmplManager, "localhost:8080", nil)
|
||||||
|
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
@@ -101,7 +101,7 @@ func BenchmarkPrepareTemplateData(b *testing.B) {
|
|||||||
b.Fatalf("Failed to create template manager: %v", err)
|
b.Fatalf("Failed to create template manager: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
handler := NewCVHandler(tmplManager, "localhost:8080")
|
handler := NewCVHandler(tmplManager, "localhost:8080", nil)
|
||||||
|
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
@@ -144,7 +144,7 @@ func BenchmarkParallelHome(b *testing.B) {
|
|||||||
b.Fatalf("Failed to create template manager: %v", err)
|
b.Fatalf("Failed to create template manager: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
handler := NewCVHandler(tmplManager, "localhost:8080")
|
handler := NewCVHandler(tmplManager, "localhost:8080", nil)
|
||||||
|
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
b.RunParallel(func(pb *testing.PB) {
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
@@ -168,7 +168,7 @@ func BenchmarkParallelToggleLength(b *testing.B) {
|
|||||||
b.Fatalf("Failed to create template manager: %v", err)
|
b.Fatalf("Failed to create template manager: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
handler := NewCVHandler(tmplManager, "localhost:8080")
|
handler := NewCVHandler(tmplManager, "localhost:8080", nil)
|
||||||
|
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
b.RunParallel(func(pb *testing.PB) {
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/juanatsap/cv-site/internal/pdf"
|
"github.com/juanatsap/cv-site/internal/pdf"
|
||||||
|
"github.com/juanatsap/cv-site/internal/services"
|
||||||
"github.com/juanatsap/cv-site/internal/templates"
|
"github.com/juanatsap/cv-site/internal/templates"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -12,18 +13,21 @@ import (
|
|||||||
// - cv_pages.go: Page rendering (Home, CVContent, DefaultCVShortcut)
|
// - cv_pages.go: Page rendering (Home, CVContent, DefaultCVShortcut)
|
||||||
// - cv_pdf.go: PDF export (ExportPDF)
|
// - cv_pdf.go: PDF export (ExportPDF)
|
||||||
// - cv_htmx.go: HTMX toggles (ToggleLength, ToggleIcons, SwitchLanguage, ToggleTheme)
|
// - cv_htmx.go: HTMX toggles (ToggleLength, ToggleIcons, SwitchLanguage, ToggleTheme)
|
||||||
|
// - cv_contact.go: Contact form submission (HandleContact)
|
||||||
// - cv_helpers.go: Helper functions (skills, dates, git, templates, cookies)
|
// - cv_helpers.go: Helper functions (skills, dates, git, templates, cookies)
|
||||||
type CVHandler struct {
|
type CVHandler struct {
|
||||||
templates *templates.Manager
|
templates *templates.Manager
|
||||||
pdfGenerator *pdf.Generator
|
pdfGenerator *pdf.Generator
|
||||||
|
emailService *services.EmailService
|
||||||
serverAddr string
|
serverAddr string
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCVHandler creates a new CV handler
|
// NewCVHandler creates a new CV handler
|
||||||
func NewCVHandler(tmpl *templates.Manager, serverAddr string) *CVHandler {
|
func NewCVHandler(tmpl *templates.Manager, serverAddr string, emailService *services.EmailService) *CVHandler {
|
||||||
return &CVHandler{
|
return &CVHandler{
|
||||||
templates: tmpl,
|
templates: tmpl,
|
||||||
pdfGenerator: pdf.NewGenerator(30 * time.Second),
|
pdfGenerator: pdf.NewGenerator(30 * time.Second),
|
||||||
|
emailService: emailService,
|
||||||
serverAddr: serverAddr,
|
serverAddr: serverAddr,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ func TestCmdKData(t *testing.T) {
|
|||||||
t.Fatalf("Failed to create template manager: %v", err)
|
t.Fatalf("Failed to create template manager: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
handler := NewCVHandler(tmplManager, "localhost:8080")
|
handler := NewCVHandler(tmplManager, "localhost:8080", nil)
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
@@ -207,7 +207,7 @@ func TestCmdKDataCaching(t *testing.T) {
|
|||||||
t.Fatalf("Failed to create template manager: %v", err)
|
t.Fatalf("Failed to create template manager: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
handler := NewCVHandler(tmplManager, "localhost:8080")
|
handler := NewCVHandler(tmplManager, "localhost:8080", nil)
|
||||||
|
|
||||||
req := httptest.NewRequest(http.MethodGet, "/api/cmd-k", nil)
|
req := httptest.NewRequest(http.MethodGet, "/api/cmd-k", nil)
|
||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
uimodel "github.com/juanatsap/cv-site/internal/models/ui"
|
uimodel "github.com/juanatsap/cv-site/internal/models/ui"
|
||||||
|
"github.com/juanatsap/cv-site/internal/services"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ==============================================================================
|
// ==============================================================================
|
||||||
@@ -81,14 +82,33 @@ func (h *CVHandler) HandleContact(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log the contact form submission (in production, send email or save to database)
|
// Log the contact form submission
|
||||||
log.Printf("Contact form submission from %s (IP: %s)", formData.Email, getClientIP(r))
|
log.Printf("Contact form submission from %s (IP: %s)", formData.Email, getClientIP(r))
|
||||||
log.Printf(" Name: %s, Company: %s", formData.Name, formData.Company)
|
log.Printf(" Name: %s, Company: %s", formData.Name, formData.Company)
|
||||||
log.Printf(" Subject: %s", formData.Subject)
|
log.Printf(" Subject: %s", formData.Subject)
|
||||||
log.Printf(" Message length: %d characters", len(formData.Message))
|
log.Printf(" Message length: %d characters", len(formData.Message))
|
||||||
|
|
||||||
// TODO: Implement actual email sending or database storage here
|
// Send email via EmailService
|
||||||
// For now, we just log and return success
|
if h.emailService != nil {
|
||||||
|
emailData := &services.ContactFormData{
|
||||||
|
Email: formData.Email,
|
||||||
|
Name: formData.Name,
|
||||||
|
Company: formData.Company,
|
||||||
|
Subject: formData.Subject,
|
||||||
|
Message: formData.Message,
|
||||||
|
IP: getClientIP(r),
|
||||||
|
Time: time.Now(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := h.emailService.SendContactForm(emailData); err != nil {
|
||||||
|
log.Printf("ERROR sending contact email: %v", err)
|
||||||
|
h.renderContactError(w, r, "Failed to send message. Please try again later.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Printf("Contact email sent successfully to configured recipient")
|
||||||
|
} else {
|
||||||
|
log.Printf("WARNING: Email service not configured, skipping email send")
|
||||||
|
}
|
||||||
|
|
||||||
// Render success response
|
// Render success response
|
||||||
h.renderContactSuccess(w, r, lang)
|
h.renderContactSuccess(w, r, lang)
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ func TestToggleLength(t *testing.T) {
|
|||||||
t.Fatalf("Failed to create template manager: %v", err)
|
t.Fatalf("Failed to create template manager: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
handler := NewCVHandler(tmplManager, "localhost:8080")
|
handler := NewCVHandler(tmplManager, "localhost:8080", nil)
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
@@ -94,7 +94,7 @@ func TestToggleIcons(t *testing.T) {
|
|||||||
t.Fatalf("Failed to create template manager: %v", err)
|
t.Fatalf("Failed to create template manager: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
handler := NewCVHandler(tmplManager, "localhost:8080")
|
handler := NewCVHandler(tmplManager, "localhost:8080", nil)
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
@@ -152,7 +152,7 @@ func TestSwitchLanguage(t *testing.T) {
|
|||||||
t.Fatalf("Failed to create template manager: %v", err)
|
t.Fatalf("Failed to create template manager: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
handler := NewCVHandler(tmplManager, "localhost:8080")
|
handler := NewCVHandler(tmplManager, "localhost:8080", nil)
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
@@ -221,7 +221,7 @@ func TestToggleTheme(t *testing.T) {
|
|||||||
t.Fatalf("Failed to create template manager: %v", err)
|
t.Fatalf("Failed to create template manager: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
handler := NewCVHandler(tmplManager, "localhost:8080")
|
handler := NewCVHandler(tmplManager, "localhost:8080", nil)
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
@@ -287,7 +287,7 @@ func TestHTMXHandlersRequirePost(t *testing.T) {
|
|||||||
t.Fatalf("Failed to create template manager: %v", err)
|
t.Fatalf("Failed to create template manager: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
handler := NewCVHandler(tmplManager, "localhost:8080")
|
handler := NewCVHandler(tmplManager, "localhost:8080", nil)
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ func TestHome(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create handler
|
// Create handler
|
||||||
handler := NewCVHandler(tmplManager, "localhost:8080")
|
handler := NewCVHandler(tmplManager, "localhost:8080", nil)
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
@@ -95,7 +95,7 @@ func TestCVContent(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create handler
|
// Create handler
|
||||||
handler := NewCVHandler(tmplManager, "localhost:8080")
|
handler := NewCVHandler(tmplManager, "localhost:8080", nil)
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
@@ -162,7 +162,7 @@ func TestDefaultCVShortcut(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create handler
|
// Create handler
|
||||||
handler := NewCVHandler(tmplManager, "localhost:8080")
|
handler := NewCVHandler(tmplManager, "localhost:8080", nil)
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ func TestPlainText(t *testing.T) {
|
|||||||
t.Fatalf("Failed to create template manager: %v", err)
|
t.Fatalf("Failed to create template manager: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
handler := NewCVHandler(tmplManager, "localhost:8080")
|
handler := NewCVHandler(tmplManager, "localhost:8080", nil)
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
@@ -152,7 +152,7 @@ func TestPlainTextDownloadFilename(t *testing.T) {
|
|||||||
t.Fatalf("Failed to create template manager: %v", err)
|
t.Fatalf("Failed to create template manager: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
handler := NewCVHandler(tmplManager, "localhost:8080")
|
handler := NewCVHandler(tmplManager, "localhost:8080", nil)
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ func TestExportPDF_ParameterValidation(t *testing.T) {
|
|||||||
t.Fatalf("Failed to create template manager: %v", err)
|
t.Fatalf("Failed to create template manager: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
handler := NewCVHandler(tmpl, "localhost:1999")
|
handler := NewCVHandler(tmpl, "localhost:1999", nil)
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
@@ -157,7 +157,7 @@ func TestExportPDF_FilenameGeneration(t *testing.T) {
|
|||||||
t.Fatalf("Failed to create template manager: %v", err)
|
t.Fatalf("Failed to create template manager: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
handler := NewCVHandler(tmpl, "localhost:1999")
|
handler := NewCVHandler(tmpl, "localhost:1999", nil)
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
@@ -266,7 +266,7 @@ func TestExportPDF_DefaultParameters(t *testing.T) {
|
|||||||
t.Fatalf("Failed to create template manager: %v", err)
|
t.Fatalf("Failed to create template manager: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
handler := NewCVHandler(tmpl, "localhost:1999")
|
handler := NewCVHandler(tmpl, "localhost:1999", nil)
|
||||||
|
|
||||||
// Request with no parameters
|
// Request with no parameters
|
||||||
req := httptest.NewRequest(http.MethodGet, "/export/pdf", nil)
|
req := httptest.NewRequest(http.MethodGet, "/export/pdf", nil)
|
||||||
@@ -298,7 +298,7 @@ func TestExportPDF_LongWithSkills(t *testing.T) {
|
|||||||
t.Fatalf("Failed to create template manager: %v", err)
|
t.Fatalf("Failed to create template manager: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
handler := NewCVHandler(tmpl, "localhost:1999")
|
handler := NewCVHandler(tmpl, "localhost:1999", nil)
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
@@ -449,7 +449,7 @@ func TestExportPDF_SkillsSidebarFeatures(t *testing.T) {
|
|||||||
t.Fatalf("Failed to create template manager: %v", err)
|
t.Fatalf("Failed to create template manager: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
handler := NewCVHandler(tmpl, "localhost:1999")
|
handler := NewCVHandler(tmpl, "localhost:1999", nil)
|
||||||
|
|
||||||
validVersions := []string{"clean", "with_skills"}
|
validVersions := []string{"clean", "with_skills"}
|
||||||
|
|
||||||
@@ -484,7 +484,7 @@ func TestExportPDF_SkillsSidebarFeatures(t *testing.T) {
|
|||||||
t.Fatalf("Failed to create template manager: %v", err)
|
t.Fatalf("Failed to create template manager: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
handler := NewCVHandler(tmpl, "localhost:1999")
|
handler := NewCVHandler(tmpl, "localhost:1999", nil)
|
||||||
|
|
||||||
modalTests := []struct {
|
modalTests := []struct {
|
||||||
name string
|
name string
|
||||||
@@ -604,7 +604,7 @@ func TestExportPDF_CompactFontsIntegration(t *testing.T) {
|
|||||||
t.Fatalf("Failed to create template manager: %v", err)
|
t.Fatalf("Failed to create template manager: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
handler := NewCVHandler(tmpl, "localhost:1999")
|
handler := NewCVHandler(tmpl, "localhost:1999", nil)
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import (
|
|||||||
"github.com/juanatsap/cv-site/internal/config"
|
"github.com/juanatsap/cv-site/internal/config"
|
||||||
"github.com/juanatsap/cv-site/internal/handlers"
|
"github.com/juanatsap/cv-site/internal/handlers"
|
||||||
"github.com/juanatsap/cv-site/internal/routes"
|
"github.com/juanatsap/cv-site/internal/routes"
|
||||||
|
"github.com/juanatsap/cv-site/internal/services"
|
||||||
"github.com/juanatsap/cv-site/internal/templates"
|
"github.com/juanatsap/cv-site/internal/templates"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -41,8 +42,19 @@ func main() {
|
|||||||
log.Fatalf("❌ Failed to initialize templates: %v", err)
|
log.Fatalf("❌ Failed to initialize templates: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize email service
|
||||||
|
emailService := services.NewEmailService(&services.EmailConfig{
|
||||||
|
SMTPHost: cfg.Email.SMTPHost,
|
||||||
|
SMTPPort: cfg.Email.SMTPPort,
|
||||||
|
SMTPUser: cfg.Email.SMTPUser,
|
||||||
|
SMTPPassword: cfg.Email.SMTPPassword,
|
||||||
|
FromEmail: cfg.Email.FromEmail,
|
||||||
|
ToEmail: cfg.Email.ContactEmail,
|
||||||
|
})
|
||||||
|
log.Printf("📧 Email service configured (SMTP: %s:%s)", cfg.Email.SMTPHost, cfg.Email.SMTPPort)
|
||||||
|
|
||||||
// Initialize handlers
|
// Initialize handlers
|
||||||
cvHandler := handlers.NewCVHandler(templateMgr, cfg.Address())
|
cvHandler := handlers.NewCVHandler(templateMgr, cfg.Address(), emailService)
|
||||||
healthHandler := handlers.NewHealthHandler(version)
|
healthHandler := handlers.NewHealthHandler(version)
|
||||||
|
|
||||||
// Setup routes and middleware
|
// Setup routes and middleware
|
||||||
|
|||||||
Reference in New Issue
Block a user