c2cgeoportal-admin 2.5.0.100__py3-none-any.whl → 2.9rc44__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 (99) hide show
  1. c2cgeoportal_admin/__init__.py +44 -14
  2. c2cgeoportal_admin/lib/__init__.py +0 -0
  3. c2cgeoportal_admin/lib/lingva_extractor.py +77 -0
  4. c2cgeoportal_admin/lib/ogcserver_synchronizer.py +410 -0
  5. c2cgeoportal_admin/py.typed +0 -0
  6. c2cgeoportal_admin/routes.py +30 -11
  7. c2cgeoportal_admin/schemas/dimensions.py +17 -11
  8. c2cgeoportal_admin/schemas/functionalities.py +60 -22
  9. c2cgeoportal_admin/schemas/interfaces.py +27 -19
  10. c2cgeoportal_admin/schemas/metadata.py +122 -48
  11. c2cgeoportal_admin/schemas/restriction_areas.py +26 -20
  12. c2cgeoportal_admin/schemas/roles.py +13 -7
  13. c2cgeoportal_admin/schemas/treegroup.py +90 -20
  14. c2cgeoportal_admin/schemas/treeitem.py +3 -4
  15. c2cgeoportal_admin/static/layertree.css +26 -4
  16. c2cgeoportal_admin/static/navbar.css +59 -36
  17. c2cgeoportal_admin/static/theme.css +51 -11
  18. c2cgeoportal_admin/subscribers.py +3 -3
  19. c2cgeoportal_admin/templates/404.jinja2 +41 -2
  20. c2cgeoportal_admin/templates/edit.jinja2 +23 -0
  21. c2cgeoportal_admin/templates/home.jinja2 +23 -0
  22. c2cgeoportal_admin/templates/index.jinja2 +23 -0
  23. c2cgeoportal_admin/templates/layertree.jinja2 +55 -11
  24. c2cgeoportal_admin/templates/layout.jinja2 +23 -0
  25. c2cgeoportal_admin/templates/navigation_navbar.jinja2 +56 -0
  26. c2cgeoportal_admin/templates/ogcserver_synchronize.jinja2 +90 -0
  27. c2cgeoportal_admin/templates/widgets/child.pt +35 -3
  28. c2cgeoportal_admin/templates/widgets/children.pt +121 -92
  29. c2cgeoportal_admin/templates/widgets/dimension.pt +23 -0
  30. c2cgeoportal_admin/templates/widgets/dimensions.pt +23 -0
  31. c2cgeoportal_admin/templates/widgets/functionality_fields.pt +51 -0
  32. c2cgeoportal_admin/templates/widgets/layer_fields.pt +23 -0
  33. c2cgeoportal_admin/templates/widgets/layer_group_fields.pt +23 -0
  34. c2cgeoportal_admin/templates/widgets/layer_v1_fields.pt +23 -0
  35. c2cgeoportal_admin/templates/widgets/metadata.pt +30 -1
  36. c2cgeoportal_admin/templates/widgets/metadatas.pt +23 -0
  37. c2cgeoportal_admin/templates/widgets/ogcserver_fields.pt +23 -0
  38. c2cgeoportal_admin/templates/widgets/restriction_area_fields.pt +25 -9
  39. c2cgeoportal_admin/templates/widgets/role_fields.pt +52 -25
  40. c2cgeoportal_admin/templates/widgets/theme_fields.pt +23 -0
  41. c2cgeoportal_admin/templates/widgets/user_fields.pt +23 -0
  42. c2cgeoportal_admin/views/__init__.py +29 -0
  43. c2cgeoportal_admin/views/dimension_layers.py +14 -9
  44. c2cgeoportal_admin/views/functionalities.py +52 -18
  45. c2cgeoportal_admin/views/home.py +5 -5
  46. c2cgeoportal_admin/views/interfaces.py +29 -21
  47. c2cgeoportal_admin/views/layer_groups.py +36 -25
  48. c2cgeoportal_admin/views/layers.py +17 -13
  49. c2cgeoportal_admin/views/layers_cog.py +135 -0
  50. c2cgeoportal_admin/views/layers_vectortiles.py +62 -27
  51. c2cgeoportal_admin/views/layers_wms.py +61 -36
  52. c2cgeoportal_admin/views/layers_wmts.py +54 -32
  53. c2cgeoportal_admin/views/layertree.py +37 -28
  54. c2cgeoportal_admin/views/logged_views.py +83 -0
  55. c2cgeoportal_admin/views/logs.py +91 -0
  56. c2cgeoportal_admin/views/oauth2_clients.py +96 -0
  57. c2cgeoportal_admin/views/ogc_servers.py +192 -21
  58. c2cgeoportal_admin/views/restriction_areas.py +78 -25
  59. c2cgeoportal_admin/views/roles.py +88 -25
  60. c2cgeoportal_admin/views/themes.py +47 -35
  61. c2cgeoportal_admin/views/themes_ordering.py +44 -24
  62. c2cgeoportal_admin/views/treeitems.py +21 -17
  63. c2cgeoportal_admin/views/users.py +46 -26
  64. c2cgeoportal_admin/widgets.py +79 -28
  65. {c2cgeoportal_admin-2.5.0.100.dist-info → c2cgeoportal_admin-2.9rc44.dist-info}/METADATA +15 -13
  66. c2cgeoportal_admin-2.9rc44.dist-info/RECORD +97 -0
  67. {c2cgeoportal_admin-2.5.0.100.dist-info → c2cgeoportal_admin-2.9rc44.dist-info}/WHEEL +1 -1
  68. c2cgeoportal_admin-2.9rc44.dist-info/entry_points.txt +5 -0
  69. tests/__init__.py +36 -27
  70. tests/conftest.py +23 -24
  71. tests/test_edit_url.py +16 -19
  72. tests/test_functionalities.py +52 -14
  73. tests/test_home.py +0 -1
  74. tests/test_interface.py +35 -12
  75. tests/test_layer_groups.py +58 -32
  76. tests/test_layers_cog.py +243 -0
  77. tests/test_layers_vectortiles.py +46 -30
  78. tests/test_layers_wms.py +77 -82
  79. tests/test_layers_wmts.py +51 -30
  80. tests/test_layertree.py +107 -101
  81. tests/test_learn.py +1 -1
  82. tests/test_left_menu.py +0 -1
  83. tests/test_lingva_extractor_config.py +64 -0
  84. tests/test_logs.py +102 -0
  85. tests/test_main.py +4 -2
  86. tests/test_metadatas.py +79 -71
  87. tests/test_oauth2_clients.py +186 -0
  88. tests/test_ogc_servers.py +110 -28
  89. tests/test_restriction_areas.py +109 -20
  90. tests/test_role.py +142 -82
  91. tests/test_themes.py +75 -41
  92. tests/test_themes_ordering.py +1 -2
  93. tests/test_treegroup.py +2 -2
  94. tests/test_user.py +72 -70
  95. tests/themes_ordering.py +1 -2
  96. c2cgeoportal_admin/templates/navigation_vertical.jinja2 +0 -10
  97. c2cgeoportal_admin-2.5.0.100.dist-info/RECORD +0 -84
  98. c2cgeoportal_admin-2.5.0.100.dist-info/entry_points.txt +0 -3
  99. {c2cgeoportal_admin-2.5.0.100.dist-info → c2cgeoportal_admin-2.9rc44.dist-info}/top_level.txt +0 -0
