From 28da56ec85c3a6c36abaa71bc462a7c77f201f44 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Laur=C3=A9line=20Gu=C3=A9rin?= <zebuline@entrouvert.com>
Date: Fri, 4 Dec 2020 10:35:27 +0100
Subject: [PATCH] misc: add |get_auto_geoloc filter (#49079)

---
 tests/test_formdata.py            | 63 ++++++++++++++++++++++++++-----
 wcs/qommon/templatetags/qommon.py |  5 +++
 wcs/variables.py                  | 21 ++++++++---
 3 files changed, 73 insertions(+), 16 deletions(-)

diff --git a/tests/test_formdata.py b/tests/test_formdata.py
index 76a9599c..2d501176 100644
--- a/tests/test_formdata.py
+++ b/tests/test_formdata.py
@@ -927,31 +927,61 @@ def test_lazy_formdata_queryset(pub, variable_test_data):
 
 
 def test_lazy_formdata_queryset_distance(pub, variable_test_data):
+    # Form
     lazy_formdata = variable_test_data
     formdef = lazy_formdata._formdef
     formdef.geolocations = {'base': 'Base'}
     formdef.store()
     data_class = lazy_formdata._formdef.data_class()
+    # Card
+    CardDef.wipe()
+    carddef = CardDef()
+    carddef.name = 'items'
+    carddef.fields = []
+    carddef.geolocations = {'base': 'Base'}
+    carddef.store()
+    carddata_class = carddef.data_class()
+    carddata_class.wipe()
+
+    # create initial carddata like lazy_formdata, with same geolocations
+    carddata = carddata_class()
+    carddata.geolocations = {'base': {'lat': 1, 'lon': 2}}
+    carddata.just_created()
+    carddata.store()
+    lazy_carddata = LazyFormData(carddata)
+
+    # create objects
     for i in range(6):
-        formdata = data_class()
-        formdata.geolocations = {'base': {'lat': i, 'lon': i}}
-        formdata.just_created()
-        formdata.store()
+        for dclass in [data_class, carddata_class]:
+            data = dclass()
+            data.geolocations = {'base': {'lat': i, 'lon': i}}
+            data.just_created()
+            data.store()
     for i in range(4):
-        formdata = data_class()
-        formdata.geolocations = {'base': {'lat': i + 0.5, 'lon': i + 0.5}}
-        formdata.just_created()
-        formdata.jump_status('finished')
-        formdata.store()
-
+        for dclass in [data_class, carddata_class]:
+            data = dclass()
+            data.geolocations = {'base': {'lat': i + 0.5, 'lon': i + 0.5}}
+            data.just_created()
+            data.jump_status('finished')
+            data.store()
+
+    # drafts
     formdata = data_class()
     formdata.status = 'draft'
+    formdata.geolocations = {'base': {'lat': 1, 'lon': 2}}
     formdata.store()
+    carddata = carddata_class()
+    carddata.status = 'draft'
+    carddata.geolocations = {'base': {'lat': 1, 'lon': 2}}
+    carddata.store()
 
     # compute distance against map field of lazy formdata
     nearby = lazy_formdata.objects.distance_filter(200000)
     assert len(nearby) == 6
     assert set([x.number for x in nearby]) == set(['1-1', '1-3', '1-4', '1-8', '1-9', '1-10'])
+    nearby = lazy_carddata.objects.set_geo_center(lazy_formdata).distance_filter(200000)
+    assert len(nearby) == 6
+    assert set([x.number for x in nearby]) == set(['1-1', '1-3', '1-4', '1-8', '1-9', '1-10'])
 
     # compute distance against geolocation
     lazy_formdata._formdata.geolocations = {'base': {'lat': 2, 'lon': 2.5}}
@@ -959,16 +989,29 @@ def test_lazy_formdata_queryset_distance(pub, variable_test_data):
     assert len(nearby) == 6
     assert set([x.number for x in nearby]) == set(['1-1', '1-4', '1-5', '1-9', '1-10', '1-11'])
     assert bool(nearby) is True
+    nearby = lazy_carddata.objects.set_geo_center(lazy_formdata).distance_filter(200000)
+    assert len(nearby) == 6
+    assert set([x.number for x in nearby]) == set(['1-1', '1-4', '1-5', '1-9', '1-10', '1-11'])
+    assert bool(nearby) is True
+
     context = pub.substitutions.get_context_variables(mode='lazy')
     tmpl = Template('{{form_objects|distance_filter:200000|count}}')
     assert tmpl.render(context) == '6'
+    tmpl = Template('{{cards|objects:"items"|set_geo_center:form|distance_filter:200000|count}}')
+    assert tmpl.render(context) == '6'
 
     lazy_formdata._formdata.geolocations = {'base': {'lat': 7, 'lon': 7.5}}
     nearby = lazy_formdata.objects.distance_filter(200000)
     assert bool(nearby) is False
     assert len(nearby) == 0
+    nearby = lazy_carddata.objects.set_geo_center(lazy_formdata).distance_filter(200000)
+    assert bool(nearby) is False
+    assert len(nearby) == 0
+
     tmpl = Template('{{form_objects|distance_filter:200000|count}}')
     assert tmpl.render(context) == '0'
+    tmpl = Template('{{cards|objects:"items"|set_geo_center:form|distance_filter:200000|count}}')
+    assert tmpl.render(context) == '0'
 
 
 def test_lazy_formdata_queryset_filter(pub, variable_test_data):
diff --git a/wcs/qommon/templatetags/qommon.py b/wcs/qommon/templatetags/qommon.py
index e0f532ce..97c53bf0 100644
--- a/wcs/qommon/templatetags/qommon.py
+++ b/wcs/qommon/templatetags/qommon.py
@@ -564,6 +564,11 @@ def distance(obj1, obj2):
     return distance
 
 
+@register.filter
+def set_geo_center(queryset, lazy_formdata):
+    return queryset.set_geo_center(lazy_formdata)
+
+
 @register.filter
 def distance_filter(queryset, distance=1000):
     if hasattr(distance, 'get_value'):
diff --git a/wcs/variables.py b/wcs/variables.py
index 0667d42a..9ba9260f 100644
--- a/wcs/variables.py
+++ b/wcs/variables.py
@@ -35,9 +35,10 @@ from .formdef import FormDef
 
 
 class LazyFormDefObjectsManager(object):
-    def __init__(self, formdef, formdata=None, criterias=None, order_by=None):
+    def __init__(self, formdef, formdata=None, geoloc_center_formdata=None, criterias=None, order_by=None):
         self._formdef = formdef
         self._formdata = formdata
+        self._geoloc_center_formdata = geoloc_center_formdata
         if criterias is None:
             criterias = [
                 NotEqual('status', 'draft'),
@@ -57,9 +58,10 @@ class LazyFormDefObjectsManager(object):
 
     def _clone(self, criterias, order_by=None):
         return LazyFormDefObjectsManager(
-                self._formdef,
-                self._formdata,
-                criterias,
+                formdef=self._formdef,
+                formdata=self._formdata,
+                geoloc_center_formdata=self._geoloc_center_formdata,
+                criterias=criterias,
                 order_by=order_by or self._order_by)
 
     def order_by(self, attribute):
@@ -132,17 +134,24 @@ class LazyFormDefObjectsManager(object):
         criterias = [Or([Equal('status', x) for x in status_filters])]
         return self._clone(self._criterias + criterias)
 
+    def set_geo_center(self, lazy_formdata):
+        qs = self._clone(self._criterias)
+        qs._geoloc_center_formdata = lazy_formdata._formdata
+        return qs
+
     def distance_filter(self, distance):
         geod = Geod(ellps='WGS84')
-        center = self._formdata.get_auto_geoloc()
+        center = (self._geoloc_center_formdata or self._formdata).get_auto_geoloc()
         center_lon, center_lat = center['lon'], center['lat']
+
         def distance_check(obj):
             geoloc = obj.get_auto_geoloc()
             if not geoloc:
                 return False
             # keep computed distance in object
-            obj._distance  = geod.inv(center_lon, center_lat, geoloc['lon'], geoloc['lat'])[2]
+            obj._distance = geod.inv(center_lon, center_lat, geoloc['lon'], geoloc['lat'])[2]
             return bool(obj._distance < distance)
+
         return self._clone(self._criterias + [distance_check])
 
     def filter_by(self, attribute):
-- 
2.28.0

