Refactor form validation into a new type

I was worried that i was repeating the AddInputErrors function for each
form, because they were basically the same.  I could create a Form type
and make all forms embed it, but i realized that with a separate
validator i would have cleaner validation functions and would not need
the Valid field in the form that i am using only for that method.
This commit is contained in:
jordi fita mas 2023-02-01 11:30:30 +01:00
parent ff5b76b4f5
commit b8b3d73e95
5 changed files with 86 additions and 83 deletions

View File

@ -2,6 +2,7 @@ package pkg
import (
"context"
"errors"
"net/http"
"net/mail"
"strings"
@ -25,19 +26,6 @@ func (field *InputField) FillValue(r *http.Request) {
field.Value = strings.TrimSpace(r.FormValue(field.Name))
}
func (field *InputField) Equals(other *InputField) bool {
return field.Value == other.Value
}
func (field *InputField) IsEmpty() bool {
return field.Value == ""
}
func (field *InputField) HasValidEmail() bool {
_, err := mail.ParseAddress(field.Value)
return err == nil
}
type SelectOption struct {
Value string
Label string
@ -86,3 +74,48 @@ func MustGetOptions(ctx context.Context, conn *Conn, sql string, args ...interfa
return options
}
type FormValidator struct {
Valid bool
}
func newFormValidator() *FormValidator {
return &FormValidator{true}
}
func (v *FormValidator) AllOK() bool {
return v.Valid
}
func (v *FormValidator) CheckRequiredInput(field *InputField, message string) bool {
return v.checkInput(field, field.Value != "", message)
}
func (v *FormValidator) CheckValidEmailInput(field *InputField, message string) bool {
_, err := mail.ParseAddress(field.Value)
return v.checkInput(field, err == nil, message)
}
func (v *FormValidator) CheckPasswordConfirmation(password *InputField, confirm *InputField, message string) bool {
return v.checkInput(confirm, password.Value == confirm.Value, message)
}
func (v *FormValidator) CheckValidSelectOption(field *SelectField, message string) bool {
return v.checkSelect(field, field.HasValidOption(), message)
}
func (v *FormValidator) checkInput(field *InputField, ok bool, message string) bool {
if !ok {
field.Errors = append(field.Errors, errors.New(message))
v.Valid = false
}
return ok
}
func (v *FormValidator) checkSelect(field *SelectField, ok bool, message string) bool {
if !ok {
field.Errors = append(field.Errors, errors.New(message))
v.Valid = false
}
return ok
}

View File

@ -23,7 +23,6 @@ type loginForm struct {
Errors []error
Email *InputField
Password *InputField
Valid bool
}
func newLoginForm(locale *Locale) *loginForm {
@ -63,21 +62,12 @@ func (form *loginForm) Parse(r *http.Request) error {
}
func (form *loginForm) Validate() bool {
form.Valid = true
if form.Email.IsEmpty() {
form.AppendInputError(form.Email, errors.New(gettext("Email can not be empty.", form.locale)))
} else if !form.Email.HasValidEmail() {
form.AppendInputError(form.Email, errors.New(gettext("This value is not a valid email. It should be like name@domain.com.", form.locale)))
validator := newFormValidator()
if validator.CheckRequiredInput(form.Email, gettext("Email can not be empty.", form.locale)) {
validator.CheckValidEmailInput(form.Email, gettext("This value is not a valid email. It should be like name@domain.com.", form.locale))
}
if form.Password.IsEmpty() {
form.AppendInputError(form.Password, errors.New(gettext("Password can not be empty.", form.locale)))
}
return form.Valid
}
func (form *loginForm) AppendInputError(field *InputField, err error) {
field.Errors = append(field.Errors, err)
form.Valid = false
validator.CheckRequiredInput(form.Password, gettext("Password can not be empty.", form.locale))
return validator.AllOK()
}
func LoginHandler() http.Handler {

View File

@ -2,7 +2,6 @@ package pkg
import (
"context"
"errors"
"net/http"
)
@ -18,7 +17,6 @@ type profileForm struct {
Password *InputField
PasswordConfirm *InputField
Language *SelectField
Valid bool
}
func newProfileForm(ctx context.Context, conn *Conn, locale *Locale) *profileForm {
@ -69,32 +67,14 @@ func (form *profileForm) Parse(r *http.Request) error {
}
func (form *profileForm) Validate() bool {
form.Valid = true
if form.Email.IsEmpty() {
form.AppendInputError(form.Email, errors.New(gettext("Email can not be empty.", form.locale)))
} else if !form.Email.HasValidEmail() {
form.AppendInputError(form.Email, errors.New(gettext("This value is not a valid email. It should be like name@domain.com.", form.locale)))
validator := newFormValidator()
if validator.CheckRequiredInput(form.Email, gettext("Email can not be empty.", form.locale)) {
validator.CheckValidEmailInput(form.Email, gettext("This value is not a valid email. It should be like name@domain.com.", form.locale))
}
if form.Name.IsEmpty() {
form.AppendInputError(form.Name, errors.New(gettext("Name can not be empty.", form.locale)))
}
if !form.PasswordConfirm.Equals(form.Password) {
form.AppendInputError(form.PasswordConfirm, errors.New(gettext("Confirmation does not match password.", form.locale)))
}
if !form.Language.HasValidOption() {
form.AppendSelectError(form.Language, errors.New(gettext("Selected language is not valid.", form.locale)))
}
return form.Valid
}
func (form *profileForm) AppendInputError(field *InputField, err error) {
field.Errors = append(field.Errors, err)
form.Valid = false
}
func (form *profileForm) AppendSelectError(field *SelectField, err error) {
field.Errors = append(field.Errors, err)
form.Valid = false
validator.CheckRequiredInput(form.Name, gettext("Name can not be empty.", form.locale))
validator.CheckPasswordConfirmation(form.Password, form.PasswordConfirm, gettext("Confirmation does not match password.", form.locale))
validator.CheckValidSelectOption(form.Language, gettext("Selected language is not valid.", form.locale))
return validator.AllOK()
}
func ProfileHandler() http.Handler {

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: numerus\n"
"Report-Msgid-Bugs-To: jordi@tandem.blog\n"
"POT-Creation-Date: 2023-02-01 10:52+0100\n"
"POT-Creation-Date: 2023-02-01 11:26+0100\n"
"PO-Revision-Date: 2023-01-18 17:08+0100\n"
"Last-Translator: jordi fita mas <jordi@tandem.blog>\n"
"Language-Team: Catalan <ca@dodds.net>\n"
@ -142,7 +142,7 @@ msgid "Phone"
msgstr "Telèfon"
#: web/template/tax-details.gohtml:27 web/template/contacts-new.gohtml:27
#: pkg/login.go:34 pkg/profile.go:37
#: pkg/login.go:33 pkg/profile.go:35
msgctxt "input"
msgid "Email"
msgstr "Correu-e"
@ -221,56 +221,56 @@ msgctxt "title"
msgid "New Contact"
msgstr "Nou contacte"
#: pkg/login.go:45 pkg/profile.go:43
#: pkg/login.go:44 pkg/profile.go:41
msgctxt "input"
msgid "Password"
msgstr "Contrasenya"
#: pkg/login.go:68 pkg/profile.go:74
#: pkg/login.go:66 pkg/profile.go:71
msgid "Email can not be empty."
msgstr "No podeu deixar el correu-e en blanc."
#: pkg/login.go:70 pkg/profile.go:76
#: pkg/login.go:67 pkg/profile.go:72
msgid "This value is not a valid email. It should be like name@domain.com."
msgstr "Aquest valor no és un correu-e vàlid. Hauria de ser similar a nom@domini.cat."
#: pkg/login.go:73
#: pkg/login.go:69
msgid "Password can not be empty."
msgstr "No podeu deixar la contrasenya en blanc."
#: pkg/login.go:105
#: pkg/login.go:95
msgid "Invalid user or password."
msgstr "Nom dusuari o contrasenya incorrectes."
#: pkg/profile.go:25
#: pkg/profile.go:23
msgctxt "language option"
msgid "Automatic"
msgstr "Automàtic"
#: pkg/profile.go:31
#: pkg/profile.go:29
msgctxt "input"
msgid "User name"
msgstr "Nom dusuari"
#: pkg/profile.go:48
#: pkg/profile.go:46
msgctxt "input"
msgid "Password Confirmation"
msgstr "Confirmació contrasenya"
#: pkg/profile.go:53
#: pkg/profile.go:51
msgctxt "input"
msgid "Language"
msgstr "Idioma"
#: pkg/profile.go:79
#: pkg/profile.go:74
msgid "Name can not be empty."
msgstr "No podeu deixar el nom en blanc."
#: pkg/profile.go:82
#: pkg/profile.go:75
msgid "Confirmation does not match password."
msgstr "La confirmació no és igual a la contrasenya."
#: pkg/profile.go:85
#: pkg/profile.go:76
msgid "Selected language is not valid."
msgstr "Heu seleccionat un idioma que no és vàlid."

View File

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: numerus\n"
"Report-Msgid-Bugs-To: jordi@tandem.blog\n"
"POT-Creation-Date: 2023-02-01 10:52+0100\n"
"POT-Creation-Date: 2023-02-01 11:26+0100\n"
"PO-Revision-Date: 2023-01-18 17:45+0100\n"
"Last-Translator: jordi fita mas <jordi@tandem.blog>\n"
"Language-Team: Spanish <es@tp.org.es>\n"
@ -142,7 +142,7 @@ msgid "Phone"
msgstr "Teléfono"
#: web/template/tax-details.gohtml:27 web/template/contacts-new.gohtml:27
#: pkg/login.go:34 pkg/profile.go:37
#: pkg/login.go:33 pkg/profile.go:35
msgctxt "input"
msgid "Email"
msgstr "Correo-e"
@ -221,56 +221,56 @@ msgctxt "title"
msgid "New Contact"
msgstr "Nuevo contacto"
#: pkg/login.go:45 pkg/profile.go:43
#: pkg/login.go:44 pkg/profile.go:41
msgctxt "input"
msgid "Password"
msgstr "Contraseña"
#: pkg/login.go:68 pkg/profile.go:74
#: pkg/login.go:66 pkg/profile.go:71
msgid "Email can not be empty."
msgstr "No podéis dejar el correo-e en blanco."
#: pkg/login.go:70 pkg/profile.go:76
#: pkg/login.go:67 pkg/profile.go:72
msgid "This value is not a valid email. It should be like name@domain.com."
msgstr "Este valor no es un correo-e válido. Tiene que ser parecido a nombre@dominio.es."
#: pkg/login.go:73
#: pkg/login.go:69
msgid "Password can not be empty."
msgstr "No podéis dejar la contaseña en blanco."
#: pkg/login.go:105
#: pkg/login.go:95
msgid "Invalid user or password."
msgstr "Nombre de usuario o contraseña inválido."
#: pkg/profile.go:25
#: pkg/profile.go:23
msgctxt "language option"
msgid "Automatic"
msgstr "Automático"
#: pkg/profile.go:31
#: pkg/profile.go:29
msgctxt "input"
msgid "User name"
msgstr "Nombre de usuario"
#: pkg/profile.go:48
#: pkg/profile.go:46
msgctxt "input"
msgid "Password Confirmation"
msgstr "Confirmación contrasenya"
#: pkg/profile.go:53
#: pkg/profile.go:51
msgctxt "input"
msgid "Language"
msgstr "Idioma"
#: pkg/profile.go:79
#: pkg/profile.go:74
msgid "Name can not be empty."
msgstr "No podéis dejar el nombre en blanco."
#: pkg/profile.go:82
#: pkg/profile.go:75
msgid "Confirmation does not match password."
msgstr "La confirmación no corresponde con la contraseña."
#: pkg/profile.go:85
#: pkg/profile.go:76
msgid "Selected language is not valid."
msgstr "Habéis escogido un idioma que no es válido."