| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384 |
- package form
- import (
- "net/http"
- "reflect"
- )
- /* ValidateForm parses a POST form into a pre-defined struct */
- func ValidateForm(r *http.Request, p any) (formErr error) {
- /* asserts */
- switch {
- case r == nil:
- /* error on nil requestst */
- return ENilRequest
- case r.Method != http.MethodPost:
- /* only support with POST methods */
- return EInvalidMethod
- case p == nil:
- /* error on nil form */
- return ENilForm
- }
- /* assert on form being a pointer */
- fv := reflect.ValueOf(p)
- if fv.Kind() != reflect.Pointer || fv.IsNil() {
- return EInvalidForm
- }
- /* assert on form being a pointer to a struct */
- fv = fv.Elem()
- if fv.Kind() != reflect.Struct {
- return EInvalidForm
- }
- /* parse form in the request */
- if err := r.ParseForm(); err != nil {
- /* TODO: handle multipart forms / file uploads */
- return err
- }
- /* walk target form fields */
- for idx := 0; idx < fv.NumField(); idx++ {
- f := fv.Field(idx)
- /* ignore non-pointer form fields or nil fields */
- if f.Kind() != reflect.Pointer || f.IsNil() {
- continue
- }
- /* ignore fields of type different from *FormField */
- ff, ok := f.Interface().(*FormField)
- if !ok || ff == nil {
- continue
- }
- ff.Error = nil
- /* store value in *FormField */
- defaultValue := ff.Value
- if v, ok := r.PostForm[ff.Name]; ok {
- ff.Value = v[0]
- } else {
- ff.Value = ""
- }
- /* assert on required fields */
- if ff.Required && ff.Value == "" {
- ff.Error = append(ff.Error, ERequiredField)
- formErr = EFormHasErrors
- continue
- }
- /* do not run validators on empty values */
- if ff.Value == "" {
- continue
- }
- /* run field validators if any */
- for _, fieldValidator := range ff.Validators {
- if fieldValidator == nil {
- continue
- }
- if err := fieldValidator(ff, r.Context()); err != nil {
- ff.Error = append(ff.Error, err)
- formErr = EFormHasErrors
- break
- }
- }
- /* restore default value if necessary */
- if ff.Sticky {
- ff.Value = defaultValue
- }
- }
- return
- }
|