From 4b16a942625d50af4d25b194a593c6b8406c94be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= Date: Tue, 29 Nov 2022 10:54:31 +0100 Subject: [PATCH] wcs: add distance filters (#70588) --- .../wcs/context_processors.py | 27 +++++++++++++-- .../wcs/templatetags/wcs.py | 24 ++++++++++++++ tests/test_wcs.py | 33 +++++++++++++++++++ 3 files changed, 82 insertions(+), 2 deletions(-) diff --git a/publik_django_templatetags/wcs/context_processors.py b/publik_django_templatetags/wcs/context_processors.py index 2338936..30c24a0 100644 --- a/publik_django_templatetags/wcs/context_processors.py +++ b/publik_django_templatetags/wcs/context_processors.py @@ -33,13 +33,16 @@ def get_default_wcs_service_key(): class LazyCardDefObjectsManager: - def __init__(self, service_key, card_id, custom_view_id=None, filters=None, user=Ellipsis): + def __init__( + self, service_key, card_id, custom_view_id=None, filters=None, geo_center=None, user=Ellipsis + ): self._service_key = service_key self._card_id = card_id self._custom_view_id = custom_view_id self._filters = filters or {} self._user = user + self._geo_center = geo_center or {} self._cached_resultset = None @@ -49,6 +52,7 @@ class LazyCardDefObjectsManager: card_id=self._card_id, custom_view_id=self._custom_view_id, filters=self._filters, + geo_center=self._geo_center, user=self._user, ) @@ -121,7 +125,7 @@ class LazyCardDefObjectsManager: if isinstance(value, bool): value = str(value).lower() op = getattr(self, 'pending_op', 'eq') - if self.pending_attr in ['internal_id', 'number', 'user', 'status']: + if self.pending_attr in ['internal_id', 'number', 'user', 'status', 'distance']: 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 @@ -176,6 +180,23 @@ class LazyCardDefObjectsManager: qs._filters['filter-operator'] = op return qs + def filter_by_distance(self, distance, op=None): + # distance do not currently support an operator + qs = self._clone() + if distance: + qs._filters['filter-distance'] = distance + return qs + + def set_geo_center_lat(self, lat): + qs = self._clone() + qs._geo_center['center_lat'] = lat + return qs + + def set_geo_center_lon(self, lon): + qs = self._clone() + qs._geo_center['center_lon'] = lon + return qs + def _get_results_from_wcs(self): service = get_wcs_services().get(self._service_key) if not service: @@ -187,6 +208,8 @@ class LazyCardDefObjectsManager: if self._filters: query = urlencode(self._filters) api_url += '?%s' % query + if 'center_lat' in self._geo_center and 'center_lon' in self._geo_center: + api_url += '&' + urlencode(self._geo_center) without_user = self._user is Ellipsis # not set try: response = requests.get( diff --git a/publik_django_templatetags/wcs/templatetags/wcs.py b/publik_django_templatetags/wcs/templatetags/wcs.py index a9ea314..c8b25f7 100644 --- a/publik_django_templatetags/wcs/templatetags/wcs.py +++ b/publik_django_templatetags/wcs/templatetags/wcs.py @@ -209,3 +209,27 @@ def order_by(queryset, attribute): return queryset.order_by(attribute) except AttributeError: return None + + +@register.filter +def filter_by_distance(queryset, distance): + try: + return queryset.filter_by_distance(distance) + except AttributeError: + return None + + +@register.filter +def set_geo_center_lat(queryset, lat): + try: + return queryset.set_geo_center_lat(lat) + except AttributeError: + return None + + +@register.filter +def set_geo_center_lon(queryset, lon): + try: + return queryset.set_geo_center_lon(lon) + except AttributeError: + return None diff --git a/tests/test_wcs.py b/tests/test_wcs.py index da4400f..9d33041 100644 --- a/tests/test_wcs.py +++ b/tests/test_wcs.py @@ -507,6 +507,39 @@ def test_filter_by_status(mock_send, context, nocache): assert mock_send.call_args_list == [] +@mock.patch('requests.Session.send', side_effect=mocked_requests_send) +def test_filter_by_distance(mock_send, context, nocache): + t = Template('{{ cards|objects:"foo"|list }}') + t.render(context) + assert 'filter-distance=&' not in mock_send.call_args_list[0][0][0].url + + for tpl in ['filter_by_distance', 'filter_by:"distance"|filter_value']: + mock_send.reset_mock() + t = Template('{{ cards|objects:"foo"|%s:None|list }}' % tpl) + t.render(context) + assert 'filter-distance=&' 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-distance=&' not in mock_send.call_args_list[0][0][0].url + + mock_send.reset_mock() + t = Template('{{ cards|objects:"foo"|%s:"10000"|list }}' % tpl) + t.render(context) + assert 'filter-distance=&' not in mock_send.call_args_list[0][0][0].url + + mock_send.reset_mock() + t = Template( + '{{ cards|objects:"foo"|set_geo_center_lat:1|set_geo_center_lon:2|%s:"10000"|list }}' % tpl + ) + t.render(context) + assert 'center_lat=1&' in mock_send.call_args_list[0][0][0].url + assert 'center_lon=2&' in mock_send.call_args_list[0][0][0].url + assert 'filter-distance=10000&' in mock_send.call_args_list[0][0][0].url + assert 'filter-distance-operator' not in mock_send.call_args_list[0][0][0].url + + @mock.patch('requests.Session.send', side_effect=mocked_requests_send) def test_getlist(mock_send, context, nocache): t = Template('{% for v in cards|objects:"foo"|getlist:"id" %}{{ v }},{% endfor %}')