c2cgeoportal-admin 2.8.1.181__py3-none-any.whl → 2.9rc2__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 (49) hide show
  1. c2cgeoportal_admin/__init__.py +14 -6
  2. c2cgeoportal_admin/lib/{lingua_extractor.py → lingva_extractor.py} +6 -6
  3. c2cgeoportal_admin/lib/ogcserver_synchronizer.py +6 -5
  4. c2cgeoportal_admin/routes.py +12 -3
  5. c2cgeoportal_admin/schemas/dimensions.py +4 -2
  6. c2cgeoportal_admin/schemas/functionalities.py +9 -12
  7. c2cgeoportal_admin/schemas/interfaces.py +7 -3
  8. c2cgeoportal_admin/schemas/metadata.py +13 -13
  9. c2cgeoportal_admin/schemas/restriction_areas.py +5 -3
  10. c2cgeoportal_admin/schemas/roles.py +7 -3
  11. c2cgeoportal_admin/schemas/treegroup.py +14 -10
  12. c2cgeoportal_admin/schemas/treeitem.py +2 -2
  13. c2cgeoportal_admin/static/theme.css +3 -0
  14. c2cgeoportal_admin/views/dimension_layers.py +11 -7
  15. c2cgeoportal_admin/views/functionalities.py +25 -18
  16. c2cgeoportal_admin/views/interfaces.py +22 -15
  17. c2cgeoportal_admin/views/layer_groups.py +33 -20
  18. c2cgeoportal_admin/views/layers.py +12 -9
  19. c2cgeoportal_admin/views/layers_cog.py +135 -0
  20. c2cgeoportal_admin/views/layers_vectortiles.py +42 -27
  21. c2cgeoportal_admin/views/layers_wms.py +47 -32
  22. c2cgeoportal_admin/views/layers_wmts.py +46 -32
  23. c2cgeoportal_admin/views/layertree.py +9 -8
  24. c2cgeoportal_admin/views/logged_views.py +15 -12
  25. c2cgeoportal_admin/views/logs.py +9 -8
  26. c2cgeoportal_admin/views/oauth2_clients.py +26 -22
  27. c2cgeoportal_admin/views/ogc_servers.py +48 -34
  28. c2cgeoportal_admin/views/restriction_areas.py +29 -19
  29. c2cgeoportal_admin/views/roles.py +29 -19
  30. c2cgeoportal_admin/views/themes.py +35 -24
  31. c2cgeoportal_admin/views/themes_ordering.py +11 -11
  32. c2cgeoportal_admin/views/treeitems.py +13 -11
  33. c2cgeoportal_admin/views/users.py +37 -22
  34. c2cgeoportal_admin/widgets.py +3 -3
  35. {c2cgeoportal_admin-2.8.1.181.dist-info → c2cgeoportal_admin-2.9rc2.dist-info}/METADATA +3 -12
  36. {c2cgeoportal_admin-2.8.1.181.dist-info → c2cgeoportal_admin-2.9rc2.dist-info}/RECORD +48 -46
  37. {c2cgeoportal_admin-2.8.1.181.dist-info → c2cgeoportal_admin-2.9rc2.dist-info}/WHEEL +1 -1
  38. c2cgeoportal_admin-2.9rc2.dist-info/entry_points.txt +5 -0
  39. tests/__init__.py +13 -8
  40. tests/conftest.py +20 -10
  41. tests/test_layers_cog.py +243 -0
  42. tests/test_layers_vectortiles.py +2 -7
  43. tests/{test_lingua_extractor_config.py → test_lingva_extractor_config.py} +3 -3
  44. tests/test_logs.py +3 -4
  45. tests/test_oauth2_clients.py +3 -2
  46. tests/test_role.py +3 -2
  47. tests/test_user.py +8 -2
  48. c2cgeoportal_admin-2.8.1.181.dist-info/entry_points.txt +0 -6
  49. {c2cgeoportal_admin-2.8.1.181.dist-info → c2cgeoportal_admin-2.9rc2.dist-info}/top_level.txt +0 -0
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2017-2023, Camptocamp SA
1
+ # Copyright (c) 2017-2024, Camptocamp SA
2
2
  # All rights reserved.
