c2cgeoportal-admin 2.6.0__py3-none-any.whl → 2.8.1.180__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 (78) hide show
  1. c2cgeoportal_admin/__init__.py +32 -10
  2. c2cgeoportal_admin/lib/lingua_extractor.py +77 -0
  3. c2cgeoportal_admin/lib/ogcserver_synchronizer.py +168 -56
  4. c2cgeoportal_admin/py.typed +0 -0
  5. c2cgeoportal_admin/routes.py +7 -4
  6. c2cgeoportal_admin/schemas/dimensions.py +12 -10
  7. c2cgeoportal_admin/schemas/functionalities.py +62 -21
  8. c2cgeoportal_admin/schemas/interfaces.py +22 -18
  9. c2cgeoportal_admin/schemas/metadata.py +100 -47
  10. c2cgeoportal_admin/schemas/restriction_areas.py +21 -19
  11. c2cgeoportal_admin/schemas/roles.py +7 -5
  12. c2cgeoportal_admin/schemas/treegroup.py +38 -17
  13. c2cgeoportal_admin/schemas/treeitem.py +2 -3
  14. c2cgeoportal_admin/static/layertree.css +3 -4
  15. c2cgeoportal_admin/static/navbar.css +36 -35
  16. c2cgeoportal_admin/static/theme.css +16 -9
  17. c2cgeoportal_admin/subscribers.py +3 -3
  18. c2cgeoportal_admin/templates/404.jinja2 +18 -2
  19. c2cgeoportal_admin/templates/layertree.jinja2 +31 -9
  20. c2cgeoportal_admin/templates/navigation_navbar.jinja2 +33 -0
  21. c2cgeoportal_admin/templates/ogcserver_synchronize.jinja2 +12 -0
  22. c2cgeoportal_admin/templates/widgets/functionality_fields.pt +51 -0
  23. c2cgeoportal_admin/templates/widgets/metadata.pt +7 -1
  24. c2cgeoportal_admin/views/__init__.py +29 -0
  25. c2cgeoportal_admin/views/dimension_layers.py +7 -6
  26. c2cgeoportal_admin/views/functionalities.py +33 -6
  27. c2cgeoportal_admin/views/home.py +5 -5
  28. c2cgeoportal_admin/views/interfaces.py +7 -8
  29. c2cgeoportal_admin/views/layer_groups.py +9 -11
  30. c2cgeoportal_admin/views/layers.py +8 -7
  31. c2cgeoportal_admin/views/layers_vectortiles.py +30 -10
  32. c2cgeoportal_admin/views/layers_wms.py +41 -35
  33. c2cgeoportal_admin/views/layers_wmts.py +41 -35
  34. c2cgeoportal_admin/views/layertree.py +36 -28
  35. c2cgeoportal_admin/views/logged_views.py +80 -0
  36. c2cgeoportal_admin/views/logs.py +90 -0
  37. c2cgeoportal_admin/views/oauth2_clients.py +30 -22
  38. c2cgeoportal_admin/views/ogc_servers.py +119 -37
  39. c2cgeoportal_admin/views/restriction_areas.py +13 -11
  40. c2cgeoportal_admin/views/roles.py +16 -12
  41. c2cgeoportal_admin/views/themes.py +15 -14
  42. c2cgeoportal_admin/views/themes_ordering.py +13 -8
  43. c2cgeoportal_admin/views/treeitems.py +14 -12
  44. c2cgeoportal_admin/views/users.py +12 -7
  45. c2cgeoportal_admin/widgets.py +17 -14
  46. {c2cgeoportal_admin-2.6.0.dist-info → c2cgeoportal_admin-2.8.1.180.dist-info}/METADATA +17 -8
  47. c2cgeoportal_admin-2.8.1.180.dist-info/RECORD +95 -0
  48. {c2cgeoportal_admin-2.6.0.dist-info → c2cgeoportal_admin-2.8.1.180.dist-info}/WHEEL +1 -1
  49. c2cgeoportal_admin-2.8.1.180.dist-info/entry_points.txt +6 -0
  50. tests/__init__.py +11 -12
  51. tests/conftest.py +2 -1
  52. tests/test_edit_url.py +11 -14
  53. tests/test_functionalities.py +52 -14
  54. tests/test_home.py +0 -1
  55. tests/test_interface.py +34 -11
  56. tests/test_layer_groups.py +57 -27
  57. tests/test_layers_vectortiles.py +43 -20
  58. tests/test_layers_wms.py +67 -45
  59. tests/test_layers_wmts.py +47 -26
  60. tests/test_layertree.py +99 -16
  61. tests/test_left_menu.py +0 -1
  62. tests/test_lingua_extractor_config.py +64 -0
  63. tests/test_logs.py +103 -0
  64. tests/test_main.py +3 -1
  65. tests/test_metadatas.py +34 -21
  66. tests/test_oauth2_clients.py +37 -9
  67. tests/test_ogc_servers.py +84 -35
  68. tests/test_restriction_areas.py +38 -15
  69. tests/test_role.py +68 -41
  70. tests/test_themes.py +71 -37
  71. tests/test_themes_ordering.py +1 -2
  72. tests/test_treegroup.py +2 -2
  73. tests/test_user.py +48 -17
  74. tests/themes_ordering.py +1 -2
  75. c2cgeoportal_admin/templates/navigation_vertical.jinja2 +0 -33
  76. c2cgeoportal_admin-2.6.0.dist-info/RECORD +0 -89
  77. c2cgeoportal_admin-2.6.0.dist-info/entry_points.txt +0 -3
  78. {c2cgeoportal_admin-2.6.0.dist-info → c2cgeoportal_admin-2.8.1.180.dist-info}/top_level.txt +0 -0
