c2cgeoportal-admin 2.5.0.100__py3-none-any.whl → 2.9rc44__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. c2cgeoportal_admin/__init__.py +44 -14
  2. c2cgeoportal_admin/lib/__init__.py +0 -0
  3. c2cgeoportal_admin/lib/lingva_extractor.py +77 -0
  4. c2cgeoportal_admin/lib/ogcserver_synchronizer.py +410 -0
  5. c2cgeoportal_admin/py.typed +0 -0
  6. c2cgeoportal_admin/routes.py +30 -11
  7. c2cgeoportal_admin/schemas/dimensions.py +17 -11
  8. c2cgeoportal_admin/schemas/functionalities.py +60 -22
  9. c2cgeoportal_admin/schemas/interfaces.py +27 -19
  10. c2cgeoportal_admin/schemas/metadata.py +122 -48
  11. c2cgeoportal_admin/schemas/restriction_areas.py +26 -20
  12. c2cgeoportal_admin/schemas/roles.py +13 -7
  13. c2cgeoportal_admin/schemas/treegroup.py +90 -20
  14. c2cgeoportal_admin/schemas/treeitem.py +3 -4
  15. c2cgeoportal_admin/static/layertree.css +26 -4
  16. c2cgeoportal_admin/static/navbar.css +59 -36
  17. c2cgeoportal_admin/static/theme.css +51 -11
  18. c2cgeoportal_admin/subscribers.py +3 -3
  19. c2cgeoportal_admin/templates/404.jinja2 +41 -2
  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/__init__.py +29 -0
  43. c2cgeoportal_admin/views/dimension_layers.py +14 -9
  44. c2cgeoportal_admin/views/functionalities.py +52 -18
  45. c2cgeoportal_admin/views/home.py +5 -5
  46. c2cgeoportal_admin/views/interfaces.py +29 -21
  47. c2cgeoportal_admin/views/layer_groups.py +36 -25
  48. c2cgeoportal_admin/views/layers.py +17 -13
  49. c2cgeoportal_admin/views/layers_cog.py +135 -0
  50. c2cgeoportal_admin/views/layers_vectortiles.py +62 -27
  51. c2cgeoportal_admin/views/layers_wms.py +61 -36
  52. c2cgeoportal_admin/views/layers_wmts.py +54 -32
  53. c2cgeoportal_admin/views/layertree.py +37 -28
  54. c2cgeoportal_admin/views/logged_views.py +83 -0
  55. c2cgeoportal_admin/views/logs.py +91 -0
  56. c2cgeoportal_admin/views/oauth2_clients.py +96 -0
  57. c2cgeoportal_admin/views/ogc_servers.py +192 -21
  58. c2cgeoportal_admin/views/restriction_areas.py +78 -25
  59. c2cgeoportal_admin/views/roles.py +88 -25
  60. c2cgeoportal_admin/views/themes.py +47 -35
  61. c2cgeoportal_admin/views/themes_ordering.py +44 -24
  62. c2cgeoportal_admin/views/treeitems.py +21 -17
  63. c2cgeoportal_admin/views/users.py +46 -26
  64. c2cgeoportal_admin/widgets.py +79 -28
  65. {c2cgeoportal_admin-2.5.0.100.dist-info → c2cgeoportal_admin-2.9rc44.dist-info}/METADATA +15 -13
  66. c2cgeoportal_admin-2.9rc44.dist-info/RECORD +97 -0
  67. {c2cgeoportal_admin-2.5.0.100.dist-info → c2cgeoportal_admin-2.9rc44.dist-info}/WHEEL +1 -1
  68. c2cgeoportal_admin-2.9rc44.dist-info/entry_points.txt +5 -0
  69. tests/__init__.py +36 -27
  70. tests/conftest.py +23 -24
  71. tests/test_edit_url.py +16 -19
  72. tests/test_functionalities.py +52 -14
  73. tests/test_home.py +0 -1
  74. tests/test_interface.py +35 -12
  75. tests/test_layer_groups.py +58 -32
  76. tests/test_layers_cog.py +243 -0
  77. tests/test_layers_vectortiles.py +46 -30
  78. tests/test_layers_wms.py +77 -82
  79. tests/test_layers_wmts.py +51 -30
  80. tests/test_layertree.py +107 -101
  81. tests/test_learn.py +1 -1
  82. tests/test_left_menu.py +0 -1
  83. tests/test_lingva_extractor_config.py +64 -0
  84. tests/test_logs.py +102 -0
  85. tests/test_main.py +4 -2
  86. tests/test_metadatas.py +79 -71
  87. tests/test_oauth2_clients.py +186 -0
  88. tests/test_ogc_servers.py +110 -28
  89. tests/test_restriction_areas.py +109 -20
  90. tests/test_role.py +142 -82
  91. tests/test_themes.py +75 -41
  92. tests/test_themes_ordering.py +1 -2
  93. tests/test_treegroup.py +2 -2
  94. tests/test_user.py +72 -70
  95. tests/themes_ordering.py +1 -2
  96. c2cgeoportal_admin/templates/navigation_vertical.jinja2 +0 -10
  97. c2cgeoportal_admin-2.5.0.100.dist-info/RECORD +0 -84
  98. c2cgeoportal_admin-2.5.0.100.dist-info/entry_points.txt +0 -3
  99. {c2cgeoportal_admin-2.5.0.100.dist-info → c2cgeoportal_admin-2.9rc44.dist-info}/top_level.txt +0 -0
