umap-project 2.7.3__py3-none-any.whl → 2.8.0a0__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.
Files changed (279) hide show
  1. umap/__init__.py +1 -1
  2. umap/forms.py +4 -14
  3. umap/locale/am_ET/LC_MESSAGES/django.mo +0 -0
  4. umap/locale/am_ET/LC_MESSAGES/django.po +278 -151
  5. umap/locale/ar/LC_MESSAGES/django.mo +0 -0
  6. umap/locale/ar/LC_MESSAGES/django.po +335 -141
  7. umap/locale/bg/LC_MESSAGES/django.mo +0 -0
  8. umap/locale/bg/LC_MESSAGES/django.po +279 -152
  9. umap/locale/br/LC_MESSAGES/django.mo +0 -0
  10. umap/locale/br/LC_MESSAGES/django.po +95 -79
  11. umap/locale/ca/LC_MESSAGES/django.mo +0 -0
  12. umap/locale/ca/LC_MESSAGES/django.po +85 -68
  13. umap/locale/cs_CZ/LC_MESSAGES/django.mo +0 -0
  14. umap/locale/cs_CZ/LC_MESSAGES/django.po +78 -66
  15. umap/locale/da/LC_MESSAGES/django.mo +0 -0
  16. umap/locale/da/LC_MESSAGES/django.po +280 -153
  17. umap/locale/de/LC_MESSAGES/django.mo +0 -0
  18. umap/locale/de/LC_MESSAGES/django.po +80 -64
  19. umap/locale/el/LC_MESSAGES/django.mo +0 -0
  20. umap/locale/el/LC_MESSAGES/django.po +82 -66
  21. umap/locale/en/LC_MESSAGES/django.po +73 -61
  22. umap/locale/es/LC_MESSAGES/django.mo +0 -0
  23. umap/locale/es/LC_MESSAGES/django.po +75 -63
  24. umap/locale/et/LC_MESSAGES/django.mo +0 -0
  25. umap/locale/et/LC_MESSAGES/django.po +280 -153
  26. umap/locale/eu/LC_MESSAGES/django.mo +0 -0
  27. umap/locale/eu/LC_MESSAGES/django.po +82 -66
  28. umap/locale/fa_IR/LC_MESSAGES/django.mo +0 -0
  29. umap/locale/fa_IR/LC_MESSAGES/django.po +80 -64
  30. umap/locale/fi/LC_MESSAGES/django.mo +0 -0
  31. umap/locale/fi/LC_MESSAGES/django.po +278 -151
  32. umap/locale/fr/LC_MESSAGES/django.mo +0 -0
  33. umap/locale/fr/LC_MESSAGES/django.po +75 -63
  34. umap/locale/gl/LC_MESSAGES/django.mo +0 -0
  35. umap/locale/gl/LC_MESSAGES/django.po +280 -153
  36. umap/locale/he/LC_MESSAGES/django.mo +0 -0
  37. umap/locale/he/LC_MESSAGES/django.po +281 -154
  38. umap/locale/hu/LC_MESSAGES/django.mo +0 -0
  39. umap/locale/hu/LC_MESSAGES/django.po +80 -64
  40. umap/locale/is/LC_MESSAGES/django.mo +0 -0
  41. umap/locale/is/LC_MESSAGES/django.po +280 -153
  42. umap/locale/it/LC_MESSAGES/django.mo +0 -0
  43. umap/locale/it/LC_MESSAGES/django.po +82 -66
  44. umap/locale/ja/LC_MESSAGES/django.mo +0 -0
  45. umap/locale/ja/LC_MESSAGES/django.po +280 -153
  46. umap/locale/ko/LC_MESSAGES/django.mo +0 -0
  47. umap/locale/ko/LC_MESSAGES/django.po +280 -153
  48. umap/locale/lt/LC_MESSAGES/django.mo +0 -0
  49. umap/locale/lt/LC_MESSAGES/django.po +280 -153
  50. umap/locale/ms/LC_MESSAGES/django.mo +0 -0
  51. umap/locale/ms/LC_MESSAGES/django.po +82 -66
  52. umap/locale/nl/LC_MESSAGES/django.mo +0 -0
  53. umap/locale/nl/LC_MESSAGES/django.po +280 -153
  54. umap/locale/pl/LC_MESSAGES/django.mo +0 -0
  55. umap/locale/pl/LC_MESSAGES/django.po +82 -66
  56. umap/locale/pt/LC_MESSAGES/django.mo +0 -0
  57. umap/locale/pt/LC_MESSAGES/django.po +75 -63
  58. umap/locale/pt_BR/LC_MESSAGES/django.mo +0 -0
  59. umap/locale/pt_BR/LC_MESSAGES/django.po +280 -153
  60. umap/locale/pt_PT/LC_MESSAGES/django.mo +0 -0
  61. umap/locale/pt_PT/LC_MESSAGES/django.po +280 -153
  62. umap/locale/ru/LC_MESSAGES/django.mo +0 -0
  63. umap/locale/ru/LC_MESSAGES/django.po +280 -153
  64. umap/locale/sk_SK/LC_MESSAGES/django.mo +0 -0
  65. umap/locale/sk_SK/LC_MESSAGES/django.po +280 -153
  66. umap/locale/sl/LC_MESSAGES/django.mo +0 -0
  67. umap/locale/sl/LC_MESSAGES/django.po +280 -153
  68. umap/locale/sr/LC_MESSAGES/django.mo +0 -0
  69. umap/locale/sr/LC_MESSAGES/django.po +280 -153
  70. umap/locale/sv/LC_MESSAGES/django.mo +0 -0
  71. umap/locale/sv/LC_MESSAGES/django.po +81 -65
  72. umap/locale/th_TH/LC_MESSAGES/django.mo +0 -0
  73. umap/locale/th_TH/LC_MESSAGES/django.po +257 -185
  74. umap/locale/tr/LC_MESSAGES/django.mo +0 -0
  75. umap/locale/tr/LC_MESSAGES/django.po +280 -153
  76. umap/locale/uk_UA/LC_MESSAGES/django.mo +0 -0
  77. umap/locale/uk_UA/LC_MESSAGES/django.po +280 -153
  78. umap/locale/vi/LC_MESSAGES/django.mo +0 -0
  79. umap/locale/vi/LC_MESSAGES/django.po +278 -151
  80. umap/locale/zh/LC_MESSAGES/django.mo +0 -0
  81. umap/locale/zh/LC_MESSAGES/django.po +278 -151
  82. umap/locale/zh_TW/LC_MESSAGES/django.mo +0 -0
  83. umap/locale/zh_TW/LC_MESSAGES/django.po +97 -81
  84. umap/management/commands/empty_trash.py +32 -0
  85. umap/management/commands/migrate_to_S3.py +29 -0
  86. umap/migrations/0023_alter_datalayer_uuid.py +19 -0
  87. umap/migrations/0024_alter_map_share_status.py +30 -0
  88. umap/migrations/0025_alter_datalayer_geojson.py +24 -0
  89. umap/models.py +68 -116
  90. umap/settings/base.py +22 -2
  91. umap/static/umap/base.css +3 -603
  92. umap/static/umap/content.css +5 -3
  93. umap/static/umap/css/bar.css +202 -0
  94. umap/static/umap/css/form.css +617 -0
  95. umap/static/umap/css/icon.css +21 -1
  96. umap/static/umap/css/popup.css +125 -0
  97. umap/static/umap/img/16-white.svg +16 -4
  98. umap/static/umap/img/16.svg +1 -1
  99. umap/static/umap/img/source/16-white.svg +46 -45
  100. umap/static/umap/img/source/16.svg +1 -753
  101. umap/static/umap/js/components/fragment.js +3 -1
  102. umap/static/umap/js/modules/browser.js +20 -19
  103. umap/static/umap/js/modules/caption.js +21 -22
  104. umap/static/umap/js/modules/data/features.js +101 -74
  105. umap/static/umap/js/modules/data/layer.js +157 -137
  106. umap/static/umap/js/modules/facets.js +9 -9
  107. umap/static/umap/js/modules/formatter.js +5 -5
  108. umap/static/umap/js/modules/global.js +4 -52
  109. umap/static/umap/js/modules/help.js +18 -21
  110. umap/static/umap/js/modules/importer.js +71 -39
  111. umap/static/umap/js/modules/importers/cadastrefr.js +4 -0
  112. umap/static/umap/js/modules/importers/geodatamine.js +3 -3
  113. umap/static/umap/js/modules/importers/overpass.js +5 -0
  114. umap/static/umap/js/modules/permissions.js +85 -87
  115. umap/static/umap/js/modules/rendering/layers/base.js +15 -15
  116. umap/static/umap/js/modules/rendering/layers/classified.js +1 -1
  117. umap/static/umap/js/modules/rendering/layers/cluster.js +1 -1
  118. umap/static/umap/js/modules/rendering/layers/heat.js +1 -1
  119. umap/static/umap/js/modules/rendering/map.js +390 -0
  120. umap/static/umap/js/modules/rendering/popup.js +10 -9
  121. umap/static/umap/js/modules/rendering/template.js +35 -12
  122. umap/static/umap/js/modules/rendering/ui.js +57 -12
  123. umap/static/umap/js/modules/rules.js +22 -25
  124. umap/static/umap/js/modules/saving.js +47 -0
  125. umap/static/umap/js/modules/schema.js +5 -0
  126. umap/static/umap/js/modules/share.js +21 -24
  127. umap/static/umap/js/modules/slideshow.js +24 -20
  128. umap/static/umap/js/modules/sync/updaters.js +7 -9
  129. umap/static/umap/js/modules/tableeditor.js +20 -19
  130. umap/static/umap/js/modules/ui/bar.js +196 -0
  131. umap/static/umap/js/modules/ui/panel.js +10 -9
  132. umap/static/umap/js/modules/umap.js +1668 -0
  133. umap/static/umap/js/modules/urls.js +2 -2
  134. umap/static/umap/js/modules/utils.js +20 -6
  135. umap/static/umap/js/umap.controls.js +74 -301
  136. umap/static/umap/js/umap.core.js +29 -50
  137. umap/static/umap/js/umap.forms.js +34 -27
  138. umap/static/umap/keycloak.png +0 -0
  139. umap/static/umap/locale/am_ET.js +26 -10
  140. umap/static/umap/locale/am_ET.json +26 -10
  141. umap/static/umap/locale/ar.js +26 -10
  142. umap/static/umap/locale/ar.json +26 -10
  143. umap/static/umap/locale/ast.js +26 -10
  144. umap/static/umap/locale/ast.json +26 -10
  145. umap/static/umap/locale/bg.js +26 -10
  146. umap/static/umap/locale/bg.json +26 -10
  147. umap/static/umap/locale/br.js +27 -20
  148. umap/static/umap/locale/br.json +27 -20
  149. umap/static/umap/locale/ca.js +32 -29
  150. umap/static/umap/locale/ca.json +32 -29
  151. umap/static/umap/locale/cs_CZ.js +24 -17
  152. umap/static/umap/locale/cs_CZ.json +24 -17
  153. umap/static/umap/locale/da.js +26 -10
  154. umap/static/umap/locale/da.json +26 -10
  155. umap/static/umap/locale/de.js +21 -14
  156. umap/static/umap/locale/de.json +21 -14
  157. umap/static/umap/locale/el.js +28 -12
  158. umap/static/umap/locale/el.json +28 -12
  159. umap/static/umap/locale/en.js +12 -9
  160. umap/static/umap/locale/en.json +12 -9
  161. umap/static/umap/locale/en_US.json +26 -10
  162. umap/static/umap/locale/es.js +16 -13
  163. umap/static/umap/locale/es.json +16 -13
  164. umap/static/umap/locale/et.js +26 -10
  165. umap/static/umap/locale/et.json +26 -10
  166. umap/static/umap/locale/eu.js +16 -9
  167. umap/static/umap/locale/eu.json +16 -9
  168. umap/static/umap/locale/fa_IR.js +16 -9
  169. umap/static/umap/locale/fa_IR.json +16 -9
  170. umap/static/umap/locale/fi.js +26 -10
  171. umap/static/umap/locale/fi.json +26 -10
  172. umap/static/umap/locale/fr.js +12 -9
  173. umap/static/umap/locale/fr.json +12 -9
  174. umap/static/umap/locale/gl.js +26 -10
  175. umap/static/umap/locale/gl.json +26 -10
  176. umap/static/umap/locale/he.js +26 -10
  177. umap/static/umap/locale/he.json +26 -10
  178. umap/static/umap/locale/hr.js +26 -10
  179. umap/static/umap/locale/hr.json +26 -10
  180. umap/static/umap/locale/hu.js +16 -9
  181. umap/static/umap/locale/hu.json +16 -9
  182. umap/static/umap/locale/id.js +26 -10
  183. umap/static/umap/locale/id.json +26 -10
  184. umap/static/umap/locale/is.js +26 -10
  185. umap/static/umap/locale/is.json +26 -10
  186. umap/static/umap/locale/it.js +26 -10
  187. umap/static/umap/locale/it.json +26 -10
  188. umap/static/umap/locale/ja.js +26 -10
  189. umap/static/umap/locale/ja.json +26 -10
  190. umap/static/umap/locale/ko.js +26 -10
  191. umap/static/umap/locale/ko.json +26 -10
  192. umap/static/umap/locale/lt.js +26 -10
  193. umap/static/umap/locale/lt.json +26 -10
  194. umap/static/umap/locale/ms.js +28 -12
  195. umap/static/umap/locale/ms.json +28 -12
  196. umap/static/umap/locale/nl.js +28 -12
  197. umap/static/umap/locale/nl.json +28 -12
  198. umap/static/umap/locale/no.js +26 -10
  199. umap/static/umap/locale/no.json +26 -10
  200. umap/static/umap/locale/pl.js +28 -12
  201. umap/static/umap/locale/pl.json +28 -12
  202. umap/static/umap/locale/pl_PL.json +26 -10
  203. umap/static/umap/locale/pt.js +16 -9
  204. umap/static/umap/locale/pt.json +16 -9
  205. umap/static/umap/locale/pt_BR.js +26 -10
  206. umap/static/umap/locale/pt_BR.json +26 -10
  207. umap/static/umap/locale/pt_PT.js +16 -9
  208. umap/static/umap/locale/pt_PT.json +16 -9
  209. umap/static/umap/locale/ro.js +26 -10
  210. umap/static/umap/locale/ro.json +26 -10
  211. umap/static/umap/locale/ru.js +26 -10
  212. umap/static/umap/locale/ru.json +26 -10
  213. umap/static/umap/locale/si.js +7 -7
  214. umap/static/umap/locale/si.json +7 -7
  215. umap/static/umap/locale/sk_SK.js +26 -10
  216. umap/static/umap/locale/sk_SK.json +26 -10
  217. umap/static/umap/locale/sl.js +26 -10
  218. umap/static/umap/locale/sl.json +26 -10
  219. umap/static/umap/locale/sr.js +26 -10
  220. umap/static/umap/locale/sr.json +26 -10
  221. umap/static/umap/locale/sv.js +27 -11
  222. umap/static/umap/locale/sv.json +27 -11
  223. umap/static/umap/locale/th_TH.js +28 -12
  224. umap/static/umap/locale/th_TH.json +28 -12
  225. umap/static/umap/locale/tr.js +26 -10
  226. umap/static/umap/locale/tr.json +26 -10
  227. umap/static/umap/locale/uk_UA.js +26 -10
  228. umap/static/umap/locale/uk_UA.json +26 -10
  229. umap/static/umap/locale/vi.js +26 -10
  230. umap/static/umap/locale/vi.json +26 -10
  231. umap/static/umap/locale/vi_VN.json +26 -10
  232. umap/static/umap/locale/zh.js +26 -10
  233. umap/static/umap/locale/zh.json +26 -10
  234. umap/static/umap/locale/zh_CN.json +26 -10
  235. umap/static/umap/locale/zh_TW.Big5.json +26 -10
  236. umap/static/umap/locale/zh_TW.js +34 -27
  237. umap/static/umap/locale/zh_TW.json +34 -27
  238. umap/static/umap/map.css +5 -364
  239. umap/static/umap/unittests/URLs.js +15 -15
  240. umap/static/umap/unittests/utils.js +23 -1
  241. umap/static/umap/vars.css +2 -0
  242. umap/static/umap/vendors/formbuilder/Leaflet.FormBuilder.js +5 -1
  243. umap/storage.py +152 -0
  244. umap/templates/registration/login.html +7 -6
  245. umap/templates/umap/css.html +3 -0
  246. umap/templates/umap/js.html +1 -2
  247. umap/templates/umap/map_init.html +4 -5
  248. umap/templates/umap/user_dashboard.html +18 -19
  249. umap/tests/base.py +5 -1
  250. umap/tests/integration/conftest.py +2 -1
  251. umap/tests/integration/test_anonymous_owned_map.py +18 -10
  252. umap/tests/integration/test_browser.py +16 -1
  253. umap/tests/integration/test_dashboard.py +1 -1
  254. umap/tests/integration/test_edit_datalayer.py +18 -7
  255. umap/tests/integration/test_import.py +8 -5
  256. umap/tests/integration/test_optimistic_merge.py +31 -8
  257. umap/tests/integration/test_owned_map.py +22 -16
  258. umap/tests/integration/test_popup.py +44 -0
  259. umap/tests/integration/test_save.py +35 -0
  260. umap/tests/integration/test_view_marker.py +12 -0
  261. umap/tests/integration/test_view_polyline.py +257 -0
  262. umap/tests/integration/test_websocket_sync.py +81 -9
  263. umap/tests/test_datalayer.py +6 -7
  264. umap/tests/test_datalayer_s3.py +135 -0
  265. umap/tests/test_datalayer_views.py +28 -10
  266. umap/tests/test_empty_trash.py +34 -0
  267. umap/tests/test_map.py +12 -3
  268. umap/tests/test_map_views.py +69 -37
  269. umap/tests/test_views.py +53 -0
  270. umap/urls.py +3 -3
  271. umap/views.py +107 -76
  272. {umap_project-2.7.3.dist-info → umap_project-2.8.0a0.dist-info}/METADATA +16 -13
  273. {umap_project-2.7.3.dist-info → umap_project-2.8.0a0.dist-info}/RECORD +276 -262
  274. umap/management/commands/purge_purgatory.py +0 -28
  275. umap/static/umap/js/umap.js +0 -1903
  276. umap/tests/test_purge_purgatory.py +0 -25
  277. {umap_project-2.7.3.dist-info → umap_project-2.8.0a0.dist-info}/WHEEL +0 -0
  278. {umap_project-2.7.3.dist-info → umap_project-2.8.0a0.dist-info}/entry_points.txt +0 -0
  279. {umap_project-2.7.3.dist-info → umap_project-2.8.0a0.dist-info}/licenses/LICENSE +0 -0