tests/test_layers_wms.py CHANGED
@@ -14,16 +14,16 @@ def layer_wms_test_data(dbsession, transact):
14
14
 
15
15
  from c2cgeoportal_commons.models.main import LayerWMS, OGCServer
16
16
 
17
- servers = [OGCServer(name="server_{}".format(i)) for i in range(0, 4)]
17
+ servers = [OGCServer(name=f"server_{i}") for i in range(0, 4)]
18
18
  for i, server in enumerate(servers):
19
- server.url = "http://wms.geo.admin.ch_{}".format(i)
19
+ server.url = f"http://wms.geo.admin.ch_{i}"
20
20
  server.image_type = "image/jpeg" if i % 2 == 0 else "image/png"
21
21
 
22
22
  def layer_builder(i):
23
- layer = LayerWMS(name="layer_wms_{}".format(i))
24
- layer.layer = "layer_{}".format(i)
23
+ layer = LayerWMS(name=f"layer_wms_{i}")
24
+ layer.layer = f"layer_{i}"
25
25
  layer.public = 1 == i % 2
26
- layer.geo_table = "geotable_{}".format(i)
26
+ layer.geo_table = f"geotable_{i}"
27
27
  layer.ogc_server = servers[i % 4]
28
28
  layer.style = "décontrasté"
29
29
  return layer
@@ -39,7 +39,6 @@ def layer_wms_test_data(dbsession, transact):
39
39
 
40
40
  @pytest.mark.usefixtures("layer_wms_test_data", "test_app")
41
41
  class TestLayerWMSViews(AbstractViewsTests):
42
-
43
42
  _prefix = "/admin/layers_wms"
44
43
 
45
44
  def test_index_rendering(self, test_app):
@@ -154,6 +153,8 @@ class TestLayerWMSViews(AbstractViewsTests):
154
153
  assert form["public"].checked
155
154
 
156
155
  def test_edit(self, test_app, layer_wms_test_data, dbsession):
156
+ from c2cgeoportal_commons.models.main import Log, LogAction
157
+
157
158
  layer = layer_wms_test_data["layers"][0]
158
159
 
159
160
  form = self.get_item(test_app, layer.id).form
@@ -173,11 +174,11 @@ class TestLayerWMSViews(AbstractViewsTests):
173
174
  assert str(layer.time_widget) == form["time_widget"].value
174
175
 
175
176
  interfaces = layer_wms_test_data["interfaces"]
176
- assert set((interfaces[0].id, interfaces[2].id)) == set(i.id for i in layer.interfaces)
177
+ assert {interfaces[0].id, interfaces[2].id} == {i.id for i in layer.interfaces}
177
178
  self._check_interfaces(form, interfaces, layer)
178
179
 
179
180
  ras = layer_wms_test_data["restrictionareas"]
180
- assert set((ras[0].id, ras[2].id)) == set(i.id for i in layer.restrictionareas)
181
+ assert {ras[0].id, ras[2].id} == {i.id for i in layer.restrictionareas}
181
182
  self._check_restrictionsareas(form, ras, layer)
182
183
 