@@ -4,40 +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):
40
-
52
+ class TestRestrictionAreaViews(TestTreeGroup):
41
53
  _prefix = "/admin/restriction_areas"
42
54
 
43
55
  def test_index_rendering(self, test_app):
@@ -59,31 +71,75 @@ class TestRestrictionAreaViews(AbstractViewsTests):
59
71
  def test_grid_search(self, test_app):
60
72
  self.check_search(test_app, "restrictionarea_1", total=1)
61
73
 
62
- def test_submit_new(self, dbsession, test_app):
63
- from c2cgeoportal_commons.models.main import RestrictionArea
74
+ def test_submit_new(self, dbsession, test_app, restriction_area_test_data):
75
+ from c2cgeoportal_commons.models.main import Log, LogAction, RestrictionArea
76
+
77
+ roles = restriction_area_test_data["roles"]
78
+ layers = restriction_area_test_data["layers"]
64
79
 
65
80
  resp = test_app.post(
66
- "/admin/restriction_areas/new", {"name": "new_name", "description": "new_description"}, status=302
81
+ "/admin/restriction_areas/new",
82
+ (
83
+ ("_charset_", "UTF-8"),
84
+ ("__formid__", "deform"),
85
+ ("id", ""),
86
+ ("name", "new_name"),
87
+ ("description", "new_description"),
88
+ ("readwrite", "true"),
89
+ ("area", ""),
90
+ ("__start__", "roles:sequence"),
91
+ ("roles", str(roles[0].id)),
92
+ ("roles", str(roles[1].id)),
93
+ ("__end__", "roles:sequence"),
94
+ ("__start__", "layers:sequence"),
95
+ ("__start__", "layer:mapping"),
96
+ ("id", str(layers[0].id)),
97
+ ("__end__", "layer:mapping"),
98
+ ("__start__", "layer:mapping"),
99
+ ("id", str(layers[1].id)),
100
+ ("__end__", "layer:mapping"),
101
+ ("__end__", "layers:sequence"),
102
+ ("formsubmit", "formsubmit"),
103
+ ),
104
+ status=302,
67
105
  )
68
106
 
69
107
  restriction_area = dbsession.query(RestrictionArea).filter(RestrictionArea.name == "new_name").one()
70
108
  assert str(restriction_area.id) == re.match(
71
109
  r"http://localhost/admin/restriction_areas/(.*)\?msg_col=submit_ok", resp.location
72
110
  ).group(1)
111
+
73
112
  assert restriction_area.name == "new_name"
113
+ assert restriction_area.description == "new_description"
114
+ assert restriction_area.readwrite
115
+ assert set(restriction_area.roles) == {roles[0], roles[1]}
116
+ assert set(restriction_area.layers) == {layers[0], layers[1]}
117
+
118
+ log = dbsession.query(Log).one()
119
+ assert log.date != None
120
+ assert log.action == LogAction.INSERT
121
+ assert log.element_type == "restrictionarea"
122
+ assert log.element_id == restriction_area.id
123
+ assert log.element_name == restriction_area.name
124
+ assert log.username == "test_user"
74
125
 
