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"] = "This site only accepts messages written in English. If your message is in English, try adding a few more clear sentences so we can detect the language reliably." default: errs["message"] = "Could not accept this message." } } } if errs.Any() { return Submission{}, errs } return Submission{Name: name, Email: email, Message: message}, nil }