Use compose.dev.yaml and compose.prod.yaml with fixed Go cache mounts, block sudo make dev, build Air outside app/tmp for rootless Docker, soften English spam checks, and simplify contact error copy. Co-authored-by: Cursor <cursoragent@cursor.com>
91 lines
2.1 KiB
Go
91 lines
2.1 KiB
Go
package contact
|
|
|
|
import (
|
|
"errors"
|
|
"net/mail"
|
|
"strings"
|
|
"unicode/utf8"
|
|
|
|
"technical.kiwi/website/internal/contactcheck"
|
|
)
|
|
|
|
const (
|
|
maxNameLen = 120
|
|
maxEmailLen = 254
|
|
maxMessageLen = 8000
|
|
minMessageLen = 20
|
|
)
|
|
|
|
// Submission is validated contact form input.
|
|
type Submission struct {
|
|
Name string
|
|
Email string
|
|
Message string
|
|
}
|
|
|
|
// Errors maps field names to user-facing messages.
|
|
type Errors map[string]string
|
|
|
|
func (e Errors) Any() bool {
|
|
return len(e) > 0
|
|
}
|
|
|
|
// Parse reads and validates a contact form POST.
|
|
func Parse(name, email, message string) (Submission, Errors) {
|
|
errs := make(Errors)
|
|
|
|
name = strings.TrimSpace(name)
|
|
email = strings.TrimSpace(email)
|
|
message = strings.TrimSpace(message)
|
|
|
|
if name == "" {
|
|
errs["name"] = "Name is required."
|
|
} else if utf8.RuneCountInString(name) > maxNameLen {
|
|
errs["name"] = "Name is too long."
|
|
}
|
|
|
|
if email == "" {
|
|
errs["email"] = "Email is required."
|
|
} else if utf8.RuneCountInString(email) > maxEmailLen {
|
|
errs["email"] = "Email is too long."
|
|
} else {
|
|
addr, err := mail.ParseAddress(email)
|
|
if err != nil {
|
|
errs["email"] = "Enter a valid email address."
|
|
} else {
|
|
email = addr.Address
|
|
}
|
|
}
|
|
|
|
if message == "" {
|
|
errs["message"] = "Message is required."
|
|
} else if utf8.RuneCountInString(message) < minMessageLen {
|
|
errs["message"] = "Message must be at least 20 characters."
|
|
} else if utf8.RuneCountInString(message) > maxMessageLen {
|
|
errs["message"] = "Message is too long."
|
|
}
|
|
|
|
if !errs.Any() {
|
|
if err := contactcheck.ValidateEnglish(name, message); err != nil {
|
|
switch {
|
|
case errors.Is(err, contactcheck.ErrTooShort):
|
|
errs["message"] = "Message must be at least 20 characters."
|
|
case errors.Is(err, contactcheck.ErrTooLong):
|
|
errs["message"] = "Message is too long."
|
|
case errors.Is(err, contactcheck.ErrName):
|
|
errs["name"] = "Name is too long."
|
|
case errors.Is(err, contactcheck.ErrNotEnglish):
|
|
errs["message"] = "Please write your message in English."
|
|
default:
|
|
errs["message"] = "Could not accept this message."
|
|
}
|
|
}
|
|
}
|
|
|
|
if errs.Any() {
|
|
return Submission{}, errs
|
|
}
|
|
|
|
return Submission{Name: name, Email: email, Message: message}, nil
|
|
}
|