75
126
  def test_unicity_validator(self, restriction_area_test_data, test_app):
76
127
  restriction_area = restriction_area_test_data["restriction_areas"][2]
77
128
 
78
- resp = test_app.get("/admin/restriction_areas/{}/duplicate".format(restriction_area.id), status=200)
129
+ resp = test_app.get(f"/admin/restriction_areas/{restriction_area.id}/duplicate", status=200)
79
130
  resp = resp.form.submit("submit")
80
131
 
81
- self._check_submission_problem(resp, "{} is already used.".format(restriction_area.name))
132
+ self._check_submission_problem(resp, f"{restriction_area.name} is already used.")
82
133
 
83
134
  def test_edit(self, test_app, restriction_area_test_data, dbsession):
135
+ from c2cgeoportal_commons.models.main import Log, LogAction
136
+
84
137
  restriction_area = restriction_area_test_data["restriction_areas"][0]
85
138
  roles = restriction_area_test_data["roles"]
86
139
 
140
+ # Ensure restriction_area.layers is loaded with relationship "order_by"
141
+ dbsession.expire(restriction_area)
142
+
87
143
  form = self.get_item(test_app, restriction_area.id).form
88
144
 
89
145
  assert str(restriction_area.id) == self.get_first_field_named(form, "id").value
@@ -100,6 +156,14 @@ class TestRestrictionAreaViews(AbstractViewsTests):
100
156
  )
101
157
  assert expected.almost_equals(shape(json.loads(form["area"].value)), decimal=0)
102
158
  self._check_roles(form, roles, restriction_area)
159
+ self.check_children(
160
+ form,
161
+ "layers",
162
+ [
163
+ {"label": layer.name, "values": {"id": str(layer.id)}}
164
+ for layer in sorted(restriction_area.layers, key=lambda l: l.name)
165
+ ],
166
+ )
103
167
 
104
168
  form["description"] = "new_description"
105
169
  form["roles"] = [roles[i].id for i in range(0, 3)]
@@ -107,28 +171,53 @@ class TestRestrictionAreaViews(AbstractViewsTests):
107
171
 
108
172
  dbsession.expire(restriction_area)
109
173
  assert restriction_area.description == "new_description"
110
- assert set(restriction_area.roles) == set([roles[i] for i in range(0, 3)])
174
+ assert set(restriction_area.roles) == {roles[i] for i in range(0, 3)}
175
+
176
+ log = dbsession.query(Log).one()
177
+ assert log.date != None
178
+ assert log.action == LogAction.UPDATE
179
+ assert log.element_type == "restrictionarea"
180
+ assert log.element_id == restriction_area.id
181
+ assert log.element_name == restriction_area.name
182
+ assert log.username == "test_user"
111
183
 
112
184
  def test_delete(self, test_app, restriction_area_test_data, dbsession):
113
- from c2cgeoportal_commons.models.main import RestrictionArea
185
+ from c2cgeoportal_commons.models.main import Log, LogAction, RestrictionArea
114
186
 
115
187
  restriction_area = restriction_area_test_data["restriction_areas"][0]
116
188
  deleted_id = restriction_area.id
117
- test_app.delete("/admin/restriction_areas/{}".format(deleted_id), status=200)
189
+ test_app.delete(f"/admin/restriction_areas/{deleted_id}", status=200)
118
190
  assert dbsession.query(RestrictionArea).get(deleted_id) is None
119
191
 
192
+ log = dbsession.query(Log).one()
193
+ assert log.date != None
194
+ assert log.action == LogAction.DELETE
195
+ assert log.element_type == "restrictionarea"
196
+ assert log.element_id == restriction_area.id
197
+ assert log.element_name == restriction_area.name
198
+ assert log.username == "test_user"
199
+
120
200
  def test_duplicate(self, restriction_area_test_data, test_app, dbsession):
121
201
  from c2cgeoportal_commons.models.main import RestrictionArea
122
202
 
123
203
  restriction_area = restriction_area_test_data["restriction_areas"][3]
124
204
  roles = restriction_area_test_data["roles"]
125
205
 
126
- form = test_app.get(
127
- "/admin/restriction_areas/{}/duplicate".format(restriction_area.id), status=200
128
- ).form
206
+ # Ensure restriction_area.layers is loaded with relationship "order_by"
207
+ dbsession.expire(restriction_area)
208
+
209
+ form = test_app.get(f"/admin/restriction_areas/{restriction_area.id}/duplicate", status=200).form
129
210
 
