c2cgeoportal-admin 2.5.0.100__py3-none-any.whl → 2.7.1.156__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 (91) hide show
  1. c2cgeoportal_admin/__init__.py +19 -12
  2. c2cgeoportal_admin/lib/__init__.py +0 -0
  3. c2cgeoportal_admin/lib/lingua_extractor.py +77 -0
  4. c2cgeoportal_admin/lib/ogcserver_synchronizer.py +409 -0
  5. c2cgeoportal_admin/py.typed +0 -0
  6. c2cgeoportal_admin/routes.py +18 -10
  7. c2cgeoportal_admin/schemas/dimensions.py +13 -11
  8. c2cgeoportal_admin/schemas/functionalities.py +63 -22
  9. c2cgeoportal_admin/schemas/interfaces.py +23 -19
  10. c2cgeoportal_admin/schemas/metadata.py +121 -47
  11. c2cgeoportal_admin/schemas/restriction_areas.py +22 -20
  12. c2cgeoportal_admin/schemas/roles.py +8 -6
  13. c2cgeoportal_admin/schemas/treegroup.py +84 -18
  14. c2cgeoportal_admin/schemas/treeitem.py +2 -3
  15. c2cgeoportal_admin/static/layertree.css +26 -4
  16. c2cgeoportal_admin/static/navbar.css +59 -36
  17. c2cgeoportal_admin/static/theme.css +48 -11
  18. c2cgeoportal_admin/subscribers.py +3 -3
  19. c2cgeoportal_admin/templates/404.jinja2 +23 -0
  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/dimension_layers.py +7 -6
  43. c2cgeoportal_admin/views/functionalities.py +31 -5
  44. c2cgeoportal_admin/views/home.py +5 -5
  45. c2cgeoportal_admin/views/interfaces.py +8 -8
  46. c2cgeoportal_admin/views/layer_groups.py +9 -11
  47. c2cgeoportal_admin/views/layers.py +8 -7
  48. c2cgeoportal_admin/views/layers_vectortiles.py +30 -10
  49. c2cgeoportal_admin/views/layers_wms.py +45 -37
  50. c2cgeoportal_admin/views/layers_wmts.py +39 -33
  51. c2cgeoportal_admin/views/layertree.py +34 -26
  52. c2cgeoportal_admin/views/oauth2_clients.py +89 -0
  53. c2cgeoportal_admin/views/ogc_servers.py +130 -27
  54. c2cgeoportal_admin/views/restriction_areas.py +50 -8
  55. c2cgeoportal_admin/views/roles.py +60 -8
  56. c2cgeoportal_admin/views/themes.py +15 -14
  57. c2cgeoportal_admin/views/themes_ordering.py +38 -18
  58. c2cgeoportal_admin/views/treeitems.py +12 -11
  59. c2cgeoportal_admin/views/users.py +7 -5
  60. c2cgeoportal_admin/widgets.py +79 -28
  61. {c2cgeoportal_admin-2.5.0.100.dist-info → c2cgeoportal_admin-2.7.1.156.dist-info}/METADATA +16 -11
  62. c2cgeoportal_admin-2.7.1.156.dist-info/RECORD +92 -0
  63. {c2cgeoportal_admin-2.5.0.100.dist-info → c2cgeoportal_admin-2.7.1.156.dist-info}/WHEEL +1 -1
  64. c2cgeoportal_admin-2.7.1.156.dist-info/entry_points.txt +5 -0
  65. tests/__init__.py +23 -18
  66. tests/conftest.py +4 -15
  67. tests/test_edit_url.py +16 -18
  68. tests/test_functionalities.py +23 -10
  69. tests/test_interface.py +8 -8
  70. tests/test_layer_groups.py +15 -23
  71. tests/test_layers_vectortiles.py +16 -20
  72. tests/test_layers_wms.py +37 -75
  73. tests/test_layers_wmts.py +20 -24
  74. tests/test_layertree.py +107 -100
  75. tests/test_learn.py +1 -1
  76. tests/test_lingua_extractor_config.py +66 -0
  77. tests/test_main.py +4 -2
  78. tests/test_metadatas.py +79 -70
  79. tests/test_oauth2_clients.py +157 -0
  80. tests/test_ogc_servers.py +51 -7
  81. tests/test_restriction_areas.py +81 -17
  82. tests/test_role.py +110 -76
  83. tests/test_themes.py +44 -37
  84. tests/test_themes_ordering.py +1 -1
  85. tests/test_treegroup.py +2 -2
  86. tests/test_user.py +31 -64
  87. tests/themes_ordering.py +1 -1
  88. c2cgeoportal_admin/templates/navigation_vertical.jinja2 +0 -10
  89. c2cgeoportal_admin-2.5.0.100.dist-info/RECORD +0 -84
  90. c2cgeoportal_admin-2.5.0.100.dist-info/entry_points.txt +0 -3
  91. {c2cgeoportal_admin-2.5.0.100.dist-info → c2cgeoportal_admin-2.7.1.156.dist-info}/top_level.txt +0 -0
