Server Side form validation 3

This commit is contained in:
Muyao CHEN 2024-07-01 13:37:03 +02:00
parent 8be6ba7119
commit 87dfd26268
3 changed files with 46 additions and 10 deletions

View File

@ -1,8 +1,10 @@
package forms package forms
import ( import (
"fmt"
"net/http" "net/http"
"net/url" "net/url"
"strings"
) )
// Form creates a custom form struct, embeds a url.Values object // Form creates a custom form struct, embeds a url.Values object
@ -19,17 +21,33 @@ func New(data url.Values) *Form {
} }
} }
// Required checks required fields
func (f *Form) Required(fields ...string) {
for _, field := range fields {
value := f.Get(field)
if strings.TrimSpace(value) == "" {
f.Errors.Add(field, "This field cannot be blank")
}
}
}
// Has checks if form field is in post and not emtpy // Has checks if form field is in post and not emtpy
func (f *Form) Has(field string, r *http.Request) bool { func (f *Form) Has(field string, r *http.Request) bool {
x := r.Form.Get(field) x := r.Form.Get(field)
if x == "" { return x != ""
f.Errors.Add(field, "This field cannot be blank")
return false
}
return true
} }
// Valid returns true if there are no errors, otherwise false // Valid returns true if there are no errors, otherwise false
func (f *Form) Valid() bool { func (f *Form) Valid() bool {
return len(f.Errors) == 0 return len(f.Errors) == 0
} }
// MinLength checks for string minimum length
func (f *Form) MinLength(field string, length int, r *http.Request) bool {
value := r.Form.Get(field)
if len(value) < length {
f.Errors.Add(field, fmt.Sprintf("This field must have at least %d letters", length))
return false
}
return true
}

View File

@ -69,8 +69,16 @@ func (m *Repository) Majors(w http.ResponseWriter, r *http.Request) {
// MakeReservation is the make reservation page handler // MakeReservation is the make reservation page handler
func (m *Repository) MakeReservation(w http.ResponseWriter, r *http.Request) { func (m *Repository) MakeReservation(w http.ResponseWriter, r *http.Request) {
// For the first time render emptyReservation so that this object is
// filled with the info when sent back.
var emptyReservation models.Reservation
data := make(map[string]interface{})
data["reservation"] = emptyReservation
render.RenderTemplate(w, r, "make-reservation.page.tmpl", &models.TemplateData{ render.RenderTemplate(w, r, "make-reservation.page.tmpl", &models.TemplateData{
Form: forms.New(nil), Form: forms.New(nil),
Data: data,
}) })
} }
@ -91,7 +99,8 @@ func (m *Repository) PostMakeReservation(w http.ResponseWriter, r *http.Request)
form := forms.New(r.PostForm) form := forms.New(r.PostForm)
form.Has("first_name", r) form.Required("first_name", "last_name", "email")
form.MinLength("first_name", 2, r)
if !form.Valid() { if !form.Valid() {
data := make(map[string]interface{}) data := make(map[string]interface{})

View File

@ -5,6 +5,7 @@
<div class="col"> <div class="col">
<h1 class="text-center mt-3">Make reservation</h1> <h1 class="text-center mt-3">Make reservation</h1>
{{$res := index .Data "reservation"}}
<!-- <form method="post" action="" class="needs-validation" novalidate> --> <!-- <form method="post" action="" class="needs-validation" novalidate> -->
<form method="post" action="" class="" novalidate> <form method="post" action="" class="" novalidate>
<input type="hidden" name="csrf_token" value="{{.CSRFToken}}"> <input type="hidden" name="csrf_token" value="{{.CSRFToken}}">
@ -15,19 +16,27 @@
<label class="text-danger">{{.}}</label> <label class="text-danger">{{.}}</label>
{{end}} {{end}}
<input type="text" name="first_name" id="first_name" class="form-control {{with .Form.Errors.Get "first_name"}} is-invalid {{end}}" <input type="text" name="first_name" id="first_name" class="form-control {{with .Form.Errors.Get "first_name"}} is-invalid {{end}}"
required autocomplete="off"> value="{{$res.FirstName}}" required autocomplete="off">
</div> </div>
<div class="form-group mt-5"> <div class="form-group mt-5">
<label for="last_name">Last name:</label> <label for="last_name">Last name:</label>
<input type="text" name="last_name" id="last_name" class="form-control" required autocomplete="off"> {{with .Form.Errors.Get "last_name"}}
<label class="text-danger">{{.}}</label>
{{end}}
<input type="text" name="last_name" id="last_name" class="form-control {{with .Form.Errors.Get "last_name"}} is-invalid {{end}}"
value="{{$res.LastName}}" required autocomplete="off">
</div> </div>
<div class="form-group mt-5"> <div class="form-group mt-5">
<label for="email">Email:</label> <label for="email">Email:</label>
<input type="email" name="email" id="email" class="form-control" required autocomplete="off"> {{with .Form.Errors.Get "email"}}
<label class="text-danger">{{.}}</label>
{{end}}
<input type="email" name="email" id="email" class="form-control {{with .Form.Errors.Get "email"}} is-invalid {{end}}"
value="{{$res.Email}}" required autocomplete="off">
</div> </div>
<div class="form-group mt-5"> <div class="form-group mt-5">
<label for="phone">Phone number:</label> <label for="phone">Phone number:</label>
<input type="text" name="phone" id="phone" class="form-control" required autocomplete="off"> <input type="text" name="phone" id="phone" class="form-control" value="{{$res.Phone}}" autocomplete="off">
</div> </div>
<hr> <hr>