From d4e253190f1c0296e66299c2db55b9f6a38a087b Mon Sep 17 00:00:00 2001 From: Yohan Boniface Date: Mon, 22 Jan 2024 17:26:06 +0100 Subject: [PATCH] feat: set preconnect link for tilelayer --- umap/templates/umap/map_detail.html | 5 ++++ umap/tests/base.py | 2 +- umap/tests/integration/test_export_map.py | 2 +- umap/tests/integration/test_map.py | 29 +++++++++++++++++++++++ umap/tests/test_map_views.py | 4 ++-- umap/views.py | 16 +++++++++++++ 6 files changed, 54 insertions(+), 4 deletions(-) diff --git a/umap/templates/umap/map_detail.html b/umap/templates/umap/map_detail.html index 42000f4a..88eb5d4e 100644 --- a/umap/templates/umap/map_detail.html +++ b/umap/templates/umap/map_detail.html @@ -7,6 +7,11 @@ map_detail {% endblock body_class %} {% block extra_head %} + {% if preconnect_domains %} + {% for domain in preconnect_domains %} + + {% endfor %} + {% endif %} {% umap_css %} {% umap_js locale=locale %} {% if object.share_status != object.PUBLIC %}{% endif %} diff --git a/umap/tests/base.py b/umap/tests/base.py index 687793e6..62f948eb 100644 --- a/umap/tests/base.py +++ b/umap/tests/base.py @@ -81,7 +81,7 @@ class MapFactory(factory.django.DjangoModelFactory): "attribution": "\xa9 OSM Contributors", "maxZoom": 18, "minZoom": 0, - "url_template": "https://{s}.tile.openstreetmap.fr/osmfr/{z}/{x}/{y}.png", + "url_template": "https://a.tile.openstreetmap.fr/osmfr/{z}/{x}/{y}.png", }, "tilelayersControl": True, "zoom": 7, diff --git a/umap/tests/integration/test_export_map.py b/umap/tests/integration/test_export_map.py index e1735e9b..69599dde 100644 --- a/umap/tests/integration/test_export_map.py +++ b/umap/tests/integration/test_export_map.py @@ -61,7 +61,7 @@ def test_umap_export(map, live_server, datalayer, page): "attribution": "© OSM Contributors", "maxZoom": 18, "minZoom": 0, - "url_template": "https://{s}.tile.openstreetmap.fr/osmfr/{z}/{x}/{y}.png", + "url_template": "https://a.tile.openstreetmap.fr/osmfr/{z}/{x}/{y}.png", }, "tilelayersControl": True, "zoom": 7, diff --git a/umap/tests/integration/test_map.py b/umap/tests/integration/test_map.py index 3bcbb2f8..7f77ad5f 100644 --- a/umap/tests/integration/test_map.py +++ b/umap/tests/integration/test_map.py @@ -12,6 +12,35 @@ from ..base import DataLayerFactory pytestmark = pytest.mark.django_db +def test_preconnect_for_tilelayer(map, page, live_server, tilelayer): + page.goto(f"{live_server.url}{map.get_absolute_url()}") + meta = page.locator('link[rel="preconnect"]') + expect(meta).to_have_count(1) + expect(meta).to_have_attribute("href", "//a.tile.openstreetmap.fr") + # Add custom tilelayer + map.settings["properties"]["tilelayer"] = { + "name": "OSM Piano FR", + "maxZoom": 20, + "minZoom": 0, + "attribution": "test", + "url_template": "https://a.piano.tiles.quaidorsay.fr/fr{r}/{z}/{x}/{y}.png", + } + map.save() + page.goto(f"{live_server.url}{map.get_absolute_url()}") + expect(meta).to_have_attribute("href", "//a.piano.tiles.quaidorsay.fr") + # Add custom tilelayer with variable in domain, should create a preconnect + map.settings["properties"]["tilelayer"] = { + "name": "OSM Piano FR", + "maxZoom": 20, + "minZoom": 0, + "attribution": "test", + "url_template": "https://{s}.piano.tiles.quaidorsay.fr/fr{r}/{z}/{x}/{y}.png", + } + map.save() + page.goto(f"{live_server.url}{map.get_absolute_url()}") + expect(meta).to_have_count(0) + + def test_default_view_latest_without_datalayer_should_use_default_center( map, live_server, datalayer, page ): diff --git a/umap/tests/test_map_views.py b/umap/tests/test_map_views.py index 6ef798e2..f31350e3 100644 --- a/umap/tests/test_map_views.py +++ b/umap/tests/test_map_views.py @@ -19,7 +19,7 @@ def post_data(): return { "name": "name", "center": '{"type":"Point","coordinates":[13.447265624999998,48.94415123418794]}', # noqa - "settings": '{"type":"Feature","geometry":{"type":"Point","coordinates":[5.0592041015625,52.05924589011585]},"properties":{"tilelayer":{"maxZoom":20,"url_template":"http://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png","minZoom":0,"attribution":"HOT and friends"},"licence":"","description":"","name":"test enrhûmé","tilelayersControl":true,"displayDataBrowserOnLoad":false,"displayPopupFooter":true,"displayCaptionOnLoad":false,"miniMap":true,"moreControl":true,"scaleControl":true,"zoomControl":true,"datalayersControl":true,"zoom":8}}', # noqa + "settings": '{"type":"Feature","geometry":{"type":"Point","coordinates":[5.0592041015625,52.05924589011585]},"properties":{"tilelayer":{"maxZoom":20,"url_template":"http://a.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png","minZoom":0,"attribution":"HOT and friends"},"licence":"","description":"","name":"test enrhûmé","tilelayersControl":true,"displayDataBrowserOnLoad":false,"displayPopupFooter":true,"displayCaptionOnLoad":false,"miniMap":true,"moreControl":true,"scaleControl":true,"zoomControl":true,"datalayersControl":true,"zoom":8}}', # noqa } @@ -624,7 +624,7 @@ def test_download(client, map, datalayer): "attribution": "© OSM Contributors", "maxZoom": 18, "minZoom": 0, - "url_template": "https://{s}.tile.openstreetmap.fr/osmfr/{z}/{x}/{y}.png", + "url_template": "https://a.tile.openstreetmap.fr/osmfr/{z}/{x}/{y}.png", }, "tilelayersControl": True, "zoom": 7, diff --git a/umap/views.py b/umap/views.py index 4561fadf..b152afea 100644 --- a/umap/views.py +++ b/umap/views.py @@ -421,6 +421,21 @@ class MapDetailMixin: model = Map pk_url_kwarg = "map_id" + def set_preconnect(self, properties, context): + # Try to extract the tilelayer domain, in order to but a preconnect meta. + url_template = properties.get("tilelayer", {}).get("url_template") + # Not explicit tilelayer set, take the first of the list, which will be + # used by frontend too. + if not url_template: + tilelayers = properties.get("tilelayers") + if tilelayers: + url_template = tilelayers[0].get("url_template") + if url_template: + domain = urlparse(url_template).netloc + # Do not try to preconnect on domains with variables + if domain and "{" not in domain: + context["preconnect_domains"] = [f"//{domain}"] + def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) user = self.request.user @@ -473,6 +488,7 @@ class MapDetailMixin: map_settings["properties"].update(properties) map_settings["properties"]["datalayers"] = self.get_datalayers() context["map_settings"] = json.dumps(map_settings, indent=settings.DEBUG) + self.set_preconnect(map_settings["properties"], context) return context def get_datalayers(self):