tests/test_metadatas.py CHANGED
@@ -2,8 +2,7 @@
2
2
 
3
3
  import pytest
4
4
 
5
- from . import AbstractViewsTests, skip_if_ci
6
- from .selenium.page import IndexPage
5
+ from . import AbstractViewsTests
7
6
 
8
7
 
9
8
  @pytest.fixture(scope="function")
@@ -11,7 +10,7 @@ from .selenium.page import IndexPage
11
10
  def metadatas_test_data(dbsession, transact):
12
11
  del transact
13
12
 
14
- from c2cgeoportal_commons.models.main import LayerWMS, LayerWMTS, OGCServer, Metadata, Theme, LayerGroup
13
+ from c2cgeoportal_commons.models.main import LayerGroup, LayerWMS, LayerWMTS, Metadata, OGCServer, Theme
15
14
 
16
15
  ogc_server = OGCServer(name="ogc_server")
17
16
 
@@ -77,7 +76,18 @@ class TestMetadatasView(AbstractViewsTests):
77
76
  "string",
78
77
  )
79
78
 
80
- def _check_metadatas(self, test_app, item, metadatas):
79
+ def expected_value(self, test_app, metadata):
80
+ if self.__metadata_ui_type(test_app, metadata.name) == "boolean":
81
+ if metadata.value == "true":
82
+ return True
83
+ if metadata.value == "false":
84
+ return False
85
+ return None
86
+ return metadata.value
87
+
88
+ def _check_metadatas(self, test_app, item, metadatas, model):
89
+ from c2cgeoportal_admin.schemas.metadata import metadata_definitions
90
+
81
91
  settings = test_app.app.registry.settings
82
92
  self._check_sequence(
83
93
  item,
@@ -88,13 +98,14 @@ class TestMetadatasView(AbstractViewsTests):
88
98
  "name": "name",
89
99
  "value": [
90
100
  {"text": s_m["name"], "value": s_m["name"], "selected": s_m["name"] == m.name}
91
- for s_m in sorted(
92
- settings["admin_interface"]["available_metadata"], key=lambda m: m["name"]
93
- )
101
+ for s_m in sorted(metadata_definitions(settings, model), key=lambda m: m["name"])
94
102
  ],
95
103
  "label": "Name",
96
104
  },
97
- {"name": self.__metadata_ui_type(test_app, m.name), "value": m.value},
105
+ {
106
+ "name": self.__metadata_ui_type(test_app, m.name),
107
+ "value": self.expected_value(test_app, m),
108
+ },
98
109
  {"name": "description", "value": m.description, "label": "Description"},
99
110
  ]
100
111
  for m in metadatas
@@ -120,7 +131,7 @@ class TestMetadatasView(AbstractViewsTests):
120
131
  resp = self._post_metadata(test_app, url, base_mapping, name, value, 200)
121
132
  assert (
122
133
  error_msg
123
- == resp.html.select_one(".item-{} .help-block".format(self.__metadata_ui_type(test_app, name)))
134
+ == resp.html.select_one(f".item-{self.__metadata_ui_type(test_app, name)} .help-block")
124
135
  .getText()
125
136
  .strip()
126
137
  )
@@ -144,6 +155,46 @@ class TestMetadatasView(AbstractViewsTests):
144
155
  '"number" is not a number',
145
156
  )
146
157
 
158
+ def test_get_true_boolean_metadata(self, metadatas_test_data, test_app):
159
+ from c2cgeoportal_commons.models.main import LayerWMS
160
+
161
+ metadatas_test_data["layer_wms"].get_metadata("_boolean")[0].value = "true"
162
+ self._test_edit_treeitem("layers_wms", metadatas_test_data["layer_wms"], test_app, LayerWMS)
163
+
164
+ def test_get_false_boolean_metadata(self, metadatas_test_data, test_app):
165
+ from c2cgeoportal_commons.models.main import LayerWMS
166
+
167
+ metadatas_test_data["layer_wms"].get_metadata("_boolean")[0].value = "false"
168
+ self._test_edit_treeitem("layers_wms", metadatas_test_data["layer_wms"], test_app, LayerWMS)
169
+
170
+ def test_post_true_boolean_metadata(self, test_app, metadatas_test_data, dbsession):
171
+ from c2cgeoportal_commons.models.main import LayerWMS
172
+
173
+ self._post_metadata(
174
+ test_app,
175
+ "/admin/layers_wms/new",
176
+ self._base_metadata_params(metadatas_test_data),
177
+ "_boolean",
178
+ "true",
179
+ 302,
180
+ )
181
+ layer = dbsession.query(LayerWMS).filter(LayerWMS.name == "new_name").one()
182
+ assert layer.get_metadata("_boolean")[0].value == "true"
183
+
184
+ def test_post_false_boolean_metadata(self, test_app, metadatas_test_data, dbsession):
185
+ from c2cgeoportal_commons.models.main import LayerWMS
186
+
187
+ self._post_metadata(
188
+ test_app,
189
+ "/admin/layers_wms/new",
190
+ self._base_metadata_params(metadatas_test_data),
191
+ "_boolean",
192
+ "false",
193
+ 302,
194
+ )
195
+ layer = dbsession.query(LayerWMS).filter(LayerWMS.name == "new_name").one()
196
+ assert layer.get_metadata("_boolean")[0].value == "false"
197
+
147
198
  def test_valid_float_metadata(self, test_app, metadatas_test_data):
