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_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):
@@ -0,0 +1,64 @@
1
+ # Copyright (c) 2022-2024, Camptocamp SA
2
+ # All rights reserved.
3
+
4
+ # Redistribution and use in source and binary forms, with or without
5
+ # modification, are permitted provided that the following conditions are met:
6
+
7
+ # 1. Redistributions of source code must retain the above copyright notice, this
8
+ # list of conditions and the following disclaimer.
9
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
10
+ # this list of conditions and the following disclaimer in the documentation
11
+ # and/or other materials provided with the distribution.
12
+
13
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
14
+ # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15
+ # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
17
+ # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18
+ # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19
+ # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20
+ # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21
+ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22
+ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23
+
24
+ # The views and conclusions contained in the software and documentation are those
25
+ # of the authors and should not be interpreted as representing official policies,
26
+ # either expressed or implied, of the FreeBSD Project.
27
+
28
+ # pylint: disable=missing-docstring
29
+
30
+ from unittest.mock import Mock, mock_open, patch
31
+
32
+ import pytest
33
+ import yaml
34
+ from c2c.template.config import config as configuration
35
+
36
+ from c2cgeoportal_admin.lib.lingva_extractor import GeomapfishConfigExtractor
37
+
38
+ GMF_CONFIG = """
39
+ vars:
40
+ admin_interface:
41
+ available_metadata:
42
+ - name: metadata1
43
+ description: description1
44
+ translate: true
45
+ available_functionalities:
46
+ - name: functionality1
47
+ description: description2
48
+ """
49
+
50
+
51
+ class TestGeomapfishConfigExtractor:
52
+ @patch(
53
+ "c2cgeoportal_admin.lib.lingva_extractor.open",
54
+ mock_open(read_data=GMF_CONFIG),
55
+ )
56
+ def test_extract_config(self):
57
+ extractor = GeomapfishConfigExtractor()
58
+
59
+ options = Mock()
60
+ options.keywords = []
61
+
62
+ messages = list(extractor("config.yaml", options))
63
+
64
+ assert {msg.msgid for msg in messages} == {"description1", "description2"}
tests/test_logs.py ADDED
@@ -0,0 +1,102 @@
1
+ # pylint: disable=no-self-use,unsubscriptable-object
2
+
3
+ import datetime
4
+ from datetime import timezone
5
+
6
+ import pytest
7
+
8
+ from . import AbstractViewsTests
9
+
10
+
11
+ @pytest.fixture(scope="function")
12
+ @pytest.mark.usefixtures("dbsession", "transact")
13
+ def logs_test_data(dbsession, transact):
14
+ del transact
15
+
16
+ from c2cgeoportal_commons.models.main import AbstractLog
17
+ from c2cgeoportal_commons.models.main import Log as MainLog
18
+ from c2cgeoportal_commons.models.main import LogAction
19
+ from c2cgeoportal_commons.models.static import Log as StaticLog
20
+
21
+ logs = []
22
+ for i in range(0, 5):
23
+ log = MainLog(
24
+ date=datetime.datetime.now(timezone.utc),
25
+ action=[LogAction.INSERT, LogAction.UPDATE, LogAction.DELETE][i % 3],
26
+ element_type="role",
27
+ element_id=i,
28
+ element_name=f"role_{i}",
29
+ element_url_table="roles",
30
+ username="testuser",
31
+ )
32
+ dbsession.add(log)
33
+ logs.append(log)
34
+
35
+ log = StaticLog(
36
+ date=datetime.datetime.now(timezone.utc),
37
+ action=[LogAction.INSERT, LogAction.UPDATE, LogAction.DELETE][i % 3],
38
+ element_type="user",
39
+ element_id=i,
40
+ element_name=f"user_{i}",
41
+ element_url_table="users",
42
+ username="testuser",
43
+ )
44
+ dbsession.add(log)
45
+ logs.append(log)
46
+
47
+ dbsession.flush()
48
+
49
+ yield {
50
+ "logs": logs,
51
+ }
52
+
53
+
54
+ @pytest.mark.usefixtures("logs_test_data", "test_app")
55
+ class TestLog(AbstractViewsTests):
56
+ _prefix = "/admin/logs"
57
+
58
+ def test_index_rendering(self, test_app):
59
+ resp = self.get(test_app)
60
+
61
+ self.check_left_menu(resp, "Logs")
62
+
63
+ expected = [
64
+ ("actions", "", "false"),
65
+ ("id", "id", "true"),
66
+ ("date", "Date"),
67
+ ("username", "Username"),
68
+ ("action", "Action"),
69
+ ("element_type", "Element type"),
70
+ ("element_id", "Element identifier"),
71
+ ("element_name", "Element name"),
72
+ ]
73
+ self.check_grid_headers(resp, expected, new=False)
74
+
75
+ def test_grid_default_sort_on_date_desc(self, test_app, logs_test_data):
76
+ json = self.check_search(test_app)
77
+ expected_ids = [
78
+ log.id
79
+ for log in sorted(
80
+ logs_test_data["logs"],
81
+ key=lambda log: log.date,
82
+ reverse=True,
83
+ )
84
+ ]
85
+ result_ids = [int(row["_id_"]) for row in json["rows"]]
86
+ assert result_ids == expected_ids
87
+
88
+ def test_grid_sort_on_element_type(self, test_app, logs_test_data):
89
+ json = self.check_search(test_app, sort="element_type")
90
+ expected_ids = [
91
+ log.id
92
+ for log in sorted(
93
+ logs_test_data["logs"],
94
+ key=lambda log: (log.element_type, -log.date.timestamp()),
95
+ )
96
+ ]
97
+ result_ids = [int(row["_id_"]) for row in json["rows"]]
98
+ assert result_ids == expected_ids
99
+
100
+ def test_grid_search(self, test_app):
101
+ self.check_search(test_app, "role", total=5)
102
+ self.check_search(test_app, "user_2", total=1)
tests/test_main.py CHANGED
@@ -5,7 +5,9 @@ from webtest import TestApp as WebTestApp
5
5
 