umap/views.py CHANGED
@@ -1,7 +1,6 @@
1
1
  import io
2
2
  import json
3
3
  import mimetypes
4
- import os
5
4
  import re
6
5
  import socket
7
6
  import zipfile
@@ -373,6 +372,7 @@ class UserDashboard(PaginatorMixin, DetailView, SearchMixin):
373
372
 
374
373
  def get_maps(self):
375
374
  qs = self.get_search_queryset() or Map.objects.all()
375
+ qs = qs.exclude(share_status__in=[Map.DELETED, Map.BLOCKED])
376
376
  teams = self.object.teams.all()
377
377
  qs = (
378
378
  qs.filter(owner=self.object)
@@ -598,29 +598,34 @@ class MapDetailMixin(SessionMixin):
598
598
  "tilelayers": TileLayer.get_list(),
599
599
  "editMode": self.edit_mode,
600
600
  "schema": Map.extra_schema,
601
- "umap_id": self.get_umap_id(),
601
+ "id": self.get_id(),
602
602
  "starred": self.is_starred(),
603
603
  "licences": dict((l.name, l.json) for l in Licence.objects.all()),
604
- "share_statuses": [
605
- (i, str(label)) for i, label in Map.SHARE_STATUS if i != Map.BLOCKED
606
- ],
607
604
  "umap_version": VERSION,
608
605
  "featuresHaveOwner": settings.UMAP_DEFAULT_FEATURES_HAVE_OWNERS,
609
606
  "websocketEnabled": settings.WEBSOCKET_ENABLED,
610
607
  "websocketURI": settings.WEBSOCKET_FRONT_URI,
611
608
  "importers": settings.UMAP_IMPORTERS,
609
+ "defaultLabelKeys": settings.UMAP_LABEL_KEYS,
612
610
  }
