Allow the prefixes like "eq:" and "neq:" in the custom REST UUID type

* Fields of type UUID with a filter prefix are denied because they
  don't match the UUID string format. E.g.
  "eq:6c07a453-c5e1-4bbe-97ed-3cb77b4f55ff" will throw an
  InputException. This patch makes the change that allows to have:
  "eq:" "neq:" "gt:" "gte:" "lt:" "lte:" "has:" "in:" "nin:" prefixes
  in a value of such fields.

Closes-Bug: #1792875
Change-Id: I26667a82ec768c858f0282124864e377d8cf39f4
Signed-off-by: ali <ali.abdelal@nokia.com>
This commit is contained in:
ali 2019-12-15 12:34:58 +00:00
parent bc46b29f01
commit 6948e50de8
3 changed files with 81 additions and 33 deletions

View File

@ -13,6 +13,7 @@
# limitations under the License. # limitations under the License.
import json import json
from mistral.utils import filter_utils
from oslo_utils import uuidutils from oslo_utils import uuidutils
import six import six
from wsme import types as wtypes from wsme import types as wtypes
@ -77,12 +78,13 @@ class UuidType(wtypes.UserType):
@staticmethod @staticmethod
def validate(value): def validate(value):
if not uuidutils.is_uuid_like(value): _, data = filter_utils.extract_filter_type_and_value(value)
if not uuidutils.is_uuid_like(data):
raise exc.InputException( raise exc.InputException(
"Expected a uuid but received %s." % value "Expected a uuid but received %s." % data
) )
return value return data
@staticmethod @staticmethod
def frombasetype(value): def frombasetype(value):

View File

@ -0,0 +1,46 @@
# Copyright 2017 - Nokia Networks
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from mistral.api.controllers.v2 import types
from mistral import exceptions as exc
from mistral.tests.unit import base
from mistral.utils import filter_utils
class TestTypesController(base.BaseTest):
base_id = '88888888-4444-4444-4444-777777755555'
uuid_type = types.uuid
def test_uuid_type(self):
self.uuid_type.validate(self.base_id)
def test_uuid_type_wit_invalid_format(self):
self.assertRaises(exc.InputException,
self.uuid_type.validate, 'invalid_format')
self.assertRaises(exc.InputException,
self.uuid_type.validate, '44-231-454-542123')
def test_uuid_with_filters(self):
for filter_type in filter_utils.ALL:
value = '{}{}'.format(filter_type + ':', self.base_id)
if filter_type.startswith((filter_utils.IN, filter_utils.NOT_IN)):
self.assertRaises(exc.InputException,
self.uuid_type.validate, value)
else:
self.uuid_type.validate(value)
def test_uuid_type_with_invalid_prefix(self):
value = 'invalid:{}'.format(self.base_id)
self.assertRaises(exc.InputException, self.uuid_type.validate, value)

View File

@ -1,4 +1,5 @@
# Copyright 2016 NEC Corporation. All rights reserved. # Copyright 2016 NEC Corporation. All rights reserved.
# Copyright 2019 Nokia Software. All rights reserved.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); you may # Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain # not use this file except in compliance with the License. You may obtain
@ -14,6 +15,20 @@
import six import six
EQUALS = 'eq'
NOT_EQUAL = 'neq'
LESS_THAN = 'lt'
LESS_THAN_EQUALS = 'lte'
GREATER_THAN = 'gt'
GREATER_THAN_EQUALS = 'gte'
IN = 'in'
NOT_IN = 'nin'
HAS = 'has'
ALL = (GREATER_THAN_EQUALS, GREATER_THAN,
LESS_THAN_EQUALS, HAS, NOT_EQUAL,
LESS_THAN, IN, EQUALS, NOT_IN)
def create_filters_from_request_params(none_values=None, **params): def create_filters_from_request_params(none_values=None, **params):
"""Create filters from REST request parameters. """Create filters from REST request parameters.
@ -28,7 +43,7 @@ def create_filters_from_request_params(none_values=None, **params):
for column, data in params.items(): for column, data in params.items():
if (data is None and column in none_values) or data is not None: if (data is None and column in none_values) or data is not None:
if isinstance(data, six.string_types): if isinstance(data, six.string_types):
f_type, value = _extract_filter_type_and_value(data) f_type, value = extract_filter_type_and_value(data)
create_or_update_filter(column, value, f_type, filters) create_or_update_filter(column, value, f_type, filters)
else: else:
@ -58,7 +73,7 @@ def create_or_update_filter(column, value, filter_type='eq', _filter=None):
return _filter return _filter
def _extract_filter_type_and_value(data): def extract_filter_type_and_value(data):
"""Extract filter type and its value from the data. """Extract filter type and its value from the data.
:param data: REST parameter value from which filter type and :param data: REST parameter value from which filter type and
@ -66,35 +81,20 @@ def _extract_filter_type_and_value(data):
'filter_type:value'. 'filter_type:value'.
:return: filter type and value. :return: filter type and value.
""" """
if data.startswith("in:"): if has_filters(data):
value = list(six.text_type(data[3:]).split(",")) filter_type, value = data.split(':', 1)
filter_type = 'in' value = six.text_type(value)
elif data.startswith("nin:"): if data.startswith((IN, NOT_IN)):
value = list(six.text_type(data[4:]).split(",")) value = list(value.split(","))
filter_type = 'nin'
elif data.startswith("neq:"):
value = six.text_type(data[4:])
filter_type = 'neq'
elif data.startswith("gt:"):
value = six.text_type(data[3:])
filter_type = 'gt'
elif data.startswith("gte:"):
value = six.text_type(data[4:])
filter_type = 'gte'
elif data.startswith("lt:"):
value = six.text_type(data[3:])
filter_type = 'lt'
elif data.startswith("lte:"):
value = six.text_type(data[4:])
filter_type = 'lte'
elif data.startswith("eq:"):
value = six.text_type(data[3:])
filter_type = 'eq'
elif data.startswith("has:"):
value = six.text_type(data[4:])
filter_type = 'has'
else: else:
value = data value = data
filter_type = 'eq' filter_type = EQUALS
return filter_type, value return filter_type, value
def has_filters(value):
for filter_type in ALL:
if value.startswith(filter_type + ':'):
return True
return False