Skip to content

Commit

Permalink
feat(form): add validation for Options
Browse files Browse the repository at this point in the history
  • Loading branch information
rande committed Oct 25, 2023
1 parent fe7e7ce commit d20e51e
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 21 deletions.
1 change: 1 addition & 0 deletions core/form/form_structs.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,7 @@ func create(name string, options ...interface{}) *FormField {
if field.Input.Type == "select" {
field.Marshaller = selectMarshal
field.Unmarshaller = selectUnmarshal
field.Validators = append(field.Validators, OptionsValidator())
field.Input.Template = "form:fields/input.select.tpl"
}

Expand Down
41 changes: 39 additions & 2 deletions core/form/form_structs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ func Test_FormField_Validate(t *testing.T) {
assert.Nil(t, result)

field.Touched = false
field.SubmittedValue = nil
field.SubmittedValue = "john.doe"

result = validateForm(form.Fields, form)

Expand Down Expand Up @@ -490,7 +490,7 @@ func Test_Bind_Form_Select_Invalid_Multiple_Type(t *testing.T) {
{Label: "Car", Value: int32(2)},
{Label: "Travel", Value: int32(3)},
{Label: "Games", Value: int32(4)},
}).SetMultiple(true)
})

PrepareForm(form)

Expand All @@ -511,6 +511,43 @@ func Test_Bind_Form_Select_Invalid_Multiple_Type(t *testing.T) {
assert.NotNil(t, err)
}

func Test_Bind_Form_Select_Invalid_Multiple_Type_Scope(t *testing.T) {
user := &TestUser{
Name: "John Doe",
Enabled: true,
Hidden: false,
Position: int32(1),
Items: []int32{1, 2},
}

form := CreateForm(user)
form.Add("Items", "select", nil, FieldOptions{
{Label: "Food", Value: int32(1)},
{Label: "Car", Value: int32(2)},
{Label: "Travel", Value: int32(3)},
{Label: "Games", Value: int32(4)},
})

PrepareForm(form)

v := url.Values{
"Items": []string{"5", "3"}, // 5 is not a valid value
}

err := BindUrlValues(form, v)
assert.Nil(t, err)

err = ValidateForm(form)

assert.NotNil(t, err)
assert.Equal(t, 1, len(form.Get("Items").Errors))
assert.Equal(t, "the value is not in the list of options", form.Get("Items").Errors[0])

err = AttachValues(form)

assert.NotNil(t, err)
}

func Test_Bind_Form_Select_Invalid_Type(t *testing.T) {
user := &TestUser{
Name: "John Doe",
Expand Down
62 changes: 52 additions & 10 deletions core/form/form_validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"errors"
"net/mail"
"net/url"
"reflect"
)

var (
Expand All @@ -18,6 +19,7 @@ var (
ErrUrlValidator = errors.New("the value is not a valid url")
ErrMaxValidator = errors.New("the value is too big")
ErrMinValidator = errors.New("the value is too small")
ErrOptionsValidator = errors.New("the value is not in the list of options")
)

type number interface {
Expand Down Expand Up @@ -100,7 +102,7 @@ func EmailValidator() Validator {
code: "email",
validator: func(field *FormField, form *Form) error {
if field.SubmittedValue == nil {
return ErrEmailValidator
return nil
}

if _, err := mail.ParseAddress(field.SubmittedValue.(string)); err != nil {
Expand All @@ -116,12 +118,8 @@ func UrlValidator() Validator {
return &ValidatorFunc{
code: "url",
validator: func(field *FormField, form *Form) error {
if !field.Touched {
return ErrUrlValidator
}

if field.SubmittedValue == nil {
return ErrUrlValidator
return nil
}

if _, err := url.Parse(field.SubmittedValue.(string)); err != nil {
Expand All @@ -138,7 +136,7 @@ func MinValidator[T number](min T) Validator {
code: "min",
validator: func(field *FormField, form *Form) error {
if field.SubmittedValue == nil {
return ErrMinValidator
return nil
}

if field.SubmittedValue.(T) < min {
Expand All @@ -155,7 +153,7 @@ func MaxValidator[T number](max T) Validator {
code: "max",
validator: func(field *FormField, form *Form) error {
if field.SubmittedValue == nil {
return ErrMaxValidator
return nil
}

if field.SubmittedValue.(T) > max {
Expand All @@ -172,7 +170,7 @@ func MaxLengthValidator(max uint32, mode string) Validator {
code: "max_length",
validator: func(field *FormField, form *Form) error {
if field.SubmittedValue == nil {
return ErrMaxValidator
return nil
}

if mode == "bytes" {
Expand All @@ -197,7 +195,7 @@ func MinLengthValidator(min uint32, mode string) Validator {
code: "min_length",
validator: func(field *FormField, form *Form) error {
if field.SubmittedValue == nil {
return ErrMaxValidator
return nil
}

if mode == "bytes" {
Expand All @@ -216,3 +214,47 @@ func MinLengthValidator(min uint32, mode string) Validator {
},
}
}

func OptionsValidator() Validator {
return &ValidatorFunc{
code: "select",
validator: func(field *FormField, form *Form) error {
if field.SubmittedValue == nil {
return nil
}

if !field.Input.Multiple {
submittedValue := reflect.ValueOf(field.SubmittedValue)
for _, option := range field.Options.(FieldOptions) {
optionValue := reflect.ValueOf(option.Value)

if optionValue.Equal(submittedValue) {
return nil
}
}

return ErrOptionsValidator
} else {
slice := reflect.ValueOf(field.SubmittedValue)
for i := 0; i < slice.Len(); i++ {
v := slice.Index(i)

found := false
for _, option := range field.Options.(FieldOptions) {
optionValue := reflect.ValueOf(option.Value)

if optionValue.Equal(v) {
found = true
}
}

if !found {
return ErrOptionsValidator
}
}
}

return nil
},
}
}
17 changes: 8 additions & 9 deletions core/form/form_validator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
package form

import (
"fmt"
"testing"

"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -79,10 +78,10 @@ func Test_Min_Validator_Float(t *testing.T) {
}

func Test_MaxLength(t *testing.T) {
msg := "abc"
fmt.Printf("size: %d\n", len(msg))
fmt.Printf("size: %d\n", len([]rune(msg)))
fmt.Printf("size: %d\n", uint32(len([]rune(msg))))
// msg := "abc"
// fmt.Printf("size: %d\n", len(msg))
// fmt.Printf("size: %d\n", len([]rune(msg)))
// fmt.Printf("size: %d\n", uint32(len([]rune(msg))))

field := &FormField{
Name: "Name",
Expand Down Expand Up @@ -118,10 +117,10 @@ func Test_MaxLength(t *testing.T) {
}

func Test_MinLength(t *testing.T) {
msg := "πŸ‡«πŸ‡·πŸ‡«πŸ‡·"
fmt.Printf("size: %d\n", len(msg))
fmt.Printf("size: %d\n", len([]rune(msg)))
fmt.Printf("size: %d\n", uint32(len([]rune(msg))))
// msg := "πŸ‡«πŸ‡·πŸ‡«πŸ‡·"
// fmt.Printf("size: %d\n", len(msg))
// fmt.Printf("size: %d\n", len([]rune(msg)))
// fmt.Printf("size: %d\n", uint32(len([]rune(msg))))

field := &FormField{
Name: "Name",
Expand Down

0 comments on commit d20e51e

Please sign in to comment.