Exemple #1
0
// SetSort parses and validate a sort parameter and set it as lookup's Sort
func (l *Lookup) SetSort(sort string, validator schema.Validator) error {
	sorts := []string{}
	for _, f := range strings.Split(sort, ",") {
		f = strings.Trim(f, " ")
		if f == "" {
			return errors.New("empty soft field")
		}
		// If the field start with - (to indicate descended sort), shift it before
		// validator lookup
		i := 0
		if f[0] == '-' {
			i = 1
		}
		// Make sure the field exists
		field := validator.GetField(f[i:])
		if field == nil {
			return fmt.Errorf("invalid sort field: %s", f[i:])
		}
		if !field.Sortable {
			return fmt.Errorf("field is not sortable: %s", f[i:])
		}
		sorts = append(sorts, f)
	}
	l.sort = sorts
	return nil
}
Exemple #2
0
// checkReferences checks that fields with the Reference validator reference an existing object
func (r *requestHandler) checkReferences(payload map[string]interface{}, s schema.Validator) *Error {
	for name, value := range payload {
		field := s.GetField(name)
		if field == nil {
			continue
		}
		// Check reference if validator is of type Reference
		if field.Validator != nil {
			if ref, ok := field.Validator.(*schema.Reference); ok {
				resource := r.h.getResource(ref.Path)
				if resource == nil {
					return &Error{500, fmt.Sprintf("Invalid resource reference for field `%s': %s", name, ref.Path), nil}
				}
				lookup := NewLookup()
				lookup.Fields["id"] = value
				list, _ := resource.handler.Find(lookup, 1, 1)
				if len(list.Items) == 0 {
					return &Error{404, fmt.Sprintf("Resource reference not found for field `%s'", name), nil}
				}
			}
		}
		// Check sub-schema if any
		if field.Schema != nil && value != nil {
			if subPayload, ok := value.(map[string]interface{}); ok {
				if err := r.checkReferences(subPayload, field.Schema); err != nil {
					return err
				}
			}
		}
	}
	return nil
}
Exemple #3
0
func applySelector(s []Field, v schema.Validator, p map[string]interface{}, resolver ReferenceResolver) (map[string]interface{}, error) {
	res := map[string]interface{}{}
	for _, f := range s {
		if val, found := p[f.Name]; found {
			name := f.Name
			// Handle aliasing
			if f.Alias != "" {
				name = f.Alias
			}
			// Handle selector params
			if len(f.Params) > 0 {
				def := v.GetField(f.Name)
				if def == nil || def.Params == nil {
					return nil, fmt.Errorf("%s: params not allowed", f.Name)
				}
				var err error
				val, err = def.Params.Handler(val, f.Params)
				if err != nil {
					return nil, fmt.Errorf("%s: %s", f.Name, err.Error())
				}
			}
			// Handle sub field selection (if field has a value)
			if len(f.Fields) > 0 && val != nil {
				def := v.GetField(f.Name)
				if def != nil && def.Schema != nil {
					subval, ok := val.(map[string]interface{})
					if !ok {
						return nil, fmt.Errorf("%s: invalid value: not a dict", f.Name)
					}
					var err error
					res[name], err = applySelector(f.Fields, def.Schema, subval, resolver)
					if err != nil {
						return nil, fmt.Errorf("%s.%s", f.Name, err.Error())
					}
				} else if ref, ok := def.Validator.(*schema.Reference); ok {
					// Sub-field on a reference (sub-request)
					subres, subval, err := resolver(ref.Path, val)
					if err != nil {
						return nil, fmt.Errorf("%s: error fetching sub-field: %s", f.Name, err.Error())
					}
					res[name], err = applySelector(f.Fields, subres.validator, subval, resolver)
				} else {
					return nil, fmt.Errorf("%s: field as no children", f.Name)
				}
			} else {
				res[name] = val
			}
		}
	}
	return res, nil
}
Exemple #4
0
func validateSelector(s []Field, v schema.Validator) error {
	for _, f := range s {
		def := v.GetField(f.Name)
		if def == nil {
			return fmt.Errorf("%s: unknown field", f.Name)
		}
		if len(f.Fields) > 0 {
			if def.Schema != nil {
				// Sub-field on a dict (sub-schema)
				if err := validateSelector(f.Fields, def.Schema); err != nil {
					return fmt.Errorf("%s.%s", f.Name, err.Error())
				}
			} else if _, ok := def.Validator.(*schema.Reference); ok {
				// Sub-field on a reference (sub-request)
			} else {
				return fmt.Errorf("%s: field as no children", f.Name)
			}
		}
		// TODO: support connections
		if len(f.Params) > 0 {
			if def.Params == nil {
				return fmt.Errorf("%s: params not allowed", f.Name)
			}
			for param, value := range f.Params {
				val, found := def.Params.Validators[param]
				if !found {
					return fmt.Errorf("%s: unsupported param name: %s", f.Name, param)
				}
				value, err := val.Validate(value)
				if err != nil {
					return fmt.Errorf("%s: invalid param `%s' value: %s", f.Name, param, err.Error())
				}
				f.Params[param] = value
			}
		}
	}
	return nil
}
Exemple #5
0
// checkReferences ensures that fields with the Reference validator reference an existing object
func checkReferences(ctx context.Context, payload map[string]interface{}, s schema.Validator) *Error {
	for name, value := range payload {
		field := s.GetField(name)
		if field == nil {
			continue
		}
		// Check reference if validator is of type Reference
		if field.Validator != nil {
			if ref, ok := field.Validator.(*schema.Reference); ok {
				router, ok := IndexFromContext(ctx)
				if !ok {
					return &Error{500, "Router not available in context", nil}
				}
				rsrc, found := router.GetResource(ref.Path, nil)
				if !found {
					return &Error{500, fmt.Sprintf("Invalid resource reference for field `%s': %s", name, ref.Path), nil}
				}
				_, err := rsrc.Get(ctx, value)
				if err == resource.ErrNotFound {
					return &Error{404, fmt.Sprintf("Resource reference not found for field `%s'", name), nil}
				} else if err != nil {
					return &Error{500, fmt.Sprintf("Error fetching resource reference for field `%s': %v", name, err), nil}
				}
			}
		}
		// Check sub-schema if any
		if field.Schema != nil && value != nil {
			if subPayload, ok := value.(map[string]interface{}); ok {
				if err := checkReferences(ctx, subPayload, field.Schema); err != nil {
					return err
				}
			}
		}
	}
	return nil
}
Exemple #6
0
// checkReferences checks that fields with the Reference validator reference an existing object
func (r *request) checkReferences(ctx context.Context, payload map[string]interface{}, s schema.Validator) *Error {
	for name, value := range payload {
		field := s.GetField(name)
		if field == nil {
			continue
		}
		// Check reference if validator is of type Reference
		if field.Validator != nil {
			if ref, ok := field.Validator.(*schema.Reference); ok {
				router, ok := IndexFromContext(ctx)
				if !ok {
					return &Error{500, "Router not available in context", nil}
				}
				rsrc, _, found := router.GetResource(ref.Path)
				if !found {
					return &Error{500, fmt.Sprintf("Invalid resource reference for field `%s': %s", name, ref.Path), nil}
				}
				l := resource.NewLookup()
				l.AddQuery(schema.Query{schema.Equal{Field: "id", Value: value}})
				list, _ := rsrc.Find(ctx, l, 1, 1)
				if len(list.Items) == 0 {
					return &Error{404, fmt.Sprintf("Resource reference not found for field `%s'", name), nil}
				}
			}
		}
		// Check sub-schema if any
		if field.Schema != nil && value != nil {
			if subPayload, ok := value.(map[string]interface{}); ok {
				if err := r.checkReferences(ctx, subPayload, field.Schema); err != nil {
					return err
				}
			}
		}
	}
	return nil
}
Exemple #7
0
// validateFilter recursively validates the format of a filter query
func validateFilter(f map[string]interface{}, validator schema.Validator, parentKey string) error {
	for key, exp := range f {
		switch key {
		case "$ne", "$gt", "$gte", "$lt", "$lte":
			op := key
			if parentKey == "" {
				return fmt.Errorf("%s can't be at first level", op)
			}
			if _, ok := isNumber(exp); !ok {
				return fmt.Errorf("%s: value for %s must be a number", parentKey, op)
			}
			if field := validator.GetField(parentKey); field != nil {
				if field.Validator != nil {
					switch field.Validator.(type) {
					case schema.Integer, schema.Float:
						// Ok
					default:
						return fmt.Errorf("%s: cannot apply %s operation on a non numerical field", parentKey, op)
					}
				}
			}
		case "$in", "$nin":
			op := key
			if parentKey == "" {
				return fmt.Errorf("%s can't be at first level", op)
			}
			if _, ok := exp.(map[string]interface{}); ok {
				return fmt.Errorf("%s: value for %s can't be a dict", parentKey, op)
			}
		case "$or":
			var subFilters []interface{}
			var ok bool
			if subFilters, ok = exp.([]interface{}); !ok {
				return fmt.Errorf("%s: value for $or must be an array of dicts", parentKey)
			}
			if len(subFilters) < 2 {
				return fmt.Errorf("%s: $or must contain at least to elements", parentKey)
			}
			for _, subFilter := range subFilters {
				if sf, ok := subFilter.(map[string]interface{}); !ok {
					return fmt.Errorf("%s: value for $or must be an array of dicts", parentKey)
				} else if err := validateFilter(sf, validator, ""); err != nil {
					return err
				}
			}
		default:
			// Exact match
			if subFilter, ok := exp.(map[string]interface{}); ok {
				if parentKey != "" {
					return fmt.Errorf("%s: invalid expression", parentKey)
				}
				if err := validateFilter(subFilter, validator, key); err != nil {
					return err
				}
			} else {
				if field := validator.GetField(key); field != nil {
					if field.Validator != nil {
						if _, err := field.Validator.Validate(exp); err != nil {
							return fmt.Errorf("invalid filter expression for field `%s': %s", key, err)
						}
					}
				} else {
					return fmt.Errorf("unknown filter field: %s", key)
				}
			}
		}
	}
	return nil
}