tests/test_interface.py CHANGED
@@ -12,18 +12,18 @@ from . import AbstractViewsTests
12
12
  def interface_test_data(dbsession, transact):
13
13
  del transact
14
14
 
15
- from c2cgeoportal_commons.models.main import Interface, Theme, OGCServer, LayerWMS
15
+ from c2cgeoportal_commons.models.main import Interface, LayerWMS, OGCServer, Theme
16
16
 
17
17
  themes = []
18
18
  for i in range(0, 5):
19
- theme = Theme(name="theme_{}".format(i), ordering=1)
19
+ theme = Theme(name=f"theme_{i}", ordering=1)
20
20
  themes.append(theme)
21
21
 
22
- servers = [OGCServer(name="server_{}".format(i)) for i in range(0, 4)]
22
+ servers = [OGCServer(name=f"server_{i}") for i in range(0, 4)]
23
23
 
24
24
  layers = []
25
25
  for i in range(0, 15):
26
- layer = LayerWMS(name="layer_wms_{}".format(i))
26
+ layer = LayerWMS(name=f"layer_wms_{i}")
27
27
  layer.public = 1 == i % 2
28
28
  layer.ogc_server = servers[i % 4]
29
29
  dbsession.add(layer)
@@ -31,7 +31,7 @@ def interface_test_data(dbsession, transact):
31
31
 
32
32
  interfaces = []
33
33
  for i in range(0, 5):
34
- interface = Interface(name="interface_{}".format(i), description="description_{}".format(i))
34
+ interface = Interface(name=f"interface_{i}", description=f"description_{i}")
35
35
  interface.themes = [themes[i % 2], themes[(i + 5) % 5]]
36
36
  interface.layers = [layers[i % 2], layers[(i + 4) % 5]]
