132 lines
2.2 KiB
Go
132 lines
2.2 KiB
Go
package form
|
|
|
|
import (
|
|
"mime/multipart"
|
|
"net/http"
|
|
"net/url"
|
|
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
type ValidationErrors map[string]error
|
|
|
|
type Form struct {
|
|
fields []*Field
|
|
errors ValidationErrors
|
|
}
|
|
|
|
func (f *Form) Handle(r *http.Request) error {
|
|
if err := r.ParseForm(); err != nil {
|
|
return errors.WithStack(err)
|
|
}
|
|
|
|
if err := f.Parse(r.Form); err != nil {
|
|
return errors.WithStack(err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (f *Form) HandleMultipart(r *http.Request, maxMemory int64) error {
|
|
if err := r.ParseMultipartForm(maxMemory); err != nil {
|
|
return errors.WithStack(err)
|
|
}
|
|
|
|
if err := f.ParseMultipart(r.MultipartForm); err != nil {
|
|
return errors.WithStack(err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (f *Form) ParseMultipart(multi *multipart.Form) error {
|
|
for _, f := range f.fields {
|
|
name := f.Name()
|
|
|
|
values, exists := multi.Value[name]
|
|
if !exists {
|
|
f.Del("value")
|
|
} else {
|
|
f.Set("value", values)
|
|
}
|
|
|
|
files, exists := multi.File[name]
|
|
if !exists {
|
|
f.Del("file")
|
|
} else {
|
|
f.Set("file", files)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (f *Form) Parse(values url.Values) error {
|
|
for _, f := range f.fields {
|
|
name := f.Name()
|
|
if !values.Has(name) {
|
|
f.Del("value")
|
|
continue
|
|
}
|
|
|
|
value := values.Get(name)
|
|
f.Set("value", value)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (f *Form) Validate() ValidationErrors {
|
|
var errs ValidationErrors
|
|
|
|
for _, f := range f.fields {
|
|
if err := f.Validate(); err != nil {
|
|
if errs == nil {
|
|
errs = make(ValidationErrors)
|
|
}
|
|
|
|
errs[f.Name()] = err
|
|
}
|
|
}
|
|
|
|
f.errors = errs
|
|
|
|
return errs
|
|
}
|
|
|
|
func (f *Form) Field(name string) *Field {
|
|
for _, field := range f.fields {
|
|
if field.Name() == name {
|
|
return field
|
|
}
|
|
}
|
|
|
|
panic(errors.Errorf("no form field named '%s'", name))
|
|
}
|
|
|
|
func (f *Form) Error(name string) (ValidationError, bool) {
|
|
err, exists := f.errors[name]
|
|
if !exists {
|
|
return nil, false
|
|
}
|
|
|
|
var validationErr ValidationError
|
|
if errors.As(err, &validationErr) {
|
|
return validationErr, true
|
|
}
|
|
|
|
return NewValidationError("Unexpected error"), true
|
|
}
|
|
|
|
func (f *Form) Extend(fields ...*Field) *Form {
|
|
fields = append(f.fields, fields...)
|
|
return New(fields...)
|
|
}
|
|
|
|
func New(fields ...*Field) *Form {
|
|
return &Form{
|
|
fields: fields,
|
|
errors: make(ValidationErrors),
|
|
}
|
|
}
|