umap-project 2.5.1__py3-none-any.whl → 2.6.0b0__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.

Files changed (193) hide show
  1. umap/__init__.py +1 -1
  2. umap/admin.py +6 -1
  3. umap/context_processors.py +2 -1
  4. umap/decorators.py +13 -2
  5. umap/forms.py +26 -2
  6. umap/locale/br/LC_MESSAGES/django.mo +0 -0
  7. umap/locale/br/LC_MESSAGES/django.po +252 -146
  8. umap/locale/ca/LC_MESSAGES/django.mo +0 -0
  9. umap/locale/ca/LC_MESSAGES/django.po +274 -162
  10. umap/locale/cs_CZ/LC_MESSAGES/django.mo +0 -0
  11. umap/locale/cs_CZ/LC_MESSAGES/django.po +261 -150
  12. umap/locale/de/LC_MESSAGES/django.mo +0 -0
  13. umap/locale/de/LC_MESSAGES/django.po +299 -187
  14. umap/locale/el/LC_MESSAGES/django.mo +0 -0
  15. umap/locale/el/LC_MESSAGES/django.po +215 -159
  16. umap/locale/en/LC_MESSAGES/django.po +211 -155
  17. umap/locale/es/LC_MESSAGES/django.mo +0 -0
  18. umap/locale/es/LC_MESSAGES/django.po +255 -144
  19. umap/locale/eu/LC_MESSAGES/django.mo +0 -0
  20. umap/locale/eu/LC_MESSAGES/django.po +254 -198
  21. umap/locale/fa_IR/LC_MESSAGES/django.mo +0 -0
  22. umap/locale/fa_IR/LC_MESSAGES/django.po +346 -234
  23. umap/locale/fr/LC_MESSAGES/django.mo +0 -0
  24. umap/locale/fr/LC_MESSAGES/django.po +216 -160
  25. umap/locale/hu/LC_MESSAGES/django.mo +0 -0
  26. umap/locale/hu/LC_MESSAGES/django.po +215 -159
  27. umap/locale/it/LC_MESSAGES/django.mo +0 -0
  28. umap/locale/it/LC_MESSAGES/django.po +252 -146
  29. umap/locale/ms/LC_MESSAGES/django.mo +0 -0
  30. umap/locale/ms/LC_MESSAGES/django.po +252 -146
  31. umap/locale/pl/LC_MESSAGES/django.mo +0 -0
  32. umap/locale/pl/LC_MESSAGES/django.po +254 -148
  33. umap/locale/pt/LC_MESSAGES/django.mo +0 -0
  34. umap/locale/pt/LC_MESSAGES/django.po +215 -159
  35. umap/locale/sv/LC_MESSAGES/django.mo +0 -0
  36. umap/locale/sv/LC_MESSAGES/django.po +254 -143
  37. umap/locale/th_TH/LC_MESSAGES/django.mo +0 -0
  38. umap/locale/th_TH/LC_MESSAGES/django.po +125 -70
  39. umap/locale/zh_TW/LC_MESSAGES/django.mo +0 -0
  40. umap/locale/zh_TW/LC_MESSAGES/django.po +256 -145
  41. umap/migrations/0022_add_team.py +94 -0
  42. umap/models.py +45 -10
  43. umap/settings/__init__.py +2 -0
  44. umap/settings/base.py +3 -2
  45. umap/static/umap/base.css +32 -41
  46. umap/static/umap/content.css +19 -25
  47. umap/static/umap/css/icon.css +63 -37
  48. umap/static/umap/css/importers.css +1 -1
  49. umap/static/umap/css/slideshow.css +7 -5
  50. umap/static/umap/css/tableeditor.css +4 -3
  51. umap/static/umap/img/16-white.svg +1 -4
  52. umap/static/umap/img/16.svg +2 -6
  53. umap/static/umap/img/24-white.svg +4 -4
  54. umap/static/umap/img/24.svg +6 -6
  55. umap/static/umap/img/source/16-white.svg +2 -5
  56. umap/static/umap/img/source/16.svg +3 -7
  57. umap/static/umap/img/source/24-white.svg +7 -14
  58. umap/static/umap/img/source/24.svg +10 -17
  59. umap/static/umap/js/components/alerts/alert.css +20 -8
  60. umap/static/umap/js/modules/autocomplete.js +3 -3
  61. umap/static/umap/js/modules/browser.js +4 -3
  62. umap/static/umap/js/modules/caption.js +9 -11
  63. umap/static/umap/js/modules/data/features.js +994 -0
  64. umap/static/umap/js/modules/data/layer.js +1210 -0
  65. umap/static/umap/js/modules/formatter.js +12 -3
  66. umap/static/umap/js/modules/global.js +21 -5
  67. umap/static/umap/js/modules/permissions.js +280 -0
  68. umap/static/umap/js/{umap.icon.js → modules/rendering/icon.js} +77 -56
  69. umap/static/umap/js/modules/rendering/layers/base.js +105 -0
  70. umap/static/umap/js/modules/rendering/layers/classified.js +484 -0
  71. umap/static/umap/js/modules/rendering/layers/cluster.js +103 -0
  72. umap/static/umap/js/modules/rendering/layers/heat.js +182 -0
  73. umap/static/umap/js/modules/rendering/popup.js +99 -0
  74. umap/static/umap/js/modules/rendering/template.js +217 -0
  75. umap/static/umap/js/modules/rendering/ui.js +573 -0
  76. umap/static/umap/js/modules/schema.js +24 -0
  77. umap/static/umap/js/modules/share.js +66 -45
  78. umap/static/umap/js/modules/sync/updaters.js +9 -10
  79. umap/static/umap/js/modules/tableeditor.js +7 -7
  80. umap/static/umap/js/modules/ui/dialog.js +8 -4
  81. umap/static/umap/js/modules/utils.js +22 -13
  82. umap/static/umap/js/umap.controls.js +79 -146
  83. umap/static/umap/js/umap.core.js +9 -9
  84. umap/static/umap/js/umap.forms.js +32 -12
  85. umap/static/umap/js/umap.js +65 -63
  86. umap/static/umap/locale/br.js +35 -35
  87. umap/static/umap/locale/br.json +35 -35
  88. umap/static/umap/locale/ca.js +50 -50
  89. umap/static/umap/locale/ca.json +50 -50
  90. umap/static/umap/locale/de.js +136 -136
  91. umap/static/umap/locale/de.json +136 -136
  92. umap/static/umap/locale/el.js +47 -47
  93. umap/static/umap/locale/el.json +47 -47
  94. umap/static/umap/locale/en.js +7 -1
  95. umap/static/umap/locale/en.json +7 -1
  96. umap/static/umap/locale/fa_IR.js +44 -44
  97. umap/static/umap/locale/fa_IR.json +44 -44
  98. umap/static/umap/locale/fr.js +8 -2
  99. umap/static/umap/locale/fr.json +8 -2
  100. umap/static/umap/locale/pt.js +17 -17
  101. umap/static/umap/locale/pt.json +17 -17
  102. umap/static/umap/locale/pt_PT.js +207 -207
  103. umap/static/umap/locale/pt_PT.json +207 -207
  104. umap/static/umap/locale/th_TH.js +25 -25
  105. umap/static/umap/locale/th_TH.json +25 -25
  106. umap/static/umap/map.css +107 -104
  107. umap/static/umap/nav.css +19 -10
  108. umap/static/umap/unittests/utils.js +230 -107
  109. umap/static/umap/vendors/csv2geojson/csv2geojson.js +62 -40
  110. umap/static/umap/vendors/markercluster/MarkerCluster.Default.css +1 -1
  111. umap/storage.py +1 -0
  112. umap/templates/404.html +5 -1
  113. umap/templates/500.html +3 -1
  114. umap/templates/auth/user_detail.html +8 -2
  115. umap/templates/auth/user_form.html +19 -10
  116. umap/templates/auth/user_stars.html +8 -2
  117. umap/templates/base.html +1 -0
  118. umap/templates/registration/login.html +18 -3
  119. umap/templates/umap/about.html +1 -0
  120. umap/templates/umap/about_summary.html +22 -7
  121. umap/templates/umap/components/alerts/alert.html +42 -21
  122. umap/templates/umap/content.html +2 -0
  123. umap/templates/umap/content_footer.html +6 -2
  124. umap/templates/umap/css.html +1 -0
  125. umap/templates/umap/dashboard_menu.html +15 -0
  126. umap/templates/umap/home.html +14 -4
  127. umap/templates/umap/js.html +4 -9
  128. umap/templates/umap/login_popup_end.html +10 -4
  129. umap/templates/umap/map_detail.html +8 -2
  130. umap/templates/umap/map_fragment.html +3 -1
  131. umap/templates/umap/map_init.html +2 -1
  132. umap/templates/umap/map_list.html +4 -3
  133. umap/templates/umap/map_table.html +36 -12
  134. umap/templates/umap/messages.html +0 -1
  135. umap/templates/umap/navigation.html +2 -1
  136. umap/templates/umap/password_change.html +5 -1
  137. umap/templates/umap/password_change_done.html +8 -2
  138. umap/templates/umap/search.html +8 -2
  139. umap/templates/umap/search_bar.html +1 -0
  140. umap/templates/umap/team_confirm_delete.html +19 -0
  141. umap/templates/umap/team_detail.html +27 -0
  142. umap/templates/umap/team_form.html +60 -0
  143. umap/templates/umap/user_dashboard.html +7 -9
  144. umap/templates/umap/user_teams.html +51 -0
  145. umap/tests/base.py +8 -1
  146. umap/tests/conftest.py +6 -0
  147. umap/tests/fixtures/test_circles_layer.geojson +219 -0
  148. umap/tests/fixtures/test_upload_georss.xml +20 -0
  149. umap/tests/integration/conftest.py +18 -4
  150. umap/tests/integration/helpers.py +12 -0
  151. umap/tests/integration/test_anonymous_owned_map.py +23 -0
  152. umap/tests/integration/test_basics.py +29 -0
  153. umap/tests/integration/test_caption.py +20 -0
  154. umap/tests/integration/test_circles_layer.py +69 -0
  155. umap/tests/integration/test_draw_polygon.py +110 -13
  156. umap/tests/integration/test_draw_polyline.py +8 -18
  157. umap/tests/integration/test_edit_datalayer.py +1 -1
  158. umap/tests/integration/test_import.py +64 -5
  159. umap/tests/integration/test_owned_map.py +21 -13
  160. umap/tests/integration/test_team.py +47 -0
  161. umap/tests/integration/test_tilelayer.py +19 -2
  162. umap/tests/integration/test_view_marker.py +28 -1
  163. umap/tests/integration/test_websocket_sync.py +5 -5
  164. umap/tests/test_datalayer.py +32 -7
  165. umap/tests/test_datalayer_views.py +1 -1
  166. umap/tests/test_map.py +30 -4
  167. umap/tests/test_map_views.py +2 -2
  168. umap/tests/test_statics.py +40 -0
  169. umap/tests/test_team_views.py +131 -0
  170. umap/tests/test_views.py +15 -1
  171. umap/urls.py +23 -13
  172. umap/views.py +116 -10
  173. {umap_project-2.5.1.dist-info → umap_project-2.6.0b0.dist-info}/METADATA +9 -9
  174. {umap_project-2.5.1.dist-info → umap_project-2.6.0b0.dist-info}/RECORD +177 -170
  175. umap/static/umap/js/umap.datalayer.permissions.js +0 -70
  176. umap/static/umap/js/umap.features.js +0 -1290
  177. umap/static/umap/js/umap.layer.js +0 -1837
  178. umap/static/umap/js/umap.permissions.js +0 -208
  179. umap/static/umap/js/umap.popup.js +0 -341
  180. umap/static/umap/test/TableEditor.js +0 -104
  181. umap/static/umap/vendors/leaflet/leaflet-src.js +0 -14512
  182. umap/static/umap/vendors/leaflet/leaflet-src.js.map +0 -1
  183. umap/static/umap/vendors/leaflet/leaflet.js +0 -6
  184. umap/static/umap/vendors/leaflet/leaflet.js.map +0 -1
  185. umap/static/umap/vendors/markercluster/WhereAreTheJavascriptFiles.txt +0 -5
  186. umap/static/umap/vendors/markercluster/leaflet.markercluster-src.js +0 -2718
  187. umap/static/umap/vendors/markercluster/leaflet.markercluster-src.js.map +0 -1
  188. umap/static/umap/vendors/toolbar/leaflet.toolbar-src.css +0 -117
  189. umap/static/umap/vendors/toolbar/leaflet.toolbar-src.js +0 -365
  190. umap/tests/integration/test_statics.py +0 -47
  191. {umap_project-2.5.1.dist-info → umap_project-2.6.0b0.dist-info}/WHEEL +0 -0
  192. {umap_project-2.5.1.dist-info → umap_project-2.6.0b0.dist-info}/entry_points.txt +0 -0
  193. {umap_project-2.5.1.dist-info → umap_project-2.6.0b0.dist-info}/licenses/LICENSE +0 -0
@@ -9,6 +9,8 @@ from playwright.sync_api import expect
9
9
 
10
10
  from umap.models import DataLayer
11
11
 
12
+ from .helpers import save_and_get_json
13
+
12
14
  pytestmark = pytest.mark.django_db
13
15
 
14
16
 
@@ -142,7 +144,8 @@ def test_import_kml_from_textarea(tilelayer, live_server, page):
142
144
  expect(paths).to_have_count(2)
143
145
 
144
146
 
145
- def test_import_gpx_from_textarea(tilelayer, live_server, page):
147
+ def test_import_gpx_from_textarea(tilelayer, live_server, page, settings):
148
+ settings.UMAP_ALLOW_ANONYMOUS = True
146
149
  page.goto(f"{live_server.url}/map/new/")
147
150
  page.get_by_title("Open browser").click()
148
151
  layers = page.locator(".umap-browser .datalayer")
@@ -163,6 +166,42 @@ def test_import_gpx_from_textarea(tilelayer, live_server, page):
163
166
  expect(layers).to_have_count(1)
164
167
  expect(markers).to_have_count(1)
165
168
  expect(paths).to_have_count(1)
169
+ data = save_and_get_json(page)
170
+ assert data["features"][0]["geometry"] == {
171
+ "coordinates": [
172
+ [
173
+ -121.7295456,
174
+ 45.4431641,
175
+ ],
176
+ [
177
+ -121.72908,
178
+ 45.4428615,
179
+ ],
180
+ [
181
+ -121.7279085,
182
+ 45.4425697,
183
+ ],
184
+ ],
185
+ "type": "LineString",
186
+ }
187
+ assert data["features"][0]["properties"] == {
188
+ "description": "Simple description",
189
+ "desc": "Simple description",
190
+ "name": "Simple path",
191
+ }
192
+ assert data["features"][1]["geometry"] == {
193
+ "coordinates": [
194
+ -121.72904,
195
+ 45.44283,
196
+ 1374,
197
+ ],
198
+ "type": "Point",
199
+ }
200
+ assert data["features"][1]["properties"] == {
201
+ "description": "Simple description",
202
+ "desc": "Simple description",
203
+ "name": "Simple Point",
204
+ }
166
205
 
167
206
 
168
207
  def test_import_osm_from_textarea(tilelayer, live_server, page):
@@ -476,7 +515,7 @@ def test_create_remote_data(page, live_server, tilelayer):
476
515
  page.route("*/**/ajax-proxy/**", handle)
477
516
  page.goto(f"{live_server.url}/map/new/")
478
517
  expect(page.locator(".leaflet-marker-icon")).to_be_hidden()
479
- page.get_by_role("link", name="Import data (Ctrl+I)").click()
518
+ page.get_by_role("link", name="Import data").click()
480
519
  page.get_by_placeholder("Provide an URL here").click()
481
520
  page.get_by_placeholder("Provide an URL here").fill("https://remote.org/data.json")
482
521
  page.locator("[name=format]").select_option("geojson")
@@ -513,7 +552,7 @@ def test_import_geojson_from_url(page, live_server, tilelayer):
513
552
  page.route("https://remote.org/data.json", handle)
514
553
  page.goto(f"{live_server.url}/map/new/")
515
554
  expect(page.locator(".leaflet-marker-icon")).to_be_hidden()
516
- page.get_by_role("link", name="Import data (Ctrl+I)").click()
555
+ page.get_by_role("link", name="Import data").click()
517
556
  page.get_by_placeholder("Provide an URL here").click()
518
557
  page.get_by_placeholder("Provide an URL here").fill("https://remote.org/data.json")
519
558
  page.locator("[name=format]").select_option("geojson")
@@ -531,7 +570,7 @@ def test_overpass_import_with_bbox(page, live_server, tilelayer, settings):
531
570
  "overpass": {"url": "https://my.overpass.io/interpreter"}
532
571
  }
533
572
  page.goto(f"{live_server.url}/map/new/")
534
- page.get_by_role("link", name="Import data (Ctrl+I)").click()
573
+ page.get_by_role("link", name="Import data").click()
535
574
  page.get_by_role("button", name="Overpass").click()
536
575
  page.get_by_placeholder("amenity=drinking_water").fill("building")
537
576
  page.get_by_role("button", name="Choose this data").click()
@@ -574,7 +613,7 @@ def test_import_from_datasets(page, live_server, tilelayer, settings):
574
613
  page.route("https://remote.org/data.json", handle)
575
614
  page.goto(f"{live_server.url}/map/new/")
576
615
  expect(page.locator(".leaflet-marker-icon")).to_be_hidden()
577
- page.get_by_role("link", name="Import data (Ctrl+I)").click()
616
+ page.get_by_role("link", name="Import data").click()
578
617
  page.get_by_role("button", name="Datasets").click()