613
611
  created = bool(getattr(self, "object", None))
614
612
  if (created and self.object.owner) or (not created and not user.is_anonymous):
615
- map_statuses = Map.EDIT_STATUS
613
+ edit_statuses = Map.EDIT_STATUS
616
614
  datalayer_statuses = DataLayer.EDIT_STATUS
615
+ share_statuses = Map.SHARE_STATUS
617
616
  else:
618
- map_statuses = AnonymousMapPermissionsForm.STATUS
619
- datalayer_statuses = AnonymousDataLayerPermissionsForm.STATUS
620
- properties["edit_statuses"] = [(i, str(label)) for i, label in map_statuses]
617
+ edit_statuses = Map.ANONYMOUS_EDIT_STATUS
618
+ datalayer_statuses = DataLayer.ANONYMOUS_EDIT_STATUS
619
+ share_statuses = Map.ANONYMOUS_SHARE_STATUS
620
+ properties["edit_statuses"] = [(i, str(label)) for i, label in edit_statuses]
621
621
  properties["datalayer_edit_statuses"] = [
622
622
  (i, str(label)) for i, label in datalayer_statuses
623
623
  ]
624
+ properties["share_statuses"] = [
625
+ (i, str(label))
626
+ for i, label in share_statuses
627
+ if i not in [Map.BLOCKED, Map.DELETED]
628
+ ]
624
629
  if self.get_short_url():
625
630
  properties["shortUrl"] = self.get_short_url()
626
631
 
@@ -655,7 +660,7 @@ class MapDetailMixin(SessionMixin):
655
660
  def edit_mode(self):
656
661
  return "advanced"
657
662
 
658
- def get_umap_id(self):
663
+ def get_id(self):
659
664
  return None
660
665
 
661
666
  def is_starred(self):
@@ -683,14 +688,9 @@ class PermissionsMixin:
683
688
  permissions["edit_status"] = self.object.edit_status
684
689
  permissions["share_status"] = self.object.share_status
685
690
  if self.object.owner:
686
- permissions["owner"] = {
687
- "id": self.object.owner.pk,
688
- "name": str(self.object.owner),
689
- "url": self.object.owner.get_url(),
690
- }
691
+ permissions["owner"] = self.object.owner.get_metadata()
691
692
  permissions["editors"] = [
692
- {"id": editor.pk, "name": str(editor)}
693
- for editor in self.object.editors.all()
693
+ editor.get_metadata() for editor in self.object.editors.all()
694
694
  ]
695
695
  if self.object.team:
696
696
  permissions["team"] = self.object.team.get_metadata()
@@ -725,6 +725,8 @@ class MapView(MapDetailMixin, PermissionsMixin, DetailView):
725
725
  return self.object.get_absolute_url()
726
726
 
727
727
  def get_datalayers(self):
728
+ # When initializing datalayers from map, we cannot get the reference version
729
+ # the normal way, which is from the header X-Reference-Version
728
730
  return [dl.metadata(self.request) for dl in self.object.datalayer_set.all()]
729
731
 
730
732
  @property
@@ -736,7 +738,7 @@ class MapView(MapDetailMixin, PermissionsMixin, DetailView):
736
738
  edit_mode = "simple"
737
739
  return edit_mode
738
740
 
739
- def get_umap_id(self):
741
+ def get_id(self):
740
742
  return self.object.pk
741
743
 
742
744
  def get_short_url(self):
@@ -844,6 +846,17 @@ class MapViewGeoJSON(MapView):
844
846
  class MapNew(MapDetailMixin, TemplateView):
845
847
  template_name = "umap/map_detail.html"
846
848
 
849
+ def get_map_properties(self):
850
+ properties = super().get_map_properties()
851
+ properties["permissions"] = {
852
+ "edit_status": Map.edit_status.field.default(),
853
+ "share_status": Map.share_status.field.default(),
854
+ }
855
+ if self.request.user.is_authenticated:
856
+ user = self.request.user
857
+ properties["permissions"]["owner"] = user.get_metadata()
858
+ return properties
859
+
847
860
 
848
861
  class MapPreview(MapDetailMixin, TemplateView):
849
862
  template_name = "umap/map_detail.html"
@@ -1008,7 +1021,7 @@ class MapDelete(DeleteView):
1008
1021
  self.object = self.get_object()
1009
1022
  if not self.object.can_delete(self.request):
1010
1023
  return HttpResponseForbidden(_("Only its owner can delete the map."))
1011
- self.object.delete()
1024
+ self.object.move_to_trash()
1012
1025
  home_url = reverse("home")
1013
1026
  messages.info(self.request, _("Map successfully deleted."))
1014
1027
  if is_ajax(self.request):
@@ -1103,97 +1116,117 @@ class MapAnonymousEditUrl(RedirectView):
1103
1116
  # ############## #
1104
1117
 
1105
1118
 
1106
- class GZipMixin(object):
1107
- EXT = ".gz"
1119
+ class DataLayerView(BaseDetailView):
1120
+ model = DataLayer
1108
1121
 
1109
1122
  @property
1110
- def path(self):
1111
- return Path(self.object.geojson.path)
1123
+ def accepts_gzip(self):
1124
+ return settings.UMAP_GZIP and re_accepts_gzip.search(
1125
+ self.request.META.get("HTTP_ACCEPT_ENCODING", "")
1126
+ )
1112
1127
 
1113
1128
  @property
1114
- def gzip_path(self):
1115
- return Path(f"{self.path}{self.EXT}")
1116
-
1117
- def read_version(self, path):
1118
- # Remove optional .gz, then .geojson, then return the trailing version from path.
1119
- return str(path.with_suffix("").with_suffix("")).split("_")[-1]
1129
+ def is_s3(self):
1130
+ return "S3" in settings.STORAGES["data"]["BACKEND"]
1120
1131
 
1121
1132
  @property
1122
- def version(self):
1123
- # Prior to 1.3.0 we did not set gzip mtime as geojson mtime,
1124
- # but we switched from If-Match header to If-Unmodified-Since
1125
- # and when users accepts gzip their last modified value is the gzip
1126
- # (when umap is served by nginx and X-Accel-Redirect)
1127
- # one, so we need to compare with that value in that case.
1128
- # cf https://github.com/umap-project/umap/issues/1212
1129
- path = (
1130
- self.gzip_path
1131
- if self.accepts_gzip and self.gzip_path.exists()
1132
- else self.path
1133
- )
1134
- return self.read_version(path)
1133
+ def filepath(self):
1134
+ return Path(self.object.geojson.path)
1135
1135
 
1136
1136
  @property
1137
- def accepts_gzip(self):
1138
- return settings.UMAP_GZIP and re_accepts_gzip.search(
1139
- self.request.META.get("HTTP_ACCEPT_ENCODING", "")
1140
- )
1137
+ def fileurl(self):
1138
+ return self.object.geojson.url
1141
1139
 
1140
+ @property
1141
+ def filedata(self):
1142
+ with self.object.geojson.open("rb") as f:
1143
+ return f.read()
1142
1144
 
1143
- class DataLayerView(GZipMixin, BaseDetailView):
1144
- model = DataLayer
1145
+ @property
1146
+ def fileversion(self):
1147
+ return self.object.reference_version
1145
1148
 
1146
1149
  def render_to_response(self, context, **response_kwargs):
1147
1150
  response = None
1148
- path = self.path
1149
1151
  # Generate gzip if needed
1150
- if self.accepts_gzip:
1151
- if not self.gzip_path.exists():
1152
- gzip_file(path, self.gzip_path)
1152
+ if not self.is_s3 and self.accepts_gzip:
1153
+ gzip_path = Path(f"{self.filepath}.gz")
1154
+ if not gzip_path.exists():
1155
+ gzip_file(self.filepath, gzip_path)
1153
1156
 
1154
1157
  if getattr(settings, "UMAP_XSENDFILE_HEADER", None):