183
184
  new_values = {
@@ -200,7 +201,7 @@ class TestLayerWMSViews(AbstractViewsTests):
200
201
 
201
202
  resp = form.submit("submit")
202
203
  assert str(layer.id) == re.match(
203
- r"http://localhost{}/(.*)\?msg_col=submit_ok".format(self._prefix), resp.location
204
+ rf"http://localhost{self._prefix}/(.*)\?msg_col=submit_ok", resp.location
204
205
  ).group(1)
205
206
 
206
207
  dbsession.expire(layer)
@@ -209,13 +210,19 @@ class TestLayerWMSViews(AbstractViewsTests):
209
210
  assert value == getattr(layer, key)
210
211
  else:
211
212
  assert str(value or "") == str(getattr(layer, key) or "")
212
- assert set([interfaces[1].id, interfaces[3].id]) == set(
213
- [interface.id for interface in layer.interfaces]
214
- )
215
- assert set([ras[1].id, ras[3].id]) == set([ra.id for ra in layer.restrictionareas])
213
+ assert {interfaces[1].id, interfaces[3].id} == {interface.id for interface in layer.interfaces}
214
+ assert {ras[1].id, ras[3].id} == {ra.id for ra in layer.restrictionareas}
215
+
216
+ log = dbsession.query(Log).one()
217
+ assert log.date != None
218
+ assert log.action == LogAction.UPDATE
219
+ assert log.element_type == "layer_wms"
220
+ assert log.element_id == layer.id
221
+ assert log.element_name == layer.name
222
+ assert log.username == "test_user"
216
223
 
217
224
  def test_submit_new(self, dbsession, test_app, layer_wms_test_data):
218
- from c2cgeoportal_commons.models.main import LayerWMS
225
+ from c2cgeoportal_commons.models.main import LayerWMS, Log, LogAction
219
226
 
220
227
  resp = test_app.post(
221
228
  "/admin/layers_wms/new",
@@ -239,12 +246,20 @@ class TestLayerWMSViews(AbstractViewsTests):
239
246
  r"http://localhost/admin/layers_wms/(.*)\?msg_col=submit_ok", resp.location
240
247
  ).group(1)
241
248
 
249
+ log = dbsession.query(Log).one()
250
+ assert log.date != None
251
+ assert log.action == LogAction.INSERT
252
+ assert log.element_type == "layer_wms"
253
+ assert log.element_id == layer.id
254
+ assert log.element_name == layer.name
255
+ assert log.username == "test_user"
256
+
242
257
  def test_duplicate(self, layer_wms_test_data, test_app, dbsession):
243
258
  from c2cgeoportal_commons.models.main import LayerWMS
244
259
 
245
260
  layer = layer_wms_test_data["layers"][3]
246
261
 
247
- resp = test_app.get("/admin/layers_wms/{}/duplicate".format(layer.id), status=200)
262
+ resp = test_app.get(f"/admin/layers_wms/{layer.id}/duplicate", status=200)
248
263
  form = resp.form
249
264
 
250
265
  assert "" == self.get_first_field_named(form, "id").value
@@ -260,11 +275,11 @@ class TestLayerWMSViews(AbstractViewsTests):
260
275
  assert str(layer.time_mode) == form["time_mode"].value
261
276
  assert str(layer.time_widget) == form["time_widget"].value
262
277
  interfaces = layer_wms_test_data["interfaces"]
263
- assert set((interfaces[3].id, interfaces[1].id)) == set(i.id for i in layer.interfaces)
278
+ assert {interfaces[3].id, interfaces[1].id} == {i.id for i in layer.interfaces}
264
279
  self._check_interfaces(form, interfaces, layer)
265
280
 
266
281
  ras = layer_wms_test_data["restrictionareas"]
267
- assert set((ras[3].id, ras[0].id)) == set(i.id for i in layer.restrictionareas)
282
+ assert {ras[3].id, ras[0].id} == {i.id for i in layer.restrictionareas}
268
283
  self._check_restrictionsareas(form, ras, layer)
269
284
 
270
285
  self._check_dimensions(resp.html, layer.dimensions, duplicated=True)
@@ -289,12 +304,9 @@ class TestLayerWMSViews(AbstractViewsTests):
289
304
  assert 0 == dbsession.query(LayerWMTS).filter(LayerWMTS.name == layer.name).count()
290
305
  assert 1 == dbsession.query(LayerWMS).filter(LayerWMS.name == layer.name).count()
291
306
 
292
- resp = test_app.post("/admin/layers_wms/{}/convert_to_wmts".format(layer.id), status=200)
307
+ resp = test_app.post(f"/admin/layers_wms/{layer.id}/convert_to_wmts", status=200)
293
308
  assert resp.json["success"]
294
- assert (
295
- "http://localhost/admin/layers_wmts/{}?msg_col=submit_ok".format(layer.id)
296
- == resp.json["redirect"]
297
- )
309
+ assert f"http://localhost/admin/layers_wmts/{layer.id}?msg_col=submit_ok" == resp.json["redirect"]
298
310
 
299
311
  assert 1 == dbsession.query(LayerWMTS).filter(LayerWMTS.name == layer.name).count()
300
312
  assert 0 == dbsession.query(LayerWMS).filter(LayerWMS.name == layer.name).count()
@@ -328,41 +340,43 @@ class TestLayerWMSViews(AbstractViewsTests):
328
340
  def test_convert_image_type_from_ogcserver(self, layer_wms_test_data, test_app):
329
341
  layer = layer_wms_test_data["layers"][3]
330
342
 
331
- resp = test_app.post("/admin/layers_wms/{}/convert_to_wmts".format(layer.id), status=200)
343
+ resp = test_app.post(f"/admin/layers_wms/{layer.id}/convert_to_wmts", status=200)
332
344
  assert resp.json["success"]
333
- assert (
334
- "http://localhost/admin/layers_wmts/{}?msg_col=submit_ok".format(layer.id)
335
- == resp.json["redirect"]
336
- )
345
+ assert f"http://localhost/admin/layers_wmts/{layer.id}?msg_col=submit_ok" == resp.json["redirect"]
337
346
 
338
347
  resp = test_app.get(resp.json["redirect"], status=200)
339
348
  assert "image/png" == resp.form["image_type"].value
340
349
 
341
350
  layer = layer_wms_test_data["layers"][2]
342
- resp = test_app.post("/admin/layers_wms/{}/convert_to_wmts".format(layer.id), status=200)
351
+ resp = test_app.post(f"/admin/layers_wms/{layer.id}/convert_to_wmts", status=200)
343
352
  assert resp.json["success"]
344
- assert (
345
- "http://localhost/admin/layers_wmts/{}?msg_col=submit_ok".format(layer.id)
346
- == resp.json["redirect"]
347
- )
353
+ assert f"http://localhost/admin/layers_wmts/{layer.id}?msg_col=submit_ok" == resp.json["redirect"]
348
354
 
349
355
  resp = test_app.get(resp.json["redirect"], status=200)
350
356
  assert "image/jpeg" == resp.form["image_type"].value
351
357
 
352
358
  def test_convert_without_wmts_defaults(self, test_app, layer_wms_test_data, dbsession):
353
- from c2cgeoportal_commons.models.main import LayerWMTS
359
+ from c2cgeoportal_commons.models.main import LayerWMTS, Log, LogAction
354
360
 
355
361
  dbsession.delete(LayerWMTS.get_default(dbsession))
356
362
  layer = layer_wms_test_data["layers"][3]
357
- test_app.post("/admin/layers_wms/{}/convert_to_wmts".format(layer.id), status=200)
363
+ test_app.post(f"/admin/layers_wms/{layer.id}/convert_to_wmts", status=200)
364
+
365
+ log = dbsession.query(Log).one()
366
+ assert log.date != None
367
+ assert log.action == LogAction.CONVERT_TO_WMTS
368
+ assert log.element_type == "layer_wms"
369
+ assert log.element_id == layer.id
370
+ assert log.element_name == layer.name
371
+ assert log.username == "test_user"
358
372
 
359
373
  def test_unicity_validator(self, layer_wms_test_data, test_app):
360
374
  layer = layer_wms_test_data["layers"][2]
361
- resp = test_app.get("/admin/layers_wms/{}/duplicate".format(layer.id), status=200)
375
+ resp = test_app.get(f"/admin/layers_wms/{layer.id}/duplicate", status=200)
362
376
 
363
377
  resp = resp.form.submit("submit")
364
378
 
365
- self._check_submission_problem(resp, "{} is already used.".format(layer.name))
379
+ self._check_submission_problem(resp, f"{layer.name} is already used.")
366
380
 
367
381
  def test_unicity_validator_does_not_matter_amongst_cousin(self, layer_wms_test_data, test_app, dbsession):
368
382
  from c2cgeoportal_commons.models.main import LayerGroup, LayerWMS
@@ -372,7 +386,7 @@ class TestLayerWMSViews(AbstractViewsTests):
372
386
  assert dbsession.query(LayerWMS).filter(LayerWMS.name == "layer_group_0").one_or_none() is None
373
387
 
374
388
  layer = layer_wms_test_data["layers"][2]
375
- resp = test_app.get("/admin/layers_wms/{}/duplicate".format(layer.id), status=200)
389
+ resp = test_app.get(f"/admin/layers_wms/{layer.id}/duplicate", status=200)
376
390
  self.set_first_field_named(resp.form, "name", "layer_group_0")
377
391
  resp = resp.form.submit("submit")
378
392
 
@@ -382,17 +396,25 @@ class TestLayerWMSViews(AbstractViewsTests):
382
396
  # assert str(layer.id) == re.match('http://localhost/admin/layers_wms/(.*)', resp.location).group(1)
383
397
 
384
398
  def test_delete(self, test_app, dbsession):
385
- from c2cgeoportal_commons.models.main import Layer, LayerWMS, TreeItem
399
+ from c2cgeoportal_commons.models.main import Layer, LayerWMS, Log, LogAction, TreeItem
400
+
401
+ layer = dbsession.query(LayerWMS).first()
386
402
 
387
- layer_id = dbsession.query(LayerWMS.id).first().id
403
+ test_app.delete(f"/admin/layers_wms/{layer.id}", status=200)
388
404
 
389
- test_app.delete("/admin/layers_wms/{}".format(layer_id), status=200)
405
+ assert dbsession.query(LayerWMS).get(layer.id) is None
406
+ assert dbsession.query(Layer).get(layer.id) is None
407
+ assert dbsession.query(TreeItem).get(layer.id) is None
390
408
 
391
- assert dbsession.query(LayerWMS).get(layer_id) is None
392
- assert dbsession.query(Layer).get(layer_id) is None
393
- assert dbsession.query(TreeItem).get(layer_id) is None
409
+ log = dbsession.query(Log).one()
410
+ assert log.date != None
411
+ assert log.action == LogAction.DELETE
412
+ assert log.element_type == "layer_wms"
413
+ assert log.element_id == layer.id
414
+ assert log.element_name == layer.name
415
+ assert log.username == "test_user"
394
416
 
395
- def test_submit_new_no_layer_name(self, test_app, layer_wms_test_data):
417
+ def test_submit_new_no_layer_name(self, test_app, layer_wms_test_data, dbsession):
396
418
  resp = test_app.post(
397
419
  "/admin/layers_wms/new",
398
420
  {
@@ -417,5 +439,5 @@ class TestLayerWMSViews(AbstractViewsTests):
417
439
  "Errors have been highlighted below" == resp.html.select_one('div[class="error-msg-detail"]').text
418
440
  )
419
441
  assert ["WMS layer name"] == sorted(
420
- [(x.select_one("label").text.strip()) for x in resp.html.select("[class~='has-error']")]
442
+ (x.select_one("label").text.strip()) for x in resp.html.select("[class~='has-error']")
421
443
  )
tests/test_layers_wmts.py CHANGED
@@ -19,12 +19,12 @@ def layer_wmts_test_data(dbsession, transact):
19
19
  server.image_type = "image/png"
20
20
 
21
21
  def layer_builder(i):
22
- name = "layer_wmts_{}".format(i)
22
+ name = f"layer_wmts_{i}"
23
23
  layer = LayerWMTS(name=name)
24
24
  layer.layer = name
25
- layer.url = "https:///wms.geo.admin.ch_{}.org?service=wms&request=GetCapabilities".format(i)
25
+ layer.url = f"https:///wms.geo.admin.ch_{i}.org?service=wms&request=GetCapabilities"
26
26
  layer.public = 1 == i % 2
27
- layer.geo_table = "geotable_{}".format(i)
27
+ layer.geo_table = f"geotable_{i}"
28
28
  layer.image_type = "image/jpeg"
29
29
  layer.style = "décontrasté"
30
30
  return layer
@@ -39,7 +39,6 @@ def layer_wmts_test_data(dbsession, transact):
39
39
 
40
40
  @pytest.mark.usefixtures("layer_wmts_test_data", "test_app")
41
41
  class TestLayerWMTS(AbstractViewsTests):
42
-
43
42
  _prefix = "/admin/layers_wmts"
44
43
 
45
44
  def test_index_rendering(self, test_app):
@@ -102,6 +101,8 @@ class TestLayerWMTS(AbstractViewsTests):
102
101
  assert default_wmts.matrix_set == self.get_first_field_named(form, "matrix_set").value
103
102
 
104
103
  def test_edit(self, test_app, layer_wmts_test_data, dbsession):
104
+ from c2cgeoportal_commons.models.main import Log, LogAction
105
+
105
106
  layer = layer_wmts_test_data["layers"][0]
106
107
 
107
108
  form = self.get_item(test_app, layer.id).form
@@ -121,11 +122,11 @@ class TestLayerWMTS(AbstractViewsTests):
121
122
  assert str(layer.image_type or "") == form["image_type"].value
122
123
 
123
124
  interfaces = layer_wmts_test_data["interfaces"]
124
- assert set((interfaces[0].id, interfaces[2].id)) == set(i.id for i in layer.interfaces)
125
+ assert {interfaces[0].id, interfaces[2].id} == {i.id for i in layer.interfaces}
125
126
  self._check_interfaces(form, interfaces, layer)
126
127
 
127
128
  ras = layer_wmts_test_data["restrictionareas"]
128
- assert set((ras[0].id, ras[2].id)) == set(i.id for i in layer.restrictionareas)
129
+ assert {ras[0].id, ras[2].id} == {i.id for i in layer.restrictionareas}
129
130
  self._check_restrictionsareas(form, ras, layer)
130
131
 
131
132
  new_values = {
@@ -148,7 +149,7 @@ class TestLayerWMTS(AbstractViewsTests):
148
149
 
149
150
  resp = form.submit("submit")
150
151
  assert str(layer.id) == re.match(
151
- r"http://localhost{}/(.*)\?msg_col=submit_ok".format(self._prefix), resp.location
152
+ rf"http://localhost{self._prefix}/(.*)\?msg_col=submit_ok", resp.location
152
153
  ).group(1)
153
154
 
154
155
  dbsession.expire(layer)
@@ -157,17 +158,23 @@ class TestLayerWMTS(AbstractViewsTests):
157
158
  assert value == getattr(layer, key)
158
159
  else:
159
160
  assert str(value or "") == str(getattr(layer, key) or "")
160
- assert set([interfaces[1].id, interfaces[3].id]) == set(
161
- [interface.id for interface in layer.interfaces]
162
- )
163
- assert set([ras[1].id, ras[3].id]) == set([ra.id for ra in layer.restrictionareas])
161
+ assert {interfaces[1].id, interfaces[3].id} == {interface.id for interface in layer.interfaces}
162
+ assert {ras[1].id, ras[3].id} == {ra.id for ra in layer.restrictionareas}
163
+
164
+ log = dbsession.query(Log).one()
165
+ assert log.date != None
166
+ assert log.action == LogAction.UPDATE
167
+ assert log.element_type == "layer_wmts"
168
+ assert log.element_id == layer.id
169
+ assert log.element_name == layer.name
170
+ assert log.username == "test_user"
164
171
 
165
172
  def test_duplicate(self, layer_wmts_test_data, test_app, dbsession):
166
173
  from c2cgeoportal_commons.models.main import LayerWMTS
167
174
 
168
175
  layer = layer_wmts_test_data["layers"][3]
169
176
 
170
- resp = test_app.get("/admin/layers_wmts/{}/duplicate".format(layer.id), status=200)
177
+ resp = test_app.get(f"/admin/layers_wmts/{layer.id}/duplicate", status=200)
171
178
  form = resp.form
172
179
 
173
180
  assert "" == self.get_first_field_named(form, "id").value
@@ -192,23 +199,31 @@ class TestLayerWMTS(AbstractViewsTests):
192
199
  ).group(1)
193
200
 
194
201
  def test_delete(self, test_app, dbsession):
195
- from c2cgeoportal_commons.models.main import Layer, LayerWMTS, TreeItem
202
+ from c2cgeoportal_commons.models.main import Layer, LayerWMTS, Log, LogAction, TreeItem
196
203
 
197
- layer_id = dbsession.query(LayerWMTS.id).first().id
204
+ layer = dbsession.query(LayerWMTS).first()
198
205
 
199
- test_app.delete("/admin/layers_wmts/{}".format(layer_id), status=200)
206
+ test_app.delete(f"/admin/layers_wmts/{layer.id}", status=200)
200
207
 
201
- assert dbsession.query(LayerWMTS).get(layer_id) is None
202
- assert dbsession.query(Layer).get(layer_id) is None
203
- assert dbsession.query(TreeItem).get(layer_id) is None
208
+ assert dbsession.query(LayerWMTS).get(layer.id) is None
209
+ assert dbsession.query(Layer).get(layer.id) is None
210
+ assert dbsession.query(TreeItem).get(layer.id) is None
211
+
212
+ log = dbsession.query(Log).one()
213
+ assert log.date != None
214
+ assert log.action == LogAction.DELETE
215
+ assert log.element_type == "layer_wmts"
216
+ assert log.element_id == layer.id
217
+ assert log.element_name == layer.name
218
+ assert log.username == "test_user"
204
219
 
205
220
  def test_unicity_validator(self, layer_wmts_test_data, test_app):
206
221
  layer = layer_wmts_test_data["layers"][2]
207
- resp = test_app.get("/admin/layers_wmts/{}/duplicate".format(layer.id), status=200)
222
+ resp = test_app.get(f"/admin/layers_wmts/{layer.id}/duplicate", status=200)
208
223
 
209
224
  resp = resp.form.submit("submit")
210
225
 
211
- self._check_submission_problem(resp, "{} is already used.".format(layer.name))
226
+ self._check_submission_problem(resp, f"{layer.name} is already used.")
212
227
 
213
228
  def test_convert_common_fields_copied(self, layer_wmts_test_data, test_app, dbsession):
214
229
  from c2cgeoportal_commons.models.main import LayerWMS, LayerWMTS
@@ -218,10 +233,8 @@ class TestLayerWMTS(AbstractViewsTests):
218
233
  assert 0 == dbsession.query(LayerWMS).filter(LayerWMS.name == layer.name).count()
219
234
  assert 1 == dbsession.query(LayerWMTS).filter(LayerWMTS.name == layer.name).count()
220
235
 
221
- resp = test_app.post("/admin/layers_wmts/{}/convert_to_wms".format(layer.id), status=200)
222
- assert (
223
- "http://localhost/admin/layers_wms/{}?msg_col=submit_ok".format(layer.id) == resp.json["redirect"]
224
- )
236
+ resp = test_app.post(f"/admin/layers_wmts/{layer.id}/convert_to_wms", status=200)
237
+ assert f"http://localhost/admin/layers_wms/{layer.id}?msg_col=submit_ok" == resp.json["redirect"]
225
238
 
226
239
  assert 1 == dbsession.query(LayerWMS).filter(LayerWMS.name == layer.name).count()
227
240
  assert 0 == dbsession.query(LayerWMTS).filter(LayerWMTS.name == layer.name).count()
@@ -252,8 +265,16 @@ class TestLayerWMTS(AbstractViewsTests):
252
265
  )
253
266
 
254
267
  def test_convert_without_wms_defaults(self, test_app, layer_wmts_test_data, dbsession):
255
- from c2cgeoportal_commons.models.main import LayerWMS
268
+ from c2cgeoportal_commons.models.main import LayerWMS, Log, LogAction
256
269
 
257
270
  dbsession.delete(LayerWMS.get_default(dbsession))
258
271
  layer = layer_wmts_test_data["layers"][3]
259
- test_app.post("/admin/layers_wmts/{}/convert_to_wms".format(layer.id), status=200)
272
+ test_app.post(f"/admin/layers_wmts/{layer.id}/convert_to_wms", status=200)
273
+
274
+ log = dbsession.query(Log).one()
275
+ assert log.date != None
276
+ assert log.action == LogAction.CONVERT_TO_WMS
277
+ assert log.element_type == "layer_wmts"
278
+ assert log.element_id == layer.id
279
+ assert log.element_name == layer.name
280
+ assert log.username == "test_user"
tests/test_layertree.py CHANGED
@@ -13,6 +13,7 @@ def layertree_test_data(dbsession, transact):
13
13
  del transact
14
14
 
15
15
  from c2cgeoportal_commons.models.main import (
16
+ Interface,
16
17
  LayerGroup,
17
18
  LayergroupTreeitem,
18
19
  LayerWMS,
@@ -21,26 +22,39 @@ def layertree_test_data(dbsession, transact):
21
22
  Theme,
22
23
  )
23
24
 
25
+ interface1 = Interface("interface1")
26
+ dbsession.add(interface1)
27
+ interface2 = Interface("interface2")
28
+ dbsession.add(interface2)
29
+
24
30
  layers_wms = []
25
31
  ogc_server = OGCServer(name="ogc_server")
26
32
  dbsession.add(ogc_server)
27
- for i in range(0, 10):
28
- layer_wms = LayerWMS(name="layer_wms_{}".format(i))
33
+ for i in range(10):
34
+ layer_wms = LayerWMS(name=f"layer_wms_{i}")
35
+ if i == 1:
36
+ layer_wms.interfaces = [interface1]
37
+ elif i > 1:
38
+ layer_wms.interfaces = [interface1, interface2]
29
39
  layer_wms.ogc_server = ogc_server
30
40
  layers_wms.append(layer_wms)
31
41
  dbsession.add(layer_wms)
32
42
 
33
43
  layers_wmts = []
34
- for i in range(0, 10):
35
- layer_wmts = LayerWMTS(name="layer_wmts_{}".format(i))
44
+ for i in range(10):
45
+ layer_wmts = LayerWMTS(name=f"layer_wmts_{i}")
46
+ if i == 1:
47
+ layer_wmts.interfaces = [interface1]
48
+ elif i > 1:
49
+ layer_wmts.interfaces = [interface1, interface2]
36
50
  layer_wmts.url = "http://localhost/wmts"
37
51
  layer_wmts.layer = layer_wmts.name
38
52
  layers_wmts.append(layer_wmts)
39
53
  dbsession.add(layer_wmts)
40
54
 
41
55
  groups = []
42
- for i in range(0, 10):
43
- group = LayerGroup(name="layer_group_{}".format(i))
56
+ for i in range(10):
57
+ group = LayerGroup(name=f"layer_group_{i}")
44
58
  groups.append(group)
45
59
  dbsession.add(group)
46
60
 
@@ -51,10 +65,14 @@ def layertree_test_data(dbsession, transact):
51
65
  dbsession.add(LayergroupTreeitem(group=groups[9], item=groups[8], ordering=3))
52
66
 
53
67
  themes = []
54
- for i in range(0, 5):
55
- theme = Theme(name="theme_{}".format(i))
68
+ for i in range(5):
69
+ theme = Theme(name=f"theme_{i}")
56
70
  themes.append(theme)
57
71
  dbsession.add(theme)
72
+ if i == 1:
73
+ theme.interfaces = [interface1]
74
+ elif i > 1:
75
+ theme.interfaces = [interface1, interface2]
58
76
 
59
77
  dbsession.add(LayergroupTreeitem(group=theme, item=groups[i], ordering=0))
60
78
  dbsession.add(LayergroupTreeitem(group=theme, item=groups[i + 5], ordering=1))
@@ -74,6 +92,7 @@ def layertree_test_data(dbsession, transact):
74
92
  "layers_wms": layers_wms,
75
93
  "layers_wmts": layers_wmts,
76
94
  "ogc_servers": [ogc_server],
95
+ "interfaces": [interface1, interface2],
77
96
  }