6
6
  @pytest.mark.usefixtures("app_env")
7
7
  def test_main(app_env):
8
- """Test dev environment"""
8
+ """
9
+ Test dev environment.
10
+ """
9
11
  config = testing.setUp(registry=app_env["registry"])
10
12
  app = config.make_wsgi_app()
11
13
  testapp = WebTestApp(app)
tests/test_metadatas.py CHANGED
@@ -59,7 +59,6 @@ def metadatas_test_data(dbsession, transact):
59
59
 
60
60
  @pytest.mark.usefixtures("metadatas_test_data", "test_app")
61
61
  class TestMetadatasView(AbstractViewsTests):
62
-
63
62
  _prefix = "/admin/"
64
63
 
65
64
  def __metadata_ui_types(self):
@@ -85,7 +84,9 @@ class TestMetadatasView(AbstractViewsTests):
85
84
  return None
86
85
  return metadata.value
87
86
 
88
- def _check_metadatas(self, test_app, item, metadatas):
87
+ def _check_metadatas(self, test_app, item, metadatas, model):
88
+ from c2cgeoportal_admin.schemas.metadata import metadata_definitions
89
+
89
90
  settings = test_app.app.registry.settings
90
91
  self._check_sequence(
91
92
  item,
@@ -96,9 +97,7 @@ class TestMetadatasView(AbstractViewsTests):
96
97
  "name": "name",
97
98
  "value": [
98
99
  {"text": s_m["name"], "value": s_m["name"], "selected": s_m["name"] == m.name}
99
- for s_m in sorted(
100
- settings["admin_interface"]["available_metadata"], key=lambda m: m["name"]
101
- )
100
+ for s_m in sorted(metadata_definitions(settings, model), key=lambda m: m["name"])
102
101
  ],
103
102
  "label": "Name",
104
103
  },
@@ -131,7 +130,7 @@ class TestMetadatasView(AbstractViewsTests):
131
130
  resp = self._post_metadata(test_app, url, base_mapping, name, value, 200)
