umap-project 1.14.0a5__py3-none-any.whl → 2.0.0a1__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.
Potentially problematic release.
This version of umap-project might be problematic. Click here for more details.
- umap/__init__.py +1 -1
- umap/decorators.py +0 -14
- umap/locale/br/LC_MESSAGES/django.mo +0 -0
- umap/locale/br/LC_MESSAGES/django.po +137 -85
- umap/locale/cs_CZ/LC_MESSAGES/django.mo +0 -0
- umap/locale/cs_CZ/LC_MESSAGES/django.po +136 -84
- umap/locale/el/LC_MESSAGES/django.mo +0 -0
- umap/locale/el/LC_MESSAGES/django.po +136 -84
- umap/locale/en/LC_MESSAGES/django.po +128 -88
- umap/locale/es/LC_MESSAGES/django.mo +0 -0
- umap/locale/es/LC_MESSAGES/django.po +136 -84
- umap/locale/fr/LC_MESSAGES/django.mo +0 -0
- umap/locale/fr/LC_MESSAGES/django.po +131 -91
- umap/locale/hu/LC_MESSAGES/django.mo +0 -0
- umap/locale/hu/LC_MESSAGES/django.po +137 -85
- umap/locale/it/LC_MESSAGES/django.mo +0 -0
- umap/locale/it/LC_MESSAGES/django.po +136 -84
- umap/locale/ms/LC_MESSAGES/django.mo +0 -0
- umap/locale/ms/LC_MESSAGES/django.po +136 -84
- umap/locale/pl/LC_MESSAGES/django.mo +0 -0
- umap/locale/pl/LC_MESSAGES/django.po +136 -84
- umap/locale/sv/LC_MESSAGES/django.mo +0 -0
- umap/locale/sv/LC_MESSAGES/django.po +135 -83
- umap/locale/zh_TW/LC_MESSAGES/django.mo +0 -0
- umap/locale/zh_TW/LC_MESSAGES/django.po +143 -91
- umap/models.py +23 -1
- umap/settings/__init__.py +1 -4
- umap/settings/base.py +1 -0
- umap/static/umap/base.css +5 -0
- umap/static/umap/content.css +185 -13
- umap/static/umap/favicons/icon.svg +2 -2
- umap/static/umap/img/edit.svg +3 -3
- umap/static/umap/img/icon-delete.svg +4 -0
- umap/static/umap/img/icon-download.svg +13 -0
- umap/static/umap/img/icon-duplicate.svg +5 -0
- umap/static/umap/img/icon-edit.svg +12 -0
- umap/static/umap/img/icon-share.svg +11 -0
- umap/static/umap/img/icon-view.svg +12 -0
- umap/static/umap/img/logo.svg +2 -2
- umap/static/umap/img/logo_small.svg +2 -2
- umap/static/umap/img/marker.svg +4 -0
- umap/static/umap/img/opensource.svg +2 -2
- umap/static/umap/img/osm.svg +2 -2
- umap/static/umap/js/components/fragment.js +1 -1
- umap/static/umap/js/modules/browser.js +159 -0
- umap/static/umap/js/modules/global.js +3 -1
- umap/static/umap/js/modules/request.js +155 -0
- umap/static/umap/js/umap.autocomplete.js +28 -38
- umap/static/umap/js/umap.controls.js +73 -58
- umap/static/umap/js/umap.core.js +4 -9
- umap/static/umap/js/umap.datalayer.permissions.js +13 -12
- umap/static/umap/js/umap.features.js +51 -49
- umap/static/umap/js/umap.forms.js +19 -19
- umap/static/umap/js/umap.icon.js +17 -17
- umap/static/umap/js/umap.importer.js +2 -1
- umap/static/umap/js/umap.js +242 -291
- umap/static/umap/js/umap.layer.js +173 -141
- umap/static/umap/js/umap.permissions.js +24 -25
- umap/static/umap/js/umap.popup.js +14 -14
- umap/static/umap/js/umap.share.js +4 -4
- umap/static/umap/js/umap.slideshow.js +4 -4
- umap/static/umap/js/umap.tableeditor.js +2 -2
- umap/static/umap/js/umap.ui.js +1 -1
- umap/static/umap/locale/am_ET.js +1 -11
- umap/static/umap/locale/am_ET.json +1 -11
- umap/static/umap/locale/ar.js +1 -11
- umap/static/umap/locale/ar.json +1 -11
- umap/static/umap/locale/ast.js +1 -11
- umap/static/umap/locale/ast.json +1 -11
- umap/static/umap/locale/bg.js +1 -11
- umap/static/umap/locale/bg.json +1 -11
- umap/static/umap/locale/br.js +1 -11
- umap/static/umap/locale/br.json +1 -11
- umap/static/umap/locale/ca.js +1 -11
- umap/static/umap/locale/ca.json +1 -11
- umap/static/umap/locale/cs_CZ.js +1 -11
- umap/static/umap/locale/cs_CZ.json +1 -11
- umap/static/umap/locale/da.js +1 -11
- umap/static/umap/locale/da.json +1 -11
- umap/static/umap/locale/de.js +1 -11
- umap/static/umap/locale/de.json +1 -11
- umap/static/umap/locale/el.js +1 -11
- umap/static/umap/locale/el.json +1 -11
- umap/static/umap/locale/en.js +1 -11
- umap/static/umap/locale/en.json +1 -11
- umap/static/umap/locale/en_US.json +1 -11
- umap/static/umap/locale/es.js +1 -11
- umap/static/umap/locale/es.json +1 -11
- umap/static/umap/locale/et.js +1 -11
- umap/static/umap/locale/et.json +1 -11
- umap/static/umap/locale/fa_IR.js +6 -16
- umap/static/umap/locale/fa_IR.json +6 -16
- umap/static/umap/locale/fi.js +1 -11
- umap/static/umap/locale/fi.json +1 -11
- umap/static/umap/locale/fr.js +1 -11
- umap/static/umap/locale/fr.json +1 -11
- umap/static/umap/locale/gl.js +1 -11
- umap/static/umap/locale/gl.json +1 -11
- umap/static/umap/locale/he.js +1 -11
- umap/static/umap/locale/he.json +1 -11
- umap/static/umap/locale/hr.js +1 -11
- umap/static/umap/locale/hr.json +1 -11
- umap/static/umap/locale/hu.js +1 -11
- umap/static/umap/locale/hu.json +1 -11
- umap/static/umap/locale/id.js +1 -11
- umap/static/umap/locale/id.json +1 -11
- umap/static/umap/locale/is.js +1 -11
- umap/static/umap/locale/is.json +1 -11
- umap/static/umap/locale/it.js +1 -11
- umap/static/umap/locale/it.json +1 -11
- umap/static/umap/locale/ja.js +1 -11
- umap/static/umap/locale/ja.json +1 -11
- umap/static/umap/locale/ko.js +1 -11
- umap/static/umap/locale/ko.json +1 -11
- umap/static/umap/locale/lt.js +1 -11
- umap/static/umap/locale/lt.json +1 -11
- umap/static/umap/locale/ms.js +1 -11
- umap/static/umap/locale/ms.json +1 -11
- umap/static/umap/locale/nl.js +1 -11
- umap/static/umap/locale/nl.json +1 -11
- umap/static/umap/locale/no.js +1 -11
- umap/static/umap/locale/no.json +1 -11
- umap/static/umap/locale/pl.js +1 -11
- umap/static/umap/locale/pl.json +1 -11
- umap/static/umap/locale/pl_PL.json +1 -11
- umap/static/umap/locale/pt.js +1 -11
- umap/static/umap/locale/pt.json +1 -11
- umap/static/umap/locale/pt_BR.js +1 -11
- umap/static/umap/locale/pt_BR.json +1 -11
- umap/static/umap/locale/pt_PT.js +1 -11
- umap/static/umap/locale/pt_PT.json +1 -11
- umap/static/umap/locale/ro.js +1 -11
- umap/static/umap/locale/ro.json +1 -11
- umap/static/umap/locale/ru.js +1 -11
- umap/static/umap/locale/ru.json +1 -11
- umap/static/umap/locale/sk_SK.js +1 -11
- umap/static/umap/locale/sk_SK.json +1 -11
- umap/static/umap/locale/sl.js +1 -11
- umap/static/umap/locale/sl.json +1 -11
- umap/static/umap/locale/sr.js +1 -11
- umap/static/umap/locale/sr.json +1 -11
- umap/static/umap/locale/sv.js +1 -11
- umap/static/umap/locale/sv.json +1 -11
- umap/static/umap/locale/th_TH.js +1 -11
- umap/static/umap/locale/th_TH.json +1 -11
- umap/static/umap/locale/tr.js +1 -11
- umap/static/umap/locale/tr.json +1 -11
- umap/static/umap/locale/uk_UA.js +1 -11
- umap/static/umap/locale/uk_UA.json +1 -11
- umap/static/umap/locale/vi.js +1 -11
- umap/static/umap/locale/vi.json +1 -11
- umap/static/umap/locale/vi_VN.json +1 -11
- umap/static/umap/locale/zh.js +1 -11
- umap/static/umap/locale/zh.json +1 -11
- umap/static/umap/locale/zh_CN.json +1 -11
- umap/static/umap/locale/zh_TW.Big5.json +1 -11
- umap/static/umap/locale/zh_TW.js +17 -27
- umap/static/umap/locale/zh_TW.json +17 -27
- umap/static/umap/map.css +2 -2
- umap/static/umap/nav.css +2 -1
- umap/static/umap/test/.eslintrc +0 -1
- umap/static/umap/test/Choropleth.js +29 -27
- umap/static/umap/test/DataLayer.js +207 -239
- umap/static/umap/test/Feature.js +33 -58
- umap/static/umap/test/Map.Export.js +11 -11
- umap/static/umap/test/Map.js +66 -67
- umap/static/umap/test/Marker.js +36 -32
- umap/static/umap/test/Polygon.js +95 -95
- umap/static/umap/test/Polyline.js +31 -31
- umap/static/umap/test/TableEditor.js +29 -25
- umap/static/umap/test/_pre.js +2 -7
- umap/static/umap/test/index.html +4 -4
- umap/storage.py +2 -0
- umap/templates/auth/user_form.html +3 -2
- umap/templates/base.html +1 -0
- umap/templates/registration/login.html +51 -36
- umap/templates/umap/about_summary.html +1 -1
- umap/templates/umap/branding.html +3 -0
- umap/templates/umap/content.html +15 -39
- umap/templates/umap/header.html +0 -0
- umap/templates/umap/home.html +4 -2
- umap/templates/umap/js.html +0 -2
- umap/templates/umap/map_detail.html +9 -0
- umap/templates/umap/map_init.html +1 -1
- umap/templates/umap/map_messages.html +4 -2
- umap/templates/umap/map_table.html +130 -69
- umap/templates/umap/navigation.html +2 -4
- umap/templates/umap/user_dashboard.html +29 -6
- umap/tests/base.py +1 -1
- umap/tests/integration/conftest.py +18 -0
- umap/tests/integration/test_anonymous_owned_map.py +6 -3
- umap/tests/integration/test_browser.py +166 -6
- umap/tests/integration/test_collaborative_editing.py +23 -5
- umap/tests/integration/test_dashboard.py +17 -0
- umap/tests/integration/test_edit_datalayer.py +4 -3
- umap/tests/integration/test_export_map.py +1 -1
- umap/tests/integration/test_import.py +9 -4
- umap/tests/integration/test_map.py +64 -0
- umap/tests/integration/test_map_preview.py +75 -0
- umap/tests/integration/test_owned_map.py +11 -25
- umap/tests/integration/test_picto.py +3 -3
- umap/tests/integration/test_querystring.py +52 -0
- umap/tests/integration/test_share.py +22 -0
- umap/tests/test_map_views.py +157 -14
- umap/tests/test_views.py +50 -11
- umap/urls.py +6 -12
- umap/views.py +170 -47
- {umap_project-1.14.0a5.dist-info → umap_project-2.0.0a1.dist-info}/METADATA +13 -15
- {umap_project-1.14.0a5.dist-info → umap_project-2.0.0a1.dist-info}/RECORD +212 -200
- umap/static/umap/js/umap.browser.js +0 -148
- umap/static/umap/js/umap.xhr.js +0 -304
- umap/static/umap/test/Controls.js +0 -100
- umap/static/umap/test/Map.Init.js +0 -46
- {umap_project-1.14.0a5.dist-info → umap_project-2.0.0a1.dist-info}/WHEEL +0 -0
- {umap_project-1.14.0a5.dist-info → umap_project-2.0.0a1.dist-info}/entry_points.txt +0 -0
- {umap_project-1.14.0a5.dist-info → umap_project-2.0.0a1.dist-info}/licenses/LICENSE +0 -0
umap/views.py
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import io
|
|
1
2
|
import json
|
|
2
3
|
import mimetypes
|
|
3
4
|
import os
|
|
4
5
|
import re
|
|
5
6
|
import socket
|
|
7
|
+
import zipfile
|
|
6
8
|
from datetime import datetime, timedelta
|
|
7
9
|
from http.client import InvalidURL
|
|
8
10
|
from io import BytesIO
|
|
@@ -18,20 +20,23 @@ from django.contrib.auth import logout as do_logout
|
|
|
18
20
|
from django.contrib.gis.measure import D
|
|
19
21
|
from django.contrib.postgres.search import SearchQuery, SearchVector
|
|
20
22
|
from django.contrib.staticfiles.storage import staticfiles_storage
|
|
23
|
+
from django.core.exceptions import PermissionDenied
|
|
21
24
|
from django.core.mail import send_mail
|
|
22
25
|
from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator
|
|
23
26
|
from django.core.signing import BadSignature, Signer
|
|
24
27
|
from django.core.validators import URLValidator, ValidationError
|
|
25
28
|
from django.http import (
|
|
29
|
+
Http404,
|
|
26
30
|
HttpResponse,
|
|
27
31
|
HttpResponseBadRequest,
|
|
28
32
|
HttpResponseForbidden,
|
|
29
33
|
HttpResponsePermanentRedirect,
|
|
30
34
|
HttpResponseRedirect,
|
|
35
|
+
HttpResponseServerError,
|
|
31
36
|
)
|
|
32
37
|
from django.middleware.gzip import re_accepts_gzip
|
|
33
38
|
from django.shortcuts import get_object_or_404
|
|
34
|
-
from django.urls import reverse, reverse_lazy
|
|
39
|
+
from django.urls import resolve, reverse, reverse_lazy
|
|
35
40
|
from django.utils.encoding import smart_bytes
|
|
36
41
|
from django.utils.http import http_date
|
|
37
42
|
from django.utils.timezone import make_aware
|
|
@@ -105,6 +110,12 @@ class PaginatorMixin:
|
|
|
105
110
|
return [self.list_template_name]
|
|
106
111
|
return super().get_template_names()
|
|
107
112
|
|
|
113
|
+
def get(self, *args, **kwargs):
|
|
114
|
+
response = super().get(*args, **kwargs)
|
|
115
|
+
if is_ajax(self.request):
|
|
116
|
+
return simple_json_response(html=response.rendered_content)
|
|
117
|
+
return response
|
|
118
|
+
|
|
108
119
|
|
|
109
120
|
class PublicMapsMixin(object):
|
|
110
121
|
def get_public_maps(self):
|
|
@@ -118,13 +129,26 @@ class PublicMapsMixin(object):
|
|
|
118
129
|
maps = qs.order_by("-modified_at")
|
|
119
130
|
return maps
|
|
120
131
|
|
|
132
|
+
def get_highlighted_maps(self):
|
|
133
|
+
staff = User.objects.filter(is_staff=True)
|
|
134
|
+
stars = Star.objects.filter(by__in=staff).values("map")
|
|
135
|
+
qs = Map.public.filter(pk__in=stars)
|
|
136
|
+
maps = qs.order_by("-modified_at")
|
|
137
|
+
return maps
|
|
138
|
+
|
|
121
139
|
|
|
122
140
|
class Home(PaginatorMixin, TemplateView, PublicMapsMixin):
|
|
123
141
|
template_name = "umap/home.html"
|
|
124
142
|
list_template_name = "umap/map_list.html"
|
|
125
143
|
|
|
126
144
|
def get_context_data(self, **kwargs):
|
|
127
|
-
|
|
145
|
+
if settings.UMAP_HOME_FEED is None:
|
|
146
|
+
maps = []
|
|
147
|
+
elif settings.UMAP_HOME_FEED == "highlighted":
|
|
148
|
+
maps = self.get_highlighted_maps()
|
|
149
|
+
else:
|
|
150
|
+
maps = self.get_public_maps()
|
|
151
|
+
maps = self.paginate(maps, settings.UMAP_MAPS_PER_PAGE)
|
|
128
152
|
|
|
129
153
|
demo_map = None
|
|
130
154
|
if hasattr(settings, "UMAP_DEMO_PK"):
|
|
@@ -140,8 +164,6 @@ class Home(PaginatorMixin, TemplateView, PublicMapsMixin):
|
|
|
140
164
|
except Map.DoesNotExist:
|
|
141
165
|
pass
|
|
142
166
|
|
|
143
|
-
maps = self.paginate(maps, settings.UMAP_MAPS_PER_PAGE)
|
|
144
|
-
|
|
145
167
|
return {
|
|
146
168
|
"maps": maps,
|
|
147
169
|
"demo_map": demo_map,
|
|
@@ -268,20 +290,44 @@ class UserDashboard(PaginatorMixin, DetailView, SearchMixin):
|
|
|
268
290
|
return qs.order_by("-modified_at")
|
|
269
291
|
|
|
270
292
|
def get_context_data(self, **kwargs):
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
"q": self.request.GET.get("q"),
|
|
274
|
-
"maps": self.paginate(
|
|
275
|
-
self.get_maps(), settings.UMAP_MAPS_PER_PAGE_OWNER
|
|
276
|
-
),
|
|
277
|
-
}
|
|
278
|
-
)
|
|
293
|
+
page = self.paginate(self.get_maps(), settings.UMAP_MAPS_PER_PAGE_OWNER)
|
|
294
|
+
kwargs.update({"q": self.request.GET.get("q"), "maps": page})
|
|
279
295
|
return super().get_context_data(**kwargs)
|
|
280
296
|
|
|
281
297
|
|
|
282
298
|
user_dashboard = UserDashboard.as_view()
|
|
283
299
|
|
|
284
300
|
|
|
301
|
+
class UserDownload(DetailView, SearchMixin):
|
|
302
|
+
model = User
|
|
303
|
+
|
|
304
|
+
def get_object(self):
|
|
305
|
+
return self.get_queryset().get(pk=self.request.user.pk)
|
|
306
|
+
|
|
307
|
+
def get_maps(self):
|
|
308
|
+
qs = Map.objects.filter(id__in=self.request.GET.getlist("map_id"))
|
|
309
|
+
qs = qs.filter(owner=self.object).union(qs.filter(editors=self.object))
|
|
310
|
+
return qs.order_by("-modified_at")
|
|
311
|
+
|
|
312
|
+
def render_to_response(self, context, *args, **kwargs):
|
|
313
|
+
zip_buffer = io.BytesIO()
|
|
314
|
+
with zipfile.ZipFile(zip_buffer, "a", zipfile.ZIP_DEFLATED, False) as zip_file:
|
|
315
|
+
for map_ in self.get_maps():
|
|
316
|
+
umapjson = map_.generate_umapjson(self.request)
|
|
317
|
+
geojson_file = io.StringIO(json.dumps(umapjson))
|
|
318
|
+
file_name = f"umap_backup_{map_.slug}_{map_.pk}.umap"
|
|
319
|
+
zip_file.writestr(file_name, geojson_file.getvalue())
|
|
320
|
+
|
|
321
|
+
response = HttpResponse(zip_buffer.getvalue(), content_type="application/zip")
|
|
322
|
+
response[
|
|
323
|
+
"Content-Disposition"
|
|
324
|
+
] = 'attachment; filename="umap_backup_complete.zip"'
|
|
325
|
+
return response
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
user_download = UserDownload.as_view()
|
|
329
|
+
|
|
330
|
+
|
|
285
331
|
class MapsShowCase(View):
|
|
286
332
|
def get(self, *args, **kwargs):
|
|
287
333
|
maps = Map.public.filter(center__distance_gt=(DEFAULT_CENTER, D(km=1)))
|
|
@@ -315,7 +361,6 @@ showcase = MapsShowCase.as_view()
|
|
|
315
361
|
|
|
316
362
|
def validate_url(request):
|
|
317
363
|
assert request.method == "GET"
|
|
318
|
-
assert is_ajax(request)
|
|
319
364
|
url = request.GET.get("url")
|
|
320
365
|
assert url
|
|
321
366
|
try:
|
|
@@ -421,14 +466,28 @@ class MapDetailMixin:
|
|
|
421
466
|
model = Map
|
|
422
467
|
pk_url_kwarg = "map_id"
|
|
423
468
|
|
|
424
|
-
def
|
|
425
|
-
|
|
469
|
+
def set_preconnect(self, properties, context):
|
|
470
|
+
# Try to extract the tilelayer domain, in order to but a preconnect meta.
|
|
471
|
+
url_template = properties.get("tilelayer", {}).get("url_template")
|
|
472
|
+
# Not explicit tilelayer set, take the first of the list, which will be
|
|
473
|
+
# used by frontend too.
|
|
474
|
+
if not url_template:
|
|
475
|
+
tilelayers = properties.get("tilelayers")
|
|
476
|
+
if tilelayers:
|
|
477
|
+
url_template = tilelayers[0].get("url_template")
|
|
478
|
+
if url_template:
|
|
479
|
+
domain = urlparse(url_template).netloc
|
|
480
|
+
# Do not try to preconnect on domains with variables
|
|
481
|
+
if domain and "{" not in domain:
|
|
482
|
+
context["preconnect_domains"] = [f"//{domain}"]
|
|
483
|
+
|
|
484
|
+
def get_map_properties(self):
|
|
426
485
|
user = self.request.user
|
|
427
486
|
properties = {
|
|
428
487
|
"urls": _urls_for_js(),
|
|
429
488
|
"tilelayers": TileLayer.get_list(),
|
|
430
489
|
"editMode": self.edit_mode,
|
|
431
|
-
"default_iconUrl": "%sumap/img/marker.
|
|
490
|
+
"default_iconUrl": "%sumap/img/marker.svg" % settings.STATIC_URL, # noqa
|
|
432
491
|
"umap_id": self.get_umap_id(),
|
|
433
492
|
"starred": self.is_starred(),
|
|
434
493
|
"licences": dict((l.name, l.json) for l in Licence.objects.all()),
|
|
@@ -452,6 +511,17 @@ class MapDetailMixin:
|
|
|
452
511
|
if self.get_short_url():
|
|
453
512
|
properties["shortUrl"] = self.get_short_url()
|
|
454
513
|
|
|
514
|
+
if not user.is_anonymous:
|
|
515
|
+
properties["user"] = {
|
|
516
|
+
"id": user.pk,
|
|
517
|
+
"name": str(user),
|
|
518
|
+
"url": reverse("user_dashboard"),
|
|
519
|
+
}
|
|
520
|
+
return properties
|
|
521
|
+
|
|
522
|
+
def get_context_data(self, **kwargs):
|
|
523
|
+
context = super().get_context_data(**kwargs)
|
|
524
|
+
properties = self.get_map_properties()
|
|
455
525
|
if settings.USE_I18N:
|
|
456
526
|
lang = settings.LANGUAGE_CODE
|
|
457
527
|
# Check attr in case the middleware is not active
|
|
@@ -461,18 +531,13 @@ class MapDetailMixin:
|
|
|
461
531
|
locale = to_locale(lang)
|
|
462
532
|
properties["locale"] = locale
|
|
463
533
|
context["locale"] = locale
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
if "properties" not in map_settings:
|
|
472
|
-
map_settings["properties"] = {}
|
|
473
|
-
map_settings["properties"].update(properties)
|
|
474
|
-
map_settings["properties"]["datalayers"] = self.get_datalayers()
|
|
475
|
-
context["map_settings"] = json.dumps(map_settings, indent=settings.DEBUG)
|
|
534
|
+
geojson = self.get_geojson()
|
|
535
|
+
if "properties" not in geojson:
|
|
536
|
+
geojson["properties"] = {}
|
|
537
|
+
geojson["properties"].update(properties)
|
|
538
|
+
geojson["properties"]["datalayers"] = self.get_datalayers()
|
|
539
|
+
context["map_settings"] = json.dumps(geojson, indent=settings.DEBUG)
|
|
540
|
+
self.set_preconnect(geojson["properties"], context)
|
|
476
541
|
return context
|
|
477
542
|
|
|
478
543
|
def get_datalayers(self):
|
|
@@ -525,6 +590,16 @@ class PermissionsMixin:
|
|
|
525
590
|
|
|
526
591
|
|
|
527
592
|
class MapView(MapDetailMixin, PermissionsMixin, DetailView):
|
|
593
|
+
def get_context_data(self, **kwargs):
|
|
594
|
+
context = super().get_context_data(**kwargs)
|
|
595
|
+
context["oembed_absolute_uri"] = self.request.build_absolute_uri(
|
|
596
|
+
reverse("map_oembed")
|
|
597
|
+
)
|
|
598
|
+
context["absolute_uri"] = self.request.build_absolute_uri(
|
|
599
|
+
self.object.get_absolute_url()
|
|
600
|
+
)
|
|
601
|
+
return context
|
|
602
|
+
|
|
528
603
|
def get(self, request, *args, **kwargs):
|
|
529
604
|
self.object = self.get_object()
|
|
530
605
|
canonical = self.get_canonical_url()
|
|
@@ -588,24 +663,60 @@ class MapDownload(DetailView):
|
|
|
588
663
|
return reverse("map_download", args=(self.object.pk,))
|
|
589
664
|
|
|
590
665
|
def render_to_response(self, context, *args, **kwargs):
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
geojson["uri"] = self.request.build_absolute_uri(self.object.get_absolute_url())
|
|
594
|
-
datalayers = []
|
|
595
|
-
for datalayer in self.object.datalayer_set.all():
|
|
596
|
-
with open(datalayer.geojson.path, "rb") as f:
|
|
597
|
-
layer = json.loads(f.read())
|
|
598
|
-
if datalayer.settings:
|
|
599
|
-
layer["_umap_options"] = datalayer.settings
|
|
600
|
-
datalayers.append(layer)
|
|
601
|
-
geojson["layers"] = datalayers
|
|
602
|
-
response = simple_json_response(**geojson)
|
|
666
|
+
umapjson = self.object.generate_umapjson(self.request)
|
|
667
|
+
response = simple_json_response(**umapjson)
|
|
603
668
|
response[
|
|
604
669
|
"Content-Disposition"
|
|
605
670
|
] = f'attachment; filename="umap_backup_{self.object.slug}.umap"'
|
|
606
671
|
return response
|
|
607
672
|
|
|
608
673
|
|
|
674
|
+
class MapOEmbed(View):
|
|
675
|
+
def get(self, request, *args, **kwargs):
|
|
676
|
+
data = {"type": "rich", "version": "1.0"}
|
|
677
|
+
format_ = request.GET.get("format", "json")
|
|
678
|
+
if format_ != "json":
|
|
679
|
+
response = HttpResponseServerError("Only `json` format is implemented.")
|
|
680
|
+
response.status_code = 501
|
|
681
|
+
return response
|
|
682
|
+
|
|
683
|
+
url = request.GET.get("url")
|
|
684
|
+
if not url:
|
|
685
|
+
raise Http404("Missing `url` parameter.")
|
|
686
|
+
|
|
687
|
+
parsed_url = urlparse(url)
|
|
688
|
+
netloc = parsed_url.netloc
|
|
689
|
+
allowed_hosts = settings.ALLOWED_HOSTS
|
|
690
|
+
if parsed_url.hostname not in allowed_hosts and allowed_hosts != ["*"]:
|
|
691
|
+
raise Http404("Host not allowed.")
|
|
692
|
+
|
|
693
|
+
url_path = parsed_url.path
|
|
694
|
+
view, args, kwargs = resolve(url_path)
|
|
695
|
+
if "slug" not in kwargs or "map_id" not in kwargs:
|
|
696
|
+
raise Http404("Invalid URL path.")
|
|
697
|
+
|
|
698
|
+
map_ = Map.objects.get(id=kwargs["map_id"], slug=kwargs["slug"])
|
|
699
|
+
|
|
700
|
+
if map_.share_status != Map.PUBLIC:
|
|
701
|
+
raise PermissionDenied("This map is not public.")
|
|
702
|
+
|
|
703
|
+
map_url = map_.get_absolute_url()
|
|
704
|
+
label = _("See full screen")
|
|
705
|
+
height = 300
|
|
706
|
+
data["height"] = height
|
|
707
|
+
width = 800
|
|
708
|
+
data["width"] = width
|
|
709
|
+
# TODISCUSS: do we keep width=100% by default for the iframe?
|
|
710
|
+
html = (
|
|
711
|
+
f'<iframe width="100%" height="{height}px" '
|
|
712
|
+
f'frameborder="0" allowfullscreen allow="geolocation" '
|
|
713
|
+
f'src="//{netloc}{map_url}"></iframe>'
|
|
714
|
+
f'<p><a href="//{netloc}{map_url}">{label}</a></p>'
|
|
715
|
+
)
|
|
716
|
+
data["html"] = html
|
|
717
|
+
return simple_json_response(**data)
|
|
718
|
+
|
|
719
|
+
|
|
609
720
|
class MapViewGeoJSON(MapView):
|
|
610
721
|
def get_canonical_url(self):
|
|
611
722
|
return reverse("map_geojson", args=(self.object.pk,))
|
|
@@ -618,6 +729,15 @@ class MapNew(MapDetailMixin, TemplateView):
|
|
|
618
729
|
template_name = "umap/map_detail.html"
|
|
619
730
|
|
|
620
731
|
|
|
732
|
+
class MapPreview(MapDetailMixin, TemplateView):
|
|
733
|
+
template_name = "umap/map_detail.html"
|
|
734
|
+
|
|
735
|
+
def get_map_properties(self):
|
|
736
|
+
properties = super().get_map_properties()
|
|
737
|
+
properties["preview"] = True
|
|
738
|
+
return properties
|
|
739
|
+
|
|
740
|
+
|
|
621
741
|
class MapCreate(FormLessEditMixin, PermissionsMixin, CreateView):
|
|
622
742
|
model = Map
|
|
623
743
|
form_class = MapSettingsForm
|
|
@@ -738,12 +858,14 @@ class MapDelete(DeleteView):
|
|
|
738
858
|
|
|
739
859
|
def form_valid(self, form):
|
|
740
860
|
self.object = self.get_object()
|
|
741
|
-
if self.object.
|
|
861
|
+
if not self.object.can_delete(self.request.user, self.request):
|
|
742
862
|
return HttpResponseForbidden(_("Only its owner can delete the map."))
|
|
743
|
-
if not self.object.owner and not self.object.is_anonymous_owner(self.request):
|
|
744
|
-
return HttpResponseForbidden()
|
|
745
863
|
self.object.delete()
|
|
746
|
-
|
|
864
|
+
home_url = reverse("home")
|
|
865
|
+
if is_ajax(self.request):
|
|
866
|
+
return simple_json_response(redirect=home_url)
|
|
867
|
+
else:
|
|
868
|
+
return HttpResponseRedirect(form.data.get("next") or home_url)
|
|
747
869
|
|
|
748
870
|
|
|
749
871
|
class MapClone(PermissionsMixin, View):
|
|
@@ -755,7 +877,10 @@ class MapClone(PermissionsMixin, View):
|
|
|
755
877
|
return HttpResponseForbidden()
|
|
756
878
|
owner = self.request.user if self.request.user.is_authenticated else None
|
|
757
879
|
self.object = kwargs["map_inst"].clone(owner=owner)
|
|
758
|
-
|
|
880
|
+
if is_ajax(self.request):
|
|
881
|
+
response = simple_json_response(redirect=self.object.get_absolute_url())
|
|
882
|
+
else:
|
|
883
|
+
response = HttpResponseRedirect(self.object.get_absolute_url())
|
|
759
884
|
if not self.request.user.is_authenticated:
|
|
760
885
|
key, value = self.object.signed_cookie_elements
|
|
761
886
|
response.set_signed_cookie(
|
|
@@ -1086,8 +1211,6 @@ def webmanifest(request):
|
|
|
1086
1211
|
|
|
1087
1212
|
def logout(request):
|
|
1088
1213
|
do_logout(request)
|
|
1089
|
-
if is_ajax(request):
|
|
1090
|
-
return simple_json_response(redirect="/")
|
|
1091
1214
|
return HttpResponseRedirect("/")
|
|
1092
1215
|
|
|
1093
1216
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: umap-project
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2.0.0a1
|
|
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>
|
|
@@ -11,33 +11,31 @@ Classifier: Intended Audience :: Developers
|
|
|
11
11
|
Classifier: Operating System :: OS Independent
|
|
12
12
|
Classifier: Programming Language :: Python
|
|
13
13
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
16
14
|
Classifier: Programming Language :: Python :: 3.10
|
|
17
15
|
Classifier: Programming Language :: Python :: 3.11
|
|
18
16
|
Classifier: Programming Language :: Python :: 3.12
|
|
19
17
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
20
|
-
Requires-Python: >=3.
|
|
18
|
+
Requires-Python: >=3.10
|
|
21
19
|
Requires-Dist: django-agnocomplete==2.2.0
|
|
22
|
-
Requires-Dist: django-environ==0.
|
|
20
|
+
Requires-Dist: django-environ==0.11.2
|
|
23
21
|
Requires-Dist: django-probes==1.7.0
|
|
24
|
-
Requires-Dist: django==
|
|
25
|
-
Requires-Dist: pillow==10.0
|
|
26
|
-
Requires-Dist:
|
|
22
|
+
Requires-Dist: django==5.0.2
|
|
23
|
+
Requires-Dist: pillow==10.2.0
|
|
24
|
+
Requires-Dist: psycopg==3.1.18
|
|
27
25
|
Requires-Dist: rcssmin==1.1.2
|
|
28
26
|
Requires-Dist: requests==2.31.0
|
|
29
27
|
Requires-Dist: rjsmin==1.2.2
|
|
30
|
-
Requires-Dist: social-auth-app-django==5.
|
|
31
|
-
Requires-Dist: social-auth-core==4.
|
|
28
|
+
Requires-Dist: social-auth-app-django==5.4.0
|
|
29
|
+
Requires-Dist: social-auth-core==4.5.2
|
|
32
30
|
Provides-Extra: dev
|
|
33
31
|
Requires-Dist: djlint==1.34.1; extra == 'dev'
|
|
34
|
-
Requires-Dist: hatch==1.9.
|
|
32
|
+
Requires-Dist: hatch==1.9.3; extra == 'dev'
|
|
35
33
|
Requires-Dist: isort==5.12; extra == 'dev'
|
|
36
|
-
Requires-Dist: mkdocs-material==9.
|
|
34
|
+
Requires-Dist: mkdocs-material==9.5.7; extra == 'dev'
|
|
37
35
|
Requires-Dist: mkdocs==1.5.3; extra == 'dev'
|
|
38
|
-
Requires-Dist: pymdown-extensions==10.
|
|
39
|
-
Requires-Dist: ruff==0.
|
|
40
|
-
Requires-Dist: vermin==1.
|
|
36
|
+
Requires-Dist: pymdown-extensions==10.7; extra == 'dev'
|
|
37
|
+
Requires-Dist: ruff==0.2.0; extra == 'dev'
|
|
38
|
+
Requires-Dist: vermin==1.6.0; extra == 'dev'
|
|
41
39
|
Provides-Extra: docker
|
|
42
40
|
Requires-Dist: uwsgi==2.0.23; extra == 'docker'
|
|
43
41
|
Provides-Extra: test
|