umap-project 2.0.0a3__py3-none-any.whl → 2.0.3__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/locale/en/LC_MESSAGES/django.po +33 -28
- umap/locale/fr/LC_MESSAGES/django.mo +0 -0
- umap/locale/fr/LC_MESSAGES/django.po +33 -28
- umap/locale/hu/LC_MESSAGES/django.mo +0 -0
- umap/locale/hu/LC_MESSAGES/django.po +48 -43
- umap/locale/it/LC_MESSAGES/django.mo +0 -0
- umap/locale/it/LC_MESSAGES/django.po +20 -20
- umap/locale/ms/LC_MESSAGES/django.mo +0 -0
- umap/locale/ms/LC_MESSAGES/django.po +20 -20
- umap/locale/zh_TW/LC_MESSAGES/django.mo +0 -0
- umap/locale/zh_TW/LC_MESSAGES/django.po +12 -12
- umap/management/commands/import_pictograms.py +1 -1
- umap/settings/base.py +2 -2
- umap/static/umap/base.css +6 -6
- umap/static/umap/content.css +14 -14
- umap/static/umap/js/umap.forms.js +2 -2
- umap/static/umap/js/umap.js +18 -27
- umap/static/umap/js/umap.popup.js +1 -1
- umap/static/umap/js/umap.share.js +2 -0
- umap/static/umap/locale/hu.js +8 -1
- umap/static/umap/locale/hu.json +8 -1
- umap/static/umap/locale/it.js +37 -30
- umap/static/umap/locale/it.json +37 -30
- umap/static/umap/locale/ms.js +28 -21
- umap/static/umap/locale/ms.json +28 -21
- umap/static/umap/locale/zh_TW.js +8 -1
- umap/static/umap/locale/zh_TW.json +8 -1
- umap/static/umap/map.css +9 -9
- umap/static/umap/nav.css +1 -1
- umap/static/umap/test/index.html +16 -13
- umap/static/umap/vars.css +13 -0
- umap/storage.py +3 -2
- umap/templates/registration/login.html +40 -40
- umap/templates/umap/css.html +1 -1
- umap/templates/umap/js.html +26 -15
- umap/templates/umap/map_detail.html +5 -7
- umap/templates/umap/map_fragment.html +1 -1
- umap/templates/umap/map_init.html +10 -3
- umap/templates/umap/map_table.html +18 -17
- umap/templates/umap/user_dashboard.html +8 -9
- umap/tests/conftest.py +0 -2
- umap/tests/integration/test_anonymous_owned_map.py +50 -1
- umap/tests/integration/test_collaborative_editing.py +57 -1
- umap/tests/integration/test_dashboard.py +13 -0
- umap/tests/integration/test_map_preview.py +8 -0
- umap/tests/integration/test_querystring.py +14 -0
- umap/tests/integration/test_share.py +19 -1
- umap/tests/integration/test_star.py +27 -0
- umap/tests/integration/test_statics.py +6 -3
- umap/tests/settings.py +1 -1
- umap/tests/test_map_views.py +3 -3
- umap/urls.py +1 -1
- umap/views.py +16 -10
- {umap_project-2.0.0a3.dist-info → umap_project-2.0.3.dist-info}/METADATA +4 -4
- {umap_project-2.0.0a3.dist-info → umap_project-2.0.3.dist-info}/RECORD +59 -58
- umap/templates/umap/map_messages.html +0 -12
- {umap_project-2.0.0a3.dist-info → umap_project-2.0.3.dist-info}/WHEEL +0 -0
- {umap_project-2.0.0a3.dist-info → umap_project-2.0.3.dist-info}/entry_points.txt +0 -0
- {umap_project-2.0.0a3.dist-info → umap_project-2.0.3.dist-info}/licenses/LICENSE +0 -0
umap/templates/umap/css.html
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
{% load static %}
|
|
2
|
-
|
|
3
2
|
<link rel="stylesheet"
|
|
4
3
|
href="{% static 'umap/vendors/leaflet/leaflet.css' %}" />
|
|
5
4
|
<link rel="stylesheet"
|
|
@@ -22,6 +21,7 @@
|
|
|
22
21
|
href="{% static 'umap/vendors/locatecontrol/L.Control.Locate.min.css' %}" />
|
|
23
22
|
<link rel="stylesheet"
|
|
24
23
|
href="{% static 'umap/vendors/iconlayers/iconLayers.css' %}" />
|
|
24
|
+
<link rel="stylesheet" href="{% static 'umap/vars.css' %}" />
|
|
25
25
|
<link rel="stylesheet" href="{% static 'umap/font.css' %}" />
|
|
26
26
|
<link rel="stylesheet" href="{% static 'umap/base.css' %}" />
|
|
27
27
|
<link rel="stylesheet" href="{% static 'umap/content.css' %}" />
|
umap/templates/umap/js.html
CHANGED
|
@@ -1,37 +1,48 @@
|
|
|
1
1
|
{% load static %}
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
<script type="module"
|
|
3
|
+
src="{% static 'umap/vendors/leaflet/leaflet-src.esm.js' %}"
|
|
4
|
+
defer></script>
|
|
4
5
|
<script type="module" src="{% static 'umap/js/modules/global.js' %}" defer></script>
|
|
5
6
|
<script src="{% static 'umap/vendors/editable/Path.Drag.js' %}" defer></script>
|
|
6
7
|
<script src="{% static 'umap/vendors/editable/Leaflet.Editable.js' %}" defer></script>
|
|
7
8
|
<script src="{% static 'umap/vendors/hash/leaflet-hash.js' %}" defer></script>
|
|
8
9
|
<script src="{% static 'umap/vendors/i18n/Leaflet.i18n.js' %}" defer></script>
|
|
9
|
-
<script src="{% static 'umap/vendors/editinosm/Leaflet.EditInOSM.js' %}"
|
|
10
|
-
|
|
10
|
+
<script src="{% static 'umap/vendors/editinosm/Leaflet.EditInOSM.js' %}"
|
|
11
|
+
defer></script>
|
|
12
|
+
<script src="{% static 'umap/vendors/minimap/Control.MiniMap.min.js' %}"
|
|
13
|
+
defer></script>
|
|
11
14
|
<script src="{% static 'umap/vendors/csv2geojson/csv2geojson.js' %}" defer></script>
|
|
12
15
|
<script src="{% static 'umap/vendors/togeojson/togeojson.umd.js' %}" defer></script>
|
|
13
16
|
<script src="{% static 'umap/vendors/osmtogeojson/osmtogeojson.js' %}" defer></script>
|
|
14
17
|
<script src="{% static 'umap/vendors/loading/Control.Loading.js' %}" defer></script>
|
|
15
|
-
<script src="{% static 'umap/vendors/markercluster/leaflet.markercluster.js' %}"
|
|
16
|
-
|
|
18
|
+
<script src="{% static 'umap/vendors/markercluster/leaflet.markercluster.js' %}"
|
|
19
|
+
defer></script>
|
|
20
|
+
<script src="{% static 'umap/vendors/contextmenu/leaflet.contextmenu.min.js' %}"
|
|
21
|
+
defer></script>
|
|
17
22
|
<script src="{% static 'umap/vendors/photon/leaflet.photon.js' %}" defer></script>
|
|
18
|
-
<script src="{% static 'umap/vendors/georsstogeojson/GeoRSSToGeoJSON.js' %}"
|
|
23
|
+
<script src="{% static 'umap/vendors/georsstogeojson/GeoRSSToGeoJSON.js' %}"
|
|
24
|
+
defer></script>
|
|
19
25
|
<script src="{% static 'umap/vendors/heat/leaflet-heat.js' %}" defer></script>
|
|
20
|
-
<script src="{% static 'umap/vendors/fullscreen/Leaflet.fullscreen.min.js' %}"
|
|
26
|
+
<script src="{% static 'umap/vendors/fullscreen/Leaflet.fullscreen.min.js' %}"
|
|
27
|
+
defer></script>
|
|
21
28
|
<script src="{% static 'umap/vendors/toolbar/leaflet.toolbar.js' %}" defer></script>
|
|
22
|
-
<script src="{% static 'umap/vendors/formbuilder/Leaflet.FormBuilder.js' %}"
|
|
23
|
-
|
|
29
|
+
<script src="{% static 'umap/vendors/formbuilder/Leaflet.FormBuilder.js' %}"
|
|
30
|
+
defer></script>
|
|
31
|
+
<script src="{% static 'umap/vendors/measurable/Leaflet.Measurable.js' %}"
|
|
32
|
+
defer></script>
|
|
24
33
|
<script src="{% static 'umap/vendors/togpx/togpx.js' %}" defer></script>
|
|
25
34
|
<script src="{% static 'umap/vendors/iconlayers/iconLayers.js' %}" defer></script>
|
|
26
35
|
<script src="{% static 'umap/vendors/tokml/tokml.js' %}" defer></script>
|
|
27
|
-
<script src="{% static 'umap/vendors/locatecontrol/L.Control.Locate.min.js' %}"
|
|
36
|
+
<script src="{% static 'umap/vendors/locatecontrol/L.Control.Locate.min.js' %}"
|
|
37
|
+
defer></script>
|
|
28
38
|
<script src="{% static 'umap/vendors/dompurify/purify.min.js' %}" defer></script>
|
|
29
39
|
<script src="{% static 'umap/vendors/colorbrewer/colorbrewer.js' %}" defer></script>
|
|
30
|
-
<script src="{% static 'umap/vendors/simple-statistics/simple-statistics.min.js' %}"
|
|
40
|
+
<script src="{% static 'umap/vendors/simple-statistics/simple-statistics.min.js' %}"
|
|
41
|
+
defer></script>
|
|
31
42
|
{% if locale %}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
43
|
+
{% with "umap/locale/"|add:locale|add:".js" as path %}
|
|
44
|
+
<script src="{% static path %}" defer></script>
|
|
45
|
+
{% endwith %}
|
|
35
46
|
{% endif %}
|
|
36
47
|
<script src="{% static 'umap/js/umap.core.js' %}" defer></script>
|
|
37
48
|
<script src="{% static 'umap/js/umap.autocomplete.js' %}" defer></script>
|
|
@@ -8,21 +8,19 @@
|
|
|
8
8
|
{% endblock body_class %}
|
|
9
9
|
{% block extra_head %}
|
|
10
10
|
{% if preconnect_domains %}
|
|
11
|
-
{% for domain in preconnect_domains %}
|
|
12
|
-
<link rel="preconnect" href="{{ domain }}" />
|
|
13
|
-
{% endfor %}
|
|
11
|
+
{% for domain in preconnect_domains %}<link rel="preconnect" href="{{ domain }}" />{% endfor %}
|
|
14
12
|
{% endif %}
|
|
15
13
|
{% umap_css %}
|
|
16
14
|
{{ block.super }}
|
|
17
15
|
{% umap_js locale=locale %}
|
|
18
16
|
{% if object.share_status != object.PUBLIC %}<meta name="robots" content="noindex">{% endif %}
|
|
19
|
-
<link rel="alternate"
|
|
20
|
-
|
|
21
|
-
|
|
17
|
+
<link rel="alternate"
|
|
18
|
+
type="application/json+oembed"
|
|
19
|
+
href="{{ oembed_absolute_uri }}?url={{ quoted_absolute_uri }}&format=json"
|
|
20
|
+
title="{{ map.name }} oEmbed URL" />
|
|
22
21
|
{% endblock extra_head %}
|
|
23
22
|
{% block content %}
|
|
24
23
|
{% block map_init %}
|
|
25
24
|
{% include "umap/map_init.html" %}
|
|
26
25
|
{% endblock map_init %}
|
|
27
|
-
{% include "umap/map_messages.html" %}
|
|
28
26
|
{% endblock content %}
|
|
@@ -2,9 +2,16 @@
|
|
|
2
2
|
<div id="map"></div>
|
|
3
3
|
<!-- djlint:off -->
|
|
4
4
|
<script defer type="text/javascript">
|
|
5
|
-
let MAP
|
|
6
5
|
window.addEventListener('DOMContentLoaded', (event) => {
|
|
7
|
-
MAP = new U.Map("map", {{ map_settings|notag|safe }})
|
|
8
|
-
|
|
6
|
+
U.MAP = new U.Map("map", {{ map_settings|notag|safe }})
|
|
7
|
+
{% for m in messages %}
|
|
8
|
+
{# We have just one, but we need to loop, as for messages API #}
|
|
9
|
+
U.MAP.ui.alert({
|
|
10
|
+
content: "{{ m }}",
|
|
11
|
+
level: "{{ m.tags }}",
|
|
12
|
+
duration: 100000
|
|
13
|
+
})
|
|
14
|
+
{% endfor %}
|
|
15
|
+
})
|
|
9
16
|
</script>
|
|
10
17
|
<!-- djlint:on -->
|
|
@@ -21,8 +21,9 @@
|
|
|
21
21
|
</th>
|
|
22
22
|
<td>
|
|
23
23
|
{{ map_inst.preview_settings|json_script:unique_id }}
|
|
24
|
-
<button class="map-icon map-opener"
|
|
25
|
-
|
|
24
|
+
<button class="map-icon map-opener"
|
|
25
|
+
data-map-id="{{ unique_id }}"
|
|
26
|
+
title="{% translate "Open preview" %}">
|
|
26
27
|
<span class="icon-dashboard icon-view"></span>
|
|
27
28
|
<span class="sr-only">{% translate "Open preview" %}</span>
|
|
28
29
|
</button>
|
|
@@ -42,35 +43,37 @@
|
|
|
42
43
|
<a href="{{ map_inst.owner.get_url }}">{{ map_inst.owner }}</a>
|
|
43
44
|
</td>
|
|
44
45
|
<td>
|
|
45
|
-
<a href="{{ map_inst.get_absolute_url }}?share"
|
|
46
|
-
|
|
46
|
+
<a href="{{ map_inst.get_absolute_url }}?share"
|
|
47
|
+
class="icon-link"
|
|
48
|
+
title="{% translate "Share" %}">
|
|
47
49
|
<span class="icon-dashboard icon-share"></span>
|
|
48
50
|
<span class="sr-only">{% translate "Share" %}</span>
|
|
49
51
|
</a>
|
|
50
|
-
<a href="{{ map_inst.get_absolute_url }}?edit"
|
|
51
|
-
|
|
52
|
+
<a href="{{ map_inst.get_absolute_url }}?edit"
|
|
53
|
+
class="icon-link"
|
|
54
|
+
title="{% translate "Edit" %}">
|
|
52
55
|
<span class="icon-dashboard icon-edit"></span>
|
|
53
56
|
<span class="sr-only">{% translate "Edit" %}</span>
|
|
54
57
|
</a>
|
|
55
|
-
<a href="{% url 'map_download' map_inst.pk %}"
|
|
56
|
-
|
|
58
|
+
<a href="{% url 'map_download' map_inst.pk %}"
|
|
59
|
+
class="icon-link"
|
|
60
|
+
title="{% translate "Download" %}">
|
|
57
61
|
<span class="icon-dashboard icon-download"></span>
|
|
58
62
|
<span class="sr-only">{% translate "Download" %}</span>
|
|
59
63
|
</a>
|
|
60
64
|
<form action="{% url 'map_clone' map_inst.pk %}" method="post">
|
|
61
65
|
{% csrf_token %}
|
|
62
|
-
<button class="map-icon" type="submit"
|
|
63
|
-
title="{% translate "Clone" %}">
|
|
66
|
+
<button class="map-icon" type="submit" title="{% translate "Clone" %}">
|
|
64
67
|
<span class="icon-dashboard icon-duplicate"></span>
|
|
65
68
|
<span class="sr-only">{% translate "Clone" %}</span>
|
|
66
69
|
</button>
|
|
67
70
|
</form>
|
|
68
71
|
<form action="{% url 'map_delete' map_inst.pk %}"
|
|
69
|
-
|
|
72
|
+
method="post"
|
|
73
|
+
class="map-delete">
|
|
70
74
|
{% csrf_token %}
|
|
71
75
|
<input type="hidden" name="next" value="{% url 'user_dashboard' %}">
|
|
72
|
-
<button class="map-icon" type="submit"
|
|
73
|
-
title="{% translate "Delete" %}">
|
|
76
|
+
<button class="map-icon" type="submit" title="{% translate "Delete" %}">
|
|
74
77
|
<span class="icon-dashboard icon-delete"></span>
|
|
75
78
|
<span class="sr-only">{% translate "Delete" %}</span>
|
|
76
79
|
</button>
|
|
@@ -93,13 +96,11 @@
|
|
|
93
96
|
<span></span>
|
|
94
97
|
{# djlint:on #}
|
|
95
98
|
{% endif %}
|
|
96
|
-
|
|
97
99
|
<span class="current">
|
|
98
100
|
{% blocktranslate with maps_number=maps.number num_pages=maps.paginator.num_pages trimmed %}
|
|
99
101
|
Page {{ maps_number }} of {{ num_pages }}
|
|
100
102
|
{% endblocktranslate %}
|
|
101
103
|
</span>
|
|
102
|
-
|
|
103
104
|
{% if maps.has_next %}
|
|
104
105
|
<a href="?p={{ maps.next_page_number }}{% if q %}&q={{ q }}{% endif %}">{% translate "next" %} ›</a>
|
|
105
106
|
<a href="?p={{ maps.paginator.num_pages }}{% if q %}&q={{ q }}{% endif %}">{% translate "last" %} »</a>
|
|
@@ -111,12 +112,12 @@
|
|
|
111
112
|
{% endif %}
|
|
112
113
|
<span>
|
|
113
114
|
{% blocktranslate with per_page=maps.paginator.per_page trimmed %}
|
|
114
|
-
|
|
115
|
+
Lines per page: {{ per_page }}
|
|
115
116
|
{% endblocktranslate %}
|
|
116
117
|
</span>
|
|
117
118
|
<span>
|
|
118
119
|
{% blocktranslate with count=maps.paginator.count trimmed %}
|
|
119
|
-
|
|
120
|
+
{{ count }} maps
|
|
120
121
|
{% endblocktranslate %}
|
|
121
122
|
</span>
|
|
122
123
|
{% endif %}
|
|
@@ -7,8 +7,7 @@
|
|
|
7
7
|
{% trans "Search my maps" as placeholder %}
|
|
8
8
|
<div class="row">
|
|
9
9
|
<h2 class="section tabs">
|
|
10
|
-
<a class="selected" href="{% url 'user_dashboard' %}"
|
|
11
|
-
>{% blocktranslate with count=maps.paginator.count %}My Maps ({{ count }}){% endblocktranslate %}
|
|
10
|
+
<a class="selected" href="{% url 'user_dashboard' %}">{% blocktranslate with count=maps.paginator.count %}My Maps ({{ count }}){% endblocktranslate %}
|
|
12
11
|
</a>
|
|
13
12
|
<a href="{% url 'user_profile' %}">{% trans "My profile" %}</a>
|
|
14
13
|
</h2>
|
|
@@ -19,17 +18,18 @@
|
|
|
19
18
|
<form action="{{ request.get_full_path }}" method="get">
|
|
20
19
|
<span>
|
|
21
20
|
<label class="sr-only" for="q">{% translate "Map’s title" %}</label>
|
|
22
|
-
<input id="q"
|
|
21
|
+
<input id="q"
|
|
22
|
+
name="q"
|
|
23
|
+
type="search"
|
|
23
24
|
placeholder="{% translate "Map’s title" %}"
|
|
24
25
|
value="{{ request.GET.q|default:"" }}" />
|
|
25
26
|
</span>
|
|
26
27
|
<input type="submit" value="{% trans "Search my maps" %}" />
|
|
27
28
|
</form>
|
|
28
29
|
{% if maps.object_list|length > 1 %}
|
|
29
|
-
<a href="{% url 'user_download' %}?{% spaceless %}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
>{% blocktranslate with count=maps.object_list|length trimmed %}
|
|
30
|
+
<a href="{% url 'user_download' %}?{% spaceless %} {% for map_inst in maps %}map_id={{ map_inst.pk }}{% if not forloop.last %}&{% endif %}{% endfor %} {% endspaceless %}"
|
|
31
|
+
class="button button-download">
|
|
32
|
+
{% blocktranslate with count=maps.object_list|length trimmed %}
|
|
33
33
|
Download {{ count }} maps
|
|
34
34
|
{% endblocktranslate %}
|
|
35
35
|
</a>
|
|
@@ -45,7 +45,6 @@
|
|
|
45
45
|
</div>
|
|
46
46
|
</div>
|
|
47
47
|
{% endblock maincontent %}
|
|
48
|
-
|
|
49
48
|
{% block bottom_js %}
|
|
50
49
|
{{ block.super }}
|
|
51
50
|
<script type="text/javascript">
|
|
@@ -58,7 +57,7 @@
|
|
|
58
57
|
const mapId = button.dataset.mapId
|
|
59
58
|
if (!document.querySelector(`#${mapId}_target`).hasChildNodes()) {
|
|
60
59
|
const previewSettings = JSON.parse(document.getElementById(mapId).textContent)
|
|
61
|
-
const map = new
|
|
60
|
+
const map = new U.Map(`${mapId}_target`, previewSettings)
|
|
62
61
|
CACHE[mapId] = map
|
|
63
62
|
} else {
|
|
64
63
|
CACHE[mapId].invalidateSize()
|
umap/tests/conftest.py
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import re
|
|
2
|
+
from smtplib import SMTPException
|
|
3
|
+
from unittest.mock import patch
|
|
2
4
|
|
|
3
5
|
import pytest
|
|
4
6
|
from django.core.signing import get_cookie_signer
|
|
5
7
|
from playwright.sync_api import expect
|
|
6
8
|
|
|
7
|
-
from umap.models import DataLayer
|
|
9
|
+
from umap.models import DataLayer, Map
|
|
8
10
|
|
|
9
11
|
from ..base import DataLayerFactory
|
|
10
12
|
|
|
@@ -150,3 +152,50 @@ def test_can_change_perms_after_create(tilelayer, live_server, page):
|
|
|
150
152
|
".datalayer-permissions select[name='edit_status'] option:checked"
|
|
151
153
|
)
|
|
152
154
|
expect(option).to_have_text("Inherit")
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def test_alert_message_after_create(
|
|
158
|
+
tilelayer, live_server, page, monkeypatch, settings
|
|
159
|
+
):
|
|
160
|
+
page.goto(f"{live_server.url}/en/map/new")
|
|
161
|
+
save = page.get_by_role("button", name="Save")
|
|
162
|
+
expect(save).to_be_visible()
|
|
163
|
+
alert = page.locator(".umap-alert")
|
|
164
|
+
expect(alert).to_be_hidden()
|
|
165
|
+
with page.expect_response(re.compile(r".*/map/create/")):
|
|
166
|
+
save.click()
|
|
167
|
+
new_map = Map.objects.last()
|
|
168
|
+
expect(alert).to_be_visible()
|
|
169
|
+
expect(
|
|
170
|
+
alert.get_by_text(
|
|
171
|
+
"Your map has been created! As you are not logged in, here is your secret "
|
|
172
|
+
"link to edit the map, please keep it safe:"
|
|
173
|
+
)
|
|
174
|
+
).to_be_visible()
|
|
175
|
+
expect(alert.get_by_role("button", name="Copy")).to_be_visible()
|
|
176
|
+
expect(alert.get_by_role("button", name="Send me the link")).to_be_visible()
|
|
177
|
+
alert.get_by_placeholder("Email").fill("foo@bar.com")
|
|
178
|
+
with patch("umap.views.send_mail") as patched:
|
|
179
|
+
with page.expect_response(re.compile("/en/map/.*/send-edit-link/")):
|
|
180
|
+
alert.get_by_role("button", name="Send me the link").click()
|
|
181
|
+
assert patched.called
|
|
182
|
+
patched.assert_called_with(
|
|
183
|
+
"The uMap edit link for your map: Untitled map",
|
|
184
|
+
f"Here is your secret edit link: {new_map.get_anonymous_edit_url()}",
|
|
185
|
+
"test@test.org",
|
|
186
|
+
["foo@bar.com"],
|
|
187
|
+
fail_silently=False,
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def test_email_sending_error_are_catched(tilelayer, page, live_server):
|
|
192
|
+
page.goto(f"{live_server.url}/en/map/new")
|
|
193
|
+
alert = page.locator(".umap-alert")
|
|
194
|
+
with page.expect_response(re.compile(r".*/map/create/")):
|
|
195
|
+
page.get_by_role("button", name="Save").click()
|
|
196
|
+
alert.get_by_placeholder("Email").fill("foo@bar.com")
|
|
197
|
+
with patch("umap.views.send_mail", side_effect=SMTPException) as patched:
|
|
198
|
+
with page.expect_response(re.compile("/en/map/.*/send-edit-link/")):
|
|
199
|
+
alert.get_by_role("button", name="Send me the link").click()
|
|
200
|
+
assert patched.called
|
|
201
|
+
expect(alert.get_by_text("Can't send email to foo@bar.com")).to_be_visible()
|
|
@@ -38,7 +38,7 @@ def test_collaborative_editing_create_markers(context, live_server, tilelayer):
|
|
|
38
38
|
|
|
39
39
|
with page_one.expect_response(DATALAYER_UPDATE):
|
|
40
40
|
save_p1.click()
|
|
41
|
-
#
|
|
41
|
+
# Prevent two layers to be saved on the same second, as we compare them based
|
|
42
42
|
# on time in case of conflict. FIXME do not use time for comparison.
|
|
43
43
|
sleep(1)
|
|
44
44
|
assert DataLayer.objects.get(pk=datalayer.pk).settings == {
|
|
@@ -140,3 +140,59 @@ def test_collaborative_editing_create_markers(context, live_server, tilelayer):
|
|
|
140
140
|
"permissions": {"edit_status": 1},
|
|
141
141
|
}
|
|
142
142
|
expect(marker_pane_p2).to_have_count(5)
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def test_empty_datalayers_can_be_merged(context, live_server, tilelayer):
|
|
146
|
+
# Let's create a new map with an empty datalayer
|
|
147
|
+
map = MapFactory(name="collaborative editing")
|
|
148
|
+
DataLayerFactory(map=map, edit_status=DataLayer.ANONYMOUS, data={})
|
|
149
|
+
|
|
150
|
+
# Open two tabs at the same time, on the same empty map
|
|
151
|
+
page_one = context.new_page()
|
|
152
|
+
page_one.goto(f"{live_server.url}{map.get_absolute_url()}?edit")
|
|
153
|
+
|
|
154
|
+
page_two = context.new_page()
|
|
155
|
+
page_two.goto(f"{live_server.url}{map.get_absolute_url()}?edit")
|
|
156
|
+
|
|
157
|
+
save_p1 = page_one.get_by_role("button", name="Save")
|
|
158
|
+
expect(save_p1).to_be_visible()
|
|
159
|
+
|
|
160
|
+
# Click on the Draw a marker button on a new map.
|
|
161
|
+
create_marker_p1 = page_one.get_by_title("Draw a marker")
|
|
162
|
+
expect(create_marker_p1).to_be_visible()
|
|
163
|
+
create_marker_p1.click()
|
|
164
|
+
|
|
165
|
+
# Check no marker is present by default.
|
|
166
|
+
marker_pane_p1 = page_one.locator(".leaflet-marker-pane > div")
|
|
167
|
+
expect(marker_pane_p1).to_have_count(0)
|
|
168
|
+
|
|
169
|
+
# Click on the map, it will place a marker at the given position.
|
|
170
|
+
map_el_p1 = page_one.locator("#map")
|
|
171
|
+
map_el_p1.click(position={"x": 200, "y": 200})
|
|
172
|
+
expect(marker_pane_p1).to_have_count(1)
|
|
173
|
+
|
|
174
|
+
with page_one.expect_response(DATALAYER_UPDATE):
|
|
175
|
+
save_p1.click()
|
|
176
|
+
sleep(1)
|
|
177
|
+
|
|
178
|
+
save_p2 = page_two.get_by_role("button", name="Save")
|
|
179
|
+
expect(save_p2).to_be_visible()
|
|
180
|
+
|
|
181
|
+
# Click on the Draw a marker button on a new map.
|
|
182
|
+
create_marker_p2 = page_two.get_by_title("Draw a marker")
|
|
183
|
+
expect(create_marker_p2).to_be_visible()
|
|
184
|
+
create_marker_p2.click()
|
|
185
|
+
|
|
186
|
+
marker_pane_p2 = page_two.locator(".leaflet-marker-pane > div")
|
|
187
|
+
|
|
188
|
+
# Click on the map, it will place a marker at the given position.
|
|
189
|
+
map_el_p2 = page_two.locator("#map")
|
|
190
|
+
map_el_p2.click(position={"x": 220, "y": 220})
|
|
191
|
+
expect(marker_pane_p2).to_have_count(1)
|
|
192
|
+
|
|
193
|
+
# Save p1 and p2 at the same time
|
|
194
|
+
with page_two.expect_response(DATALAYER_UPDATE):
|
|
195
|
+
save_p2.click()
|
|
196
|
+
sleep(1)
|
|
197
|
+
|
|
198
|
+
expect(marker_pane_p2).to_have_count(2)
|
|
@@ -23,3 +23,16 @@ def test_owner_can_delete_map_after_confirmation(map, live_server, login):
|
|
|
23
23
|
delete_button.click()
|
|
24
24
|
assert dialog_shown
|
|
25
25
|
assert Map.objects.all().count() == 0
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def test_dashboard_map_preview(map, live_server, datalayer, login):
|
|
29
|
+
page = login(map.owner)
|
|
30
|
+
page.goto(f"{live_server.url}/en/me")
|
|
31
|
+
dialog = page.locator("dialog")
|
|
32
|
+
expect(dialog).to_be_hidden()
|
|
33
|
+
button = page.get_by_role("button", name="Open preview")
|
|
34
|
+
expect(button).to_be_visible()
|
|
35
|
+
button.click()
|
|
36
|
+
expect(dialog).to_be_visible()
|
|
37
|
+
# Let's check we have a marker on it, so we can guess the map loaded correctly
|
|
38
|
+
expect(dialog.locator(".leaflet-marker-icon")).to_be_visible()
|
|
@@ -73,3 +73,11 @@ def test_map_preview_can_change_styling_from_querystring(page, live_server, tile
|
|
|
73
73
|
markers = page.locator(".leaflet-marker-icon .icon_container")
|
|
74
74
|
expect(markers).to_have_count(1)
|
|
75
75
|
expect(markers).to_have_css("background-color", "rgb(139, 0, 0)")
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def test_can_open_feature_on_load(page, live_server, tilelayer):
|
|
79
|
+
page.goto(
|
|
80
|
+
f"{live_server.url}/map/?data={quote(json.dumps(GEOJSON))}&feature=Niagara Falls"
|
|
81
|
+
)
|
|
82
|
+
# Popup is open.
|
|
83
|
+
expect(page.get_by_text("Niagara Falls")).to_be_visible()
|
|
@@ -50,3 +50,17 @@ def test_can_deactivate_wheel_from_query_string(map, live_server, page):
|
|
|
50
50
|
expect(page).to_have_url(re.compile(r".*#7/.+"))
|
|
51
51
|
page.mouse.wheel(0, 1)
|
|
52
52
|
expect(page).to_have_url(re.compile(r".*#7/.+"))
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def test_zoom_control(map, live_server, datalayer, page):
|
|
56
|
+
control = page.locator(".leaflet-control-zoom")
|
|
57
|
+
page.goto(f"{live_server.url}{map.get_absolute_url()}")
|
|
58
|
+
expect(control).to_be_visible()
|
|
59
|
+
page.goto(f"{live_server.url}{map.get_absolute_url()}?zoomControl=false")
|
|
60
|
+
expect(control).to_be_hidden()
|
|
61
|
+
page.goto(f"{live_server.url}{map.get_absolute_url()}?zoomControl=true")
|
|
62
|
+
expect(control).to_be_visible()
|
|
63
|
+
page.goto(f"{live_server.url}{map.get_absolute_url()}?zoomControl=null")
|
|
64
|
+
expect(control).to_be_hidden()
|
|
65
|
+
page.get_by_title("More controls").click()
|
|
66
|
+
expect(control).to_be_visible()
|
|
@@ -6,7 +6,7 @@ from playwright.sync_api import expect
|
|
|
6
6
|
pytestmark = pytest.mark.django_db
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
def
|
|
9
|
+
def test_iframe_code_can_contain_datalayers(map, live_server, datalayer, page):
|
|
10
10
|
page.goto(f"{live_server.url}{map.get_absolute_url()}?share")
|
|
11
11
|
textarea = page.locator(".umap-share-iframe")
|
|
12
12
|
expect(textarea).to_be_visible()
|
|
@@ -20,3 +20,21 @@ def test_iframe_code(map, live_server, datalayer, page):
|
|
|
20
20
|
page.get_by_text("Embed and link options").click()
|
|
21
21
|
page.get_by_title("Keep current visible layers").click()
|
|
22
22
|
expect(textarea).to_have_text(re.compile(f"datalayers={datalayer.pk}"))
|
|
23
|
+
# Now click again
|
|
24
|
+
page.get_by_title("Keep current visible layers").click()
|
|
25
|
+
expect(textarea).not_to_have_text(re.compile(f"datalayers={datalayer.pk}"))
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def test_iframe_code_can_contain_feature(map, live_server, datalayer, page):
|
|
29
|
+
page.goto(f"{live_server.url}{map.get_absolute_url()}?share")
|
|
30
|
+
page.locator(".icon_container").click()
|
|
31
|
+
textarea = page.locator(".umap-share-iframe")
|
|
32
|
+
expect(textarea).to_be_visible()
|
|
33
|
+
expect(textarea).not_to_have_text(re.compile("feature=Here"))
|
|
34
|
+
# Open options
|
|
35
|
+
page.get_by_text("Embed and link options").click()
|
|
36
|
+
page.get_by_title("Open current feature on load").click()
|
|
37
|
+
expect(textarea).to_have_text(re.compile("feature=Here"))
|
|
38
|
+
# Click again to deactivate it
|
|
39
|
+
page.get_by_title("Open current feature on load").click()
|
|
40
|
+
expect(textarea).not_to_have_text(re.compile("feature=Here"))
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import re
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
from playwright.sync_api import expect
|
|
5
|
+
|
|
6
|
+
from umap.models import Star
|
|
7
|
+
|
|
8
|
+
pytestmark = pytest.mark.django_db
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def test_star_control_is_visible_if_logged_in(map, live_server, page, login, user):
|
|
12
|
+
login(user)
|
|
13
|
+
assert not Star.objects.count()
|
|
14
|
+
page.goto(f"{live_server.url}{map.get_absolute_url()}")
|
|
15
|
+
page.get_by_title("More controls").click()
|
|
16
|
+
control = page.locator(".leaflet-control-star")
|
|
17
|
+
expect(control).to_be_visible()
|
|
18
|
+
with page.expect_response(re.compile(".*/star/")):
|
|
19
|
+
control.click()
|
|
20
|
+
assert Star.objects.count() == 1
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def test_no_star_control_if_not_logged_in(map, live_server, page):
|
|
24
|
+
page.goto(f"{live_server.url}{map.get_absolute_url()}")
|
|
25
|
+
page.get_by_title("More controls").click()
|
|
26
|
+
control = page.locator(".leaflet-control-star")
|
|
27
|
+
expect(control).to_be_hidden()
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import re
|
|
2
2
|
import shutil
|
|
3
3
|
import tempfile
|
|
4
|
+
from copy import deepcopy
|
|
4
5
|
|
|
5
6
|
import pytest
|
|
6
7
|
from django.core.management import call_command
|
|
@@ -12,6 +13,11 @@ from playwright.sync_api import expect
|
|
|
12
13
|
def staticfiles(settings):
|
|
13
14
|
static_root = tempfile.mkdtemp(prefix="test_static")
|
|
14
15
|
settings.STATIC_ROOT = static_root
|
|
16
|
+
# Make sure settings are properly reset after the test
|
|
17
|
+
settings.STORAGES = deepcopy(settings.STORAGES)
|
|
18
|
+
settings.STORAGES["staticfiles"][
|
|
19
|
+
"BACKEND"
|
|
20
|
+
] = "umap.storage.UmapManifestStaticFilesStorage"
|
|
15
21
|
try:
|
|
16
22
|
call_command("collectstatic", "--noinput")
|
|
17
23
|
yield
|
|
@@ -22,9 +28,6 @@ def staticfiles(settings):
|
|
|
22
28
|
def test_javascript_have_been_loaded(
|
|
23
29
|
map, live_server, datalayer, page, settings, staticfiles
|
|
24
30
|
):
|
|
25
|
-
settings.STORAGES["staticfiles"][
|
|
26
|
-
"BACKEND"
|
|
27
|
-
] = "umap.storage.UmapManifestStaticFilesStorage"
|
|
28
31
|
datalayer.settings["displayOnLoad"] = False
|
|
29
32
|
datalayer.save()
|
|
30
33
|
map.settings["properties"]["defaultView"] = "latest"
|
umap/tests/settings.py
CHANGED
|
@@ -3,7 +3,7 @@ import os
|
|
|
3
3
|
from umap.settings.base import * # pylint: disable=W0614,W0401
|
|
4
4
|
|
|
5
5
|
SECRET_KEY = "justfortests"
|
|
6
|
-
|
|
6
|
+
DEFAULT_FROM_EMAIL = "test@test.org"
|
|
7
7
|
EMAIL_BACKEND = "django.core.mail.backends.locmem.EmailBackend"
|
|
8
8
|
STORAGES["staticfiles"][
|
|
9
9
|
"BACKEND"
|
umap/tests/test_map_views.py
CHANGED
|
@@ -818,10 +818,10 @@ def test_oembed_map(client, map, datalayer):
|
|
|
818
818
|
def test_oembed_link(client, map, datalayer):
|
|
819
819
|
response = client.get(map.get_absolute_url())
|
|
820
820
|
assert response.status_code == 200
|
|
821
|
+
|
|
821
822
|
assert (
|
|
822
|
-
'<link rel="alternate"
|
|
823
|
-
|
|
824
|
-
)
|
|
823
|
+
'<link rel="alternate"\n type="application/json+oembed"'
|
|
824
|
+
) in response.content.decode()
|
|
825
825
|
assert (
|
|
826
826
|
'href="http://testserver/map/oembed/'
|
|
827
827
|
f'?url=http%3A%2F%2Ftestserver%2Fen%2Fmap%2Ftest-map_{map.id}&format=json"'
|
umap/urls.py
CHANGED
umap/views.py
CHANGED
|
@@ -9,6 +9,7 @@ from datetime import datetime, timedelta
|
|
|
9
9
|
from http.client import InvalidURL
|
|
10
10
|
from io import BytesIO
|
|
11
11
|
from pathlib import Path
|
|
12
|
+
from smtplib import SMTPException
|
|
12
13
|
from urllib.error import HTTPError, URLError
|
|
13
14
|
from urllib.parse import quote, quote_plus, urlparse
|
|
14
15
|
from urllib.request import Request, build_opener
|
|
@@ -836,16 +837,19 @@ class SendEditLink(FormLessEditMixin, FormView):
|
|
|
836
837
|
return HttpResponseBadRequest("Invalid")
|
|
837
838
|
link = self.object.get_anonymous_edit_url()
|
|
838
839
|
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
% {"map_name": self.object.name}
|
|
843
|
-
),
|
|
844
|
-
_("Here is your secret edit link: %(link)s" % {"link": link}),
|
|
845
|
-
settings.FROM_EMAIL,
|
|
846
|
-
[email],
|
|
847
|
-
fail_silently=False,
|
|
840
|
+
subject = _(
|
|
841
|
+
"The uMap edit link for your map: %(map_name)s"
|
|
842
|
+
% {"map_name": self.object.name}
|
|
848
843
|
)
|
|
844
|
+
body = _("Here is your secret edit link: %(link)s" % {"link": link})
|
|
845
|
+
try:
|
|
846
|
+
send_mail(
|
|
847
|
+
subject, body, settings.DEFAULT_FROM_EMAIL, [email], fail_silently=False
|
|
848
|
+
)
|
|
849
|
+
except SMTPException:
|
|
850
|
+
return simple_json_response(
|
|
851
|
+
error=_("Can't send email to %(email)s" % {"email": email})
|
|
852
|
+
)
|
|
849
853
|
return simple_json_response(
|
|
850
854
|
info=_("Email sent to %(email)s" % {"email": email})
|
|
851
855
|
)
|
|
@@ -1076,7 +1080,9 @@ class DataLayerUpdate(FormLessEditMixin, GZipMixin, UpdateView):
|
|
|
1076
1080
|
|
|
1077
1081
|
try:
|
|
1078
1082
|
merged_features = merge_features(
|
|
1079
|
-
reference
|
|
1083
|
+
reference.get("features", []),
|
|
1084
|
+
latest.get("features", []),
|
|
1085
|
+
entrant.get("features", []),
|
|
1080
1086
|
)
|
|
1081
1087
|
latest["features"] = merged_features
|
|
1082
1088
|
return latest
|