c2cgeoportal-admin 2.6.0__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 (80) hide show
  1. c2cgeoportal_admin/__init__.py +42 -12
  2. c2cgeoportal_admin/lib/lingva_extractor.py +77 -0
  3. c2cgeoportal_admin/lib/ogcserver_synchronizer.py +170 -57
  4. c2cgeoportal_admin/py.typed +0 -0
  5. c2cgeoportal_admin/routes.py +18 -6
  6. c2cgeoportal_admin/schemas/dimensions.py +16 -10
  7. c2cgeoportal_admin/schemas/functionalities.py +59 -21
  8. c2cgeoportal_admin/schemas/interfaces.py +26 -18
  9. c2cgeoportal_admin/schemas/metadata.py +101 -48
  10. c2cgeoportal_admin/schemas/restriction_areas.py +25 -19
  11. c2cgeoportal_admin/schemas/roles.py +12 -6
  12. c2cgeoportal_admin/schemas/treegroup.py +46 -21
  13. c2cgeoportal_admin/schemas/treeitem.py +3 -4
  14. c2cgeoportal_admin/static/layertree.css +3 -4
  15. c2cgeoportal_admin/static/navbar.css +36 -35
  16. c2cgeoportal_admin/static/theme.css +19 -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 +14 -9
  26. c2cgeoportal_admin/views/functionalities.py +52 -18
  27. c2cgeoportal_admin/views/home.py +5 -5
  28. c2cgeoportal_admin/views/interfaces.py +26 -20
  29. c2cgeoportal_admin/views/layer_groups.py +36 -25
  30. c2cgeoportal_admin/views/layers.py +17 -13
  31. c2cgeoportal_admin/views/layers_cog.py +135 -0
  32. c2cgeoportal_admin/views/layers_vectortiles.py +62 -27
  33. c2cgeoportal_admin/views/layers_wms.py +55 -34
  34. c2cgeoportal_admin/views/layers_wmts.py +54 -34
  35. c2cgeoportal_admin/views/layertree.py +38 -29
  36. c2cgeoportal_admin/views/logged_views.py +83 -0
  37. c2cgeoportal_admin/views/logs.py +91 -0
  38. c2cgeoportal_admin/views/oauth2_clients.py +30 -18
  39. c2cgeoportal_admin/views/ogc_servers.py +132 -36
  40. c2cgeoportal_admin/views/restriction_areas.py +39 -27
  41. c2cgeoportal_admin/views/roles.py +42 -28
  42. c2cgeoportal_admin/views/themes.py +47 -35
  43. c2cgeoportal_admin/views/themes_ordering.py +19 -14
  44. c2cgeoportal_admin/views/treeitems.py +21 -17
  45. c2cgeoportal_admin/views/users.py +46 -26
  46. c2cgeoportal_admin/widgets.py +17 -14
  47. {c2cgeoportal_admin-2.6.0.dist-info → c2cgeoportal_admin-2.9rc44.dist-info}/METADATA +12 -12
  48. c2cgeoportal_admin-2.9rc44.dist-info/RECORD +97 -0
  49. {c2cgeoportal_admin-2.6.0.dist-info → c2cgeoportal_admin-2.9rc44.dist-info}/WHEEL +1 -1
  50. c2cgeoportal_admin-2.9rc44.dist-info/entry_points.txt +5 -0
  51. tests/__init__.py +24 -20
  52. tests/conftest.py +22 -11
  53. tests/test_edit_url.py +11 -14
  54. tests/test_functionalities.py +52 -14
  55. tests/test_home.py +0 -1
  56. tests/test_interface.py +34 -11
  57. tests/test_layer_groups.py +57 -27
  58. tests/test_layers_cog.py +243 -0
  59. tests/test_layers_vectortiles.py +43 -25
  60. tests/test_layers_wms.py +67 -45
  61. tests/test_layers_wmts.py +47 -26
  62. tests/test_layertree.py +99 -16
  63. tests/test_left_menu.py +0 -1
  64. tests/test_lingva_extractor_config.py +64 -0
  65. tests/test_logs.py +102 -0
  66. tests/test_main.py +3 -1
  67. tests/test_metadatas.py +34 -21
  68. tests/test_oauth2_clients.py +40 -11
  69. tests/test_ogc_servers.py +84 -35
  70. tests/test_restriction_areas.py +38 -15
  71. tests/test_role.py +71 -43
  72. tests/test_themes.py +71 -37
  73. tests/test_themes_ordering.py +1 -2
  74. tests/test_treegroup.py +2 -2
  75. tests/test_user.py +56 -19
  76. tests/themes_ordering.py +1 -2
  77. c2cgeoportal_admin/templates/navigation_vertical.jinja2 +0 -33
  78. c2cgeoportal_admin-2.6.0.dist-info/RECORD +0 -89
  79. c2cgeoportal_admin-2.6.0.dist-info/entry_points.txt +0 -3
  80. {c2cgeoportal_admin-2.6.0.dist-info → c2cgeoportal_admin-2.9rc44.dist-info}/top_level.txt +0 -0
tests/test_interface.py CHANGED
@@ -16,14 +16,14 @@ def interface_test_data(dbsession, transact):
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"
@@ -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
  ]
@@ -95,6 +93,8 @@ class TestLayersGroups(TestTreeGroup):
95
93
  self.check_search(test_app, "copyable", total=8)
96
94
 
97
95
  def test_edit(self, test_app, layer_groups_test_data, dbsession):
96
+ from c2cgeoportal_commons.models.main import Log, LogAction
97
+
98
98
  group = layer_groups_test_data["groups"][1]
99
99
 
100
100
  form = self.get_item(test_app, group.id).form
@@ -103,8 +103,6 @@ class TestLayersGroups(TestTreeGroup):
103
103
  assert "hidden" == self.get_first_field_named(form, "id").attrs["type"]
104
104
  assert group.name == self.get_first_field_named(form, "name").value
105
105
  assert str(group.description or "") == self.get_first_field_named(form, "description").value
106
- assert group.is_expanded is False
107
- assert group.is_expanded == form["is_expanded"].checked
108
106
 
109
107
  self.check_children(
110
108
  form,
@@ -121,7 +119,6 @@ class TestLayersGroups(TestTreeGroup):
121
119
  new_values = {
122
120
  "name": "new_name",
123
121
  "description": "new description",
124
- "is_expanded": True,
125
122
  }
126
123
  for key, value in new_values.items():
127
124
  self.set_first_field_named(form, key, value)
@@ -138,13 +135,21 @@ class TestLayersGroups(TestTreeGroup):
138
135
  else:
139
136
  assert str(value or "") == str(getattr(group, key) or "")
140
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
+
141
146
  def test_post_new_with_children_invalid(self, test_app, layer_groups_test_data):
142
147
  """
143
148
  Check there is no rendering error when validation fails.
144
149
  """
145
150
  groups = layer_groups_test_data["groups"]
146
151
  resp = test_app.post(
147
- "{}/new".format(self._prefix),
152
+ f"{self._prefix}/new",
148
153
  (
149
154
  ("_charset_", "UTF-8"),
150
155
  ("__formid__", "deform"),
@@ -163,9 +168,11 @@ class TestLayersGroups(TestTreeGroup):
163
168
  assert "Required" == resp.html.select_one(".item-name .help-block").getText().strip()
164
169
 
165
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
+
166
173
  groups = layer_groups_test_data["groups"]
167
174
  resp = test_app.post(
168
- "{}/new".format(self._prefix),
175
+ f"{self._prefix}/new",
169
176
  (
170
177
  ("_charset_", "UTF-8"),
171
178
  ("__formid__", "deform"),
@@ -206,11 +213,21 @@ class TestLayersGroups(TestTreeGroup):
206
213
  rel.treeitem_id for rel in group.children_relation
207
214
  ]
208
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
+
209
224
  def test_post_with_ancestor(self, layer_groups_test_data, test_app):
210
- """Check that ancestors are refused to avoid cycles"""
225
+ """
226
+ Check that ancestors are refused to avoid cycles.
227
+ """
211
228
  groups = layer_groups_test_data["groups"]
212
229
  resp = test_app.post(
213
- "{}/{}".format(self._prefix, groups[3].id),
230
+ f"{self._prefix}/{groups[3].id}",
214
231
  (
215
232
  ("_charset_", "UTF-8"),
216
233
  ("__formid__", "deform"),
@@ -228,7 +245,7 @@ class TestLayersGroups(TestTreeGroup):
228
245
  status=200,
229
246
  )
230
247
  assert (
231
- "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"
232
249
  == resp.html.select_one(".item-children_relation + .help-block").getText().strip()
233
250
  )
234
251
 
@@ -237,7 +254,7 @@ class TestLayersGroups(TestTreeGroup):
237
254
 
238
255
  group = layer_groups_test_data["groups"][1]
239
256
 
240
- 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)
241
258
  form = resp.form
242
259
 
243
260
  group = dbsession.query(LayerGroup).filter(LayerGroup.id == group.id).one()
@@ -245,8 +262,6 @@ class TestLayersGroups(TestTreeGroup):
245
262
  assert "" == self.get_first_field_named(form, "id").value
246
263
  assert group.name == self.get_first_field_named(form, "name").value
247
264
  assert str(group.description or "") == self.get_first_field_named(form, "description").value
248
- assert group.is_expanded is False
249
- assert group.is_expanded == form["is_expanded"].checked
250
265
 
251
266
  self.check_children(
252
267
  form,
@@ -263,7 +278,7 @@ class TestLayersGroups(TestTreeGroup):
263
278
  duplicated = dbsession.query(LayerGroup).filter(LayerGroup.name == "duplicated").one()
264
279
 
265
280
  assert str(duplicated.id) == re.match(
266
- r"http://localhost{}/(.*)\?msg_col=submit_ok".format(self._prefix), resp.location
281
+ rf"http://localhost{self._prefix}/(.*)\?msg_col=submit_ok", resp.location
267
282
  ).group(1)
268
283
  assert duplicated.id != group.id
269
284
  assert duplicated.children_relation[0].id != group.children_relation[0].id
@@ -271,41 +286,56 @@ class TestLayersGroups(TestTreeGroup):
271
286
 
272
287
  def test_unicity_validator(self, layer_groups_test_data, test_app):
273
288
  group = layer_groups_test_data["groups"][1]
274
- 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)
275
290
 
276
291
  resp = resp.form.submit("submit")
277
292
 
278
- self._check_submission_problem(resp, "{} is already used.".format(group.name))
293
+ self._check_submission_problem(resp, f"{group.name} is already used.")
279
294
 
280
295
  def test_delete(self, test_app, dbsession, layer_groups_test_data):
281
- from c2cgeoportal_commons.models.main import LayerGroup, LayergroupTreeitem, TreeGroup, TreeItem
296
+ from c2cgeoportal_commons.models.main import (
297
+ LayerGroup,
298
+ LayergroupTreeitem,
299
+ Log,
300
+ LogAction,
301
+ TreeGroup,
302
+ TreeItem,
303
+ )
282
304
 
283
- group_id = layer_groups_test_data["groups"][9].id
305
+ group = layer_groups_test_data["groups"][9]
284
306
 
285
307
  assert (
286
308
  3
287
- == dbsession.query(LayergroupTreeitem).filter(LayergroupTreeitem.treegroup_id == group_id).count()
309
+ == dbsession.query(LayergroupTreeitem).filter(LayergroupTreeitem.treegroup_id == group.id).count()
288
310
  )
289
311
 
290
312
  assert (
291
313
  1
292
- == dbsession.query(LayergroupTreeitem).filter(LayergroupTreeitem.treeitem_id == group_id).count()
314
+ == dbsession.query(LayergroupTreeitem).filter(LayergroupTreeitem.treeitem_id == group.id).count()
293
315
  )
294
316
 
295
- test_app.delete("/admin/layer_groups/{}".format(group_id), status=200)
317
+ test_app.delete(f"/admin/layer_groups/{group.id}", status=200)
296
318
 
297
319
  dbsession.expire_all()
298
320
 
299
- assert dbsession.query(LayerGroup).get(group_id) is None
300
- assert dbsession.query(TreeGroup).get(group_id) is None
301
- 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
302
324
 
303
325
  assert (
304
326
  0
305
- == dbsession.query(LayergroupTreeitem).filter(LayergroupTreeitem.treegroup_id == group_id).count()
327
+ == dbsession.query(LayergroupTreeitem).filter(LayergroupTreeitem.treegroup_id == group.id).count()
306
328
  )
307
329
 
308
330
  assert (
309
331
  0
310
- == dbsession.query(LayergroupTreeitem).filter(LayergroupTreeitem.treeitem_id == group_id).count()
332
+ == dbsession.query(LayergroupTreeitem).filter(LayergroupTreeitem.treeitem_id == group.id).count()
311
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"