148
199
  self._post_metadata(
149
200
  test_app,
@@ -257,85 +308,43 @@ class TestMetadatasView(AbstractViewsTests):
257
308
  302,
258
309
  )
259
310
 
260
- def _test_edit_treeitem(self, prefix, item, test_app):
261
- resp = self.get(test_app, "{}/{}".format(prefix, item.id))
262
- self._check_metadatas(test_app, resp.html.select_one(".item-metadatas"), item.metadatas)
311
+ def _test_edit_treeitem(self, prefix, item, test_app, model):
312
+ resp = self.get(test_app, f"{prefix}/{item.id}")
313
+ self._check_metadatas(test_app, resp.html.select_one(".item-metadatas"), item.metadatas, model)
263
314
  resp.form.submit("submit", status=302)
264
315
 
265
316
  def test_layer_wms_metadatas(self, metadatas_test_data, test_app):
266
- self._test_edit_treeitem("layers_wms", metadatas_test_data["layer_wms"], test_app)
317
+ from c2cgeoportal_commons.models.main import LayerWMS
318
+
319
+ self._test_edit_treeitem("layers_wms", metadatas_test_data["layer_wms"], test_app, LayerWMS)
267
320
 
268
321
  def test_layer_wmts_metadatas(self, metadatas_test_data, test_app):
269
- self._test_edit_treeitem("layers_wmts", metadatas_test_data["layer_wmts"], test_app)
322
+ from c2cgeoportal_commons.models.main import LayerWMTS
323
+
324
+ self._test_edit_treeitem("layers_wmts", metadatas_test_data["layer_wmts"], test_app, LayerWMTS)
270
325
 
271
326
  def test_theme_metadatas(self, metadatas_test_data, test_app):
272
- self._test_edit_treeitem("themes", metadatas_test_data["theme"], test_app)
327
+ from c2cgeoportal_commons.models.main import Theme
328
+
329
+ self._test_edit_treeitem("themes", metadatas_test_data["theme"], test_app, Theme)
273
330
 
274
331
  def test_group_metadatas(self, metadatas_test_data, test_app):
275
- self._test_edit_treeitem("layer_groups", metadatas_test_data["group"], test_app)
332
+ from c2cgeoportal_commons.models.main import LayerGroup
333
+
334
+ self._test_edit_treeitem("layer_groups", metadatas_test_data["group"], test_app, LayerGroup)
276
335
 
277
336
  def test_undefined_metadata(self, metadatas_test_data, test_app):
278
- """Undefined metadata must be kept intact accross submissions"""
337
+ """
338
+ Undefined metadata must be kept intact across submissions.
339
+ """
279
340
  from c2cgeoportal_commons.models.main import Metadata
280
341
 
281
342
  layer = metadatas_test_data["layer_wms"]
282
343
  layer.metadatas = [Metadata("_undefined", "This is an undefined metadata")]
283
344
 
284
- resp = self.get(test_app, "layers_wms/{}".format(layer.id))
345
+ resp = self.get(test_app, f"layers_wms/{layer.id}")
285
346
  resp.form.submit("submit", status=302)
286
347
 
287
348
  metadata = layer.metadatas[0]
288
349
  assert metadata.name == "_undefined"
289
350
  assert metadata.value == "This is an undefined metadata"
