c2cgeoportal-geoportal 2.9rc83__py3-none-any.whl → 2.9.0.352__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_geoportal/__init__.py +28 -8
- c2cgeoportal_geoportal/lib/__init__.py +1 -1
- c2cgeoportal_geoportal/lib/authentication.py +4 -1
- c2cgeoportal_geoportal/lib/bashcolor.py +1 -1
- c2cgeoportal_geoportal/lib/cacheversion.py +1 -1
- c2cgeoportal_geoportal/lib/caching.py +1 -1
- c2cgeoportal_geoportal/lib/check_collector.py +1 -1
- c2cgeoportal_geoportal/lib/checker.py +1 -1
- c2cgeoportal_geoportal/lib/dbreflection.py +1 -1
- c2cgeoportal_geoportal/lib/filter_capabilities.py +1 -1
- c2cgeoportal_geoportal/lib/fulltextsearch.py +1 -1
- c2cgeoportal_geoportal/lib/functionality.py +1 -1
- c2cgeoportal_geoportal/lib/headers.py +1 -1
- c2cgeoportal_geoportal/lib/i18n.py +1 -1
- c2cgeoportal_geoportal/lib/layers.py +1 -1
- c2cgeoportal_geoportal/lib/loader.py +1 -1
- c2cgeoportal_geoportal/lib/metrics.py +1 -1
- c2cgeoportal_geoportal/lib/oauth2.py +1 -1
- c2cgeoportal_geoportal/lib/oidc.py +109 -71
- c2cgeoportal_geoportal/lib/wmstparsing.py +1 -1
- c2cgeoportal_geoportal/lib/xsd.py +1 -1
- c2cgeoportal_geoportal/resources.py +1 -1
- c2cgeoportal_geoportal/scaffolds/advance_create/ci/config.yaml +1 -12
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/Dockerfile +3 -3
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/Makefile +1 -1
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/alembic.ini +2 -2
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/gunicorn.conf.py +1 -1
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/language_mapping +1 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/webpack.apps.js +11 -1
- c2cgeoportal_geoportal/scaffolds/advance_update/cookiecutter.json +2 -0
- c2cgeoportal_geoportal/scaffolds/create/cookiecutter.json +2 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.github/workflows/main.yaml +1 -1
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.github/workflows/rebuild.yaml +1 -7
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/Dockerfile +1 -1
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/Makefile +4 -4
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/build +2 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/ci/config.yaml +1 -8
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/ci/requirements.txt +2 -2
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/docker-compose-lib.yaml +8 -4
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/env.default +3 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/env.project +1 -5
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/geoportal/vars.yaml +2 -2
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/project.yaml +2 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/scripts/db-backup +1 -1
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/scripts/db-restore +1 -1
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/tilegeneration/config.yaml.tmpl +6 -4
- c2cgeoportal_geoportal/scaffolds/update/cookiecutter.json +2 -0
- c2cgeoportal_geoportal/scaffolds/update/{{cookiecutter.project}}/CONST_CHANGELOG.txt +14 -6
- c2cgeoportal_geoportal/scaffolds/update/{{cookiecutter.project}}/geoportal/CONST_config-schema.yaml +2 -0
- c2cgeoportal_geoportal/scaffolds/update/{{cookiecutter.project}}/geoportal/CONST_vars.yaml +16 -8
- c2cgeoportal_geoportal/scripts/__init__.py +1 -1
- c2cgeoportal_geoportal/scripts/c2cupgrade.py +2 -2
- c2cgeoportal_geoportal/scripts/create_demo_theme.py +1 -1
- c2cgeoportal_geoportal/scripts/manage_users.py +1 -1
- c2cgeoportal_geoportal/scripts/pcreate.py +11 -5
- c2cgeoportal_geoportal/scripts/theme2fts.py +141 -36
- c2cgeoportal_geoportal/scripts/urllogin.py +1 -1
- c2cgeoportal_geoportal/views/__init__.py +1 -1
- c2cgeoportal_geoportal/views/dev.py +1 -1
- c2cgeoportal_geoportal/views/entry.py +4 -2
- c2cgeoportal_geoportal/views/fulltextsearch.py +10 -4
- c2cgeoportal_geoportal/views/geometry_processing.py +1 -1
- c2cgeoportal_geoportal/views/i18n.py +1 -1
- c2cgeoportal_geoportal/views/layers.py +1 -1
- c2cgeoportal_geoportal/views/login.py +18 -8
- c2cgeoportal_geoportal/views/mapserverproxy.py +1 -1
- c2cgeoportal_geoportal/views/memory.py +1 -1
- c2cgeoportal_geoportal/views/ogcproxy.py +1 -1
- c2cgeoportal_geoportal/views/pdfreport.py +1 -1
- c2cgeoportal_geoportal/views/printproxy.py +1 -1
- c2cgeoportal_geoportal/views/profile.py +1 -1
- c2cgeoportal_geoportal/views/raster.py +1 -1
- c2cgeoportal_geoportal/views/resourceproxy.py +1 -1
- c2cgeoportal_geoportal/views/shortener.py +23 -7
- c2cgeoportal_geoportal/views/theme.py +18 -4
- c2cgeoportal_geoportal/views/tinyowsproxy.py +12 -6
- c2cgeoportal_geoportal/views/vector_tiles.py +1 -1
- {c2cgeoportal_geoportal-2.9rc83.dist-info → c2cgeoportal_geoportal-2.9.0.352.dist-info}/METADATA +7 -1
- {c2cgeoportal_geoportal-2.9rc83.dist-info → c2cgeoportal_geoportal-2.9.0.352.dist-info}/RECORD +93 -93
- tests/__init__.py +1 -1
- tests/test_cachebuster.py +1 -1
- tests/test_checker.py +1 -1
- tests/test_decimaljson.py +1 -1
- tests/test_headerstween.py +1 -1
- tests/test_init.py +1 -1
- tests/test_locale_negociator.py +1 -1
- tests/test_mapserverproxy_route_predicate.py +1 -1
- tests/test_raster.py +1 -1
- tests/test_wmstparsing.py +1 -1
- tests/xmlstr.py +1 -1
- {c2cgeoportal_geoportal-2.9rc83.dist-info → c2cgeoportal_geoportal-2.9.0.352.dist-info}/WHEEL +0 -0
- {c2cgeoportal_geoportal-2.9rc83.dist-info → c2cgeoportal_geoportal-2.9.0.352.dist-info}/entry_points.txt +0 -0
- {c2cgeoportal_geoportal-2.9rc83.dist-info → c2cgeoportal_geoportal-2.9.0.352.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
|
|
@@ -42,10 +42,8 @@ import c2cwsgiutils.db
|
|
|
42
42
|
import c2cwsgiutils.index
|
|
43
43
|
import dateutil.parser
|
|
44
44
|
import pyramid.config
|
|
45
|
-
import pyramid.renderers
|
|
46
45
|
import pyramid.request
|
|
47
46
|
import pyramid.response
|
|
48
|
-
import pyramid.security
|
|
49
47
|
import sqlalchemy
|
|
50
48
|
import sqlalchemy.orm
|
|
51
49
|
import zope.event.classhandler
|
|
@@ -408,17 +406,36 @@ def create_get_user_from_request(
|
|
|
408
406
|
access_token_expires = dateutil.parser.isoparse(
|
|
409
407
|
user_info_remember["access_token_expires"]
|
|
410
408
|
)
|
|
411
|
-
|
|
409
|
+
# If access_token_expires is not offset-aware make it offset-aware
|
|
410
|
+
if access_token_expires.tzinfo is None:
|
|
411
|
+
_LOG.warning(
|
|
412
|
+
"access_token_expires is not offset-aware, "
|
|
413
|
+
"make it offset-aware by replacing tzinfo with UTC"
|
|
414
|
+
)
|
|
415
|
+
access_token_expires = access_token_expires.replace(tzinfo=datetime.timezone.utc)
|
|
416
|
+
if access_token_expires < datetime.datetime.now(datetime.timezone.utc):
|
|
412
417
|
if user_info_remember["refresh_token_expires"] is None:
|
|
413
418
|
return None
|
|
419
|
+
refresh_token = request.cookies.get("refresh_token")
|
|
420
|
+
if refresh_token is None:
|
|
421
|
+
return None
|
|
414
422
|
refresh_token_expires = dateutil.parser.isoparse(
|
|
415
423
|
user_info_remember["refresh_token_expires"]
|
|
416
424
|
)
|
|
417
|
-
|
|
425
|
+
# If refresh_token_expires is not offset-aware make it offset-aware
|
|
426
|
+
if refresh_token_expires.tzinfo is None:
|
|
427
|
+
_LOG.warning(
|
|
428
|
+
"refresh_token_expires is not offset-aware, "
|
|
429
|
+
"make it offset-aware by replacing tzinfo with UTC"
|
|
430
|
+
)
|
|
431
|
+
refresh_token_expires = refresh_token_expires.replace(
|
|
432
|
+
tzinfo=datetime.timezone.utc
|
|
433
|
+
)
|
|
434
|
+
if refresh_token_expires < datetime.datetime.now(datetime.timezone.utc):
|
|
418
435
|
return None
|
|
419
436
|
token_response = oidc.get_oidc_client(
|
|
420
437
|
request, request.host
|
|
421
|
-
).exchange_refresh_token(
|
|
438
|
+
).exchange_refresh_token(refresh_token)
|
|
422
439
|
user_info_remember = oidc.OidcRemember(request).remember(
|
|
423
440
|
token_response, request.host
|
|
424
441
|
)
|
|
@@ -430,7 +447,7 @@ def create_get_user_from_request(
|
|
|
430
447
|
request.user_ = (
|
|
431
448
|
DBSession.query(User)
|
|
432
449
|
.filter_by(username=username, deactivated=False)
|
|
433
|
-
.options(joinedload(User.roles))
|
|
450
|
+
.options(joinedload(User.roles), joinedload(User.settings_role))
|
|
434
451
|
.first()
|
|
435
452
|
)
|
|
436
453
|
|
|
@@ -674,9 +691,11 @@ def includeme(config: pyramid.config.Configurator) -> None:
|
|
|
674
691
|
"/mapserv_proxy/{ogcserver}/wfs3/*path",
|
|
675
692
|
mapserverproxy=True,
|
|
676
693
|
pregenerator=C2CPregenerator(role=True),
|
|
677
|
-
request_method="GET",
|
|
694
|
+
request_method=("GET", "POST", "PUT", "DELETE", "PATCH"),
|
|
678
695
|
)
|
|
679
696
|
add_cors_route(config, "/mapserv_proxy", "mapserver")
|
|
697
|
+
add_cors_route(config, "/mapserv_proxy/{ogcserver}/ogcapi/*path", "mapserver_ogcapi_mapserver")
|
|
698
|
+
add_cors_route(config, "/mapserv_proxy/{ogcserver}/wfs3/*path", "mapserver_ogcapi_qgisserver")
|
|
680
699
|
|
|
681
700
|
# Add route to the tinyows proxy
|
|
682
701
|
config.add_route("tinyowsproxy", "/tinyows_proxy", pregenerator=C2CPregenerator(role=True))
|
|
@@ -767,6 +786,7 @@ def includeme(config: pyramid.config.Configurator) -> None:
|
|
|
767
786
|
add_cors_route(config, "/short/create", "shortener")
|
|
768
787
|
config.add_route("shortener_create", "/short/create", request_method="POST")
|
|
769
788
|
config.add_route("shortener_get", "/s/{ref}", request_method="GET")
|
|
789
|
+
config.add_route("shortener_fetch", "/short/get/{ref}", request_method="GET")
|
|
770
790
|
|
|
771
791
|
# Geometry processing
|
|
772
792
|
config.add_route("difference", "/difference", request_method="POST")
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright (c) 2014-
|
|
1
|
+
# Copyright (c) 2014-2025, Camptocamp SA
|
|
2
2
|
# All rights reserved.
|
|
3
3
|
|
|
4
4
|
# Redistribution and use in source and binary forms, with or without
|
|
@@ -47,6 +47,7 @@ from pyramid.security import remember
|
|
|
47
47
|
from pyramid_multiauth import MultiAuthenticationPolicy
|
|
48
48
|
from zope.interface import implementer
|
|
49
49
|
|
|
50
|
+
import c2cgeoportal_commons.models
|
|
50
51
|
from c2cgeoportal_geoportal.lib import oauth2
|
|
51
52
|
from c2cgeoportal_geoportal.resources import defaultgroupsfinder
|
|
52
53
|
|
|
@@ -147,6 +148,8 @@ class OAuth2AuthenticationPolicy(CallbackAuthenticationPolicy): # type: ignore
|
|
|
147
148
|
_LOG.debug("OAuth verify_request: %s", valid)
|
|
148
149
|
if valid:
|
|
149
150
|
request.user_ = oauth2_request.user
|
|
151
|
+
if request.user_ is not None and c2cgeoportal_commons.models.DBSession is not None:
|
|
152
|
+
c2cgeoportal_commons.models.DBSession.add(request.user_)
|
|
150
153
|
|
|
151
154
|
return cast(str, request.user.username)
|
|
152
155
|
return None
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright (c) 2024, Camptocamp SA
|
|
1
|
+
# Copyright (c) 2024-2025, Camptocamp SA
|
|
2
2
|
# All rights reserved.
|
|
3
3
|
|
|
4
4
|
# Redistribution and use in source and binary forms, with or without
|
|
@@ -28,10 +28,10 @@
|
|
|
28
28
|
import datetime
|
|
29
29
|
import json
|
|
30
30
|
import logging
|
|
31
|
+
import string
|
|
31
32
|
from typing import TYPE_CHECKING, Any, NamedTuple, Optional, TypedDict, Union
|
|
32
33
|
|
|
33
34
|
import pyramid.request
|
|
34
|
-
import pyramid.response
|
|
35
35
|
import simple_openid_connect.client
|
|
36
36
|
import simple_openid_connect.data
|
|
37
37
|
from pyramid.httpexceptions import HTTPBadRequest, HTTPInternalServerError, HTTPUnauthorized
|
|
@@ -77,7 +77,7 @@ def get_oidc_client(request: pyramid.request.Request, host: str) -> simple_openi
|
|
|
77
77
|
url=openid_connect["url"],
|
|
78
78
|
authentication_redirect_uri=request.route_url("oidc_callback"),
|
|
79
79
|
client_id=openid_connect["client_id"],
|
|
80
|
-
client_secret=openid_connect.get("
|
|
80
|
+
client_secret=openid_connect.get("client_secret"),
|
|
81
81
|
scope=" ".join(openid_connect.get("scopes", ["openid", "profile", "email"])),
|
|
82
82
|
)
|
|
83
83
|
|
|
@@ -87,9 +87,7 @@ class OidcRememberObject(TypedDict):
|
|
|
87
87
|
The JSON object that is stored in a cookie to remember the user.
|
|
88
88
|
"""
|
|
89
89
|
|
|
90
|
-
access_token: str
|
|
91
90
|
access_token_expires: str
|
|
92
|
-
refresh_token: str | None
|
|
93
91
|
refresh_token_expires: str | None
|
|
94
92
|
username: str | None
|
|
95
93
|
display_name: str | None
|
|
@@ -124,16 +122,31 @@ def get_remember_from_user_info(
|
|
|
124
122
|
("settings_role", None),
|
|
125
123
|
("roles", None),
|
|
126
124
|
):
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
125
|
+
_LOG.debug("User info keys: %s", ", ".join(user_info.keys()))
|
|
126
|
+
user_info_field_template = settings_fields.get(field_, default_field)
|
|
127
|
+
if user_info_field_template is not None:
|
|
128
|
+
if "{" in user_info_field_template:
|
|
129
|
+
formatter = string.Formatter()
|
|
130
|
+
attributes = formatter.parse(user_info_field_template)
|
|
131
|
+
user_info_fields = [e[1] for e in attributes if e[1] is not None]
|
|
132
|
+
else:
|
|
133
|
+
user_info_fields = [user_info_field_template]
|
|
134
|
+
|
|
135
|
+
for user_info_field in user_info_fields:
|
|
136
|
+
if user_info_field not in user_info:
|
|
137
|
+
_LOG.error(
|
|
138
|
+
"Field '%s' not found in user info, available: %s.",
|
|
139
|
+
user_info_field,
|
|
140
|
+
", ".join(user_info.keys()),
|
|
141
|
+
)
|
|
142
|
+
raise HTTPInternalServerError(f"Field '{user_info_field}' not found in user info.")
|
|
143
|
+
|
|
144
|
+
user_info_value = (
|
|
145
|
+
user_info_field_template.format(**user_info)
|
|
146
|
+
if "{" in user_info_field_template
|
|
147
|
+
else user_info[user_info_field_template]
|
|
148
|
+
)
|
|
149
|
+
remember_object[field_] = user_info_value # type: ignore[literal-required]
|
|
137
150
|
|
|
138
151
|
|
|
139
152
|
def get_user_from_remember(
|
|
@@ -155,60 +168,66 @@ def get_user_from_remember(
|
|
|
155
168
|
assert models.DBSession is not None
|
|
156
169
|
|
|
157
170
|
user: static.User | DynamicUser | None
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
"
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
171
|
+
try:
|
|
172
|
+
username = remember_object["username"]
|
|
173
|
+
assert username is not None
|
|
174
|
+
email = remember_object["email"]
|
|
175
|
+
assert email is not None
|
|
176
|
+
display_name = remember_object["display_name"] or email
|
|
177
|
+
|
|
178
|
+
openid_connect_configuration = request.registry.settings.get("authentication", {}).get(
|
|
179
|
+
"openid_connect", {}
|
|
180
|
+
)
|
|
181
|
+
provide_roles = openid_connect_configuration.get("provide_roles", False)
|
|
182
|
+
if provide_roles is False:
|
|
183
|
+
user_query = models.DBSession.query(static.User)
|
|
184
|
+
match_field = openid_connect_configuration.get("match_field", "username")
|
|
185
|
+
if match_field == "username":
|
|
186
|
+
user_query = user_query.filter_by(username=username)
|
|
187
|
+
elif match_field == "email":
|
|
188
|
+
user_query = user_query.filter_by(email=email)
|
|
189
|
+
else:
|
|
190
|
+
raise HTTPInternalServerError(
|
|
191
|
+
f"Unknown match_field: '{match_field}', allowed values are 'username' and 'email'"
|
|
192
|
+
)
|
|
193
|
+
user = user_query.one_or_none()
|
|
194
|
+
if update_create_user is True:
|
|
195
|
+
if user is not None:
|
|
196
|
+
for field in openid_connect_configuration.get("update_fields", []):
|
|
197
|
+
if field == "username":
|
|
198
|
+
user.username = username
|
|
199
|
+
elif field == "display_name":
|
|
200
|
+
user.display_name = display_name
|
|
201
|
+
elif field == "email":
|
|
202
|
+
user.email = email
|
|
203
|
+
else:
|
|
204
|
+
raise HTTPInternalServerError(
|
|
205
|
+
f"Unknown update_field: '{field}', allowed values are 'username', 'display_name' and 'email'"
|
|
206
|
+
)
|
|
207
|
+
elif openid_connect_configuration.get("create_user", False) is True:
|
|
208
|
+
user = static.User(username=username, email=email, display_name=display_name)
|
|
209
|
+
models.DBSession.add(user)
|
|
175
210
|
else:
|
|
176
|
-
|
|
177
|
-
|
|
211
|
+
roles = []
|
|
212
|
+
role_names = remember_object.get("roles", [])
|
|
213
|
+
if role_names:
|
|
214
|
+
query = models.DBSession.query(main.Role).filter(main.Role.name.in_(role_names))
|
|
215
|
+
roles = query.all()
|
|
216
|
+
user = DynamicUser(
|
|
217
|
+
id=-1,
|
|
218
|
+
username=username,
|
|
219
|
+
display_name=display_name,
|
|
220
|
+
email=email,
|
|
221
|
+
settings_role=(
|
|
222
|
+
models.DBSession.query(main.Role).filter_by(name=remember_object["settings_role"]).first()
|
|
223
|
+
if remember_object.get("settings_role") is not None
|
|
224
|
+
else None
|
|
225
|
+
),
|
|
226
|
+
roles=roles,
|
|
178
227
|
)
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
for field in openid_connect_configuration.get("update_fields", []):
|
|
183
|
-
if field == "username":
|
|
184
|
-
user.username = username
|
|
185
|
-
elif field == "display_name":
|
|
186
|
-
user.display_name = display_name
|
|
187
|
-
elif field == "email":
|
|
188
|
-
user.email = email
|
|
189
|
-
else:
|
|
190
|
-
raise HTTPInternalServerError(
|
|
191
|
-
f"Unknown update_field: '{field}', allowed values are 'username', 'display_name' and 'email'"
|
|
192
|
-
)
|
|
193
|
-
elif openid_connect_configuration.get("create_user", False) is True:
|
|
194
|
-
user = static.User(username=username, email=email, display_name=display_name)
|
|
195
|
-
models.DBSession.add(user)
|
|
196
|
-
else:
|
|
197
|
-
user = DynamicUser(
|
|
198
|
-
id=-1,
|
|
199
|
-
username=username,
|
|
200
|
-
display_name=display_name,
|
|
201
|
-
email=email,
|
|
202
|
-
settings_role=(
|
|
203
|
-
models.DBSession.query(main.Role).filter_by(name=remember_object["settings_role"]).first()
|
|
204
|
-
if remember_object.get("settings_role") is not None
|
|
205
|
-
else None
|
|
206
|
-
),
|
|
207
|
-
roles=[
|
|
208
|
-
models.DBSession.query(main.Role).filter_by(name=role).one()
|
|
209
|
-
for role in remember_object.get("roles", [])
|
|
210
|
-
],
|
|
211
|
-
)
|
|
228
|
+
except KeyError:
|
|
229
|
+
_LOG.exception("Missing field in remember object")
|
|
230
|
+
return None
|
|
212
231
|
return user
|
|
213
232
|
|
|
214
233
|
|
|
@@ -248,17 +267,36 @@ class OidcRemember:
|
|
|
248
267
|
raise HTTPUnauthorized("See server logs for details")
|
|
249
268
|
|
|
250
269
|
openid_connect = self.authentication_settings.get("openid_connect", {})
|
|
270
|
+
self.request.response.set_cookie(
|
|
271
|
+
"access_token",
|
|
272
|
+
token_response.access_token,
|
|
273
|
+
max_age=token_response.expires_in,
|
|
274
|
+
secure=True,
|
|
275
|
+
httponly=True,
|
|
276
|
+
samesite="Lax",
|
|
277
|
+
domain=self.request.domain,
|
|
278
|
+
)
|
|
279
|
+
if token_response.refresh_expires_in is not None:
|
|
280
|
+
self.request.response.set_cookie(
|
|
281
|
+
"refresh_token",
|
|
282
|
+
token_response.refresh_token,
|
|
283
|
+
max_age=token_response.refresh_expires_in,
|
|
284
|
+
secure=True,
|
|
285
|
+
httponly=True,
|
|
286
|
+
samesite="Lax",
|
|
287
|
+
domain=self.request.domain,
|
|
288
|
+
)
|
|
251
289
|
remember_object: OidcRememberObject = {
|
|
252
|
-
"access_token": token_response.access_token,
|
|
253
290
|
"access_token_expires": (
|
|
254
|
-
datetime.datetime.now(
|
|
291
|
+
datetime.datetime.now(datetime.timezone.utc)
|
|
292
|
+
+ datetime.timedelta(seconds=token_response.expires_in)
|
|
255
293
|
).isoformat(),
|
|
256
|
-
"refresh_token": token_response.refresh_token,
|
|
257
294
|
"refresh_token_expires": (
|
|
258
295
|
None
|
|
259
296
|
if token_response.refresh_expires_in is None
|
|
260
297
|
else (
|
|
261
|
-
datetime.datetime.now(
|
|
298
|
+
datetime.datetime.now(datetime.timezone.utc)
|
|
299
|
+
+ datetime.timedelta(seconds=token_response.refresh_expires_in)
|
|
262
300
|
).isoformat()
|
|
263
301
|
),
|
|
264
302
|
"username": None,
|
|
@@ -1,15 +1,4 @@
|
|
|
1
|
-
# yaml-language-server: $schema=https://raw.githubusercontent.com/camptocamp/c2cciutils/
|
|
2
|
-
|
|
3
|
-
checks:
|
|
4
|
-
black: False
|
|
5
|
-
isort: False
|
|
6
|
-
prettier: False
|
|
7
|
-
codespell: False
|
|
8
|
-
eof: False
|
|
9
|
-
required_workflows: False
|
|
10
|
-
dependabot_config: False
|
|
11
|
-
prospector_config: False
|
|
12
|
-
setup: False
|
|
1
|
+
# yaml-language-server: $schema=https://raw.githubusercontent.com/camptocamp/c2cciutils/1.7/c2cciutils/schema.json
|
|
13
2
|
|
|
14
3
|
version:
|
|
15
4
|
branch_to_version_re:
|
c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/Dockerfile
CHANGED
|
@@ -19,7 +19,7 @@ RUN make build
|
|
|
19
19
|
RUN mv webpack.apps.js webpack.apps.js.tmpl
|
|
20
20
|
|
|
21
21
|
ENTRYPOINT [ "/usr/bin/eval-templates" ]
|
|
22
|
-
CMD [ "webpack", "serve", "--open", "--mode=development"
|
|
22
|
+
CMD [ "webpack", "serve", "--open", "--mode=development" ]
|
|
23
23
|
|
|
24
24
|
###############################################################################
|
|
25
25
|
|
|
@@ -33,8 +33,8 @@ WORKDIR /app
|
|
|
33
33
|
COPY . /app
|
|
34
34
|
# Workaround, see:https://github.com/moby/moby/issues/37965
|
|
35
35
|
RUN true
|
|
36
|
-
COPY --from=builder /opt/c2cgeoportal/geoportal/node_modules/ngeo/dist
|
|
37
|
-
|
|
36
|
+
COPY --from=builder /opt/c2cgeoportal/geoportal/node_modules/ngeo/dist/vendor.* /etc/static-ngeo/
|
|
37
|
+
COPY --from=builder /opt/c2cgeoportal/geoportal/node_modules/ngeo/dist/*_alt.* /etc/static-ngeo/
|
|
38
38
|
COPY --from=builder /etc/static-ngeo/* /etc/static-ngeo/
|
|
39
39
|
COPY --from=builder /app/alembic.ini /app/alembic.yaml ./
|
|
40
40
|
RUN chmod go+w /etc/static-ngeo/
|
c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/alembic.ini
CHANGED
|
@@ -44,13 +44,13 @@ qualname = alembic
|
|
|
44
44
|
|
|
45
45
|
[handler_console]
|
|
46
46
|
class = StreamHandler
|
|
47
|
-
|
|
47
|
+
args = (sys.stderr,)
|
|
48
48
|
level = NOTSET
|
|
49
49
|
formatter = generic
|
|
50
50
|
|
|
51
51
|
[handler_json]
|
|
52
52
|
class = c2cwsgiutils.pyramid_logging.JsonLogHandler
|
|
53
|
-
|
|
53
|
+
args = (sys.stderr,)
|
|
54
54
|
level = NOTSET
|
|
55
55
|
|
|
56
56
|
[formatter_generic]
|
c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/webpack.apps.js
CHANGED
|
@@ -42,10 +42,20 @@ module.exports = {
|
|
|
42
42
|
publicPath: devServer ? '${VISIBLE_ENTRY_POINT}dev/' : '.__ENTRY_POINT__static-ngeo/',
|
|
43
43
|
},
|
|
44
44
|
devServer: {
|
|
45
|
-
|
|
45
|
+
devMiddleware: {
|
|
46
|
+
publicPath: '${VISIBLE_WEB_PROTOCOL}://${VISIBLE_WEB_HOST}${VISIBLE_ENTRY_POINT}dev/',
|
|
47
|
+
},
|
|
46
48
|
port: 8080,
|
|
47
49
|
host: 'webpack_dev_server',
|
|
48
50
|
hot: true,
|
|
51
|
+
compress: false,
|
|
52
|
+
client: {
|
|
53
|
+
webSocketURL: {
|
|
54
|
+
hostname: 'localhost',
|
|
55
|
+
port: 8080,
|
|
56
|
+
protocol: 'ws',
|
|
57
|
+
},
|
|
58
|
+
},
|
|
49
59
|
},
|
|
50
60
|
entry: entry,
|
|
51
61
|
plugins: plugins,
|
c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.github/workflows/main.yaml
CHANGED
|
@@ -6,7 +6,6 @@ on:
|
|
|
6
6
|
|
|
7
7
|
# To publish the images to be used on Kubernetes
|
|
8
8
|
# env:
|
|
9
|
-
# PROJECT: {{cookiecutter.package}}
|
|
10
9
|
# HAS_SECRETS: ${{'{{'}} secrets.HAS_SECRETS }}
|
|
11
10
|
|
|
12
11
|
jobs:
|
|
@@ -19,6 +18,7 @@ jobs:
|
|
|
19
18
|
- uses: actions/checkout@v4
|
|
20
19
|
|
|
21
20
|
# To publish the images to be used on Kubernetes
|
|
21
|
+
# Requires CI_GPG_PRIVATE_KEY and GOPASS_CI_GITHUB_TOKEN secrets.
|
|
22
22
|
# - uses: camptocamp/initialise-gopass-summon-action@v2
|
|
23
23
|
# with:
|
|
24
24
|
# ci-gpg-private-key: ${{'{{'}} secrets.CI_GPG_PRIVATE_KEY }}
|
c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.github/workflows/rebuild.yaml
CHANGED
|
@@ -5,13 +5,6 @@ on:
|
|
|
5
5
|
schedule:
|
|
6
6
|
- cron: '30 2 * * *'
|
|
7
7
|
|
|
8
|
-
env:
|
|
9
|
-
PROJECT: {{cookiecutter.package}}
|
|
10
|
-
# Requires CI_GPG_PRIVATE_KEY and GOPASS_CI_GITHUB_TOKEN secrets.
|
|
11
|
-
# OPENSHIFT_PROJECT: gs-gmf-{{cookiecutter.package}}
|
|
12
|
-
# The release branches
|
|
13
|
-
HELM_RELEASE_NAMES: int-{{cookiecutter.geomapfish_main_version_dash}},prod-{{cookiecutter.geomapfish_main_version_dash}}
|
|
14
|
-
|
|
15
8
|
jobs:
|
|
16
9
|
rebuild:
|
|
17
10
|
runs-on: ubuntu-24.04
|
|
@@ -30,6 +23,7 @@ jobs:
|
|
|
30
23
|
with:
|
|
31
24
|
ref: ${{'{{'}} matrix.branch }}
|
|
32
25
|
|
|
26
|
+
# Requires CI_GPG_PRIVATE_KEY and GOPASS_CI_GITHUB_TOKEN secrets.
|
|
33
27
|
- uses: camptocamp/initialise-gopass-summon-action@v2
|
|
34
28
|
with:
|
|
35
29
|
ci-gpg-private-key: ${{'{{'}} secrets.CI_GPG_PRIVATE_KEY }}
|