1155
1158
  response = HttpResponse()
1156
- internal_path = str(path).replace(settings.MEDIA_ROOT, "/internal")
1159
+ if self.is_s3:
1160
+ internal_path = f"/s3/{self.fileurl}"
1161
+ else:
1162
+ internal_path = str(self.filepath).replace(
1163
+ settings.MEDIA_ROOT, "/internal"
1164
+ )
1157
1165
  response[settings.UMAP_XSENDFILE_HEADER] = internal_path
1158
1166
  else:
1159
1167
  # Do not use in production
1160
1168
  # (no gzip/cache-control/If-Modified-Since/If-None-Match)
1161
- statobj = os.stat(path)
1162
- with open(path, "rb") as f:
1163
- # Should not be used in production!
1164
- response = HttpResponse(f.read(), content_type="application/geo+json")
1165
- response["X-Datalayer-Version"] = self.version
1166
- response["Content-Length"] = statobj.st_size
1169
+ data = self.filedata
1170
+ response = HttpResponse(data, content_type="application/geo+json")
1171
+ response["X-Datalayer-Version"] = self.fileversion
1167
1172
  return response
1168
1173
 
1169
1174
 
1170
1175
  class DataLayerVersion(DataLayerView):
1171
1176
  @property
1172
- def path(self):
1173
- return Path(settings.MEDIA_ROOT) / self.object.get_version_path(
1174
- self.kwargs["name"]
1175
- )
1177
+ def filepath(self):
1178
+ try:
1179
+ return Path(settings.MEDIA_ROOT) / self.object.get_version_path(
1180
+ self.kwargs["ref"]
1181
+ )
1182
+ except ValueError:
1183
+ raise Http404("Invalid version reference")
1184
+
1185
+ @property
1186
+ def fileurl(self):
1187
+ return self.object.get_version_path(self.kwargs["ref"])
1188
+
1189
+ @property
1190
+ def filedata(self):
1191
+ try:
1192
+ return self.object.get_version(self.kwargs["ref"])
1193
+ except ValueError:
1194
+ raise Http404("Invalid version reference.")
1195
+
1196
+ @property
1197
+ def fileversion(self):
1198
+ return self.kwargs["ref"]
1176
1199
 
1177
1200
 
1178
- class DataLayerCreate(FormLessEditMixin, GZipMixin, CreateView):
1201
+ class DataLayerCreate(FormLessEditMixin, CreateView):
1179
1202
  model = DataLayer
1180
1203
  form_class = DataLayerForm
1181
1204
 
1182
1205
  def form_valid(self, form):
1183
1206
  form.instance.map = self.kwargs["map_inst"]
1207
+
1208
+ uuid = self.kwargs["pk"]
1209
+ # Check if UUID already exists
1210
+ if DataLayer.objects.filter(uuid=uuid).exists():
1211
+ return HttpResponseBadRequest("UUID already exists")
1212
+
1213
+ form.instance.uuid = uuid
1184
1214
  self.object = form.save()
1185
- # Simple response with only metadata (including new id)
1186
- response = simple_json_response(**self.object.metadata(self.request))
1187
- response["X-Datalayer-Version"] = self.version
1215
+ assert uuid == self.object.uuid
1216
+
1217
+ # Simple response with only metadata
1218
+ data = self.object.metadata(self.request)
1219
+ response = simple_json_response(**data)
1220
+ response["X-Datalayer-Version"] = self.object.reference_version
1188
1221
  return response
1189
1222
 
1190
1223
 
1191
- class DataLayerUpdate(FormLessEditMixin, GZipMixin, UpdateView):
1224
+ class DataLayerUpdate(FormLessEditMixin, UpdateView):
1192
1225
  model = DataLayer
1193
1226
  form_class = DataLayerForm
1194
1227
 
1195
1228
  def has_changes_since(self, incoming_version):
1196
- return incoming_version and self.version != incoming_version
1229
+ return incoming_version and self.object.reference_version != incoming_version
1197
1230
 
1198
1231
  def merge(self, reference_version):