132
131
  assert (
133
132
  error_msg
134
- == resp.html.select_one(".item-{} .help-block".format(self.__metadata_ui_type(test_app, name)))
133
+ == resp.html.select_one(f".item-{self.__metadata_ui_type(test_app, name)} .help-block")
135
134
  .getText()
136
135
  .strip()
137
136
  )
@@ -156,12 +155,16 @@ class TestMetadatasView(AbstractViewsTests):
156
155
  )
157
156
 
158
157
  def test_get_true_boolean_metadata(self, metadatas_test_data, test_app):
159
- metadatas_test_data["layer_wms"].get_metadatas("_boolean")[0].value = "true"
160
- self._test_edit_treeitem("layers_wms", metadatas_test_data["layer_wms"], test_app)
158
+ from c2cgeoportal_commons.models.main import LayerWMS
159
+
160
+ metadatas_test_data["layer_wms"].get_metadata("_boolean")[0].value = "true"
161
+ self._test_edit_treeitem("layers_wms", metadatas_test_data["layer_wms"], test_app, LayerWMS)
161
162
 
162
163
  def test_get_false_boolean_metadata(self, metadatas_test_data, test_app):
163
- metadatas_test_data["layer_wms"].get_metadatas("_boolean")[0].value = "false"
164
- self._test_edit_treeitem("layers_wms", metadatas_test_data["layer_wms"], test_app)
164
+ from c2cgeoportal_commons.models.main import LayerWMS
165
+
166
+ metadatas_test_data["layer_wms"].get_metadata("_boolean")[0].value = "false"
167
+ self._test_edit_treeitem("layers_wms", metadatas_test_data["layer_wms"], test_app, LayerWMS)
165
168
 
166
169
  def test_post_true_boolean_metadata(self, test_app, metadatas_test_data, dbsession):
167
170
  from c2cgeoportal_commons.models.main import LayerWMS
@@ -175,7 +178,7 @@ class TestMetadatasView(AbstractViewsTests):
175
178
  302,
176
179
  )
177
180
  layer = dbsession.query(LayerWMS).filter(LayerWMS.name == "new_name").one()
178
- assert layer.get_metadatas("_boolean")[0].value == "true"
181
+ assert layer.get_metadata("_boolean")[0].value == "true"
179
182
 
180
183
  def test_post_false_boolean_metadata(self, test_app, metadatas_test_data, dbsession):
181
184
  from c2cgeoportal_commons.models.main import LayerWMS
@@ -189,7 +192,7 @@ class TestMetadatasView(AbstractViewsTests):
189
192
  302,
190
193
  )
191
194
  layer = dbsession.query(LayerWMS).filter(LayerWMS.name == "new_name").one()
192
- assert layer.get_metadatas("_boolean")[0].value == "false"
195
+ assert layer.get_metadata("_boolean")[0].value == "false"
193
196
 
194
197
  def test_valid_float_metadata(self, test_app, metadatas_test_data):
195
198
  self._post_metadata(
@@ -304,31 +307,41 @@ class TestMetadatasView(AbstractViewsTests):
304
307
  302,
305
308
  )
306
309
 
307
- def _test_edit_treeitem(self, prefix, item, test_app):
308
- resp = self.get(test_app, "{}/{}".format(prefix, item.id))
309
- self._check_metadatas(test_app, resp.html.select_one(".item-metadatas"), item.metadatas)
310
+ def _test_edit_treeitem(self, prefix, item, test_app, model):
311
+ resp = self.get(test_app, f"{prefix}/{item.id}")
312
+ self._check_metadatas(test_app, resp.html.select_one(".item-metadatas"), item.metadatas, model)
310
313
  resp.form.submit("submit", status=302)
311
314
 
312
315
  def test_layer_wms_metadatas(self, metadatas_test_data, test_app):
313
- self._test_edit_treeitem("layers_wms", metadatas_test_data["layer_wms"], test_app)
316
+ from c2cgeoportal_commons.models.main import LayerWMS
317
+
318
+ self._test_edit_treeitem("layers_wms", metadatas_test_data["layer_wms"], test_app, LayerWMS)
314
319
 
315
320
  def test_layer_wmts_metadatas(self, metadatas_test_data, test_app):
316
- self._test_edit_treeitem("layers_wmts", metadatas_test_data["layer_wmts"], test_app)
321
+ from c2cgeoportal_commons.models.main import LayerWMTS
322
+
323
+ self._test_edit_treeitem("layers_wmts", metadatas_test_data["layer_wmts"], test_app, LayerWMTS)
317
324
 
318
325
  def test_theme_metadatas(self, metadatas_test_data, test_app):
319
- self._test_edit_treeitem("themes", metadatas_test_data["theme"], test_app)
326
+ from c2cgeoportal_commons.models.main import Theme
327
+
328
+ self._test_edit_treeitem("themes", metadatas_test_data["theme"], test_app, Theme)
320
329
 
321
330
  def test_group_metadatas(self, metadatas_test_data, test_app):
322
- self._test_edit_treeitem("layer_groups", metadatas_test_data["group"], test_app)
331
+ from c2cgeoportal_commons.models.main import LayerGroup
332
+
333
+ self._test_edit_treeitem("layer_groups", metadatas_test_data["group"], test_app, LayerGroup)
323
334
 
324
335
  def test_undefined_metadata(self, metadatas_test_data, test_app):
325
- """Undefined metadata must be kept intact across submissions"""
336
+ """
337
+ Undefined metadata must be kept intact across submissions.
338
+ """
326
339
  from c2cgeoportal_commons.models.main import Metadata
327
340
 
328
341
  layer = metadatas_test_data["layer_wms"]
329
342
  layer.metadatas = [Metadata("_undefined", "This is an undefined metadata")]
330
343
 
331
- resp = self.get(test_app, "layers_wms/{}".format(layer.id))
344
+ resp = self.get(test_app, f"layers_wms/{layer.id}")
332
345
  resp.form.submit("submit", status=302)
333
346
 
334
347
  metadata = layer.metadatas[0]
@@ -3,6 +3,7 @@
3
3
  import re
4
4
  from uuid import uuid4
5
5
 
6
+ import pyramid.httpexceptions
6
7
  import pytest
7
8
  from pyramid.testing import DummyRequest
8
9
 
@@ -35,7 +36,6 @@ def oauth2_clients_test_data(dbsession, transact):
35
36
 
36
37
  @pytest.mark.usefixtures("oauth2_clients_test_data", "test_app")
37
38
  class TestOAuth2Client(TestTreeGroup):
38
-
39
39
  _prefix = "/admin/oauth2_clients"
40
40
 
41
41
  def test_index_rendering(self, test_app):
@@ -59,7 +59,8 @@ class TestOAuth2Client(TestTreeGroup):
59
59
  self.check_search(test_app, client.client_id, total=1)
60
60
 
61
61
  def test_submit_new(self, dbsession, test_app, oauth2_clients_test_data):
62
- from c2cgeoportal_commons.models.static import OAuth2Client
62
+ from c2cgeoportal_commons.models.main import LogAction
63
+ from c2cgeoportal_commons.models.static import Log, OAuth2Client
63
64
 
64
65
  resp = test_app.post(
65
66
  "/admin/oauth2_clients/new",
@@ -84,7 +85,18 @@ class TestOAuth2Client(TestTreeGroup):
84
85
  assert oauth2_client.secret == "12345"
85
86
  assert oauth2_client.redirect_uri == "http://127.0.0.1:7070/bis"
86
87
 
88
+ log = dbsession.query(Log).one()
89
+ assert log.date != None
90
+ assert log.action == LogAction.INSERT
91
+ assert log.element_type == "oauth2_client"
92
+ assert log.element_id == oauth2_client.id
93
+ assert log.element_name == oauth2_client.client_id
94
+ assert log.username == "test_user"
95
+
87
96
  def test_edit_then_save(self, dbsession, test_app, oauth2_clients_test_data):
97
+ from c2cgeoportal_commons.models.main import LogAction
98
+ from c2cgeoportal_commons.models.static import Log
99
+
88
100
  oauth2_client = oauth2_clients_test_data["oauth2_clients"][10]
89
101
 
90
102
  dbsession.expire(oauth2_client)
@@ -112,12 +124,20 @@ class TestOAuth2Client(TestTreeGroup):
112
124
  assert "New secret" == oauth2_client.secret
113
125
  assert "New redirect URI" == oauth2_client.redirect_uri
114
126
 
127
+ log = dbsession.query(Log).one()
128
+ assert log.date != None
129
+ assert log.action == LogAction.UPDATE
130
+ assert log.element_type == "oauth2_client"
131
+ assert log.element_id == oauth2_client.id
132
+ assert log.element_name == oauth2_client.client_id
133
+ assert log.username == "test_user"
134
+
115
135
  def test_duplicate(self, oauth2_clients_test_data, test_app, dbsession):
116
136
  from c2cgeoportal_commons.models.static import OAuth2Client
117
137
 
118
138
  oauth2_client_proto = oauth2_clients_test_data["oauth2_clients"][7]
119
139
 
120
- resp = test_app.get("/admin/oauth2_clients/{}/duplicate".format(oauth2_client_proto.id), status=200)
140
+ resp = test_app.get(f"/admin/oauth2_clients/{oauth2_client_proto.id}/duplicate", status=200)
121
141
  form = resp.form
122
142
 
123
143
  assert "" == self.get_first_field_named(form, "id").value
@@ -134,24 +154,33 @@ class TestOAuth2Client(TestTreeGroup):
134
154
  assert oauth2_client_proto.id != oauth2_client.id
135
155
 
136
156
  def test_delete(self, test_app, dbsession):
137
- from c2cgeoportal_commons.models.static import OAuth2Client
157
+ from c2cgeoportal_commons.models.main import LogAction
158
+ from c2cgeoportal_commons.models.static import Log, OAuth2Client
159
+
160
+ oauth2_client = dbsession.query(OAuth2Client).first()
161
+ test_app.delete(f"/admin/oauth2_clients/{oauth2_client.id}", status=200)
162
+ assert dbsession.query(OAuth2Client).get(oauth2_client.id) is None
138
163
 
139
- oauth2_client_id = dbsession.query(OAuth2Client.id).first().id
140
- test_app.delete("/admin/oauth2_clients/{}".format(oauth2_client_id), status=200)
141
- assert dbsession.query(OAuth2Client).get(oauth2_client_id) is None
164
+ log = dbsession.query(Log).one()
165
+ assert log.date != None
166
+ assert log.action == LogAction.DELETE
167
+ assert log.element_type == "oauth2_client"
168
+ assert log.element_id == oauth2_client.id
169
+ assert log.element_name == oauth2_client.client_id
170
+ assert log.username == "test_user"
142
171
 
143
172
  def test_unicity_validator(self, oauth2_clients_test_data, test_app):
144
173
  oauth2_client_proto = oauth2_clients_test_data["oauth2_clients"][7]
145
- resp = test_app.get("/admin/oauth2_clients/{}/duplicate".format(oauth2_client_proto.id), status=200)
174
+ resp = test_app.get(f"/admin/oauth2_clients/{oauth2_client_proto.id}/duplicate", status=200)
146
175
 
147
176
  resp = resp.form.submit("submit")
148
177
 
149
- self._check_submission_problem(resp, "{} is already used.".format(oauth2_client_proto.client_id))
178
+ self._check_submission_problem(resp, f"{oauth2_client_proto.client_id} is already used.")
150
179
 
151
180
  @pytest.mark.usefixtures("raise_db_error_on_query")
152
181
  def test_grid_dberror(self, dbsession):
153
182
  from c2cgeoportal_admin.views.oauth2_clients import OAuth2ClientViews
154
183
 
155
184
  request = DummyRequest(dbsession=dbsession, params={"offset": 0, "limit": 10})
156
- info = OAuth2ClientViews(request).grid()
157
- assert info.status_int == 500, "Expected 500 status when db error"
185
+ with pytest.raises(pyramid.httpexceptions.HTTPInternalServerError):
186
+ OAuth2ClientViews(request).grid()