78
97
  )
79
98
 
@@ -84,7 +103,6 @@ def layertree_test_data(dbsession, transact):
84
103
  )
85
104
  @pytest.mark.usefixtures("layertree_test_data", "test_app")
86
105
  class TestLayerTreeView(AbstractViewsTests):
87
-
88
106
  _prefix = "/admin/layertree"
89
107
 
90
108
  def test_index(self, test_app):
@@ -93,13 +111,13 @@ class TestLayerTreeView(AbstractViewsTests):
93
111
  def check_edit_action(self, test_app, nodes, table, item_id):
94
112
  node = next(n for n in nodes if n["id"] == item_id)
95
113
  action = next(a for a in node["actions"] if a["name"] == "edit")
96
- assert "http://localhost/admin/{}/{}".format(table, item_id) == action["url"]
114
+ assert f"http://localhost/admin/{table}/{item_id}" == action["url"]
97
115
  test_app.get(action["url"], status=200)
98
116
 
99
117
  def check_unlink_action(self, test_app, nodes, group_id, item_id):
100
118
  node = next(n for n in nodes if n["id"] == item_id)
101
119
  action = next(a for a in node["actions"] if a["name"] == "unlink")
102
- assert "http://localhost/admin/layertree/unlink/{}/{}".format(group_id, item_id) == action["url"]
120
+ assert f"http://localhost/admin/layertree/unlink/{group_id}/{item_id}" == action["url"]
103
121
  test_app.delete(action["url"], status=200)
