Skip to content

Commit

Permalink
Fix VALIDATE_FILTERS behaviour for filters on sub-document fields (is…
Browse files Browse the repository at this point in the history
…sue pyeve#1123)
  • Loading branch information
lmoretto committed Mar 23, 2018
1 parent 53e4bb9 commit 6168ae9
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 8 deletions.
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ Patches and Contributions
- Kurt Bonne
- Kurt Doherty
- Luca Di Gaspero
- Luca Moretto
- Luis Fernando Gomes
- Magdas Adrian
- Mandar Vaze
Expand Down
30 changes: 30 additions & 0 deletions eve/tests/methods/get.py
Original file line number Diff line number Diff line change
Expand Up @@ -1099,6 +1099,36 @@ def test_get_invalid_where_fields(self):
response, status = self.get(self.known_resource, where)
self.assert200(status)

# test for nested resource field validating correctly
# (location is dict)
where = '?where={"location.address": "str 1"}'
response, status = self.get(self.known_resource, where)
self.assert200(status)

# test for nested resource field validating correctly
# (rows is list of dicts)
where = '?where={"rows.price": 10}'
response, status = self.get(self.known_resource, where)
self.assert200(status)

# test for nested resource field validating correctly
# (dict_list_fixed_len is a fixed-size list of dicts)
where = '?where={"dict_list_fixed_len.key2": 1}'
response, status = self.get(self.known_resource, where)
self.assert200(status)

# test for nested resource field not validating correctly
# (bad_base_key doesn't exist in the base resource schema)
where = '?where={"bad_base_key.sub": 1}'
response, status = self.get(self.known_resource, where)
self.assert400(status)

# test for nested resource field not validating correctly
# (bad_sub_key doesn't exist in the dict_list_fixed_len schema)
where = '?where={"dict_list_fixed_len.bad_sub_key": 1}'
response, status = self.get(self.known_resource, where)
self.assert400(status)

def test_get_lookup_field_as_string(self):
# Test that a resource where 'item_lookup_field' is set to a field
# of string type and which value is castable to a ObjectId is still
Expand Down
13 changes: 13 additions & 0 deletions eve/tests/test_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,19 @@
'type': 'list',
'items': [{'type': 'objectid'}]
},
'dict_list_fixed_len': {
'type': 'list',
'items': [
{
'type': 'dict',
'schema': {'key1': {'type': 'string'}}
},
{
'type': 'dict',
'schema': {'key2': {'type': 'integer'}}
}
]
},
'dependency_field1': {
'type': 'string',
'default': 'default'
Expand Down
52 changes: 44 additions & 8 deletions eve/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -401,16 +401,52 @@ def validate_filter(filter):
return r
else:
if config.VALIDATE_FILTERS:
def get_sub_schemas(base_schema):
def dict_sub_schema(base):
if base.get('type') == 'dict':
return base.get('schema')

return None

if base_schema.get('type') == 'list':
if 'schema' in base_schema:
# Try to get dict sub-schema for arbitrary sized list
sub = dict_sub_schema(base_schema['schema'])
return [sub] if sub is not None else []
elif 'items' in base_schema:
# Try to get dict sub-schema(s) for fixed-size list
items = base_schema['items']
sub_schemas = []
for item in items:
sub = dict_sub_schema(item)
if sub is not None:
sub_schemas.append(sub)

return sub_schemas
else:
sub = dict_sub_schema(base_schema)
return [sub] if sub is not None else []

def recursive_validate_filter(key, value, schema):
if key not in schema:
base_key, _, sub_keys = key.partition('.')
if sub_keys and base_key in schema:
# key is the composition of base field and sub-fields
for sub_schema in get_sub_schemas(schema[base_key]):
if recursive_validate_filter(sub_keys, value, sub_schema):
return True

return False
else:
field_schema = schema.get(key)
v = Validator({key: field_schema})
return v.validate({key: value})

res_schema = config.DOMAIN[resource]['schema']
if key not in res_schema:
if not recursive_validate_filter(key, value, res_schema):
return "filter on '%s' is invalid"
else:
field_schema = res_schema.get(key)
v = Validator({key: field_schema})
if not v.validate({key: value}):
return "filter on '%s' is invalid"
else:
return None

return None

if '*' in allowed and not config.VALIDATE_FILTERS:
return None
Expand Down

0 comments on commit 6168ae9

Please sign in to comment.