diff --git a/mistral/api/controllers/v2/types.py b/mistral/api/controllers/v2/types.py index ca474c2db..3a9642f4c 100644 --- a/mistral/api/controllers/v2/types.py +++ b/mistral/api/controllers/v2/types.py @@ -13,6 +13,7 @@ # limitations under the License. import json +from mistral.utils import filter_utils from oslo_utils import uuidutils import six from wsme import types as wtypes @@ -77,12 +78,13 @@ class UuidType(wtypes.UserType): @staticmethod 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( - "Expected a uuid but received %s." % value + "Expected a uuid but received %s." % data ) - return value + return data @staticmethod def frombasetype(value): diff --git a/mistral/tests/unit/actions/test_types.py b/mistral/tests/unit/actions/test_types.py new file mode 100644 index 000000000..652de1753 --- /dev/null +++ b/mistral/tests/unit/actions/test_types.py @@ -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) diff --git a/mistral/utils/filter_utils.py b/mistral/utils/filter_utils.py index ade70c41e..662e4c833 100644 --- a/mistral/utils/filter_utils.py +++ b/mistral/utils/filter_utils.py @@ -1,4 +1,5 @@ # 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 # not use this file except in compliance with the License. You may obtain @@ -14,6 +15,20 @@ 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): """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(): if (data is None and column in none_values) or data is not None: 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) else: @@ -58,7 +73,7 @@ def create_or_update_filter(column, value, filter_type='eq', _filter=None): 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. :param data: REST parameter value from which filter type and @@ -66,35 +81,20 @@ def _extract_filter_type_and_value(data): 'filter_type:value'. :return: filter type and value. """ - if data.startswith("in:"): - value = list(six.text_type(data[3:]).split(",")) - filter_type = 'in' - elif data.startswith("nin:"): - value = list(six.text_type(data[4:]).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' + if has_filters(data): + filter_type, value = data.split(':', 1) + value = six.text_type(value) + if data.startswith((IN, NOT_IN)): + value = list(value.split(",")) else: value = data - filter_type = 'eq' + filter_type = EQUALS return filter_type, value + + +def has_filters(value): + for filter_type in ALL: + if value.startswith(filter_type + ':'): + return True + return False