Projet

Général

Profil

0001-maps-geojson-url-per-geojson-layer-40742.patch

Lauréline Guérin, 16 avril 2020 16:58

Télécharger (30,4 ko)

Voir les différences:

Subject: [PATCH] maps: geojson url per geojson layer (#40742)

 combo/apps/maps/models.py                    |  39 +++---
 combo/apps/maps/static/js/combo.map.js       |  94 +++++++-------
 combo/apps/maps/templates/maps/map_cell.html |   9 +-
 combo/apps/maps/urls.py                      |   2 +-
 combo/apps/maps/views.py                     |  24 ++--
 tests/test_maps_cells.py                     | 121 +++++++++++--------
 tests/test_maps_manager.py                   |   4 +-
 7 files changed, 162 insertions(+), 131 deletions(-)
combo/apps/maps/models.py
178 178
        layer = next(serializers.deserialize('json', json.dumps([json_layer]), ignorenonexistent=True))
179 179
        layer.save()
180 180

  
181
    def get_geojson(self, request=None, multiple_layers=False):
181
    def get_geojson(self, request):
182 182
        geojson_url = get_templated_url(self.geojson_url)
183
        response = requests.get(geojson_url,
184
                            remote_service='auto',
185
                            cache_duration=self.cache_duration,
186
                            user=request.user if (request and self.include_user_identifier) else None,
187
                            without_user=not(self.include_user_identifier),
188
                            headers={'accept': 'application/json'})
183
        response = requests.get(
184
            geojson_url,
185
            remote_service='auto',
186
            cache_duration=self.cache_duration,
187
            user=request.user if (request and self.include_user_identifier) else None,
188
            without_user=not(self.include_user_identifier),
189
            headers={'accept': 'application/json'})
189 190
        if not response.ok:
190 191
            return []
191 192
        data = response.json()
......
230 231
            # all words must match
231 232
            query_words = [slugify(x) for x in request.GET['q'].split()]
232 233

  
233
            additional_strings = []
234
            if multiple_layers:  # also match on layer name
235
                additional_strings = [self.label]
236

  
237 234
            def match(feature):
238 235
                matching_query_words = set()
239
                feature_words = additional_strings[:]
236
                feature_words = [self.label]
240 237

  
241 238
                def get_feature_words(properties):
242 239
                    for property in properties.values():
......
266 263
                'identifier': self.slug,
267 264
                'properties': properties,
268 265
            }
269
        return features
266
        return {'type': 'FeatureCollection', 'features': features}
270 267

  
271 268

  
272 269
@register_cell_class
......
319 316
                  'max_zoom', 'group_markers', 'marker_behaviour_onclick')
320 317
        return forms.models.modelform_factory(self.__class__, fields=fields)
321 318

  
322
    def get_geojson(self, request):
323
        geojson = {'type': 'FeatureCollection', 'features': []}
324
        layers = self.layers.filter(kind='geojson')
325
        for layer in layers:
326
            geojson['features'] += layer.get_geojson(request,
327
                    multiple_layers=bool(len(layers) > 1))
328
        return geojson
329

  
330 319
    @classmethod
331 320
    def is_enabled(cls):
332 321
        return MapLayer.objects.exists()
......
363 352
            })
364 353
        return tiles_layers
365 354

  
355
    def get_geojson_layers(self):
356
        if not self.pk:
357
            return []
358
        return [{'url': reverse_lazy('mapcell-geojson', kwargs={'cell_id': self.pk, 'layer_slug': l.slug}),
359
                 'slug': l.slug} for l in self.layers.filter(kind='geojson')]
360

  
366 361
    def get_cell_extra_context(self, context):
367 362
        ctx = super(Map, self).get_cell_extra_context(context)
368 363
        ctx['title'] = self.title
......
373 368
        ctx['initial_zoom'] = self.initial_zoom
374 369
        ctx['min_zoom'] = self.min_zoom
375 370
        ctx['max_zoom'] = self.max_zoom
376
        ctx['geojson_url'] = reverse_lazy('mapcell-geojson', kwargs={'cell_id': self.pk})