104
122
 
105
123
  def check_translation(self, nodes, item):
@@ -111,7 +129,7 @@ class TestLayerTreeView(AbstractViewsTests):
111
129
  node = next(n for n in nodes if n["id"] == parent_id)
112
130
  action = next(a for a in node["actions"] if a["name"] == action_name)
113
131
  assert label == action["label"]
114
- assert "http://localhost/admin/{}/new?parent_id={}".format(route_table, parent_id) == action["url"]
132
+ assert f"http://localhost/admin/{route_table}/new?parent_id={parent_id}" == action["url"]
115
133
 
116
134
  form = test_app.get(action["url"], status=200).form
117
135
  assert form["parent_id"].value == str(parent_id)
@@ -150,12 +168,26 @@ class TestLayerTreeView(AbstractViewsTests):
150
168
  {"name": "new_name_from_layer_group"},
151
169
  )
152
170
 
153
- def test_groups(self, test_app, layertree_test_data):
171
+ def test_groups(self, test_app, layertree_test_data, dbsession):
154
172
  theme = layertree_test_data["themes"][0]
173
+
174
+ # Invert children order (to test ordering)
175
+ theme.children_relation[0].ordering = 1
176
+ theme.children_relation[1].ordering = 0
177
+ dbsession.flush()
178
+
155
179
  resp = self.get(test_app, "/children?group_id={0}&path=_{0}".format(theme.id), status=200)