3
3
 
4
4
  # Redistribution and use in source and binary forms, with or without
@@ -29,11 +29,22 @@
29
29
  import logging
30
30
  import threading
31
31
  from functools import partial
32
- from typing import Any, Dict, List, Union, cast
32
+ from typing import Any, cast
33
33
 
34
34
  import requests
35
+ from c2cgeoform import JSONDict
35
36
  from c2cgeoform.schema import GeoFormSchemaNode
36
- from c2cgeoform.views.abstract_views import AbstractViews, ItemAction, ListField, UserMessage
37
+ from c2cgeoform.views.abstract_views import (
38
+ AbstractViews,
39
+ DeleteResponse,
40
+ GridResponse,
41
+ IndexResponse,
42
+ ItemAction,
43
+ ListField,
44
+ ObjectResponse,
45
+ SaveResponse,
46
+ UserMessage,
47
+ )
37
48
  from deform.widget import FormWidget
38
49
  from pyramid.httpexceptions import HTTPFound
39
50
  from pyramid.view import view_config, view_defaults
@@ -51,11 +62,11 @@ _list_field = partial(ListField, OGCServer)
51
62
  base_schema = GeoFormSchemaNode(OGCServer, widget=FormWidget(fields_template="ogcserver_fields"))
52
63
  base_schema.add_unique_validator(OGCServer.name, OGCServer.id)
53
64
 
54
- LOG = logging.getLogger(__name__)
65
+ _LOG = logging.getLogger(__name__)
55
66
 
56
67
 
57
68
  @view_defaults(match_param="table=ogc_servers")
58
- class OGCServerViews(LoggedViews):
69
+ class OGCServerViews(LoggedViews[OGCServer]):
59
70
  """The OGC server administration view."""
60
71
 
61
72
  _list_fields = [
@@ -82,18 +93,18 @@ class OGCServerViews(LoggedViews):
82
93
  ),
83
94
  }
84
95
 
85
- @view_config(route_name="c2cgeoform_index", renderer="../templates/index.jinja2") # type: ignore
86
- def index(self) -> Dict[str, Any]:
87
- return super().index() # type: ignore
96
+ @view_config(route_name="c2cgeoform_index", renderer="../templates/index.jinja2") # type: ignore[misc]
97
+ def index(self) -> IndexResponse:
98
+ return super().index()
88
99
 
89
- @view_config(route_name="c2cgeoform_grid", renderer="fast_json") # type: ignore
90
- def grid(self) -> Dict[str, Any]:
91
- return super().grid() # type: ignore
100
+ @view_config(route_name="c2cgeoform_grid", renderer="fast_json") # type: ignore[misc]
101
+ def grid(self) -> GridResponse:
102
+ return super().grid()
92
103
 
93
104
  def schema(self) -> GeoFormSchemaNode:
94
105
  obj = self._get_object()
95
106
 
