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) 2018-2020, Camptocamp SA
|
1
|
+
# Copyright (c) 2018-2024, Camptocamp SA
|
4
2
|
# All rights reserved.
|
5
3
|
|
6
4
|
# Redistribution and use in source and binary forms, with or without
|
@@ -28,16 +26,24 @@
|
|
28
26
|
# either expressed or implied, of the FreeBSD Project.
|
29
27
|
|
30
28
|
|
29
|
+
from typing import Any
|
30
|
+
|
31
31
|
import colander
|
32
32
|
from c2cgeoform.schema import GeoFormSchemaNode
|
33
33
|
from deform.widget import MappingWidget, SequenceWidget
|
34
|
+
from sqlalchemy.orm.attributes import InstrumentedAttribute
|
34
35
|
|
35
|
-
from c2cgeoportal_admin import _
|
36
36
|
from c2cgeoportal_commons.models.main import Dimension
|
37
37
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
38
|
+
|
39
|
+
def dimensions_schema_node(
|
40
|
+
prop: InstrumentedAttribute[Any], # pylint: disable=unsubscriptable-object
|
41
|
+
) -> colander.SequenceSchema:
|
42
|
+
"""Get the scheme of the dimensions."""
|
43
|
+
return colander.SequenceSchema(
|
44
|
+
GeoFormSchemaNode(Dimension, name="dimension", widget=MappingWidget(template="dimension")),
|
45
|
+
name=prop.key,
|
46
|
+
title=prop.info["colanderalchemy"]["title"],
|
47
|
+
description=prop.info["colanderalchemy"]["description"],
|
48
|
+
widget=SequenceWidget(category="structural", template="dimensions"),
|
49
|
+
)
|
@@ -1,6 +1,4 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
# Copyright (c) 2018-2020, Camptocamp SA
|
1
|
+
# Copyright (c) 2018-2024, Camptocamp SA
|
4
2
|
# All rights reserved.
|
5
3
|
|
6
4
|
# Redistribution and use in source and binary forms, with or without
|
@@ -28,28 +26,68 @@
|
|
28
26
|
# either expressed or implied, of the FreeBSD Project.
|
29
27
|
|
30
28
|
|
29
|
+
from typing import Any
|
30
|
+
|
31
31
|
import colander
|
32
32
|
from c2cgeoform.ext.deform_ext import RelationCheckBoxListWidget
|
33
33
|
from c2cgeoform.schema import GeoFormManyToManySchemaNode, manytomany_validator
|
34
|
-
from sqlalchemy import select
|
34
|
+
from sqlalchemy import inspect, select
|
35
|
+
from sqlalchemy.orm.attributes import InstrumentedAttribute
|
35
36
|
from sqlalchemy.sql.functions import concat
|
36
37
|
|
37
38
|
from c2cgeoportal_commons.models.main import Functionality
|
38
39
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
"
|
47
|
-
"
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
40
|
+
|
41
|
+
def available_functionalities_for(settings: dict[str, Any], model: type[Any]) -> list[dict[str, Any]]:
|
42
|
+
"""Return filtered list of functionality definitions."""
|
43
|
+
mapper = inspect(model)
|
44
|
+
relevant_for = {mapper.local_table.name}
|
45
|
+
return [
|
46
|
+
f
|
47
|
+
for f in settings["admin_interface"]["available_functionalities"]
|
48
|
+
if relevant_for & set(f.get("relevant_for", relevant_for))
|
49
|
+
]
|
50
|
+
|
51
|
+
|
52
|
+
def functionalities_widget(model: type[Any]) -> colander.deferred:
|
53
|
+
"""Return a colander deferred which itself returns a widget for the functionalities field."""
|
54
|
+
|
55
|
+
def create_widget(node, kw):
|
56
|
+
del node
|
57
|
+
|
58
|
+
return RelationCheckBoxListWidget(
|
59
|
+
select( # type: ignore[arg-type]
|
60
|
+
Functionality.id,
|
61
|
+
concat(Functionality.name, "=", Functionality.value).label("label"),
|
62
|
+
)
|
63
|
+
.where(
|
64
|
+
Functionality.name.in_(
|
65
|
+
[f["name"] for f in available_functionalities_for(kw["request"].registry.settings, model)]
|
66
|
+
)
|
67
|
+
)
|
68
|
+
.alias("functionality_labels"),
|
69
|
+
"id",
|
70
|
+
"label",
|
71
|
+
order_by="label",
|
72
|
+
edit_url=lambda request, value: request.route_url(
|
73
|
+
"c2cgeoform_item", table="functionalities", id=value
|
74
|
+
),
|
75
|
+
)
|
76
|
+
|
77
|
+
return colander.deferred(create_widget)
|
78
|
+
|
79
|
+
|
80
|
+
def functionalities_schema_node(
|
81
|
+
prop: InstrumentedAttribute[Any], model: type[Any]
|
82
|
+
) -> colander.SequenceSchema:
|
83
|
+
"""Get the schema of the functionalities."""
|
84
|
+
|
85
|
+
return colander.SequenceSchema(
|
86
|
+
GeoFormManyToManySchemaNode(Functionality, None),
|
87
|
+
name=prop.key,
|
88
|
+
title=prop.info["colanderalchemy"]["title"],
|
89
|
+
description=prop.info["colanderalchemy"].get("description"),
|
90
|
+
widget=functionalities_widget(model),
|
91
|
+
validator=manytomany_validator,
|
92
|
+
missing=colander.drop,
|
93
|
+
)
|
@@ -1,6 +1,4 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
# Copyright (c) 2018-2020, Camptocamp SA
|
1
|
+
# Copyright (c) 2018-2024, Camptocamp SA
|
4
2
|
# All rights reserved.
|
5
3
|
|
6
4
|
# Redistribution and use in source and binary forms, with or without
|
@@ -28,24 +26,34 @@
|
|
28
26
|
# either expressed or implied, of the FreeBSD Project.
|
29
27
|
|
30
28
|
|
29
|
+
from typing import Any
|
30
|
+
|
31
31
|
import colander
|
32
32
|
from c2cgeoform.ext.deform_ext import RelationCheckBoxListWidget
|
33
33
|
from c2cgeoform.schema import GeoFormManyToManySchemaNode, manytomany_validator
|
34
|
+
from sqlalchemy.orm.attributes import InstrumentedAttribute
|
34
35
|
|
35
|
-
from c2cgeoportal_admin import _
|
36
36
|
from c2cgeoportal_commons.models.main import Interface
|
37
37
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
38
|
+
|
39
|
+
def interfaces_schema_node(
|
40
|
+
prop: InstrumentedAttribute[Any], # pylint: disable=unsubscriptable-object
|
41
|
+
) -> colander.SequenceSchema:
|
42
|
+
"""Get the serializable representation of an interface."""
|
43
|
+
return colander.SequenceSchema(
|
44
|
+
GeoFormManyToManySchemaNode(Interface, None),
|
45
|
+
name=prop.key,
|
46
|
+
title=prop.info["colanderalchemy"]["title"],
|
47
|
+
description=prop.info["colanderalchemy"]["description"],
|
48
|
+
widget=RelationCheckBoxListWidget(
|
49
|
+
Interface,
|
50
|
+
"id",
|
51
|
+
"name",
|
52
|
+
order_by="name",
|
53
|
+
edit_url=lambda request, value: request.route_url(
|
54
|
+
"c2cgeoform_item", table="interfaces", id=value
|
55
|
+
),
|
56
|
+
),
|
57
|
+
validator=manytomany_validator,
|
58
|
+
missing=colander.drop,
|
59
|
+
)
|
@@ -1,6 +1,4 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
# Copyright (c) 2018-2021, Camptocamp SA
|
1
|
+
# Copyright (c) 2018-2024, Camptocamp SA
|
4
2
|
# All rights reserved.
|
5
3
|
|
6
4
|
# Redistribution and use in source and binary forms, with or without
|
@@ -27,32 +25,49 @@
|
|
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
|
-
|
31
28
|
import json
|
32
|
-
from typing import Any,
|
29
|
+
from typing import Any, cast
|
33
30
|
|
34
31
|
import colander
|
32
|
+
import pyramid.request
|
35
33
|
from c2cgeoform.schema import GeoFormSchemaNode
|
36
34
|
from deform.widget import MappingWidget, SelectWidget, SequenceWidget, TextAreaWidget
|
35
|
+
from sqlalchemy import inspect
|
36
|
+
from sqlalchemy.orm.attributes import InstrumentedAttribute
|
37
|
+
from sqlalchemy.orm.mapper import Mapper
|
37
38
|
|
38
39
|
from c2cgeoportal_admin import _
|
39
40
|
from c2cgeoportal_commons.lib.validators import url
|
40
41
|
from c2cgeoportal_commons.models.main import Metadata
|
41
42
|
|
42
43
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
44
|
+
def get_relevant_for(model: type[Any] | Mapper[Any]) -> set[str]:
|
45
|
+
"""Return list of relevant_for values for passed class."""
|
46
|
+
mapper = inspect(model)
|
47
|
+
assert mapper is not None
|
48
|
+
relevant_for = {mapper.local_table.name} # or mapper.polymorphic_identity
|
49
|
+
if mapper.inherits:
|
50
|
+
relevant_for |= get_relevant_for(mapper.inherits)
|
51
|
+
return relevant_for
|
52
|
+
|
53
|
+
|
54
|
+
def metadata_definitions(settings: dict[str, Any], model: type[Any]) -> list[dict[str, Any]]:
|
55
|
+
"""Return filtered list metadata definitions."""
|
56
|
+
return [
|
57
|
+
m
|
58
|
+
for m in settings["admin_interface"]["available_metadata"]
|
59
|
+
if get_relevant_for(model) & set(m.get("relevant_for", ["treeitem"]))
|
60
|
+
]
|
47
61
|
|
48
62
|
|
49
|
-
class MetadataSelectWidget(SelectWidget):
|
50
|
-
"""
|
63
|
+
class MetadataSelectWidget(SelectWidget): # type: ignore
|
64
|
+
"""
|
65
|
+
Extends class SelectWidget to support undefined metadata.
|
51
66
|
|
52
67
|
Override serialize to add option in values for current cstruct when needed.
|
53
68
|
"""
|
54
69
|
|
55
|
-
def serialize(self, field, cstruct, **kw):
|
70
|
+
def serialize(self, field: Any, cstruct: Any, **kw: Any) -> Any:
|
56
71
|
values = kw.get("values", self.values)
|
57
72
|
if isinstance(cstruct, str) and (cstruct, cstruct) not in values:
|
58
73
|
values = values.copy()
|
@@ -61,21 +76,26 @@ class MetadataSelectWidget(SelectWidget):
|
|
61
76
|
return super().serialize(field, cstruct, **kw)
|
62
77
|
|
63
78
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
79
|
+
def metadata_name_widget(model: type[Any]) -> colander.deferred:
|
80
|
+
"""Return a colander deferred which itself returns a widget for the metadata name field."""
|
81
|
+
|
82
|
+
def create_widget(node, kw):
|
83
|
+
del node
|
84
|
+
return MetadataSelectWidget(
|
85
|
+
values=[
|
86
|
+
(m["name"], m["name"])
|
87
|
+
for m in sorted(
|
88
|
+
metadata_definitions(kw["request"].registry.settings, model),
|
89
|
+
key=lambda m: cast(str, m["name"]),
|
90
|
+
)
|
91
|
+
]
|
92
|
+
)
|
93
|
+
|
94
|
+
return colander.deferred(create_widget)
|
76
95
|
|
77
96
|
|
78
97
|
def json_validator(node, value):
|
98
|
+
"""Validate the value to be a valid JSON."""
|
79
99
|
try:
|
80
100
|
json.loads(value)
|
81
101
|
except ValueError as e:
|
@@ -83,6 +103,7 @@ def json_validator(node, value):
|
|
83
103
|
|
84
104
|
|
85
105
|
def regex_validator(node, value):
|
106
|
+
"""Validate the value with a regexp."""
|
86
107
|
definition = node.metadata_definitions.get(value["name"], {})
|
87
108
|
if definition.get("type", "string") == "regex":
|
88
109
|
validator = colander.Regex(definition["regex"], msg=_(definition["error_message"]))
|
@@ -91,11 +112,11 @@ def regex_validator(node, value):
|
|
91
112
|
except colander.Invalid as e:
|
92
113
|
error = colander.Invalid(node)
|
93
114
|
error.add(e, node.children.index(node["string"]))
|
94
|
-
raise error
|
115
|
+
raise error from e
|
95
116
|
|
96
117
|
|
97
|
-
class BooleanMetadata(colander.Boolean):
|
98
|
-
"""Boolean metadata values are stored as string in database"""
|
118
|
+
class BooleanMetadata(colander.Boolean): # type: ignore
|
119
|
+
"""Boolean metadata values are stored as string in database."""
|
99
120
|
|
100
121
|
def serialize(self, node, appstruct):
|
101
122
|
if appstruct == "true":
|
@@ -116,13 +137,14 @@ class BooleanMetadata(colander.Boolean):
|
|
116
137
|
|
117
138
|
|
118
139
|
class MetadataSchemaNode(GeoFormSchemaNode): # pylint: disable=abstract-method
|
140
|
+
"""The metadata schema."""
|
119
141
|
|
120
|
-
metadata_definitions:
|
142
|
+
metadata_definitions: dict[str, Any] | None = None
|
121
143
|
|
122
|
-
def __init__(self, *args, **kw):
|
144
|
+
def __init__(self, *args: Any, **kw: Any):
|
123
145
|
super().__init__(*args, **kw)
|
124
146
|
|
125
|
-
self.available_types:
|
147
|
+
self.available_types: list[str] = []
|
126
148
|
|
127
149
|
self._add_value_node("string", colander.String())
|
128
150
|
self._add_value_node("liste", colander.String())
|
@@ -134,10 +156,17 @@ class MetadataSchemaNode(GeoFormSchemaNode): # pylint: disable=abstract-method
|
|
134
156
|
"json", colander.String(), widget=TextAreaWidget(rows=10), validator=json_validator
|
135
157
|
)
|
136
158
|
|
137
|
-
def _add_value_node(self, type_name, colander_type, **kw):
|
159
|
+
def _add_value_node(self, type_name: str, colander_type: colander.SchemaType, **kw: Any) -> None:
|
138
160
|
self.add_before(
|
139
161
|
"description",
|
140
|
-
colander.SchemaNode(
|
162
|
+
colander.SchemaNode(
|
163
|
+
colander_type,
|
164
|
+
name=type_name,
|
165
|
+
title=Metadata.value.info["colanderalchemy"]["title"],
|
166
|
+
description=Metadata.value.info["colanderalchemy"]["description"],
|
167
|
+
missing=colander.null,
|
168
|
+
**kw,
|
169
|
+
),
|
141
170
|
)
|
142
171
|
self.available_types.append(type_name)
|
143
172
|
|
@@ -153,24 +182,48 @@ class MetadataSchemaNode(GeoFormSchemaNode): # pylint: disable=abstract-method
|
|
153
182
|
dict_[self._ui_type(obj.name)] = value
|
154
183
|
return dict_
|
155
184
|
|
156
|
-
def _ui_type(self, metadata_name: str):
|
185
|
+
def _ui_type(self, metadata_name: str) -> str:
|
157
186
|
metadata_type = (
|
158
|
-
cast(
|
187
|
+
cast(dict[str, dict[str, str]], self.metadata_definitions)
|
188
|
+
.get(metadata_name, {})
|
189
|
+
.get("type", "string")
|
159
190
|
)
|
160
191
|
return metadata_type if metadata_type in self.available_types else "string"
|
161
192
|
|
162
193
|
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
194
|
+
def _translate_available_metadata(
|
195
|
+
available_metadata: dict[str, Any], request: pyramid.request.Request
|
196
|
+
) -> dict[str, Any]:
|
197
|
+
result = {}
|
198
|
+
result.update(available_metadata)
|
199
|
+
result["description"] = request.localizer.translate(_(available_metadata.get("description", "").strip()))
|
200
|
+
return result
|
201
|
+
|
202
|
+
|
203
|
+
def metadata_schema_node(prop: InstrumentedAttribute[Any], model: type[Any]) -> colander.SequenceSchema:
|
204
|
+
"""Get the schema of a collection of metadata."""
|
205
|
+
|
206
|
+
# Deferred which returns a dictionary with metadata name as key and metadata definition as value.
|
207
|
+
# Needed to get the metadata types on UI side.
|
208
|
+
metadata_definitions_dict = colander.deferred(
|
209
|
+
lambda node, kw: {
|
210
|
+
m["name"]: _translate_available_metadata(m, kw["request"])
|
211
|
+
for m in metadata_definitions(kw["request"].registry.settings, model)
|
212
|
+
}
|
213
|
+
)
|
214
|
+
|
215
|
+
return colander.SequenceSchema(
|
216
|
+
MetadataSchemaNode(
|
217
|
+
Metadata,
|
218
|
+
name="metadata",
|
219
|
+
metadata_definitions=metadata_definitions_dict,
|
220
|
+
validator=regex_validator,
|
221
|
+
widget=MappingWidget(template="metadata"),
|
222
|
+
overrides={"name": {"widget": metadata_name_widget(model)}},
|
223
|
+
),
|
224
|
+
name=prop.key,
|
225
|
+
title=prop.info["colanderalchemy"]["title"],
|
226
|
+
description=prop.info["colanderalchemy"]["description"],
|
227
|
+
metadata_definitions=metadata_definitions_dict,
|
228
|
+
widget=SequenceWidget(template="metadatas", category="structural"),
|
229
|
+
)
|
@@ -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,26 +26,34 @@
|
|
28
26
|
# either expressed or implied, of the FreeBSD Project.
|
29
27
|
|
30
28
|
|
29
|
+
from typing import Any
|
30
|
+
|
31
31
|
import colander
|
32
32
|
from c2cgeoform.ext.deform_ext import RelationCheckBoxListWidget
|
33
33
|
from c2cgeoform.schema import GeoFormManyToManySchemaNode, manytomany_validator
|
34
|
+
from sqlalchemy.orm.attributes import InstrumentedAttribute
|
34
35
|
|
35
|
-
from c2cgeoportal_admin import _
|
36
36
|
from c2cgeoportal_commons.models.main import RestrictionArea
|
37
37
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
38
|
+
|
39
|
+
def restrictionareas_schema_node(
|
40
|
+
prop: InstrumentedAttribute[Any], # pylint: disable=unsubscriptable-object
|
41
|
+
) -> colander.SequenceSchema:
|
42
|
+
"""Get the schema of a restriction area."""
|
43
|
+
return colander.SequenceSchema(
|
44
|
+
GeoFormManyToManySchemaNode(RestrictionArea, None),
|
45
|
+
name=prop.key,
|
46
|
+
title=prop.info["colanderalchemy"]["title"],
|
47
|
+
description=prop.info["colanderalchemy"].get("description"),
|
48
|
+
widget=RelationCheckBoxListWidget(
|
49
|
+
RestrictionArea,
|
50
|
+
"id",
|
51
|
+
"name",
|
52
|
+
order_by="name",
|
53
|
+
edit_url=lambda request, value: request.route_url(
|
54
|
+
"c2cgeoform_item", table="restriction_areas", id=value
|
55
|
+
),
|
49
56
|
),
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
)
|
57
|
+
validator=manytomany_validator,
|
58
|
+
missing=colander.drop,
|
59
|
+
)
|
@@ -1,6 +1,4 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
# Copyright (c) 2018-2020, Camptocamp SA
|
1
|
+
# Copyright (c) 2018-2024, Camptocamp SA
|
4
2
|
# All rights reserved.
|
5
3
|
|
6
4
|
# Redistribution and use in source and binary forms, with or without
|
@@ -28,17 +26,25 @@
|
|
28
26
|
# either expressed or implied, of the FreeBSD Project.
|
29
27
|
|
30
28
|
|
29
|
+
from typing import Any
|
30
|
+
|
31
31
|
import colander
|
32
32
|
from c2cgeoform.ext.deform_ext import RelationCheckBoxListWidget
|
33
33
|
from c2cgeoform.schema import GeoFormManyToManySchemaNode, manytomany_validator
|
34
|
+
from sqlalchemy.orm.attributes import InstrumentedAttribute
|
34
35
|
|
35
36
|
from c2cgeoportal_commons.models.main import Role
|
36
37
|
|
37
38
|
|
38
|
-
def roles_schema_node(
|
39
|
+
def roles_schema_node(
|
40
|
+
prop: InstrumentedAttribute[Any], # pylint: disable=unsubscriptable-object
|
41
|
+
) -> colander.SequenceSchema:
|
42
|
+
"""Get the schema of all the items."""
|
39
43
|
return colander.SequenceSchema(
|
40
|
-
GeoFormManyToManySchemaNode(Role),
|
41
|
-
name=
|
44
|
+
GeoFormManyToManySchemaNode(Role, None),
|
45
|
+
name=prop.key,
|
46
|
+
title=prop.info["colanderalchemy"]["title"],
|
47
|
+
description=prop.info["colanderalchemy"].get("description"),
|
42
48
|
widget=RelationCheckBoxListWidget(
|
43
49
|
Role,
|
44
50
|
"id",
|