156
180
  nodes = resp.json
157
181
  assert 2 == len(nodes)
158
182
 
183
+ # check groups are sorted by ordering
184
+ expected = [
185
+ relation.treeitem.name
186
+ for relation in sorted(theme.children_relation, key=lambda relation: relation.ordering)
187
+ ]
188
+ group_names = [node["name"] for node in nodes]
189
+ assert expected == group_names
190
+
159
191
  group = layertree_test_data["groups"][0]
160
192
  self.check_edit_action(test_app, nodes, "layer_groups", group.id)
161
193
  self.check_unlink_action(test_app, nodes, theme.id, group.id)
@@ -186,15 +218,29 @@ class TestLayerTreeView(AbstractViewsTests):
186
218
  },
187
219
  )
188
220
 
189
- def test_layers(self, test_app, layertree_test_data):
221
+ def test_layers(self, test_app, layertree_test_data, dbsession):
190
222
  theme = layertree_test_data["themes"][0]
191
223
  group = layertree_test_data["groups"][0]
224
+
225
+ # Invert children order (to test ordering)
226
+ group.children_relation[0].ordering = 1
227
+ group.children_relation[1].ordering = 0
228
+ dbsession.flush()
229
+
192
230
  resp = self.get(
193
231
  test_app, "/children?group_id={0}&path=_{1}_{0}".format(group.id, theme.id), status=200
194
232
  )