290
-
291
-
292
- @skip_if_ci
293
- @pytest.mark.selenium
294
- @pytest.mark.usefixtures("selenium", "selenium_app", "metadatas_test_data")
295
- class TestMetadatasSelenium:
296
- def test_hidden_type_validator_does_not_take_precedence_over_visible(
297
- self, selenium, selenium_app, metadatas_test_data
298
- ):
299
- layer = metadatas_test_data["layer_wms"]
300
- selenium.get(selenium_app + "/admin/layers_wms/{}".format(layer.id))
301
- selenium.execute_script("window.scrollBy(0,3000)", "")
302
- selenium.find_element_by_xpath(
303
- """//div[contains(., "Metadatas")]
304
- /following-sibling::div[@class="panel-footer"]/a[@href="#"]"""
305
- ).click()
306
- selenium.execute_script("window.scrollBy(0,3000)", "")
307
- selenium.find_elements_by_xpath(
308
- """//div[contains(., "Metadatas")]//label[contains(., "Name")]
309
- /following-sibling::select/option[contains(.,"_int")]"""
310
- )[9].click()
311
- selenium.find_elements_by_xpath('//div[contains(., "Metadatas")]//input[@name="int"]')[9].send_keys(
312
- "AAA"
313
- )
314
-
315
- selenium.find_element_by_id("deformformsubmit").click()
316
-
317
- assert '"AAA" is not a number' == selenium.find_element_by_xpath('//p[@class="help-block"]').text
318
-
319
- selenium.find_elements_by_xpath(
320
- """//div[contains(., "Metadatas")]//label[contains(., "Name")]
321
- /following-sibling::select/option[contains(.,"_color")]"""
322
- )[9].click()
323
- selenium.find_elements_by_xpath('//div[contains(., "Metadatas")]//input[@name="string"]')[
324
- 9
325
- ].send_keys("BBB")
326
-
327
- selenium.find_element_by_id("deformformsubmit").click()
328
-
329
- assert (
330
- "Expecting hex format for color, e.g. #007DCD"
331
- == selenium.find_element_by_xpath('//p[@class="help-block"]').text
332
- )
333
-
334
- # have to check there are no side effects, especially that modifications held at template side
335
- # don't trigger "are you sure you want to leave alert"
336
- layer = metadatas_test_data["layer_wms"]
337
- IndexPage(selenium)
338
- selenium.get(selenium_app + "/admin/layers_wms/{}".format(layer.id))
339
-
340
- selenium.find_element_by_xpath('//a[contains(@href, "roles")]').click()
341
- assert selenium.current_url.endswith("/roles")
@@ -0,0 +1,157 @@
1
+ # pylint: disable=no-self-use,unsubscriptable-object
2
+
3
+ import re
4
+ from uuid import uuid4
5
+
6
+ import pytest
7
+ from pyramid.testing import DummyRequest
8
+
9
+ from .test_treegroup import TestTreeGroup
10
+
11
+
12
+ @pytest.fixture(scope="function")
13
+ @pytest.mark.usefixtures("dbsession", "transact")
14
+ def oauth2_clients_test_data(dbsession, transact):
15
+ del transact
16
+
17
+ from c2cgeoportal_commons.models.static import OAuth2Client
18
+
19
+ clients = []
20
+ for i in range(23):
21
+ client = OAuth2Client()
22
+ client.client_id = str(uuid4())
23
+ client.secret = "1234"
24
+ client.redirect_uri = "http://127.0.0.1:7070/"
25
+
26
+ dbsession.add(client)
27
+ clients.append(client)
28
+
29
+ dbsession.flush()
30
+
31
+ yield {
32
+ "oauth2_clients": clients,
33
+ }
34
+
35
+
36
+ @pytest.mark.usefixtures("oauth2_clients_test_data", "test_app")
37
+ class TestOAuth2Client(TestTreeGroup):
38
+
39
+ _prefix = "/admin/oauth2_clients"
40
+
41
+ def test_index_rendering(self, test_app):
42
+ resp = self.get(test_app)
43
+
44
+ self.check_left_menu(resp, "OAuth2 Clients")
45
+
46
+ expected = [
47
+ ("actions", "", "false"),
48
+ ("id", "id", "true"),
49
+ ("client_id", "Client ID"),
50
+ ("secret", "Secret"),
51
+ ("redirect_uri", "Redirect URI"),
52
+ ]
53
+ self.check_grid_headers(resp, expected)
54
+
55
+ def test_grid_search(self, test_app, oauth2_clients_test_data):
56
+ self.check_search(test_app, "", total=23)
57
+
58
+ client = oauth2_clients_test_data["oauth2_clients"][0]
59
+ self.check_search(test_app, client.client_id, total=1)
60
+
61
+ def test_submit_new(self, dbsession, test_app, oauth2_clients_test_data):
62
+ from c2cgeoportal_commons.models.static import OAuth2Client
63
+
64
+ resp = test_app.post(
65
+ "/admin/oauth2_clients/new",
66
+ (
67
+ ("_charset_", "UTF-8"),
68
+ ("__formid__", "deform"),
69
+ ("id", ""),
70
+ ("client_id", "qgis2"),
71
+ ("secret", "12345"),
72
+ ("redirect_uri", "http://127.0.0.1:7070/bis"),
73
+ ("formsubmit", "formsubmit"),
74
+ ),
75
+ status=302,
76
+ )
77
+
78
+ oauth2_client = dbsession.query(OAuth2Client).filter(OAuth2Client.client_id == "qgis2").one()
79
+ assert str(oauth2_client.id) == re.match(
80
+ r"http://localhost/admin/oauth2_clients/(.*)\?msg_col=submit_ok", resp.location
81
+ ).group(1)
82
+
83
+ assert oauth2_client.client_id == "qgis2"
84
+ assert oauth2_client.secret == "12345"
85
+ assert oauth2_client.redirect_uri == "http://127.0.0.1:7070/bis"
86
+
87
+ def test_edit_then_save(self, dbsession, test_app, oauth2_clients_test_data):
88
+ oauth2_client = oauth2_clients_test_data["oauth2_clients"][10]
89
+
90
+ dbsession.expire(oauth2_client)
91
+
92
+ form = self.get_item(test_app, oauth2_client.id).form
93
+
94
+ assert str(oauth2_client.id) == form["id"].value
95
+ assert oauth2_client.client_id == form["client_id"].value
96
+ assert oauth2_client.secret == form["secret"].value
97
+ assert oauth2_client.redirect_uri == form["redirect_uri"].value
98
+
99
+ form["client_id"] = "New client ID"
100
+ form["secret"] = "New secret"
101
+ form["redirect_uri"] = "New redirect URI"
102
+
103
+ resp = form.submit("submit")
104
+
105
+ assert str(oauth2_client.id) == re.match(
106
+ r"http://localhost/admin/oauth2_clients/(.*)\?msg_col=submit_ok", resp.location
107
+ ).group(1)
108
+
109
+ dbsession.expire(oauth2_client)
110
+
111
+ assert "New client ID" == oauth2_client.client_id
112
+ assert "New secret" == oauth2_client.secret
113
+ assert "New redirect URI" == oauth2_client.redirect_uri
114
+
115
+ def test_duplicate(self, oauth2_clients_test_data, test_app, dbsession):
116
+ from c2cgeoportal_commons.models.static import OAuth2Client
117
+
118
+ oauth2_client_proto = oauth2_clients_test_data["oauth2_clients"][7]
119
+
120
+ resp = test_app.get(f"/admin/oauth2_clients/{oauth2_client_proto.id}/duplicate", status=200)
121
+ form = resp.form
122
+
123
+ assert "" == self.get_first_field_named(form, "id").value
124
+ assert oauth2_client_proto.client_id == form["client_id"].value
125
+ assert oauth2_client_proto.secret == form["secret"].value
126
+ assert oauth2_client_proto.redirect_uri == form["redirect_uri"].value
127
+ form["client_id"].value = "clone"
128
+ resp = form.submit("submit")
129
+
130
+ oauth2_client = dbsession.query(OAuth2Client).filter(OAuth2Client.client_id == "clone").one()
131
+ assert str(oauth2_client.id) == re.match(
132
+ r"http://localhost/admin/oauth2_clients/(.*)\?msg_col=submit_ok", resp.location
133
+ ).group(1)
134
+ assert oauth2_client_proto.id != oauth2_client.id
135
+
136
+ def test_delete(self, test_app, dbsession):
137
+ from c2cgeoportal_commons.models.static import OAuth2Client
138
+
139
+ oauth2_client_id = dbsession.query(OAuth2Client.id).first().id
140
+ test_app.delete(f"/admin/oauth2_clients/{oauth2_client_id}", status=200)
141
+ assert dbsession.query(OAuth2Client).get(oauth2_client_id) is None
142
+
143
+ def test_unicity_validator(self, oauth2_clients_test_data, test_app):
144
+ oauth2_client_proto = oauth2_clients_test_data["oauth2_clients"][7]
145
+ resp = test_app.get(f"/admin/oauth2_clients/{oauth2_client_proto.id}/duplicate", status=200)
146
+
147
+ resp = resp.form.submit("submit")
148
+
149
+ self._check_submission_problem(resp, f"{oauth2_client_proto.client_id} is already used.")
150
+
151
+ @pytest.mark.usefixtures("raise_db_error_on_query")
152
+ def test_grid_dberror(self, dbsession):
153
+ from c2cgeoportal_admin.views.oauth2_clients import OAuth2ClientViews
154
+
155
+ 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"
tests/test_ogc_servers.py CHANGED
@@ -17,8 +17,8 @@ def ogc_server_test_data(dbsession, transact):
17
17
  auth = ["No auth", "Standard auth", "Geoserver auth", "Proxy"]