579
618
  page.get_by_role("dialog").get_by_role("combobox").select_option(
580
619
  "https://remote.org/data.json"
@@ -607,3 +646,23 @@ def test_import_osm_relation(tilelayer, live_server, page):
607
646
  # A layer and one path has been created
608
647
  expect(layers).to_have_count(1)
609
648
  expect(paths).to_have_count(1)
649
+
650
+
651
+ def test_import_georss_from_textarea(tilelayer, live_server, page):
652
+ page.goto(f"{live_server.url}/map/new/")
653
+ page.get_by_title("Open browser").click()
654
+ layers = page.locator(".umap-browser .datalayer")
655
+ markers = page.locator(".leaflet-marker-icon")
656
+ expect(markers).to_have_count(0)
657
+ expect(layers).to_have_count(0)
658
+ button = page.get_by_title("Import data")
659
+ expect(button).to_be_visible()
660
+ button.click()
661
+ textarea = page.locator(".umap-upload textarea")
662
+ path = Path(__file__).parent.parent / "fixtures/test_upload_georss.xml"
663
+ textarea.fill(path.read_text())
664
+ page.locator('select[name="format"]').select_option("georss")
665
+ page.get_by_role("button", name="Import data", exact=True).click()
666
+ # A layer has been created
667
+ expect(layers).to_have_count(1)
668
+ expect(markers).to_have_count(1)
@@ -81,7 +81,7 @@ def test_owner_permissions_form(map, datalayer, live_server, login):
81
81
 
82
82
 
83
83
  def test_map_update_with_editor(map, live_server, login, user):
84
- map.edit_status = Map.EDITORS
84
+ map.edit_status = Map.COLLABORATORS
85
85
  map.editors.add(user)
86
86
  map.save()
87
87
  page = login(user)
@@ -104,7 +104,7 @@ def test_map_update_with_editor(map, live_server, login, user):
104
104
 
105
105
 
106
106
  def test_permissions_form_with_editor(map, datalayer, live_server, login, user):
107
- map.edit_status = Map.EDITORS
107
+ map.edit_status = Map.COLLABORATORS
108
108
  map.editors.add(user)
109
109
  map.save()
110
110
  page = login(user)
@@ -134,22 +134,14 @@ def test_owner_has_delete_map_button(map, live_server, login):
134
134
  advanced.click()
135
135
  delete = page.get_by_role("button", name="Delete", exact=True)
136
136
  expect(delete).to_be_visible()
137
- dialog_shown = False
138
-
139
- def handle_dialog(dialog):
140
- dialog.accept()
141
- nonlocal dialog_shown
142
- dialog_shown = True
143
-
144
- page.on("dialog", handle_dialog)
137
+ delete.click()
145
138
  with page.expect_navigation():
146
- delete.click()
147
- assert dialog_shown
139
+ page.get_by_role("button", name="OK").click()
148
140
  assert Map.objects.all().count() == 0
149
141
 
150
142
 
151
143
  def test_editor_do_not_have_delete_map_button(map, live_server, login, user):
152
- map.edit_status = Map.EDITORS
144
+ map.edit_status = Map.COLLABORATORS
153
145
  map.editors.add(user)
154
146
  map.save()
155
147
  page = login(user)
@@ -249,3 +241,19 @@ def test_can_delete_datalayer(live_server, map, login, datalayer):
249
241
  expect(markers).to_have_count(0)
250
242
  # FIXME does not work, resolve to 1 element, even if this command is empty:
251
243
  expect(layers).to_have_count(0)
244
+
245
+
246
+ def test_can_set_team(map, live_server, login, team):
247
+ map.owner.teams.add(team)
248
+ map.owner.save()
249
+ page = login(map.owner)
250
+ page.goto(f"{live_server.url}{map.get_absolute_url()}?edit")
251
+ edit_permissions = page.get_by_title("Update permissions and editors")
252
+ edit_permissions.click()
253
+ page.locator("select[name=team]").select_option(str(team.pk))
254
+ save = page.get_by_role("button", name="Save")
255
+ expect(save).to_be_visible()
256
+ with page.expect_response(re.compile(r".*/update/permissions/.*")):
257
+ save.click()
258
+ modified = Map.objects.get(pk=map.pk)
259
+ assert modified.team == team
@@ -0,0 +1,47 @@
1
+ import re
2
+
3
+ import pytest
4
+
5
+ from umap.models import Team
6
+
7
+ pytestmark = pytest.mark.django_db
8
+
9
+
10
+ def test_can_add_user_to_team(live_server, map, user, team, login):
11
+ map.owner.teams.add(team)
12
+ map.owner.save()
13
+ assert Team.objects.count() == 1
14
+ page = login(map.owner)
15
+ with page.expect_navigation():
16
+ page.get_by_role("link", name="My teams").click()
17
+ with page.expect_navigation():
18
+ page.get_by_role("link", name="Edit").click()
19
+ page.get_by_placeholder("Add user").click()
20
+ with page.expect_response(re.compile(r".*/agnocomplete/.*")):
21
+ page.get_by_placeholder("Add user").press_sequentially("joe")
22
+ page.get_by_text("Joe").click()
23
+ page.get_by_role("button", name="Save").click()
24
+ assert Team.objects.count() == 1
25
+ modified = Team.objects.first()
26
+ assert user in modified.users.all()
27
+
28
+
29
+ def test_can_remove_user_from_team(live_server, map, user, user2, team, login):
30
+ map.owner.teams.add(team)
31
+ map.owner.save()
32
+ user.teams.add(team)
33
+ user.save()
34
+ user2.teams.add(team)
35
+ user2.save()
36
+ assert Team.objects.count() == 1
37
+ page = login(map.owner)
38
+ with page.expect_navigation():
39
+ page.get_by_role("link", name="My teams").click()
40
+ with page.expect_navigation():
41
+ page.get_by_role("link", name="Edit").click()
42
+ page.locator("li").filter(has_text="Averell").locator(".close").click()
43
+ page.get_by_role("button", name="Save").click()
44
+ assert Team.objects.count() == 1
45
+ modified = Team.objects.first()
46
+ assert user in modified.users.all()
47
+ assert user2 not in modified.users.all()
@@ -16,7 +16,7 @@ def tilelayers():
16
16
  TileLayerFactory(
17
17
  rank=1,
18
18
  name="OpenStreetMap",
19
- url_template="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
19
+ url_template="https://tile.openstreetmap.org/{z}/{x}/{y}.png",
20
20
  )
21
21
  TileLayerFactory(
22
22
  rank=2,
@@ -76,7 +76,7 @@ def test_map_should_display_first_tilelayer_by_default(
76
76
  page.goto(f"{live_server.url}/map/new")
77
77
  tiles = page.locator(".leaflet-tile-pane img")
78
78
  expect(tiles.first).to_have_attribute(
79
- "src", re.compile(r"https://[abc].tile.openstreetmap.org/\d+/\d+/\d+.png")
79
+ "src", re.compile(r"https://tile.openstreetmap.org/\d+/\d+/\d+.png")
80
80
  )
81
81
 
82
82
 
@@ -122,3 +122,20 @@ def test_can_have_smart_text_in_attribution(tilelayer, map, live_server, page):
122
122
  page.goto(f"{live_server.url}{map.get_absolute_url()}")
123
123
  expect(page.get_by_text("© OpenStreetMap contributors")).to_be_visible()
124
124
  expect(page.get_by_role("link", name="OpenStreetMap")).to_be_visible()
125
+
126
+
127
+ def test_map_should_display_a_more_button(map, live_server, tilelayers, page):
128
+ map.settings["properties"]["tilelayersControl"] = True
129
+ map.save()
130
+ page.goto(f"{live_server.url}{map.get_absolute_url()}")
131
+ page.locator(".leaflet-iconLayers").hover()
132
+ page.get_by_role("button", name="+").click()
133
+ panel = page.locator(".panel.left.on")
134
+ expect(panel).to_be_visible()
135
+ expect(panel.get_by_text("Forte")).to_be_visible()
136
+ panel.get_by_text("Forte").click()
137
+ tiles = page.locator(".leaflet-tile-pane img")
138
+ url_pattern = re.compile(
139
+ r"https://[abc]{1}.forte.tiles.quaidorsay.fr/fr/\d+/\d+/\d+.png"
140
+ )
141
+ expect(tiles.first).to_have_attribute("src", url_pattern)
@@ -19,7 +19,7 @@ DATALAYER_DATA = {
19
19
  },
20
20
  "geometry": {
21
21
  "type": "Point",
22
- "coordinates": [14.6889, 48.5529],
22
+ "coordinates": [14.6889, 48.5529, 241],
23
23
  },
24
24
  },
25
25
  ],
@@ -79,3 +79,30 @@ def test_should_open_popup_panel_on_click(live_server, map, page, bootstrap):
79
79
  # Close popup
80
80
  page.locator("#map").click()
81
81
  expect(panel).to_be_hidden()
82
+
83
+
84
+ def test_extended_properties_in_popup(live_server, map, page, bootstrap):
85
+ map.settings["properties"]["popupContentTemplate"] = """
86
+ Rank: {rank}
87
+ Locale: {locale}
88
+ Lang: {lang}
89
+ Lat: {lat}
90
+ Lon: {lon}
91
+ Alt: {alt}
92
+ Zoom: {zoom}
93
+ Layer: {layer}
94
+ """
95
+ map.save()
96
+ page.goto(f"{live_server.url}{map.get_absolute_url()}")
97
+ expect(page.locator(".umap-icon-active")).to_be_hidden()
98
+ page.locator(".leaflet-marker-icon").click()
99
+ expect(page.locator(".umap-icon-active")).to_be_visible()
100
+ expect(page.locator(".leaflet-popup-content-wrapper")).to_be_visible()
101
+ expect(page.get_by_text("Rank: 1")).to_be_visible()
102
+ expect(page.get_by_text("Locale: en")).to_be_visible()
103
+ expect(page.get_by_text("Lang: en")).to_be_visible()
104
+ expect(page.get_by_text("Lat: 48.5529")).to_be_visible()
105
+ expect(page.get_by_text("Lon: 14.6889")).to_be_visible()
106
+ expect(page.get_by_text("Alt: 241")).to_be_visible()
107
+ expect(page.get_by_text("Zoom: 7")).to_be_visible()
108
+ expect(page.get_by_text("Layer: test datalayer")).to_be_visible()
@@ -12,7 +12,7 @@ DATALAYER_UPDATE = re.compile(r".*/datalayer/update/.*")
12
12
 
13
13
  @pytest.mark.xdist_group(name="websockets")
14
14
  def test_websocket_connection_can_sync_markers(
15
- context, live_server, websocket_server, tilelayer
15
+ new_page, live_server, websocket_server, tilelayer
16
16
  ):
17
17
  map = MapFactory(name="sync", edit_status=Map.ANONYMOUS)
18
18
  map.settings["properties"]["syncEnabled"] = True
@@ -20,9 +20,9 @@ def test_websocket_connection_can_sync_markers(
20
20
  DataLayerFactory(map=map, data={})
21
21
 
22
22
  # Create two tabs
23
- peerA = context.new_page()
23
+ peerA = new_page("Page A")
24
24
  peerA.goto(f"{live_server.url}{map.get_absolute_url()}?edit")
25
- peerB = context.new_page()
25
+ peerB = new_page("Page B")
26
26
  peerB.goto(f"{live_server.url}{map.get_absolute_url()}?edit")
27
27
 
28
28
  a_marker_pane = peerA.locator(".leaflet-marker-pane > div")
@@ -60,12 +60,12 @@ def test_websocket_connection_can_sync_markers(
60
60
  expect(b_marker_pane).to_have_count(2)
61
61
 
62
62
  # Drag a marker on peer B and check that it moved on peer A
63
- a_first_marker.bounding_box() == b_first_marker.bounding_box()
63
+ assert a_first_marker.bounding_box() == b_first_marker.bounding_box()
64
64
  b_old_bbox = b_first_marker.bounding_box()
65
65
  b_first_marker.drag_to(b_map_el, target_position={"x": 250, "y": 250})
66
66
 
67
67
  assert b_old_bbox is not b_first_marker.bounding_box()
68
- a_first_marker.bounding_box() == b_first_marker.bounding_box()
68
+ assert a_first_marker.bounding_box() == b_first_marker.bounding_box()
69
69
 
70
70
  # Delete a marker from peer A and check it's been deleted on peer B
71
71
  a_first_marker.click(button="right")
@@ -101,22 +101,33 @@ def test_should_remove_old_versions_on_save(map, settings):
101
101
 
102
102
 
103
103
  def test_anonymous_cannot_edit_in_editors_mode(datalayer):
104
- datalayer.edit_status = DataLayer.EDITORS
104
+ datalayer.edit_status = DataLayer.COLLABORATORS
105
105
  datalayer.save()
106
106
  assert not datalayer.can_edit()
107
107
 
108
108
 
109
109
  def test_owner_can_edit_in_editors_mode(datalayer, user):
110
- datalayer.edit_status = DataLayer.EDITORS
110
+ datalayer.edit_status = DataLayer.COLLABORATORS
111
111
  datalayer.save()
112
112
  assert datalayer.can_edit(datalayer.map.owner)
113
113
 
114
114
 
115
- def test_editor_can_edit_in_editors_mode(datalayer, user):
115
+ def test_editor_can_edit_in_collaborators_mode(datalayer, user):
116
116
  map = datalayer.map
117
117
  map.editors.add(user)
118
118
  map.save()
119
- datalayer.edit_status = DataLayer.EDITORS
119
+ datalayer.edit_status = DataLayer.COLLABORATORS
120
+ datalayer.save()
121
+ assert datalayer.can_edit(user)
122
+
123
+
124
+ def test_team_members_can_edit_in_collaborators_mode(datalayer, user, team):
125
+ user.teams.add(team)
126
+ user.save()
127
+ map = datalayer.map
128
+ map.team = team
129
+ map.save()
130
+ datalayer.edit_status = DataLayer.COLLABORATORS
120
131
  datalayer.save()
121
132
  assert datalayer.can_edit(user)
122
133
 
@@ -170,6 +181,20 @@ def test_editors_cannot_edit_in_inherit_mode_and_map_in_owner_mode(datalayer, us
170
181
  assert not datalayer.can_edit(user)
171
182
 
172
183
 
184
+ def test_team_members_cannot_edit_in_inherit_mode_and_map_in_owner_mode(
185
+ datalayer, user, team
186
+ ):
187
+ datalayer.edit_status = DataLayer.INHERIT
188
+ datalayer.save()
189
+ user.teams.add(team)
190
+ team.save()
191
+ map = datalayer.map
192
+ map.team = team
193
+ map.edit_status = Map.OWNER
194
+ map.save()
195
+ assert not datalayer.can_edit(user)
196
+
197
+
173
198
  def test_anonymous_cannot_edit_in_inherit_mode_and_map_in_owner_mode(datalayer):
174
199
  datalayer.edit_status = DataLayer.INHERIT
175
200
  datalayer.save()
@@ -183,7 +208,7 @@ def test_owner_can_edit_in_inherit_mode_and_map_in_editors_mode(datalayer):
183
208
  datalayer.edit_status = DataLayer.INHERIT
184
209
  datalayer.save()
185
210
  map = datalayer.map
186
- map.edit_status = Map.EDITORS
211
+ map.edit_status = Map.COLLABORATORS
187
212
  map.save()
188
213
  assert datalayer.can_edit(map.owner)
189
214
 
@@ -193,7 +218,7 @@ def test_editors_can_edit_in_inherit_mode_and_map_in_editors_mode(datalayer, use
193
218
  datalayer.save()
194
219
  map = datalayer.map
195
220
  map.editors.add(user)
196
- map.edit_status = Map.EDITORS
221
+ map.edit_status = Map.COLLABORATORS
197
222
  map.save()
198
223
  assert datalayer.can_edit(user)
199
224
 
@@ -202,7 +227,7 @@ def test_anonymous_cannot_edit_in_inherit_mode_and_map_in_editors_mode(datalayer
202
227
  datalayer.edit_status = DataLayer.INHERIT
203
228
  datalayer.save()
204
229
  map = datalayer.map
205
- map.edit_status = Map.EDITORS
230
+ map.edit_status = Map.COLLABORATORS
206
231
  map.save()
207
232
  assert not datalayer.can_edit()
208
233
 
@@ -379,7 +379,7 @@ def test_owner_can_edit_in_owner_mode(datalayer, client, map, post_data):
379
379
 
380
380
  def test_editor_can_edit_in_editors_mode(datalayer, client, map, post_data):
381
381
  client.login(username=map.owner.username, password="123123")
382
- datalayer.edit_status = DataLayer.EDITORS
382
+ datalayer.edit_status = DataLayer.COLLABORATORS
383
383
  datalayer.save()
384
384
  url = reverse("datalayer_update", args=(map.pk, datalayer.pk))
385
385
  name = "new name"
umap/tests/test_map.py CHANGED
@@ -43,13 +43,31 @@ def test_editors_cannot_edit_if_status_owner(map, user):
43
43
  assert not map.can_edit(user)
44
44
 
45
45
 
46
- def test_editors_can_edit_if_status_editors(map, user):
47
- map.edit_status = map.EDITORS
46
+ def test_editors_can_edit_if_status_collaborators(map, user):
47
+ map.edit_status = map.COLLABORATORS
48
48
  map.editors.add(user)
49
49
  map.save()
50
50
  assert map.can_edit(user)
51
51
 
52
52
 
53
+ def test_team_members_cannot_edit_if_status_owner(map, user, team):
54
+ user.teams.add(team)
55
+ user.save()
56
+ map.edit_status = map.OWNER
57
+ map.team = team
58
+ map.save()
59
+ assert not map.can_edit(user)
60
+
61
+
62
+ def test_team_members_can_edit_if_status_collaborators(map, user, team):
63
+ user.teams.add(team)
64
+ user.save()
65
+ map.edit_status = map.COLLABORATORS
66
+ map.team = team
67
+ map.save()
68
+ assert map.can_edit(user)
69
+
70
+
53
71
  def test_logged_in_user_should_be_allowed_for_anonymous_map_with_anonymous_edit_status(
54
72
  map, user, rf
55
73
  ): # noqa
@@ -87,6 +105,14 @@ def test_clone_should_keep_editors(map, user):
87
105
  assert user in clone.editors.all()
88
106
 
89
107
 
108
+ def test_clone_should_keep_team(map, user, team):
109
+ map.team = team
110
+ map.save()
111
+ clone = map.clone()
112
+ assert map.pk != clone.pk
113
+ assert clone.team == team
114
+
115
+
90
116
  def test_clone_should_update_owner_if_passed(map, user):
91
117
  clone = map.clone(owner=user)
92
118
  assert map.pk != clone.pk
@@ -119,9 +145,9 @@ def test_publicmanager_should_get_only_public_maps(map, user, licence):
119
145
  def test_can_change_default_edit_status(user, settings):
120
146
  map = MapFactory(owner=user)
121
147
  assert map.edit_status == Map.OWNER
122
- settings.UMAP_DEFAULT_EDIT_STATUS = Map.EDITORS
148
+ settings.UMAP_DEFAULT_EDIT_STATUS = Map.COLLABORATORS
123
149
  map = MapFactory(owner=user)
124
- assert map.edit_status == Map.EDITORS
150
+ assert map.edit_status == Map.COLLABORATORS
125
151
 
126
152
 
127
153
  def test_can_change_default_share_status(user, settings):
@@ -210,7 +210,7 @@ def test_user_not_allowed_should_not_clone_map(client, map, user, settings):
210
210
 
211
211
  def test_clone_should_set_cloner_as_owner(client, map, user):
212
212
  url = reverse("map_clone", kwargs={"map_id": map.pk})
213
- map.edit_status = map.EDITORS
213
+ map.edit_status = map.COLLABORATORS
214
214
  map.editors.add(user)
215
215
  map.save()
216
216
  client.login(username=user.username, password="123123")
@@ -330,7 +330,7 @@ def test_only_owner_can_delete(client, map, user):
330
330
 
331
331
  def test_map_editors_do_not_see_owner_change_input(client, map, user):
332
332
  map.editors.add(user)
333
- map.edit_status = map.EDITORS
333
+ map.edit_status = map.COLLABORATORS
334
334
  map.save()
335
335
  url = reverse("map_update_permissions", kwargs={"map_id": map.pk})
336
336
  client.login(username=user.username, password="123123")
@@ -0,0 +1,40 @@
1
+ import json
2
+ import shutil
3
+ import tempfile
4
+ from copy import deepcopy
5
+ from pathlib import Path
6
+
7
+ import pytest
8
+ from django.core.management import call_command
9
+
10
+
11
+ @pytest.fixture
12
+ def staticfiles(settings):
13
+ static_root = tempfile.mkdtemp(prefix="test_static")
14
+ settings.STATIC_ROOT = static_root
15
+ # Make sure settings are properly reset after the test
16
+ settings.STORAGES = deepcopy(settings.STORAGES)
17
+ settings.STORAGES["staticfiles"]["BACKEND"] = (
18
+ "umap.storage.UmapManifestStaticFilesStorage"
19
+ )
20
+ try:
21
+ call_command("collectstatic", "--noinput")
22
+ yield
23
+ finally:
24
+ shutil.rmtree(static_root)
25
+
26
+
27
+ def test_collectstatic_ran_successfully_with_hashes(settings, staticfiles):
28
+ static_root = settings.STATIC_ROOT
29
+ manifest = Path(static_root) / "staticfiles.json"
30
+ assert manifest.exists()
31
+ json_manifest = json.loads(manifest.read_text())
32
+ assert "hash" in json_manifest.keys()
33
+ assert "umap/base.css" in json_manifest["paths"]
34
+ # Hash + the dot ("umap/base.<hash>.css").
35
+ md5_hash_lenght = 12 + 1
36
+ # The value of the manifest must contain the hash (length).
37
+ assert (
38
+ len(json_manifest["paths"]["umap/base.css"])
39
+ == len("umap/base.css") + md5_hash_lenght
40
+ )