195
233
  nodes = resp.json
196
234
  assert len(nodes) == 2
197
235
 
236
+ # check layers are sorted by ordering
237
+ expected = [
238
+ relation.treeitem.name
239
+ for relation in sorted(group.children_relation, key=lambda relation: relation.ordering)
240
+ ]
241
+ layer_names = [node["name"] for node in nodes]
242
+ assert expected == layer_names
243
+
198
244
  layer_wms = layertree_test_data["layers_wms"][0]
199
245
  layer_wmts = layertree_test_data["layers_wmts"][0]
200
246
 
@@ -210,7 +256,7 @@ class TestLayerTreeView(AbstractViewsTests):
210
256
  def test_unlink(self, test_app, layertree_test_data, dbsession):
211
257
  group = layertree_test_data["groups"][0]
212
258
  item = layertree_test_data["layers_wms"][0]
213
- test_app.delete("/admin/layertree/unlink/{}/{}".format(group.id, item.id), status=200)
259
+ test_app.delete(f"/admin/layertree/unlink/{group.id}/{item.id}", status=200)
214
260
  dbsession.expire_all()
215
261
  assert item not in group.children
216
262
 
@@ -226,5 +272,42 @@ class TestLayerTreeView(AbstractViewsTests):
226
272
  (layers_wms[1].id, LayerWMS),
