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
@@ -0,0 +1,64 @@
1
+ # Copyright (c) 2022-2023, 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.lingua_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.lingua_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,103 @@
1
+ # pylint: disable=no-self-use,unsubscriptable-object
2
+
3
+ import datetime
4
+
5
+ import pytest
6
+ import pytz
7
+ from pyramid.testing import DummyRequest
8
+
9
+ from . import AbstractViewsTests
10
+
11
+
12
+ @pytest.fixture(scope="function")
13
+ @pytest.mark.usefixtures("dbsession", "transact")
14
+ def logs_test_data(dbsession, transact):
15
+ del transact
16
+
17
+ from c2cgeoportal_commons.models.main import AbstractLog
18
+ from c2cgeoportal_commons.models.main import Log as MainLog
19
+ from c2cgeoportal_commons.models.main import LogAction
20
+ from c2cgeoportal_commons.models.static import Log as StaticLog
21
+
22
+ logs = []
23
+ for i in range(0, 5):
24
+ log = MainLog(
25
+ date=datetime.datetime.now(pytz.utc),
26
+ action=[LogAction.INSERT, LogAction.UPDATE, LogAction.DELETE][i % 3],
27
+ element_type="role",
28
+ element_id=i,
29
+ element_name=f"role_{i}",
30
+ element_url_table="roles",
31
+ username="testuser",
32
+ )
33
+ dbsession.add(log)
34
+ logs.append(log)
35
+
36
+ log = StaticLog(
37
+ date=datetime.datetime.now(pytz.utc),
38
+ action=[LogAction.INSERT, LogAction.UPDATE, LogAction.DELETE][i % 3],
39
+ element_type="user",
40
+ element_id=i,
41
+ element_name=f"user_{i}",
42
+ element_url_table="users",
43
+ username="testuser",
44
+ )
45
+ dbsession.add(log)
46
+ logs.append(log)
47
+
48
+ dbsession.flush()
49
+
50
+ yield {
51
+ "logs": logs,
52
+ }
53
+
54
+
55
+ @pytest.mark.usefixtures("logs_test_data", "test_app")
56
+ class TestLog(AbstractViewsTests):
57
+ _prefix = "/admin/logs"
58
+
59
+ def test_index_rendering(self, test_app):
60
+ resp = self.get(test_app)
61
+
62
+ self.check_left_menu(resp, "Logs")
63
+
64
+ expected = [
65
+ ("actions", "", "false"),
66
+ ("id", "id", "true"),
67
+ ("date", "Date"),
68
+ ("username", "Username"),
69
+ ("action", "Action"),
70
+ ("element_type", "Element type"),
71
+ ("element_id", "Element identifier"),
72
+ ("element_name", "Element name"),
73
+ ]
74
+ self.check_grid_headers(resp, expected, new=False)
75
+
76
+ def test_grid_default_sort_on_date_desc(self, test_app, logs_test_data):
77
+ json = self.check_search(test_app)
78
+ expected_ids = [
79
+ log.id
80
+ for log in sorted(
81
+ logs_test_data["logs"],
82
+ key=lambda log: log.date,
83
+ reverse=True,
84
+ )
85
+ ]
86
+ result_ids = [int(row["_id_"]) for row in json["rows"]]
87
+ assert result_ids == expected_ids
88
+
89
+ def test_grid_sort_on_element_type(self, test_app, logs_test_data):
90
+ json = self.check_search(test_app, sort="element_type")
91
+ expected_ids = [
92
+ log.id
93
+ for log in sorted(
94
+ logs_test_data["logs"],
95
+ key=lambda log: (log.element_type, -log.date.timestamp()),
96
+ )
97
+ ]
98
+ result_ids = [int(row["_id_"]) for row in json["rows"]]
99
+ assert result_ids == expected_ids
100
+
101
+ def test_grid_search(self, test_app):
102
+ self.check_search(test_app, "role", total=5)
103
+ 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]
@@ -35,7 +35,6 @@ def oauth2_clients_test_data(dbsession, transact):
35
35
 