130
211
  assert "" == self.get_first_field_named(form, "id").value
131
212
  self._check_roles(form, roles, restriction_area)
213
+ self.check_children(
214
+ form,
215
+ "layers",
216
+ [
217
+ {"label": layer.name, "values": {"id": str(layer.id)}}
218
+ for layer in sorted(restriction_area.layers, key=lambda l: l.name)
219
+ ],
220
+ )
132
221
 
133
222
  self.set_first_field_named(form, "name", "clone")
134
223
  resp = form.submit("submit")
tests/test_role.py CHANGED
@@ -3,14 +3,13 @@
3
3
  import json
4
4
  import re
5
5
 
6
+ import pyramid.httpexceptions
7
+ import pytest
6
8
  from geoalchemy2.shape import from_shape, to_shape
7
9
  from pyramid.testing import DummyRequest
8
- import pytest
9
- from selenium.webdriver.common.by import By
10
10
  from shapely.geometry import Polygon, box, shape
11
11
 
12
- from . import AbstractViewsTests, skip_if_ci
13
- from .selenium.page import IndexPage
12
+ from .test_treegroup import TestTreeGroup
14
13
 
15
14
 
16
15
  @pytest.fixture(scope="function")
@@ -18,20 +17,21 @@ from .selenium.page import IndexPage
18
17
  def roles_test_data(dbsession, transact):
19
18
  del transact
20
19
 
21
- from c2cgeoportal_commons.models.main import Role, Functionality, RestrictionArea
20
+ from c2cgeoportal_commons.models.main import Functionality, RestrictionArea, Role
22
21
  from c2cgeoportal_commons.models.static import User
23
22
 
23
+ # Note that "default_basemap" is not relevant for roles
24
24
  functionalities = {}
25
- for name in ("default_basemap", "location"):
25
+ for name in ("default_basemap", "default_theme", "print_template"):
26
26
  functionalities[name] = []
27
27
  for v in range(0, 4):
28
- functionality = Functionality(name=name, value="value_{}".format(v))
28
+ functionality = Functionality(name=name, value=f"value_{v}")
29
29
  dbsession.add(functionality)
30
30
  functionalities[name].append(functionality)
31
31
 
32
32
  restrictionareas = []
33
33
  for i in range(0, 5):
34
- restrictionarea = RestrictionArea(name="restrictionarea_{}".format(i))
34
+ restrictionarea = RestrictionArea(name=f"restrictionarea_{i}")
35
35
  dbsession.add(restrictionarea)
36
36
  restrictionareas.append(restrictionarea)
37
37
 
@@ -39,9 +39,9 @@ def roles_test_data(dbsession, transact):
39
39
  for i in range(0, 23):
40
40
  role = Role("secretary_" + str(i))
41
41
  role.functionalities = [
42
- functionalities["default_basemap"][0],
43
- functionalities["location"][0],
44
- functionalities["location"][1],
42
+ functionalities["default_theme"][0],
43
+ functionalities["print_template"][0],
44
+ functionalities["print_template"][1],
45
45
  ]
46
46
  role.restrictionareas = [restrictionareas[0], restrictionareas[1]]
47
47
  role.extent = from_shape(box(485869.5728, 76443.1884, 837076.5648, 299941.7864), srid=21781)
@@ -68,8 +68,7 @@ def roles_test_data(dbsession, transact):
68
68
 
69
69
 
70
70
  @pytest.mark.usefixtures("roles_test_data", "test_app")
71
- class TestRole(AbstractViewsTests):
72
-
71
+ class TestRole(TestTreeGroup):
73
72
  _prefix = "/admin/roles"
74
73
 
75
74
  def test_index_rendering(self, test_app):
@@ -87,24 +86,90 @@ class TestRole(AbstractViewsTests):
87
86
  ]
88
87
  self.check_grid_headers(resp, expected)
89
88
 
90
- @pytest.mark.skip(reason="Translation is not finished")
89
+ @pytest.mark.skip(reason="Translation seems not available in tests")
91
90
  def test_index_rendering_fr(self, test_app):
92
91
  resp = self.get(test_app, locale="fr")
93
92
 
