c2cgeoportal-commons 2.7.1.145__py3-none-any.whl → 2.9.0.350__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_commons/__init__.py +1 -1
- c2cgeoportal_commons/alembic/env.py +18 -15
- c2cgeoportal_commons/alembic/main/028477929d13_add_technical_roles.py +3 -3
- c2cgeoportal_commons/alembic/main/04f05bfbb05e_remove_the_old_is_expanded_column.py +3 -1
- c2cgeoportal_commons/alembic/main/116b9b79fc4d_internal_and_external_layer_tables_.py +35 -39
- c2cgeoportal_commons/alembic/main/1418cb05921b_merge_1_6_and_master_branches.py +2 -4
- c2cgeoportal_commons/alembic/main/164ac0819a61_add_image_format_to_wmts_layer.py +2 -2
- c2cgeoportal_commons/alembic/main/166ff2dcc48d_create_database.py +5 -5
- c2cgeoportal_commons/alembic/main/16e43f8c0330_remove_old_metadata_column.py +2 -2
- c2cgeoportal_commons/alembic/main/1d5d4abfebd1_add_restricted_theme.py +3 -3
- c2cgeoportal_commons/alembic/main/1de20166b274_remove_v1_artifacts.py +2 -2
- c2cgeoportal_commons/alembic/main/20137477bd02_update_icons_url.py +2 -2
- c2cgeoportal_commons/alembic/main/21f11066f8ec_trigger_on_role_updates_user_in_static.py +14 -16
- c2cgeoportal_commons/alembic/main/22e6dfb556de_add_description_tree_.py +2 -2
- c2cgeoportal_commons/alembic/main/29f2a32859ec_merge_1_6_and_master_branches.py +2 -4
- c2cgeoportal_commons/alembic/main/2b8ed8c1df94_set_layergroup_treeitem_is_as_a_primary_.py +2 -2
- c2cgeoportal_commons/alembic/main/2e57710fecfe_update_the_ogc_server_for_ogc_api.py +77 -0
- c2cgeoportal_commons/alembic/main/32527659d57b_move_exclude_properties_from_layerv1_to_.py +8 -8
- c2cgeoportal_commons/alembic/main/32b21aa1d0ed_merge_e004f76e951a_and_e004f76e951a_.py +2 -4
- c2cgeoportal_commons/alembic/main/338b57593823_remove_trigger_on_role_name_change.py +16 -18
- c2cgeoportal_commons/alembic/main/415746eb9f6_changes_for_v2.py +31 -31
- c2cgeoportal_commons/alembic/main/44c91d82d419_add_table_log.py +72 -0
- c2cgeoportal_commons/alembic/main/5109242131ce_add_column_time_widget.py +4 -3
- c2cgeoportal_commons/alembic/main/52916d8fde8b_add_sql_fields_to_vector_tiles.py +5 -3
- c2cgeoportal_commons/alembic/main/53ba1a68d5fe_add_theme_to_fulltextsearch.py +2 -2
- c2cgeoportal_commons/alembic/main/54645a535ad6_add_ordering_in_relation.py +10 -10
- c2cgeoportal_commons/alembic/main/56dc90838d90_fix_removing_layerv1.py +2 -2
- c2cgeoportal_commons/alembic/main/596ba21e3833_separate_local_internal.py +6 -10
- c2cgeoportal_commons/alembic/main/678f88c7ad5e_add_vector_tiles_layers_table.py +2 -2
- c2cgeoportal_commons/alembic/main/6a412d9437b1_rename_serverogc_to_ogcserver.py +4 -4
- c2cgeoportal_commons/alembic/main/6d87fdad275a_convert_metadata_to_the_right_case.py +2 -2
- c2cgeoportal_commons/alembic/main/7530011a66a7_trigger_on_role_updates_user_in_static.py +14 -16
- c2cgeoportal_commons/alembic/main/78fd093c8393_add_api_s_intrfaces.py +30 -49
- c2cgeoportal_commons/alembic/main/7d271f4527cd_add_layer_column_in_layerv1_table.py +2 -2
- c2cgeoportal_commons/alembic/main/809650bd04c3_add_dimension_field.py +2 -2
- c2cgeoportal_commons/alembic/main/8117bb9bba16_use_dimension_on_all_the_layers.py +4 -4
- c2cgeoportal_commons/alembic/main/87f8330ed64e_add_missing_delete_cascades.py +2 -2
- c2cgeoportal_commons/alembic/main/9268a1dffac0_add_trigger_to_be_able_to_correctly_.py +2 -2
- c2cgeoportal_commons/alembic/main/94db7e7e5b21_merge_2_2_and_master_branches.py +2 -4
- c2cgeoportal_commons/alembic/main/951ff84bd8ec_be_able_to_delete_a_wms_layer_in_sql.py +2 -2
- c2cgeoportal_commons/alembic/main/a00109812f89_add_field_layer_wms_valid.py +4 -4
- c2cgeoportal_commons/alembic/main/a4558f032d7d_add_support_of_cog_layers.py +74 -0
- c2cgeoportal_commons/alembic/main/a4f1aac9bda_merge_1_6_and_master_branches.py +2 -4
- c2cgeoportal_commons/alembic/main/b60f2a505f42_remame_uimetadata_to_metadata.py +2 -2
- c2cgeoportal_commons/alembic/main/b6b09f414fe8_sync_model_database.py +174 -0
- c2cgeoportal_commons/alembic/main/c75124553bf3_remove_deprecated_columns.py +2 -2
- c2cgeoportal_commons/alembic/main/d48a63b348f1_change_mapserver_url_for_docker.py +6 -10
- c2cgeoportal_commons/alembic/main/d8ef99bc227e_be_able_to_delete_a_linked_functionality.py +2 -2
- c2cgeoportal_commons/alembic/main/daf738d5bae4_merge_2_0_and_master_branches.py +2 -4
- c2cgeoportal_commons/alembic/main/dba87f2647f9_merge_2_2_on_2_3.py +2 -4
- c2cgeoportal_commons/alembic/main/e004f76e951a_add_missing_not_null.py +6 -22
- c2cgeoportal_commons/alembic/main/e7e03dedade3_put_the_default_wms_server_in_the_.py +6 -10
- c2cgeoportal_commons/alembic/main/e85afd327ab3_cascade_deletes_to_tsearch.py +2 -2
- c2cgeoportal_commons/alembic/main/ec82a8906649_add_missing_on_delete_cascade_on_layer_.py +2 -2
- c2cgeoportal_commons/alembic/main/ee25d267bf46_main_interface_desktop.py +4 -10
- c2cgeoportal_commons/alembic/main/eeb345672454_merge_2_4_and_master_branches.py +2 -4
- c2cgeoportal_commons/alembic/static/0c640a58a09a_add_opt_key_column.py +2 -2
- c2cgeoportal_commons/alembic/static/107b81f5b9fe_add_missing_delete_cascades.py +2 -2
- c2cgeoportal_commons/alembic/static/1857owc78a07_add_last_login_and_expiration_date.py +2 -2
- c2cgeoportal_commons/alembic/static/1da396a88908_move_user_table_to_static_schema.py +6 -10
- c2cgeoportal_commons/alembic/static/267b4c1bde2e_add_display_name_in_the_user_for_better_.py +62 -0
- c2cgeoportal_commons/alembic/static/3f89a7d71a5e_alter_column_url_to_remove_limitation.py +2 -2
- c2cgeoportal_commons/alembic/static/44c91d82d419_add_table_log.py +72 -0
- c2cgeoportal_commons/alembic/static/53d671b17b20_add_timezone_on_datetime_fields.py +2 -2
- c2cgeoportal_commons/alembic/static/5472fbc19f39_add_temp_password_column.py +2 -2
- c2cgeoportal_commons/alembic/static/76d72fb3fcb9_add_oauth2_pkce.py +70 -0
- c2cgeoportal_commons/alembic/static/7ef947f30f20_add_oauth2_tables.py +3 -1
- c2cgeoportal_commons/alembic/static/910b4ca53b68_sync_model_database.py +186 -0
- c2cgeoportal_commons/alembic/static/aa41e9613256_wip_add_openid_connect_support.py +64 -0
- c2cgeoportal_commons/alembic/static/ae5e88f35669_add_table_user_role.py +8 -14
- c2cgeoportal_commons/alembic/static/bd029dbfc11a_fill_tech_data_column.py +2 -2
- c2cgeoportal_commons/lib/email_.py +15 -19
- c2cgeoportal_commons/lib/literal.py +3 -3
- c2cgeoportal_commons/lib/url.py +15 -16
- c2cgeoportal_commons/lib/validators.py +1 -3
- c2cgeoportal_commons/models/__init__.py +16 -9
- c2cgeoportal_commons/models/main.py +415 -226
- c2cgeoportal_commons/models/sqlalchemy.py +13 -13
- c2cgeoportal_commons/models/static.py +162 -71
- c2cgeoportal_commons/testing/__init__.py +12 -7
- c2cgeoportal_commons/testing/initializedb.py +7 -6
- {c2cgeoportal_commons-2.7.1.145.dist-info → c2cgeoportal_commons-2.9.0.350.dist-info}/METADATA +4 -5
- c2cgeoportal_commons-2.9.0.350.dist-info/RECORD +89 -0
- {c2cgeoportal_commons-2.7.1.145.dist-info → c2cgeoportal_commons-2.9.0.350.dist-info}/WHEEL +1 -1
- tests/conftest.py +1 -1
- c2cgeoportal_commons-2.7.1.145.dist-info/RECORD +0 -80
- {c2cgeoportal_commons-2.7.1.145.dist-info → c2cgeoportal_commons-2.9.0.350.dist-info}/top_level.txt +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright (c) 2011-
|
|
1
|
+
# Copyright (c) 2011-2025, Camptocamp SA
|
|
2
2
|
# All rights reserved.
|
|
3
3
|
|
|
4
4
|
# Redistribution and use in source and binary forms, with or without
|
|
@@ -26,10 +26,12 @@
|
|
|
26
26
|
# either expressed or implied, of the FreeBSD Project.
|
|
27
27
|
|
|
28
28
|
|
|
29
|
+
import enum
|
|
29
30
|
import logging
|
|
30
31
|
import os
|
|
31
32
|
import re
|
|
32
|
-
from
|
|
33
|
+
from datetime import datetime
|
|
34
|
+
from typing import Any, Literal, Optional, cast, get_args
|
|
33
35
|
|
|
34
36
|
import pyramid.request
|
|
35
37
|
import sqlalchemy.orm.base
|
|
@@ -38,24 +40,29 @@ from geoalchemy2 import Geometry
|
|
|
38
40
|
from geoalchemy2.shape import to_shape
|
|
39
41
|
from papyrus.geo_interface import GeoInterface
|
|
40
42
|
from sqlalchemy import Column, ForeignKey, Table, UniqueConstraint, event
|
|
41
|
-
from sqlalchemy.
|
|
43
|
+
from sqlalchemy.ext.declarative import AbstractConcreteBase
|
|
44
|
+
from sqlalchemy.orm import Mapped, Session, backref, mapped_column, relationship
|
|
42
45
|
from sqlalchemy.schema import Index
|
|
43
|
-
from sqlalchemy.types import Boolean, Enum, Integer, String, Unicode
|
|
46
|
+
from sqlalchemy.types import Boolean, DateTime, Enum, Integer, String, Unicode
|
|
44
47
|
|
|
45
|
-
|
|
48
|
+
import c2cgeoportal_commons.lib.literal
|
|
46
49
|
from c2cgeoportal_commons.lib.url import get_url2
|
|
47
50
|
from c2cgeoportal_commons.models import Base, _, cache_invalidate_cb
|
|
48
51
|
from c2cgeoportal_commons.models.sqlalchemy import JSONEncodedDict, TsVector
|
|
49
52
|
|
|
50
53
|
try:
|
|
54
|
+
import colander
|
|
51
55
|
from c2cgeoform import default_map_settings
|
|
52
56
|
from c2cgeoform.ext.colander_ext import Geometry as ColanderGeometry
|
|
53
57
|
from c2cgeoform.ext.deform_ext import MapWidget, RelationSelect2Widget
|
|
54
58
|
from colander import drop
|
|
55
59
|
from deform.widget import CheckboxWidget, HiddenWidget, SelectWidget, TextAreaWidget, TextInputWidget
|
|
60
|
+
|
|
61
|
+
colander_null = colander.null
|
|
56
62
|
except ModuleNotFoundError:
|
|
57
|
-
drop = None
|
|
63
|
+
drop = None # pylint: disable=invalid-name
|
|
58
64
|
default_map_settings = {"srid": 3857, "view": {"projection": "EPSG:3857"}}
|
|
65
|
+
colander_null = None # pylint: disable=invalid-name
|
|
59
66
|
|
|
60
67
|
class GenericClass:
|
|
61
68
|
"""Fallback class implementation."""
|
|
@@ -65,11 +72,11 @@ except ModuleNotFoundError:
|
|
|
65
72
|
|
|
66
73
|
CheckboxWidget = GenericClass
|
|
67
74
|
HiddenWidget = GenericClass
|
|
68
|
-
MapWidget = GenericClass
|
|
75
|
+
MapWidget = GenericClass # type: ignore[misc,assignment]
|
|
69
76
|
SelectWidget = GenericClass
|
|
70
77
|
TextAreaWidget = GenericClass
|
|
71
|
-
ColanderGeometry = GenericClass
|
|
72
|
-
RelationSelect2Widget = GenericClass
|
|
78
|
+
ColanderGeometry = GenericClass # type: ignore[misc,assignment]
|
|
79
|
+
RelationSelect2Widget = GenericClass # type: ignore[misc,assignment]
|
|
73
80
|
TextInputWidget = GenericClass
|
|
74
81
|
|
|
75
82
|
|
|
@@ -84,14 +91,16 @@ if os.environ.get("DEVELOPMENT", "0") == "1":
|
|
|
84
91
|
# information
|
|
85
92
|
sqlalchemy.orm.base.state_str = state_str
|
|
86
93
|
|
|
87
|
-
|
|
94
|
+
_LOG = logging.getLogger(__name__)
|
|
88
95
|
|
|
89
96
|
_schema: str = config["schema"] or "main"
|
|
90
97
|
_srid: int = cast(int, config["srid"]) or 3857
|
|
91
98
|
|
|
92
99
|
# Set some default values for the admin interface
|
|
93
|
-
|
|
94
|
-
|
|
100
|
+
conf = config.get_config()
|
|
101
|
+
assert conf is not None
|
|
102
|
+
_admin_config: dict[str, Any] = conf.get("admin_interface", {})
|
|
103
|
+
_map_config: dict[str, Any] = {**default_map_settings, **_admin_config.get("map", {})}
|
|
95
104
|
view_srid_match = re.match(r"EPSG:(\d+)", _map_config["view"]["projection"])
|
|
96
105
|
if "map_srid" not in _admin_config and view_srid_match is not None:
|
|
97
106
|
_admin_config["map_srid"] = view_srid_match.group(1)
|
|
@@ -101,22 +110,30 @@ class FullTextSearch(GeoInterface, Base): # type: ignore
|
|
|
101
110
|
"""The tsearch table representation."""
|
|
102
111
|
|
|
103
112
|
__tablename__ = "tsearch"
|
|
104
|
-
__table_args__ = (
|
|
113
|
+
__table_args__ = (
|
|
114
|
+
Index("tsearch_search_index", "ts", "public", "role_id", "interface_id", "lang"),
|
|
115
|
+
Index("tsearch_ts_idx", "ts", postgresql_using="gin"),
|
|
116
|
+
{"schema": _schema},
|
|
117
|
+
)
|
|
105
118
|
|
|
106
|
-
id =
|
|
107
|
-
label =
|
|
108
|
-
layer_name =
|
|
109
|
-
role_id =
|
|
119
|
+
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
120
|
+
label: Mapped[str] = mapped_column(Unicode)
|
|
121
|
+
layer_name: Mapped[str] = mapped_column(Unicode, nullable=True)
|
|
122
|
+
role_id: Mapped[int] = mapped_column(
|
|
123
|
+
Integer, ForeignKey(_schema + ".role.id", ondelete="CASCADE"), nullable=True
|
|
124
|
+
)
|
|
110
125
|
role = relationship("Role")
|
|
111
|
-
interface_id =
|
|
126
|
+
interface_id: Mapped[int] = mapped_column(
|
|
127
|
+
Integer, ForeignKey(_schema + ".interface.id", ondelete="CASCADE"), nullable=True
|
|
128
|
+
)
|
|
112
129
|
interface = relationship("Interface")
|
|
113
|
-
lang =
|
|
114
|
-
public =
|
|
115
|
-
ts =
|
|
116
|
-
the_geom =
|
|
117
|
-
params =
|
|
118
|
-
actions =
|
|
119
|
-
from_theme =
|
|
130
|
+
lang: Mapped[str] = mapped_column(String(2), nullable=True)
|
|
131
|
+
public: Mapped[bool] = mapped_column(Boolean, server_default="true")
|
|
132
|
+
ts = mapped_column(TsVector)
|
|
133
|
+
the_geom = mapped_column(Geometry("GEOMETRY", srid=_srid, spatial_index=False))
|
|
134
|
+
params = mapped_column(JSONEncodedDict, nullable=True)
|
|
135
|
+
actions = mapped_column(JSONEncodedDict, nullable=True)
|
|
136
|
+
from_theme: Mapped[bool] = mapped_column(Boolean, server_default="false")
|
|
120
137
|
|
|
121
138
|
def __str__(self) -> str:
|
|
122
139
|
return f"{self.label}[{self.id}]"
|
|
@@ -131,8 +148,10 @@ class Functionality(Base): # type: ignore
|
|
|
131
148
|
|
|
132
149
|
__c2cgeoform_config__ = {"duplicate": True}
|
|
133
150
|
|
|
134
|
-
id
|
|
135
|
-
|
|
151
|
+
id: Mapped[int] = mapped_column(
|
|
152
|
+
Integer, primary_key=True, info={"colanderalchemy": {"widget": HiddenWidget()}}
|
|
153
|
+
)
|
|
154
|
+
name: Mapped[str] = mapped_column(
|
|
136
155
|
Unicode,
|
|
137
156
|
nullable=False,
|
|
138
157
|
info={
|
|
@@ -152,7 +171,7 @@ class Functionality(Base): # type: ignore
|
|
|
152
171
|
}
|
|
153
172
|
},
|
|
154
173
|
)
|
|
155
|
-
description =
|
|
174
|
+
description: Mapped[str | None] = mapped_column(
|
|
156
175
|
Unicode,
|
|
157
176
|
info={
|
|
158
177
|
"colanderalchemy": {
|
|
@@ -161,7 +180,7 @@ class Functionality(Base): # type: ignore
|
|
|
161
180
|
}
|
|
162
181
|
},
|
|
163
182
|
)
|
|
164
|
-
value =
|
|
183
|
+
value: Mapped[str] = mapped_column(
|
|
165
184
|
Unicode,
|
|
166
185
|
nullable=False,
|
|
167
186
|
info={
|
|
@@ -222,8 +241,10 @@ class Role(Base): # type: ignore
|
|
|
222
241
|
__colanderalchemy_config__ = {"title": _("Role"), "plural": _("Roles")}
|
|
223
242
|
__c2cgeoform_config__ = {"duplicate": True}
|
|
224
243
|
|
|
225
|
-
id
|
|
226
|
-
|
|
244
|
+
id: Mapped[int] = mapped_column(
|
|
245
|
+
Integer, primary_key=True, info={"colanderalchemy": {"widget": HiddenWidget()}}
|
|
246
|
+
)
|
|
247
|
+
name: Mapped[str] = mapped_column(
|
|
227
248
|
Unicode,
|
|
228
249
|
unique=True,
|
|
229
250
|
nullable=False,
|
|
@@ -234,7 +255,7 @@ class Role(Base): # type: ignore
|
|
|
234
255
|
}
|
|
235
256
|
},
|
|
236
257
|
)
|
|
237
|
-
description =
|
|
258
|
+
description: Mapped[str | None] = mapped_column(
|
|
238
259
|
Unicode,
|
|
239
260
|
info={
|
|
240
261
|
"colanderalchemy": {
|
|
@@ -243,8 +264,8 @@ class Role(Base): # type: ignore
|
|
|
243
264
|
}
|
|
244
265
|
},
|
|
245
266
|
)
|
|
246
|
-
extent =
|
|
247
|
-
Geometry("POLYGON", srid=_srid),
|
|
267
|
+
extent = mapped_column(
|
|
268
|
+
Geometry("POLYGON", srid=_srid, spatial_index=False),
|
|
248
269
|
info={
|
|
249
270
|
"colanderalchemy": {
|
|
250
271
|
"title": _("Extent"),
|
|
@@ -273,8 +294,8 @@ class Role(Base): # type: ignore
|
|
|
273
294
|
self,
|
|
274
295
|
name: str = "",
|
|
275
296
|
description: str = "",
|
|
276
|
-
functionalities:
|
|
277
|
-
extent: Geometry = None,
|
|
297
|
+
functionalities: list[Functionality] | None = None,
|
|
298
|
+
extent: Geometry | None = None,
|
|
278
299
|
) -> None:
|
|
279
300
|
if functionalities is None:
|
|
280
301
|
functionalities = []
|
|
@@ -287,10 +308,10 @@ class Role(Base): # type: ignore
|
|
|
287
308
|
return f"{self.name}[{self.id}]>"
|
|
288
309
|
|
|
289
310
|
@property
|
|
290
|
-
def bounds(self) ->
|
|
311
|
+
def bounds(self) -> tuple[float, float, float, float] | None: # TODO
|
|
291
312
|
if self.extent is None:
|
|
292
313
|
return None
|
|
293
|
-
return cast(
|
|
314
|
+
return cast(tuple[float, float, float, float], to_shape(self.extent).bounds)
|
|
294
315
|
|
|
295
316
|
|
|
296
317
|
event.listen(Role.functionalities, "set", cache_invalidate_cb)
|
|
@@ -302,15 +323,17 @@ class TreeItem(Base): # type: ignore
|
|
|
302
323
|
"""The treeitem table representation."""
|
|
303
324
|
|
|
304
325
|
__tablename__ = "treeitem"
|
|
305
|
-
__table_args__:
|
|
326
|
+
__table_args__: tuple[Any, ...] | dict[str, Any] = (
|
|
306
327
|
UniqueConstraint("type", "name"),
|
|
307
328
|
{"schema": _schema},
|
|
308
329
|
)
|
|
309
|
-
item_type =
|
|
330
|
+
item_type: Mapped[str] = mapped_column(
|
|
331
|
+
"type", String(10), nullable=False, info={"colanderalchemy": {"exclude": True}}
|
|
332
|
+
)
|
|
310
333
|
__mapper_args__ = {"polymorphic_on": item_type}
|
|
311
334
|
|
|
312
|
-
id =
|
|
313
|
-
name =
|
|
335
|
+
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
336
|
+
name: Mapped[str] = mapped_column(
|
|
314
337
|
Unicode,
|
|
315
338
|
nullable=False,
|
|
316
339
|
info={
|
|
@@ -325,7 +348,7 @@ class TreeItem(Base): # type: ignore
|
|
|
325
348
|
}
|
|
326
349
|
},
|
|
327
350
|
)
|
|
328
|
-
description =
|
|
351
|
+
description: Mapped[str | None] = mapped_column(
|
|
329
352
|
Unicode,
|
|
330
353
|
info={
|
|
331
354
|
"colanderalchemy": {
|
|
@@ -337,7 +360,7 @@ class TreeItem(Base): # type: ignore
|
|
|
337
360
|
|
|
338
361
|
@property
|
|
339
362
|
# Better: def parents(self) -> List[TreeGroup]:
|
|
340
|
-
def parents(self) ->
|
|
363
|
+
def parents(self) -> list["TreeItem"]:
|
|
341
364
|
return [c.treegroup for c in self.parents_relation]
|
|
342
365
|
|
|
343
366
|
def is_in_interface(self, name: str) -> bool:
|
|
@@ -350,7 +373,7 @@ class TreeItem(Base): # type: ignore
|
|
|
350
373
|
|
|
351
374
|
return False
|
|
352
375
|
|
|
353
|
-
def get_metadata(self, name: str) ->
|
|
376
|
+
def get_metadata(self, name: str) -> list["Metadata"]:
|
|
354
377
|
return [metadata for metadata in self.metadatas if metadata.name == name]
|
|
355
378
|
|
|
356
379
|
def __init__(self, name: str = "") -> None:
|
|
@@ -373,11 +396,13 @@ class LayergroupTreeitem(Base): # type: ignore
|
|
|
373
396
|
__table_args__ = {"schema": _schema}
|
|
374
397
|
|
|
375
398
|
# required by formalchemy
|
|
376
|
-
id
|
|
377
|
-
|
|
378
|
-
|
|
399
|
+
id: Mapped[int] = mapped_column(
|
|
400
|
+
Integer, primary_key=True, info={"colanderalchemy": {"widget": HiddenWidget()}}
|
|
401
|
+
)
|
|
402
|
+
description: Mapped[str | None] = mapped_column(Unicode, info={"colanderalchemy": {"exclude": True}})
|
|
403
|
+
treegroup_id: Mapped[int] = mapped_column(
|
|
379
404
|
Integer,
|
|
380
|
-
ForeignKey(_schema + ".treegroup.id"),
|
|
405
|
+
ForeignKey(_schema + ".treegroup.id", name="treegroup_id_fkey"),
|
|
381
406
|
nullable=False,
|
|
382
407
|
info={"colanderalchemy": {"exclude": True}},
|
|
383
408
|
)
|
|
@@ -392,9 +417,9 @@ class LayergroupTreeitem(Base): # type: ignore
|
|
|
392
417
|
primaryjoin="LayergroupTreeitem.treegroup_id==TreeGroup.id",
|
|
393
418
|
info={"colanderalchemy": {"exclude": True}, "c2cgeoform": {"duplicate": False}},
|
|
394
419
|
)
|
|
395
|
-
treeitem_id =
|
|
420
|
+
treeitem_id: Mapped[int] = mapped_column(
|
|
396
421
|
Integer,
|
|
397
|
-
ForeignKey(_schema + ".treeitem.id"),
|
|
422
|
+
ForeignKey(_schema + ".treeitem.id", ondelete="CASCADE"),
|
|
398
423
|
nullable=False,
|
|
399
424
|
info={"colanderalchemy": {"widget": HiddenWidget()}},
|
|
400
425
|
)
|
|
@@ -411,10 +436,10 @@ class LayergroupTreeitem(Base): # type: ignore
|
|
|
411
436
|
primaryjoin="LayergroupTreeitem.treeitem_id==TreeItem.id",
|
|
412
437
|
info={"colanderalchemy": {"exclude": True}, "c2cgeoform": {"duplicate": False}},
|
|
413
438
|
)
|
|
414
|
-
ordering =
|
|
439
|
+
ordering: Mapped[int] = mapped_column(Integer, info={"colanderalchemy": {"widget": HiddenWidget()}})
|
|
415
440
|
|
|
416
441
|
def __init__(
|
|
417
|
-
self, group: Optional["TreeGroup"] = None, item:
|
|
442
|
+
self, group: Optional["TreeGroup"] = None, item: TreeItem | None = None, ordering: int = 0
|
|
418
443
|
) -> None:
|
|
419
444
|
self.treegroup = group
|
|
420
445
|
self.treeitem = item
|
|
@@ -434,14 +459,18 @@ class TreeGroup(TreeItem):
|
|
|
434
459
|
|
|
435
460
|
__tablename__ = "treegroup"
|
|
436
461
|
__table_args__ = {"schema": _schema}
|
|
437
|
-
__mapper_args__ = {"polymorphic_identity": "treegroup"} # needed for _identity_class
|
|
462
|
+
__mapper_args__ = {"polymorphic_identity": "treegroup"} # type: ignore[dict-item] # needed for _identity_class
|
|
438
463
|
|
|
439
|
-
id =
|
|
464
|
+
id: Mapped[int] = mapped_column(
|
|
465
|
+
Integer,
|
|
466
|
+
ForeignKey(_schema + ".treeitem.id", ondelete="CASCADE", name="treegroup_id_fkey"),
|
|
467
|
+
primary_key=True,
|
|
468
|
+
)
|
|
440
469
|
|
|
441
|
-
def _get_children(self) ->
|
|
470
|
+
def _get_children(self) -> list[TreeItem]:
|
|
442
471
|
return [c.treeitem for c in self.children_relation]
|
|
443
472
|
|
|
444
|
-
def _set_children(self, children:
|
|
473
|
+
def _set_children(self, children: list[TreeItem], order: bool = False) -> None:
|
|
445
474
|
"""
|
|
446
475
|
Set the current TreeGroup children TreeItem instances.
|
|
447
476
|
|
|
@@ -487,7 +516,7 @@ class LayerGroup(TreeGroup):
|
|
|
487
516
|
__colanderalchemy_config__ = {
|
|
488
517
|
"title": _("Layers group"),
|
|
489
518
|
"plural": _("Layers groups"),
|
|
490
|
-
"description": Literal(
|
|
519
|
+
"description": c2cgeoportal_commons.lib.literal.Literal(
|
|
491
520
|
_(
|
|
492
521
|
"""
|
|
493
522
|
<div class="help-block">
|
|
@@ -500,12 +529,12 @@ class LayerGroup(TreeGroup):
|
|
|
500
529
|
)
|
|
501
530
|
),
|
|
502
531
|
}
|
|
503
|
-
__mapper_args__ = {"polymorphic_identity": "group"}
|
|
532
|
+
__mapper_args__ = {"polymorphic_identity": "group"} # type: ignore[dict-item]
|
|
504
533
|
__c2cgeoform_config__ = {"duplicate": True}
|
|
505
534
|
|
|
506
|
-
id =
|
|
535
|
+
id: Mapped[int] = mapped_column(
|
|
507
536
|
Integer,
|
|
508
|
-
ForeignKey(_schema + ".treegroup.id"),
|
|
537
|
+
ForeignKey(_schema + ".treegroup.id", ondelete="CASCADE"),
|
|
509
538
|
primary_key=True,
|
|
510
539
|
info={"colanderalchemy": {"missing": drop, "widget": HiddenWidget()}},
|
|
511
540
|
)
|
|
@@ -530,19 +559,19 @@ class Theme(TreeGroup):
|
|
|
530
559
|
__tablename__ = "theme"
|
|
531
560
|
__table_args__ = {"schema": _schema}
|
|
532
561
|
__colanderalchemy_config__ = {"title": _("Theme"), "plural": _("Themes")}
|
|
533
|
-
__mapper_args__ = {"polymorphic_identity": "theme"}
|
|
562
|
+
__mapper_args__ = {"polymorphic_identity": "theme"} # type: ignore[dict-item]
|
|
534
563
|
__c2cgeoform_config__ = {"duplicate": True}
|
|
535
564
|
|
|
536
|
-
id =
|
|
565
|
+
id: Mapped[int] = mapped_column(
|
|
537
566
|
Integer,
|
|
538
|
-
ForeignKey(_schema + ".treegroup.id"),
|
|
567
|
+
ForeignKey(_schema + ".treegroup.id", ondelete="CASCADE"),
|
|
539
568
|
primary_key=True,
|
|
540
569
|
info={"colanderalchemy": {"missing": drop, "widget": HiddenWidget()}},
|
|
541
570
|
)
|
|
542
|
-
ordering =
|
|
571
|
+
ordering: Mapped[int] = mapped_column(
|
|
543
572
|
Integer, nullable=False, info={"colanderalchemy": {"title": _("Order"), "widget": HiddenWidget()}}
|
|
544
573
|
)
|
|
545
|
-
public =
|
|
574
|
+
public: Mapped[bool] = mapped_column(
|
|
546
575
|
Boolean,
|
|
547
576
|
default=True,
|
|
548
577
|
nullable=False,
|
|
@@ -553,12 +582,14 @@ class Theme(TreeGroup):
|
|
|
553
582
|
}
|
|
554
583
|
},
|
|
555
584
|
)
|
|
556
|
-
icon =
|
|
585
|
+
icon: Mapped[str] = mapped_column(
|
|
557
586
|
Unicode,
|
|
587
|
+
nullable=True,
|
|
558
588
|
info={
|
|
559
589
|
"colanderalchemy": {
|
|
560
590
|
"title": _("Icon"),
|
|
561
591
|
"description": _("The icon URL."),
|
|
592
|
+
"missing": "",
|
|
562
593
|
}
|
|
563
594
|
},
|
|
564
595
|
)
|
|
@@ -607,15 +638,15 @@ class Layer(TreeItem):
|
|
|
607
638
|
|
|
608
639
|
__tablename__ = "layer"
|
|
609
640
|
__table_args__ = {"schema": _schema}
|
|
610
|
-
__mapper_args__ = {"polymorphic_identity": "layer"} # needed for _identity_class
|
|
641
|
+
__mapper_args__ = {"polymorphic_identity": "layer"} # type: ignore[dict-item] # needed for _identity_class
|
|
611
642
|
|
|
612
|
-
id =
|
|
643
|
+
id: Mapped[int] = mapped_column(
|
|
613
644
|
Integer,
|
|
614
|
-
ForeignKey(_schema + ".treeitem.id"),
|
|
645
|
+
ForeignKey(_schema + ".treeitem.id", ondelete="CASCADE"),
|
|
615
646
|
primary_key=True,
|
|
616
647
|
info={"colanderalchemy": {"widget": HiddenWidget()}},
|
|
617
648
|
)
|
|
618
|
-
public =
|
|
649
|
+
public: Mapped[bool] = mapped_column(
|
|
619
650
|
Boolean,
|
|
620
651
|
default=True,
|
|
621
652
|
info={
|
|
@@ -625,7 +656,7 @@ class Layer(TreeItem):
|
|
|
625
656
|
}
|
|
626
657
|
},
|
|
627
658
|
)
|
|
628
|
-
geo_table =
|
|
659
|
+
geo_table: Mapped[str | None] = mapped_column(
|
|
629
660
|
Unicode,
|
|
630
661
|
info={
|
|
631
662
|
"colanderalchemy": {
|
|
@@ -634,18 +665,22 @@ class Layer(TreeItem):
|
|
|
634
665
|
}
|
|
635
666
|
},
|
|
636
667
|
)
|
|
637
|
-
exclude_properties =
|
|
668
|
+
exclude_properties: Mapped[str] = mapped_column(
|
|
638
669
|
Unicode,
|
|
670
|
+
nullable=True,
|
|
639
671
|
info={
|
|
640
672
|
"colanderalchemy": {
|
|
641
673
|
"title": _("Exclude properties"),
|
|
642
|
-
"description":
|
|
643
|
-
|
|
674
|
+
"description": c2cgeoportal_commons.lib.literal.Literal(
|
|
675
|
+
_(
|
|
676
|
+
"""
|
|
644
677
|
The list of attributes (database columns) that should not appear in
|
|
645
678
|
the editing form so that they cannot be modified by the end user.
|
|
646
|
-
For enumerable attributes (foreign key), the column name should end with
|
|
679
|
+
For enumerable attributes (foreign key), the column name should end with <code>_id</code>.
|
|
647
680
|
"""
|
|
681
|
+
)
|
|
648
682
|
),
|
|
683
|
+
"missing": "",
|
|
649
684
|
}
|
|
650
685
|
},
|
|
651
686
|
)
|
|
@@ -658,19 +693,27 @@ class Layer(TreeItem):
|
|
|
658
693
|
class DimensionLayer(Layer):
|
|
659
694
|
"""The intermediate class for the leyser with dimension."""
|
|
660
695
|
|
|
661
|
-
__mapper_args__ = {"polymorphic_identity": "dimensionlayer"} # needed for _identity_class
|
|
696
|
+
__mapper_args__ = {"polymorphic_identity": "dimensionlayer"} # type: ignore[dict-item] # needed for _identity_class
|
|
662
697
|
|
|
663
698
|
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
699
|
+
OGCServerType = Literal["mapserver", "qgisserver", "geoserver", "arcgis", "other"]
|
|
700
|
+
OGCSERVER_TYPE_MAPSERVER: OGCServerType = "mapserver"
|
|
701
|
+
OGCSERVER_TYPE_QGISSERVER: OGCServerType = "qgisserver"
|
|
702
|
+
OGCSERVER_TYPE_GEOSERVER: OGCServerType = "geoserver"
|
|
703
|
+
OGCSERVER_TYPE_ARCGIS: OGCServerType = "arcgis"
|
|
704
|
+
OGCSERVER_TYPE_OTHER: OGCServerType = "other"
|
|
669
705
|
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
706
|
+
|
|
707
|
+
OGCServerAuth = Literal["No auth", "Standard auth", "Geoserver auth", "Proxy"]
|
|
708
|
+
OGCSERVER_AUTH_NOAUTH: OGCServerAuth = "No auth"
|
|
709
|
+
OGCSERVER_AUTH_STANDARD: OGCServerAuth = "Standard auth"
|
|
710
|
+
OGCSERVER_AUTH_GEOSERVER: OGCServerAuth = "Geoserver auth"
|
|
711
|
+
OGCSERVER_AUTH_PROXY: OGCServerAuth = "Proxy"
|
|
712
|
+
|
|
713
|
+
|
|
714
|
+
ImageType = Literal["image/jpeg", "image/png", "image/webp"]
|
|
715
|
+
TimeMode = Literal["disabled", "value", "range"]
|
|
716
|
+
TimeWidget = Literal["slider", "datepicker"]
|
|
674
717
|
|
|
675
718
|
|
|
676
719
|
class OGCServer(Base): # type: ignore
|
|
@@ -681,7 +724,7 @@ class OGCServer(Base): # type: ignore
|
|
|
681
724
|
__colanderalchemy_config__ = {
|
|
682
725
|
"title": _("OGC Server"),
|
|
683
726
|
"plural": _("OGC Servers"),
|
|
684
|
-
"description": Literal(
|
|
727
|
+
"description": c2cgeoportal_commons.lib.literal.Literal(
|
|
685
728
|
_(
|
|
686
729
|
"""
|
|
687
730
|
<div class="help-block">
|
|
@@ -696,55 +739,58 @@ class OGCServer(Base): # type: ignore
|
|
|
696
739
|
),
|
|
697
740
|
}
|
|
698
741
|
__c2cgeoform_config__ = {"duplicate": True}
|
|
699
|
-
id
|
|
700
|
-
|
|
742
|
+
id: Mapped[int] = mapped_column(
|
|
743
|
+
Integer, primary_key=True, info={"colanderalchemy": {"widget": HiddenWidget()}}
|
|
744
|
+
)
|
|
745
|
+
name: Mapped[str] = mapped_column(
|
|
701
746
|
Unicode,
|
|
702
747
|
nullable=False,
|
|
703
748
|
unique=True,
|
|
704
749
|
info={
|
|
705
750
|
"colanderalchemy": {
|
|
706
751
|
"title": _("Name"),
|
|
707
|
-
"description":
|
|
752
|
+
"description": c2cgeoportal_commons.lib.literal.Literal(
|
|
753
|
+
_(
|
|
754
|
+
"The name of the OGC Server should contain only unaccentuated letters, numbers and _. "
|
|
755
|
+
"When you rename it, do not forget to update the <code>ogcServer</code> metadata on the "
|
|
756
|
+
"WMTS and COG layers."
|
|
757
|
+
)
|
|
758
|
+
),
|
|
708
759
|
}
|
|
709
760
|
},
|
|
710
761
|
)
|
|
711
|
-
description =
|
|
762
|
+
description: Mapped[str | None] = mapped_column(
|
|
712
763
|
Unicode,
|
|
713
764
|
info={
|
|
714
765
|
"colanderalchemy": {
|
|
715
766
|
"title": _("Description"),
|
|
716
|
-
"description": _("
|
|
767
|
+
"description": _("An optional description."),
|
|
717
768
|
}
|
|
718
769
|
},
|
|
719
770
|
)
|
|
720
|
-
url =
|
|
771
|
+
url: Mapped[str] = mapped_column(
|
|
721
772
|
Unicode,
|
|
722
773
|
nullable=False,
|
|
723
774
|
info={
|
|
724
775
|
"colanderalchemy": {
|
|
725
776
|
"title": _("Basic URL"),
|
|
726
|
-
"description": _("The server URL"),
|
|
777
|
+
"description": _("The server URL."),
|
|
727
778
|
}
|
|
728
779
|
},
|
|
729
780
|
)
|
|
730
|
-
url_wfs =
|
|
781
|
+
url_wfs: Mapped[str | None] = mapped_column(
|
|
731
782
|
Unicode,
|
|
732
783
|
info={
|
|
733
784
|
"colanderalchemy": {
|
|
734
785
|
"title": _("WFS URL"),
|
|
735
|
-
"description":
|
|
786
|
+
"description": c2cgeoportal_commons.lib.literal.Literal(
|
|
787
|
+
_("The WFS server URL. If empty, the <code>Basic URL</code> is used.")
|
|
788
|
+
),
|
|
736
789
|
}
|
|
737
790
|
},
|
|
738
791
|
)
|
|
739
|
-
type =
|
|
740
|
-
Enum(
|
|
741
|
-
OGCSERVER_TYPE_MAPSERVER,
|
|
742
|
-
OGCSERVER_TYPE_QGISSERVER,
|
|
743
|
-
OGCSERVER_TYPE_GEOSERVER,
|
|
744
|
-
OGCSERVER_TYPE_ARCGIS,
|
|
745
|
-
OGCSERVER_TYPE_OTHER,
|
|
746
|
-
native_enum=False,
|
|
747
|
-
),
|
|
792
|
+
type: Mapped[OGCServerType] = mapped_column(
|
|
793
|
+
Enum(*get_args(OGCServerType), native_enum=False),
|
|
748
794
|
nullable=False,
|
|
749
795
|
info={
|
|
750
796
|
"colanderalchemy": {
|
|
@@ -752,56 +798,39 @@ class OGCServer(Base): # type: ignore
|
|
|
752
798
|
"description": _(
|
|
753
799
|
"The server type which is used to know which custom attribute will be used."
|
|
754
800
|
),
|
|
755
|
-
"widget": SelectWidget(
|
|
756
|
-
values=(
|
|
757
|
-
(OGCSERVER_TYPE_MAPSERVER, OGCSERVER_TYPE_MAPSERVER),
|
|
758
|
-
(OGCSERVER_TYPE_QGISSERVER, OGCSERVER_TYPE_QGISSERVER),
|
|
759
|
-
(OGCSERVER_TYPE_GEOSERVER, OGCSERVER_TYPE_GEOSERVER),
|
|
760
|
-
(OGCSERVER_TYPE_ARCGIS, OGCSERVER_TYPE_ARCGIS),
|
|
761
|
-
(OGCSERVER_TYPE_OTHER, OGCSERVER_TYPE_OTHER),
|
|
762
|
-
)
|
|
763
|
-
),
|
|
801
|
+
"widget": SelectWidget(values=list((e, e) for e in get_args(OGCServerType))),
|
|
764
802
|
}
|
|
765
803
|
},
|
|
766
804
|
)
|
|
767
|
-
image_type =
|
|
768
|
-
Enum(
|
|
805
|
+
image_type: Mapped[ImageType] = mapped_column(
|
|
806
|
+
Enum(*get_args(ImageType), native_enum=False),
|
|
769
807
|
nullable=False,
|
|
770
808
|
info={
|
|
771
809
|
"colanderalchemy": {
|
|
772
810
|
"title": _("Image type"),
|
|
773
|
-
"description":
|
|
774
|
-
|
|
811
|
+
"description": c2cgeoportal_commons.lib.literal.Literal(
|
|
812
|
+
_(
|
|
813
|
+
"The MIME type of the images (e.g.: <code>image/png</code>, <code>image/webp</code> is experimental)."
|
|
814
|
+
)
|
|
815
|
+
),
|
|
816
|
+
"widget": SelectWidget(values=list((e, e) for e in get_args(ImageType))),
|
|
775
817
|
"column": 2,
|
|
776
818
|
}
|
|
777
819
|
},
|
|
778
820
|
)
|
|
779
|
-
auth =
|
|
780
|
-
Enum(
|
|
781
|
-
OGCSERVER_AUTH_NOAUTH,
|
|
782
|
-
OGCSERVER_AUTH_STANDARD,
|
|
783
|
-
OGCSERVER_AUTH_GEOSERVER,
|
|
784
|
-
OGCSERVER_AUTH_PROXY,
|
|
785
|
-
native_enum=False,
|
|
786
|
-
),
|
|
821
|
+
auth: Mapped[OGCServerAuth] = mapped_column(
|
|
822
|
+
Enum(*get_args(OGCServerAuth), native_enum=False),
|
|
787
823
|
nullable=False,
|
|
788
824
|
info={
|
|
789
825
|
"colanderalchemy": {
|
|
790
826
|
"title": _("Authentication type"),
|
|
791
827
|
"description": "The kind of authentication to use.",
|
|
792
|
-
"widget": SelectWidget(
|
|
793
|
-
values=(
|
|
794
|
-
(OGCSERVER_AUTH_NOAUTH, OGCSERVER_AUTH_NOAUTH),
|
|
795
|
-
(OGCSERVER_AUTH_STANDARD, OGCSERVER_AUTH_STANDARD),
|
|
796
|
-
(OGCSERVER_AUTH_GEOSERVER, OGCSERVER_AUTH_GEOSERVER),
|
|
797
|
-
(OGCSERVER_AUTH_PROXY, OGCSERVER_AUTH_PROXY),
|
|
798
|
-
)
|
|
799
|
-
),
|
|
828
|
+
"widget": SelectWidget(values=list((e, e) for e in get_args(OGCServerAuth))),
|
|
800
829
|
"column": 2,
|
|
801
830
|
}
|
|
802
831
|
},
|
|
803
832
|
)
|
|
804
|
-
wfs_support =
|
|
833
|
+
wfs_support: Mapped[bool] = mapped_column(
|
|
805
834
|
Boolean,
|
|
806
835
|
info={
|
|
807
836
|
"colanderalchemy": {
|
|
@@ -811,7 +840,7 @@ class OGCServer(Base): # type: ignore
|
|
|
811
840
|
}
|
|
812
841
|
},
|
|
813
842
|
)
|
|
814
|
-
is_single_tile =
|
|
843
|
+
is_single_tile: Mapped[bool] = mapped_column(
|
|
815
844
|
Boolean,
|
|
816
845
|
info={
|
|
817
846
|
"colanderalchemy": {
|
|
@@ -825,12 +854,12 @@ class OGCServer(Base): # type: ignore
|
|
|
825
854
|
def __init__(
|
|
826
855
|
self,
|
|
827
856
|
name: str = "",
|
|
828
|
-
description:
|
|
857
|
+
description: str | None = None,
|
|
829
858
|
url: str = "https://wms.example.com",
|
|
830
|
-
url_wfs:
|
|
831
|
-
type_:
|
|
832
|
-
image_type:
|
|
833
|
-
auth:
|
|
859
|
+
url_wfs: str | None = None,
|
|
860
|
+
type_: OGCServerType = OGCSERVER_TYPE_MAPSERVER,
|
|
861
|
+
image_type: ImageType = "image/png",
|
|
862
|
+
auth: OGCServerAuth = OGCSERVER_AUTH_STANDARD,
|
|
834
863
|
wfs_support: bool = True,
|
|
835
864
|
is_single_tile: bool = False,
|
|
836
865
|
) -> None:
|
|
@@ -848,23 +877,18 @@ class OGCServer(Base): # type: ignore
|
|
|
848
877
|
return self.name or ""
|
|
849
878
|
|
|
850
879
|
def url_description(self, request: pyramid.request.Request) -> str:
|
|
851
|
-
errors:
|
|
880
|
+
errors: set[str] = set()
|
|
852
881
|
url = get_url2(self.name, self.url, request, errors)
|
|
853
882
|
return url.url() if url else "\n".join(errors)
|
|
854
883
|
|
|
855
|
-
def url_wfs_description(self, request: pyramid.request.Request) ->
|
|
884
|
+
def url_wfs_description(self, request: pyramid.request.Request) -> str | None:
|
|
856
885
|
if not self.url_wfs:
|
|
857
886
|
return self.url_description(request)
|
|
858
|
-
errors:
|
|
887
|
+
errors: set[str] = set()
|
|
859
888
|
url = get_url2(self.name, self.url_wfs, request, errors)
|
|
860
889
|
return url.url() if url else "\n".join(errors)
|
|
861
890
|
|
|
862
891
|
|
|
863
|
-
event.listen(OGCServer, "after_insert", cache_invalidate_cb, propagate=True)
|
|
864
|
-
event.listen(OGCServer, "after_update", cache_invalidate_cb, propagate=True)
|
|
865
|
-
event.listen(OGCServer, "after_delete", cache_invalidate_cb, propagate=True)
|
|
866
|
-
|
|
867
|
-
|
|
868
892
|
class LayerWMS(DimensionLayer):
|
|
869
893
|
"""The layer_wms table representation."""
|
|
870
894
|
|
|
@@ -873,7 +897,7 @@ class LayerWMS(DimensionLayer):
|
|
|
873
897
|
__colanderalchemy_config__ = {
|
|
874
898
|
"title": _("WMS Layer"),
|
|
875
899
|
"plural": _("WMS Layers"),
|
|
876
|
-
"description": Literal(
|
|
900
|
+
"description": c2cgeoportal_commons.lib.literal.Literal(
|
|
877
901
|
_(
|
|
878
902
|
"""
|
|
879
903
|
<div class="help-block">
|
|
@@ -889,15 +913,15 @@ class LayerWMS(DimensionLayer):
|
|
|
889
913
|
|
|
890
914
|
__c2cgeoform_config__ = {"duplicate": True}
|
|
891
915
|
|
|
892
|
-
__mapper_args__ = {"polymorphic_identity": "l_wms"}
|
|
916
|
+
__mapper_args__ = {"polymorphic_identity": "l_wms"} # type: ignore[dict-item]
|
|
893
917
|
|
|
894
|
-
id =
|
|
918
|
+
id: Mapped[int] = mapped_column(
|
|
895
919
|
Integer,
|
|
896
920
|
ForeignKey(_schema + ".layer.id", ondelete="CASCADE"),
|
|
897
921
|
primary_key=True,
|
|
898
922
|
info={"colanderalchemy": {"missing": None, "widget": HiddenWidget()}},
|
|
899
923
|
)
|
|
900
|
-
ogc_server_id =
|
|
924
|
+
ogc_server_id: Mapped[int] = mapped_column(
|
|
901
925
|
Integer,
|
|
902
926
|
ForeignKey(_schema + ".ogc_server.id"),
|
|
903
927
|
nullable=False,
|
|
@@ -911,7 +935,7 @@ class LayerWMS(DimensionLayer):
|
|
|
911
935
|
}
|
|
912
936
|
},
|
|
913
937
|
)
|
|
914
|
-
layer =
|
|
938
|
+
layer: Mapped[str] = mapped_column(
|
|
915
939
|
Unicode,
|
|
916
940
|
nullable=False,
|
|
917
941
|
info={
|
|
@@ -929,7 +953,7 @@ class LayerWMS(DimensionLayer):
|
|
|
929
953
|
}
|
|
930
954
|
},
|
|
931
955
|
)
|
|
932
|
-
style =
|
|
956
|
+
style: Mapped[str | None] = mapped_column(
|
|
933
957
|
Unicode,
|
|
934
958
|
info={
|
|
935
959
|
"colanderalchemy": {
|
|
@@ -939,30 +963,34 @@ class LayerWMS(DimensionLayer):
|
|
|
939
963
|
}
|
|
940
964
|
},
|
|
941
965
|
)
|
|
942
|
-
valid =
|
|
966
|
+
valid: Mapped[bool] = mapped_column(
|
|
943
967
|
Boolean,
|
|
968
|
+
nullable=True,
|
|
944
969
|
info={
|
|
945
970
|
"colanderalchemy": {
|
|
946
971
|
"title": _("Valid"),
|
|
947
972
|
"description": _("The status reported by latest synchronization (readonly)."),
|
|
948
973
|
"column": 2,
|
|
949
974
|
"widget": CheckboxWidget(readonly=True),
|
|
975
|
+
"missing": colander_null,
|
|
950
976
|
}
|
|
951
977
|
},
|
|
952
978
|
)
|
|
953
|
-
invalid_reason =
|
|
979
|
+
invalid_reason: Mapped[str] = mapped_column(
|
|
954
980
|
Unicode,
|
|
981
|
+
nullable=True,
|
|
955
982
|
info={
|
|
956
983
|
"colanderalchemy": {
|
|
957
984
|
"title": _("Reason why I am not valid"),
|
|
958
985
|
"description": _("The reason for status reported by latest synchronization (readonly)."),
|
|
959
986
|
"column": 2,
|
|
960
987
|
"widget": TextInputWidget(readonly=True),
|
|
988
|
+
"missing": "",
|
|
961
989
|
}
|
|
962
990
|
},
|
|
963
991
|
)
|
|
964
|
-
time_mode =
|
|
965
|
-
Enum(
|
|
992
|
+
time_mode: Mapped[TimeMode] = mapped_column(
|
|
993
|
+
Enum(*get_args(TimeMode), native_enum=False),
|
|
966
994
|
default="disabled",
|
|
967
995
|
nullable=False,
|
|
968
996
|
info={
|
|
@@ -976,8 +1004,8 @@ class LayerWMS(DimensionLayer):
|
|
|
976
1004
|
}
|
|
977
1005
|
},
|
|
978
1006
|
)
|
|
979
|
-
time_widget =
|
|
980
|
-
Enum(
|
|
1007
|
+
time_widget: Mapped[TimeWidget] = mapped_column(
|
|
1008
|
+
Enum(*get_args(TimeWidget), native_enum=False),
|
|
981
1009
|
default="slider",
|
|
982
1010
|
nullable=False,
|
|
983
1011
|
info={
|
|
@@ -1008,8 +1036,8 @@ class LayerWMS(DimensionLayer):
|
|
|
1008
1036
|
name: str = "",
|
|
1009
1037
|
layer: str = "",
|
|
1010
1038
|
public: bool = True,
|
|
1011
|
-
time_mode:
|
|
1012
|
-
time_widget:
|
|
1039
|
+
time_mode: TimeMode = "disabled",
|
|
1040
|
+
time_widget: TimeWidget = "slider",
|
|
1013
1041
|
) -> None:
|
|
1014
1042
|
super().__init__(name=name, public=public)
|
|
1015
1043
|
self.layer = layer
|
|
@@ -1017,7 +1045,7 @@ class LayerWMS(DimensionLayer):
|
|
|
1017
1045
|
self.time_widget = time_widget
|
|
1018
1046
|
|
|
1019
1047
|
@staticmethod
|
|
1020
|
-
def get_default(dbsession: Session) ->
|
|
1048
|
+
def get_default(dbsession: Session) -> DimensionLayer | None:
|
|
1021
1049
|
return cast(
|
|
1022
1050
|
Optional[DimensionLayer],
|
|
1023
1051
|
dbsession.query(LayerWMS).filter(LayerWMS.name == "wms-defaults").one_or_none(),
|
|
@@ -1032,7 +1060,7 @@ class LayerWMTS(DimensionLayer):
|
|
|
1032
1060
|
__colanderalchemy_config__ = {
|
|
1033
1061
|
"title": _("WMTS Layer"),
|
|
1034
1062
|
"plural": _("WMTS Layers"),
|
|
1035
|
-
"description": Literal(
|
|
1063
|
+
"description": c2cgeoportal_commons.lib.literal.Literal(
|
|
1036
1064
|
_(
|
|
1037
1065
|
"""
|
|
1038
1066
|
<div class="help-block">
|
|
@@ -1080,15 +1108,15 @@ class LayerWMTS(DimensionLayer):
|
|
|
1080
1108
|
),
|
|
1081
1109
|
}
|
|
1082
1110
|
__c2cgeoform_config__ = {"duplicate": True}
|
|
1083
|
-
__mapper_args__ = {"polymorphic_identity": "l_wmts"}
|
|
1111
|
+
__mapper_args__ = {"polymorphic_identity": "l_wmts"} # type: ignore[dict-item]
|
|
1084
1112
|
|
|
1085
|
-
id =
|
|
1113
|
+
id: Mapped[int] = mapped_column(
|
|
1086
1114
|
Integer,
|
|
1087
|
-
ForeignKey(_schema + ".layer.id"),
|
|
1115
|
+
ForeignKey(_schema + ".layer.id", ondelete="CASCADE"),
|
|
1088
1116
|
primary_key=True,
|
|
1089
1117
|
info={"colanderalchemy": {"missing": None, "widget": HiddenWidget()}},
|
|
1090
1118
|
)
|
|
1091
|
-
url =
|
|
1119
|
+
url: Mapped[str] = mapped_column(
|
|
1092
1120
|
Unicode,
|
|
1093
1121
|
nullable=False,
|
|
1094
1122
|
info={
|
|
@@ -1099,29 +1127,32 @@ class LayerWMTS(DimensionLayer):
|
|
|
1099
1127
|
}
|
|
1100
1128
|
},
|
|
1101
1129
|
)
|
|
1102
|
-
layer =
|
|
1130
|
+
layer: Mapped[str] = mapped_column(
|
|
1103
1131
|
Unicode,
|
|
1104
1132
|
nullable=False,
|
|
1105
1133
|
info={
|
|
1106
1134
|
"colanderalchemy": {
|
|
1107
1135
|
"title": _("WMTS layer name"),
|
|
1108
|
-
"description": _("The name of the WMTS layer to use"),
|
|
1136
|
+
"description": _("The name of the WMTS layer to use."),
|
|
1109
1137
|
"column": 2,
|
|
1110
1138
|
}
|
|
1111
1139
|
},
|
|
1112
1140
|
)
|
|
1113
|
-
style =
|
|
1141
|
+
style: Mapped[str] = mapped_column(
|
|
1114
1142
|
Unicode,
|
|
1143
|
+
nullable=True,
|
|
1115
1144
|
info={
|
|
1116
1145
|
"colanderalchemy": {
|
|
1117
1146
|
"title": _("Style"),
|
|
1118
1147
|
"description": _("The style to use; if not present, the default style is used."),
|
|
1119
1148
|
"column": 2,
|
|
1149
|
+
"missing": "",
|
|
1120
1150
|
}
|
|
1121
1151
|
},
|
|
1122
1152
|
)
|
|
1123
|
-
matrix_set =
|
|
1153
|
+
matrix_set: Mapped[str] = mapped_column(
|
|
1124
1154
|
Unicode,
|
|
1155
|
+
nullable=True,
|
|
1125
1156
|
info={
|
|
1126
1157
|
"colanderalchemy": {
|
|
1127
1158
|
"title": _("Matrix set"),
|
|
@@ -1130,34 +1161,35 @@ class LayerWMTS(DimensionLayer):
|
|
|
1130
1161
|
"left empty."
|
|
1131
1162
|
),
|
|
1132
1163
|
"column": 2,
|
|
1164
|
+
"missing": "",
|
|
1133
1165
|
}
|
|
1134
1166
|
},
|
|
1135
1167
|
)
|
|
1136
|
-
image_type =
|
|
1137
|
-
Enum(
|
|
1168
|
+
image_type: Mapped[ImageType] = mapped_column(
|
|
1169
|
+
Enum(*get_args(ImageType), native_enum=False),
|
|
1138
1170
|
nullable=False,
|
|
1139
1171
|
info={
|
|
1140
1172
|
"colanderalchemy": {
|
|
1141
1173
|
"title": _("Image type"),
|
|
1142
|
-
"description": Literal(
|
|
1174
|
+
"description": c2cgeoportal_commons.lib.literal.Literal(
|
|
1143
1175
|
_(
|
|
1144
1176
|
"""
|
|
1145
|
-
The MIME type of the images (e.g.: <code>image/png</code>).
|
|
1177
|
+
The MIME type of the images (e.g.: <code>image/png</code>, <code>image/webp</code> is experimental).
|
|
1146
1178
|
"""
|
|
1147
1179
|
)
|
|
1148
1180
|
),
|
|
1149
1181
|
"column": 2,
|
|
1150
|
-
"widget": SelectWidget(values=((
|
|
1182
|
+
"widget": SelectWidget(values=list((e, e) for e in get_args(ImageType))),
|
|
1151
1183
|
}
|
|
1152
1184
|
},
|
|
1153
1185
|
)
|
|
1154
1186
|
|
|
1155
|
-
def __init__(self, name: str = "", public: bool = True, image_type:
|
|
1187
|
+
def __init__(self, name: str = "", public: bool = True, image_type: ImageType = "image/png") -> None:
|
|
1156
1188
|
super().__init__(name=name, public=public)
|
|
1157
1189
|
self.image_type = image_type
|
|
1158
1190
|
|
|
1159
1191
|
@staticmethod
|
|
1160
|
-
def get_default(dbsession: Session) ->
|
|
1192
|
+
def get_default(dbsession: Session) -> DimensionLayer | None:
|
|
1161
1193
|
return cast(
|
|
1162
1194
|
Optional[DimensionLayer],
|
|
1163
1195
|
dbsession.query(LayerWMTS).filter(LayerWMTS.name == "wmts-defaults").one_or_none(),
|
|
@@ -1193,6 +1225,58 @@ layer_ra = Table(
|
|
|
1193
1225
|
)
|
|
1194
1226
|
|
|
1195
1227
|
|
|
1228
|
+
class LayerCOG(Layer):
|
|
1229
|
+
"""The Cloud Optimized GeoTIFF layer table representation."""
|
|
1230
|
+
|
|
1231
|
+
__tablename__ = "layer_cog"
|
|
1232
|
+
__table_args__ = {"schema": _schema}
|
|
1233
|
+
__colanderalchemy_config__ = {
|
|
1234
|
+
"title": _("COG Layer"),
|
|
1235
|
+
"plural": _("COG Layers"),
|
|
1236
|
+
"description": c2cgeoportal_commons.lib.literal.Literal(
|
|
1237
|
+
_(
|
|
1238
|
+
"""
|
|
1239
|
+
<div class="help-block">
|
|
1240
|
+
<p>Definition of a <code>COG Layer</code> (COG for
|
|
1241
|
+
<a href="https://www.cogeo.org/">Cloud Optimized GeoTIFF</a>).</p>
|
|
1242
|
+
<p>Note: The layer named <code>cog-defaults</code> contain the values
|
|
1243
|
+
used when a new <code>COG layer</code> is created.</p>
|
|
1244
|
+
</div>
|
|
1245
|
+
"""
|
|
1246
|
+
)
|
|
1247
|
+
),
|
|
1248
|
+
}
|
|
1249
|
+
__c2cgeoform_config__ = {"duplicate": True}
|
|
1250
|
+
__mapper_args__ = {"polymorphic_identity": "l_cog"} # type: ignore[dict-item]
|
|
1251
|
+
|
|
1252
|
+
id: Mapped[int] = mapped_column(
|
|
1253
|
+
Integer,
|
|
1254
|
+
ForeignKey(_schema + ".layer.id"),
|
|
1255
|
+
primary_key=True,
|
|
1256
|
+
info={"colanderalchemy": {"missing": None, "widget": HiddenWidget()}},
|
|
1257
|
+
)
|
|
1258
|
+
url: Mapped[str] = mapped_column(
|
|
1259
|
+
Unicode,
|
|
1260
|
+
nullable=False,
|
|
1261
|
+
info={
|
|
1262
|
+
"colanderalchemy": {
|
|
1263
|
+
"title": _("URL"),
|
|
1264
|
+
"description": _("URL of the COG file."),
|
|
1265
|
+
"column": 2,
|
|
1266
|
+
}
|
|
1267
|
+
},
|
|
1268
|
+
)
|
|
1269
|
+
|
|
1270
|
+
@staticmethod
|
|
1271
|
+
def get_default(dbsession: Session) -> Layer | None:
|
|
1272
|
+
return dbsession.query(LayerCOG).filter(LayerCOG.name == "cog-defaults").one_or_none()
|
|
1273
|
+
|
|
1274
|
+
def url_description(self, request: pyramid.request.Request) -> str:
|
|
1275
|
+
errors: set[str] = set()
|
|
1276
|
+
url = get_url2(self.name, self.url, request, errors)
|
|
1277
|
+
return url.url() if url else "\n".join(errors)
|
|
1278
|
+
|
|
1279
|
+
|
|
1196
1280
|
class LayerVectorTiles(DimensionLayer):
|
|
1197
1281
|
"""The layer_vectortiles table representation."""
|
|
1198
1282
|
|
|
@@ -1201,7 +1285,7 @@ class LayerVectorTiles(DimensionLayer):
|
|
|
1201
1285
|
__colanderalchemy_config__ = {
|
|
1202
1286
|
"title": _("Vector Tiles Layer"),
|
|
1203
1287
|
"plural": _("Vector Tiles Layers"),
|
|
1204
|
-
"description": Literal(
|
|
1288
|
+
"description": c2cgeoportal_commons.lib.literal.Literal(
|
|
1205
1289
|
_(
|
|
1206
1290
|
"""
|
|
1207
1291
|
<div class="help-block">
|
|
@@ -1235,16 +1319,16 @@ class LayerVectorTiles(DimensionLayer):
|
|
|
1235
1319
|
|
|
1236
1320
|
__c2cgeoform_config__ = {"duplicate": True}
|
|
1237
1321
|
|
|
1238
|
-
__mapper_args__ = {"polymorphic_identity": "l_mvt"}
|
|
1322
|
+
__mapper_args__ = {"polymorphic_identity": "l_mvt"} # type: ignore[dict-item]
|
|
1239
1323
|
|
|
1240
|
-
id =
|
|
1324
|
+
id: Mapped[int] = mapped_column(
|
|
1241
1325
|
Integer,
|
|
1242
1326
|
ForeignKey(_schema + ".layer.id"),
|
|
1243
1327
|
primary_key=True,
|
|
1244
1328
|
info={"colanderalchemy": {"missing": None, "widget": HiddenWidget()}},
|
|
1245
1329
|
)
|
|
1246
1330
|
|
|
1247
|
-
style =
|
|
1331
|
+
style: Mapped[str] = mapped_column(
|
|
1248
1332
|
Unicode,
|
|
1249
1333
|
nullable=False,
|
|
1250
1334
|
info={
|
|
@@ -1252,7 +1336,7 @@ class LayerVectorTiles(DimensionLayer):
|
|
|
1252
1336
|
"title": _("Style"),
|
|
1253
1337
|
"description": _(
|
|
1254
1338
|
"""
|
|
1255
|
-
The path to a Mapbox Style file (version 8 or higher). Example: https://url/style.json
|
|
1339
|
+
The path to a Mapbox Style file (version 8 or higher). Example: https://url/style.json.
|
|
1256
1340
|
"""
|
|
1257
1341
|
),
|
|
1258
1342
|
"column": 2,
|
|
@@ -1260,24 +1344,20 @@ class LayerVectorTiles(DimensionLayer):
|
|
|
1260
1344
|
},
|
|
1261
1345
|
)
|
|
1262
1346
|
|
|
1263
|
-
sql =
|
|
1347
|
+
sql: Mapped[str] = mapped_column(
|
|
1264
1348
|
Unicode,
|
|
1265
1349
|
nullable=True,
|
|
1266
1350
|
info={
|
|
1267
1351
|
"colanderalchemy": {
|
|
1268
1352
|
"title": _("SQL query"),
|
|
1269
|
-
"description": _(
|
|
1270
|
-
"""
|
|
1271
|
-
A SQL query to get the vector tiles data.
|
|
1272
|
-
"""
|
|
1273
|
-
),
|
|
1353
|
+
"description": _("An SQL query to retrieve the vector tiles data."),
|
|
1274
1354
|
"column": 2,
|
|
1275
1355
|
"widget": TextAreaWidget(rows=15),
|
|
1276
1356
|
}
|
|
1277
1357
|
},
|
|
1278
1358
|
)
|
|
1279
1359
|
|
|
1280
|
-
xyz =
|
|
1360
|
+
xyz: Mapped[str] = mapped_column(
|
|
1281
1361
|
Unicode,
|
|
1282
1362
|
nullable=True,
|
|
1283
1363
|
info={
|
|
@@ -1300,7 +1380,7 @@ class LayerVectorTiles(DimensionLayer):
|
|
|
1300
1380
|
self.sql = sql
|
|
1301
1381
|
|
|
1302
1382
|
@staticmethod
|
|
1303
|
-
def get_default(dbsession: Session) ->
|
|
1383
|
+
def get_default(dbsession: Session) -> DimensionLayer | None:
|
|
1304
1384
|
return cast(
|
|
1305
1385
|
Optional[DimensionLayer],
|
|
1306
1386
|
dbsession.query(LayerVectorTiles)
|
|
@@ -1309,7 +1389,7 @@ class LayerVectorTiles(DimensionLayer):
|
|
|
1309
1389
|
)
|
|
1310
1390
|
|
|
1311
1391
|
def style_description(self, request: pyramid.request.Request) -> str:
|
|
1312
|
-
errors:
|
|
1392
|
+
errors: set[str] = set()
|
|
1313
1393
|
url = get_url2(self.name, self.style, request, errors)
|
|
1314
1394
|
return url.url() if url else "\n".join(errors)
|
|
1315
1395
|
|
|
@@ -1321,9 +1401,11 @@ class RestrictionArea(Base): # type: ignore
|
|
|
1321
1401
|
__table_args__ = {"schema": _schema}
|
|
1322
1402
|
__colanderalchemy_config__ = {"title": _("Restriction area"), "plural": _("Restriction areas")}
|
|
1323
1403
|
__c2cgeoform_config__ = {"duplicate": True}
|
|
1324
|
-
id
|
|
1404
|
+
id: Mapped[int] = mapped_column(
|
|
1405
|
+
Integer, primary_key=True, info={"colanderalchemy": {"widget": HiddenWidget()}}
|
|
1406
|
+
)
|
|
1325
1407
|
|
|
1326
|
-
name =
|
|
1408
|
+
name: Mapped[str] = mapped_column(
|
|
1327
1409
|
Unicode,
|
|
1328
1410
|
info={
|
|
1329
1411
|
"colanderalchemy": {
|
|
@@ -1332,16 +1414,16 @@ class RestrictionArea(Base): # type: ignore
|
|
|
1332
1414
|
}
|
|
1333
1415
|
},
|
|
1334
1416
|
)
|
|
1335
|
-
description =
|
|
1417
|
+
description: Mapped[str | None] = mapped_column(
|
|
1336
1418
|
Unicode,
|
|
1337
1419
|
info={
|
|
1338
1420
|
"colanderalchemy": {
|
|
1339
1421
|
"title": _("Description"),
|
|
1340
|
-
"description": _("An optional description"),
|
|
1422
|
+
"description": _("An optional description."),
|
|
1341
1423
|
}
|
|
1342
1424
|
},
|
|
1343
1425
|
)
|
|
1344
|
-
readwrite =
|
|
1426
|
+
readwrite: Mapped[bool] = mapped_column(
|
|
1345
1427
|
Boolean,
|
|
1346
1428
|
default=False,
|
|
1347
1429
|
info={
|
|
@@ -1351,7 +1433,7 @@ class RestrictionArea(Base): # type: ignore
|
|
|
1351
1433
|
}
|
|
1352
1434
|
},
|
|
1353
1435
|
)
|
|
1354
|
-
area =
|
|
1436
|
+
area = mapped_column(
|
|
1355
1437
|
Geometry("POLYGON", srid=_srid),
|
|
1356
1438
|
info={
|
|
1357
1439
|
"colanderalchemy": {
|
|
@@ -1396,7 +1478,7 @@ class RestrictionArea(Base): # type: ignore
|
|
|
1396
1478
|
"colanderalchemy": {
|
|
1397
1479
|
"title": _("Layers"),
|
|
1398
1480
|
"exclude": True,
|
|
1399
|
-
"description": Literal(
|
|
1481
|
+
"description": c2cgeoportal_commons.lib.literal.Literal(
|
|
1400
1482
|
_(
|
|
1401
1483
|
"""
|
|
1402
1484
|
<div class="help-block">
|
|
@@ -1425,9 +1507,9 @@ class RestrictionArea(Base): # type: ignore
|
|
|
1425
1507
|
self,
|
|
1426
1508
|
name: str = "",
|
|
1427
1509
|
description: str = "",
|
|
1428
|
-
layers:
|
|
1429
|
-
roles:
|
|
1430
|
-
area: Geometry = None,
|
|
1510
|
+
layers: list[Layer] | None = None,
|
|
1511
|
+
roles: list[Role] | None = None,
|
|
1512
|
+
area: Geometry | None = None,
|
|
1431
1513
|
readwrite: bool = False,
|
|
1432
1514
|
) -> None:
|
|
1433
1515
|
if layers is None:
|
|
@@ -1481,8 +1563,10 @@ class Interface(Base): # type: ignore
|
|
|
1481
1563
|
__c2cgeoform_config__ = {"duplicate": True}
|
|
1482
1564
|
__colanderalchemy_config__ = {"title": _("Interface"), "plural": _("Interfaces")}
|
|
1483
1565
|
|
|
1484
|
-
id
|
|
1485
|
-
|
|
1566
|
+
id: Mapped[int] = mapped_column(
|
|
1567
|
+
Integer, primary_key=True, info={"colanderalchemy": {"widget": HiddenWidget()}}
|
|
1568
|
+
)
|
|
1569
|
+
name: Mapped[str] = mapped_column(
|
|
1486
1570
|
Unicode,
|
|
1487
1571
|
info={
|
|
1488
1572
|
"colanderalchemy": {
|
|
@@ -1491,7 +1575,7 @@ class Interface(Base): # type: ignore
|
|
|
1491
1575
|
}
|
|
1492
1576
|
},
|
|
1493
1577
|
)
|
|
1494
|
-
description =
|
|
1578
|
+
description: Mapped[str | None] = mapped_column(
|
|
1495
1579
|
Unicode,
|
|
1496
1580
|
info={
|
|
1497
1581
|
"colanderalchemy": {
|
|
@@ -1553,18 +1637,23 @@ class Metadata(Base): # type: ignore
|
|
|
1553
1637
|
"plural": _("Metadatas"),
|
|
1554
1638
|
}
|
|
1555
1639
|
|
|
1556
|
-
id
|
|
1557
|
-
|
|
1640
|
+
id: Mapped[int] = mapped_column(
|
|
1641
|
+
Integer, primary_key=True, info={"colanderalchemy": {"widget": HiddenWidget()}}
|
|
1642
|
+
)
|
|
1643
|
+
name: Mapped[str] = mapped_column(
|
|
1558
1644
|
Unicode,
|
|
1559
1645
|
info={
|
|
1560
1646
|
"colanderalchemy": {
|
|
1561
1647
|
"title": _("Name"),
|
|
1562
|
-
"description": Literal(
|
|
1648
|
+
"description": c2cgeoportal_commons.lib.literal.Literal(
|
|
1649
|
+
_("The type of <code>Metadata</code> we want to set.")
|
|
1650
|
+
),
|
|
1563
1651
|
}
|
|
1564
1652
|
},
|
|
1565
1653
|
)
|
|
1566
|
-
value =
|
|
1654
|
+
value: Mapped[str] = mapped_column(
|
|
1567
1655
|
Unicode,
|
|
1656
|
+
nullable=True,
|
|
1568
1657
|
info={
|
|
1569
1658
|
"colanderalchemy": {
|
|
1570
1659
|
"title": _("Value"),
|
|
@@ -1573,7 +1662,7 @@ class Metadata(Base): # type: ignore
|
|
|
1573
1662
|
}
|
|
1574
1663
|
},
|
|
1575
1664
|
)
|
|
1576
|
-
description =
|
|
1665
|
+
description: Mapped[str | None] = mapped_column(
|
|
1577
1666
|
Unicode,
|
|
1578
1667
|
info={
|
|
1579
1668
|
"colanderalchemy": {
|
|
@@ -1584,10 +1673,10 @@ class Metadata(Base): # type: ignore
|
|
|
1584
1673
|
},
|
|
1585
1674
|
)
|
|
1586
1675
|
|
|
1587
|
-
item_id =
|
|
1676
|
+
item_id: Mapped[int] = mapped_column(
|
|
1588
1677
|
"item_id",
|
|
1589
1678
|
Integer,
|
|
1590
|
-
ForeignKey(_schema + ".treeitem.id"),
|
|
1679
|
+
ForeignKey(_schema + ".treeitem.id", ondelete="CASCADE"),
|
|
1591
1680
|
nullable=False,
|
|
1592
1681
|
info={"colanderalchemy": {"exclude": True}, "c2cgeoform": {"duplicate": False}},
|
|
1593
1682
|
)
|
|
@@ -1601,7 +1690,7 @@ class Metadata(Base): # type: ignore
|
|
|
1601
1690
|
info={
|
|
1602
1691
|
"colanderalchemy": {
|
|
1603
1692
|
"title": _("Metadatas"),
|
|
1604
|
-
"description": Literal(
|
|
1693
|
+
"description": c2cgeoportal_commons.lib.literal.Literal(
|
|
1605
1694
|
_(
|
|
1606
1695
|
"""
|
|
1607
1696
|
<div class="help-block">
|
|
@@ -1634,7 +1723,7 @@ class Metadata(Base): # type: ignore
|
|
|
1634
1723
|
),
|
|
1635
1724
|
)
|
|
1636
1725
|
|
|
1637
|
-
def __init__(self, name: str = "", value: str = "", description:
|
|
1726
|
+
def __init__(self, name: str = "", value: str = "", description: str | None = None) -> None:
|
|
1638
1727
|
self.name = name
|
|
1639
1728
|
self.value = value
|
|
1640
1729
|
self.description = description
|
|
@@ -1658,8 +1747,10 @@ class Dimension(Base): # type: ignore
|
|
|
1658
1747
|
"plural": _("Dimensions"),
|
|
1659
1748
|
}
|
|
1660
1749
|
|
|
1661
|
-
id
|
|
1662
|
-
|
|
1750
|
+
id: Mapped[int] = mapped_column(
|
|
1751
|
+
Integer, primary_key=True, info={"colanderalchemy": {"widget": HiddenWidget()}}
|
|
1752
|
+
)
|
|
1753
|
+
name: Mapped[str] = mapped_column(
|
|
1663
1754
|
Unicode,
|
|
1664
1755
|
info={
|
|
1665
1756
|
"colanderalchemy": {
|
|
@@ -1668,8 +1759,9 @@ class Dimension(Base): # type: ignore
|
|
|
1668
1759
|
}
|
|
1669
1760
|
},
|
|
1670
1761
|
)
|
|
1671
|
-
value =
|
|
1762
|
+
value: Mapped[str] = mapped_column(
|
|
1672
1763
|
Unicode,
|
|
1764
|
+
nullable=True,
|
|
1673
1765
|
info={
|
|
1674
1766
|
"colanderalchemy": {
|
|
1675
1767
|
"title": _("Value"),
|
|
@@ -1677,7 +1769,7 @@ class Dimension(Base): # type: ignore
|
|
|
1677
1769
|
}
|
|
1678
1770
|
},
|
|
1679
1771
|
)
|
|
1680
|
-
field =
|
|
1772
|
+
field: Mapped[str | None] = mapped_column(
|
|
1681
1773
|
Unicode,
|
|
1682
1774
|
info={
|
|
1683
1775
|
"colanderalchemy": {
|
|
@@ -1688,7 +1780,7 @@ class Dimension(Base): # type: ignore
|
|
|
1688
1780
|
}
|
|
1689
1781
|
},
|
|
1690
1782
|
)
|
|
1691
|
-
description =
|
|
1783
|
+
description: Mapped[str | None] = mapped_column(
|
|
1692
1784
|
Unicode,
|
|
1693
1785
|
info={
|
|
1694
1786
|
"colanderalchemy": {
|
|
@@ -1699,7 +1791,7 @@ class Dimension(Base): # type: ignore
|
|
|
1699
1791
|
},
|
|
1700
1792
|
)
|
|
1701
1793
|
|
|
1702
|
-
layer_id =
|
|
1794
|
+
layer_id: Mapped[int] = mapped_column(
|
|
1703
1795
|
"layer_id",
|
|
1704
1796
|
Integer,
|
|
1705
1797
|
ForeignKey(_schema + ".layer.id"),
|
|
@@ -1716,7 +1808,7 @@ class Dimension(Base): # type: ignore
|
|
|
1716
1808
|
"colanderalchemy": {
|
|
1717
1809
|
"title": _("Dimensions"),
|
|
1718
1810
|
"exclude": True,
|
|
1719
|
-
"description": Literal(
|
|
1811
|
+
"description": c2cgeoportal_commons.lib.literal.Literal(
|
|
1720
1812
|
_(
|
|
1721
1813
|
"""
|
|
1722
1814
|
<div class="help-block">
|
|
@@ -1735,9 +1827,9 @@ class Dimension(Base): # type: ignore
|
|
|
1735
1827
|
self,
|
|
1736
1828
|
name: str = "",
|
|
1737
1829
|
value: str = "",
|
|
1738
|
-
layer:
|
|
1739
|
-
field:
|
|
1740
|
-
description:
|
|
1830
|
+
layer: str | None = None,
|
|
1831
|
+
field: str | None = None,
|
|
1832
|
+
description: str | None = None,
|
|
1741
1833
|
) -> None:
|
|
1742
1834
|
self.name = name
|
|
1743
1835
|
self.value = value
|
|
@@ -1748,3 +1840,100 @@ class Dimension(Base): # type: ignore
|
|
|
1748
1840
|
|
|
1749
1841
|
def __str__(self) -> str:
|
|
1750
1842
|
return f"{self.name}={self.value}[{self.id}]"
|
|
1843
|
+
|
|
1844
|
+
|
|
1845
|
+
class LogAction(enum.Enum):
|
|
1846
|
+
"""The log action enumeration."""
|
|
1847
|
+
|
|
1848
|
+
INSERT = enum.auto()
|
|
1849
|
+
UPDATE = enum.auto()
|
|
1850
|
+
DELETE = enum.auto()
|
|
1851
|
+
SYNCHRONIZE = enum.auto()
|
|
1852
|
+
CONVERT_TO_WMTS = enum.auto()
|
|
1853
|
+
CONVERT_TO_WMS = enum.auto()
|
|
1854
|
+
|
|
1855
|
+
|
|
1856
|
+
class AbstractLog(AbstractConcreteBase, Base): # type: ignore
|
|
1857
|
+
"""The abstract log table representation."""
|
|
1858
|
+
|
|
1859
|
+
strict_attrs = True
|
|
1860
|
+
__colanderalchemy_config__ = {
|
|
1861
|
+
"title": _("Log"),
|
|
1862
|
+
"plural": _("Logs"),
|
|
1863
|
+
}
|
|
1864
|
+
|
|
1865
|
+
id: Mapped[int] = mapped_column(Integer, primary_key=True, info={"colanderalchemy": {}})
|
|
1866
|
+
date: Mapped[datetime] = mapped_column(
|
|
1867
|
+
DateTime(timezone=True),
|
|
1868
|
+
nullable=False,
|
|
1869
|
+
info={
|
|
1870
|
+
"colanderalchemy": {
|
|
1871
|
+
"title": _("Date"),
|
|
1872
|
+
}
|
|
1873
|
+
},
|
|
1874
|
+
)
|
|
1875
|
+
action: Mapped[LogAction] = mapped_column(
|
|
1876
|
+
Enum(LogAction, native_enum=False),
|
|
1877
|
+
nullable=False,
|
|
1878
|
+
info={
|
|
1879
|
+
"colanderalchemy": {
|
|
1880
|
+
"title": _("Action"),
|
|
1881
|
+
}
|
|
1882
|
+
},
|
|
1883
|
+
)
|
|
1884
|
+
element_type: Mapped[str] = mapped_column(
|
|
1885
|
+
String(50),
|
|
1886
|
+
nullable=False,
|
|
1887
|
+
info={
|
|
1888
|
+
"colanderalchemy": {
|
|
1889
|
+
"title": _("Element type"),
|
|
1890
|
+
}
|
|
1891
|
+
},
|
|
1892
|
+
)
|
|
1893
|
+
element_id: Mapped[int] = mapped_column(
|
|
1894
|
+
Integer,
|
|
1895
|
+
nullable=False,
|
|
1896
|
+
info={
|
|
1897
|
+
"colanderalchemy": {
|
|
1898
|
+
"title": _("Element identifier"),
|
|
1899
|
+
}
|
|
1900
|
+
},
|
|
1901
|
+
)
|
|
1902
|
+
element_name: Mapped[str] = mapped_column(
|
|
1903
|
+
Unicode,
|
|
1904
|
+
nullable=False,
|
|
1905
|
+
info={
|
|
1906
|
+
"colanderalchemy": {
|
|
1907
|
+
"title": _("Element name"),
|
|
1908
|
+
}
|
|
1909
|
+
},
|
|
1910
|
+
)
|
|
1911
|
+
element_url_table: Mapped[str] = mapped_column(
|
|
1912
|
+
Unicode,
|
|
1913
|
+
nullable=False,
|
|
1914
|
+
info={
|
|
1915
|
+
"colanderalchemy": {
|
|
1916
|
+
"title": _("Table segment of the element URL"),
|
|
1917
|
+
}
|
|
1918
|
+
},
|
|
1919
|
+
)
|
|
1920
|
+
username: Mapped[str] = mapped_column(
|
|
1921
|
+
Unicode,
|
|
1922
|
+
nullable=False,
|
|
1923
|
+
info={
|
|
1924
|
+
"colanderalchemy": {
|
|
1925
|
+
"title": _("Username"),
|
|
1926
|
+
}
|
|
1927
|
+
},
|
|
1928
|
+
)
|
|
1929
|
+
|
|
1930
|
+
|
|
1931
|
+
class Log(AbstractLog):
|
|
1932
|
+
"""The main log table representation."""
|
|
1933
|
+
|
|
1934
|
+
__tablename__ = "log"
|
|
1935
|
+
__table_args__ = {"schema": _schema}
|
|
1936
|
+
__mapper_args__ = {
|
|
1937
|
+
"polymorphic_identity": "main",
|
|
1938
|
+
"concrete": True,
|
|
1939
|
+
}
|