36
36
  @pytest.mark.usefixtures("oauth2_clients_test_data", "test_app")
37
37
  class TestOAuth2Client(TestTreeGroup):
38
-
39
38
  _prefix = "/admin/oauth2_clients"
40
39
 
41
40
  def test_index_rendering(self, test_app):
@@ -59,7 +58,8 @@ class TestOAuth2Client(TestTreeGroup):
59
58
  self.check_search(test_app, client.client_id, total=1)
60
59
 
61
60
  def test_submit_new(self, dbsession, test_app, oauth2_clients_test_data):
62
- from c2cgeoportal_commons.models.static import OAuth2Client
61
+ from c2cgeoportal_commons.models.main import LogAction
62
+ from c2cgeoportal_commons.models.static import Log, OAuth2Client
63
63
 
64
64
  resp = test_app.post(
65
65
  "/admin/oauth2_clients/new",
@@ -84,7 +84,18 @@ class TestOAuth2Client(TestTreeGroup):
84
84
  assert oauth2_client.secret == "12345"
85
85
  assert oauth2_client.redirect_uri == "http://127.0.0.1:7070/bis"
86
86
 
87
+ log = dbsession.query(Log).one()
88
+ assert log.date != None
89
+ assert log.action == LogAction.INSERT
90
+ assert log.element_type == "oauth2_client"
91
+ assert log.element_id == oauth2_client.id
92
+ assert log.element_name == oauth2_client.client_id
93
+ assert log.username == "test_user"
94
+
87
95
  def test_edit_then_save(self, dbsession, test_app, oauth2_clients_test_data):
96
+ from c2cgeoportal_commons.models.main import LogAction
97
+ from c2cgeoportal_commons.models.static import Log
98
+
88
99
  oauth2_client = oauth2_clients_test_data["oauth2_clients"][10]
89
100
 
90
101
  dbsession.expire(oauth2_client)
@@ -112,12 +123,20 @@ class TestOAuth2Client(TestTreeGroup):
112
123
  assert "New secret" == oauth2_client.secret
113
124
  assert "New redirect URI" == oauth2_client.redirect_uri
114
125
 
126
+ log = dbsession.query(Log).one()
127
+ assert log.date != None
128
+ assert log.action == LogAction.UPDATE
129
+ assert log.element_type == "oauth2_client"
130
+ assert log.element_id == oauth2_client.id
131
+ assert log.element_name == oauth2_client.client_id
132
+ assert log.username == "test_user"
133
+
115
134
  def test_duplicate(self, oauth2_clients_test_data, test_app, dbsession):
116
135
  from c2cgeoportal_commons.models.static import OAuth2Client
117
136
 
118
137
  oauth2_client_proto = oauth2_clients_test_data["oauth2_clients"][7]
119
138
 
120
- resp = test_app.get("/admin/oauth2_clients/{}/duplicate".format(oauth2_client_proto.id), status=200)
139
+ resp = test_app.get(f"/admin/oauth2_clients/{oauth2_client_proto.id}/duplicate", status=200)
121
140
  form = resp.form
122
141
 
123
142
  assert "" == self.get_first_field_named(form, "id").value
@@ -134,19 +153,28 @@ class TestOAuth2Client(TestTreeGroup):
134
153
  assert oauth2_client_proto.id != oauth2_client.id
135
154
 
136
155
  def test_delete(self, test_app, dbsession):
137
- from c2cgeoportal_commons.models.static import OAuth2Client
156
+ from c2cgeoportal_commons.models.main import LogAction
157
+ from c2cgeoportal_commons.models.static import Log, OAuth2Client
158
+
159
+ oauth2_client = dbsession.query(OAuth2Client).first()
160
+ test_app.delete(f"/admin/oauth2_clients/{oauth2_client.id}", status=200)
161
+ assert dbsession.query(OAuth2Client).get(oauth2_client.id) is None
138
162
 
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
163
+ log = dbsession.query(Log).one()
164
+ assert log.date != None
165
+ assert log.action == LogAction.DELETE
166
+ assert log.element_type == "oauth2_client"
167
+ assert log.element_id == oauth2_client.id
168
+ assert log.element_name == oauth2_client.client_id
169
+ assert log.username == "test_user"
142
170
 
143
171
  def test_unicity_validator(self, oauth2_clients_test_data, test_app):
144
172
  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)
