158 lines
3.9 KiB
Go
158 lines
3.9 KiB
Go
package validation
|
|
|
|
import (
|
|
"net/http"
|
|
"regexp"
|
|
"strings"
|
|
"time"
|
|
|
|
"git.haelnorr.com/h/golib/hws"
|
|
"git.haelnorr.com/h/oslstats/internal/notify"
|
|
"git.haelnorr.com/h/oslstats/internal/throw"
|
|
"git.haelnorr.com/h/timefmt"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
// FormGetter wraps http.Request to get form values
|
|
type FormGetter struct {
|
|
r *http.Request
|
|
checks []*ValidationRule
|
|
}
|
|
|
|
func NewFormGetter(r *http.Request) *FormGetter {
|
|
return &FormGetter{r: r, checks: []*ValidationRule{}}
|
|
}
|
|
|
|
func (f *FormGetter) Get(key string) string {
|
|
return f.r.FormValue(key)
|
|
}
|
|
|
|
func (f *FormGetter) GetList(key string) []string {
|
|
if f.r.Form == nil {
|
|
return nil
|
|
}
|
|
values, ok := f.r.Form[key]
|
|
if !ok || len(values) == 0 {
|
|
return nil
|
|
}
|
|
// Support both comma-separated single values and multiple form fields
|
|
if len(values) == 1 {
|
|
return strings.Split(values[0], ",")
|
|
}
|
|
return values
|
|
}
|
|
|
|
func (f *FormGetter) GetMaps(key string) []map[string]string {
|
|
results := map[string]map[string]string{}
|
|
re := regexp.MustCompile(key + "\\[([0-9]+)\\]\\[([a-zA-Z_]+)\\]")
|
|
for k, v := range f.r.Form {
|
|
matches := re.FindStringSubmatch(k)
|
|
if len(matches) >= 3 {
|
|
realKey := matches[1]
|
|
field := matches[2]
|
|
value := strings.Join(v, ",")
|
|
if _, exists := results[realKey]; !exists {
|
|
results[realKey] = map[string]string{}
|
|
}
|
|
results[realKey][field] = value
|
|
}
|
|
}
|
|
result := []map[string]string{}
|
|
for _, v := range results {
|
|
result = append(result, v)
|
|
}
|
|
return result
|
|
}
|
|
|
|
func (f *FormGetter) getChecks() []*ValidationRule {
|
|
return f.checks
|
|
}
|
|
|
|
func (f *FormGetter) AddCheck(check *ValidationRule) {
|
|
f.checks = append(f.checks, check)
|
|
}
|
|
|
|
func (f *FormGetter) ValidateChecks() []*ValidationRule {
|
|
return validate(f)
|
|
}
|
|
|
|
func (f *FormGetter) String(key string) *StringField {
|
|
return newStringField(key, f)
|
|
}
|
|
|
|
func (f *FormGetter) Int(key string) *IntField {
|
|
return newIntField(key, f)
|
|
}
|
|
|
|
func (f *FormGetter) Bool(key string) *BoolField {
|
|
return newBoolField(key, f)
|
|
}
|
|
|
|
func (f *FormGetter) Time(key string, format *timefmt.Format) *TimeField {
|
|
return newTimeField(key, format, f)
|
|
}
|
|
|
|
func (f *FormGetter) TimeInLocation(key string, format *timefmt.Format, loc *time.Location) *TimeField {
|
|
return newTimeFieldInLocation(key, format, loc, f)
|
|
}
|
|
|
|
func (f *FormGetter) StringList(key string) *StringList {
|
|
return newStringList(key, f)
|
|
}
|
|
|
|
func (f *FormGetter) IntList(key string) *IntList {
|
|
return newIntList(key, f)
|
|
}
|
|
|
|
func ParseForm(r *http.Request) (*FormGetter, error) {
|
|
err := r.ParseForm()
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "r.ParseForm")
|
|
}
|
|
return NewFormGetter(r), nil
|
|
}
|
|
|
|
// ParseFormOrNotify attempts to parse the form data and notifies the user on fail
|
|
func ParseFormOrNotify(s *hws.Server, w http.ResponseWriter, r *http.Request) (*FormGetter, bool) {
|
|
getter, err := ParseForm(r)
|
|
if err != nil {
|
|
notify.Warn(s, w, r, "Invalid Form", "Please check your input and try again.", nil)
|
|
return nil, false
|
|
}
|
|
return getter, true
|
|
}
|
|
|
|
// ParseFormOrError attempts to parse the form data and renders an error page on fail
|
|
func ParseFormOrError(s *hws.Server, w http.ResponseWriter, r *http.Request) (*FormGetter, bool) {
|
|
getter, err := ParseForm(r)
|
|
if err != nil {
|
|
throw.BadRequest(s, w, r, "Invalid form data", err)
|
|
return nil, false
|
|
}
|
|
return getter, true
|
|
}
|
|
|
|
func (f *FormGetter) Validate() bool {
|
|
return len(validate(f)) == 0
|
|
}
|
|
|
|
// ValidateAndNotify runs the provided validation checks and sends a notification for each failed check
|
|
// Returns true if all checks passed
|
|
func (f *FormGetter) ValidateAndNotify(
|
|
s *hws.Server,
|
|
w http.ResponseWriter,
|
|
r *http.Request,
|
|
) bool {
|
|
return validateAndNotify(s, w, r, f)
|
|
}
|
|
|
|
// ValidateAndError runs the provided validation checks and renders an error page with all the error messages
|
|
// Returns true if all checks passed
|
|
func (f *FormGetter) ValidateAndError(
|
|
s *hws.Server,
|
|
w http.ResponseWriter,
|
|
r *http.Request,
|
|
) bool {
|
|
return validateAndError(s, w, r, f)
|
|
}
|