umap-project 2.7.3__py3-none-any.whl → 2.8.0__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/forms.py +4 -14
- umap/locale/am_ET/LC_MESSAGES/django.mo +0 -0
- umap/locale/am_ET/LC_MESSAGES/django.po +278 -151
- umap/locale/ar/LC_MESSAGES/django.mo +0 -0
- umap/locale/ar/LC_MESSAGES/django.po +335 -141
- umap/locale/bg/LC_MESSAGES/django.mo +0 -0
- umap/locale/bg/LC_MESSAGES/django.po +279 -152
- umap/locale/br/LC_MESSAGES/django.mo +0 -0
- umap/locale/br/LC_MESSAGES/django.po +95 -79
- umap/locale/ca/LC_MESSAGES/django.mo +0 -0
- umap/locale/ca/LC_MESSAGES/django.po +85 -68
- umap/locale/cs_CZ/LC_MESSAGES/django.mo +0 -0
- umap/locale/cs_CZ/LC_MESSAGES/django.po +78 -66
- umap/locale/da/LC_MESSAGES/django.mo +0 -0
- umap/locale/da/LC_MESSAGES/django.po +280 -153
- umap/locale/de/LC_MESSAGES/django.mo +0 -0
- umap/locale/de/LC_MESSAGES/django.po +80 -64
- umap/locale/el/LC_MESSAGES/django.mo +0 -0
- umap/locale/el/LC_MESSAGES/django.po +82 -66
- umap/locale/en/LC_MESSAGES/django.po +73 -61
- umap/locale/es/LC_MESSAGES/django.mo +0 -0
- umap/locale/es/LC_MESSAGES/django.po +75 -63
- umap/locale/et/LC_MESSAGES/django.mo +0 -0
- umap/locale/et/LC_MESSAGES/django.po +280 -153
- umap/locale/eu/LC_MESSAGES/django.mo +0 -0
- umap/locale/eu/LC_MESSAGES/django.po +82 -66
- umap/locale/fa_IR/LC_MESSAGES/django.mo +0 -0
- umap/locale/fa_IR/LC_MESSAGES/django.po +80 -64
- umap/locale/fi/LC_MESSAGES/django.mo +0 -0
- umap/locale/fi/LC_MESSAGES/django.po +278 -151
- umap/locale/fr/LC_MESSAGES/django.mo +0 -0
- umap/locale/fr/LC_MESSAGES/django.po +75 -63
- umap/locale/gl/LC_MESSAGES/django.mo +0 -0
- umap/locale/gl/LC_MESSAGES/django.po +280 -153
- umap/locale/he/LC_MESSAGES/django.mo +0 -0
- umap/locale/he/LC_MESSAGES/django.po +281 -154
- umap/locale/hu/LC_MESSAGES/django.mo +0 -0
- umap/locale/hu/LC_MESSAGES/django.po +80 -64
- umap/locale/is/LC_MESSAGES/django.mo +0 -0
- umap/locale/is/LC_MESSAGES/django.po +280 -153
- umap/locale/it/LC_MESSAGES/django.mo +0 -0
- umap/locale/it/LC_MESSAGES/django.po +82 -66
- umap/locale/ja/LC_MESSAGES/django.mo +0 -0
- umap/locale/ja/LC_MESSAGES/django.po +280 -153
- umap/locale/ko/LC_MESSAGES/django.mo +0 -0
- umap/locale/ko/LC_MESSAGES/django.po +280 -153
- umap/locale/lt/LC_MESSAGES/django.mo +0 -0
- umap/locale/lt/LC_MESSAGES/django.po +280 -153
- umap/locale/ms/LC_MESSAGES/django.mo +0 -0
- umap/locale/ms/LC_MESSAGES/django.po +82 -66
- umap/locale/nl/LC_MESSAGES/django.mo +0 -0
- umap/locale/nl/LC_MESSAGES/django.po +280 -153
- umap/locale/pl/LC_MESSAGES/django.mo +0 -0
- umap/locale/pl/LC_MESSAGES/django.po +82 -66
- umap/locale/pt/LC_MESSAGES/django.mo +0 -0
- umap/locale/pt/LC_MESSAGES/django.po +75 -63
- umap/locale/pt_BR/LC_MESSAGES/django.mo +0 -0
- umap/locale/pt_BR/LC_MESSAGES/django.po +280 -153
- umap/locale/pt_PT/LC_MESSAGES/django.mo +0 -0
- umap/locale/pt_PT/LC_MESSAGES/django.po +280 -153
- umap/locale/ru/LC_MESSAGES/django.mo +0 -0
- umap/locale/ru/LC_MESSAGES/django.po +280 -153
- umap/locale/sk_SK/LC_MESSAGES/django.mo +0 -0
- umap/locale/sk_SK/LC_MESSAGES/django.po +280 -153
- umap/locale/sl/LC_MESSAGES/django.mo +0 -0
- umap/locale/sl/LC_MESSAGES/django.po +280 -153
- umap/locale/sr/LC_MESSAGES/django.mo +0 -0
- umap/locale/sr/LC_MESSAGES/django.po +280 -153
- umap/locale/sv/LC_MESSAGES/django.mo +0 -0
- umap/locale/sv/LC_MESSAGES/django.po +81 -65
- umap/locale/th_TH/LC_MESSAGES/django.mo +0 -0
- umap/locale/th_TH/LC_MESSAGES/django.po +257 -185
- umap/locale/tr/LC_MESSAGES/django.mo +0 -0
- umap/locale/tr/LC_MESSAGES/django.po +280 -153
- umap/locale/uk_UA/LC_MESSAGES/django.mo +0 -0
- umap/locale/uk_UA/LC_MESSAGES/django.po +280 -153
- umap/locale/vi/LC_MESSAGES/django.mo +0 -0
- umap/locale/vi/LC_MESSAGES/django.po +278 -151
- umap/locale/zh/LC_MESSAGES/django.mo +0 -0
- umap/locale/zh/LC_MESSAGES/django.po +278 -151
- umap/locale/zh_TW/LC_MESSAGES/django.mo +0 -0
- umap/locale/zh_TW/LC_MESSAGES/django.po +97 -81
- umap/management/commands/empty_trash.py +35 -0
- umap/management/commands/migrate_to_S3.py +29 -0
- umap/migrations/0023_alter_datalayer_uuid.py +19 -0
- umap/migrations/0024_alter_map_share_status.py +30 -0
- umap/migrations/0025_alter_datalayer_geojson.py +24 -0
- umap/models.py +68 -116
- umap/settings/base.py +23 -3
- umap/settings/local_s3.py +45 -0
- umap/static/umap/base.css +3 -603
- umap/static/umap/content.css +5 -3
- umap/static/umap/css/bar.css +202 -0
- umap/static/umap/css/form.css +620 -0
- umap/static/umap/css/icon.css +21 -1
- umap/static/umap/css/popup.css +125 -0
- umap/static/umap/img/16-white.svg +16 -4
- umap/static/umap/img/16.svg +1 -1
- umap/static/umap/img/source/16-white.svg +46 -45
- umap/static/umap/img/source/16.svg +1 -753
- umap/static/umap/js/components/fragment.js +3 -1
- umap/static/umap/js/modules/browser.js +20 -19
- umap/static/umap/js/modules/caption.js +21 -22
- umap/static/umap/js/modules/data/features.js +120 -78
- umap/static/umap/js/modules/data/layer.js +195 -153
- umap/static/umap/js/modules/facets.js +9 -9
- umap/static/umap/js/modules/formatter.js +5 -5
- umap/static/umap/js/modules/global.js +4 -52
- umap/static/umap/js/modules/help.js +18 -21
- umap/static/umap/js/modules/importer.js +133 -56
- umap/static/umap/js/modules/importers/cadastrefr.js +4 -0
- umap/static/umap/js/modules/importers/geodatamine.js +3 -3
- umap/static/umap/js/modules/importers/overpass.js +5 -0
- umap/static/umap/js/modules/permissions.js +85 -87
- umap/static/umap/js/modules/rendering/icon.js +2 -1
- umap/static/umap/js/modules/rendering/layers/base.js +15 -15
- umap/static/umap/js/modules/rendering/layers/classified.js +1 -1
- umap/static/umap/js/modules/rendering/layers/cluster.js +1 -1
- umap/static/umap/js/modules/rendering/layers/heat.js +1 -1
- umap/static/umap/js/modules/rendering/map.js +390 -0
- umap/static/umap/js/modules/rendering/popup.js +19 -19
- umap/static/umap/js/modules/rendering/template.js +88 -21
- umap/static/umap/js/modules/rendering/ui.js +63 -14
- umap/static/umap/js/modules/request.js +2 -2
- umap/static/umap/js/modules/rules.js +22 -25
- umap/static/umap/js/modules/saving.js +47 -0
- umap/static/umap/js/modules/schema.js +6 -0
- umap/static/umap/js/modules/share.js +21 -24
- umap/static/umap/js/modules/slideshow.js +24 -20
- umap/static/umap/js/modules/sync/updaters.js +7 -9
- umap/static/umap/js/modules/tableeditor.js +20 -19
- umap/static/umap/js/modules/ui/bar.js +196 -0
- umap/static/umap/js/modules/ui/dialog.js +5 -0
- umap/static/umap/js/modules/ui/panel.js +10 -9
- umap/static/umap/js/modules/umap.js +1691 -0
- umap/static/umap/js/modules/urls.js +2 -2
- umap/static/umap/js/modules/utils.js +22 -6
- umap/static/umap/js/umap.controls.js +81 -305
- umap/static/umap/js/umap.core.js +29 -50
- umap/static/umap/js/umap.forms.js +78 -27
- umap/static/umap/keycloak.png +0 -0
- umap/static/umap/locale/am_ET.js +26 -10
- umap/static/umap/locale/am_ET.json +26 -10
- umap/static/umap/locale/ar.js +26 -10
- umap/static/umap/locale/ar.json +26 -10
- umap/static/umap/locale/ast.js +26 -10
- umap/static/umap/locale/ast.json +26 -10
- umap/static/umap/locale/bg.js +26 -10
- umap/static/umap/locale/bg.json +26 -10
- umap/static/umap/locale/br.js +27 -20
- umap/static/umap/locale/br.json +27 -20
- umap/static/umap/locale/ca.js +32 -29
- umap/static/umap/locale/ca.json +32 -29
- umap/static/umap/locale/cs_CZ.js +24 -17
- umap/static/umap/locale/cs_CZ.json +24 -17
- umap/static/umap/locale/da.js +26 -10
- umap/static/umap/locale/da.json +26 -10
- umap/static/umap/locale/de.js +21 -14
- umap/static/umap/locale/de.json +21 -14
- umap/static/umap/locale/el.js +28 -12
- umap/static/umap/locale/el.json +28 -12
- umap/static/umap/locale/en.js +14 -9
- umap/static/umap/locale/en.json +14 -9
- umap/static/umap/locale/en_US.json +26 -10
- umap/static/umap/locale/es.js +16 -13
- umap/static/umap/locale/es.json +16 -13
- umap/static/umap/locale/et.js +26 -10
- umap/static/umap/locale/et.json +26 -10
- umap/static/umap/locale/eu.js +16 -9
- umap/static/umap/locale/eu.json +16 -9
- umap/static/umap/locale/fa_IR.js +16 -9
- umap/static/umap/locale/fa_IR.json +16 -9
- umap/static/umap/locale/fi.js +26 -10
- umap/static/umap/locale/fi.json +26 -10
- umap/static/umap/locale/fr.js +14 -9
- umap/static/umap/locale/fr.json +14 -9
- umap/static/umap/locale/gl.js +26 -10
- umap/static/umap/locale/gl.json +26 -10
- umap/static/umap/locale/he.js +26 -10
- umap/static/umap/locale/he.json +26 -10
- umap/static/umap/locale/hr.js +26 -10
- umap/static/umap/locale/hr.json +26 -10
- umap/static/umap/locale/hu.js +16 -9
- umap/static/umap/locale/hu.json +16 -9
- umap/static/umap/locale/id.js +26 -10
- umap/static/umap/locale/id.json +26 -10
- umap/static/umap/locale/is.js +26 -10
- umap/static/umap/locale/is.json +26 -10
- umap/static/umap/locale/it.js +26 -10
- umap/static/umap/locale/it.json +26 -10
- umap/static/umap/locale/ja.js +26 -10
- umap/static/umap/locale/ja.json +26 -10
- umap/static/umap/locale/ko.js +26 -10
- umap/static/umap/locale/ko.json +26 -10
- umap/static/umap/locale/lt.js +26 -10
- umap/static/umap/locale/lt.json +26 -10
- umap/static/umap/locale/ms.js +28 -12
- umap/static/umap/locale/ms.json +28 -12
- umap/static/umap/locale/nl.js +28 -12
- umap/static/umap/locale/nl.json +28 -12
- umap/static/umap/locale/no.js +26 -10
- umap/static/umap/locale/no.json +26 -10
- umap/static/umap/locale/pl.js +28 -12
- umap/static/umap/locale/pl.json +28 -12
- umap/static/umap/locale/pl_PL.json +26 -10
- umap/static/umap/locale/pt.js +16 -9
- umap/static/umap/locale/pt.json +16 -9
- umap/static/umap/locale/pt_BR.js +26 -10
- umap/static/umap/locale/pt_BR.json +26 -10
- umap/static/umap/locale/pt_PT.js +16 -9
- umap/static/umap/locale/pt_PT.json +16 -9
- umap/static/umap/locale/ro.js +26 -10
- umap/static/umap/locale/ro.json +26 -10
- umap/static/umap/locale/ru.js +26 -10
- umap/static/umap/locale/ru.json +26 -10
- umap/static/umap/locale/si.js +7 -7
- umap/static/umap/locale/si.json +7 -7
- umap/static/umap/locale/sk_SK.js +26 -10
- umap/static/umap/locale/sk_SK.json +26 -10
- umap/static/umap/locale/sl.js +26 -10
- umap/static/umap/locale/sl.json +26 -10
- umap/static/umap/locale/sr.js +26 -10
- umap/static/umap/locale/sr.json +26 -10
- umap/static/umap/locale/sv.js +27 -11
- umap/static/umap/locale/sv.json +27 -11
- umap/static/umap/locale/th_TH.js +28 -12
- umap/static/umap/locale/th_TH.json +28 -12
- umap/static/umap/locale/tr.js +26 -10
- umap/static/umap/locale/tr.json +26 -10
- umap/static/umap/locale/uk_UA.js +26 -10
- umap/static/umap/locale/uk_UA.json +26 -10
- umap/static/umap/locale/vi.js +26 -10
- umap/static/umap/locale/vi.json +26 -10
- umap/static/umap/locale/vi_VN.json +26 -10
- umap/static/umap/locale/zh.js +26 -10
- umap/static/umap/locale/zh.json +26 -10
- umap/static/umap/locale/zh_CN.json +26 -10
- umap/static/umap/locale/zh_TW.Big5.json +26 -10
- umap/static/umap/locale/zh_TW.js +34 -27
- umap/static/umap/locale/zh_TW.json +34 -27
- umap/static/umap/map.css +39 -530
- umap/static/umap/unittests/URLs.js +15 -15
- umap/static/umap/unittests/utils.js +23 -1
- umap/static/umap/vars.css +2 -1
- umap/static/umap/vendors/formbuilder/Leaflet.FormBuilder.js +5 -1
- umap/storage/__init__.py +3 -0
- umap/storage/fs.py +101 -0
- umap/storage/s3.py +61 -0
- umap/templates/base.html +2 -0
- umap/templates/registration/login.html +7 -6
- umap/templates/umap/components/alerts/alert.html +4 -0
- umap/templates/umap/css.html +6 -0
- umap/templates/umap/js.html +3 -2
- umap/templates/umap/map_init.html +6 -5
- umap/templates/umap/user_dashboard.html +20 -19
- umap/tests/base.py +5 -1
- umap/tests/fixtures/test_upload_simple_marker.json +19 -0
- umap/tests/integration/conftest.py +2 -1
- umap/tests/integration/test_anonymous_owned_map.py +18 -10
- umap/tests/integration/test_browser.py +16 -1
- umap/tests/integration/test_dashboard.py +1 -1
- umap/tests/integration/test_edit_datalayer.py +29 -7
- umap/tests/integration/test_import.py +28 -6
- umap/tests/integration/test_optimistic_merge.py +31 -8
- umap/tests/integration/test_owned_map.py +22 -16
- umap/tests/integration/test_popup.py +44 -0
- umap/tests/integration/test_save.py +35 -0
- umap/tests/integration/test_view_marker.py +12 -0
- umap/tests/integration/test_view_polyline.py +257 -0
- umap/tests/integration/test_websocket_sync.py +81 -9
- umap/tests/test_dashboard.py +82 -0
- umap/tests/test_datalayer.py +6 -7
- umap/tests/test_datalayer_s3.py +135 -0
- umap/tests/test_datalayer_views.py +28 -10
- umap/tests/test_empty_trash.py +34 -0
- umap/tests/test_map.py +12 -3
- umap/tests/test_map_views.py +69 -37
- umap/tests/test_statics.py +1 -1
- umap/tests/test_team_views.py +35 -1
- umap/tests/test_views.py +31 -52
- umap/urls.py +3 -3
- umap/views.py +126 -90
- {umap_project-2.7.3.dist-info → umap_project-2.8.0.dist-info}/METADATA +16 -13
- {umap_project-2.7.3.dist-info → umap_project-2.8.0.dist-info}/RECORD +289 -269
- umap/management/commands/purge_purgatory.py +0 -28
- umap/static/umap/js/umap.js +0 -1903
- umap/tests/test_purge_purgatory.py +0 -25
- /umap/{storage.py → storage/staticfiles.py} +0 -0
- {umap_project-2.7.3.dist-info → umap_project-2.8.0.dist-info}/WHEEL +0 -0
- {umap_project-2.7.3.dist-info → umap_project-2.8.0.dist-info}/entry_points.txt +0 -0
- {umap_project-2.7.3.dist-info → umap_project-2.8.0.dist-info}/licenses/LICENSE +0 -0
umap/views.py
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import io
|
|
2
2
|
import json
|
|
3
3
|
import mimetypes
|
|
4
|
-
import os
|
|
5
4
|
import re
|
|
6
5
|
import socket
|
|
7
6
|
import zipfile
|
|
@@ -318,7 +317,11 @@ class TeamMaps(PaginatorMixin, DetailView):
|
|
|
318
317
|
context_object_name = "current_team"
|
|
319
318
|
|
|
320
319
|
def get_maps(self):
|
|
321
|
-
|
|
320
|
+
qs = Map.public
|
|
321
|
+
user = self.request.user
|
|
322
|
+
if user.is_authenticated and user in self.object.users.all():
|
|
323
|
+
qs = Map.objects
|
|
324
|
+
return qs.filter(team=self.object).order_by("-modified_at")
|
|
322
325
|
|
|
323
326
|
def get_context_data(self, **kwargs):
|
|
324
327
|
kwargs.update(
|
|
@@ -373,6 +376,7 @@ class UserDashboard(PaginatorMixin, DetailView, SearchMixin):
|
|
|
373
376
|
|
|
374
377
|
def get_maps(self):
|
|
375
378
|
qs = self.get_search_queryset() or Map.objects.all()
|
|
379
|
+
qs = qs.exclude(share_status__in=[Map.DELETED, Map.BLOCKED])
|
|
376
380
|
teams = self.object.teams.all()
|
|
377
381
|
qs = (
|
|
378
382
|
qs.filter(owner=self.object)
|
|
@@ -452,27 +456,27 @@ showcase = MapsShowCase.as_view()
|
|
|
452
456
|
|
|
453
457
|
|
|
454
458
|
def validate_url(request):
|
|
455
|
-
assert request.method == "GET"
|
|
459
|
+
assert request.method == "GET", "Wrong HTTP method"
|
|
456
460
|
url = request.GET.get("url")
|
|
457
|
-
assert url
|
|
461
|
+
assert url, "Missing URL"
|
|
458
462
|
try:
|
|
459
463
|
URLValidator(url)
|
|
460
|
-
except ValidationError:
|
|
461
|
-
raise AssertionError()
|
|
462
|
-
assert "HTTP_REFERER" in request.META
|
|
464
|
+
except ValidationError as err:
|
|
465
|
+
raise AssertionError(err)
|
|
466
|
+
assert "HTTP_REFERER" in request.META, "Missing HTTP_REFERER"
|
|
463
467
|
referer = urlparse(request.META.get("HTTP_REFERER"))
|
|
464
468
|
toproxy = urlparse(url)
|
|
465
469
|
local = urlparse(settings.SITE_URL)
|
|
466
|
-
assert toproxy.hostname
|
|
467
|
-
assert referer.hostname == local.hostname
|
|
468
|
-
assert toproxy.hostname != "localhost"
|
|
469
|
-
assert toproxy.netloc != local.netloc
|
|
470
|
+
assert toproxy.hostname, "No hostname"
|
|
471
|
+
assert referer.hostname == local.hostname, f"{referer.hostname} != {local.hostname}"
|
|
472
|
+
assert toproxy.hostname != "localhost", "Invalid localhost target"
|
|
473
|
+
assert toproxy.netloc != local.netloc, "Invalid netloc"
|
|
470
474
|
try:
|
|
471
475
|
# clean this when in python 3.4
|
|
472
476
|
ipaddress = socket.gethostbyname(toproxy.hostname)
|
|
473
|
-
except:
|
|
474
|
-
raise AssertionError()
|
|
475
|
-
assert not PRIVATE_IP.match(ipaddress)
|
|
477
|
+
except Exception as err:
|
|
478
|
+
raise AssertionError(err)
|
|
479
|
+
assert not PRIVATE_IP.match(ipaddress), "Private IP"
|
|
476
480
|
return url
|
|
477
481
|
|
|
478
482
|
|
|
@@ -480,7 +484,8 @@ class AjaxProxy(View):
|
|
|
480
484
|
def get(self, *args, **kwargs):
|
|
481
485
|
try:
|
|
482
486
|
url = validate_url(self.request)
|
|
483
|
-
except AssertionError:
|
|
487
|
+
except AssertionError as err:
|
|
488
|
+
print(f"AjaxProxy: {err}")
|
|
484
489
|
return HttpResponseBadRequest()
|
|
485
490
|
try:
|
|
486
491
|
ttl = int(self.request.GET.get("ttl"))
|
|
@@ -598,29 +603,34 @@ class MapDetailMixin(SessionMixin):
|
|
|
598
603
|
"tilelayers": TileLayer.get_list(),
|
|
599
604
|
"editMode": self.edit_mode,
|
|
600
605
|
"schema": Map.extra_schema,
|
|
601
|
-
"
|
|
606
|
+
"id": self.get_id(),
|
|
602
607
|
"starred": self.is_starred(),
|
|
603
608
|
"licences": dict((l.name, l.json) for l in Licence.objects.all()),
|
|
604
|
-
"share_statuses": [
|
|
605
|
-
(i, str(label)) for i, label in Map.SHARE_STATUS if i != Map.BLOCKED
|
|
606
|
-
],
|
|
607
609
|
"umap_version": VERSION,
|
|
608
610
|
"featuresHaveOwner": settings.UMAP_DEFAULT_FEATURES_HAVE_OWNERS,
|
|
609
611
|
"websocketEnabled": settings.WEBSOCKET_ENABLED,
|
|
610
612
|
"websocketURI": settings.WEBSOCKET_FRONT_URI,
|
|
611
613
|
"importers": settings.UMAP_IMPORTERS,
|
|
614
|
+
"defaultLabelKeys": settings.UMAP_LABEL_KEYS,
|
|
612
615
|
}
|
|
613
616
|
created = bool(getattr(self, "object", None))
|
|
614
617
|
if (created and self.object.owner) or (not created and not user.is_anonymous):
|
|
615
|
-
|
|
618
|
+
edit_statuses = Map.EDIT_STATUS
|
|
616
619
|
datalayer_statuses = DataLayer.EDIT_STATUS
|
|
620
|
+
share_statuses = Map.SHARE_STATUS
|
|
617
621
|
else:
|
|
618
|
-
|
|
619
|
-
datalayer_statuses =
|
|
620
|
-
|
|
622
|
+
edit_statuses = Map.ANONYMOUS_EDIT_STATUS
|
|
623
|
+
datalayer_statuses = DataLayer.ANONYMOUS_EDIT_STATUS
|
|
624
|
+
share_statuses = Map.ANONYMOUS_SHARE_STATUS
|
|
625
|
+
properties["edit_statuses"] = [(i, str(label)) for i, label in edit_statuses]
|
|
621
626
|
properties["datalayer_edit_statuses"] = [
|
|
622
627
|
(i, str(label)) for i, label in datalayer_statuses
|
|
623
628
|
]
|
|
629
|
+
properties["share_statuses"] = [
|
|
630
|
+
(i, str(label))
|
|
631
|
+
for i, label in share_statuses
|
|
632
|
+
if i not in [Map.BLOCKED, Map.DELETED]
|
|
633
|
+
]
|
|
624
634
|
if self.get_short_url():
|
|
625
635
|
properties["shortUrl"] = self.get_short_url()
|
|
626
636
|
|
|
@@ -655,7 +665,7 @@ class MapDetailMixin(SessionMixin):
|
|
|
655
665
|
def edit_mode(self):
|
|
656
666
|
return "advanced"
|
|
657
667
|
|
|
658
|
-
def
|
|
668
|
+
def get_id(self):
|
|
659
669
|
return None
|
|
660
670
|
|
|
661
671
|
def is_starred(self):
|
|
@@ -683,14 +693,9 @@ class PermissionsMixin:
|
|
|
683
693
|
permissions["edit_status"] = self.object.edit_status
|
|
684
694
|
permissions["share_status"] = self.object.share_status
|
|
685
695
|
if self.object.owner:
|
|
686
|
-
permissions["owner"] =
|
|
687
|
-
"id": self.object.owner.pk,
|
|
688
|
-
"name": str(self.object.owner),
|
|
689
|
-
"url": self.object.owner.get_url(),
|
|
690
|
-
}
|
|
696
|
+
permissions["owner"] = self.object.owner.get_metadata()
|
|
691
697
|
permissions["editors"] = [
|
|
692
|
-
|
|
693
|
-
for editor in self.object.editors.all()
|
|
698
|
+
editor.get_metadata() for editor in self.object.editors.all()
|
|
694
699
|
]
|
|
695
700
|
if self.object.team:
|
|
696
701
|
permissions["team"] = self.object.team.get_metadata()
|
|
@@ -725,6 +730,8 @@ class MapView(MapDetailMixin, PermissionsMixin, DetailView):
|
|
|
725
730
|
return self.object.get_absolute_url()
|
|
726
731
|
|
|
727
732
|
def get_datalayers(self):
|
|
733
|
+
# When initializing datalayers from map, we cannot get the reference version
|
|
734
|
+
# the normal way, which is from the header X-Reference-Version
|
|
728
735
|
return [dl.metadata(self.request) for dl in self.object.datalayer_set.all()]
|
|
729
736
|
|
|
730
737
|
@property
|
|
@@ -736,7 +743,7 @@ class MapView(MapDetailMixin, PermissionsMixin, DetailView):
|
|
|
736
743
|
edit_mode = "simple"
|
|
737
744
|
return edit_mode
|
|
738
745
|
|
|
739
|
-
def
|
|
746
|
+
def get_id(self):
|
|
740
747
|
return self.object.pk
|
|
741
748
|
|
|
742
749
|
def get_short_url(self):
|
|
@@ -844,6 +851,17 @@ class MapViewGeoJSON(MapView):
|
|
|
844
851
|
class MapNew(MapDetailMixin, TemplateView):
|
|
845
852
|
template_name = "umap/map_detail.html"
|
|
846
853
|
|
|
854
|
+
def get_map_properties(self):
|
|
855
|
+
properties = super().get_map_properties()
|
|
856
|
+
properties["permissions"] = {
|
|
857
|
+
"edit_status": Map.edit_status.field.default(),
|
|
858
|
+
"share_status": Map.share_status.field.default(),
|
|
859
|
+
}
|
|
860
|
+
if self.request.user.is_authenticated:
|
|
861
|
+
user = self.request.user
|
|
862
|
+
properties["permissions"]["owner"] = user.get_metadata()
|
|
863
|
+
return properties
|
|
864
|
+
|
|
847
865
|
|
|
848
866
|
class MapPreview(MapDetailMixin, TemplateView):
|
|
849
867
|
template_name = "umap/map_detail.html"
|
|
@@ -1008,7 +1026,7 @@ class MapDelete(DeleteView):
|
|
|
1008
1026
|
self.object = self.get_object()
|
|
1009
1027
|
if not self.object.can_delete(self.request):
|
|
1010
1028
|
return HttpResponseForbidden(_("Only its owner can delete the map."))
|
|
1011
|
-
self.object.
|
|
1029
|
+
self.object.move_to_trash()
|
|
1012
1030
|
home_url = reverse("home")
|
|
1013
1031
|
messages.info(self.request, _("Map successfully deleted."))
|
|
1014
1032
|
if is_ajax(self.request):
|
|
@@ -1103,97 +1121,117 @@ class MapAnonymousEditUrl(RedirectView):
|
|
|
1103
1121
|
# ############## #
|
|
1104
1122
|
|
|
1105
1123
|
|
|
1106
|
-
class
|
|
1107
|
-
|
|
1124
|
+
class DataLayerView(BaseDetailView):
|
|
1125
|
+
model = DataLayer
|
|
1108
1126
|
|
|
1109
1127
|
@property
|
|
1110
|
-
def
|
|
1111
|
-
return
|
|
1128
|
+
def accepts_gzip(self):
|
|
1129
|
+
return settings.UMAP_GZIP and re_accepts_gzip.search(
|
|
1130
|
+
self.request.META.get("HTTP_ACCEPT_ENCODING", "")
|
|
1131
|
+
)
|
|
1112
1132
|
|
|
1113
1133
|
@property
|
|
1114
|
-
def
|
|
1115
|
-
return
|
|
1116
|
-
|
|
1117
|
-
def read_version(self, path):
|
|
1118
|
-
# Remove optional .gz, then .geojson, then return the trailing version from path.
|
|
1119
|
-
return str(path.with_suffix("").with_suffix("")).split("_")[-1]
|
|
1134
|
+
def is_s3(self):
|
|
1135
|
+
return "S3" in settings.STORAGES["data"]["BACKEND"]
|
|
1120
1136
|
|
|
1121
1137
|
@property
|
|
1122
|
-
def
|
|
1123
|
-
|
|
1124
|
-
# but we switched from If-Match header to If-Unmodified-Since
|
|
1125
|
-
# and when users accepts gzip their last modified value is the gzip
|
|
1126
|
-
# (when umap is served by nginx and X-Accel-Redirect)
|
|
1127
|
-
# one, so we need to compare with that value in that case.
|
|
1128
|
-
# cf https://github.com/umap-project/umap/issues/1212
|
|
1129
|
-
path = (
|
|
1130
|
-
self.gzip_path
|
|
1131
|
-
if self.accepts_gzip and self.gzip_path.exists()
|
|
1132
|
-
else self.path
|
|
1133
|
-
)
|
|
1134
|
-
return self.read_version(path)
|
|
1138
|
+
def filepath(self):
|
|
1139
|
+
return Path(self.object.geojson.path)
|
|
1135
1140
|
|
|
1136
1141
|
@property
|
|
1137
|
-
def
|
|
1138
|
-
return
|
|
1139
|
-
self.request.META.get("HTTP_ACCEPT_ENCODING", "")
|
|
1140
|
-
)
|
|
1142
|
+
def fileurl(self):
|
|
1143
|
+
return self.object.geojson.url
|
|
1141
1144
|
|
|
1145
|
+
@property
|
|
1146
|
+
def filedata(self):
|
|
1147
|
+
with self.object.geojson.open("rb") as f:
|
|
1148
|
+
return f.read()
|
|
1142
1149
|
|
|
1143
|
-
|
|
1144
|
-
|
|
1150
|
+
@property
|
|
1151
|
+
def fileversion(self):
|
|
1152
|
+
return self.object.reference_version
|
|
1145
1153
|
|
|
1146
1154
|
def render_to_response(self, context, **response_kwargs):
|
|
1147
1155
|
response = None
|
|
1148
|
-
path = self.path
|
|
1149
1156
|
# Generate gzip if needed
|
|
1150
|
-
if self.accepts_gzip:
|
|
1151
|
-
|
|
1152
|
-
|
|
1157
|
+
if not self.is_s3 and self.accepts_gzip:
|
|
1158
|
+
gzip_path = Path(f"{self.filepath}.gz")
|
|
1159
|
+
if not gzip_path.exists():
|
|
1160
|
+
gzip_file(self.filepath, gzip_path)
|
|
1153
1161
|
|
|
1154
1162
|
if getattr(settings, "UMAP_XSENDFILE_HEADER", None):
|
|
1155
1163
|
response = HttpResponse()
|
|
1156
|
-
|
|
1164
|
+
if self.is_s3:
|
|
1165
|
+
internal_path = f"/s3/{self.fileurl}"
|
|
1166
|
+
else:
|
|
1167
|
+
internal_path = str(self.filepath).replace(
|
|
1168
|
+
settings.MEDIA_ROOT, "/internal"
|
|
1169
|
+
)
|
|
1157
1170
|
response[settings.UMAP_XSENDFILE_HEADER] = internal_path
|
|
1158
1171
|
else:
|
|
1159
1172
|
# Do not use in production
|
|
1160
1173
|
# (no gzip/cache-control/If-Modified-Since/If-None-Match)
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
response = HttpResponse(f.read(), content_type="application/geo+json")
|
|
1165
|
-
response["X-Datalayer-Version"] = self.version
|
|
1166
|
-
response["Content-Length"] = statobj.st_size
|
|
1174
|
+
data = self.filedata
|
|
1175
|
+
response = HttpResponse(data, content_type="application/geo+json")
|
|
1176
|
+
response["X-Datalayer-Version"] = self.fileversion
|
|
1167
1177
|
return response
|
|
1168
1178
|
|
|
1169
1179
|
|
|
1170
1180
|
class DataLayerVersion(DataLayerView):
|
|
1171
1181
|
@property
|
|
1172
|
-
def
|
|
1173
|
-
|
|
1174
|
-
self.
|
|
1175
|
-
|
|
1182
|
+
def filepath(self):
|
|
1183
|
+
try:
|
|
1184
|
+
return Path(settings.MEDIA_ROOT) / self.object.get_version_path(
|
|
1185
|
+
self.kwargs["ref"]
|
|
1186
|
+
)
|
|
1187
|
+
except ValueError:
|
|
1188
|
+
raise Http404("Invalid version reference")
|
|
1176
1189
|
|
|
1190
|
+
@property
|
|
1191
|
+
def fileurl(self):
|
|
1192
|
+
return self.object.get_version_path(self.kwargs["ref"])
|
|
1177
1193
|
|
|
1178
|
-
|
|
1194
|
+
@property
|
|
1195
|
+
def filedata(self):
|
|
1196
|
+
try:
|
|
1197
|
+
return self.object.get_version(self.kwargs["ref"])
|
|
1198
|
+
except ValueError:
|
|
1199
|
+
raise Http404("Invalid version reference.")
|
|
1200
|
+
|
|
1201
|
+
@property
|
|
1202
|
+
def fileversion(self):
|
|
1203
|
+
return self.kwargs["ref"]
|
|
1204
|
+
|
|
1205
|
+
|
|
1206
|
+
class DataLayerCreate(FormLessEditMixin, CreateView):
|
|
1179
1207
|
model = DataLayer
|
|
1180
1208
|
form_class = DataLayerForm
|
|
1181
1209
|
|
|
1182
1210
|
def form_valid(self, form):
|
|
1183
1211
|
form.instance.map = self.kwargs["map_inst"]
|
|
1212
|
+
|
|
1213
|
+
uuid = self.kwargs["pk"]
|
|
1214
|
+
# Check if UUID already exists
|
|
1215
|
+
if DataLayer.objects.filter(uuid=uuid).exists():
|
|
1216
|
+
return HttpResponseBadRequest("UUID already exists")
|
|
1217
|
+
|
|
1218
|
+
form.instance.uuid = uuid
|
|
1184
1219
|
self.object = form.save()
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
response
|
|
1220
|
+
assert uuid == self.object.uuid
|
|
1221
|
+
|
|
1222
|
+
# Simple response with only metadata
|
|
1223
|
+
data = self.object.metadata(self.request)
|
|
1224
|
+
response = simple_json_response(**data)
|
|
1225
|
+
response["X-Datalayer-Version"] = self.object.reference_version
|
|
1188
1226
|
return response
|
|
1189
1227
|
|
|
1190
1228
|
|
|
1191
|
-
class DataLayerUpdate(FormLessEditMixin,
|
|
1229
|
+
class DataLayerUpdate(FormLessEditMixin, UpdateView):
|
|
1192
1230
|
model = DataLayer
|
|
1193
1231
|
form_class = DataLayerForm
|
|
1194
1232
|
|
|
1195
1233
|
def has_changes_since(self, incoming_version):
|
|
1196
|
-
return incoming_version and self.
|
|
1234
|
+
return incoming_version and self.object.reference_version != incoming_version
|
|
1197
1235
|
|
|
1198
1236
|
def merge(self, reference_version):
|
|
1199
1237
|
"""
|
|
@@ -1205,11 +1243,9 @@ class DataLayerUpdate(FormLessEditMixin, GZipMixin, UpdateView):
|
|
|
1205
1243
|
|
|
1206
1244
|
# Use the provided info to find the correct version in our storage.
|
|
1207
1245
|
for version in self.object.versions:
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
with open(path) as f:
|
|
1212
|
-
reference = json.loads(f.read())
|
|
1246
|
+
ref = version["ref"]
|
|
1247
|
+
if reference_version == ref:
|
|
1248
|
+
reference = json.loads(self.object.get_version(ref))
|
|
1213
1249
|
break
|
|
1214
1250
|
else:
|
|
1215
1251
|
# If the reference document is not found, we can't merge.
|
|
@@ -1218,7 +1254,7 @@ class DataLayerUpdate(FormLessEditMixin, GZipMixin, UpdateView):
|
|
|
1218
1254
|
incoming = json.loads(self.request.FILES["geojson"].read())
|
|
1219
1255
|
|
|
1220
1256
|
# Latest known version of the data.
|
|
1221
|
-
with open(
|
|
1257
|
+
with self.object.geojson.open() as f:
|
|
1222
1258
|
latest = json.loads(f.read())
|
|
1223
1259
|
|
|
1224
1260
|
try:
|
|
@@ -1262,7 +1298,7 @@ class DataLayerUpdate(FormLessEditMixin, GZipMixin, UpdateView):
|
|
|
1262
1298
|
data["geojson"] = json.loads(self.object.geojson.read().decode())
|
|
1263
1299
|
self.request.session["needs_reload"] = False
|
|
1264
1300
|
response = simple_json_response(**data)
|
|
1265
|
-
response["X-Datalayer-Version"] = self.
|
|
1301
|
+
response["X-Datalayer-Version"] = self.object.reference_version
|
|
1266
1302
|
return response
|
|
1267
1303
|
|
|
1268
1304
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: umap-project
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.8.0
|
|
4
4
|
Summary: Create maps with OpenStreetMap layers in a minute and embed them in your site.
|
|
5
5
|
Author-email: Yohan Boniface <yb@enix.org>
|
|
6
6
|
Maintainer-email: David Larlet <david@larlet.fr>
|
|
@@ -18,39 +18,42 @@ Requires-Python: >=3.10
|
|
|
18
18
|
Requires-Dist: django-agnocomplete==2.2.0
|
|
19
19
|
Requires-Dist: django-environ==0.11.2
|
|
20
20
|
Requires-Dist: django-probes==1.7.0
|
|
21
|
-
Requires-Dist: django==5.1.
|
|
21
|
+
Requires-Dist: django==5.1.4
|
|
22
22
|
Requires-Dist: pillow==11.0.0
|
|
23
23
|
Requires-Dist: psycopg==3.2.3
|
|
24
|
-
Requires-Dist: rcssmin==1.
|
|
24
|
+
Requires-Dist: rcssmin==1.2.0
|
|
25
25
|
Requires-Dist: requests==2.32.3
|
|
26
26
|
Requires-Dist: rjsmin==1.2.3
|
|
27
27
|
Requires-Dist: social-auth-app-django==5.4.2
|
|
28
28
|
Requires-Dist: social-auth-core==4.5.4
|
|
29
29
|
Provides-Extra: dev
|
|
30
|
-
Requires-Dist: djlint==1.
|
|
30
|
+
Requires-Dist: djlint==1.36.3; extra == 'dev'
|
|
31
31
|
Requires-Dist: hatch==1.13.0; extra == 'dev'
|
|
32
32
|
Requires-Dist: isort==5.13.2; extra == 'dev'
|
|
33
|
-
Requires-Dist: mkdocs-material==9.5.
|
|
33
|
+
Requires-Dist: mkdocs-material==9.5.48; extra == 'dev'
|
|
34
34
|
Requires-Dist: mkdocs-static-i18n==1.2.3; extra == 'dev'
|
|
35
35
|
Requires-Dist: mkdocs==1.6.1; extra == 'dev'
|
|
36
|
-
Requires-Dist: pymdown-extensions==10.
|
|
37
|
-
Requires-Dist: ruff==0.
|
|
36
|
+
Requires-Dist: pymdown-extensions==10.12; extra == 'dev'
|
|
37
|
+
Requires-Dist: ruff==0.8.2; extra == 'dev'
|
|
38
38
|
Requires-Dist: vermin==1.6.0; extra == 'dev'
|
|
39
39
|
Provides-Extra: docker
|
|
40
|
-
Requires-Dist: uwsgi==2.0.
|
|
40
|
+
Requires-Dist: uwsgi==2.0.28; extra == 'docker'
|
|
41
|
+
Provides-Extra: s3
|
|
42
|
+
Requires-Dist: django-storages[s3]==1.14.4; extra == 's3'
|
|
41
43
|
Provides-Extra: sync
|
|
42
|
-
Requires-Dist: channels==4.
|
|
44
|
+
Requires-Dist: channels==4.2.0; extra == 'sync'
|
|
43
45
|
Requires-Dist: daphne==4.1.2; extra == 'sync'
|
|
44
|
-
Requires-Dist: pydantic==2.
|
|
46
|
+
Requires-Dist: pydantic==2.10.3; extra == 'sync'
|
|
45
47
|
Requires-Dist: websockets==13.1; extra == 'sync'
|
|
46
48
|
Provides-Extra: test
|
|
47
49
|
Requires-Dist: factory-boy==3.3.1; extra == 'test'
|
|
50
|
+
Requires-Dist: moto[s3]==5.0.21; extra == 'test'
|
|
48
51
|
Requires-Dist: playwright>=1.39; extra == 'test'
|
|
49
52
|
Requires-Dist: pytest-django==4.9.0; extra == 'test'
|
|
50
|
-
Requires-Dist: pytest-playwright==0.
|
|
51
|
-
Requires-Dist: pytest-rerunfailures==
|
|
53
|
+
Requires-Dist: pytest-playwright==0.6.2; extra == 'test'
|
|
54
|
+
Requires-Dist: pytest-rerunfailures==15.0; extra == 'test'
|
|
52
55
|
Requires-Dist: pytest-xdist<4,>=3.5.0; extra == 'test'
|
|
53
|
-
Requires-Dist: pytest==8.3.
|
|
56
|
+
Requires-Dist: pytest==8.3.4; extra == 'test'
|
|
54
57
|
Description-Content-Type: text/markdown
|
|
55
58
|
|
|
56
59
|
# uMap project
|