mirror of
https://github.com/0rangebananaspy/authelia.git
synced 2024-09-14 22:47:21 +07:00
54694c4fca
* [MISC] Ignore errcheck recommendations for legacy code Some of this is likely intended to stay how it is, some could use refactoring, for now we will mark is and ignore it from the linter to be potentially addressed in the future. * [MISC] Ensure files are gofmt-ed
135 lines
3.2 KiB
Go
135 lines
3.2 KiB
Go
package schema
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
|
|
"github.com/Workiva/go-datastructures/queue"
|
|
)
|
|
|
|
// ErrorContainer represents a container where we can add errors and retrieve them
|
|
type ErrorContainer interface {
|
|
Push(err error)
|
|
HasErrors() bool
|
|
Errors() []error
|
|
}
|
|
|
|
// Validator represents the validator interface
|
|
type Validator struct {
|
|
errors map[string][]error
|
|
}
|
|
|
|
// NewValidator create a validator
|
|
func NewValidator() *Validator {
|
|
validator := new(Validator)
|
|
validator.errors = make(map[string][]error)
|
|
return validator
|
|
}
|
|
|
|
// QueueItem an item representing a struct field and its path.
|
|
type QueueItem struct {
|
|
value reflect.Value
|
|
path string
|
|
}
|
|
|
|
func (v *Validator) validateOne(item QueueItem, q *queue.Queue) error { //nolint:unparam
|
|
if item.value.Type().Kind() == reflect.Ptr {
|
|
if item.value.IsNil() {
|
|
return nil
|
|
}
|
|
|
|
elem := item.value.Elem()
|
|
q.Put(QueueItem{ //nolint:errcheck // TODO: Legacy code, consider refactoring time permitting.
|
|
value: elem,
|
|
path: item.path,
|
|
})
|
|
} else if item.value.Kind() == reflect.Struct {
|
|
numFields := item.value.Type().NumField()
|
|
|
|
validateFn := item.value.Addr().MethodByName("Validate")
|
|
|
|
if validateFn.IsValid() {
|
|
structValidator := NewStructValidator()
|
|
validateFn.Call([]reflect.Value{reflect.ValueOf(structValidator)})
|
|
v.errors[item.path] = structValidator.Errors()
|
|
}
|
|
|
|
for i := 0; i < numFields; i++ {
|
|
field := item.value.Type().Field(i)
|
|
value := item.value.Field(i)
|
|
|
|
q.Put(QueueItem{ //nolint:errcheck // TODO: Legacy code, consider refactoring time permitting.
|
|
value: value,
|
|
path: item.path + "." + field.Name,
|
|
})
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Validate validate a struct
|
|
func (v *Validator) Validate(s interface{}) error {
|
|
q := queue.New(40)
|
|
q.Put(QueueItem{value: reflect.ValueOf(s), path: "root"}) //nolint:errcheck // TODO: Legacy code, consider refactoring time permitting.
|
|
|
|
for !q.Empty() {
|
|
val, err := q.Get(1)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
item, ok := val[0].(QueueItem)
|
|
if !ok {
|
|
return fmt.Errorf("Cannot convert item into QueueItem")
|
|
}
|
|
v.validateOne(item, q) //nolint:errcheck // TODO: Legacy code, consider refactoring time permitting.
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// PrintErrors display the errors thrown during validation
|
|
func (v *Validator) PrintErrors() {
|
|
for path, errs := range v.errors {
|
|
fmt.Printf("Errors at %s:\n", path)
|
|
for _, err := range errs {
|
|
fmt.Printf("--> %s\n", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Errors return the errors thrown during validation
|
|
func (v *Validator) Errors() map[string][]error {
|
|
return v.errors
|
|
}
|
|
|
|
// StructValidator is a validator for structs
|
|
type StructValidator struct {
|
|
errors []error
|
|
}
|
|
|
|
// NewStructValidator is a constructor of struct validator
|
|
func NewStructValidator() *StructValidator {
|
|
val := new(StructValidator)
|
|
val.errors = make([]error, 0)
|
|
return val
|
|
}
|
|
|
|
// Push an error in the validator.
|
|
func (v *StructValidator) Push(err error) {
|
|
v.errors = append(v.errors, err)
|
|
}
|
|
|
|
// HasErrors checks whether the validator contains errors.
|
|
func (v *StructValidator) HasErrors() bool {
|
|
return len(v.errors) > 0
|
|
}
|
|
|
|
// Errors returns the errors.
|
|
func (v *StructValidator) Errors() []error {
|
|
return v.errors
|
|
}
|
|
|
|
// Clear errors
|
|
func (v *StructValidator) Clear() {
|
|
v.errors = []error{}
|
|
}
|