18
18
  servers = []
19
19
  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)
20
+ server = OGCServer(name=f"server_{i}", description=f"description_{i}")
21
+ server.url = f"https://somebasicurl_{i}.com"
22
22
  server.image_type = "image/jpeg" if i % 2 == 0 else "image/png"
23
23
  server.auth = auth[i % 4]
24
24
  dbsession.add(server)
@@ -81,7 +81,7 @@ class TestOGCServer(AbstractViewsTests):
81
81
 
82
82
  def test_edit(self, test_app, ogc_server_test_data):
83
83
  ogc_server = ogc_server_test_data["ogc_servers"][0]
84
- resp = test_app.get("/admin/ogc_servers/{}".format(ogc_server.id), status=200)
84
+ resp = test_app.get(f"/admin/ogc_servers/{ogc_server.id}", status=200)
85
85
  form = resp.form
86
86
  assert str(ogc_server.id) == self.get_first_field_named(form, "id").value
87
87
  assert "hidden" == self.get_first_field_named(form, "id").attrs["type"]
@@ -95,14 +95,14 @@ class TestOGCServer(AbstractViewsTests):
95
95
 
96
96
  ogc_server = ogc_server_test_data["ogc_servers"][0]
97
97
  deleted_id = ogc_server.id
98
- test_app.delete("/admin/ogc_servers/{}".format(deleted_id), status=200)
98
+ test_app.delete(f"/admin/ogc_servers/{deleted_id}", status=200)
99
99
  assert dbsession.query(OGCServer).get(deleted_id) is None