94
- self.check_left_menu(resp, "Roles")
93
+ self.check_left_menu(resp, "Rôles")
95
94
 
96
95
  expected = [
97
- ("_id_", "", "false"),
98
- ("name", "Name"),
96
+ ("actions", "", "false"),
97
+ ("id", "id", "true"),
98
+ ("name", "Nom"),
99
99
  ("description", "Description"),
100
- ("functionalities", "Fonctionalités", "false"),
101
- ("restrictionareas", "Aires de restriction", "false"),
100
+ ("functionalities", "Fonctionnalités", "false"),
101
+ ("restrictionareas", "Zones de restriction", "false"),
102
102
  ]
103
- self.check_grid_headers(resp, expected)
103
+ self.check_grid_headers(resp, expected, new="Nouveau")
104
+
105
+ def test_submit_new(self, dbsession, test_app, roles_test_data):
106
+ from c2cgeoportal_commons.models.main import Log, LogAction, Role
107
+
108
+ roles_test_data["roles"]
109
+ functionalities = roles_test_data["functionalities"]
110
+ restrictionareas = roles_test_data["restrictionareas"]
111
+ users = roles_test_data["users"]
112
+
113
+ resp = test_app.post(
114
+ "/admin/roles/new",
115
+ (
116
+ ("_charset_", "UTF-8"),
117
+ ("__formid__", "deform"),
118
+ ("id", ""),
119
+ ("name", "new_name"),
120
+ ("description", "new_description"),
121
+ ("extent", ""),
122
+ ("__start__", "functionalities:sequence"),
123
+ ("functionalities", str(functionalities["default_basemap"][0].id)),
124
+ ("functionalities", str(functionalities["print_template"][1].id)),
125
+ ("__end__", "functionalities:sequence"),
126
+ ("__start__", "restrictionareas:sequence"),
127
+ ("restrictionareas", str(restrictionareas[0].id)),
128
+ ("restrictionareas", str(restrictionareas[1].id)),
129
+ ("__end__", "restrictionareas:sequence"),
130
+ ("__start__", "users:sequence"),
131
+ ("__start__", "user:mapping"),
132
+ ("id", str(users[0].id)),
133
+ ("__end__", "user:mapping"),
134
+ ("__start__", "user:mapping"),
135
+ ("id", str(users[1].id)),
136
+ ("__end__", "user:mapping"),
137
+ ("__end__", "users:sequence"),
138
+ ("formsubmit", "formsubmit"),
139
+ ),
140
+ status=302,
141
+ )
142
+
143
+ role = dbsession.query(Role).filter(Role.name == "new_name").one()
144
+ assert str(role.id) == re.match(
145
+ r"http://localhost/admin/roles/(.*)\?msg_col=submit_ok", resp.location
146
+ ).group(1)
147
+
148
+ assert role.name == "new_name"
149
+ assert role.description == "new_description"
150
+ assert set(role.functionalities) == {
151
+ functionalities["default_basemap"][0],
152
+ functionalities["print_template"][1],
153
+ }
154
+ assert set(role.restrictionareas) == {restrictionareas[0], restrictionareas[1]}
155
+ assert set(role.users) == {users[0], users[1]}
156
+
157
+ log = dbsession.query(Log).one()
158
+ assert log.date != None
159
+ assert log.action == LogAction.INSERT
160
+ assert log.element_type == "role"
161
+ assert log.element_id == role.id
162
+ assert log.element_name == role.name
163
+ assert log.username == "test_user"
104
164
 
105
165
  def test_edit(self, dbsession, test_app, roles_test_data):
166
+ from c2cgeoportal_commons.models.main import Log, LogAction
167
+
106
168
  role = roles_test_data["roles"][10]
107
169
 
170
+ # Ensure role.users is loaded with relationship "order_by"
171
+ dbsession.expire(role)
172
+
108
173
  form = self.get_item(test_app, role.id).form
109
174
 
110
175
  assert "secretary_10" == form["name"].value
@@ -121,30 +186,33 @@ class TestRole(AbstractViewsTests):
121
186
  assert expected.almost_equals(shape(json.loads(form["extent"].value)), decimal=0)
122
187
 
123
188
  functionalities = roles_test_data["functionalities"]
