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.
- c2cgeoportal_admin/__init__.py +14 -6
- c2cgeoportal_admin/lib/{lingua_extractor.py → lingva_extractor.py} +6 -6
- c2cgeoportal_admin/lib/ogcserver_synchronizer.py +6 -5
- c2cgeoportal_admin/routes.py +12 -3
- c2cgeoportal_admin/schemas/dimensions.py +4 -2
- c2cgeoportal_admin/schemas/functionalities.py +9 -12
- c2cgeoportal_admin/schemas/interfaces.py +7 -3
- c2cgeoportal_admin/schemas/metadata.py +13 -13
- c2cgeoportal_admin/schemas/restriction_areas.py +5 -3
- c2cgeoportal_admin/schemas/roles.py +7 -3
- c2cgeoportal_admin/schemas/treegroup.py +14 -10
- c2cgeoportal_admin/schemas/treeitem.py +2 -2
- c2cgeoportal_admin/static/theme.css +3 -0
- c2cgeoportal_admin/views/dimension_layers.py +11 -7
- c2cgeoportal_admin/views/functionalities.py +25 -18
- c2cgeoportal_admin/views/interfaces.py +22 -15
- c2cgeoportal_admin/views/layer_groups.py +33 -20
- c2cgeoportal_admin/views/layers.py +12 -9
- c2cgeoportal_admin/views/layers_cog.py +135 -0
- c2cgeoportal_admin/views/layers_vectortiles.py +42 -27
- c2cgeoportal_admin/views/layers_wms.py +47 -32
- c2cgeoportal_admin/views/layers_wmts.py +46 -32
- c2cgeoportal_admin/views/layertree.py +9 -8
- c2cgeoportal_admin/views/logged_views.py +15 -12
- c2cgeoportal_admin/views/logs.py +9 -8
- c2cgeoportal_admin/views/oauth2_clients.py +26 -22
- c2cgeoportal_admin/views/ogc_servers.py +48 -34
- c2cgeoportal_admin/views/restriction_areas.py +29 -19
- c2cgeoportal_admin/views/roles.py +29 -19
- c2cgeoportal_admin/views/themes.py +35 -24
- c2cgeoportal_admin/views/themes_ordering.py +11 -11
- c2cgeoportal_admin/views/treeitems.py +13 -11
- c2cgeoportal_admin/views/users.py +37 -22
- c2cgeoportal_admin/widgets.py +3 -3
- {c2cgeoportal_admin-2.8.1.181.dist-info → c2cgeoportal_admin-2.9rc2.dist-info}/METADATA +3 -12
- {c2cgeoportal_admin-2.8.1.181.dist-info → c2cgeoportal_admin-2.9rc2.dist-info}/RECORD +48 -46
- {c2cgeoportal_admin-2.8.1.181.dist-info → c2cgeoportal_admin-2.9rc2.dist-info}/WHEEL +1 -1
- c2cgeoportal_admin-2.9rc2.dist-info/entry_points.txt +5 -0
- tests/__init__.py +13 -8
- tests/conftest.py +20 -10
- tests/test_layers_cog.py +243 -0
- tests/test_layers_vectortiles.py +2 -7
- tests/{test_lingua_extractor_config.py → test_lingva_extractor_config.py} +3 -3
- tests/test_logs.py +3 -4
- tests/test_oauth2_clients.py +3 -2
- tests/test_role.py +3 -2
- tests/test_user.py +8 -2
- c2cgeoportal_admin-2.8.1.181.dist-info/entry_points.txt +0 -6
- {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-
|
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,
|
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
|
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
|
-
|
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) ->
|
87
|
-
return super().index()
|
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) ->
|
91
|
-
return super().grid()
|
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) ->
|
112
|
-
actions = cast(
|
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) ->
|
145
|
-
return super().edit(self.schema())
|
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) ->
|
151
|
-
result
|
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) ->
|
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
|
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) ->
|
177
|
-
return super().duplicate()
|
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) ->
|
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":
|
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
|
-
|
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
|
-
|
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-
|
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
|
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
|
-
|
116
|
-
.options(subqueryload(
|
117
|
-
.options(subqueryload(
|
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-
|
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
|
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
|
-
|
125
|
-
.options(subqueryload(
|
126
|
-
.options(subqueryload(
|
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-
|
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
|
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
|
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
|
100
|
-
return super().
|
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(
|
110
|
+
.outerjoin(Theme.interfaces)
|
104
111
|
.outerjoin(Theme.restricted_roles)
|
105
112
|
.outerjoin(Theme.functionalities)
|
106
|
-
.options(subqueryload(
|
107
|
-
.options(subqueryload(
|
108
|
-
.options(subqueryload(
|
113
|
+
.options(subqueryload(Theme.functionalities))
|
114
|
+
.options(subqueryload(Theme.restricted_roles))
|
115
|
+
.options(subqueryload(Theme.interfaces))
|
109
116
|
)
|
110
117
|
|
111
|
-
|
112
|
-
|
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-
|
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): #
|
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):
|
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":
|
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":
|
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-
|
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
|
-
|
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
|
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(
|
89
|
-
.options(subqueryload(
|
90
|
-
.options(subqueryload(
|
90
|
+
query.outerjoin(TreeItem.metadatas)
|
91
|
+
.options(subqueryload(TreeItem.parents_relation).joinedload(LayergroupTreeitem.treegroup))
|
92
|
+
.options(subqueryload(TreeItem.metadatas))
|
91
93
|
)
|