100
100
 
101
101
  def test_duplicate(self, ogc_server_test_data, test_app, dbsession):
102
102
  from c2cgeoportal_commons.models.main import OGCServer
103
103
 
104
104
  ogc_server = ogc_server_test_data["ogc_servers"][3]
105
- resp = test_app.get("/admin/ogc_servers/{}/duplicate".format(ogc_server.id), status=200)
105
+ resp = test_app.get(f"/admin/ogc_servers/{ogc_server.id}/duplicate", status=200)
106
106
  form = resp.form
107
107
  assert "" == self.get_first_field_named(form, "id").value
108
108
  self.set_first_field_named(form, "name", "clone")
@@ -115,8 +115,52 @@ class TestOGCServer(AbstractViewsTests):
115
115
 
116
116
  def test_unicity_validator(self, ogc_server_test_data, test_app):
117
117
  ogc_server = ogc_server_test_data["ogc_servers"][3]
118
- resp = test_app.get("/admin/ogc_servers/{}/duplicate".format(ogc_server.id), status=200)
118
+ resp = test_app.get(f"/admin/ogc_servers/{ogc_server.id}/duplicate", status=200)
119
119
 
120
120
  resp = resp.form.submit("submit")
121
121
 
122
- self._check_submission_problem(resp, "{} is already used.".format(ogc_server.name))
122
+ self._check_submission_problem(resp, f"{ogc_server.name} is already used.")
123
+
124
+ def test_check_success(self, ogc_server_test_data, test_app):
125
+ ogc_server = ogc_server_test_data["ogc_servers"][3]
126
+ ogc_server.url = "config://mapserver"
127
+ resp = test_app.get(f"/admin/ogc_servers/{ogc_server.id}/synchronize", status=200)
128
+
129
+ resp = resp.forms["form-check"].submit("submit")
130
+
131
+ assert list(resp.html.find("div", class_="alert-success").stripped_strings) == [
132
+ "OGC Server has been successfully synchronized."
133
+ ]
134
+
135
+ def test_dry_run_success(self, ogc_server_test_data, test_app):
136
+ ogc_server = ogc_server_test_data["ogc_servers"][3]
137
+ ogc_server.url = "config://mapserver"
138
+ resp = test_app.get(f"/admin/ogc_servers/{ogc_server.id}/synchronize", status=200)
139
+
140
+ resp = resp.forms["form-dry-run"].submit("submit")
141
+
142
+ assert list(resp.html.find("div", class_="alert-success").stripped_strings) == [
143
+ "OGC Server has been successfully synchronized."
144
+ ]
145
+
146
+ def test_synchronize_success(self, ogc_server_test_data, test_app):
147
+ ogc_server = ogc_server_test_data["ogc_servers"][3]
148
+ ogc_server.url = "config://mapserver"
149
+ resp = test_app.get(f"/admin/ogc_servers/{ogc_server.id}/synchronize", status=200)
150
+
151
+ resp = resp.forms["form-synchronize"].submit("submit")
152
+
153
+ assert list(resp.html.find("div", class_="alert-success").stripped_strings) == [
154
+ "OGC Server has been successfully synchronized."
155
+ ]
156
+
157
+ form = resp.forms["form-synchronize"]
158
+ form["force-parents"].checked = True
159
+ form["force-ordering"].checked = True
160
+ form["clean"].checked = True
161
+
162
+ resp = form.submit("submit")
163
+
164
+ assert list(resp.html.find("div", class_="alert-success").stripped_strings) == [
165
+ "OGC Server has been successfully synchronized."
166
+ ]
@@ -4,39 +4,52 @@
4
4
  import json
