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:
parent
ff5b76b4f5
commit
b8b3d73e95
59
pkg/form.go
59
pkg/form.go
|
@ -2,6 +2,7 @@ package pkg
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/mail"
|
"net/mail"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -25,19 +26,6 @@ func (field *InputField) FillValue(r *http.Request) {
|
||||||
field.Value = strings.TrimSpace(r.FormValue(field.Name))
|
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 {
|
type SelectOption struct {
|
||||||
Value string
|
Value string
|
||||||
Label string
|
Label string
|
||||||
|
@ -86,3 +74,48 @@ func MustGetOptions(ctx context.Context, conn *Conn, sql string, args ...interfa
|
||||||
|
|
||||||
return options
|
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
|
||||||
|
}
|
||||||
|
|
20
pkg/login.go
20
pkg/login.go
|
@ -23,7 +23,6 @@ type loginForm struct {
|
||||||
Errors []error
|
Errors []error
|
||||||
Email *InputField
|
Email *InputField
|
||||||
Password *InputField
|
Password *InputField
|
||||||
Valid bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func newLoginForm(locale *Locale) *loginForm {
|
func newLoginForm(locale *Locale) *loginForm {
|
||||||
|
@ -63,21 +62,12 @@ func (form *loginForm) Parse(r *http.Request) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (form *loginForm) Validate() bool {
|
func (form *loginForm) Validate() bool {
|
||||||
form.Valid = true
|
validator := newFormValidator()
|
||||||
if form.Email.IsEmpty() {
|
if validator.CheckRequiredInput(form.Email, gettext("Email can not be empty.", form.locale)) {
|
||||||
form.AppendInputError(form.Email, errors.New(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))
|
||||||
} 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)))
|
|
||||||
}
|
}
|
||||||
if form.Password.IsEmpty() {
|
validator.CheckRequiredInput(form.Password, gettext("Password can not be empty.", form.locale))
|
||||||
form.AppendInputError(form.Password, errors.New(gettext("Password can not be empty.", form.locale)))
|
return validator.AllOK()
|
||||||
}
|
|
||||||
return form.Valid
|
|
||||||
}
|
|
||||||
|
|
||||||
func (form *loginForm) AppendInputError(field *InputField, err error) {
|
|
||||||
field.Errors = append(field.Errors, err)
|
|
||||||
form.Valid = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func LoginHandler() http.Handler {
|
func LoginHandler() http.Handler {
|
||||||
|
|
|
@ -2,7 +2,6 @@ package pkg
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -18,7 +17,6 @@ type profileForm struct {
|
||||||
Password *InputField
|
Password *InputField
|
||||||
PasswordConfirm *InputField
|
PasswordConfirm *InputField
|
||||||
Language *SelectField
|
Language *SelectField
|
||||||
Valid bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func newProfileForm(ctx context.Context, conn *Conn, locale *Locale) *profileForm {
|
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 {
|
func (form *profileForm) Validate() bool {
|
||||||
form.Valid = true
|
validator := newFormValidator()
|
||||||
if form.Email.IsEmpty() {
|
if validator.CheckRequiredInput(form.Email, gettext("Email can not be empty.", form.locale)) {
|
||||||
form.AppendInputError(form.Email, errors.New(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))
|
||||||
} 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)))
|
|
||||||
}
|
}
|
||||||
if form.Name.IsEmpty() {
|
validator.CheckRequiredInput(form.Name, gettext("Name can not be empty.", form.locale))
|
||||||
form.AppendInputError(form.Name, errors.New(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))
|
||||||
if !form.PasswordConfirm.Equals(form.Password) {
|
return validator.AllOK()
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func ProfileHandler() http.Handler {
|
func ProfileHandler() http.Handler {
|
||||||
|
|
28
po/ca.po
28
po/ca.po
|
@ -8,7 +8,7 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: numerus\n"
|
"Project-Id-Version: numerus\n"
|
||||||
"Report-Msgid-Bugs-To: jordi@tandem.blog\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"
|
"PO-Revision-Date: 2023-01-18 17:08+0100\n"
|
||||||
"Last-Translator: jordi fita mas <jordi@tandem.blog>\n"
|
"Last-Translator: jordi fita mas <jordi@tandem.blog>\n"
|
||||||
"Language-Team: Catalan <ca@dodds.net>\n"
|
"Language-Team: Catalan <ca@dodds.net>\n"
|
||||||
|
@ -142,7 +142,7 @@ msgid "Phone"
|
||||||
msgstr "Telèfon"
|
msgstr "Telèfon"
|
||||||
|
|
||||||
#: web/template/tax-details.gohtml:27 web/template/contacts-new.gohtml:27
|
#: 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"
|
msgctxt "input"
|
||||||
msgid "Email"
|
msgid "Email"
|
||||||
msgstr "Correu-e"
|
msgstr "Correu-e"
|
||||||
|
@ -221,56 +221,56 @@ msgctxt "title"
|
||||||
msgid "New Contact"
|
msgid "New Contact"
|
||||||
msgstr "Nou contacte"
|
msgstr "Nou contacte"
|
||||||
|
|
||||||
#: pkg/login.go:45 pkg/profile.go:43
|
#: pkg/login.go:44 pkg/profile.go:41
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Password"
|
msgid "Password"
|
||||||
msgstr "Contrasenya"
|
msgstr "Contrasenya"
|
||||||
|
|
||||||
#: pkg/login.go:68 pkg/profile.go:74
|
#: pkg/login.go:66 pkg/profile.go:71
|
||||||
msgid "Email can not be empty."
|
msgid "Email can not be empty."
|
||||||
msgstr "No podeu deixar el correu-e en blanc."
|
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."
|
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."
|
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."
|
msgid "Password can not be empty."
|
||||||
msgstr "No podeu deixar la contrasenya en blanc."
|
msgstr "No podeu deixar la contrasenya en blanc."
|
||||||
|
|
||||||
#: pkg/login.go:105
|
#: pkg/login.go:95
|
||||||
msgid "Invalid user or password."
|
msgid "Invalid user or password."
|
||||||
msgstr "Nom d’usuari o contrasenya incorrectes."
|
msgstr "Nom d’usuari o contrasenya incorrectes."
|
||||||
|
|
||||||
#: pkg/profile.go:25
|
#: pkg/profile.go:23
|
||||||
msgctxt "language option"
|
msgctxt "language option"
|
||||||
msgid "Automatic"
|
msgid "Automatic"
|
||||||
msgstr "Automàtic"
|
msgstr "Automàtic"
|
||||||
|
|
||||||
#: pkg/profile.go:31
|
#: pkg/profile.go:29
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "User name"
|
msgid "User name"
|
||||||
msgstr "Nom d’usuari"
|
msgstr "Nom d’usuari"
|
||||||
|
|
||||||
#: pkg/profile.go:48
|
#: pkg/profile.go:46
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Password Confirmation"
|
msgid "Password Confirmation"
|
||||||
msgstr "Confirmació contrasenya"
|
msgstr "Confirmació contrasenya"
|
||||||
|
|
||||||
#: pkg/profile.go:53
|
#: pkg/profile.go:51
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Language"
|
msgid "Language"
|
||||||
msgstr "Idioma"
|
msgstr "Idioma"
|
||||||
|
|
||||||
#: pkg/profile.go:79
|
#: pkg/profile.go:74
|
||||||
msgid "Name can not be empty."
|
msgid "Name can not be empty."
|
||||||
msgstr "No podeu deixar el nom en blanc."
|
msgstr "No podeu deixar el nom en blanc."
|
||||||
|
|
||||||
#: pkg/profile.go:82
|
#: pkg/profile.go:75
|
||||||
msgid "Confirmation does not match password."
|
msgid "Confirmation does not match password."
|
||||||
msgstr "La confirmació no és igual a la contrasenya."
|
msgstr "La confirmació no és igual a la contrasenya."
|
||||||
|
|
||||||
#: pkg/profile.go:85
|
#: pkg/profile.go:76
|
||||||
msgid "Selected language is not valid."
|
msgid "Selected language is not valid."
|
||||||
msgstr "Heu seleccionat un idioma que no és vàlid."
|
msgstr "Heu seleccionat un idioma que no és vàlid."
|
||||||
|
|
||||||
|
|
28
po/es.po
28
po/es.po
|
@ -7,7 +7,7 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: numerus\n"
|
"Project-Id-Version: numerus\n"
|
||||||
"Report-Msgid-Bugs-To: jordi@tandem.blog\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"
|
"PO-Revision-Date: 2023-01-18 17:45+0100\n"
|
||||||
"Last-Translator: jordi fita mas <jordi@tandem.blog>\n"
|
"Last-Translator: jordi fita mas <jordi@tandem.blog>\n"
|
||||||
"Language-Team: Spanish <es@tp.org.es>\n"
|
"Language-Team: Spanish <es@tp.org.es>\n"
|
||||||
|
@ -142,7 +142,7 @@ msgid "Phone"
|
||||||
msgstr "Teléfono"
|
msgstr "Teléfono"
|
||||||
|
|
||||||
#: web/template/tax-details.gohtml:27 web/template/contacts-new.gohtml:27
|
#: 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"
|
msgctxt "input"
|
||||||
msgid "Email"
|
msgid "Email"
|
||||||
msgstr "Correo-e"
|
msgstr "Correo-e"
|
||||||
|
@ -221,56 +221,56 @@ msgctxt "title"
|
||||||
msgid "New Contact"
|
msgid "New Contact"
|
||||||
msgstr "Nuevo contacto"
|
msgstr "Nuevo contacto"
|
||||||
|
|
||||||
#: pkg/login.go:45 pkg/profile.go:43
|
#: pkg/login.go:44 pkg/profile.go:41
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Password"
|
msgid "Password"
|
||||||
msgstr "Contraseña"
|
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."
|
msgid "Email can not be empty."
|
||||||
msgstr "No podéis dejar el correo-e en blanco."
|
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."
|
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."
|
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."
|
msgid "Password can not be empty."
|
||||||
msgstr "No podéis dejar la contaseña en blanco."
|
msgstr "No podéis dejar la contaseña en blanco."
|
||||||
|
|
||||||
#: pkg/login.go:105
|
#: pkg/login.go:95
|
||||||
msgid "Invalid user or password."
|
msgid "Invalid user or password."
|
||||||
msgstr "Nombre de usuario o contraseña inválido."
|
msgstr "Nombre de usuario o contraseña inválido."
|
||||||
|
|
||||||
#: pkg/profile.go:25
|
#: pkg/profile.go:23
|
||||||
msgctxt "language option"
|
msgctxt "language option"
|
||||||
msgid "Automatic"
|
msgid "Automatic"
|
||||||
msgstr "Automático"
|
msgstr "Automático"
|
||||||
|
|
||||||
#: pkg/profile.go:31
|
#: pkg/profile.go:29
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "User name"
|
msgid "User name"
|
||||||
msgstr "Nombre de usuario"
|
msgstr "Nombre de usuario"
|
||||||
|
|
||||||
#: pkg/profile.go:48
|
#: pkg/profile.go:46
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Password Confirmation"
|
msgid "Password Confirmation"
|
||||||
msgstr "Confirmación contrasenya"
|
msgstr "Confirmación contrasenya"
|
||||||
|
|
||||||
#: pkg/profile.go:53
|
#: pkg/profile.go:51
|
||||||
msgctxt "input"
|
msgctxt "input"
|
||||||
msgid "Language"
|
msgid "Language"
|
||||||
msgstr "Idioma"
|
msgstr "Idioma"
|
||||||
|
|
||||||
#: pkg/profile.go:79
|
#: pkg/profile.go:74
|
||||||
msgid "Name can not be empty."
|
msgid "Name can not be empty."
|
||||||
msgstr "No podéis dejar el nombre en blanco."
|
msgstr "No podéis dejar el nombre en blanco."
|
||||||
|
|
||||||
#: pkg/profile.go:82
|
#: pkg/profile.go:75
|
||||||
msgid "Confirmation does not match password."
|
msgid "Confirmation does not match password."
|
||||||
msgstr "La confirmación no corresponde con la contraseña."
|
msgstr "La confirmación no corresponde con la contraseña."
|
||||||
|
|
||||||
#: pkg/profile.go:85
|
#: pkg/profile.go:76
|
||||||
msgid "Selected language is not valid."
|
msgid "Selected language is not valid."
|
||||||
msgstr "Habéis escogido un idioma que no es válido."
|
msgstr "Habéis escogido un idioma que no es válido."
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue