diff --git a/umap/models.py b/umap/models.py
index 9b868bba..4bff5f75 100644
--- a/umap/models.py
+++ b/umap/models.py
@@ -223,10 +223,10 @@ class Map(NamedModel):
)
return map_settings
- def generate_geojson(self, request):
- geojson = self.settings
- geojson["type"] = "umap"
- geojson["uri"] = request.build_absolute_uri(self.get_absolute_url())
+ def generate_umapjson(self, request):
+ umapjson = self.settings
+ umapjson["type"] = "umap"
+ umapjson["uri"] = request.build_absolute_uri(self.get_absolute_url())
datalayers = []
for datalayer in self.datalayer_set.all():
with open(datalayer.geojson.path, "rb") as f:
@@ -234,8 +234,8 @@ class Map(NamedModel):
if datalayer.settings:
layer["_umap_options"] = datalayer.settings
datalayers.append(layer)
- geojson["layers"] = datalayers
- return geojson
+ umapjson["layers"] = datalayers
+ return umapjson
def get_absolute_url(self):
return reverse("map", kwargs={"slug": self.slug or "map", "map_id": self.pk})
diff --git a/umap/templates/auth/user_form.html b/umap/templates/auth/user_form.html
index 088b3be5..8fca2454 100644
--- a/umap/templates/auth/user_form.html
+++ b/umap/templates/auth/user_form.html
@@ -3,7 +3,7 @@
{% block maincontent %}
diff --git a/umap/templates/umap/map_table.html b/umap/templates/umap/map_table.html
index 84b8c12b..cec4ceeb 100644
--- a/umap/templates/umap/map_table.html
+++ b/umap/templates/umap/map_table.html
@@ -37,7 +37,8 @@
{% translate "Share" %} |
{% translate "Edit" %} |
- {% translate "Download" %}
+ {% translate "Download" %} |
+ {% translate "Delete" %}
|
{% endwith %}
@@ -45,37 +46,75 @@
- |
-
- {% translate "Download all these maps" %}
+ | |
+
+ {% blocktranslate count counter=maps.object_list|length %}
+ Download this map
+ {% plural %}
+ Download these {{ counter }} maps
+ {% endblocktranslate %}
+
|
-
+{% endif %}
+
diff --git a/umap/templates/umap/user_dashboard.html b/umap/templates/umap/user_dashboard.html
index 6e5d4ac7..64c936c4 100644
--- a/umap/templates/umap/user_dashboard.html
+++ b/umap/templates/umap/user_dashboard.html
@@ -7,7 +7,9 @@
{% trans "Search my maps" as placeholder %}
{% include "umap/search_bar.html" with action=request.get_full_path placeholder=placeholder %}
diff --git a/umap/tests/test_map_views.py b/umap/tests/test_map_views.py
index 3b87fb0d..774234d0 100644
--- a/umap/tests/test_map_views.py
+++ b/umap/tests/test_map_views.py
@@ -1,4 +1,6 @@
import json
+import zipfile
+from io import BytesIO
import pytest
from django.contrib.auth import get_user_model
@@ -8,7 +10,7 @@ from django.urls import reverse
from umap.models import DataLayer, Map, Star
-from .base import login_required
+from .base import MapFactory, UserFactory, login_required
pytestmark = pytest.mark.django_db
User = get_user_model()
@@ -656,6 +658,64 @@ def test_download(client, map, datalayer):
]
+def test_download_multiple_maps(client, map, datalayer):
+ map.share_status = Map.PRIVATE
+ map.save()
+ another_map = MapFactory(
+ owner=map.owner, name="Another map", share_status=Map.PUBLIC
+ )
+ client.login(username=map.owner.username, password="123123")
+ url = reverse("user_download")
+ response = client.get(f"{url}?map_id={map.id}&map_id={another_map.id}")
+ assert response.status_code == 200
+ with zipfile.ZipFile(file=BytesIO(response.content), mode="r") as f:
+ assert len(f.infolist()) == 2
+ assert f.infolist()[0].filename == f"umap_backup_test-map_{another_map.id}.umap"
+ assert f.infolist()[1].filename == f"umap_backup_test-map_{map.id}.umap"
+ with f.open(f.infolist()[1]) as umap_file:
+ umapjson = json.loads(umap_file.read().decode())
+ assert list(umapjson.keys()) == [
+ "type",
+ "geometry",
+ "properties",
+ "uri",
+ "layers",
+ ]
+ assert umapjson["type"] == "umap"
+ assert umapjson["uri"] == f"http://testserver/en/map/test-map_{map.id}"
+
+
+def test_download_multiple_maps_unauthorized(client, map, datalayer):
+ map.share_status = Map.PRIVATE
+ map.save()
+ user1 = UserFactory(username="user1")
+ another_map = MapFactory(owner=user1, name="Another map", share_status=Map.PUBLIC)
+ client.login(username=map.owner.username, password="123123")
+ url = reverse("user_download")
+ response = client.get(f"{url}?map_id={map.id}&map_id={another_map.id}")
+ assert response.status_code == 200
+ with zipfile.ZipFile(file=BytesIO(response.content), mode="r") as f:
+ assert len(f.infolist()) == 1
+ assert f.infolist()[0].filename == f"umap_backup_test-map_{map.id}.umap"
+
+
+def test_download_multiple_maps_editor(client, map, datalayer):
+ map.share_status = Map.PRIVATE
+ map.save()
+ user1 = UserFactory(username="user1")
+ another_map = MapFactory(owner=user1, name="Another map", share_status=Map.PUBLIC)
+ another_map.editors.add(map.owner)
+ another_map.save()
+ client.login(username=map.owner.username, password="123123")
+ url = reverse("user_download")
+ response = client.get(f"{url}?map_id={map.id}&map_id={another_map.id}")
+ assert response.status_code == 200
+ with zipfile.ZipFile(file=BytesIO(response.content), mode="r") as f:
+ assert len(f.infolist()) == 2
+ assert f.infolist()[0].filename == f"umap_backup_test-map_{another_map.id}.umap"
+ assert f.infolist()[1].filename == f"umap_backup_test-map_{map.id}.umap"
+
+
@pytest.mark.parametrize("share_status", [Map.PRIVATE, Map.BLOCKED])
def test_download_shared_status_map(client, map, datalayer, share_status):
map.share_status = share_status
diff --git a/umap/views.py b/umap/views.py
index 423308d5..0456f049 100644
--- a/umap/views.py
+++ b/umap/views.py
@@ -290,46 +290,31 @@ class UserDashboard(PaginatorMixin, DetailView, SearchMixin):
return qs.order_by("-modified_at")
def get_context_data(self, **kwargs):
- kwargs.update(
- {
- "q": self.request.GET.get("q"),
- "maps": self.paginate(
- self.get_maps(), settings.UMAP_MAPS_PER_PAGE_OWNER
- ),
- }
- )
+ page = self.paginate(self.get_maps(), settings.UMAP_MAPS_PER_PAGE_OWNER)
+ kwargs.update({"q": self.request.GET.get("q"), "maps": page})
return super().get_context_data(**kwargs)
user_dashboard = UserDashboard.as_view()
-class UserDownload(PaginatorMixin, DetailView, SearchMixin):
+class UserDownload(DetailView, SearchMixin):
model = User
- def is_owner(self):
- return self.request.user == self.object
-
- @property
- def per_page(self):
- if self.is_owner():
- return settings.UMAP_MAPS_PER_PAGE_OWNER
- return settings.UMAP_MAPS_PER_PAGE
-
def get_object(self):
return self.get_queryset().get(pk=self.request.user.pk)
def get_maps(self):
- qs = self.get_search_queryset() or Map.objects.all()
+ qs = Map.objects.filter(id__in=self.request.GET.getlist("map_id"))
qs = qs.filter(owner=self.object).union(qs.filter(editors=self.object))
return qs.order_by("-modified_at")
def render_to_response(self, context, *args, **kwargs):
zip_buffer = io.BytesIO()
with zipfile.ZipFile(zip_buffer, "a", zipfile.ZIP_DEFLATED, False) as zip_file:
- for map_ in self.paginate(self.get_maps()):
- map_geojson = map_.generate_geojson(self.request)
- geojson_file = io.StringIO(json.dumps(map_geojson))
+ for map_ in self.get_maps():
+ umapjson = map_.generate_umapjson(self.request)
+ geojson_file = io.StringIO(json.dumps(umapjson))
file_name = f"umap_backup_{map_.slug}_{map_.pk}.umap"
zip_file.writestr(file_name, geojson_file.getvalue())
@@ -674,8 +659,8 @@ class MapDownload(DetailView):
return reverse("map_download", args=(self.object.pk,))
def render_to_response(self, context, *args, **kwargs):
- geojson = self.object.generate_geojson(self.request)
- response = simple_json_response(**geojson)
+ umapjson = self.object.generate_umapjson(self.request)
+ response = simple_json_response(**umapjson)
response[
"Content-Disposition"
] = f'attachment; filename="umap_backup_{self.object.slug}.umap"'