5
5
  import re
6
6
 
7
- from geoalchemy2.shape import from_shape
8
7
  import pytest
8
+ from geoalchemy2.shape import from_shape
9
9
  from shapely.geometry import Polygon, box, shape
10
10
 
11
- from . import AbstractViewsTests
11
+ from .test_treegroup import TestTreeGroup
12
12
 
13
13
 
14
14
  @pytest.fixture(scope="function")
15
15
  @pytest.mark.usefixtures("dbsession", "transact")
16
16
  def restriction_area_test_data(dbsession, transact):
17
17
  del transact
18
- from c2cgeoportal_commons.models.main import RestrictionArea, Role
18
+ from c2cgeoportal_commons.models.main import LayerWMS, OGCServer, RestrictionArea, Role
19
19
 
20
20
  roles = []
21
21
  for i in range(0, 4):
22
22
  roles.append(Role("secretary_" + str(i)))
23
- dbsession.add(roles[i])
23
+ dbsession.add_all(roles)
24
+
25
+ ogc_server = OGCServer(name="test_server")
26
+ layers = []
27
+ for i in range(0, 4):
28
+ layer = LayerWMS(name=f"layer_{i}", layer=f"layer_{i}", public=False)
29
+ layer.ogc_server = ogc_server
30
+ layers.append(layer)
31
+ dbsession.add_all(layers)
24
32
 
25
33
  restrictionareas = []
26
34
  for i in range(0, 4):
27
- restrictionarea = RestrictionArea(name="restrictionarea_{}".format(i))
35
+ restrictionarea = RestrictionArea(name=f"restrictionarea_{i}")
28
36
  restrictionarea.area = from_shape(box(485869.5728, 76443.1884, 837076.5648, 299941.7864), srid=21781)
29
- restrictionarea.description = "description_{}".format(i)
37
+ restrictionarea.description = f"description_{i}"
30
38
  restrictionarea.roles = [roles[i % 4], roles[(i + 2) % 4]]
39
+ restrictionarea.layers = [layers[i % 4], layers[(i + 2) % 4]]
31
40
  dbsession.add(restrictionarea)
32
41
  restrictionareas.append(restrictionarea)
33
42
 
34
43
  dbsession.flush()
35
- yield {"restriction_areas": restrictionareas, "roles": roles}
44
+ yield {
45
+ "layers": layers,
46
+ "restriction_areas": restrictionareas,
47
+ "roles": roles,
48
+ }
36
49
 
37
50
 
38
51
  @pytest.mark.usefixtures("restriction_area_test_data", "test_app")
39
- class TestRestrictionAreaViews(AbstractViewsTests):
52
+ class TestRestrictionAreaViews(TestTreeGroup):
40
53
 
41
54
  _prefix = "/admin/restriction_areas"
42
55
 
@@ -59,31 +72,65 @@ class TestRestrictionAreaViews(AbstractViewsTests):
59
72
  def test_grid_search(self, test_app):
60
73
  self.check_search(test_app, "restrictionarea_1", total=1)
61
74
 
62
- def test_submit_new(self, dbsession, test_app):
75
+ def test_submit_new(self, dbsession, test_app, restriction_area_test_data):
63
76
  from c2cgeoportal_commons.models.main import RestrictionArea
64
77
 
78
+ roles = restriction_area_test_data["roles"]
79
+ layers = restriction_area_test_data["layers"]
80
+
65
81
  resp = test_app.post(
66
- "/admin/restriction_areas/new", {"name": "new_name", "description": "new_description"}, status=302
82
+ "/admin/restriction_areas/new",
83
+ (
84
+ ("_charset_", "UTF-8"),
85
+ ("__formid__", "deform"),
86
+ ("id", ""),
87
+ ("name", "new_name"),
88
+ ("description", "new_description"),
89
+ ("readwrite", "true"),
90
+ ("area", ""),
91
+ ("__start__", "roles:sequence"),
92
+ ("roles", str(roles[0].id)),
93
+ ("roles", str(roles[1].id)),
94
+ ("__end__", "roles:sequence"),
95
+ ("__start__", "layers:sequence"),
96
+ ("__start__", "layer:mapping"),
97
+ ("id", str(layers[0].id)),
98
+ ("__end__", "layer:mapping"),
99
+ ("__start__", "layer:mapping"),
100
+ ("id", str(layers[1].id)),
101
+ ("__end__", "layer:mapping"),
102
+ ("__end__", "layers:sequence"),
103
+ ("formsubmit", "formsubmit"),
104
+ ),
105
+ status=302,
67
106
  )
68
107
 