173
+ resp = test_app.get(f"/admin/oauth2_clients/{oauth2_client_proto.id}/duplicate", status=200)
146
174
 
147
175
  resp = resp.form.submit("submit")
148
176
 
149
- self._check_submission_problem(resp, "{} is already used.".format(oauth2_client_proto.client_id))
177
+ self._check_submission_problem(resp, f"{oauth2_client_proto.client_id} is already used.")
150
178
 
151
179
  @pytest.mark.usefixtures("raise_db_error_on_query")
152
180
  def test_grid_dberror(self, dbsession):
tests/test_ogc_servers.py CHANGED
@@ -1,6 +1,7 @@
1
1
  # pylint: disable=no-self-use
2
2
 
3
3
  import re
4
+ from unittest.mock import patch
4
5
 
5
6
  import pytest
6
7
 
@@ -17,8 +18,8 @@ def ogc_server_test_data(dbsession, transact):
17
18
  auth = ["No auth", "Standard auth", "Geoserver auth", "Proxy"]
18
19
  servers = []
19
20
  for i in range(0, 8):
20
- server = OGCServer(name="server_{}".format(i), description="description_{}".format(i))
21
- server.url = "https://somebasicurl_{}.com".format(i)
21
+ server = OGCServer(name=f"server_{i}", description=f"description_{i}")
22
+ server.url = f"https://somebasicurl_{i}.com"
22
23
  server.image_type = "image/jpeg" if i % 2 == 0 else "image/png"
23
24
  server.auth = auth[i % 4]
24
25
  dbsession.add(server)
@@ -31,7 +32,6 @@ def ogc_server_test_data(dbsession, transact):
31
32
 
32
33
  @pytest.mark.usefixtures("ogc_server_test_data", "test_app")
33
34
  class TestOGCServer(AbstractViewsTests):
34
-
35
35
  _prefix = "/admin/ogc_servers"
36
36
 
37
37
  def test_index_rendering(self, test_app):
@@ -59,54 +59,82 @@ class TestOGCServer(AbstractViewsTests):
59
59
  self.check_search(test_app, "server_0", total=1)
60
60
 
61
61
  def test_submit_new(self, dbsession, test_app):
62
- from c2cgeoportal_commons.models.main import OGCServer
63
-
64
- resp = test_app.post(
65
- "/admin/ogc_servers/new",
66
- {
67
- "name": "new_name",
68
- "description": "new description",
69
- "url": "www.randomurl.com",
70
- "type": "mapserver",
71
- "auth": "No auth",
72
- "image_type": "image/png",
73
- },
74
- status=302,
75
- )
62
+ from c2cgeoportal_commons.models.main import Log, LogAction, OGCServer
63
+
64
+ with patch("c2cgeoportal_admin.views.ogc_servers.OGCServerViews._update_cache"):
65
+ resp = test_app.post(
66
+ "/admin/ogc_servers/new",
67
+ {
68
+ "name": "new_name",
69
+ "description": "new description",
70
+ "url": "www.randomurl.com",
71
+ "type": "mapserver",
72
+ "auth": "No auth",
73
+ "image_type": "image/png",
74
+ },
75
+ status=302,
76
+ )
76
77
  ogc_server = dbsession.query(OGCServer).filter(OGCServer.name == "new_name").one()
77
78
  assert str(ogc_server.id) == re.match(
78
79
  r"http://localhost/admin/ogc_servers/(.*)\?msg_col=submit_ok", resp.location
79
80
  ).group(1)
80
81
  assert ogc_server.name == "new_name"
81
82
 
