umap-project 2.0.4__py3-none-any.whl → 2.1.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- umap/__init__.py +1 -1
- umap/fields.py +3 -1
- umap/locale/br/LC_MESSAGES/django.po +76 -71
- umap/locale/en/LC_MESSAGES/django.po +41 -41
- umap/locale/hu/LC_MESSAGES/django.po +42 -42
- umap/locale/it/LC_MESSAGES/django.po +64 -58
- umap/locale/ms/LC_MESSAGES/django.po +62 -57
- umap/migrations/0018_datalayer_uuid.py +62 -0
- umap/migrations/0019_migrate_internal_remote_datalayers.py +52 -0
- umap/models.py +20 -3
- umap/settings/base.py +1 -0
- umap/settings/dev.py +1 -0
- umap/static/umap/js/modules/browser.js +2 -2
- umap/static/umap/js/modules/global.js +14 -4
- umap/static/umap/js/modules/i18n.js +35 -0
- umap/static/umap/js/modules/leaflet-configure.js +7 -0
- umap/static/umap/js/modules/schema.js +388 -0
- umap/static/umap/js/modules/urls.js +17 -2
- umap/static/umap/js/modules/utils.js +24 -0
- umap/static/umap/js/umap.controls.js +9 -10
- umap/static/umap/js/umap.core.js +5 -5
- umap/static/umap/js/umap.features.js +23 -9
- umap/static/umap/js/umap.forms.js +49 -299
- umap/static/umap/js/umap.icon.js +2 -2
- umap/static/umap/js/umap.js +26 -129
- umap/static/umap/js/umap.layer.js +9 -9
- umap/static/umap/js/umap.popup.js +3 -0
- umap/static/umap/js/umap.share.js +1 -1
- umap/static/umap/locale/am_ET.json +229 -225
- umap/static/umap/locale/ar.json +229 -225
- umap/static/umap/locale/ast.json +229 -225
- umap/static/umap/locale/bg.json +229 -225
- umap/static/umap/locale/br.json +237 -233
- umap/static/umap/locale/ca.json +229 -225
- umap/static/umap/locale/cs_CZ.json +229 -225
- umap/static/umap/locale/da.json +229 -225
- umap/static/umap/locale/de.json +229 -225
- umap/static/umap/locale/el.json +229 -225
- umap/static/umap/locale/en.json +230 -233
- umap/static/umap/locale/en_US.json +229 -225
- umap/static/umap/locale/es.json +229 -225
- umap/static/umap/locale/et.json +229 -225
- umap/static/umap/locale/eu.json +226 -198
- umap/static/umap/locale/fa_IR.json +229 -225
- umap/static/umap/locale/fi.json +229 -225
- umap/static/umap/locale/fr.json +229 -232
- umap/static/umap/locale/gl.json +229 -225
- umap/static/umap/locale/he.json +229 -225
- umap/static/umap/locale/hr.json +229 -225
- umap/static/umap/locale/hu.json +229 -232
- umap/static/umap/locale/id.json +229 -225
- umap/static/umap/locale/is.json +229 -225
- umap/static/umap/locale/it.json +229 -232
- umap/static/umap/locale/ja.json +229 -225
- umap/static/umap/locale/ko.json +229 -225
- umap/static/umap/locale/lt.json +229 -225
- umap/static/umap/locale/ms.json +229 -232
- umap/static/umap/locale/nl.json +232 -228
- umap/static/umap/locale/no.json +229 -225
- umap/static/umap/locale/pl.json +229 -225
- umap/static/umap/locale/pl_PL.json +229 -225
- umap/static/umap/locale/pt.json +229 -225
- umap/static/umap/locale/pt_BR.json +229 -225
- umap/static/umap/locale/pt_PT.json +229 -225
- umap/static/umap/locale/ro.json +229 -225
- umap/static/umap/locale/ru.json +229 -225
- umap/static/umap/locale/sk_SK.json +229 -225
- umap/static/umap/locale/sl.json +229 -225
- umap/static/umap/locale/sr.json +229 -225
- umap/static/umap/locale/sv.json +229 -225
- umap/static/umap/locale/th_TH.json +229 -225
- umap/static/umap/locale/tr.json +229 -225
- umap/static/umap/locale/uk_UA.json +229 -225
- umap/static/umap/locale/vi.json +229 -225
- umap/static/umap/locale/vi_VN.json +229 -225
- umap/static/umap/locale/zh.json +229 -225
- umap/static/umap/locale/zh_CN.json +229 -225
- umap/static/umap/locale/zh_TW.Big5.json +229 -225
- umap/static/umap/locale/zh_TW.json +229 -232
- umap/static/umap/test/index.html +0 -2
- umap/static/umap/{test → unittests}/URLs.js +5 -0
- umap/static/umap/vendors/leaflet/leaflet-src.esm.js +7064 -7064
- umap/static/umap/vendors/photon/leaflet.photon.js +3 -0
- umap/templates/umap/js.html +8 -6
- umap/templatetags/umap_tags.py +3 -2
- umap/tests/integration/test_browser.py +40 -0
- umap/tests/integration/test_collaborative_editing.py +72 -3
- umap/tests/integration/test_export_map.py +226 -9
- umap/tests/integration/test_features_id_generation.py +51 -0
- umap/tests/integration/test_owned_map.py +14 -1
- umap/tests/integration/test_statics.py +3 -3
- umap/tests/integration/test_tilelayer.py +3 -3
- umap/tests/settings.py +3 -3
- umap/tests/test_datalayer_views.py +77 -20
- umap/tests/test_map_views.py +20 -0
- umap/tests/test_merge_features.py +25 -5
- umap/urls.py +12 -12
- umap/utils.py +7 -0
- umap/views.py +58 -49
- umap/wsgi.py +1 -0
- {umap_project-2.0.4.dist-info → umap_project-2.1.1.dist-info}/METADATA +9 -9
- {umap_project-2.0.4.dist-info → umap_project-2.1.1.dist-info}/RECORD +105 -99
- umap/static/umap/test/Map.Export.js +0 -106
- {umap_project-2.0.4.dist-info → umap_project-2.1.1.dist-info}/WHEEL +0 -0
- {umap_project-2.0.4.dist-info → umap_project-2.1.1.dist-info}/entry_points.txt +0 -0
- {umap_project-2.0.4.dist-info → umap_project-2.1.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -35,7 +35,7 @@ def test_get_with_public_mode(client, settings, datalayer, map):
|
|
|
35
35
|
url = reverse("datalayer_view", args=(map.pk, datalayer.pk))
|
|
36
36
|
response = client.get(url)
|
|
37
37
|
assert response.status_code == 200
|
|
38
|
-
assert response["
|
|
38
|
+
assert response["X-Datalayer-Version"] is not None
|
|
39
39
|
assert response["Cache-Control"] is not None
|
|
40
40
|
assert "Content-Encoding" not in response
|
|
41
41
|
j = json.loads(response.content.decode())
|
|
@@ -44,6 +44,16 @@ def test_get_with_public_mode(client, settings, datalayer, map):
|
|
|
44
44
|
assert j["type"] == "FeatureCollection"
|
|
45
45
|
|
|
46
46
|
|
|
47
|
+
def test_get_with_x_accel_redirect(client, settings, datalayer, map):
|
|
48
|
+
settings.UMAP_XSENDFILE_HEADER = "X-Accel-Redirect"
|
|
49
|
+
url = reverse("datalayer_view", args=(map.pk, datalayer.pk))
|
|
50
|
+
response = client.get(url)
|
|
51
|
+
assert response.status_code == 200
|
|
52
|
+
assert "X-Accel-Redirect" in response.headers
|
|
53
|
+
assert response["X-Accel-Redirect"].startswith("/internal/datalayer/")
|
|
54
|
+
assert response["X-Accel-Redirect"].endswith(".geojson")
|
|
55
|
+
|
|
56
|
+
|
|
47
57
|
def test_get_with_open_mode(client, settings, datalayer, map):
|
|
48
58
|
map.share_status = Map.PUBLIC
|
|
49
59
|
map.save()
|
|
@@ -111,7 +121,7 @@ def test_update(client, datalayer, map, post_data):
|
|
|
111
121
|
# Test response is a json
|
|
112
122
|
j = json.loads(response.content.decode())
|
|
113
123
|
assert "id" in j
|
|
114
|
-
assert datalayer.pk == j["id"]
|
|
124
|
+
assert str(datalayer.pk) == j["id"]
|
|
115
125
|
assert j["browsable"] is True
|
|
116
126
|
assert Path(modified_datalayer.geojson.path).exists()
|
|
117
127
|
|
|
@@ -154,48 +164,50 @@ def test_should_not_be_possible_to_delete_with_wrong_map_id_in_url(
|
|
|
154
164
|
assert DataLayer.objects.filter(pk=datalayer.pk).exists()
|
|
155
165
|
|
|
156
166
|
|
|
157
|
-
def
|
|
167
|
+
def test_optimistic_concurrency_control_with_good_version(
|
|
158
168
|
client, datalayer, map, post_data
|
|
159
169
|
):
|
|
160
170
|
map.share_status = Map.PUBLIC
|
|
161
171
|
map.save()
|
|
162
|
-
# Get
|
|
172
|
+
# Get reference version
|
|
163
173
|
url = reverse("datalayer_view", args=(map.pk, datalayer.pk))
|
|
164
174
|
response = client.get(url)
|
|
165
|
-
|
|
175
|
+
reference_version = response["X-Datalayer-Version"]
|
|
166
176
|
url = reverse("datalayer_update", args=(map.pk, datalayer.pk))
|
|
167
177
|
client.login(username=map.owner.username, password="123123")
|
|
168
178
|
name = "new name"
|
|
169
179
|
post_data["name"] = "new name"
|
|
170
180
|
response = client.post(
|
|
171
|
-
url, post_data, follow=True,
|
|
181
|
+
url, post_data, follow=True, HTTP_X_DATALAYER_REFERENCE=reference_version
|
|
172
182
|
)
|
|
173
183
|
assert response.status_code == 200
|
|
174
184
|
modified_datalayer = DataLayer.objects.get(pk=datalayer.pk)
|
|
175
185
|
assert modified_datalayer.name == name
|
|
176
186
|
|
|
177
187
|
|
|
178
|
-
def
|
|
188
|
+
def test_optimistic_concurrency_control_with_bad_version(
|
|
179
189
|
client, datalayer, map, post_data
|
|
180
190
|
):
|
|
181
191
|
url = reverse("datalayer_update", args=(map.pk, datalayer.pk))
|
|
182
192
|
client.login(username=map.owner.username, password="123123")
|
|
183
193
|
name = "new name"
|
|
184
194
|
post_data["name"] = name
|
|
185
|
-
response = client.post(
|
|
195
|
+
response = client.post(
|
|
196
|
+
url, post_data, follow=True, HTTP_X_DATALAYER_REFERENCE="xxx"
|
|
197
|
+
)
|
|
186
198
|
assert response.status_code == 412
|
|
187
199
|
modified_datalayer = DataLayer.objects.get(pk=datalayer.pk)
|
|
188
200
|
assert modified_datalayer.name != name
|
|
189
201
|
|
|
190
202
|
|
|
191
|
-
def
|
|
203
|
+
def test_optimistic_concurrency_control_with_empty_version(
|
|
192
204
|
client, datalayer, map, post_data
|
|
193
205
|
):
|
|
194
206
|
url = reverse("datalayer_update", args=(map.pk, datalayer.pk))
|
|
195
207
|
client.login(username=map.owner.username, password="123123")
|
|
196
208
|
name = "new name"
|
|
197
209
|
post_data["name"] = name
|
|
198
|
-
response = client.post(url, post_data, follow=True,
|
|
210
|
+
response = client.post(url, post_data, follow=True, X_DATALAYER_REFERENCE=None)
|
|
199
211
|
assert response.status_code == 200
|
|
200
212
|
modified_datalayer = DataLayer.objects.get(pk=datalayer.pk)
|
|
201
213
|
assert modified_datalayer.name == name
|
|
@@ -225,6 +237,41 @@ def test_versions_should_return_versions(client, datalayer, map, settings):
|
|
|
225
237
|
assert version in versions["versions"]
|
|
226
238
|
|
|
227
239
|
|
|
240
|
+
def test_versions_can_return_old_format(client, datalayer, map, settings):
|
|
241
|
+
map.share_status = Map.PUBLIC
|
|
242
|
+
map.save()
|
|
243
|
+
root = datalayer.storage_root()
|
|
244
|
+
datalayer.old_id = 123 # old datalayer id (now replaced by uuid)
|
|
245
|
+
datalayer.save()
|
|
246
|
+
|
|
247
|
+
datalayer.geojson.storage.save(
|
|
248
|
+
"%s/%s_1440924889.geojson" % (root, datalayer.pk), ContentFile("{}")
|
|
249
|
+
)
|
|
250
|
+
datalayer.geojson.storage.save(
|
|
251
|
+
"%s/%s_1440923687.geojson" % (root, datalayer.pk), ContentFile("{}")
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
# store with the id prefix (rather than the uuid)
|
|
255
|
+
old_format_version = "%s_1440918637.geojson" % datalayer.old_id
|
|
256
|
+
datalayer.geojson.storage.save(
|
|
257
|
+
("%s/" % root) + old_format_version, ContentFile("{}")
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
url = reverse("datalayer_versions", args=(map.pk, datalayer.pk))
|
|
261
|
+
versions = json.loads(client.get(url).content.decode())
|
|
262
|
+
assert len(versions["versions"]) == 4
|
|
263
|
+
version = {
|
|
264
|
+
"name": old_format_version,
|
|
265
|
+
"size": 2,
|
|
266
|
+
"at": "1440918637",
|
|
267
|
+
}
|
|
268
|
+
assert version in versions["versions"]
|
|
269
|
+
|
|
270
|
+
client.get(
|
|
271
|
+
reverse("datalayer_version", args=(map.pk, datalayer.pk, old_format_version))
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
|
|
228
275
|
def test_version_should_return_one_version_geojson(client, datalayer, map):
|
|
229
276
|
map.share_status = Map.PUBLIC
|
|
230
277
|
map.save()
|
|
@@ -444,7 +491,7 @@ def test_optimistic_merge_both_added(client, datalayer, map, reference_data):
|
|
|
444
491
|
assert response.status_code == 200
|
|
445
492
|
|
|
446
493
|
response = client.get(reverse("datalayer_view", args=(map.pk, datalayer.pk)))
|
|
447
|
-
|
|
494
|
+
reference_version = response.headers.get("X-Datalayer-Version")
|
|
448
495
|
|
|
449
496
|
# Client 1 adds "Point 5, 6" to the existing data
|
|
450
497
|
client1_feature = {
|
|
@@ -454,14 +501,16 @@ def test_optimistic_merge_both_added(client, datalayer, map, reference_data):
|
|
|
454
501
|
}
|
|
455
502
|
client1_data = deepcopy(reference_data)
|
|
456
503
|
client1_data["features"].append(client1_feature)
|
|
457
|
-
|
|
458
|
-
time.sleep(1)
|
|
504
|
+
|
|
459
505
|
post_data["geojson"] = SimpleUploadedFile(
|
|
460
506
|
"foo.json",
|
|
461
507
|
json.dumps(client1_data).encode("utf-8"),
|
|
462
508
|
)
|
|
463
509
|
response = client.post(
|
|
464
|
-
url,
|
|
510
|
+
url,
|
|
511
|
+
post_data,
|
|
512
|
+
follow=True,
|
|
513
|
+
headers={"X-Datalayer-Reference": reference_version},
|
|
465
514
|
)
|
|
466
515
|
assert response.status_code == 200
|
|
467
516
|
|
|
@@ -479,7 +528,10 @@ def test_optimistic_merge_both_added(client, datalayer, map, reference_data):
|
|
|
479
528
|
json.dumps(client2_data).encode("utf-8"),
|
|
480
529
|
)
|
|
481
530
|
response = client.post(
|
|
482
|
-
url,
|
|
531
|
+
url,
|
|
532
|
+
post_data,
|
|
533
|
+
follow=True,
|
|
534
|
+
headers={"X-Datalayer-Reference": reference_version},
|
|
483
535
|
)
|
|
484
536
|
assert response.status_code == 200
|
|
485
537
|
modified_datalayer = DataLayer.objects.get(pk=datalayer.pk)
|
|
@@ -513,20 +565,22 @@ def test_optimistic_merge_conflicting_change_raises(
|
|
|
513
565
|
assert response.status_code == 200
|
|
514
566
|
|
|
515
567
|
response = client.get(reverse("datalayer_view", args=(map.pk, datalayer.pk)))
|
|
516
|
-
|
|
568
|
+
|
|
569
|
+
reference_version = response.headers.get("X-Datalayer-Version")
|
|
517
570
|
|
|
518
571
|
# First client changes the first feature.
|
|
519
572
|
client1_data = deepcopy(reference_data)
|
|
520
573
|
client1_data["features"][0]["geometry"] = {"type": "Point", "coordinates": [5, 6]}
|
|
521
574
|
|
|
522
|
-
# Sleep to change the current timestamp (used in the If-Unmodified-Since header)
|
|
523
|
-
time.sleep(1)
|
|
524
575
|
post_data["geojson"] = SimpleUploadedFile(
|
|
525
576
|
"foo.json",
|
|
526
577
|
json.dumps(client1_data).encode("utf-8"),
|
|
527
578
|
)
|
|
528
579
|
response = client.post(
|
|
529
|
-
url,
|
|
580
|
+
url,
|
|
581
|
+
post_data,
|
|
582
|
+
follow=True,
|
|
583
|
+
headers={"X-Datalayer-Reference": reference_version},
|
|
530
584
|
)
|
|
531
585
|
assert response.status_code == 200
|
|
532
586
|
|
|
@@ -539,7 +593,10 @@ def test_optimistic_merge_conflicting_change_raises(
|
|
|
539
593
|
json.dumps(client2_data).encode("utf-8"),
|
|
540
594
|
)
|
|
541
595
|
response = client.post(
|
|
542
|
-
url,
|
|
596
|
+
url,
|
|
597
|
+
post_data,
|
|
598
|
+
follow=True,
|
|
599
|
+
headers={"X-Datalayer-Reference": reference_version},
|
|
543
600
|
)
|
|
544
601
|
assert response.status_code == 412
|
|
545
602
|
|
umap/tests/test_map_views.py
CHANGED
|
@@ -7,6 +7,7 @@ from django.contrib.auth import get_user_model
|
|
|
7
7
|
from django.core import mail
|
|
8
8
|
from django.core.signing import Signer
|
|
9
9
|
from django.urls import reverse
|
|
10
|
+
from django.utils import translation
|
|
10
11
|
|
|
11
12
|
from umap.models import DataLayer, Map, Star
|
|
12
13
|
|
|
@@ -147,6 +148,13 @@ def test_should_not_consider_the_query_string_for_canonical_check(client, map):
|
|
|
147
148
|
assert response.status_code == 200
|
|
148
149
|
|
|
149
150
|
|
|
151
|
+
def test_map_headers(client, map):
|
|
152
|
+
url = reverse("map", kwargs={"map_id": map.pk, "slug": map.slug})
|
|
153
|
+
response = client.get(url)
|
|
154
|
+
assert response.status_code == 200
|
|
155
|
+
assert response.headers["Access-Control-Allow-Origin"] == "*"
|
|
156
|
+
|
|
157
|
+
|
|
150
158
|
def test_short_url_should_redirect_to_canonical(client, map):
|
|
151
159
|
url = reverse("map_short_url", kwargs={"pk": map.pk})
|
|
152
160
|
canonical = reverse("map", kwargs={"map_id": map.pk, "slug": map.slug})
|
|
@@ -803,6 +811,7 @@ def test_oembed_map(client, map, datalayer):
|
|
|
803
811
|
url = f"{reverse('map_oembed')}?url=http://testserver{map.get_absolute_url()}"
|
|
804
812
|
response = client.get(url)
|
|
805
813
|
assert response.status_code == 200
|
|
814
|
+
assert response.headers["Access-Control-Allow-Origin"] == "*"
|
|
806
815
|
j = json.loads(response.content.decode())
|
|
807
816
|
assert j["type"] == "rich"
|
|
808
817
|
assert j["version"] == "1.0"
|
|
@@ -815,6 +824,17 @@ def test_oembed_map(client, map, datalayer):
|
|
|
815
824
|
)
|
|
816
825
|
|
|
817
826
|
|
|
827
|
+
def test_oembed_map_with_non_default_language(client, map, datalayer):
|
|
828
|
+
translation.activate("en")
|
|
829
|
+
path = map.get_absolute_url()
|
|
830
|
+
assert path.startswith("/en/")
|
|
831
|
+
path = path.replace("/en/", "/fr/")
|
|
832
|
+
url = f"{reverse('map_oembed')}?url=http://testserver{path}"
|
|
833
|
+
response = client.get(url)
|
|
834
|
+
assert response.status_code == 200
|
|
835
|
+
translation.activate("en")
|
|
836
|
+
|
|
837
|
+
|
|
818
838
|
def test_oembed_link(client, map, datalayer):
|
|
819
839
|
response = client.get(map.get_absolute_url())
|
|
820
840
|
assert response.status_code == 200
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import pytest
|
|
2
2
|
|
|
3
|
-
from umap.utils import merge_features
|
|
3
|
+
from umap.utils import ConflictError, merge_features
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
def test_adding_one_element():
|
|
@@ -50,18 +50,38 @@ def test_removing_same_element():
|
|
|
50
50
|
|
|
51
51
|
|
|
52
52
|
def test_removing_changed_element():
|
|
53
|
-
with pytest.raises(
|
|
53
|
+
with pytest.raises(ConflictError):
|
|
54
54
|
merge_features(["A", "B"], ["A", "C"], ["A"])
|
|
55
55
|
|
|
56
56
|
|
|
57
57
|
def test_changing_removed_element():
|
|
58
|
-
with pytest.raises(
|
|
58
|
+
with pytest.raises(ConflictError):
|
|
59
59
|
merge_features(["A", "B"], ["A"], ["A", "C"])
|
|
60
60
|
|
|
61
61
|
|
|
62
62
|
def test_changing_same_element():
|
|
63
|
-
with pytest.raises(
|
|
63
|
+
with pytest.raises(ConflictError):
|
|
64
64
|
merge_features(["A", "B"], ["A", "D"], ["A", "C"])
|
|
65
65
|
# Order does not count
|
|
66
|
-
with pytest.raises(
|
|
66
|
+
with pytest.raises(ConflictError):
|
|
67
67
|
merge_features(["A", "B", "C"], ["B", "D", "A"], ["A", "E", "B"])
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def test_merge_with_ids_raises():
|
|
71
|
+
# If reference doesn't have ids, but latest and incoming has
|
|
72
|
+
# We need to raise as a conflict
|
|
73
|
+
reference = [
|
|
74
|
+
{"properties": {}, "geometry": "A"},
|
|
75
|
+
{"properties": {}, "geometry": "B"},
|
|
76
|
+
]
|
|
77
|
+
latest = [
|
|
78
|
+
{"properties": {id: "100"}, "geometry": "A"},
|
|
79
|
+
{"properties": {id: "101"}, "geometry": "B"},
|
|
80
|
+
]
|
|
81
|
+
incoming = [
|
|
82
|
+
{"properties": {id: "200"}, "geometry": "A"},
|
|
83
|
+
{"properties": {id: "201"}, "geometry": "B"},
|
|
84
|
+
]
|
|
85
|
+
|
|
86
|
+
with pytest.raises(ConflictError):
|
|
87
|
+
merge_features(reference, latest, incoming)
|
umap/urls.py
CHANGED
|
@@ -72,18 +72,18 @@ i18n_urls = [
|
|
|
72
72
|
]
|
|
73
73
|
i18n_urls += decorated_patterns(
|
|
74
74
|
[can_view_map, cache_control(must_revalidate=True)],
|
|
75
|
-
|
|
76
|
-
|
|
75
|
+
path(
|
|
76
|
+
"datalayer/<int:map_id>/<uuid:pk>/",
|
|
77
77
|
views.DataLayerView.as_view(),
|
|
78
78
|
name="datalayer_view",
|
|
79
79
|
),
|
|
80
|
-
|
|
81
|
-
|
|
80
|
+
path(
|
|
81
|
+
"datalayer/<int:map_id>/<uuid:pk>/versions/",
|
|
82
82
|
views.DataLayerVersions.as_view(),
|
|
83
83
|
name="datalayer_versions",
|
|
84
84
|
),
|
|
85
|
-
|
|
86
|
-
|
|
85
|
+
path(
|
|
86
|
+
"datalayer/<int:map_id>/<uuid:pk>/<str:name>",
|
|
87
87
|
views.DataLayerVersion.as_view(),
|
|
88
88
|
name="datalayer_version",
|
|
89
89
|
),
|
|
@@ -145,13 +145,13 @@ map_urls = [
|
|
|
145
145
|
views.DataLayerCreate.as_view(),
|
|
146
146
|
name="datalayer_create",
|
|
147
147
|
),
|
|
148
|
-
|
|
149
|
-
|
|
148
|
+
path(
|
|
149
|
+
"map/<int:map_id>/datalayer/delete/<uuid:pk>/",
|
|
150
150
|
views.DataLayerDelete.as_view(),
|
|
151
151
|
name="datalayer_delete",
|
|
152
152
|
),
|
|
153
|
-
|
|
154
|
-
|
|
153
|
+
path(
|
|
154
|
+
"map/<int:map_id>/datalayer/permissions/<uuid:pk>/",
|
|
155
155
|
views.UpdateDataLayerPermissions.as_view(),
|
|
156
156
|
name="datalayer_permissions",
|
|
157
157
|
),
|
|
@@ -165,8 +165,8 @@ if settings.DEFAULT_FROM_EMAIL:
|
|
|
165
165
|
)
|
|
166
166
|
)
|
|
167
167
|
datalayer_urls = [
|
|
168
|
-
|
|
169
|
-
|
|
168
|
+
path(
|
|
169
|
+
"map/<int:map_id>/datalayer/update/<uuid:pk>/",
|
|
170
170
|
views.DataLayerUpdate.as_view(),
|
|
171
171
|
name="datalayer_update",
|
|
172
172
|
),
|
umap/utils.py
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import gzip
|
|
2
|
+
import json
|
|
2
3
|
import os
|
|
3
4
|
|
|
4
5
|
from django.conf import settings
|
|
6
|
+
from django.core.serializers.json import DjangoJSONEncoder
|
|
5
7
|
from django.urls import URLPattern, URLResolver, get_resolver
|
|
6
8
|
|
|
7
9
|
|
|
@@ -162,3 +164,8 @@ def merge_features(reference: list, latest: list, incoming: list):
|
|
|
162
164
|
merged.append(item)
|
|
163
165
|
|
|
164
166
|
return merged
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def json_dumps(obj, **kwargs):
|
|
170
|
+
"""Utility using the Django JSON Encoder when dumping objects"""
|
|
171
|
+
return json.dumps(obj, cls=DjangoJSONEncoder, **kwargs)
|