37
37
 
@@ -45,7 +45,6 @@ def interface_test_data(dbsession, transact):
45
45
 
46
46
  @pytest.mark.usefixtures("interface_test_data", "test_app")
47
47
  class TestInterface(AbstractViewsTests):
48
-
49
48
  _prefix = "/admin/interfaces"
50
49
 
51
50
  def test_index_rendering(self, test_app):
@@ -82,7 +81,7 @@ class TestInterface(AbstractViewsTests):
82
81
  self.check_search(test_app, "interface_0", total=1)
83
82
 
84
83
  def test_submit_new(self, dbsession, test_app):
85
- from c2cgeoportal_commons.models.main import Interface
84
+ from c2cgeoportal_commons.models.main import Interface, Log, LogAction
86
85
 
87
86
  resp = test_app.post(
88
87
  "/admin/interfaces/new", {"name": "new_name", "description": "new description"}, status=302
@@ -94,14 +93,22 @@ class TestInterface(AbstractViewsTests):
94
93
  ).group(1)
95
94
  assert interface.name == "new_name"
96
95
 
96
+ log = dbsession.query(Log).one()
97
+ assert log.date != None
98
+ assert log.action == LogAction.INSERT
99
+ assert log.element_type == "interface"
100
+ assert log.element_id == interface.id
101
+ assert log.element_name == interface.name
102
+ assert log.username == "test_user"
103
+
97
104
  def test_edit(self, test_app, interface_test_data, dbsession):
98
- from c2cgeoportal_commons.models.main import Interface
105
+ from c2cgeoportal_commons.models.main import Interface, Log, LogAction
99
106
 
100
107
  interface = interface_test_data["interfaces"][0]
101
108
  descriptions = "{}, {}".format(
102
109
  interface_test_data["interfaces"][0].description, interface_test_data["interfaces"][1].description
103
110
  )
104
- resp = test_app.get("/admin/interfaces/{}".format(interface.id), status=200)
111
+ resp = test_app.get(f"/admin/interfaces/{interface.id}", status=200)
105
112
  form = resp.form
106
113
  form["description"] = descriptions
107
114
  assert str(interface.id) == self.get_first_field_named(form, "id").value
@@ -110,16 +117,32 @@ class TestInterface(AbstractViewsTests):
110
117
  assert form.submit().status_int == 302
111
118
  assert len(dbsession.query(Interface).filter(Interface.description == descriptions).all()) == 1
112
119
 
120
+ log = dbsession.query(Log).one()
121
+ assert log.date != None
122
+ assert log.action == LogAction.UPDATE
123
+ assert log.element_type == "interface"
124
+ assert log.element_id == interface.id
125
+ assert log.element_name == interface.name
126
+ assert log.username == "test_user"
127
+
113
128
  def test_delete(self, test_app, interface_test_data, dbsession):
114
- from c2cgeoportal_commons.models.main import Interface
129
+ from c2cgeoportal_commons.models.main import Interface, Log, LogAction
115
130
 
116
131
  interface = interface_test_data["interfaces"][0]
117
- test_app.delete("/admin/interfaces/{}".format(interface.id), status=200)
132
+ test_app.delete(f"/admin/interfaces/{interface.id}", status=200)
118
133
  assert len(dbsession.query(Interface).filter(Interface.id == interface.id).all()) == 0
119
134
 
135
+ log = dbsession.query(Log).one()
136
+ assert log.date != None
137
+ assert log.action == LogAction.DELETE
138
+ assert log.element_type == "interface"
139
+ assert log.element_id == interface.id
140
+ assert log.element_name == interface.name
141
+ assert log.username == "test_user"
142
+
120
143
  def test_duplicate(self, interface_test_data, test_app):
121
144
  interface = interface_test_data["interfaces"][3]
122
- resp = test_app.get("/admin/interfaces/{}/duplicate".format(interface.id), status=200)
145
+ resp = test_app.get(f"/admin/interfaces/{interface.id}/duplicate", status=200)
123
146
  form = resp.form
124
147
  assert "" == self.get_first_field_named(form, "id").value
125
148
  assert str(interface.description or "") == "description_3"
@@ -12,7 +12,7 @@ from .test_treegroup import TestTreeGroup
12
12
  def layer_groups_test_data(dbsession, transact):
13
13
  del transact
14
14
 
15
- from c2cgeoportal_commons.models.main import LayerGroup, Metadata, LayergroupTreeitem
15
+ from c2cgeoportal_commons.models.main import LayerGroup, LayergroupTreeitem, Metadata
16
16
 