82
- def test_edit(self, test_app, ogc_server_test_data):
83
+ log = dbsession.query(Log).one()
84
+ assert log.date != None
85
+ assert log.action == LogAction.INSERT
86
+ assert log.element_type == "ogc_server"
87
+ assert log.element_id == ogc_server.id
88
+ assert log.element_name == ogc_server.name
89
+ assert log.username == "test_user"
90
+
91
+ def test_edit(self, test_app, ogc_server_test_data, dbsession):
92
+ from c2cgeoportal_commons.models.main import Log, LogAction
93
+
83
94
  ogc_server = ogc_server_test_data["ogc_servers"][0]
84
- resp = test_app.get("/admin/ogc_servers/{}".format(ogc_server.id), status=200)
95
+ resp = test_app.get(f"/admin/ogc_servers/{ogc_server.id}", status=200)
85
96
  form = resp.form
86
97
  assert str(ogc_server.id) == self.get_first_field_named(form, "id").value
87
98
  assert "hidden" == self.get_first_field_named(form, "id").attrs["type"]
88
99
  assert ogc_server.name == form["name"].value
89
100
  form["description"] = "new_description"
90
- assert form.submit().status_int == 302
101
+ with patch("c2cgeoportal_admin.views.ogc_servers.OGCServerViews._update_cache"):
102
+ assert form.submit().status_int == 302
91
103
  assert ogc_server.description == "new_description"
92
104
 
105
+ log = dbsession.query(Log).one()
106
+ assert log.date != None
107
+ assert log.action == LogAction.UPDATE
108
+ assert log.element_type == "ogc_server"
109
+ assert log.element_id == ogc_server.id
110
+ assert log.element_name == ogc_server.name
111
+ assert log.username == "test_user"
112
+
93
113
  def test_delete(self, test_app, ogc_server_test_data, dbsession):
94
- from c2cgeoportal_commons.models.main import OGCServer
114
+ from c2cgeoportal_commons.models.main import Log, LogAction, OGCServer
95
115
 
96
116
  ogc_server = ogc_server_test_data["ogc_servers"][0]
97
- deleted_id = ogc_server.id
98
- test_app.delete("/admin/ogc_servers/{}".format(deleted_id), status=200)
99
- assert dbsession.query(OGCServer).get(deleted_id) is None
117
+ test_app.delete(f"/admin/ogc_servers/{ogc_server.id}", status=200)
118
+ assert dbsession.query(OGCServer).get(ogc_server.id) is None
119
+
120
+ log = dbsession.query(Log).one()
121
+ assert log.date != None
122
+ assert log.action == LogAction.DELETE
123
+ assert log.element_type == "ogc_server"
124
+ assert log.element_id == ogc_server.id
125
+ assert log.element_name == ogc_server.name
126
+ assert log.username == "test_user"
100
127
 
101
128
  def test_duplicate(self, ogc_server_test_data, test_app, dbsession):
102
129
  from c2cgeoportal_commons.models.main import OGCServer
103
130
 
104
131
  ogc_server = ogc_server_test_data["ogc_servers"][3]
105
- resp = test_app.get("/admin/ogc_servers/{}/duplicate".format(ogc_server.id), status=200)
132
+ resp = test_app.get(f"/admin/ogc_servers/{ogc_server.id}/duplicate", status=200)
106
133
  form = resp.form
107
134
  assert "" == self.get_first_field_named(form, "id").value
108
135
  self.set_first_field_named(form, "name", "clone")
109
- resp = form.submit("submit")
136
+ with patch("c2cgeoportal_admin.views.ogc_servers.OGCServerViews._update_cache"):
137
+ resp = form.submit("submit")
110
138
  assert resp.status_int == 302
111
139
  server = dbsession.query(OGCServer).filter(OGCServer.name == "clone").one()