227
273
  (groups[1].id, LayerGroup),
228
274
  ):
229
- test_app.delete("/admin/layertree/delete/{}".format(item_id), status=200)
275
+ test_app.delete(f"/admin/layertree/delete/{item_id}", status=200)
230
276
  assert dbsession.query(model).get(item_id) is None
277
+
278
+ @pytest.mark.parametrize(
279
+ "params,expected",
280
+ [
281
+ ({}, ["theme_0", "theme_3", "theme_1", "theme_2", "theme_4"]),
282
+ ({"interface": "interface1"}, ["theme_3", "theme_1", "theme_2", "theme_4"]),
283
+ ({"interface": "interface2"}, ["theme_3", "theme_2", "theme_4"]),
284
+ ],
285
+ )
286
+ def test_themes_interfaces(self, test_app, layertree_test_data, params, expected):
287
+ resp = self.get(test_app, "/children", status=200, params=params)
288
+ nodes = resp.json
289
+ assert expected == [node["name"] for node in nodes if node["item_type"] == "theme"]
290
+
291
+ @pytest.mark.parametrize(
292
+ "interface,index,length",
293
+ [
294
+ (None, 0, 2),
295
+ (None, 1, 2),
296
+ (None, 2, 2),
297
+ ("interface1", 0, 0),
298
+ ("interface1", 1, 2),
299
+ ("interface1", 2, 2),
300
+ ("interface2", 0, 0),
301
+ ("interface2", 1, 0),
302
+ ("interface2", 2, 2),
303
+ ],
304
+ )
305
+ def test_layers_interface(self, test_app, layertree_test_data, interface, index, length):
306
+ theme = layertree_test_data["themes"][index]
307
+ group = layertree_test_data["groups"][index]
308
+ params = {"group_id": group.id, "path": f"_{theme.id}_{group.id}"}
309
+ if interface:
310
+ params["interface"] = interface
311
+ resp = self.get(test_app, "/children", status=200, params=params)
312
+ nodes = resp.json
313
+ assert length == len(nodes)
tests/test_left_menu.py CHANGED
@@ -24,7 +24,6 @@ def left_menu_test_data(dbsession, transact):
24
24
 
25
25
  @pytest.mark.usefixtures("test_app")
26
26
  class TestLeftMenu(AbstractViewsTests):
27
-
28
27
  _prefix = "/admin/roles"
29
28
 
30
29
  def test_index(self, test_app):