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.
- c2cgeoportal_admin/__init__.py +19 -12
- c2cgeoportal_admin/lib/__init__.py +0 -0
- c2cgeoportal_admin/lib/lingua_extractor.py +77 -0
- c2cgeoportal_admin/lib/ogcserver_synchronizer.py +409 -0
- c2cgeoportal_admin/py.typed +0 -0
- c2cgeoportal_admin/routes.py +18 -10
- c2cgeoportal_admin/schemas/dimensions.py +13 -11
- c2cgeoportal_admin/schemas/functionalities.py +63 -22
- c2cgeoportal_admin/schemas/interfaces.py +23 -19
- c2cgeoportal_admin/schemas/metadata.py +121 -47
- c2cgeoportal_admin/schemas/restriction_areas.py +22 -20
- c2cgeoportal_admin/schemas/roles.py +8 -6
- c2cgeoportal_admin/schemas/treegroup.py +84 -18
- c2cgeoportal_admin/schemas/treeitem.py +2 -3
- c2cgeoportal_admin/static/layertree.css +26 -4
- c2cgeoportal_admin/static/navbar.css +59 -36
- c2cgeoportal_admin/static/theme.css +48 -11
- c2cgeoportal_admin/subscribers.py +3 -3
- c2cgeoportal_admin/templates/404.jinja2 +23 -0
- c2cgeoportal_admin/templates/edit.jinja2 +23 -0
- c2cgeoportal_admin/templates/home.jinja2 +23 -0
- c2cgeoportal_admin/templates/index.jinja2 +23 -0
- c2cgeoportal_admin/templates/layertree.jinja2 +55 -11
- c2cgeoportal_admin/templates/layout.jinja2 +23 -0
- c2cgeoportal_admin/templates/navigation_navbar.jinja2 +56 -0
- c2cgeoportal_admin/templates/ogcserver_synchronize.jinja2 +90 -0
- c2cgeoportal_admin/templates/widgets/child.pt +35 -3
- c2cgeoportal_admin/templates/widgets/children.pt +121 -92
- c2cgeoportal_admin/templates/widgets/dimension.pt +23 -0
- c2cgeoportal_admin/templates/widgets/dimensions.pt +23 -0
- c2cgeoportal_admin/templates/widgets/functionality_fields.pt +51 -0
- c2cgeoportal_admin/templates/widgets/layer_fields.pt +23 -0
- c2cgeoportal_admin/templates/widgets/layer_group_fields.pt +23 -0
- c2cgeoportal_admin/templates/widgets/layer_v1_fields.pt +23 -0
- c2cgeoportal_admin/templates/widgets/metadata.pt +30 -1
- c2cgeoportal_admin/templates/widgets/metadatas.pt +23 -0
- c2cgeoportal_admin/templates/widgets/ogcserver_fields.pt +23 -0
- c2cgeoportal_admin/templates/widgets/restriction_area_fields.pt +25 -9
- c2cgeoportal_admin/templates/widgets/role_fields.pt +52 -25
- c2cgeoportal_admin/templates/widgets/theme_fields.pt +23 -0
- c2cgeoportal_admin/templates/widgets/user_fields.pt +23 -0
- c2cgeoportal_admin/views/dimension_layers.py +7 -6
- c2cgeoportal_admin/views/functionalities.py +31 -5
- c2cgeoportal_admin/views/home.py +5 -5
- c2cgeoportal_admin/views/interfaces.py +8 -8
- c2cgeoportal_admin/views/layer_groups.py +9 -11
- c2cgeoportal_admin/views/layers.py +8 -7
- c2cgeoportal_admin/views/layers_vectortiles.py +30 -10
- c2cgeoportal_admin/views/layers_wms.py +45 -37
- c2cgeoportal_admin/views/layers_wmts.py +39 -33
- c2cgeoportal_admin/views/layertree.py +34 -26
- c2cgeoportal_admin/views/oauth2_clients.py +89 -0
- c2cgeoportal_admin/views/ogc_servers.py +130 -27
- c2cgeoportal_admin/views/restriction_areas.py +50 -8
- c2cgeoportal_admin/views/roles.py +60 -8
- c2cgeoportal_admin/views/themes.py +15 -14
- c2cgeoportal_admin/views/themes_ordering.py +38 -18
- c2cgeoportal_admin/views/treeitems.py +12 -11
- c2cgeoportal_admin/views/users.py +7 -5
- c2cgeoportal_admin/widgets.py +79 -28
- {c2cgeoportal_admin-2.5.0.100.dist-info → c2cgeoportal_admin-2.7.1.156.dist-info}/METADATA +16 -11
- c2cgeoportal_admin-2.7.1.156.dist-info/RECORD +92 -0
- {c2cgeoportal_admin-2.5.0.100.dist-info → c2cgeoportal_admin-2.7.1.156.dist-info}/WHEEL +1 -1
- c2cgeoportal_admin-2.7.1.156.dist-info/entry_points.txt +5 -0
- tests/__init__.py +23 -18
- tests/conftest.py +4 -15
- tests/test_edit_url.py +16 -18
- tests/test_functionalities.py +23 -10
- tests/test_interface.py +8 -8
- tests/test_layer_groups.py +15 -23
- tests/test_layers_vectortiles.py +16 -20
- tests/test_layers_wms.py +37 -75
- tests/test_layers_wmts.py +20 -24
- tests/test_layertree.py +107 -100
- tests/test_learn.py +1 -1
- tests/test_lingua_extractor_config.py +66 -0
- tests/test_main.py +4 -2
- tests/test_metadatas.py +79 -70
- tests/test_oauth2_clients.py +157 -0
- tests/test_ogc_servers.py +51 -7
- tests/test_restriction_areas.py +81 -17
- tests/test_role.py +110 -76
- tests/test_themes.py +44 -37
- tests/test_themes_ordering.py +1 -1
- tests/test_treegroup.py +2 -2
- tests/test_user.py +31 -64
- tests/themes_ordering.py +1 -1
- c2cgeoportal_admin/templates/navigation_vertical.jinja2 +0 -10
- c2cgeoportal_admin-2.5.0.100.dist-info/RECORD +0 -84
- c2cgeoportal_admin-2.5.0.100.dist-info/entry_points.txt +0 -3
- {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
|
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,
|
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
|
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
|
-
{
|
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-{
|
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, "{}/{
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
"""
|
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/{
|
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_{}"
|
21
|
-
server.url = "https://somebasicurl_{}.com"
|
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/{
|
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/{}"
|
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"
|
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"
|
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."
|
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
|
+
]
|
tests/test_restriction_areas.py
CHANGED
@@ -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
|
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
|
-
|
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_{}"
|
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_{}"
|
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 {
|
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(
|
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",
|
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"
|
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."
|
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) ==
|
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/{}"
|
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
|
-
|
127
|
-
|
128
|
-
|
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")
|