96
- schema = self._base_schema.clone()
107
+ schema = cast(GeoFormSchemaNode, self._base_schema.clone())
97
108
  schema["url"].description = Literal(
98
109
  _("{}<br>Current runtime value is: {}").format(
99
110
  schema["url"].description,
@@ -108,9 +119,9 @@ class OGCServerViews(LoggedViews):
108
119
  )
109
120
  return schema
110
121
 
111
- def _item_actions(self, item: OGCServer, readonly: bool = False) -> List[Any]:
112
- actions = cast(List[Any], super()._item_actions(item, readonly))
113
- if inspect(item).persistent:
122
+ def _item_actions(self, item: OGCServer, readonly: bool = False) -> list[Any]:
123
+ actions = cast(list[Any], super()._item_actions(item, readonly))
124
+ if inspect(item).persistent: # type: ignore[attr-defined]
114
125
  actions.insert(
115
126
  next((i for i, v in enumerate(actions) if v.name() == "delete")),
116
127
  ItemAction(
@@ -138,23 +149,24 @@ class OGCServerViews(LoggedViews):
138
149
  )
139
150
  return actions
140
151
 
141
- @view_config( # type: ignore
152
+ @view_config( # type: ignore[misc]
142
153
  route_name="c2cgeoform_item", request_method="GET", renderer="../templates/edit.jinja2"
143
154
  )
144
- def view(self) -> Dict[str, Any]:
145
- return super().edit(self.schema()) # type: ignore
155
+ def view(self) -> ObjectResponse:
156
+ return super().edit(self.schema())
146
157
 
147
- @view_config( # type: ignore
158
+ @view_config( # type: ignore[misc]
148
159
  route_name="c2cgeoform_item", request_method="POST", renderer="../templates/edit.jinja2"
149
160
  )
150
- def save(self) -> Union[HTTPFound, Dict[str, Any]]:
151
- result: Union[HTTPFound, Dict[str, Any]] = super().save()
161
+ def save(self) -> SaveResponse:
162
+ result = super().save()
152
163
  if isinstance(result, HTTPFound):
164
+ assert self._obj is not None
153
165
  self._update_cache(self._obj)
154
166
  return result
155
167
 
156
- @view_config(route_name="c2cgeoform_item", request_method="DELETE", renderer="fast_json") # type: ignore
157
- def delete(self) -> Dict[str, Any]:
168
+ @view_config(route_name="c2cgeoform_item", request_method="DELETE", renderer="fast_json") # type: ignore[misc]
169
+ def delete(self) -> DeleteResponse:
158
170
  obj = self._get_object()
159
171
  if len(obj.layers) > 0:
160
172
  return {
@@ -166,20 +178,20 @@ class OGCServerViews(LoggedViews):
166
178
  _query=[("msg_col", "cannot_delete")],
167
179
  ),
168
180
  }
169
- result: Dict[str, Any] = super().delete()
181
+ result = super().delete()
170
182
  cache_invalidate_cb()
171
183
  return result
172
184
 
173
- @view_config( # type: ignore
185
+ @view_config( # type: ignore[misc]
174
186
  route_name="c2cgeoform_item_duplicate", request_method="GET", renderer="../templates/edit.jinja2"
175
187
  )
176
- def duplicate(self) -> Dict[str, Any]:
177
- return super().duplicate() # type: ignore
188
+ def duplicate(self) -> ObjectResponse:
189
+ return super().duplicate()
178
190
 
179
- @view_config( # type: ignore
191
+ @view_config( # type: ignore[misc]
180
192
  route_name="ogcserver_synchronize", renderer="../templates/ogcserver_synchronize.jinja2"
181
193
  )
182
- def synchronize(self) -> Dict[str, Any]:
194
+ def synchronize(self) -> JSONDict:
183
195
  obj = self._get_object()
184
196
 
185
197
  if self._request.method == "GET":
@@ -202,6 +214,7 @@ class OGCServerViews(LoggedViews):
202
214
  clean=clean,
203
215
  )
204
216
 
217
+ ogc_server_id = obj.id
205
218
  if "check" in self._request.params:
206
219
  synchronizer.check_layers()
207
220
 
@@ -214,7 +227,7 @@ class OGCServerViews(LoggedViews):
214
227
  self._create_log(LogAction.SYNCHRONIZE, obj)
215
228
 
216
229
  return {
217
- "ogcserver": obj,
230
+ "ogcserver": self._request.dbsession.query(OGCServer).get(ogc_server_id),
218
231
  "success": True,
219
232
  "report": synchronizer.report(),
220
233
  }
@@ -235,11 +248,12 @@ class OGCServerViews(LoggedViews):
235
248
  _query={
236
249
  "came_from": self._request.current_route_url(),
237
250
  },
238
- )
251
+ ),
252
+ timeout=60,
239
253
  )
240
254
  if not response.ok:
241
- LOG.error("Error while cleaning the OGC server cache:\n%s", response.text)
255
+ _LOG.error("Error while cleaning the OGC server cache:\n%s", response.text)
242
256
 
243
257
  threading.Thread(target=update_cache).start()
244
- except Exception:
245
- LOG.error("Error on cleaning the OGC server cache", exc_info=True)
258
+ except Exception: # pylint: disable=broad-exception-caught
259
+ _LOG.error("Error on cleaning the OGC server cache", exc_info=True)
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2017-2023, Camptocamp SA
1
+ # Copyright (c) 2017-2024, Camptocamp SA
2
2
  # All rights reserved.
3
3
 
4
4
  # Redistribution and use in source and binary forms, with or without
@@ -29,8 +29,16 @@
29
29
  from functools import partial
30
30
 
31
31
  import colander
32
+ import sqlalchemy.orm.query
32
33
  from c2cgeoform.schema import GeoFormManyToManySchemaNode, GeoFormSchemaNode
33
- from c2cgeoform.views.abstract_views import ListField
34
+ from c2cgeoform.views.abstract_views import (
35
+ DeleteResponse,
36
+ GridResponse,
37
+ IndexResponse,
38
+ ListField,
39
+ ObjectResponse,
40
+ SaveResponse,
41
+ )
34
42
  from deform.widget import FormWidget
35
43
  from pyramid.view import view_config, view_defaults
36
44
  from sqlalchemy.orm import subqueryload
@@ -88,7 +96,7 @@ base_schema.add(
88
96
 
89
97
 
90
98
  @view_defaults(match_param="table=restriction_areas")
91
- class RestrictionAreaViews(LoggedViews):
99
+ class RestrictionAreaViews(LoggedViews[RestrictionArea]):
92
100
  """The restriction area administration view."""
93
101
 
94
102
  _list_fields = [
@@ -110,35 +118,37 @@ class RestrictionAreaViews(LoggedViews):
110
118
  _model = RestrictionArea
111
119
  _base_schema = base_schema
112
120
 
113
- def _base_query(self):
121
+ def _base_query(self) -> sqlalchemy.orm.query.Query[RestrictionArea]:
122
+ session = self._request.dbsession
123
+ assert isinstance(session, sqlalchemy.orm.Session)
114
124
  return (
115
- self._request.dbsession.query(RestrictionArea)
116
- .options(subqueryload("roles"))
117
- .options(subqueryload("layers"))
125
+ session.query(RestrictionArea)
126
+ .options(subqueryload(RestrictionArea.roles))
127
+ .options(subqueryload(RestrictionArea.layers))
118
128
  )
119
129
 
120
- @view_config(route_name="c2cgeoform_index", renderer="../templates/index.jinja2")
121
- def index(self):
130
+ @view_config(route_name="c2cgeoform_index", renderer="../templates/index.jinja2") # type: ignore[misc]
131
+ def index(self) -> IndexResponse:
122
132
  return super().index()
123
133
 
124
- @view_config(route_name="c2cgeoform_grid", renderer="fast_json")
125
- def grid(self):
134
+ @view_config(route_name="c2cgeoform_grid", renderer="fast_json") # type: ignore[misc]
135
+ def grid(self) -> GridResponse:
126
136
  return super().grid()
127
137
 
128
- @view_config(route_name="c2cgeoform_item", request_method="GET", renderer="../templates/edit.jinja2")
129
- def view(self):
138
+ @view_config(route_name="c2cgeoform_item", request_method="GET", renderer="../templates/edit.jinja2") # type: ignore[misc]
139
+ def view(self) -> ObjectResponse:
130
140
  return super().edit()
131
141
 
132
- @view_config(route_name="c2cgeoform_item", request_method="POST", renderer="../templates/edit.jinja2")
133
- def save(self):
142
+ @view_config(route_name="c2cgeoform_item", request_method="POST", renderer="../templates/edit.jinja2") # type: ignore[misc]
143
+ def save(self) -> SaveResponse:
134
144
  return super().save()
135
145
 
136
- @view_config(route_name="c2cgeoform_item", request_method="DELETE", renderer="fast_json")
137
- def delete(self):
146
+ @view_config(route_name="c2cgeoform_item", request_method="DELETE", renderer="fast_json") # type: ignore[misc]
147
+ def delete(self) -> DeleteResponse:
138
148
  return super().delete()
139
149
 
140
- @view_config(
150
+ @view_config( # type: ignore[misc]
141
151
  route_name="c2cgeoform_item_duplicate", request_method="GET", renderer="../templates/edit.jinja2"
142
152
  )
143
- def duplicate(self):
153
+ def duplicate(self) -> ObjectResponse:
144
154
  return super().duplicate()
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2017-2023, Camptocamp SA
1
+ # Copyright (c) 2017-2024, Camptocamp SA
2
2
  # All rights reserved.
3
3
 
4
4
  # Redistribution and use in source and binary forms, with or without
@@ -29,8 +29,16 @@
29
29
  from functools import partial
30
30
 
31
31
  import colander
32
+ import sqlalchemy.orm.query
32
33
  from c2cgeoform.schema import GeoFormManyToManySchemaNode, GeoFormSchemaNode
33
- from c2cgeoform.views.abstract_views import ListField
34
+ from c2cgeoform.views.abstract_views import (
35
+ DeleteResponse,
36
+ GridResponse,
37
+ IndexResponse,
38
+ ListField,
39
+ ObjectResponse,
40
+ SaveResponse,
41
+ )
34
42
  from deform.widget import FormWidget
35
43
  from pyramid.view import view_config, view_defaults
36
44
  from sqlalchemy.orm import subqueryload
@@ -100,7 +108,7 @@ base_schema["users"].children[0].description = ""
100
108
 
101
109
 
102
110
  @view_defaults(match_param="table=roles")
103
- class RoleViews(LoggedViews):
111
+ class RoleViews(LoggedViews[Role]):
104
112
  """The roles administration view."""
105
113
 
106
114
  _list_fields = [
@@ -119,35 +127,37 @@ class RoleViews(LoggedViews):
119
127
  _model = Role
120
128
  _base_schema = base_schema
121
129
 
122
- def _base_query(self):
130
+ def _base_query(self) -> sqlalchemy.orm.query.Query[Role]:
131
+ session = self._request.dbsession
132
+ assert isinstance(session, sqlalchemy.orm.Session)
123
133
  return (
124
- self._request.dbsession.query(Role)
125
- .options(subqueryload("functionalities"))
126
- .options(subqueryload("restrictionareas"))
134
+ session.query(Role)
135
+ .options(subqueryload(Role.functionalities))
136
+ .options(subqueryload(Role.restrictionareas))
127
137
  )
128
138
 
129
- @view_config(route_name="c2cgeoform_index", renderer="../templates/index.jinja2")
130
- def index(self):
139
+ @view_config(route_name="c2cgeoform_index", renderer="../templates/index.jinja2") # type: ignore[misc]
140
+ def index(self) -> IndexResponse:
131
141
  return super().index()
132
142
 
133
- @view_config(route_name="c2cgeoform_grid", renderer="fast_json")
134
- def grid(self):
143
+ @view_config(route_name="c2cgeoform_grid", renderer="fast_json") # type: ignore[misc]
144
+ def grid(self) -> GridResponse:
135
145
  return super().grid()
136
146
 
137
- @view_config(route_name="c2cgeoform_item", request_method="GET", renderer="../templates/edit.jinja2")
138
- def view(self):
147
+ @view_config(route_name="c2cgeoform_item", request_method="GET", renderer="../templates/edit.jinja2") # type: ignore[misc]
148
+ def view(self) -> ObjectResponse:
139
149
  return super().edit()
140
150
 
141
- @view_config(route_name="c2cgeoform_item", request_method="POST", renderer="../templates/edit.jinja2")
142
- def save(self):
151
+ @view_config(route_name="c2cgeoform_item", request_method="POST", renderer="../templates/edit.jinja2") # type: ignore[misc]
152
+ def save(self) -> SaveResponse:
143
153
  return super().save()
144
154
 
145
- @view_config(route_name="c2cgeoform_item", request_method="DELETE", renderer="fast_json")
146
- def delete(self):
155
+ @view_config(route_name="c2cgeoform_item", request_method="DELETE", renderer="fast_json") # type: ignore[misc]
156
+ def delete(self) -> DeleteResponse:
147
157
  return super().delete()
148
158
 
149
- @view_config(
159
+ @view_config( # type: ignore[misc]
150
160
  route_name="c2cgeoform_item_duplicate", request_method="GET", renderer="../templates/edit.jinja2"
151
161
  )
152
- def duplicate(self):
162
+ def duplicate(self) -> ObjectResponse:
153
163
  return super().duplicate()
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2017-2023, Camptocamp SA
1
+ # Copyright (c) 2017-2024, Camptocamp SA
2
2
  # All rights reserved.
3
3
 
4
4
  # Redistribution and use in source and binary forms, with or without
@@ -27,11 +27,18 @@
27
27
 
28
28
 
29
29
  from functools import partial
30
- from typing import Optional, cast
30
+ from typing import cast
31
31
 
32
32
  import sqlalchemy
33
33
  from c2cgeoform.schema import GeoFormSchemaNode
34
- from c2cgeoform.views.abstract_views import ListField
34
+ from c2cgeoform.views.abstract_views import (
35
+ DeleteResponse,
36
+ GridResponse,
37
+ IndexResponse,
38
+ ListField,
39
+ ObjectResponse,
40
+ SaveResponse,
41
+ )
35
42
  from deform.widget import FormWidget
36
43
  from pyramid.view import view_config, view_defaults
37
44
  from sqlalchemy.orm import subqueryload
@@ -57,11 +64,11 @@ base_schema.add_unique_validator(Theme.name, Theme.id)
57
64
 
58
65
 
59
66
  @view_defaults(match_param="table=themes")
60
- class ThemeViews(TreeItemViews):
67
+ class ThemeViews(TreeItemViews[Theme]):
61
68
  """The theme administration view."""
62
69
 
63
70
  _list_fields = (
64
- TreeItemViews._list_fields
71
+ TreeItemViews._list_fields # type: ignore[misc] # pylint: disable=protected-access
65
72
  + [
66
73
  _list_field("ordering"),
67
74
  _list_field("public"),
@@ -89,47 +96,51 @@ class ThemeViews(TreeItemViews):
89
96
  filter_column=Interface.name,
90
97
  ),
91
98
  ]
92
- + TreeItemViews._extra_list_fields_no_parents
99
+ + TreeItemViews._extra_list_fields_no_parents # pylint: disable=protected-access
93
100
  )
94
101
 
95
102
  _id_field = "id"
96
103
  _model = Theme
97
104
  _base_schema = base_schema
98
105
 
99
- def _base_query(self, query: Optional[sqlalchemy.orm.query.Query] = None) -> sqlalchemy.orm.query.Query:
100
- return super()._base_query(
106
+ def _base_query(self) -> sqlalchemy.orm.query.Query[Theme]:
107
+ return super()._sub_query(
101
108
  self._request.dbsession.query(Theme)
102
109
  .distinct()
103
- .outerjoin("interfaces")
110
+ .outerjoin(Theme.interfaces)
104
111
  .outerjoin(Theme.restricted_roles)
105
112
  .outerjoin(Theme.functionalities)
106
- .options(subqueryload("functionalities"))
107
- .options(subqueryload("restricted_roles"))
108
- .options(subqueryload("interfaces"))
113
+ .options(subqueryload(Theme.functionalities))
114
+ .options(subqueryload(Theme.restricted_roles))
115
+ .options(subqueryload(Theme.interfaces))
109
116
  )
110
117
 
111
- @view_config(route_name="c2cgeoform_index", renderer="../templates/index.jinja2")
112
- def index(self):
118
+ def _sub_query(self, query: sqlalchemy.orm.query.Query[Theme]) -> sqlalchemy.orm.query.Query[Theme]:
119
+ del query
120
+ return self._base_query()
121
+
122
+ @view_config(route_name="c2cgeoform_index", renderer="../templates/index.jinja2") # type: ignore[misc]
123
+ def index(self) -> IndexResponse:
113
124
  return super().index()
114
125
 
115
- @view_config(route_name="c2cgeoform_grid", renderer="fast_json")
116
- def grid(self):
126
+ @view_config(route_name="c2cgeoform_grid", renderer="fast_json") # type: ignore[misc]
127
+ def grid(self) -> GridResponse:
117
128
  return super().grid()
118
129
 
119
- @view_config(route_name="c2cgeoform_item", request_method="GET", renderer="../templates/edit.jinja2")
120
- def view(self):
130
+ @view_config(route_name="c2cgeoform_item", request_method="GET", renderer="../templates/edit.jinja2") # type: ignore[misc]
131
+ def view(self) -> ObjectResponse:
121
132
  return super().edit()
122
133
 
123
- @view_config(route_name="c2cgeoform_item", request_method="POST", renderer="../templates/edit.jinja2")
124
- def save(self):
134
+ @view_config(route_name="c2cgeoform_item", request_method="POST", renderer="../templates/edit.jinja2") # type: ignore[misc]
135
+ def save(self) -> SaveResponse:
125
136
  return super().save()
126
137
 
127
- @view_config(route_name="c2cgeoform_item", request_method="DELETE", renderer="fast_json")
128
- def delete(self):
138
+ @view_config(route_name="c2cgeoform_item", request_method="DELETE", renderer="fast_json") # type: ignore[misc]
139
+ def delete(self) -> DeleteResponse:
129
140
  return super().delete()
130
141
 
131
- @view_config(
142
+ @view_config( # type: ignore[misc]
132
143
  route_name="c2cgeoform_item_duplicate", request_method="GET", renderer="../templates/edit.jinja2"
133
144
  )
134
- def duplicate(self):
145
+ def duplicate(self) -> ObjectResponse:
135
146
  return super().duplicate()
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2017-2021, Camptocamp SA
1
+ # Copyright (c) 2017-2024, Camptocamp SA
2
2
  # All rights reserved.
3
3
 
4
4
  # Redistribution and use in source and binary forms, with or without
@@ -28,7 +28,7 @@
28
28
 
29
29
  import colander
30
30
  from c2cgeoform.schema import GeoFormSchemaNode
31
- from c2cgeoform.views.abstract_views import AbstractViews
31
+ from c2cgeoform.views.abstract_views import AbstractViews, ObjectResponse, SaveResponse
32
32
  from deform import ValidationFailure
33
33
  from pyramid.httpexceptions import HTTPFound
34
34
  from pyramid.view import view_config
@@ -39,7 +39,7 @@ from c2cgeoportal_admin.widgets import ChildrenWidget, ChildWidget
39
39
  from c2cgeoportal_commons.models.main import Theme, TreeItem
40
40
 
41
41
 
42
- class ThemeOrderSchema(GeoFormSchemaNode): # type: ignore # pylint: disable=abstract-method
42
+ class ThemeOrderSchema(GeoFormSchemaNode): # pylint: disable=abstract-method
43
43
  """The theme order schema."""
44
44
 
45
45
  def objectify(self, dict_, context=None):
@@ -68,7 +68,7 @@ def themes_validator(node, cstruct):
68
68
  )
69
69
 
70
70
 
71
- class ThemesOrderingSchema(colander.MappingSchema): # type: ignore
71
+ class ThemesOrderingSchema(colander.MappingSchema): # type: ignore[misc]
72
72
  """The theme ordering schema."""
73
73
 
74
74
  themes = colander.SequenceSchema(
@@ -91,13 +91,13 @@ class ThemesOrderingSchema(colander.MappingSchema): # type: ignore
91
91
  )
92
92
 
93
93
 
94
- class ThemesOrdering(AbstractViews): # type: ignore
94
+ class ThemesOrdering(AbstractViews[ThemesOrderingSchema]):
95
95
  """The theme ordering admin view."""
96
96
 
97
97
  _base_schema = ThemesOrderingSchema()
98
98
 
99
- @view_config(route_name="layertree_ordering", request_method="GET", renderer="../templates/edit.jinja2")
100
- def view(self):
99
+ @view_config(route_name="layertree_ordering", request_method="GET", renderer="../templates/edit.jinja2") # type: ignore[misc]
100
+ def view(self) -> ObjectResponse:
101
101
  form = self._form()
102
102
  dict_ = {
103
103
  "themes": [
@@ -108,13 +108,13 @@ class ThemesOrdering(AbstractViews): # type: ignore
108
108
  return {
109
109
  "title": form.title,
110
110
  "form": form,
111
- "form_render_args": (dict_,),
111
+ "form_render_args": [dict_],
112
112
  "form_render_kwargs": {"request": self._request, "actions": []},
113
113
  "deform_dependencies": form.get_widget_resources(),
114
114
  }
115
115
 
116
- @view_config(route_name="layertree_ordering", request_method="POST", renderer="../templates/edit.jinja2")
117
- def save(self):
116
+ @view_config(route_name="layertree_ordering", request_method="POST", renderer="../templates/edit.jinja2") # type: ignore[misc]
117
+ def save(self) -> SaveResponse:
118
118
  try:
119
119
  form = self._form()
120
120
  form_data = self._request.POST.items()
@@ -131,7 +131,7 @@ class ThemesOrdering(AbstractViews): # type: ignore
131
131
  return {
132
132
  "title": form.title,
133
133
  "form": e,
134
- "form_render_args": tuple(),
134
+ "form_render_args": [],
135
135
  "form_render_kwargs": {"request": self._request, "actions": []},
136
136
  "deform_dependencies": form.get_widget_resources(),
137
137
  }
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2017-2023, Camptocamp SA
1
+ # Copyright (c) 2017-2024, Camptocamp SA
2
2
  # All rights reserved.
3
3
 
4
4
  # Redistribution and use in source and binary forms, with or without
@@ -27,9 +27,10 @@
27
27
 
28
28
 
29
29
  from functools import partial
30
+ from typing import Generic, TypeVar
30
31
 
31
32
  import sqlalchemy
32
- from c2cgeoform.views.abstract_views import ListField
33
+ from c2cgeoform.views.abstract_views import ListField, SaveResponse
33
34
  from pyramid.view import view_config
34
35
  from sqlalchemy.orm import subqueryload
35
36
  from sqlalchemy.sql.functions import concat
@@ -40,7 +41,10 @@ from c2cgeoportal_commons.models.main import LayergroupTreeitem, Metadata, TreeG
40
41
  _list_field = partial(ListField, TreeItem)
41
42
 
42
43
 
43
- class TreeItemViews(LoggedViews):
44
+ _T = TypeVar("_T", bound=TreeItem)
45
+
46
+
47
+ class TreeItemViews(LoggedViews[_T], Generic[_T]):
44
48
  """The admin tree item view."""
45
49
 
46
50
  _list_fields = [
@@ -68,8 +72,8 @@ class TreeItemViews(LoggedViews):
68
72
  )
69
73
  ] + _extra_list_fields_no_parents
70
74
 
71
- @view_config(route_name="c2cgeoform_item", request_method="POST", renderer="../templates/edit.jinja2")
72
- def save(self):
75
+ @view_config(route_name="c2cgeoform_item", request_method="POST", renderer="../templates/edit.jinja2") # type: ignore[misc]
76
+ def save(self) -> SaveResponse:
73
77
  response = super().save()
74
78
  # correctly handles the validation error as if there is a validation error, cstruct is empty
75
79
  has_to_be_registered_in_parent = (
@@ -81,11 +85,9 @@ class TreeItemViews(LoggedViews):
81
85
  self._request.dbsession.add(rel)
82
86
  return response
83
87
 
84
- def _base_query( # pylint: disable=arguments-differ
85
- self, query: sqlalchemy.orm.query.Query
86
- ) -> sqlalchemy.orm.query.Query:
88
+ def _sub_query(self, query: sqlalchemy.orm.query.Query[TreeItem]) -> sqlalchemy.orm.query.Query[TreeItem]:
87
89
  return (
88
- query.outerjoin("metadatas")
89
- .options(subqueryload("parents_relation").joinedload("treegroup"))
90
- .options(subqueryload("metadatas"))
90
+ query.outerjoin(TreeItem.metadatas)
91
+ .options(subqueryload(TreeItem.parents_relation).joinedload(LayergroupTreeitem.treegroup))
92
+ .options(subqueryload(TreeItem.metadatas))
91
93
  )