1199
1232
  """
@@ -1205,11 +1238,9 @@ class DataLayerUpdate(FormLessEditMixin, GZipMixin, UpdateView):
1205
1238
 
1206
1239
  # Use the provided info to find the correct version in our storage.
1207
1240
  for version in self.object.versions:
1208
- name = version["name"]
1209
- path = Path(settings.MEDIA_ROOT) / self.object.get_version_path(name)
1210
- if reference_version == self.read_version(path):
1211
- with open(path) as f:
1212
- reference = json.loads(f.read())
1241
+ ref = version["ref"]
1242
+ if reference_version == ref:
1243
+ reference = json.loads(self.object.get_version(ref))
1213
1244
  break
1214
1245
  else:
1215
1246
  # If the reference document is not found, we can't merge.
@@ -1218,7 +1249,7 @@ class DataLayerUpdate(FormLessEditMixin, GZipMixin, UpdateView):
1218
1249
  incoming = json.loads(self.request.FILES["geojson"].read())
1219
1250
 
1220
1251
  # Latest known version of the data.
1221
- with open(self.path) as f:
1252
+ with self.object.geojson.open() as f:
1222
1253
  latest = json.loads(f.read())
1223
1254
 
1224
1255
  try:
@@ -1262,7 +1293,7 @@ class DataLayerUpdate(FormLessEditMixin, GZipMixin, UpdateView):
1262
1293
  data["geojson"] = json.loads(self.object.geojson.read().decode())
1263
1294
  self.request.session["needs_reload"] = False
1264
1295
  response = simple_json_response(**data)
1265
- response["X-Datalayer-Version"] = self.version
1296
+ response["X-Datalayer-Version"] = self.object.reference_version
1266
1297
  return response
1267
1298
 
1268
1299
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: umap-project
3
- Version: 2.7.3
3
+ Version: 2.8.0a0
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>
@@ -18,39 +18,42 @@ Requires-Python: >=3.10
18
18
  Requires-Dist: django-agnocomplete==2.2.0
19
19
  Requires-Dist: django-environ==0.11.2
20
20
  Requires-Dist: django-probes==1.7.0
21
- Requires-Dist: django==5.1.2
21
+ Requires-Dist: django==5.1.4
22
22
  Requires-Dist: pillow==11.0.0
23
23
  Requires-Dist: psycopg==3.2.3
24
- Requires-Dist: rcssmin==1.1.3
24
+ Requires-Dist: rcssmin==1.2.0
25
25
  Requires-Dist: requests==2.32.3
26
26
  Requires-Dist: rjsmin==1.2.3
27
27
  Requires-Dist: social-auth-app-django==5.4.2
28
28
  Requires-Dist: social-auth-core==4.5.4
29
29
  Provides-Extra: dev
30
- Requires-Dist: djlint==1.35.2; extra == 'dev'
30
+ Requires-Dist: djlint==1.36.3; extra == 'dev'
31
31
  Requires-Dist: hatch==1.13.0; extra == 'dev'
32
32
  Requires-Dist: isort==5.13.2; extra == 'dev'
33
- Requires-Dist: mkdocs-material==9.5.42; extra == 'dev'
33
+ Requires-Dist: mkdocs-material==9.5.48; extra == 'dev'
34
34
  Requires-Dist: mkdocs-static-i18n==1.2.3; extra == 'dev'
35
35
  Requires-Dist: mkdocs==1.6.1; extra == 'dev'
36
- Requires-Dist: pymdown-extensions==10.11.2; extra == 'dev'
37
- Requires-Dist: ruff==0.7.0; extra == 'dev'
36
+ Requires-Dist: pymdown-extensions==10.12; extra == 'dev'
37
+ Requires-Dist: ruff==0.8.2; extra == 'dev'
38
38
  Requires-Dist: vermin==1.6.0; extra == 'dev'
39
39
  Provides-Extra: docker
40
- Requires-Dist: uwsgi==2.0.27; extra == 'docker'
40
+ Requires-Dist: uwsgi==2.0.28; extra == 'docker'
41
+ Provides-Extra: s3
42
+ Requires-Dist: django-storages[s3]==1.14.4; extra == 's3'
41
43
  Provides-Extra: sync
42
- Requires-Dist: channels==4.1.0; extra == 'sync'
44
+ Requires-Dist: channels==4.2.0; extra == 'sync'
43
45
  Requires-Dist: daphne==4.1.2; extra == 'sync'
44
- Requires-Dist: pydantic==2.9.2; extra == 'sync'
46
+ Requires-Dist: pydantic==2.10.3; extra == 'sync'
45
47
  Requires-Dist: websockets==13.1; extra == 'sync'
46
48
  Provides-Extra: test
47
49
  Requires-Dist: factory-boy==3.3.1; extra == 'test'
50
+ Requires-Dist: moto[s3]==5.0.21; extra == 'test'
48
51
  Requires-Dist: playwright>=1.39; extra == 'test'
49
52
  Requires-Dist: pytest-django==4.9.0; extra == 'test'
50
- Requires-Dist: pytest-playwright==0.5.2; extra == 'test'
51
- Requires-Dist: pytest-rerunfailures==14.0; extra == 'test'
53
+ Requires-Dist: pytest-playwright==0.6.2; extra == 'test'
54
+ Requires-Dist: pytest-rerunfailures==15.0; extra == 'test'
52
55
  Requires-Dist: pytest-xdist<4,>=3.5.0; extra == 'test'
53
- Requires-Dist: pytest==8.3.3; extra == 'test'
56
+ Requires-Dist: pytest==8.3.4; extra == 'test'
54
57
  Description-Content-Type: text/markdown
55
58
 
56
59
  # uMap project