feat: Add plain text CV endpoint and contact form with security
Plain text endpoint: - Add /text route for plain text CV (for curl/AI crawlers) - Use k3a/html2text library for HTML-to-text conversion - Add Plain Text button to hamburger menu with UI translations Contact form feature: - Add ContactHandler with proper email service integration - Add CSRF protection middleware - Add rate limiting (5 submissions/hour per IP) - Add honeypot and timing-based bot protection - Add input validation with detailed error messages - Add security logging middleware - Add browser-only middleware for API protection Code quality: - Fix all golangci-lint errcheck warnings for w.Write calls - Remove duplicate getClientIP functions - Wire up ContactHandler in routes.Setup
This commit is contained in:
+35
-1
@@ -159,6 +159,34 @@
|
||||
"viewSource": "View Project in Github",
|
||||
"viewSourceSubtext": "Want to know how it's built?"
|
||||
},
|
||||
"contactModal": {
|
||||
"title": "Get in Touch",
|
||||
"subtitle": "Let's connect!",
|
||||
"description": "Have a question or interested in working together? Fill out the form below and I'll get back to you as soon as possible.",
|
||||
"close": "Close",
|
||||
"form": {
|
||||
"email": "Email",
|
||||
"emailPlaceholder": "your.email@example.com",
|
||||
"name": "Name",
|
||||
"namePlaceholder": "Your name",
|
||||
"company": "Company",
|
||||
"companyPlaceholder": "Company",
|
||||
"subject": "Subject",
|
||||
"subjectPlaceholder": "Subject",
|
||||
"message": "Message",
|
||||
"messagePlaceholder": "Your message...",
|
||||
"submit": "Send Message",
|
||||
"sending": "Sending...",
|
||||
"note": "* Required fields"
|
||||
},
|
||||
"success": {
|
||||
"title": "Message Sent!",
|
||||
"message": "Thank you for your message. I'll get back to you soon."
|
||||
},
|
||||
"error": {
|
||||
"title": "Error"
|
||||
}
|
||||
},
|
||||
"widgets": {
|
||||
"backToTop": {
|
||||
"ariaLabel": "Back to top",
|
||||
@@ -196,9 +224,15 @@
|
||||
"title": "Preparing PDF",
|
||||
"closeLabel": "Close notification"
|
||||
},
|
||||
"contact": {
|
||||
"ariaLabel": "Contact me",
|
||||
"tooltip": "Contact me"
|
||||
},
|
||||
"actionButtons": {
|
||||
"downloadPdf": "Download as PDF",
|
||||
"printFriendly": "Print Friendly"
|
||||
"printFriendly": "Print Friendly",
|
||||
"plainText": "Plain Text",
|
||||
"contact": "Contact"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+35
-1
@@ -159,6 +159,34 @@
|
||||
"viewSource": "Ver proyecto en Github",
|
||||
"viewSourceSubtext": "¿Quieres saber cómo está hecho?"
|
||||
},
|
||||
"contactModal": {
|
||||
"title": "Ponerse en contacto",
|
||||
"subtitle": "¡Conectemos!",
|
||||
"description": "¿Tienes alguna pregunta o estás interesado en trabajar juntos? Rellena el formulario a continuación y me pondré en contacto contigo lo antes posible.",
|
||||
"close": "Cerrar",
|
||||
"form": {
|
||||
"email": "Correo electrónico",
|
||||
"emailPlaceholder": "tu.email@ejemplo.com",
|
||||
"name": "Nombre",
|
||||
"namePlaceholder": "Tu nombre",
|
||||
"company": "Empresa",
|
||||
"companyPlaceholder": "Empresa",
|
||||
"subject": "Asunto",
|
||||
"subjectPlaceholder": "Asunto",
|
||||
"message": "Mensaje",
|
||||
"messagePlaceholder": "Tu mensaje...",
|
||||
"submit": "Enviar mensaje",
|
||||
"sending": "Enviando...",
|
||||
"note": "* Campos obligatorios"
|
||||
},
|
||||
"success": {
|
||||
"title": "¡Mensaje enviado!",
|
||||
"message": "Gracias por tu mensaje. Me pondré en contacto contigo pronto."
|
||||
},
|
||||
"error": {
|
||||
"title": "Error"
|
||||
}
|
||||
},
|
||||
"widgets": {
|
||||
"backToTop": {
|
||||
"ariaLabel": "Volver arriba",
|
||||
@@ -196,9 +224,15 @@
|
||||
"title": "Preparando PDF",
|
||||
"closeLabel": "Cerrar notificación"
|
||||
},
|
||||
"contact": {
|
||||
"ariaLabel": "Contáctame",
|
||||
"tooltip": "Contáctame"
|
||||
},
|
||||
"actionButtons": {
|
||||
"downloadPdf": "Descargar como PDF",
|
||||
"printFriendly": "Imprimir amigable"
|
||||
"printFriendly": "Imprimir amigable",
|
||||
"plainText": "Texto Plano",
|
||||
"contact": "Contacto"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user