124
- assert set(
125
- (
126
- functionalities["default_basemap"][0].id,
127
- functionalities["location"][0].id,
128
- functionalities["location"][1].id,
129
- )
130
- ) == set(f.id for f in role.functionalities)
189
+ assert {
190
+ functionalities["default_theme"][0].id,
191
+ functionalities["print_template"][0].id,
192
+ functionalities["print_template"][1].id,
193
+ } == {f.id for f in role.functionalities}
131
194
  self.check_checkboxes(
132
195
  form,
133
196
  "functionalities",
134
197
  [
135
198
  {
136
- "label": "{}={}".format(f.name, f.value),
199
+ "label": f"{f.name}={f.value}",
137
200
  "value": str(f.id),
138
201
  "checked": f in role.functionalities,
139
202
  }
140
- for f in sum(
141
- [roles_test_data["functionalities"][name] for name in ("default_basemap", "location")], []
203
+ for f in sorted(
204
+ [
205
+ f
206
+ for f in sum(functionalities.values(), [])
207
+ if f.name in ("default_theme", "print_template")
208
+ ],
209
+ key=lambda f: (f.name, f.value),
142
210
  )
143
211
  ],
144
212
  )
145
213
 
146
214
  ras = roles_test_data["restrictionareas"]
147
- assert set((ras[0].id, ras[1].id)) == set(ra.id for ra in role.restrictionareas)
215
+ assert {ras[0].id, ras[1].id} == {ra.id for ra in role.restrictionareas}
148
216
  self.check_checkboxes(
149
217
  form,
150
218
  "restrictionareas",
@@ -154,6 +222,15 @@ class TestRole(AbstractViewsTests):
154
222
  ],
155
223
  )
156
224
 
225
+ self.check_children(
226
+ form,
227
+ "users",
228
+ [
229
+ {"label": user.username, "values": {"id": str(user.id)}}
230
+ for user in sorted(role.users, key=lambda u: u.username)
231
+ ],
232
+ )
233
+
157
234
  form["name"] = "New name"
158
235
  form["description"] = "New description"
159
236
  form["extent"] = json.dumps(
@@ -172,9 +249,9 @@ class TestRole(AbstractViewsTests):
172
249
  )
173
250
 
174
251
  functionality_ids = [
175
- roles_test_data["functionalities"]["default_basemap"][1].id,
176
- roles_test_data["functionalities"]["location"][1].id,
177
- roles_test_data["functionalities"]["default_basemap"][2].id,
252
+ roles_test_data["functionalities"]["default_theme"][1].id,
253
+ roles_test_data["functionalities"]["print_template"][1].id,
254
+ roles_test_data["functionalities"]["print_template"][2].id,
178
255
  ]
179
256
  form["functionalities"] = [str(id) for id in functionality_ids]
180
257
 
@@ -203,18 +280,26 @@ class TestRole(AbstractViewsTests):
203
280
  )
204
281
  assert expected.almost_equals(to_shape(role.extent), decimal=0)
205
282
 
206
- assert set(functionality_ids) == set([f.id for f in role.functionalities])
207
- assert set(ra_ids) == set([f.id for f in role.restrictionareas])
283
+ assert set(functionality_ids) == {f.id for f in role.functionalities}
284
+ assert set(ra_ids) == {f.id for f in role.restrictionareas}
285
+
286
+ log = dbsession.query(Log).one()
287
+ assert log.date != None
288
+ assert log.action == LogAction.UPDATE
289
+ assert log.element_type == "role"
290
+ assert log.element_id == role.id
291
+ assert log.element_name == role.name
292
+ assert log.username == "test_user"
208
293
 
209
294
  def test_duplicate(self, roles_test_data, test_app, dbsession):
210
295
  from c2cgeoportal_commons.models.main import Role
211
296
 
212
297
  role_proto = roles_test_data["roles"][7]
213
298
 
214
- resp = test_app.get("/admin/roles/{}/duplicate".format(role_proto.id), status=200)
299
+ resp = test_app.get(f"/admin/roles/{role_proto.id}/duplicate", status=200)
215
300
  form = resp.form
216
301
 
217
- assert "" == form["id"].value
302
+ assert "" == self.get_first_field_named(form, "id").value
218
303
  assert role_proto.name == form["name"].value
219
304
  assert role_proto.description == form["description"].value
220
305
  form["name"].value = "clone"