17
17
  metadatas_protos = [
18
18
  ("copyable", "true"),
@@ -22,7 +22,7 @@ def layer_groups_test_data(dbsession, transact):
22
22
 
23
23
  groups = []
24
24
  for i in range(0, 12):
25
- group = LayerGroup(name="groups_{num:02d}".format(num=i), is_expanded=False)
25
+ group = LayerGroup(name=f"groups_{i:02d}")
26
26
  group.metadatas = [
27
27
  Metadata(name=metadatas_protos[id][0], value=metadatas_protos[id][1])
28
28
  for id in [i % 3, (i + 2) % 3]
@@ -60,7 +60,6 @@ def layer_groups_test_data(dbsession, transact):
60
60
 
61
61
  @pytest.mark.usefixtures("layer_groups_test_data", "test_app")
62
62
  class TestLayersGroups(TestTreeGroup):
63
-
64
63
  _prefix = "/admin/layer_groups"
65
64
 
66
65
  def test_index_rendering(self, test_app):
@@ -73,7 +72,6 @@ class TestLayersGroups(TestTreeGroup):
73
72
  ("id", "id", "true"),
74
73
  ("name", "Name"),
75
74
  ("description", "Description"),
76
- ("is_expanded", "Expanded"),
77
75
  ("parents_relation", "Parents", "false"),
78
76
  ("metadatas", "Metadatas", "false"),
79
77
  ]
@@ -90,15 +88,13 @@ class TestLayersGroups(TestTreeGroup):
90
88
  assert "groups_02, groups_06" == row["parents_relation"]
91
89
  assert "disclaimer: © le momo, copyable: true" == row["metadatas"]
92
90
 
93
- @pytest.mark.skip(reason="use value to be defined")
94
- def test_grid_filter_on_parents(self, test_app):
95
- self.check_search(test_app, "groups_11", total=4)
96
-
97
91
  def test_grid_search(self, test_app):
98
92
  # search on metadatas
99
93
  self.check_search(test_app, "copyable", total=8)
100
94
 
101
95
  def test_edit(self, test_app, layer_groups_test_data, dbsession):
96
+ from c2cgeoportal_commons.models.main import Log, LogAction
97
+
102
98
  group = layer_groups_test_data["groups"][1]
103
99
 
104
100
  form = self.get_item(test_app, group.id).form
@@ -107,8 +103,6 @@ class TestLayersGroups(TestTreeGroup):
107
103
  assert "hidden" == self.get_first_field_named(form, "id").attrs["type"]
108
104
  assert group.name == self.get_first_field_named(form, "name").value
109
105
  assert str(group.description or "") == self.get_first_field_named(form, "description").value
110
- assert group.is_expanded is False
111
- assert group.is_expanded == form["is_expanded"].checked
112
106
 
113
107
  self.check_children(
114
108
  form,
@@ -125,7 +119,6 @@ class TestLayersGroups(TestTreeGroup):
125
119
  new_values = {
126
120
  "name": "new_name",
127
121
  "description": "new description",
128
- "is_expanded": True,
129
122
  }
130
123
  for key, value in new_values.items():
131
124
  self.set_first_field_named(form, key, value)
@@ -142,13 +135,21 @@ class TestLayersGroups(TestTreeGroup):
142
135
  else:
143
136
  assert str(value or "") == str(getattr(group, key) or "")
144
137
 
138
+ log = dbsession.query(Log).one()
139
+ assert log.date != None
140
+ assert log.action == LogAction.UPDATE
141
+ assert log.element_type == "layergroup"
142
+ assert log.element_id == group.id
143
+ assert log.element_name == group.name
144
+ assert log.username == "test_user"
145
+
145
146
  def test_post_new_with_children_invalid(self, test_app, layer_groups_test_data):
146
147
  """
147
148
  Check there is no rendering error when validation fails.
148
149
  """
149
150
  groups = layer_groups_test_data["groups"]
150
151
  resp = test_app.post(
151
- "{}/new".format(self._prefix),
152
+ f"{self._prefix}/new",
152
153
  (
153
154
  ("_charset_", "UTF-8"),
154
155
  ("__formid__", "deform"),
@@ -167,9 +168,11 @@ class TestLayersGroups(TestTreeGroup):
167
168
  assert "Required" == resp.html.select_one(".item-name .help-block").getText().strip()
168
169
 
169
170
  def test_post_new_with_children_success(self, test_app, dbsession, layer_groups_test_data):
171
+ from c2cgeoportal_commons.models.main import Log, LogAction
172
+
170
173
  groups = layer_groups_test_data["groups"]
171
174
  resp = test_app.post(
172
- "{}/new".format(self._prefix),
175
+ f"{self._prefix}/new",
173
176
  (
174
177
  ("_charset_", "UTF-8"),
175
178
  ("__formid__", "deform"),
@@ -210,11 +213,21 @@ class TestLayersGroups(TestTreeGroup):
210
213
  rel.treeitem_id for rel in group.children_relation
211
214
  ]
212
215
 
216
+ log = dbsession.query(Log).one()
217
+ assert log.date != None
218
+ assert log.action == LogAction.INSERT
219
+ assert log.element_type == "layergroup"
220
+ assert log.element_id == group.id
221
+ assert log.element_name == group.name
222
+ assert log.username == "test_user"
223
+
213
224
  def test_post_with_ancestor(self, layer_groups_test_data, test_app):
214
- """Check that ancestors are refused to avoid cycles"""
225
+ """
226
+ Check that ancestors are refused to avoid cycles.
227
+ """
215
228
  groups = layer_groups_test_data["groups"]
216
229
  resp = test_app.post(
217
- "{}/{}".format(self._prefix, groups[3].id),
230
+ f"{self._prefix}/{groups[3].id}",
218
231
  (
219
232
  ("_charset_", "UTF-8"),
220
233
  ("__formid__", "deform"),
@@ -232,7 +245,7 @@ class TestLayersGroups(TestTreeGroup):
232
245
  status=200,
233
246
  )
234
247
  assert (
235
- "Value {} does not exist in table treeitem or is not allowed to avoid cycles".format(groups[1].id)
248
+ f"Value {groups[1].id} does not exist in table treeitem or is not allowed to avoid cycles"
236
249
  == resp.html.select_one(".item-children_relation + .help-block").getText().strip()
237
250
  )
238
251
 
@@ -241,7 +254,7 @@ class TestLayersGroups(TestTreeGroup):
241
254
 
242
255
  group = layer_groups_test_data["groups"][1]
243
256
 
244
- resp = test_app.get("{}/{}/duplicate".format(self._prefix, group.id), status=200)
257
+ resp = test_app.get(f"{self._prefix}/{group.id}/duplicate", status=200)
245
258
  form = resp.form
246
259
 
247
260
  group = dbsession.query(LayerGroup).filter(LayerGroup.id == group.id).one()
@@ -249,8 +262,6 @@ class TestLayersGroups(TestTreeGroup):
249
262
  assert "" == self.get_first_field_named(form, "id").value
250
263
  assert group.name == self.get_first_field_named(form, "name").value
251
264
  assert str(group.description or "") == self.get_first_field_named(form, "description").value
252
- assert group.is_expanded is False
253
- assert group.is_expanded == form["is_expanded"].checked
254
265
 
255
266
  self.check_children(
256
267
  form,
@@ -267,7 +278,7 @@ class TestLayersGroups(TestTreeGroup):
267
278
  duplicated = dbsession.query(LayerGroup).filter(LayerGroup.name == "duplicated").one()
268
279
 
269
280
  assert str(duplicated.id) == re.match(
270
- r"http://localhost{}/(.*)\?msg_col=submit_ok".format(self._prefix), resp.location
281
+ rf"http://localhost{self._prefix}/(.*)\?msg_col=submit_ok", resp.location
271
282
  ).group(1)
272
283
  assert duplicated.id != group.id
273
284
  assert duplicated.children_relation[0].id != group.children_relation[0].id
@@ -275,41 +286,56 @@ class TestLayersGroups(TestTreeGroup):
275
286
 
276
287
  def test_unicity_validator(self, layer_groups_test_data, test_app):
277
288
  group = layer_groups_test_data["groups"][1]
278
- resp = test_app.get("{}/{}/duplicate".format(self._prefix, group.id), status=200)
289
+ resp = test_app.get(f"{self._prefix}/{group.id}/duplicate", status=200)
279
290
 
280
291
  resp = resp.form.submit("submit")
281
292
 
282
- self._check_submission_problem(resp, "{} is already used.".format(group.name))
293
+ self._check_submission_problem(resp, f"{group.name} is already used.")
283
294
 
284
295
  def test_delete(self, test_app, dbsession, layer_groups_test_data):
285
- from c2cgeoportal_commons.models.main import LayerGroup, TreeGroup, TreeItem, LayergroupTreeitem
296
+ from c2cgeoportal_commons.models.main import (
297
+ LayerGroup,
298
+ LayergroupTreeitem,
299
+ Log,
300
+ LogAction,
301
+ TreeGroup,
302
+ TreeItem,
303
+ )
286
304
 
287
- group_id = layer_groups_test_data["groups"][9].id
305
+ group = layer_groups_test_data["groups"][9]
288
306
 
289
307
  assert (
290
308
  3
291
- == dbsession.query(LayergroupTreeitem).filter(LayergroupTreeitem.treegroup_id == group_id).count()
309
+ == dbsession.query(LayergroupTreeitem).filter(LayergroupTreeitem.treegroup_id == group.id).count()
292
310
  )
293
311
 
294
312
  assert (
295
313
  1
296
- == dbsession.query(LayergroupTreeitem).filter(LayergroupTreeitem.treeitem_id == group_id).count()
314
+ == dbsession.query(LayergroupTreeitem).filter(LayergroupTreeitem.treeitem_id == group.id).count()
297
315
  )
298
316
 
299
- test_app.delete("/admin/layer_groups/{}".format(group_id), status=200)
317
+ test_app.delete(f"/admin/layer_groups/{group.id}", status=200)
300
318
 
301
319
  dbsession.expire_all()
302
320
 
303
- assert dbsession.query(LayerGroup).get(group_id) is None
304
- assert dbsession.query(TreeGroup).get(group_id) is None
305
- assert dbsession.query(TreeItem).get(group_id) is None
321
+ assert dbsession.query(LayerGroup).get(group.id) is None
322
+ assert dbsession.query(TreeGroup).get(group.id) is None
323
+ assert dbsession.query(TreeItem).get(group.id) is None
306
324
 
307
325
  assert (
308
326
  0
309
- == dbsession.query(LayergroupTreeitem).filter(LayergroupTreeitem.treegroup_id == group_id).count()
327
+ == dbsession.query(LayergroupTreeitem).filter(LayergroupTreeitem.treegroup_id == group.id).count()
310
328
  )
311
329
 
312
330
  assert (
313
331
  0
314
- == dbsession.query(LayergroupTreeitem).filter(LayergroupTreeitem.treeitem_id == group_id).count()
332
+ == dbsession.query(LayergroupTreeitem).filter(LayergroupTreeitem.treeitem_id == group.id).count()
315
333
  )
334
+
335
+ log = dbsession.query(Log).one()
336
+ assert log.date != None
337
+ assert log.action == LogAction.DELETE
338
+ assert log.element_type == "layergroup"
339
+ assert log.element_id == group.id
340
+ assert log.element_name == group.name
341
+ assert log.username == "test_user"
@@ -0,0 +1,243 @@
1
+ # pylint: disable=no-self-use
2
+
3
+ import re
4
+ from typing import Any
5
+
6
+ import pytest
7
+ from sqlalchemy.orm import Session, SessionTransaction
8
+ from webtest import TestApp as WebTestApp # Avoid warning with pytest
9
+
10
+ from . import AbstractViewsTests, factory_build_layers, get_test_default_layers
11
+
12
+
13
+ @pytest.fixture(scope="function")
14
+ @pytest.mark.usefixtures("dbsession", "transact")
15
+ def layer_cog_test_data(dbsession: Session, transact: SessionTransaction) -> dict[str, Any]:
16
+ del transact
17
+
18
+ from c2cgeoportal_commons.models.main import LayerCOG
19
+
20
+ def layer_builder(i: int) -> LayerCOG:
21
+ name = f"layer_cog_{i}"
22
+ layer = LayerCOG(name=name)
23
+ layer.public = 1 == i % 2
24
+ layer.url = "https://example.com/image.tiff"
25
+ return layer
26
+
27
+ data = factory_build_layers(layer_builder, dbsession, add_dimension=False)
28
+ data["default"] = get_test_default_layers(dbsession, None)
29
+
30
+ dbsession.flush()
31
+
32
+ yield data
33
+
34
+
35
+ @pytest.mark.usefixtures("layer_cog_test_data", "test_app")
36
+ class TestLayerVectortiles(AbstractViewsTests):
37
+ _prefix = "/admin/layers_cog"
38
+
39
+ def test_index_rendering(self, test_app: WebTestApp) -> None:
40
+ resp = self.get(test_app)
41
+
42
+ self.check_left_menu(resp, "COG Layers")
43
+
44
+ expected = [
45
+ ("actions", "", "false"),
46
+ ("id", "id", "true"),
47
+ ("name", "Name"),
48
+ ("description", "Description"),
49
+ ("public", "Public"),
50
+ ("geo_table", "Geo table"),
51
+ ("exclude_properties", "Exclude properties"),
52
+ ("url", "URL"),
53
+ ("interfaces", "Interfaces"),
54
+ ("restrictionareas", "Restriction areas", "false"),
55
+ ("parents_relation", "Parents", "false"),
56
+ ("metadatas", "Metadatas", "false"),
57
+ ]
58
+ self.check_grid_headers(resp, expected)
59
+
60
+ def test_grid_complex_column_val(self, test_app: WebTestApp, layer_cog_test_data: dict[str, Any]) -> None:
61
+ json = self.check_search(test_app, search="layer", sort="name")
62
+
63
+ row = json["rows"][0]
64
+ layer = layer_cog_test_data["layers"][0]
65
+
66
+ assert layer.name == row["name"]
67
+ assert layer.id == int(row["_id_"])
68
+
69
+ def test_new(self, test_app: WebTestApp, layer_cog_test_data: dict[str, Any], dbsession: Session) -> None:
70
+ default_cog = layer_cog_test_data["default"]["cog"]
71
+ default_cog.name = "so can I not be found"
72
+ dbsession.flush()
73
+
74
+ form = self.get_item(test_app, "new").form
75
+
76
+ assert "" == self.get_first_field_named(form, "name").value
77
+ assert "" == self.get_first_field_named(form, "id").value
78
+ assert "" == self.get_first_field_named(form, "url").value
79
+
80
+ def test_grid_search(self, test_app: WebTestApp) -> None:
81
+ self.check_search(test_app, "layer_cog_10", total=1)
82
+
83
+ def test_base_edit(self, test_app: WebTestApp, layer_cog_test_data: dict[str, Any]) -> None:
84
+ layer = layer_cog_test_data["layers"][10]
85
+
86
+ form = self.get_item(test_app, layer.id).form
87
+
88
+ assert "layer_cog_10" == self.get_first_field_named(form, "name").value
89
+ assert "" == self.get_first_field_named(form, "description").value
90
+
91
+ def test_public_checkbox_edit(self, test_app: WebTestApp, layer_cog_test_data: dict[str, Any]) -> None:
92
+ layer = layer_cog_test_data["layers"][10]
93
+ form = self.get_item(test_app, layer.id).form
94
+ assert not form["public"].checked
95
+
96
+ layer = layer_cog_test_data["layers"][11]
97
+ form = self.get_item(test_app, layer.id).form
98
+ assert form["public"].checked
99
+
100
+ def test_edit(
101
+ self, test_app: WebTestApp, layer_cog_test_data: dict[str, Any], dbsession: Session
102
+ ) -> None:
103
+ from c2cgeoportal_commons.models.main import Log, LogAction
104
+
105
+ layer = layer_cog_test_data["layers"][0]
106
+
107
+ form = self.get_item(test_app, layer.id).form
108
+
109
+ assert str(layer.id) == self.get_first_field_named(form, "id").value
110
+ assert "hidden" == self.get_first_field_named(form, "id").attrs["type"]
111
+ assert layer.name == self.get_first_field_named(form, "name").value
112
+ assert str(layer.description or "") == self.get_first_field_named(form, "description").value
113
+ assert layer.public is False
114
+ assert layer.public == form["public"].checked
115
+ assert str(layer.geo_table or "") == form["geo_table"].value
116
+ assert str(layer.exclude_properties or "") == form["exclude_properties"].value
117
+ # assert str(layer.url or "") == form["url"].value
118
+
119
+ interfaces = layer_cog_test_data["interfaces"]
120
+ assert {interfaces[0].id, interfaces[2].id} == {i.id for i in layer.interfaces}
121
+ self._check_interfaces(form, interfaces, layer)
122
+
123
+ ras = layer_cog_test_data["restrictionareas"]
124
+ assert {ras[0].id, ras[2].id} == {i.id for i in layer.restrictionareas}
125
+ self._check_restrictionsareas(form, ras, layer)
126
+
127
+ new_values = {
128
+ "name": "new_name",
129
+ "description": "new description",
130
+ "public": True,
131
+ "geo_table": "new_geo_table",
132
+ "exclude_properties": "property1,property2",
133
+ "url": "https://example.com/image.tiff",
134
+ }
135
+
136
+ for key, value in new_values.items():
137
+ self.set_first_field_named(form, key, value)
138
+ form["interfaces"] = [interfaces[1].id, interfaces[3].id]
139
+ form["restrictionareas"] = [ras[1].id, ras[3].id]
140
+
141
+ resp = form.submit("submit")
142
+ assert str(layer.id) == re.match(
143
+ rf"http://localhost{self._prefix}/(.*)\?msg_col=submit_ok", resp.location
144
+ ).group(1)
145
+
146
+ dbsession.expire(layer)
147
+ for key, value in new_values.items():
148
+ if isinstance(value, bool):
149
+ assert value == getattr(layer, key)
150
+ else:
151
+ assert str(value or "") == str(getattr(layer, key) or "")
152
+ assert {interfaces[1].id, interfaces[3].id} == {interface.id for interface in layer.interfaces}
153
+ assert {ras[1].id, ras[3].id} == {ra.id for ra in layer.restrictionareas}
154
+
155
+ log = dbsession.query(Log).one()
156
+ assert log.date != None
157
+ assert log.action == LogAction.UPDATE
158
+ assert log.element_type == "layer_cog"
159
+ assert log.element_id == layer.id
160
+ assert log.element_name == layer.name
161
+ assert log.username == "test_user"
162
+
163
+ def test_submit_new(
164
+ self, dbsession: Session, test_app: WebTestApp, layer_cog_test_data: dict[str, Any]
165
+ ) -> None:
166
+ from c2cgeoportal_commons.models.main import LayerCOG, Log, LogAction
167
+
168
+ resp = test_app.post(
169
+ "/admin/layers_cog/new",
170
+ {
171
+ "name": "new_name",
172
+ "description": "new description",
173
+ "public": True,
174
+ "url": "https://example.com/image.tiff",
175
+ },
176
+ status=302,
177
+ )
178
+
179
+ layer = dbsession.query(LayerCOG).filter(LayerCOG.name == "new_name").one()
180
+ assert str(layer.id) == re.match(
181
+ r"http://localhost/admin/layers_cog/(.*)\?msg_col=submit_ok", resp.location
182
+ ).group(1)
183
+
184
+ log = dbsession.query(Log).one()
185
+ assert log.date != None
186
+ assert log.action == LogAction.INSERT
187
+ assert log.element_type == "layer_cog"
188
+ assert log.element_id == layer.id
189
+ assert log.element_name == layer.name
190
+ assert log.username == "test_user"
191
+
192
+ def test_duplicate(
193
+ self, layer_cog_test_data: dict[str, Any], test_app: WebTestApp, dbsession: Session
194
+ ) -> None:
195
+ from c2cgeoportal_commons.models.main import LayerCOG
196
+
197
+ layer = layer_cog_test_data["layers"][3]
198
+
199
+ resp = test_app.get(f"/admin/layers_cog/{layer.id}/duplicate", status=200)
200
+ form = resp.form
201
+
202
+ assert "" == self.get_first_field_named(form, "id").value
203
+ assert layer.name == self.get_first_field_named(form, "name").value
204
+ assert str(layer.description or "") == self.get_first_field_named(form, "description").value
205
+ assert layer.public is True
206
+ assert layer.public == form["public"].checked
207
+ assert str(layer.geo_table or "") == form["geo_table"].value
208
+ assert str(layer.exclude_properties or "") == form["exclude_properties"].value
209
+ # assert str(layer.url or "") == form["url"].value
210
+ interfaces = layer_cog_test_data["interfaces"]
211
+ assert {interfaces[3].id, interfaces[1].id} == {i.id for i in layer.interfaces}
212
+ self._check_interfaces(form, interfaces, layer)
213
+
214
+ self.set_first_field_named(form, "name", "clone")
215
+ resp = form.submit("submit")
216
+
217
+ layer = dbsession.query(LayerCOG).filter(LayerCOG.name == "clone").one()
218
+ assert str(layer.id) == re.match(
219
+ r"http://localhost/admin/layers_cog/(.*)\?msg_col=submit_ok", resp.location
220
+ ).group(1)
221
+
222
+ assert layer.id == layer.metadatas[0].item_id
223
+ assert layer_cog_test_data["layers"][3].metadatas[0].name == layer.metadatas[0].name
224
+ assert layer_cog_test_data["layers"][3].metadatas[1].name == layer.metadatas[1].name
225
+
226
+ def test_delete(self, test_app: WebTestApp, dbsession: Session) -> None:
227
+ from c2cgeoportal_commons.models.main import Layer, LayerCOG, Log, LogAction, TreeItem
228
+
229
+ layer = dbsession.query(LayerCOG).first()
230
+
231
+ test_app.delete(f"/admin/layers_cog/{layer.id}", status=200)
232
+
233
+ assert dbsession.query(LayerCOG).get(layer.id) is None
234
+ assert dbsession.query(Layer).get(layer.id) is None
235
+ assert dbsession.query(TreeItem).get(layer.id) is None
236
+
237
+ log = dbsession.query(Log).one()
238
+ assert log.date != None
239
+ assert log.action == LogAction.DELETE
240
+ assert log.element_type == "layer_cog"
241
+ assert log.element_id == layer.id
242
+ assert log.element_name == layer.name
243
+ assert log.username == "test_user"