371
        ctx['geojson_layers'] = self.get_geojson_layers()
377 372
        ctx['tiles_layers'] = self.get_tiles_layers()
378 373
        ctx['max_bounds'] = settings.COMBO_MAP_MAX_BOUNDS
379 374
        ctx['group_markers'] = self.group_markers
combo/apps/maps/static/js/combo.map.js
1 1
$(function() {
2 2
    L.Map.include(
3 3
      {
4
        add_geojson_layer: function(callback) {
4
        add_geojson_layer: function(callback, geojson_data) {
5 5
          var map = this;
6 6
          var $map_widget = $(map.getContainer());
7 7
          var cell = $map_widget.parents('div.cell')[0];
8
          var geojson_url = $map_widget.data('geojson-url');
9
          if (!geojson_url) return;
8
          var geojson_url = geojson_data.url;
10 9

  
11
          if (map.geojson_retrieval) {
12
             map.geojson_retrieval.abort();
13
          }
14

  
15
          map.geojson_retrieval = $.getJSON(geojson_url, function(data) {
10
          $.getJSON(geojson_url, function(data) {
16 11
              var geo_json = L.geoJson(data, {
17 12
                  onEachFeature: function(feature, layer) {
18 13
                      $(cell).trigger('combo:map-feature-prepare', {'feature': feature, 'layer': layer});
......
63 58
                      return L.marker(latlng, {icon: marker});
64 59
                  }
65 60
              });
66
              if (map.geo_json) map.geo_json.remove();
67
              map.geo_json = geo_json;
68 61
              if ($map_widget.data('group-markers')) {
69
                  if (! map.clustered_markers) {
70
                    map.clustered_markers = L.markerClusterGroup({showCoverageOnHover: false,
71
                                          zoomToBoundsOnClick: true,
72
                                          removeOutsideVisibleBounds: true,
73
                                          iconCreateFunction: function (cluster) {
74
                                              var icon_size = 60;
75
                                              var childCount = cluster.getChildCount();
76
                                              var icon_html = '<div><span>' + childCount + '</span></div>';
77
                                              var c = ' marker-cluster-';
78
                                              if (childCount < 10) {
79
                                                  c += 'small';
80
                                              } else if (childCount < 100) {
81
                                                  c += 'medium';
82
                                              } else {
83
                                                  c += 'large';
84
                                              }
85
                                              return new L.DivIcon({html: icon_html, className: 'marker-cluster' + c, iconSize: new L.Point(icon_size, icon_size)});
86
                                              }});
87
                    map.addLayer(map.clustered_markers);
62
                  if (map.geojson_layers[geojson_data.slug]) {
63
                      map.clustered_markers.removeLayer(map.geojson_layers[geojson_data.slug]);
88 64
                  }
89
                  map.clustered_markers.eachLayer(
90
                    function(layer) {
91
                       map.clustered_markers.removeLayer(layer);
92
                    }
93
                  );
94 65
                  map.clustered_markers.addLayer(geo_json);
95 66
              } else {
67
                  if (map.geojson_layers[geojson_data.slug]) {
68
                      map.geojson_layers[geojson_data.slug].remove();
69
                  }
96 70
                  geo_json.addTo(map);
97 71
              }
72
              map.geojson_layers[geojson_data.slug] = geo_json;
98 73
              if (callback) {
99 74
                  callback(geo_json);
100 75
              }
......
123 98
        if (!isNaN(min_zoom)) map_options.minZoom = min_zoom;
124 99
        map_options.zoomControl = false;
125 100
        var latlng = [$map_widget.data('init-lat'), $map_widget.data('init-lng')];
126
        var geojson_url = $map_widget.data('geojson-url');
127 101
        if ($map_widget.data('max-bounds-lat1')) {
128 102
          map_options.maxBounds = L.latLngBounds(
129 103
                  L.latLng($map_widget.data('max-bounds-lat1'), $map_widget.data('max-bounds-lng1')),
......
131 105
        }
132 106
        map_options.gestureHandling = true;
133 107
        var map = L.map($map_widget[0], map_options);
108
        if ($map_widget.data('group-markers')) {
109
            map.clustered_markers = L.markerClusterGroup({
110
                showCoverageOnHover: false,
111
                zoomToBoundsOnClick: true,
112
                removeOutsideVisibleBounds: true,
113
                iconCreateFunction: function (cluster) {
114
                    var icon_size = 60;
115
                    var childCount = cluster.getChildCount();
116
                    var icon_html = '<div><span>' + childCount + '</span></div>';
117
                    var c = ' marker-cluster-';
118
                    if (childCount < 10) {
119
                        c += 'small';
120
                    } else if (childCount < 100) {
121
                        c += 'medium';
122
                    } else {
123
                        c += 'large';
124
                    }
125
                    return new L.DivIcon({html: icon_html, className: 'marker-cluster' + c, iconSize: new L.Point(icon_size, icon_size)});
126
                }
127
            });
128
            map.addLayer(map.clustered_markers);
129
        }
130
        map.geojson_layers = Object();
134 131
        if ($map_widget.data('draggable') === false) {
135 132
          map.dragging.disable();
136 133
        }
......
185 182
                }
186 183
            ).addTo(map);
187 184
        });
188
        if (geojson_url) {
189
            map.add_geojson_layer(function(geo_json) {
190
                var bounds = geo_json.getBounds();
191
                if (bounds.isValid()) {
192
                    if (init_state == 'fit-markers') {
193
                        map.fitBounds(bounds);
185
        map.bounds = null;
186
        map.geojson_layers_loaded = 0;
187
        var geojson_layers = window['geojson_'+map_id];
188
        if (geojson_layers.length) {
189
            $.each(geojson_layers, function(idx, geojson_data) {
190
                map.add_geojson_layer(function(geo_json) {
191
                    var bounds = geo_json.getBounds();
192
                    if (bounds.isValid()) {
193
                        if (!map.bounds) {
194
                            map.bounds = L.latLngBounds(bounds);
195
                        } else {
196
                            map.bounds.extend(bounds);
197
                        }
198
                        if (init_state == 'fit-markers') {
199
                            map.fitBounds(map.bounds);
200
                        }
194 201
                    }
202
                }, geojson_data);
203
                map.geojson_layers_loaded += 1;
204
                if (map.geojson_layers_loaded == geojson_layers.length) {
205
                    $(cell).trigger('combo:map-ready');
195 206
                }
196
                $(cell).trigger('combo:map-ready');
197 207
            });
198 208
        } else {
199 209
            $(cell).trigger('combo:map-ready');
combo/apps/maps/templates/maps/map_cell.html
5 5
<div class="combo-cell-map" data-init-state="{{ initial_state }}"
6 6
        data-init-zoom="{{ initial_zoom }}" data-min-zoom="{{ min_zoom }}"
7 7
        data-max-zoom="{{ max_zoom }}" data-init-lat="{{ init_lat }}"
8
        data-init-lng="{{ init_lng }}" data-geojson-url="{{ geojson_url }}"
8
        data-init-lng="{{ init_lng }}"
9 9
        data-include-geoloc-button="true"
10 10
        {% if group_markers %}data-group-markers="1"{% endif %}
11 11
        data-marker-behaviour-onclick="{{ cell.marker_behaviour_onclick }}"
......
27 27
      opacity: {{ layer.opacity|as_json|safe }}
28 28
    });
29 29
  {% endfor %}
30
  var geojson_{{ cell.pk }} = [];
31
  {% for layer in geojson_layers %}
32
  geojson_{{ cell.pk }}.push({
33
    url: '{{ layer.url }}',
34
    slug: '{{ layer.slug }}'
35
  });
36
  {% endfor %}
30 37
</script>
31 38
</div>
32 39
{% endblock %}
combo/apps/maps/urls.py
43 43
urlpatterns = [
44 44
    url(r'^manage/maps/', decorated_includes(manager_required,
45 45
        include(maps_manager_urls))),
46
    url(r'^ajax/mapcell/geojson/(?P<cell_id>\w+)/$', GeojsonView.as_view(),
46
    url(r'^ajax/mapcell/geojson/(?P<cell_id>\d+)/(?P<layer_slug>[\w-]+)/$', GeojsonView.as_view(),
47 47
        name='mapcell-geojson'),
48 48
]
combo/apps/maps/views.py
16 16

  
17 17
import json
18 18

  
19
from django.http import HttpResponse, HttpResponseForbidden
20
from django.shortcuts import get_object_or_404
19 21
from django.views.generic.base import View
20
from django.http import HttpResponse, Http404, HttpResponseForbidden
21 22

  
22 23
from .models import Map
23 24

  
......
25 26
class GeojsonView(View):
26 27

  
27 28
    def get(self, request, *args, **kwargs):
28
        try:
29
            cell = Map.objects.get(pk=kwargs['cell_id'])
30
        except Map.DoesNotExist:
31
            raise Http404()
32
        if cell.page.is_visible(request.user) and cell.is_visible(user=request.user):
33
            geojson = cell.get_geojson(request)
34
            content_type = 'application/json'
35
            return HttpResponse(json.dumps(geojson), content_type=content_type)
36
        return HttpResponseForbidden()
29
        cell = get_object_or_404(
30
            Map,
31
            pk=kwargs['cell_id'])
32
        layer = get_object_or_404(
33
            cell.layers.all(),
34
            kind='geojson',
35
            slug=kwargs['layer_slug'])
36
        if not cell.page.is_visible(request.user) or not cell.is_visible(user=request.user):
37
            return HttpResponseForbidden()
38
        geojson = layer.get_geojson(request)
39
        content_type = 'application/json'
40
        return HttpResponse(json.dumps(geojson), content_type=content_type)
tests/test_maps_cells.py
129 129
    MapLayer.objects.all().delete()
130 130
    assert Map.is_enabled() is False
131 131

  
132

  
132 133
def test_cell_enabled(layer):
133 134
    assert Map.is_enabled() is True
134 135

  
136

  
135 137
def test_cell_rendering(app, layer, tiles_layer):
136 138
    page = Page(title='xxx', slug='test_map_cell', template_name='standard')
137 139
    page.save()
138 140
    cell = Map(page=page, placeholder='content', order=0, title='Map with points')
139 141
    cell.save()
140
    options = MapLayerOptions.objects.create(map_cell=cell, map_layer=layer)
142
    MapLayerOptions.objects.create(map_cell=cell, map_layer=layer)
141 143
    context = {'request': RequestFactory().get('/')}
142 144
    rendered = cell.render(context)
143 145
    assert 'data-init-zoom="13"' in rendered
......
145 147
    assert 'data-max-zoom="19"' in rendered
146 148
    assert 'data-init-lat="48.83369263315934"' in rendered
147 149
    assert 'data-init-lng="2.3233688436448574"' in rendered
148
    assert 'data-geojson-url="/ajax/mapcell/geojson/1/"' in rendered
150
    assert '/ajax/mapcell/geojson/1/%s/' % layer.slug in rendered
149 151
    assert 'data-group-markers="1"' not in rendered
150 152
    resp = app.get('/test_map_cell/')
151 153
    assert 'xstatic/leaflet.js' in resp.text
......
214 216
    }]
215 217

  
216 218

  
219
def test_get_geojson_not_found(app, layer):
220
    page = Page.objects.create(title='xxx', slug='new', template_name='standard')
221
    cell = Map.objects.create(page=page, placeholder='content', order=0, title='Map with points')
222
    MapLayerOptions.objects.create(map_cell=cell, map_layer=layer)
223

  
224
    app.get(reverse('mapcell-geojson', kwargs={'cell_id': 0, 'layer_slug': layer.slug}), status=404)
225
    app.get(reverse('mapcell-geojson', kwargs={'cell_id': cell.pk, 'layer_slug': 'foo'}), status=404)
226

  
227

  
217 228
def test_get_geojson_on_non_public_page(app, layer):
218
    page = Page(title='xxx', slug='new', template_name='standard',
219
                public=False)
220
    page.save()
221
    cell = Map(page=page, placeholder='content', order=0,
222
                   title='Map with points')
223
    cell.save()
229
    page = Page.objects.create(title='xxx', slug='new', template_name='standard', public=False)
230
    cell = Map.objects.create(page=page, placeholder='content', order=0, title='Map with points')
224 231
    MapLayerOptions.objects.create(map_cell=cell, map_layer=layer)
225
    app.get(reverse('mapcell-geojson', kwargs={'cell_id': cell.id}), status=403)
232
    app.get(reverse('mapcell-geojson', kwargs={'cell_id': cell.id, 'layer_slug': layer.slug}), status=403)
233

  
226 234

  
227 235
def test_get_geojson_on_non_publik_cell(app, layer):
228
    page = Page(title='xxx', slug='new', template_name='standard')
229
    page.save()
230
    cell = Map(page=page, placeholder='content', order=0, public=False,
231
                   title='Map with points')
232
    cell.save()
236
    page = Page.objects.create(title='xxx', slug='new', template_name='standard')
237
    cell = Map.objects.create(page=page, placeholder='content', order=0, title='Map with points', public=False)
233 238
    MapLayerOptions.objects.create(map_cell=cell, map_layer=layer)
234
    app.get(reverse('mapcell-geojson', kwargs={'cell_id': cell.id}), status=403)
239
    app.get(reverse('mapcell-geojson', kwargs={'cell_id': cell.id, 'layer_slug': layer.slug}), status=403)
240

  
235 241

  
236 242
def test_geojson_on_restricted_cell(app, layer, user):
237
    page = Page(title='xxx', slug='new', template_name='standard')
238
    page.save()
243
    page = Page.objects.create(title='xxx', slug='new', template_name='standard')
239 244
    group = Group.objects.create(name='map tester')
240 245
    cell = Map(page=page, placeholder='content', order=0, public=False)
241
    cell.title = 'Map with points'
242
    cell.save()
246
    cell = Map.objects.create(page=page, placeholder='content', order=0, title='Map with points', public=False)
243 247
    MapLayerOptions.objects.create(map_cell=cell, map_layer=layer)
244 248
    cell.groups.add(group)
245 249
    login(app)
246
    app.get(reverse('mapcell-geojson', kwargs={'cell_id': cell.id}), status=403)
250
    app.get(reverse('mapcell-geojson', kwargs={'cell_id': cell.id, 'layer_slug': layer.slug}), status=403)
247 251
    user.groups.add(group)
248 252
    user.save()
249 253

  
......
252 256
                content=SAMPLE_GEOJSON_CONTENT,
253 257
                json=lambda: json.loads(SAMPLE_GEOJSON_CONTENT),
254 258
                status_code=200)
255
        resp = app.get(reverse('mapcell-geojson', kwargs={'cell_id': cell.id}))
259
        app.get(reverse('mapcell-geojson', kwargs={'cell_id': cell.id, 'layer_slug': layer.slug}))
260

  
256 261

  
257 262
def test_get_geojson(app, layer, user):
258 263
    page = Page(title='xxx', slug='new', template_name='standard')
......
264 269
    layer.save()
265 270
    MapLayerOptions.objects.create(map_cell=cell, map_layer=layer)
266 271

  
272
    geojson_url = reverse('mapcell-geojson', kwargs={'cell_id': cell.id, 'layer_slug': layer.slug})
273

  
267 274
    # check cache duration
268 275
    with mock.patch('combo.utils.requests_wrapper.RequestsSession.request') as requests_get:
269 276
        requests_get.return_value = mock.Mock(
270 277
                content=SAMPLE_GEOJSON_CONTENT,
271 278
                json=lambda: json.loads(SAMPLE_GEOJSON_CONTENT),
272 279
                status_code=200)
273
        resp = app.get(reverse('mapcell-geojson', kwargs={'cell_id': cell.id}))
280
        resp = app.get(geojson_url)
274 281
        assert len(json.loads(resp.text)['features']) == 2
275 282
        assert requests_get.call_count == 1
276
        resp = app.get(reverse('mapcell-geojson', kwargs={'cell_id': cell.id}))
277
        assert requests_get.call_count == 1 # cache was used
283
        resp = app.get(geojson_url)
284
        assert requests_get.call_count == 1  # cache was used
278 285
        layer.cache_duration = 0
279 286
        layer.save()
280
        resp = app.get(reverse('mapcell-geojson', kwargs={'cell_id': cell.id}))
281
        assert requests_get.call_count == 2 # cache was not used
287
        resp = app.get(geojson_url)
288
        assert requests_get.call_count == 2  # cache was not used
282 289

  
283 290
    # check user params
284 291
    layer.geojson_url = 'http://example.org/geojson?t2'
......
288 295
                content=SAMPLE_GEOJSON_CONTENT,
289 296
                json=lambda: json.loads(SAMPLE_GEOJSON_CONTENT),
290 297
                status_code=200)
291
        resp = app.get(reverse('mapcell-geojson', kwargs={'cell_id': cell.id}))
298
        resp = app.get(geojson_url)
292 299
        assert 'orig=combo' in requests_get.call_args[0][1]
293 300
        assert 'email=&' in requests_get.call_args[0][1]
294 301

  
......
300 307
                content=SAMPLE_GEOJSON_CONTENT,
301 308
                json=lambda: json.loads(SAMPLE_GEOJSON_CONTENT),
302 309
                status_code=200)
303
        resp = app.get(reverse('mapcell-geojson', kwargs={'cell_id': cell.id}))
310
        resp = app.get(geojson_url)
304 311
        assert 'orig=combo' in requests_get.call_args[0][1]
305 312
        assert 'email=admin%40localhost&' in requests_get.call_args[0][1]
306 313

  
......
312 319
                content=SAMPLE_GEOJSON_CONTENT,
313 320
                json=lambda: json.loads(SAMPLE_GEOJSON_CONTENT),
314 321
                status_code=200)
315
        resp = app.get(reverse('mapcell-geojson', kwargs={'cell_id': cell.id}))
322
        resp = app.get(geojson_url)
316 323
        assert 'orig=combo' in requests_get.call_args[0][1]
317
        assert not 'email=admin%40localhost&' in requests_get.call_args[0][1]
324
        assert 'email=admin%40localhost&' not in requests_get.call_args[0][1]
318 325

  
319 326
    # check query on geojson
320 327
    layer.geojson_url = 'http://example.org/geojson?t5'
......
325 332
                content=SAMPLE_GEOJSON_CONTENT,
326 333
                json=lambda: json.loads(SAMPLE_GEOJSON_CONTENT),
327 334
                status_code=200)
328
        resp = app.get(reverse('mapcell-geojson', kwargs={'cell_id': cell.id}) + '?q=bar')
335
        resp = app.get(geojson_url + '?q=bar')
329 336
        assert len(json.loads(resp.text)['features']) == 1
330 337
        assert 'orig=combo' in requests_get.call_args[0][1]
331
        assert not 'email=admin%40localhost&' in requests_get.call_args[0][1]
338
        assert 'email=admin%40localhost&' not in requests_get.call_args[0][1]
332 339

  
333 340
        # query against layer name
334
        resp = app.get(reverse('mapcell-geojson', kwargs={'cell_id': cell.id}) + '?q=bicycle')
335
        assert len(json.loads(resp.text)['features']) == 0
341
        resp = app.get(geojson_url + '?q=bicycle')
342
        assert len(json.loads(resp.text)['features']) == 2
336 343

  
337 344
        # query against subproperty
338
        resp = app.get(reverse('mapcell-geojson', kwargs={'cell_id': cell.id}) + '?q=whatever')
345
        resp = app.get(geojson_url + '?q=whatever')
339 346
        assert len(json.loads(resp.text)['features']) == 1
340 347

  
341 348
    # check distance query on geojson
......
347 354
                content=SAMPLE_GEOJSON_CONTENT,
348 355
                json=lambda: json.loads(SAMPLE_GEOJSON_CONTENT),
349 356
                status_code=200)
350
        resp = app.get(reverse('mapcell-geojson', kwargs={'cell_id': cell.id}) + '?lng=2.54&lat=48.84&distance=2000')
357
        resp = app.get(geojson_url + '?lng=2.54&lat=48.84&distance=2000')
351 358
        assert len(json.loads(resp.text)['features']) == 2
352 359

  
353
        resp = app.get(reverse('mapcell-geojson', kwargs={'cell_id': cell.id}) + '?lng=2.54&lat=48.84&distance=1000')
360
        resp = app.get(geojson_url + '?lng=2.54&lat=48.84&distance=1000')
354 361
        assert len(json.loads(resp.text)['features']) == 1
355 362

  
356
        resp = app.get(reverse('mapcell-geojson', kwargs={'cell_id': cell.id}) + '?lng=2.54&lat=48.84&distance=100')
363
        resp = app.get(geojson_url + '?lng=2.54&lat=48.84&distance=100')
357 364
        assert len(json.loads(resp.text)['features']) == 0
358 365

  
359 366
    # check on multiple words
......
362 369
                content=SAMPLE_GEOJSON_CONTENT,
363 370
                json=lambda: json.loads(SAMPLE_GEOJSON_CONTENT),
364 371
                status_code=200)
365
        resp = app.get(reverse('mapcell-geojson', kwargs={'cell_id': cell.id}) + '?q=bar baz')
372
        resp = app.get(geojson_url + '?q=bar baz')
366 373
        assert len(json.loads(resp.text)['features']) == 1
367 374

  
368
        resp = app.get(reverse('mapcell-geojson', kwargs={'cell_id': cell.id}) + '?q=quux baz')
375
        resp = app.get(geojson_url + '?q=quux baz')
369 376
        assert len(json.loads(resp.text)['features']) == 0
370 377

  
371 378
    # add a second layer
......
377 384
    layer2.icon_colour = '0000FF'
378 385
    layer2.save()
379 386
    MapLayerOptions.objects.create(map_cell=cell, map_layer=layer2)
387
    geojson_url2 = reverse('mapcell-geojson', kwargs={'cell_id': cell.id, 'layer_slug': layer2.slug})
380 388

  
381 389
    with mock.patch('combo.utils.requests_wrapper.RequestsSession.request') as requests_get:
382 390
        requests_get.return_value = mock.Mock(
383 391
                content=SAMPLE_GEOJSON_CONTENT,
384 392
                json=lambda: json.loads(SAMPLE_GEOJSON_CONTENT),
385 393
                status_code=200)
386
        resp = app.get(reverse('mapcell-geojson', kwargs={'cell_id': cell.id}) + '?q=bar')
387
        assert len(json.loads(resp.text)['features']) == 2
388

  
389
        resp = app.get(reverse('mapcell-geojson', kwargs={'cell_id': cell.id}) + '?q=xyz')
394
        resp = app.get(geojson_url + '?q=bar')
395
        assert len(json.loads(resp.text)['features']) == 1
396
        resp = app.get(geojson_url2 + '?q=bar')
397
        assert len(json.loads(resp.text)['features']) == 1
398
        resp = app.get(geojson_url + '?q=xyz')
399
        assert len(json.loads(resp.text)['features']) == 0
400
        resp = app.get(geojson_url2 + '?q=xyz')
390 401
        assert len(json.loads(resp.text)['features']) == 0
391

  
392 402
        # query against layer name, it should get results
393
        resp = app.get(reverse('mapcell-geojson', kwargs={'cell_id': cell.id}) + '?q=bicycle')
403
        resp = app.get(geojson_url + '?q=bicycle')
394 404
        assert len(json.loads(resp.text)['features']) == 2
395

  
396
        resp = app.get(reverse('mapcell-geojson', kwargs={'cell_id': cell.id}) + '?q=bar bicycle')
405
        resp = app.get(geojson_url2 + '?q=bicycle')
406
        assert len(json.loads(resp.text)['features']) == 0
407
        resp = app.get(geojson_url + '?q=bar bicycle')
397 408
        assert len(json.loads(resp.text)['features']) == 1
409
        resp = app.get(geojson_url2 + '?q=bar bicycle')
410
        assert len(json.loads(resp.text)['features']) == 0
398 411

  
399
        resp = app.get(reverse('mapcell-geojson', kwargs={'cell_id': cell.id}) + '?q=quux bicycle')
412
        resp = app.get(geojson_url + '?q=quux bicycle')
413
        assert len(json.loads(resp.text)['features']) == 0
414
        resp = app.get(geojson_url2 + '?q=quux bicycle')
400 415
        assert len(json.loads(resp.text)['features']) == 0
401 416

  
402 417

  
......
416 431
                content=SAMPLE_GEOJSON_CONTENT,
417 432
                json=lambda: json.loads(SAMPLE_GEOJSON_CONTENT),
418 433
                status_code=200)
419
        resp = app.get(reverse('mapcell-geojson', kwargs={'cell_id': cell.id}))
434
        resp = app.get(reverse('mapcell-geojson', kwargs={'cell_id': cell.id, 'layer_slug': layer.slug}))
420 435
        features = json.loads(resp.text)['features']
421 436
        assert 'name' in features[0]['properties']
422 437
        assert 'extra' in features[0]['properties']
......
430 445
                content=SAMPLE_GEOJSON_CONTENT,
431 446
                json=lambda: json.loads(SAMPLE_GEOJSON_CONTENT),
432 447
                status_code=200)
433
        resp = app.get(reverse('mapcell-geojson', kwargs={'cell_id': cell.id}))
448
        resp = app.get(reverse('mapcell-geojson', kwargs={'cell_id': cell.id, 'layer_slug': layer.slug}))
434 449
        features = json.loads(resp.text)['features']
435 450
        assert 'name' in features[0]['properties']
436 451
        assert 'extra' not in features[0]['properties']
......
444 459
                content=SAMPLE_WCS_GEOJSON_CONTENT,
445 460
                json=lambda: json.loads(SAMPLE_WCS_GEOJSON_CONTENT),
446 461
                status_code=200)
447
        resp = app.get(reverse('mapcell-geojson', kwargs={'cell_id': cell.id}))
462
        resp = app.get(reverse('mapcell-geojson', kwargs={'cell_id': cell.id, 'layer_slug': layer.slug}))
448 463
        features = json.loads(resp.text)['features']
449 464
        assert len(features[0]['properties']['display_fields']) == 2
450 465
        assert features[0]['properties']['layer']['properties'] == []
......
457 472
                content=SAMPLE_WCS_GEOJSON_CONTENT,
458 473
                json=lambda: json.loads(SAMPLE_WCS_GEOJSON_CONTENT),
459 474
                status_code=200)
460
        resp = app.get(reverse('mapcell-geojson', kwargs={'cell_id': cell.id}))
475
        resp = app.get(reverse('mapcell-geojson', kwargs={'cell_id': cell.id, 'layer_slug': layer.slug}))
461 476
        features = json.loads(resp.text)['features']
462 477
        assert len(features[0]['properties']['display_fields']) == 1
463 478
        assert features[0]['properties']['layer']['properties'] == ['id']
tests/test_maps_manager.py
186 186
                        'properties': {'property': 'property value'}}]
187 187
    mocked_response.ok.return_value = True
188 188
    mock_request.return_value = mocked_response
189
    geojson = layer.get_geojson(mock_request)
189
    geojson = layer.get_geojson(mock_request)['features']
190 190
    assert len(geojson) > 0
191 191
    for item in geojson:
192 192
        assert item['type'] == 'Feature'
......
207 207
    }
208 208
    mocked_response.ok.return_value = True
209 209
    mock_request.return_value = mocked_response
210
    geojson = layer.get_geojson(mock_request)
210
    geojson = layer.get_geojson(mock_request)['features']
211 211
    assert len(geojson) > 0
212 212
    for item in geojson:
213 213
        assert item['geometry']['type'] == 'Point'
214
-