@@ -225,62 +310,37 @@ class TestRole(AbstractViewsTests):
225
310
  r"http://localhost/admin/roles/(.*)\?msg_col=submit_ok", resp.location
226
311
  ).group(1)
227
312
  assert role_proto.id != role.id
228
- assert role_proto.functionalities[2].name == role.functionalities[2].name
229
- assert role_proto.functionalities[2].value == role.functionalities[2].value
230
- assert role_proto.functionalities[2].id == role.functionalities[2].id
231
- assert role_proto.restrictionareas[1].name == role.restrictionareas[1].name
232
- assert role_proto.restrictionareas[1].id == role.restrictionareas[1].id
313
+ assert set(role_proto.functionalities) == set(role.functionalities)
314
+ assert set(role_proto.restrictionareas) == set(role.restrictionareas)
315
+ assert set(role_proto.users) == set(role.users)
233
316
 
234
317
  def test_delete(self, test_app, dbsession):
235
- from c2cgeoportal_commons.models.main import Role
318
+ from c2cgeoportal_commons.models.main import Log, LogAction, Role
236
319
 
237
- role_id = dbsession.query(Role.id).first().id
238
- test_app.delete("/admin/roles/{}".format(role_id), status=200)
239
- assert dbsession.query(Role).get(role_id) is None
320
+ role = dbsession.query(Role).first()
321
+ test_app.delete(f"/admin/roles/{role.id}", status=200)
322
+ assert dbsession.query(Role).get(role.id) is None
323
+
324
+ log = dbsession.query(Log).one()
325
+ assert log.date != None
326
+ assert log.action == LogAction.DELETE
327
+ assert log.element_type == "role"
328
+ assert log.element_id == role.id
329
+ assert log.element_name == role.name
330
+ assert log.username == "test_user"
240
331
 
241
332
  def test_unicity_validator(self, roles_test_data, test_app):
242
333
  role_proto = roles_test_data["roles"][7]
243
- resp = test_app.get("/admin/roles/{}/duplicate".format(role_proto.id), status=200)
334
+ resp = test_app.get(f"/admin/roles/{role_proto.id}/duplicate", status=200)
244
335
 
245
336
  resp = resp.form.submit("submit")
246
337
 
247
- self._check_submission_problem(resp, "{} is already used.".format(role_proto.name))
338
+ self._check_submission_problem(resp, f"{role_proto.name} is already used.")
248
339
 
249
340
  @pytest.mark.usefixtures("raise_db_error_on_query")
250
341
  def test_grid_dberror(self, dbsession):
251
342
  from c2cgeoportal_admin.views.roles import RoleViews
252
343
 
253
344
  request = DummyRequest(dbsession=dbsession, params={"offset": 0, "limit": 10})
254
- info = RoleViews(request).grid()
255
- assert info.status_int == 500, "Expected 500 status when db error"
256
-
257
-
258
- @skip_if_ci
259
- @pytest.mark.selenium
260
- @pytest.mark.usefixtures("selenium", "selenium_app", "roles_test_data")
261
- class TestRoleSelenium:
262
-
263
- _prefix = "/admin/roles"
264
-
265
- def test_index(self, selenium, selenium_app, roles_test_data, dbsession):
266
- from c2cgeoportal_commons.models.static import Role
267
-
268
- selenium.get(selenium_app + self._prefix)
269
-
270
- index_page = IndexPage(selenium)
271
- index_page.select_language("en")
272
- index_page.check_pagination_info("Showing 1 to 23 of 23 rows", 10)
273
- index_page.select_page_size(10)
274
- index_page.check_pagination_info("Showing 1 to 10 of 23 rows", 10)
275
-
276
- # delete
277
- role = roles_test_data["roles"][3]
278
- deleted_id = role.id
279
- index_page.click_delete(deleted_id)
280
- index_page.check_pagination_info("Showing 1 to 10 of 22 rows", 10)
281
- assert dbsession.query(Role).get(deleted_id) is None
282
-
283
- # edit
284
- role = roles_test_data["roles"][4]
285
- index_page.find_item_action(role.id, "edit").click()
286
- index_page.find_element(By.XPATH, "//canvas", timeout=5)
345
+ with pytest.raises(pyramid.httpexceptions.HTTPInternalServerError):
346
+ RoleViews(request).grid()