c2cgeoportal-admin 2.6.0__py3-none-any.whl → 2.9rc45__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 +42 -12
- c2cgeoportal_admin/lib/lingva_extractor.py +77 -0
- c2cgeoportal_admin/lib/ogcserver_synchronizer.py +170 -57
- c2cgeoportal_admin/py.typed +0 -0
- c2cgeoportal_admin/routes.py +18 -6
- c2cgeoportal_admin/schemas/dimensions.py +16 -10
- c2cgeoportal_admin/schemas/functionalities.py +59 -21
- c2cgeoportal_admin/schemas/interfaces.py +26 -18
- c2cgeoportal_admin/schemas/metadata.py +101 -48
- c2cgeoportal_admin/schemas/restriction_areas.py +25 -19
- c2cgeoportal_admin/schemas/roles.py +12 -6
- c2cgeoportal_admin/schemas/treegroup.py +46 -21
- c2cgeoportal_admin/schemas/treeitem.py +3 -4
- c2cgeoportal_admin/static/layertree.css +3 -4
- c2cgeoportal_admin/static/navbar.css +36 -35
- c2cgeoportal_admin/static/theme.css +19 -9
- c2cgeoportal_admin/subscribers.py +3 -3
- c2cgeoportal_admin/templates/404.jinja2 +18 -2
- c2cgeoportal_admin/templates/layertree.jinja2 +31 -9
- c2cgeoportal_admin/templates/navigation_navbar.jinja2 +33 -0
- c2cgeoportal_admin/templates/ogcserver_synchronize.jinja2 +12 -0
- c2cgeoportal_admin/templates/widgets/functionality_fields.pt +51 -0
- c2cgeoportal_admin/templates/widgets/metadata.pt +7 -1
- c2cgeoportal_admin/views/__init__.py +29 -0
- c2cgeoportal_admin/views/dimension_layers.py +14 -9
- c2cgeoportal_admin/views/functionalities.py +52 -18
- c2cgeoportal_admin/views/home.py +5 -5
- c2cgeoportal_admin/views/interfaces.py +26 -20
- c2cgeoportal_admin/views/layer_groups.py +36 -25
- c2cgeoportal_admin/views/layers.py +17 -13
- c2cgeoportal_admin/views/layers_cog.py +135 -0
- c2cgeoportal_admin/views/layers_vectortiles.py +62 -27
- c2cgeoportal_admin/views/layers_wms.py +55 -34
- c2cgeoportal_admin/views/layers_wmts.py +54 -34
- c2cgeoportal_admin/views/layertree.py +38 -29
- c2cgeoportal_admin/views/logged_views.py +83 -0
- c2cgeoportal_admin/views/logs.py +91 -0
- c2cgeoportal_admin/views/oauth2_clients.py +30 -18
- c2cgeoportal_admin/views/ogc_servers.py +132 -36
- c2cgeoportal_admin/views/restriction_areas.py +39 -27
- c2cgeoportal_admin/views/roles.py +42 -28
- c2cgeoportal_admin/views/themes.py +47 -35
- c2cgeoportal_admin/views/themes_ordering.py +19 -14
- c2cgeoportal_admin/views/treeitems.py +21 -17
- c2cgeoportal_admin/views/users.py +46 -26
- c2cgeoportal_admin/widgets.py +17 -14
- {c2cgeoportal_admin-2.6.0.dist-info → c2cgeoportal_admin-2.9rc45.dist-info}/METADATA +12 -12
- c2cgeoportal_admin-2.9rc45.dist-info/RECORD +97 -0
- {c2cgeoportal_admin-2.6.0.dist-info → c2cgeoportal_admin-2.9rc45.dist-info}/WHEEL +1 -1
- c2cgeoportal_admin-2.9rc45.dist-info/entry_points.txt +5 -0
- tests/__init__.py +24 -20
- tests/conftest.py +22 -11
- tests/test_edit_url.py +11 -14
- tests/test_functionalities.py +52 -14
- tests/test_home.py +0 -1
- tests/test_interface.py +34 -11
- tests/test_layer_groups.py +57 -27
- tests/test_layers_cog.py +243 -0
- tests/test_layers_vectortiles.py +43 -25
- tests/test_layers_wms.py +67 -45
- tests/test_layers_wmts.py +47 -26
- tests/test_layertree.py +99 -16
- tests/test_left_menu.py +0 -1
- tests/test_lingva_extractor_config.py +64 -0
- tests/test_logs.py +102 -0
- tests/test_main.py +3 -1
- tests/test_metadatas.py +34 -21
- tests/test_oauth2_clients.py +40 -11
- tests/test_ogc_servers.py +84 -35
- tests/test_restriction_areas.py +38 -15
- tests/test_role.py +71 -43
- tests/test_themes.py +71 -37
- tests/test_themes_ordering.py +1 -2
- tests/test_treegroup.py +2 -2
- tests/test_user.py +56 -19
- tests/themes_ordering.py +1 -2
- c2cgeoportal_admin/templates/navigation_vertical.jinja2 +0 -33
- c2cgeoportal_admin-2.6.0.dist-info/RECORD +0 -89
- c2cgeoportal_admin-2.6.0.dist-info/entry_points.txt +0 -3
- {c2cgeoportal_admin-2.6.0.dist-info → c2cgeoportal_admin-2.9rc45.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,4 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
# Copyright (c) 2017-2020, Camptocamp SA
|
1
|
+
# Copyright (c) 2017-2024, Camptocamp SA
|
4
2
|
# All rights reserved.
|
5
3
|
|
6
4
|
# Redistribution and use in source and binary forms, with or without
|
@@ -29,67 +27,104 @@
|
|
29
27
|
|
30
28
|
|
31
29
|
from functools import partial
|
30
|
+
from typing import cast
|
32
31
|
|
32
|
+
import sqlalchemy
|
33
|
+
import sqlalchemy.orm.query
|
33
34
|
from c2cgeoform.schema import GeoFormSchemaNode
|
34
|
-
from c2cgeoform.views.abstract_views import
|
35
|
+
from c2cgeoform.views.abstract_views import (
|
36
|
+
DeleteResponse,
|
37
|
+
GridResponse,
|
38
|
+
IndexResponse,
|
39
|
+
ListField,
|
40
|
+
ObjectResponse,
|
41
|
+
SaveResponse,
|
42
|
+
)
|
35
43
|
from deform.widget import FormWidget
|
44
|
+
from pyramid.httpexceptions import HTTPNotFound
|
36
45
|
from pyramid.view import view_config, view_defaults
|
37
46
|
|
47
|
+
from c2cgeoportal_admin import _
|
38
48
|
from c2cgeoportal_admin.schemas.interfaces import interfaces_schema_node
|
39
|
-
from c2cgeoportal_admin.schemas.metadata import
|
49
|
+
from c2cgeoportal_admin.schemas.metadata import metadata_schema_node
|
40
50
|
from c2cgeoportal_admin.schemas.restriction_areas import restrictionareas_schema_node
|
41
51
|
from c2cgeoportal_admin.schemas.treeitem import parent_id_node
|
42
52
|
from c2cgeoportal_admin.views.dimension_layers import DimensionLayerViews
|
53
|
+
from c2cgeoportal_commons.lib.literal import Literal
|
43
54
|
from c2cgeoportal_commons.models.main import LayerGroup, LayerVectorTiles
|
44
55
|
|
45
56
|
_list_field = partial(ListField, LayerVectorTiles)
|
46
57
|
|
47
58
|
|
48
59
|
base_schema = GeoFormSchemaNode(LayerVectorTiles, widget=FormWidget(fields_template="layer_fields"))
|
49
|
-
base_schema.add(
|
50
|
-
base_schema.add(interfaces_schema_node.
|
51
|
-
base_schema.add(restrictionareas_schema_node.
|
60
|
+
base_schema.add(metadata_schema_node(LayerVectorTiles.metadatas, LayerVectorTiles))
|
61
|
+
base_schema.add(interfaces_schema_node(LayerVectorTiles.interfaces))
|
62
|
+
base_schema.add(restrictionareas_schema_node(LayerVectorTiles.restrictionareas))
|
52
63
|
base_schema.add_unique_validator(LayerVectorTiles.name, LayerVectorTiles.id)
|
53
64
|
base_schema.add(parent_id_node(LayerGroup))
|
54
65
|
|
55
66
|
|
56
67
|
@view_defaults(match_param="table=layers_vectortiles")
|
57
|
-
class LayerVectorTilesViews(DimensionLayerViews):
|
68
|
+
class LayerVectorTilesViews(DimensionLayerViews[LayerVectorTiles]):
|
69
|
+
"""The vector tiles administration view."""
|
70
|
+
|
58
71
|
_list_fields = (
|
59
|
-
DimensionLayerViews._list_fields
|
72
|
+
DimensionLayerViews._list_fields # typer: ignore[misc] # pylint: disable=protected-access
|
60
73
|
+ [_list_field("style"), _list_field("xyz")]
|
61
|
-
+ DimensionLayerViews._extra_list_fields
|
74
|
+
+ DimensionLayerViews._extra_list_fields # pylint: disable=protected-access
|
62
75
|
)
|
76
|
+
|
63
77
|
_id_field = "id"
|
64
78
|
_model = LayerVectorTiles
|
65
79
|
_base_schema = base_schema
|
66
80
|
|
67
|
-
def _base_query(self
|
81
|
+
def _base_query(self) -> sqlalchemy.orm.query.Query[LayerVectorTiles]:
|
82
|
+
return super()._sub_query(self._request.dbsession.query(LayerVectorTiles).distinct())
|
83
|
+
|
84
|
+
def _sub_query(
|
85
|
+
self, query: sqlalchemy.orm.query.Query[LayerVectorTiles] | None
|
86
|
+
) -> sqlalchemy.orm.query.Query[LayerVectorTiles]:
|
68
87
|
del query
|
69
|
-
return
|
88
|
+
return self._base_query()
|
70
89
|
|
71
|
-
@view_config(route_name="c2cgeoform_index", renderer="../templates/index.jinja2")
|
72
|
-
def index(self):
|
90
|
+
@view_config(route_name="c2cgeoform_index", renderer="../templates/index.jinja2") # type: ignore[misc]
|
91
|
+
def index(self) -> IndexResponse:
|
73
92
|
return super().index()
|
74
93
|
|
75
|
-
@view_config(route_name="c2cgeoform_grid", renderer="fast_json")
|
76
|
-
def grid(self):
|
94
|
+
@view_config(route_name="c2cgeoform_grid", renderer="fast_json") # type: ignore[misc]
|
95
|
+
def grid(self) -> GridResponse:
|
77
96
|
return super().grid()
|
78
97
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
98
|
+
def schema(self) -> GeoFormSchemaNode:
|
99
|
+
try:
|
100
|
+
obj = self._get_object()
|
101
|
+
except HTTPNotFound:
|
102
|
+
obj = None
|
103
|
+
|
104
|
+
schema = cast(GeoFormSchemaNode, self._base_schema.clone())
|
105
|
+
if obj is not None:
|
106
|
+
schema["style"].description = Literal(
|
107
|
+
_("{}<br>Current runtime value is: {}").format(
|
108
|
+
schema["style"].description,
|
109
|
+
obj.style_description(self._request),
|
110
|
+
)
|
111
|
+
)
|
112
|
+
return schema
|
113
|
+
|
114
|
+
@view_config(route_name="c2cgeoform_item", request_method="GET", renderer="../templates/edit.jinja2") # type: ignore[misc]
|
115
|
+
def view(self) -> ObjectResponse:
|
116
|
+
return super().edit(self.schema())
|
117
|
+
|
118
|
+
@view_config(route_name="c2cgeoform_item", request_method="POST", renderer="../templates/edit.jinja2") # type: ignore[misc]
|
119
|
+
def save(self) -> SaveResponse:
|
85
120
|
return super().save()
|
86
121
|
|
87
|
-
@view_config(route_name="c2cgeoform_item", request_method="DELETE", renderer="fast_json")
|
88
|
-
def delete(self):
|
122
|
+
@view_config(route_name="c2cgeoform_item", request_method="DELETE", renderer="fast_json") # type: ignore[misc]
|
123
|
+
def delete(self) -> DeleteResponse:
|
89
124
|
return super().delete()
|
90
125
|
|
91
|
-
@view_config(
|
126
|
+
@view_config( # type: ignore[misc]
|
92
127
|
route_name="c2cgeoform_item_duplicate", request_method="GET", renderer="../templates/edit.jinja2"
|
93
128
|
)
|
94
|
-
def duplicate(self):
|
129
|
+
def duplicate(self) -> ObjectResponse:
|
95
130
|
return super().duplicate()
|
@@ -1,6 +1,4 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
# Copyright (c) 2017-2020, Camptocamp SA
|
1
|
+
# Copyright (c) 2017-2024, Camptocamp SA
|
4
2
|
# All rights reserved.
|
5
3
|
|
6
4
|
# Redistribution and use in source and binary forms, with or without
|
@@ -27,13 +25,21 @@
|
|
27
25
|
# of the authors and should not be interpreted as representing official policies,
|
28
26
|
# either expressed or implied, of the FreeBSD Project.
|
29
27
|
|
30
|
-
# pylint: disable=no-member
|
31
|
-
|
32
28
|
|
33
29
|
from functools import partial
|
34
30
|
|
31
|
+
import sqlalchemy
|
32
|
+
from c2cgeoform import JSONDict
|
35
33
|
from c2cgeoform.schema import GeoFormSchemaNode
|
36
|
-
from c2cgeoform.views.abstract_views import
|
34
|
+
from c2cgeoform.views.abstract_views import (
|
35
|
+
DeleteResponse,
|
36
|
+
GridResponse,
|
37
|
+
IndexResponse,
|
38
|
+
ItemAction,
|
39
|
+
ListField,
|
40
|
+
ObjectResponse,
|
41
|
+
SaveResponse,
|
42
|
+
)
|
37
43
|
from deform.widget import FormWidget
|
38
44
|
from pyramid.view import view_config, view_defaults
|
39
45
|
from sqlalchemy import delete, insert, inspect, update
|
@@ -42,27 +48,29 @@ from zope.sqlalchemy import mark_changed
|
|
42
48
|
from c2cgeoportal_admin import _
|
43
49
|
from c2cgeoportal_admin.schemas.dimensions import dimensions_schema_node
|
44
50
|
from c2cgeoportal_admin.schemas.interfaces import interfaces_schema_node
|
45
|
-
from c2cgeoportal_admin.schemas.metadata import
|
51
|
+
from c2cgeoportal_admin.schemas.metadata import metadata_schema_node
|
46
52
|
from c2cgeoportal_admin.schemas.restriction_areas import restrictionareas_schema_node
|
47
53
|
from c2cgeoportal_admin.schemas.treeitem import parent_id_node
|
48
54
|
from c2cgeoportal_admin.views.dimension_layers import DimensionLayerViews
|
49
|
-
from c2cgeoportal_commons.models.main import LayerGroup, LayerWMS, LayerWMTS, OGCServer, TreeItem
|
55
|
+
from c2cgeoportal_commons.models.main import LayerGroup, LayerWMS, LayerWMTS, LogAction, OGCServer, TreeItem
|
50
56
|
|
51
57
|
_list_field = partial(ListField, LayerWMS)
|
52
58
|
|
53
59
|
base_schema = GeoFormSchemaNode(LayerWMS, widget=FormWidget(fields_template="layer_fields"))
|
54
|
-
base_schema.add(dimensions_schema_node.
|
55
|
-
base_schema.add(
|
56
|
-
base_schema.add(interfaces_schema_node.
|
57
|
-
base_schema.add(restrictionareas_schema_node.
|
60
|
+
base_schema.add(dimensions_schema_node(LayerWMS.dimensions))
|
61
|
+
base_schema.add(metadata_schema_node(LayerWMS.metadatas, LayerWMS))
|
62
|
+
base_schema.add(interfaces_schema_node(LayerWMS.interfaces))
|
63
|
+
base_schema.add(restrictionareas_schema_node(LayerWMS.restrictionareas))
|
58
64
|
base_schema.add_unique_validator(LayerWMS.name, LayerWMS.id)
|
59
65
|
base_schema.add(parent_id_node(LayerGroup))
|
60
66
|
|
61
67
|
|
62
68
|
@view_defaults(match_param="table=layers_wms")
|
63
|
-
class LayerWmsViews(DimensionLayerViews):
|
69
|
+
class LayerWmsViews(DimensionLayerViews[LayerWMS]):
|
70
|
+
"""The WMS layer administration view."""
|
71
|
+
|
64
72
|
_list_fields = (
|
65
|
-
DimensionLayerViews._list_fields
|
73
|
+
DimensionLayerViews._list_fields # pylint: disable=protected-access
|
66
74
|
+ [
|
67
75
|
_list_field(
|
68
76
|
"ogc_server",
|
@@ -77,27 +85,34 @@ class LayerWmsViews(DimensionLayerViews):
|
|
77
85
|
_list_field("time_mode"),
|
78
86
|
_list_field("time_widget"),
|
79
87
|
]
|
80
|
-
+ DimensionLayerViews._extra_list_fields
|
88
|
+
+ DimensionLayerViews._extra_list_fields # pylint: disable=protected-access
|
81
89
|
)
|
82
90
|
_id_field = "id"
|
83
91
|
_model = LayerWMS
|
84
92
|
_base_schema = base_schema
|
85
93
|
|
86
|
-
def _base_query(self
|
94
|
+
def _base_query(self) -> sqlalchemy.orm.query.Query[LayerWMS]:
|
95
|
+
return super()._sub_query(
|
96
|
+
self._request.dbsession.query(LayerWMS, OGCServer.name).distinct().outerjoin(LayerWMS.ogc_server)
|
97
|
+
)
|
98
|
+
|
99
|
+
def _sub_query(
|
100
|
+
self, query: sqlalchemy.orm.query.Query[LayerWMS] | None
|
101
|
+
) -> sqlalchemy.orm.query.Query[LayerWMS]:
|
87
102
|
del query
|
88
|
-
return
|
103
|
+
return self._base_query()
|
89
104
|
|
90
|
-
@view_config(route_name="c2cgeoform_index", renderer="../templates/index.jinja2")
|
91
|
-
def index(self):
|
105
|
+
@view_config(route_name="c2cgeoform_index", renderer="../templates/index.jinja2") # type: ignore[misc]
|
106
|
+
def index(self) -> IndexResponse:
|
92
107
|
return super().index()
|
93
108
|
|
94
|
-
@view_config(route_name="c2cgeoform_grid", renderer="fast_json")
|
95
|
-
def grid(self):
|
109
|
+
@view_config(route_name="c2cgeoform_grid", renderer="fast_json") # type: ignore[misc]
|
110
|
+
def grid(self) -> GridResponse:
|
96
111
|
return super().grid()
|
97
112
|
|
98
|
-
def _item_actions(self, item, readonly=False):
|
99
|
-
actions = super()._item_actions(item, readonly)
|
100
|
-
if inspect(item).persistent:
|
113
|
+
def _item_actions(self, item: LayerWMS, readonly: bool = False) -> list[ItemAction]:
|
114
|
+
actions: list[ItemAction] = super()._item_actions(item, readonly)
|
115
|
+
if inspect(item).persistent: # type: ignore[attr-defined]
|
101
116
|
actions.insert(
|
102
117
|
next((i for i, v in enumerate(actions) if v.name() == "delete")),
|
103
118
|
ItemAction(
|
@@ -111,8 +126,10 @@ class LayerWmsViews(DimensionLayerViews):
|
|
111
126
|
)
|
112
127
|
return actions
|
113
128
|
|
114
|
-
@view_config(
|
115
|
-
|
129
|
+
@view_config( # type: ignore[misc]
|
130
|
+
route_name="c2cgeoform_item", request_method="GET", renderer="../templates/edit.jinja2"
|
131
|
+
)
|
132
|
+
def view(self) -> ObjectResponse:
|
116
133
|
if self._is_new():
|
117
134
|
dbsession = self._request.dbsession
|
118
135
|
default_wms = LayerWMS.get_default(dbsession)
|
@@ -120,22 +137,24 @@ class LayerWmsViews(DimensionLayerViews):
|
|
120
137
|
return self.copy(default_wms, excludes=["name", "layer"])
|
121
138
|
return super().edit()
|
122
139
|
|
123
|
-
@view_config(
|
124
|
-
|
140
|
+
@view_config( # type: ignore[misc]
|
141
|
+
route_name="c2cgeoform_item", request_method="POST", renderer="../templates/edit.jinja2"
|
142
|
+
)
|
143
|
+
def save(self) -> SaveResponse:
|
125
144
|
return super().save()
|
126
145
|
|
127
|
-
@view_config(route_name="c2cgeoform_item", request_method="DELETE", renderer="fast_json")
|
128
|
-
def delete(self):
|
146
|
+
@view_config(route_name="c2cgeoform_item", request_method="DELETE", renderer="fast_json") # type: ignore[misc]
|
147
|
+
def delete(self) -> DeleteResponse:
|
129
148
|
return super().delete()
|
130
149
|
|
131
|
-
@view_config(
|
150
|
+
@view_config( # type: ignore[misc]
|
132
151
|
route_name="c2cgeoform_item_duplicate", request_method="GET", renderer="../templates/edit.jinja2"
|
133
152
|
)
|
134
|
-
def duplicate(self):
|
153
|
+
def duplicate(self) -> ObjectResponse:
|
135
154
|
return super().duplicate()
|
136
155
|
|
137
|
-
@view_config(route_name="convert_to_wmts", request_method="POST", renderer="fast_json")
|
138
|
-
def convert_to_wmts(self):
|
156
|
+
@view_config(route_name="convert_to_wmts", request_method="POST", renderer="fast_json") # type: ignore[misc]
|
157
|
+
def convert_to_wmts(self) -> JSONDict:
|
139
158
|
src = self._get_object()
|
140
159
|
dbsession = self._request.dbsession
|
141
160
|
default_wmts = LayerWMTS.get_default(dbsession)
|
@@ -168,6 +187,8 @@ class LayerWmsViews(DimensionLayerViews):
|
|
168
187
|
dbsession.flush()
|
169
188
|
mark_changed(dbsession)
|
170
189
|
|
190
|
+
self._create_log(LogAction.CONVERT_TO_WMTS, src, element_url_table="layers_wmts")
|
191
|
+
|
171
192
|
return {
|
172
193
|
"success": True,
|
173
194
|
"redirect": self._request.route_url(
|
@@ -1,6 +1,4 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
# Copyright (c) 2017-2020, Camptocamp SA
|
1
|
+
# Copyright (c) 2017-2024, Camptocamp SA
|
4
2
|
# All rights reserved.
|
5
3
|
|
6
4
|
# Redistribution and use in source and binary forms, with or without
|
@@ -27,13 +25,21 @@
|
|
27
25
|
# of the authors and should not be interpreted as representing official policies,
|
28
26
|
# either expressed or implied, of the FreeBSD Project.
|
29
27
|
|
30
|
-
# pylint: disable=no-member
|
31
|
-
|
32
28
|
|
33
29
|
from functools import partial
|
34
30
|
|
31
|
+
import sqlalchemy
|
32
|
+
from c2cgeoform import JSONDict
|
35
33
|
from c2cgeoform.schema import GeoFormSchemaNode
|
36
|
-
from c2cgeoform.views.abstract_views import
|
34
|
+
from c2cgeoform.views.abstract_views import (
|
35
|
+
DeleteResponse,
|
36
|
+
GridResponse,
|
37
|
+
IndexResponse,
|
38
|
+
ItemAction,
|
39
|
+
ListField,
|
40
|
+
ObjectResponse,
|
41
|
+
SaveResponse,
|
42
|
+
)
|
37
43
|
from deform.widget import FormWidget
|
38
44
|
from pyramid.view import view_config, view_defaults
|
39
45
|
from sqlalchemy import delete, insert, inspect, update
|
@@ -42,27 +48,29 @@ from zope.sqlalchemy import mark_changed
|
|
42
48
|
from c2cgeoportal_admin import _
|
43
49
|
from c2cgeoportal_admin.schemas.dimensions import dimensions_schema_node
|
44
50
|
from c2cgeoportal_admin.schemas.interfaces import interfaces_schema_node
|
45
|
-
from c2cgeoportal_admin.schemas.metadata import
|
51
|
+
from c2cgeoportal_admin.schemas.metadata import metadata_schema_node
|
46
52
|
from c2cgeoportal_admin.schemas.restriction_areas import restrictionareas_schema_node
|
47
53
|
from c2cgeoportal_admin.schemas.treeitem import parent_id_node
|
48
54
|
from c2cgeoportal_admin.views.dimension_layers import DimensionLayerViews
|
49
|
-
from c2cgeoportal_commons.models.main import LayerGroup, LayerWMS, LayerWMTS, OGCServer, TreeItem
|
55
|
+
from c2cgeoportal_commons.models.main import LayerGroup, LayerWMS, LayerWMTS, LogAction, OGCServer, TreeItem
|
50
56
|
|
51
57
|
_list_field = partial(ListField, LayerWMTS)
|
52
58
|
|
53
59
|
base_schema = GeoFormSchemaNode(LayerWMTS, widget=FormWidget(fields_template="layer_fields"))
|
54
|
-
base_schema.add(dimensions_schema_node.
|
55
|
-
base_schema.add(
|
56
|
-
base_schema.add(interfaces_schema_node.
|
57
|
-
base_schema.add(restrictionareas_schema_node.
|
60
|
+
base_schema.add(dimensions_schema_node(LayerWMTS.dimensions))
|
61
|
+
base_schema.add(metadata_schema_node(LayerWMTS.metadatas, LayerWMTS))
|
62
|
+
base_schema.add(interfaces_schema_node(LayerWMTS.interfaces))
|
63
|
+
base_schema.add(restrictionareas_schema_node(LayerWMTS.restrictionareas))
|
58
64
|
base_schema.add_unique_validator(LayerWMTS.name, LayerWMTS.id)
|
59
65
|
base_schema.add(parent_id_node(LayerGroup))
|
60
66
|
|
61
67
|
|
62
68
|
@view_defaults(match_param="table=layers_wmts")
|
63
|
-
class LayerWmtsViews(DimensionLayerViews):
|
69
|
+
class LayerWmtsViews(DimensionLayerViews[LayerWMTS]):
|
70
|
+
"""The WMTS layer administration view."""
|
71
|
+
|
64
72
|
_list_fields = (
|
65
|
-
DimensionLayerViews._list_fields
|
73
|
+
DimensionLayerViews._list_fields # pylint: disable=protected-access
|
66
74
|
+ [
|
67
75
|
_list_field("url"),
|
68
76
|
_list_field("layer"),
|
@@ -70,26 +78,32 @@ class LayerWmtsViews(DimensionLayerViews):
|
|
70
78
|
_list_field("matrix_set"),
|
71
79
|
_list_field("image_type"),
|
72
80
|
]
|
73
|
-
+ DimensionLayerViews._extra_list_fields
|
81
|
+
+ DimensionLayerViews._extra_list_fields # pylint: disable=protected-access
|
74
82
|
)
|
75
83
|
_id_field = "id"
|
76
84
|
_model = LayerWMTS
|
77
85
|
_base_schema = base_schema
|
78
86
|
|
79
|
-
def _base_query(self
|
80
|
-
return super().
|
87
|
+
def _base_query(self) -> sqlalchemy.orm.query.Query[LayerWMTS]:
|
88
|
+
return super()._sub_query(self._request.dbsession.query(LayerWMTS).distinct())
|
89
|
+
|
90
|
+
def _sub_query(
|
91
|
+
self, query: sqlalchemy.orm.query.Query[LayerWMTS]
|
92
|
+
) -> sqlalchemy.orm.query.Query[LayerWMTS]:
|
93
|
+
del query
|
94
|
+
return self._base_query()
|
81
95
|
|
82
|
-
@view_config(route_name="c2cgeoform_index", renderer="../templates/index.jinja2")
|
83
|
-
def index(self):
|
96
|
+
@view_config(route_name="c2cgeoform_index", renderer="../templates/index.jinja2") # type: ignore[misc]
|
97
|
+
def index(self) -> IndexResponse:
|
84
98
|
return super().index()
|
85
99
|
|
86
|
-
@view_config(route_name="c2cgeoform_grid", renderer="fast_json")
|
87
|
-
def grid(self):
|
100
|
+
@view_config(route_name="c2cgeoform_grid", renderer="fast_json") # type: ignore[misc]
|
101
|
+
def grid(self) -> GridResponse:
|
88
102
|
return super().grid()
|
89
103
|
|
90
|
-
def _item_actions(self, item, readonly=False):
|
91
|
-
actions = super()._item_actions(item, readonly)
|
92
|
-
if inspect(item).persistent:
|
104
|
+
def _item_actions(self, item: LayerWMTS, readonly: bool = False) -> list[ItemAction]:
|
105
|
+
actions: list[ItemAction] = super()._item_actions(item, readonly)
|
106
|
+
if inspect(item).persistent: # type: ignore[attr-defined]
|
93
107
|
actions.insert(
|
94
108
|
next((i for i, v in enumerate(actions) if v.name() == "delete")),
|
95
109
|
ItemAction(
|
@@ -103,8 +117,10 @@ class LayerWmtsViews(DimensionLayerViews):
|
|
103
117
|
)
|
104
118
|
return actions
|
105
119
|
|
106
|
-
@view_config(
|
107
|
-
|
120
|
+
@view_config( # type: ignore[misc]
|
121
|
+
route_name="c2cgeoform_item", request_method="GET", renderer="../templates/edit.jinja2"
|
122
|
+
)
|
123
|
+
def view(self) -> ObjectResponse:
|
108
124
|
if self._is_new():
|
109
125
|
dbsession = self._request.dbsession
|
110
126
|
default_wmts = LayerWMTS.get_default(dbsession)
|
@@ -112,22 +128,24 @@ class LayerWmtsViews(DimensionLayerViews):
|
|
112
128
|
return self.copy(default_wmts, excludes=["name", "layer"])
|
113
129
|
return super().edit()
|
114
130
|
|
115
|
-
@view_config(
|
116
|
-
|
131
|
+
@view_config( # type: ignore[misc]
|
132
|
+
route_name="c2cgeoform_item", request_method="POST", renderer="../templates/edit.jinja2"
|
133
|
+
)
|
134
|
+
def save(self) -> SaveResponse:
|
117
135
|
return super().save()
|
118
136
|
|
119
|
-
@view_config(route_name="c2cgeoform_item", request_method="DELETE", renderer="fast_json")
|
120
|
-
def delete(self):
|
137
|
+
@view_config(route_name="c2cgeoform_item", request_method="DELETE", renderer="fast_json") # type: ignore[misc]
|
138
|
+
def delete(self) -> DeleteResponse:
|
121
139
|
return super().delete()
|
122
140
|
|
123
|
-
@view_config(
|
141
|
+
@view_config( # type: ignore[misc]
|
124
142
|
route_name="c2cgeoform_item_duplicate", request_method="GET", renderer="../templates/edit.jinja2"
|
125
143
|
)
|
126
|
-
def duplicate(self):
|
144
|
+
def duplicate(self) -> ObjectResponse:
|
127
145
|
return super().duplicate()
|
128
146
|
|
129
|
-
@view_config(route_name="convert_to_wms", request_method="POST", renderer="fast_json")
|
130
|
-
def convert_to_wms(self):
|
147
|
+
@view_config(route_name="convert_to_wms", request_method="POST", renderer="fast_json") # type: ignore[misc]
|
148
|
+
def convert_to_wms(self) -> JSONDict:
|
131
149
|
src = self._get_object()
|
132
150
|
dbsession = self._request.dbsession
|
133
151
|
default_wms = LayerWMS.get_default(dbsession)
|
@@ -161,6 +179,8 @@ class LayerWmtsViews(DimensionLayerViews):
|
|
161
179
|
dbsession.flush()
|
162
180
|
mark_changed(dbsession)
|
163
181
|
|
182
|
+
self._create_log(LogAction.CONVERT_TO_WMS, src, element_url_table="layers_wms")
|
183
|
+
|
164
184
|
return {
|
165
185
|
"success": True,
|
166
186
|
"redirect": self._request.route_url(
|
@@ -1,6 +1,4 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
# Copyright (c) 2017-2020, Camptocamp SA
|
1
|
+
# Copyright (c) 2017-2024, Camptocamp SA
|
4
2
|
# All rights reserved.
|
5
3
|
|
6
4
|
# Redistribution and use in source and binary forms, with or without
|
@@ -28,48 +26,59 @@
|
|
28
26
|
# either expressed or implied, of the FreeBSD Project.
|
29
27
|
|
30
28
|
|
31
|
-
from
|
29
|
+
from typing import Any
|
30
|
+
|
31
|
+
import pyramid.request
|
32
|
+
from c2cgeoform.views.abstract_views import DeleteResponse, ItemAction
|
32
33
|
from pyramid.httpexceptions import HTTPNotFound
|
33
34
|
from pyramid.view import view_config, view_defaults
|
34
35
|
from translationstring import TranslationStringFactory
|
35
36
|
|
36
37
|
from c2cgeoportal_admin import _
|
37
|
-
from c2cgeoportal_commons.models.main import LayergroupTreeitem, Theme, TreeItem
|
38
|
+
from c2cgeoportal_commons.models.main import Interface, Layer, LayergroupTreeitem, Theme, TreeItem
|
38
39
|
|
39
40
|
itemtypes_tables = {
|
40
41
|
"theme": "themes",
|
41
42
|
"group": "layer_groups",
|
42
43
|
"l_wms": "layers_wms",
|
43
44
|
"l_wmts": "layers_wmts",
|
45
|
+
"l_cog": "layers_cog",
|
44
46
|
}
|
45
47
|
|
46
48
|
|
47
|
-
@view_defaults(match_param=
|
49
|
+
@view_defaults(match_param="application=admin")
|
48
50
|
class LayerTreeViews:
|
49
|
-
|
51
|
+
"""The layer tree administration view."""
|
52
|
+
|
53
|
+
def __init__(self, request: pyramid.request.Request):
|
50
54
|
self._request = request
|
51
55
|
self._dbsession = request.dbsession
|
52
56
|
|
53
|
-
@view_config(route_name="layertree", renderer="../templates/layertree.jinja2")
|
54
|
-
def index(self):
|
57
|
+
@view_config(route_name="layertree", renderer="../templates/layertree.jinja2") # type: ignore[misc]
|
58
|
+
def index(self) -> dict[str, int]:
|
55
59
|
node_limit = self._request.registry.settings["admin_interface"].get("layer_tree_max_nodes")
|
56
60
|
limit_exceeded = self._dbsession.query(LayergroupTreeitem).count() < node_limit
|
57
|
-
return {"limit_exceeded": limit_exceeded}
|
61
|
+
return {"limit_exceeded": limit_exceeded, "interfaces": self._dbsession.query(Interface).all()}
|
58
62
|
|
59
|
-
@view_config(route_name="layertree_children", renderer="fast_json")
|
60
|
-
def children(self):
|
63
|
+
@view_config(route_name="layertree_children", renderer="fast_json") # type: ignore[misc]
|
64
|
+
def children(self) -> list[dict[str, Any]]:
|
65
|
+
interface = self._request.params.get("interface", None)
|
61
66
|
group_id = self._request.params.get("group_id", None)
|
62
67
|
path = self._request.params.get("path", "")
|
63
68
|
|
64
|
-
client_tsf = TranslationStringFactory("{
|
69
|
+
client_tsf = TranslationStringFactory(f"{self._request.registry.package_name}-client")
|
65
70
|
|
66
71
|
if group_id is None:
|
67
72
|
items = self._dbsession.query(Theme).order_by(Theme.ordering)
|
73
|
+
if interface is not None:
|
74
|
+
items = items.join(Theme.interfaces).filter(Interface.name == interface)
|
75
|
+
|
68
76
|
else:
|
69
77
|
items = (
|
70
78
|
self._dbsession.query(TreeItem)
|
71
|
-
.join(TreeItem.parents_relation)
|
79
|
+
.join(TreeItem.parents_relation)
|
72
80
|
.filter(LayergroupTreeitem.treegroup_id == group_id)
|
81
|
+
.order_by(LayergroupTreeitem.ordering)
|
73
82
|
)
|
74
83
|
|
75
84
|
return [
|
@@ -79,14 +88,17 @@ class LayerTreeViews:
|
|
79
88
|
"name": item.name,
|
80
89
|
"translated_name": self._request.localizer.translate(client_tsf(item.name)),
|
81
90
|
"description": item.description,
|
82
|
-
"path": "{}_{
|
91
|
+
"path": f"{path}_{item.id}",
|
83
92
|
"parent_path": path,
|
84
93
|
"actions": [action.to_dict(self._request) for action in self._item_actions(item, group_id)],
|
85
94
|
}
|
86
95
|
for item in items
|
96
|
+
if interface is None
|
97
|
+
or not isinstance(item, Layer)
|
98
|
+
or interface in [interface.name for interface in item.interfaces]
|
87
99
|
]
|
88
100
|
|
89
|
-
def _item_actions(self, item, parent_id=None):
|
101
|
+
def _item_actions(self, item: TreeItem, parent_id: int | None = None) -> list[ItemAction]:
|
90
102
|
actions = []
|
91
103
|
actions.append(
|
92
104
|
ItemAction(
|
@@ -105,9 +117,8 @@ class LayerTreeViews:
|
|
105
117
|
name="new_layer_group",
|
106
118
|
label=_("New layer group"),
|
107
119
|
icon="glyphicon glyphicon-plus",
|
108
|
-
url="{}?
|
109
|
-
|
110
|
-
),
|
120
|
+
url=f"{self._request.route_url('c2cgeoform_item', table='layer_groups', id='new')}?"
|
121
|
+
f"parent_id={item.id}",
|
111
122
|
)
|
112
123
|
)
|
113
124
|
|
@@ -117,9 +128,8 @@ class LayerTreeViews:
|
|
117
128
|
name="new_layer_wms",
|
118
129
|
label=_("New WMS layer"),
|
119
130
|
icon="glyphicon glyphicon-plus",
|
120
|
-
url="{}?
|
121
|
-
|
122
|
-
),
|
131
|
+
url=f"{self._request.route_url('c2cgeoform_item', table='layers_wms', id='new')}?"
|
132
|
+
f"parent_id={item.id}",
|
123
133
|
)
|
124
134
|
)
|
125
135
|
|
@@ -128,9 +138,8 @@ class LayerTreeViews:
|
|
128
138
|
name="new_layer_wmts",
|
129
139
|
label=_("New WMTS layer"),
|
130
140
|
icon="glyphicon glyphicon-plus",
|
131
|
-
url="{}?
|
132
|
-
|
133
|
-
),
|
141
|
+
url=f"{self._request.route_url('c2cgeoform_item', table='layers_wmts', id='new')}?"
|
142
|
+
f"parent_id={item.id}",
|
134
143
|
)
|
135
144
|
)
|
136
145
|
|
@@ -170,8 +179,8 @@ class LayerTreeViews:
|
|
170
179
|
|
171
180
|
return actions
|
172
181
|
|
173
|
-
@view_config(route_name="layertree_unlink", request_method="DELETE", renderer="fast_json")
|
174
|
-
def unlink(self):
|
182
|
+
@view_config(route_name="layertree_unlink", request_method="DELETE", renderer="fast_json") # type: ignore[misc]
|
183
|
+
def unlink(self) -> dict[str, Any]:
|
175
184
|
group_id = self._request.matchdict.get("group_id")
|
176
185
|
item_id = self._request.matchdict.get("item_id")
|
177
186
|
link = (
|
@@ -186,8 +195,8 @@ class LayerTreeViews:
|
|
186
195
|
self._request.dbsession.flush()
|
187
196
|
return {"success": True, "redirect": self._request.route_url("layertree")}
|
188
197
|
|
189
|
-
@view_config(route_name="layertree_delete", request_method="DELETE", renderer="fast_json")
|
190
|
-
def delete(self):
|
198
|
+
@view_config(route_name="layertree_delete", request_method="DELETE", renderer="fast_json") # type: ignore[misc]
|
199
|
+
def delete(self) -> DeleteResponse:
|
191
200
|
item_id = self._request.matchdict.get("item_id")
|
192
201
|
item = self._request.dbsession.query(TreeItem).get(item_id)
|
193
202
|
if item is None:
|