112
140
  assert str(server.id) == re.match(
@@ -115,18 +143,18 @@ class TestOGCServer(AbstractViewsTests):
115
143
 
116
144
  def test_unicity_validator(self, ogc_server_test_data, test_app):
117
145
  ogc_server = ogc_server_test_data["ogc_servers"][3]
118
- resp = test_app.get("/admin/ogc_servers/{}/duplicate".format(ogc_server.id), status=200)
146
+ resp = test_app.get(f"/admin/ogc_servers/{ogc_server.id}/duplicate", status=200)
119
147
 
120
148
  resp = resp.form.submit("submit")
121
149
 
122
- self._check_submission_problem(resp, "{} is already used.".format(ogc_server.name))
150
+ self._check_submission_problem(resp, f"{ogc_server.name} is already used.")
123
151
 
124
152
  def test_check_success(self, ogc_server_test_data, test_app):
125
153
  ogc_server = ogc_server_test_data["ogc_servers"][3]
126
154
  ogc_server.url = "config://mapserver"
127
- resp = test_app.get("/admin/ogc_servers/{}/synchronize".format(ogc_server.id), status=200)
155
+ resp = test_app.get(f"/admin/ogc_servers/{ogc_server.id}/synchronize", status=200)
128
156
 
129
- resp = resp.forms["form-check"].submit("submit")
157
+ resp = resp.forms["form-check"].submit("check")
130
158
 
131
159
  assert list(resp.html.find("div", class_="alert-success").stripped_strings) == [
132
160
  "OGC Server has been successfully synchronized."
@@ -135,20 +163,41 @@ class TestOGCServer(AbstractViewsTests):
135
163
  def test_dry_run_success(self, ogc_server_test_data, test_app):
136
164
  ogc_server = ogc_server_test_data["ogc_servers"][3]
137
165
  ogc_server.url = "config://mapserver"
138
- resp = test_app.get("/admin/ogc_servers/{}/synchronize".format(ogc_server.id), status=200)
166
+ resp = test_app.get(f"/admin/ogc_servers/{ogc_server.id}/synchronize", status=200)
139
167
 
140
- resp = resp.forms["form-dry-run"].submit("submit")
168
+ resp = resp.forms["form-dry-run"].submit("dry-run")
141
169
 
142
170
  assert list(resp.html.find("div", class_="alert-success").stripped_strings) == [
143
171
  "OGC Server has been successfully synchronized."
144
172
  ]
145
173
 
146
- def test_synchronize_success(self, ogc_server_test_data, test_app):
174
+ def test_synchronize_success(self, ogc_server_test_data, test_app, dbsession):
175
+ from c2cgeoportal_commons.models.main import Log, LogAction
176
+
147
177
  ogc_server = ogc_server_test_data["ogc_servers"][3]
148
178
  ogc_server.url = "config://mapserver"
149
- resp = test_app.get("/admin/ogc_servers/{}/synchronize".format(ogc_server.id), status=200)
179
+ resp = test_app.get(f"/admin/ogc_servers/{ogc_server.id}/synchronize", status=200)
180
+
181
+ resp = resp.forms["form-synchronize"].submit("synchronize")
182
+
183
+ log = dbsession.query(Log).one()
184
+ assert log.date != None
185
+ assert log.action == LogAction.SYNCHRONIZE
186
+ assert log.element_type == "ogc_server"
187
+ assert log.element_id == ogc_server.id
188
+ assert log.element_name == ogc_server.name
189
+ assert log.username == "test_user"
190
+
191
+ assert list(resp.html.find("div", class_="alert-success").stripped_strings) == [
192
+ "OGC Server has been successfully synchronized."
193
+ ]
194
+
195
+ form = resp.forms["form-synchronize"]
196
+ form["force-parents"].checked = True
197
+ form["force-ordering"].checked = True
198
+ form["clean"].checked = True
150
199
 
151
- resp = resp.forms["form-synchronize"].submit("submit")
200
+ resp = form.submit("synchronize")
152
201
 
153
202
  assert list(resp.html.find("div", class_="alert-success").stripped_strings) == [
154
203
  "OGC Server has been successfully synchronized."