From 270e0b51dcee15c8c3fe7ac99f15e33e0801dd76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laur=C3=A9line=20Gu=C3=A9rin?= Date: Thu, 13 Oct 2022 15:50:52 +0200 Subject: [PATCH] wcs: add operators (#70125) --- .../wcs/context_processors.py | 37 +++- .../wcs/templatetags/wcs.py | 30 ++++ tests/test_wcs.py | 166 ++++++++++++------ 3 files changed, 178 insertions(+), 55 deletions(-) diff --git a/publik_django_templatetags/wcs/context_processors.py b/publik_django_templatetags/wcs/context_processors.py index e8ad0ac..b78607d 100644 --- a/publik_django_templatetags/wcs/context_processors.py +++ b/publik_django_templatetags/wcs/context_processors.py @@ -90,31 +90,60 @@ class LazyCardDefObjectsManager: value = '' if isinstance(value, bool): value = str(value).lower() + op = getattr(self, 'pending_op', 'eq') + if self.pending_attr in ['internal_id', 'number', 'user', 'status']: + return getattr(self, 'filter_by_%s' % self.pending_attr)(value, op) qs._filters['filter-%s' % self.pending_attr] = value + qs._filters['filter-%s-operator' % self.pending_attr] = op return qs - def filter_by_internal_id(self, internal_id): + def apply_op(self, op): + self.pending_op = op + return self + + def apply_eq(self): + return self.apply_op('eq') + + def apply_ne(self): + return self.apply_op('ne') + + def apply_lt(self): + return self.apply_op('lt') + + def apply_lte(self): + return self.apply_op('lte') + + def apply_gt(self): + return self.apply_op('gt') + + def apply_gte(self): + return self.apply_op('gte') + + def filter_by_internal_id(self, internal_id, op='eq'): qs = self._clone() if internal_id: qs._filters['filter-internal-id'] = internal_id + qs._filters['filter-internal-id-operator'] = op return qs - def filter_by_number(self, number): + def filter_by_number(self, number, op='eq'): qs = self._clone() if number: qs._filters['filter-number'] = number return qs - def filter_by_user(self, user): + def filter_by_user(self, user, op='eq'): qs = self._clone() if user and user.is_authenticated and user.get_name_id(): qs._filters['filter-user-uuid'] = user.get_name_id() return qs - def filter_by_status(self, status): + def filter_by_status(self, status, op='eq'): qs = self._clone() if status: qs._filters['filter'] = status + if op in ['eq', 'ne']: + qs._filters['filter-operator'] = op return qs def _get_results_from_wcs(self): diff --git a/publik_django_templatetags/wcs/templatetags/wcs.py b/publik_django_templatetags/wcs/templatetags/wcs.py index eb18ddf..4fe9a68 100644 --- a/publik_django_templatetags/wcs/templatetags/wcs.py +++ b/publik_django_templatetags/wcs/templatetags/wcs.py @@ -74,6 +74,36 @@ def filter_by_status(queryset, status): return queryset.filter_by_status(status) +@register.filter(name='equal') +def eq(queryset): + return queryset.apply_eq() + + +@register.filter(name='not_equal') +def ne(queryset): + return queryset.apply_ne() + + +@register.filter(name='less_than') +def lt(queryset): + return queryset.apply_lt() + + +@register.filter(name='less_than_or_equal') +def lte(queryset): + return queryset.apply_lte() + + +@register.filter(name='greater_than') +def gt(queryset): + return queryset.apply_gt() + + +@register.filter(name='greater_than_or_equal') +def gte(queryset): + return queryset.apply_gte() + + @register.filter def order_by(queryset, attribute): return queryset.order_by(attribute) diff --git a/tests/test_wcs.py b/tests/test_wcs.py index 98fb55a..611c42d 100644 --- a/tests/test_wcs.py +++ b/tests/test_wcs.py @@ -236,6 +236,16 @@ def test_count(mock_send, context, nocache): assert t.render(context) == "2" +OPERATORS = [ + ('equal', 'eq'), + ('not_equal', 'ne'), + ('less_than', 'lt'), + ('less_than_or_equal', 'lte'), + ('greater_than', 'gt'), + ('greater_than_or_equal', 'gte'), +] + + @mock.patch('requests.Session.send', side_effect=mocked_requests_send) def test_filter(mock_send, context, nocache): t = Template('{{ cards|objects:"foo"|filter_by:"foo"|filter_value:"bar"|list }}') @@ -266,6 +276,13 @@ def test_filter(mock_send, context, nocache): t.render(context) assert 'filter-foo=&' in mock_send.call_args_list[0][0][0].url + for filter_op, api_op in OPERATORS: + mock_send.reset_mock() + t = Template('{{ cards|objects:"foo"|filter_by:"foo"|%s|filter_value:"bar"|list }}' % filter_op) + t.render(context) + assert 'filter-foo=bar&' in mock_send.call_args_list[0][0][0].url + assert 'filter-foo-operator=%s&' % api_op in mock_send.call_args_list[0][0][0].url + @mock.patch('requests.Session.send', side_effect=mocked_requests_send) def test_filter_by_internal_id(mock_send, context, nocache): @@ -273,20 +290,30 @@ def test_filter_by_internal_id(mock_send, context, nocache): t.render(context) assert 'filter-internal-id' not in mock_send.call_args_list[0][0][0].url - mock_send.reset_mock() - t = Template('{{ cards|objects:"foo"|filter_by_internal_id:None|list }}') - t.render(context) - assert 'filter-internal-id' not in mock_send.call_args_list[0][0][0].url + for tpl in ['filter_by_internal_id', 'filter_by:"internal_id"|filter_value']: + mock_send.reset_mock() + t = Template('{{ cards|objects:"foo"|%s:None|list }}' % tpl) + t.render(context) + assert 'filter-internal-id' not in mock_send.call_args_list[0][0][0].url - mock_send.reset_mock() - t = Template('{{ cards|objects:"foo"|filter_by_internal_id:""|list }}') - t.render(context) - assert 'filter-internal-id' not in mock_send.call_args_list[0][0][0].url + mock_send.reset_mock() + t = Template('{{ cards|objects:"foo"|%s:""|list }}' % tpl) + t.render(context) + assert 'filter-internal-id' not in mock_send.call_args_list[0][0][0].url - mock_send.reset_mock() - t = Template('{{ cards|objects:"foo"|filter_by_internal_id:"42"|list }}') - t.render(context) - assert 'filter-internal-id=42&' in mock_send.call_args_list[0][0][0].url + mock_send.reset_mock() + t = Template('{{ cards|objects:"foo"|%s:"42"|list }}' % tpl) + t.render(context) + assert 'filter-internal-id=42&' in mock_send.call_args_list[0][0][0].url + + for filter_op, api_op in OPERATORS: + mock_send.reset_mock() + t = Template( + '{{ cards|objects:"foo"|filter_by:"internal_id"|%s|filter_value:"42"|list }}' % filter_op + ) + t.render(context) + assert 'filter-internal-id=42&' in mock_send.call_args_list[0][0][0].url + assert 'filter-internal-id-operator=%s&' % api_op in mock_send.call_args_list[0][0][0].url @mock.patch('requests.Session.send', side_effect=mocked_requests_send) @@ -295,42 +322,64 @@ def test_filter_by_number(mock_send, context, nocache): t.render(context) assert 'filter-number' not in mock_send.call_args_list[0][0][0].url - mock_send.reset_mock() - t = Template('{{ cards|objects:"foo"|filter_by_number:None|list }}') - t.render(context) - assert 'filter-number' not in mock_send.call_args_list[0][0][0].url + for tpl in ['filter_by_number', 'filter_by:"number"|filter_value']: + mock_send.reset_mock() + t = Template('{{ cards|objects:"foo"|%s:None|list }}' % tpl) + t.render(context) + assert 'filter-number' not in mock_send.call_args_list[0][0][0].url - mock_send.reset_mock() - t = Template('{{ cards|objects:"foo"|filter_by_number:""|list }}') - t.render(context) - assert 'filter-number' not in mock_send.call_args_list[0][0][0].url + mock_send.reset_mock() + t = Template('{{ cards|objects:"foo"|%s:""|list }}' % tpl) + t.render(context) + assert 'filter-number' not in mock_send.call_args_list[0][0][0].url - mock_send.reset_mock() - t = Template('{{ cards|objects:"foo"|filter_by_number:"42-35"|list }}') - t.render(context) - assert 'filter-number=42-35&' in mock_send.call_args_list[0][0][0].url + mock_send.reset_mock() + t = Template('{{ cards|objects:"foo"|%s:"42-35"|list }}' % tpl) + t.render(context) + assert 'filter-number=42-35&' in mock_send.call_args_list[0][0][0].url + + for filter_op, api_op in OPERATORS: + mock_send.reset_mock() + t = Template('{{ cards|objects:"foo"|filter_by:"number"|%s|filter_value:"42-35"|list }}' % filter_op) + t.render(context) + assert 'filter-number=42-35&' in mock_send.call_args_list[0][0][0].url + # not for this filter + assert 'filter-number-operator=%s&' % api_op not in mock_send.call_args_list[0][0][0].url @mock.patch('requests.Session.send', side_effect=mocked_requests_send) def test_filter_by_user(mock_send, context, nocache): - t = Template('{{ cards|objects:"foo"|filter_by_user:request.user|list }}') - t.render(context) - assert 'filter-user-uuid' not in mock_send.call_args_list[0][0][0].url + for tpl in ['filter_by_user', 'filter_by:"user"|filter_value']: + t = Template('{{ cards|objects:"foo"|%s:request.user|list }}' % tpl) + mock_send.reset_mock() + context['request'].user = None + t.render(context) + assert 'filter-user-uuid' not in mock_send.call_args_list[0][0][0].url - context['request'].user = MockAnonymousUser() - mock_send.reset_mock() - t.render(context) - assert 'filter-user-uuid' not in mock_send.call_args_list[0][0][0].url + context['request'].user = MockAnonymousUser() + mock_send.reset_mock() + t.render(context) + assert 'filter-user-uuid' not in mock_send.call_args_list[0][0][0].url - context['request'].user = MockUser() - mock_send.reset_mock() - t.render(context) - assert 'filter-user-uuid' not in mock_send.call_args_list[0][0][0].url + context['request'].user = MockUser() + mock_send.reset_mock() + t.render(context) + assert 'filter-user-uuid' not in mock_send.call_args_list[0][0][0].url - context['request'].user = MockUserWithNameId() - mock_send.reset_mock() - t.render(context) - assert 'filter-user-uuid=xyz&' in mock_send.call_args_list[0][0][0].url + context['request'].user = MockUserWithNameId() + mock_send.reset_mock() + t.render(context) + assert 'filter-user-uuid=xyz&' in mock_send.call_args_list[0][0][0].url + + for filter_op, api_op in OPERATORS: + mock_send.reset_mock() + t = Template( + '{{ cards|objects:"foo"|filter_by:"user"|%s|filter_value:request.user|list }}' % filter_op + ) + t.render(context) + assert 'filter-user-uuid=xyz&' in mock_send.call_args_list[0][0][0].url + # not for this filter + assert 'filter-user-uuid-operator=%s&' % api_op not in mock_send.call_args_list[0][0][0].url @mock.patch('requests.Session.send', side_effect=mocked_requests_send) @@ -338,21 +387,36 @@ def test_filter_by_status(mock_send, context, nocache): t = Template('{{ cards|objects:"foo"|list }}') t.render(context) assert 'filter=&' not in mock_send.call_args_list[0][0][0].url + assert 'filter-operator=eq&' not in mock_send.call_args_list[0][0][0].url - mock_send.reset_mock() - t = Template('{{ cards|objects:"foo"|filter_by_status:None|list }}') - t.render(context) - assert 'filter=&' not in mock_send.call_args_list[0][0][0].url + for tpl in ['filter_by_status', 'filter_by:"status"|filter_value']: + mock_send.reset_mock() + t = Template('{{ cards|objects:"foo"|%s:None|list }}' % tpl) + t.render(context) + assert 'filter=&' not in mock_send.call_args_list[0][0][0].url + assert 'filter-operator=eq&' not in mock_send.call_args_list[0][0][0].url - mock_send.reset_mock() - t = Template('{{ cards|objects:"foo"|filter_by_status:""|list }}') - t.render(context) - assert 'filter=&' not in mock_send.call_args_list[0][0][0].url + mock_send.reset_mock() + t = Template('{{ cards|objects:"foo"|%s:""|list }}' % tpl) + t.render(context) + assert 'filter=&' not in mock_send.call_args_list[0][0][0].url + assert 'filter-operator=eq&' not in mock_send.call_args_list[0][0][0].url - mock_send.reset_mock() - t = Template('{{ cards|objects:"foo"|filter_by_status:"foobar"|list }}') - t.render(context) - assert 'filter=foobar&' in mock_send.call_args_list[0][0][0].url + mock_send.reset_mock() + t = Template('{{ cards|objects:"foo"|%s:"foobar"|list }}' % tpl) + t.render(context) + assert 'filter=foobar&' in mock_send.call_args_list[0][0][0].url + assert 'filter-operator=eq&' in mock_send.call_args_list[0][0][0].url + + for filter_op, api_op in OPERATORS: + mock_send.reset_mock() + t = Template('{{ cards|objects:"foo"|filter_by:"status"|%s|filter_value:"foobar"|list }}' % filter_op) + t.render(context) + assert 'filter=foobar&' in mock_send.call_args_list[0][0][0].url + if api_op in ['eq', 'ne']: + assert 'filter-operator=%s&' % api_op in mock_send.call_args_list[0][0][0].url + else: + assert 'filter-operator=%s&' % api_op not in mock_send.call_args_list[0][0][0].url @mock.patch('requests.Session.send', side_effect=mocked_requests_send)