69
108
  restriction_area = dbsession.query(RestrictionArea).filter(RestrictionArea.name == "new_name").one()
70
109
  assert str(restriction_area.id) == re.match(
71
110
  r"http://localhost/admin/restriction_areas/(.*)\?msg_col=submit_ok", resp.location
72
111
  ).group(1)
112
+
73
113
  assert restriction_area.name == "new_name"
114
+ assert restriction_area.description == "new_description"
115
+ assert restriction_area.readwrite
116
+ assert set(restriction_area.roles) == {roles[0], roles[1]}
117
+ assert set(restriction_area.layers) == {layers[0], layers[1]}
74
118
 
75
119
  def test_unicity_validator(self, restriction_area_test_data, test_app):
76
120
  restriction_area = restriction_area_test_data["restriction_areas"][2]
77
121
 
78
- resp = test_app.get("/admin/restriction_areas/{}/duplicate".format(restriction_area.id), status=200)
122
+ resp = test_app.get(f"/admin/restriction_areas/{restriction_area.id}/duplicate", status=200)
79
123
  resp = resp.form.submit("submit")
80
124
 
81
- self._check_submission_problem(resp, "{} is already used.".format(restriction_area.name))
125
+ self._check_submission_problem(resp, f"{restriction_area.name} is already used.")
82
126
 
83
127
  def test_edit(self, test_app, restriction_area_test_data, dbsession):
84
128
  restriction_area = restriction_area_test_data["restriction_areas"][0]
85
129
  roles = restriction_area_test_data["roles"]
86
130
 
131
+ # Ensure restriction_area.layers is loaded with relationship "order_by"
132
+ dbsession.expire(restriction_area)
133
+
87
134
  form = self.get_item(test_app, restriction_area.id).form
88
135
 
89
136
  assert str(restriction_area.id) == self.get_first_field_named(form, "id").value
@@ -100,6 +147,14 @@ class TestRestrictionAreaViews(AbstractViewsTests):
100
147
  )
101
148
  assert expected.almost_equals(shape(json.loads(form["area"].value)), decimal=0)
102
149
  self._check_roles(form, roles, restriction_area)
150
+ self.check_children(
151
+ form,
152
+ "layers",
153
+ [
154
+ {"label": layer.name, "values": {"id": str(layer.id)}}
155
+ for layer in sorted(restriction_area.layers, key=lambda l: l.name)
156
+ ],
157
+ )
103
158
 
104
159
  form["description"] = "new_description"
105
160
  form["roles"] = [roles[i].id for i in range(0, 3)]
@@ -107,14 +162,14 @@ class TestRestrictionAreaViews(AbstractViewsTests):
107
162
 
108
163
  dbsession.expire(restriction_area)
109
164
  assert restriction_area.description == "new_description"
110
- assert set(restriction_area.roles) == set([roles[i] for i in range(0, 3)])
165
+ assert set(restriction_area.roles) == {roles[i] for i in range(0, 3)}
111
166
 
112
167
  def test_delete(self, test_app, restriction_area_test_data, dbsession):
113
168
  from c2cgeoportal_commons.models.main import RestrictionArea
114
169
 
115
170
  restriction_area = restriction_area_test_data["restriction_areas"][0]
116
171
  deleted_id = restriction_area.id
117
- test_app.delete("/admin/restriction_areas/{}".format(deleted_id), status=200)
172
+ test_app.delete(f"/admin/restriction_areas/{deleted_id}", status=200)
118
173
  assert dbsession.query(RestrictionArea).get(deleted_id) is None
119
174
 
120
175
  def test_duplicate(self, restriction_area_test_data, test_app, dbsession):
@@ -123,12 +178,21 @@ class TestRestrictionAreaViews(AbstractViewsTests):
123
178
  restriction_area = restriction_area_test_data["restriction_areas"][3]
124
179
  roles = restriction_area_test_data["roles"]
125
180
 
126
- form = test_app.get(
127
- "/admin/restriction_areas/{}/duplicate".format(restriction_area.id), status=200
128
- ).form
181
+ # Ensure restriction_area.layers is loaded with relationship "order_by"
182
+ dbsession.expire(restriction_area)
183
+
184
+ form = test_app.get(f"/admin/restriction_areas/{restriction_area.id}/duplicate", status=200).form
129
185
 
130
186
  assert "" == self.get_first_field_named(form, "id").value
131
187
  self._check_roles(form, roles, restriction_area)
188
+ self.check_children(
189
+ form,
190
+ "layers",
191
+ [
192
+ {"label": layer.name, "values": {"id": str(layer.id)}}
193
+ for layer in sorted(restriction_area.layers, key=lambda l: l.name)
194
+ ],
195
+ )
132
196
 
133
197
  self.set_first_field_named(form, "name", "clone")
134
198
  resp = form.submit("submit")