c2cgeoportal-geoportal 2.3.5.79__py3-none-any.whl → 2.9rc44__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 +960 -0
- c2cgeoportal_geoportal/lib/__init__.py +256 -0
- c2cgeoportal_geoportal/lib/authentication.py +250 -0
- c2cgeoportal_geoportal/lib/bashcolor.py +46 -0
- c2cgeoportal_geoportal/lib/cacheversion.py +77 -0
- c2cgeoportal_geoportal/lib/caching.py +176 -0
- c2cgeoportal_geoportal/lib/check_collector.py +80 -0
- c2cgeoportal_geoportal/lib/checker.py +295 -0
- c2cgeoportal_geoportal/lib/common_headers.py +172 -0
- c2cgeoportal_geoportal/lib/dbreflection.py +266 -0
- c2cgeoportal_geoportal/lib/filter_capabilities.py +360 -0
- c2cgeoportal_geoportal/lib/fulltextsearch.py +50 -0
- c2cgeoportal_geoportal/lib/functionality.py +166 -0
- c2cgeoportal_geoportal/lib/headers.py +62 -0
- c2cgeoportal_geoportal/lib/i18n.py +38 -0
- c2cgeoportal_geoportal/lib/layers.py +132 -0
- c2cgeoportal_geoportal/lib/lingva_extractor.py +937 -0
- c2cgeoportal_geoportal/lib/loader.py +57 -0
- c2cgeoportal_geoportal/lib/metrics.py +117 -0
- c2cgeoportal_geoportal/lib/oauth2.py +1186 -0
- c2cgeoportal_geoportal/lib/oidc.py +304 -0
- c2cgeoportal_geoportal/lib/wmstparsing.py +353 -0
- c2cgeoportal_geoportal/lib/xsd.py +166 -0
- c2cgeoportal_geoportal/py.typed +0 -0
- c2cgeoportal_geoportal/resources.py +49 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/ci/config.yaml +26 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/cookiecutter.json +18 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/.dockerignore +6 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/.eslintrc.yaml +19 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/.prospector.yaml +30 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/Dockerfile +75 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/Makefile +6 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/alembic.ini +58 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/alembic.yaml +19 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/development.ini +121 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/gunicorn.conf.py +139 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/language_mapping +3 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/lingva-client.cfg +5 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/lingva-server.cfg +6 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/production.ini +38 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/requirements.txt +2 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/setup.py +25 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/webpack.api.js +41 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/webpack.apps.js +64 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/webpack.commons.js +11 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/webpack.config.js +22 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/__init__.py +42 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/authentication.py +10 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/dev.py +14 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/models.py +8 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/multi_organization.py +7 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/resources.py +11 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static-ngeo/api/index.js +12 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static-ngeo/js/{{cookiecutter.package}}module.js +25 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/subscribers.py +39 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/views/__init__.py +0 -0
- c2cgeoportal_geoportal/scaffolds/advance_update/cookiecutter.json +18 -0
- c2cgeoportal_geoportal/scaffolds/advance_update/{{cookiecutter.project}}/geoportal/CONST_Makefile +121 -0
- c2cgeoportal_geoportal/scaffolds/create/cookiecutter.json +18 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.dockerignore +14 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.editorconfig +17 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.github/workflows/main.yaml +73 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.github/workflows/rebuild.yaml +50 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.github/workflows/update_l10n.yaml +66 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.gitignore +16 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.pre-commit-config.yaml +35 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.prettierignore +1 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.prettierrc.yaml +2 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/Dockerfile +75 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/Makefile +70 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/README.rst +29 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/build +179 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/ci/config.yaml +22 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/ci/docker-compose-check +25 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/ci/requirements.txt +2 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/docker-compose-db.yaml +24 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/docker-compose-lib.yaml +513 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/docker-compose-qgis.yaml +21 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/docker-compose.override.sample.yaml +65 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/docker-compose.yaml +121 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/env.default +102 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/env.project +69 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/geoportal/vars.yaml +430 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/locale/en/LC_MESSAGES/{{cookiecutter.package}}_geoportal-client.po +6 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static/css/desktop.css +0 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static/css/iframe_api.css +0 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static/css/mobile.css +0 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static/images/banner_left.png +0 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static/images/banner_right.png +0 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static/images/blank.png +0 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static/images/markers/marker-blue.png +0 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static/images/markers/marker-gold.png +0 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static/images/markers/marker-green.png +0 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static/images/markers/marker.png +0 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static/robot.txt.tmpl +3 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/data/Readme.txt +69 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/data/TM_EUROPE_BORDERS-0.3.sql +70 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/demo.map.tmpl +224 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/fonts/Arial.ttf +0 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/fonts/Arialbd.ttf +0 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/fonts/Arialbi.ttf +0 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/fonts/Ariali.ttf +0 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/fonts/NotoSans-Bold.ttf +0 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/fonts/NotoSans-BoldItalic.ttf +0 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/fonts/NotoSans-Italic.ttf +0 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/fonts/NotoSans-Regular.ttf +0 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/fonts/Verdana.ttf +0 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/fonts/Verdanab.ttf +0 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/fonts/Verdanai.ttf +0 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/fonts/Verdanaz.ttf +0 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/fonts.conf +12 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/mapserver.conf +16 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/mapserver.map.tmpl +87 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/tinyows.xml.tmpl +36 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}/A3_Landscape.jrxml +207 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}/A3_Portrait.jrxml +185 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}/A4_Landscape.jrxml +200 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}/A4_Portrait.jrxml +170 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}/config.yaml.tmpl +175 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}/legend.jrxml +109 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}/localisation.properties +4 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}/localisation_fr.properties +4 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}/logo.png +0 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}/north.svg +93 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}/results.jrxml +25 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/project.yaml +18 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/pyproject.toml +7 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/qgisserver/pg_service.conf.tmpl +15 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/run_alembic.sh +11 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/scripts/db-backup +126 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/scripts/db-restore +132 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/setup.cfg +7 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/spell-ignore-words.txt +5 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/tests/__init__.py +0 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/tests/test_app.py +78 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/tilegeneration/config.yaml.tmpl +195 -0
- c2cgeoportal_geoportal/scaffolds/update/cookiecutter.json +18 -0
- c2cgeoportal_geoportal/scaffolds/update/{{cookiecutter.project}}/.upgrade.yaml +67 -0
- c2cgeoportal_geoportal/scaffolds/update/{{cookiecutter.project}}/CONST_CHANGELOG.txt +304 -0
- c2cgeoportal_geoportal/scaffolds/update/{{cookiecutter.project}}/CONST_create_template/tests/test_testapp.py +48 -0
- c2cgeoportal_geoportal/scaffolds/update/{{cookiecutter.project}}/geoportal/.CONST_vars.yaml.swp +0 -0
- c2cgeoportal_geoportal/scaffolds/update/{{cookiecutter.project}}/geoportal/CONST_config-schema.yaml +927 -0
- c2cgeoportal_geoportal/scaffolds/update/{{cookiecutter.project}}/geoportal/CONST_vars.yaml +1503 -0
- c2cgeoportal_geoportal/scripts/__init__.py +64 -0
- c2cgeoportal_geoportal/scripts/c2cupgrade.py +879 -0
- c2cgeoportal_geoportal/scripts/create_demo_theme.py +83 -0
- c2cgeoportal_geoportal/scripts/manage_users.py +140 -0
- c2cgeoportal_geoportal/scripts/pcreate.py +296 -0
- c2cgeoportal_geoportal/scripts/theme2fts.py +347 -0
- c2cgeoportal_geoportal/scripts/urllogin.py +81 -0
- c2cgeoportal_geoportal/templates/login.html +90 -0
- c2cgeoportal_geoportal/templates/notlogin.html +62 -0
- c2cgeoportal_geoportal/templates/testi18n.html +12 -0
- c2cgeoportal_geoportal/views/__init__.py +59 -0
- c2cgeoportal_geoportal/views/dev.py +57 -0
- c2cgeoportal_geoportal/views/dynamic.py +208 -0
- c2cgeoportal_geoportal/views/entry.py +174 -0
- c2cgeoportal_geoportal/views/fulltextsearch.py +189 -0
- c2cgeoportal_geoportal/views/geometry_processing.py +75 -0
- c2cgeoportal_geoportal/views/i18n.py +129 -0
- c2cgeoportal_geoportal/views/layers.py +713 -0
- c2cgeoportal_geoportal/views/login.py +684 -0
- c2cgeoportal_geoportal/views/mapserverproxy.py +234 -0
- c2cgeoportal_geoportal/views/memory.py +90 -0
- c2cgeoportal_geoportal/views/ogcproxy.py +120 -0
- c2cgeoportal_geoportal/views/pdfreport.py +245 -0
- c2cgeoportal_geoportal/views/printproxy.py +143 -0
- c2cgeoportal_geoportal/views/profile.py +192 -0
- c2cgeoportal_geoportal/views/proxy.py +261 -0
- c2cgeoportal_geoportal/views/raster.py +233 -0
- c2cgeoportal_geoportal/views/resourceproxy.py +73 -0
- c2cgeoportal_geoportal/views/shortener.py +152 -0
- c2cgeoportal_geoportal/views/theme.py +1322 -0
- c2cgeoportal_geoportal/views/tinyowsproxy.py +189 -0
- c2cgeoportal_geoportal/views/vector_tiles.py +83 -0
- {c2cgeoportal_geoportal-2.3.5.79.dist-info → c2cgeoportal_geoportal-2.9rc44.dist-info}/METADATA +21 -24
- c2cgeoportal_geoportal-2.9rc44.dist-info/RECORD +193 -0
- {c2cgeoportal_geoportal-2.3.5.79.dist-info → c2cgeoportal_geoportal-2.9rc44.dist-info}/WHEEL +1 -1
- c2cgeoportal_geoportal-2.9rc44.dist-info/entry_points.txt +28 -0
- c2cgeoportal_geoportal-2.9rc44.dist-info/top_level.txt +2 -0
- tests/__init__.py +100 -0
- tests/test_cachebuster.py +71 -0
- tests/test_caching.py +275 -0
- tests/test_checker.py +85 -0
- tests/test_decimaljson.py +47 -0
- tests/test_headerstween.py +64 -0
- tests/test_i18n.py +31 -0
- tests/test_init.py +193 -0
- tests/test_locale_negociator.py +69 -0
- tests/test_mapserverproxy_route_predicate.py +64 -0
- tests/test_raster.py +267 -0
- tests/test_wmstparsing.py +238 -0
- tests/xmlstr.py +103 -0
- c2cgeoportal_geoportal-2.3.5.79.dist-info/DESCRIPTION.rst +0 -8
- c2cgeoportal_geoportal-2.3.5.79.dist-info/RECORD +0 -7
- c2cgeoportal_geoportal-2.3.5.79.dist-info/entry_points.txt +0 -22
- c2cgeoportal_geoportal-2.3.5.79.dist-info/metadata.json +0 -1
- c2cgeoportal_geoportal-2.3.5.79.dist-info/top_level.txt +0 -1
@@ -0,0 +1,347 @@
|
|
1
|
+
# Copyright (c) 2014-2023, Camptocamp SA
|
2
|
+
# All rights reserved.
|
3
|
+
|
4
|
+
# Redistribution and use in source and binary forms, with or without
|
5
|
+
# modification, are permitted provided that the following conditions are met:
|
6
|
+
|
7
|
+
# 1. Redistributions of source code must retain the above copyright notice, this
|
8
|
+
# list of conditions and the following disclaimer.
|
9
|
+
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
10
|
+
# this list of conditions and the following disclaimer in the documentation
|
11
|
+
# and/or other materials provided with the distribution.
|
12
|
+
|
13
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
14
|
+
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
15
|
+
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
16
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
17
|
+
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
18
|
+
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
19
|
+
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
20
|
+
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
21
|
+
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
22
|
+
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
23
|
+
|
24
|
+
# The views and conclusions contained in the software and documentation are those
|
25
|
+
# of the authors and should not be interpreted as representing official policies,
|
26
|
+
# either expressed or implied, of the FreeBSD Project.
|
27
|
+
|
28
|
+
|
29
|
+
import gettext
|
30
|
+
import os
|
31
|
+
import sys
|
32
|
+
from argparse import ArgumentParser, Namespace
|
33
|
+
from collections.abc import Iterator
|
34
|
+
from typing import TYPE_CHECKING, Any, Optional
|
35
|
+
|
36
|
+
import pyramid.config
|
37
|
+
import transaction
|
38
|
+
from sqlalchemy import func
|
39
|
+
from sqlalchemy.orm.session import Session
|
40
|
+
|
41
|
+
from c2cgeoportal_geoportal.lib.bashcolor import Color, colorize
|
42
|
+
from c2cgeoportal_geoportal.lib.fulltextsearch import Normalize
|
43
|
+
from c2cgeoportal_geoportal.lib.i18n import LOCALE_PATH
|
44
|
+
from c2cgeoportal_geoportal.scripts import fill_arguments, get_appsettings, get_session
|
45
|
+
|
46
|
+
if TYPE_CHECKING:
|
47
|
+
import c2cgeoportal_commons.models.main
|
48
|
+
|
49
|
+
|
50
|
+
def get_argparser() -> ArgumentParser:
|
51
|
+
"""Get the argument parser for this script."""
|
52
|
+
parser = ArgumentParser(
|
53
|
+
prog=sys.argv[0],
|
54
|
+
add_help=True,
|
55
|
+
description="Tool to fill the tsearch table (full-text search) from the theme information.",
|
56
|
+
)
|
57
|
+
|
58
|
+
parser.add_argument(
|
59
|
+
"--locale-folder",
|
60
|
+
default=LOCALE_PATH,
|
61
|
+
help=f"The folder where the locale files are stored (default is {LOCALE_PATH})",
|
62
|
+
)
|
63
|
+
parser.add_argument("--interfaces", action="append", help="the interfaces to export")
|
64
|
+
parser.add_argument(
|
65
|
+
"--exclude-interfaces",
|
66
|
+
action="append",
|
67
|
+
default=["api"],
|
68
|
+
help="the interfaces to exclude (can't be used with --interfaces)",
|
69
|
+
)
|
70
|
+
parser.add_argument(
|
71
|
+
"--duplicate-name",
|
72
|
+
action="store_true",
|
73
|
+
dest="name",
|
74
|
+
help="allows to add a name more than one time,\n"
|
75
|
+
"by default if we find more than one element with the same name "
|
76
|
+
"only one will be imported",
|
77
|
+
)
|
78
|
+
parser.add_argument("--no-themes", action="store_false", dest="themes", help="do not import the themes")
|
79
|
+
parser.add_argument(
|
80
|
+
"--no-blocks",
|
81
|
+
action="store_false",
|
82
|
+
dest="blocks",
|
83
|
+
help="do not import the blocks (first level layer groups)",
|
84
|
+
)
|
85
|
+
parser.add_argument(
|
86
|
+
"--no-folders", action="store_false", dest="folders", help="do not import the folders (tree folders)"
|
87
|
+
)
|
88
|
+
parser.add_argument(
|
89
|
+
"--no-layers", action="store_false", dest="layers", help="do not import the layers (tree leaf)"
|
90
|
+
)
|
91
|
+
parser.add_argument("--package", help="the application package")
|
92
|
+
fill_arguments(parser)
|
93
|
+
return parser
|
94
|
+
|
95
|
+
|
96
|
+
def main() -> None:
|
97
|
+
"""Run the command."""
|
98
|
+
|
99
|
+
options = get_argparser().parse_args()
|
100
|
+
settings = get_appsettings(options)
|
101
|
+
|
102
|
+
with transaction.manager:
|
103
|
+
session = get_session(settings, transaction.manager)
|
104
|
+
|
105
|
+
Import(session, settings, options)
|
106
|
+
|
107
|
+
|
108
|
+
class Import:
|
109
|
+
"""
|
110
|
+
To import all the themes, layer groups and layers names into the full-text search table.
|
111
|
+
|
112
|
+
Done by interface and by language.
|
113
|
+
"""
|
114
|
+
|
115
|
+
def __init__(self, session: Session, settings: pyramid.config.Configurator, options: Namespace):
|
116
|
+
self.options = options
|
117
|
+
self.imported: set[Any] = set()
|
118
|
+
package = settings["package"]
|
119
|
+
|
120
|
+
self.fts_languages = settings["fulltextsearch"]["languages"]
|
121
|
+
self.languages = settings["available_locale_names"]
|
122
|
+
self.fts_normalizer = Normalize(settings["fulltextsearch"])
|
123
|
+
|
124
|
+
fts_missing_langs = [lang for lang in self.languages if lang not in self.fts_languages]
|
125
|
+
if fts_missing_langs:
|
126
|
+
msg = f"Keys {fts_missing_langs} are missing in fulltextsearch languages configuration."
|
127
|
+
if os.environ.get("IGNORE_I18N_ERRORS", "FALSE") == "TRUE":
|
128
|
+
print(colorize(msg, Color.RED))
|
129
|
+
self.languages = [lang for lang in self.languages if lang in self.fts_languages]
|
130
|
+
else:
|
131
|
+
raise KeyError(KeyError(msg))
|
132
|
+
|
133
|
+
# must be done only once we have loaded the project config
|
134
|
+
from c2cgeoportal_commons.models.main import ( # pylint: disable=import-outside-toplevel
|
135
|
+
FullTextSearch,
|
136
|
+
Interface,
|
137
|
+
Role,
|
138
|
+
Theme,
|
139
|
+
)
|
140
|
+
|
141
|
+
self.session = session
|
142
|
+
self.session.execute(FullTextSearch.__table__.delete().where(FullTextSearch.from_theme))
|
143
|
+
|
144
|
+
self._: dict[str, gettext.NullTranslations] = {}
|
145
|
+
for lang in self.languages:
|
146
|
+
try:
|
147
|
+
self._[lang] = gettext.translation(
|
148
|
+
f"{package}_geoportal-client",
|
149
|
+
options.locale_folder.format(package=package),
|
150
|
+
[lang],
|
151
|
+
)
|
152
|
+
except OSError as e:
|
153
|
+
self._[lang] = gettext.NullTranslations()
|
154
|
+
print(f"Warning: {e} (language: {lang})")
|
155
|
+
|
156
|
+
query = self.session.query(Interface)
|
157
|
+
if options.interfaces is not None:
|
158
|
+
query = query.filter(Interface.name.in_(options.interfaces))
|
159
|
+
else:
|
160
|
+
query = query.filter(Interface.name.notin_(options.exclude_interfaces))
|
161
|
+
self.interfaces = query.all()
|
162
|
+
|
163
|
+
self.public_theme: dict[int, list[int]] = {}
|
164
|
+
self.public_group: dict[int, list[int]] = {}
|
165
|
+
for interface in self.interfaces:
|
166
|
+
self.public_theme[interface.id] = []
|
167
|
+
self.public_group[interface.id] = []
|
168
|
+
|
169
|
+
for theme in self.session.query(Theme).filter_by(public=True).all():
|
170
|
+
self._add_theme(theme)
|
171
|
+
|
172
|
+
for role in self.session.query(Role).all():
|
173
|
+
for theme in self.session.query(Theme).all():
|
174
|
+
self._add_theme(theme, role)
|
175
|
+
|
176
|
+
def _add_fts(
|
177
|
+
self,
|
178
|
+
item: "c2cgeoportal_commons.models.main.TreeItem",
|
179
|
+
interface: "c2cgeoportal_commons.models.main.Interface",
|
180
|
+
action: str,
|
181
|
+
role: Optional["c2cgeoportal_commons.models.main.Role"],
|
182
|
+
) -> None:
|
183
|
+
from c2cgeoportal_commons.models.main import FullTextSearch # pylint: disable=import-outside-toplevel
|
184
|
+
|
185
|
+
key = (
|
186
|
+
item.name if self.options.name else item.id,
|
187
|
+
interface.id,
|
188
|
+
role.id if role is not None else None,
|
189
|
+
)
|
190
|
+
if key not in self.imported:
|
191
|
+
self.imported.add(key)
|
192
|
+
for lang in self.languages:
|
193
|
+
fts = FullTextSearch()
|
194
|
+
fts.label = self._render_label(item, lang)
|
195
|
+
fts.role = role
|
196
|
+
fts.interface = interface
|
197
|
+
fts.lang = lang
|
198
|
+
fts.public = role is None
|
199
|
+
fts.ts = func.to_tsvector(
|
200
|
+
self.fts_languages[lang],
|
201
|
+
" ".join(
|
202
|
+
[self.fts_normalizer(self._[lang].gettext(item.name))]
|
203
|
+
+ [v.strip() for m in item.get_metadata("searchAlias") for v in m.value.split(",")]
|
204
|
+
),
|
205
|
+
)
|
206
|
+
fts.actions = [{"action": action, "data": item.name}]
|
207
|
+
fts.from_theme = True
|
208
|
+
self.session.add(fts)
|
209
|
+
|
210
|
+
def _add_theme(
|
211
|
+
self,
|
212
|
+
theme: "c2cgeoportal_commons.models.main.Theme",
|
213
|
+
role: Optional["c2cgeoportal_commons.models.main.Role"] = None,
|
214
|
+
) -> None:
|
215
|
+
fill = False
|
216
|
+
for interface in self.interfaces:
|
217
|
+
if interface in theme.interfaces:
|
218
|
+
for child in theme.children:
|
219
|
+
fill = self._add_block(child, interface, role) or fill
|
220
|
+
|
221
|
+
if fill and self.options.themes:
|
222
|
+
if role is None:
|
223
|
+
self.public_theme[interface.id].append(theme.id)
|
224
|
+
|
225
|
+
if role is None or theme.id not in self.public_theme[interface.id]:
|
226
|
+
self._add_fts(theme, interface, "add_theme", role)
|
227
|
+
|
228
|
+
def _add_block(
|
229
|
+
self,
|
230
|
+
group: "c2cgeoportal_commons.models.main.LayerGroup",
|
231
|
+
interface: "c2cgeoportal_commons.models.main.Interface",
|
232
|
+
role: Optional["c2cgeoportal_commons.models.main.Role"],
|
233
|
+
) -> bool:
|
234
|
+
return self._add_group(group, interface, self.options.blocks, role)
|
235
|
+
|
236
|
+
def _add_folder(
|
237
|
+
self,
|
238
|
+
group: "c2cgeoportal_commons.models.main.LayerGroup",
|
239
|
+
interface: "c2cgeoportal_commons.models.main.Interface",
|
240
|
+
role: Optional["c2cgeoportal_commons.models.main.Role"],
|
241
|
+
) -> bool:
|
242
|
+
return self._add_group(group, interface, self.options.folders, role)
|
243
|
+
|
244
|
+
def _add_group(
|
245
|
+
self,
|
246
|
+
group: "c2cgeoportal_commons.models.main.LayerGroup",
|
247
|
+
interface: "c2cgeoportal_commons.models.main.Interface",
|
248
|
+
export: bool,
|
249
|
+
role: Optional["c2cgeoportal_commons.models.main.Role"],
|
250
|
+
) -> bool:
|
251
|
+
from c2cgeoportal_commons.models.main import LayerGroup # pylint: disable=import-outside-toplevel
|
252
|
+
|
253
|
+
fill = False
|
254
|
+
for child in group.children:
|
255
|
+
if isinstance(child, LayerGroup):
|
256
|
+
fill = self._add_folder(child, interface, role) or fill
|
257
|
+
else:
|
258
|
+
fill = self._add_layer(child, interface, role) or fill
|
259
|
+
|
260
|
+
if fill and export:
|
261
|
+
if role is None:
|
262
|
+
self.public_group[interface.id].append(group.id)
|
263
|
+
|
264
|
+
if role is None or group.id not in self.public_group[interface.id]:
|
265
|
+
self._add_fts(group, interface, "add_group", role)
|
266
|
+
|
267
|
+
return fill
|
268
|
+
|
269
|
+
@staticmethod
|
270
|
+
def _layer_visible(
|
271
|
+
layer: "c2cgeoportal_commons.models.main.Layer", role: "c2cgeoportal_commons.models.main.Role"
|
272
|
+
) -> bool:
|
273
|
+
for restrictionarea in layer.restrictionareas:
|
274
|
+
if role in restrictionarea.roles:
|
275
|
+
return True
|
276
|
+
return False
|
277
|
+
|
278
|
+
def _add_layer(
|
279
|
+
self,
|
280
|
+
layer: "c2cgeoportal_commons.models.main.Layer",
|
281
|
+
interface: "c2cgeoportal_commons.models.main.Interface",
|
282
|
+
role: Optional["c2cgeoportal_commons.models.main.Role"],
|
283
|
+
) -> bool:
|
284
|
+
if role is None:
|
285
|
+
fill = layer.public and interface in layer.interfaces
|
286
|
+
else:
|
287
|
+
fill = interface in layer.interfaces and not layer.public and self._layer_visible(layer, role)
|
288
|
+
|
289
|
+
if fill and self.options.layers:
|
290
|
+
self._add_fts(layer, interface, "add_layer", role)
|
291
|
+
|
292
|
+
return fill
|
293
|
+
|
294
|
+
def _render_label(
|
295
|
+
self,
|
296
|
+
item: "c2cgeoportal_commons.models.main.TreeItem",
|
297
|
+
lang: str,
|
298
|
+
) -> str:
|
299
|
+
patterns = item.get_metadata("searchLabelPattern")
|
300
|
+
if not patterns:
|
301
|
+
return self._[lang].gettext(item.name)
|
302
|
+
pattern = patterns[0]
|
303
|
+
assert isinstance(pattern.value, str)
|
304
|
+
tree_paths = list(self._get_paths(item))
|
305
|
+
# Remove paths where the last element isn't a theme
|
306
|
+
tree_paths = [p for p in tree_paths if p[-1].item_type == "theme"]
|
307
|
+
result = None
|
308
|
+
current_result = None
|
309
|
+
if tree_paths:
|
310
|
+
for path in tree_paths:
|
311
|
+
if len(path) == 2:
|
312
|
+
current_result = pattern.value.format(
|
313
|
+
name=self._[lang].gettext(item.name),
|
314
|
+
theme=self._[lang].gettext(path[-1].name),
|
315
|
+
parent=self._[lang].gettext(path[1].name),
|
316
|
+
)
|
317
|
+
elif len(path) > 2:
|
318
|
+
current_result = pattern.value.format(
|
319
|
+
name=self._[lang].gettext(item.name),
|
320
|
+
theme=self._[lang].gettext(path[-1].name),
|
321
|
+
parent=self._[lang].gettext(path[1].name),
|
322
|
+
block=self._[lang].gettext(path[-2].name),
|
323
|
+
)
|
324
|
+
if result and current_result != result:
|
325
|
+
sys.stderr.write(
|
326
|
+
f"WARNING: the item {item.name} (id: {item.id}) has a label pattern and inconsistent "
|
327
|
+
f"multiple parents\n"
|
328
|
+
)
|
329
|
+
return self._[lang].gettext(item.name)
|
330
|
+
result = current_result
|
331
|
+
return result or pattern.value.format(
|
332
|
+
name=self._[lang].gettext(item.name),
|
333
|
+
theme=self._[lang].gettext(item.name),
|
334
|
+
)
|
335
|
+
|
336
|
+
def _get_paths(
|
337
|
+
self,
|
338
|
+
item: "c2cgeoportal_commons.models.main.TreeItem",
|
339
|
+
) -> Iterator[list["c2cgeoportal_commons.models.main.TreeItem"]]:
|
340
|
+
if item is None:
|
341
|
+
return
|
342
|
+
if any(item.parents):
|
343
|
+
for parent in item.parents:
|
344
|
+
for path in self._get_paths(parent):
|
345
|
+
yield [item, *path]
|
346
|
+
else:
|
347
|
+
yield [item]
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# Copyright (c) 2012-2024, Camptocamp SA
|
2
|
+
# All rights reserved.
|
3
|
+
|
4
|
+
# Redistribution and use in source and binary forms, with or without
|
5
|
+
# modification, are permitted provided that the following conditions are met:
|
6
|
+
|
7
|
+
# 1. Redistributions of source code must retain the above copyright notice, this
|
8
|
+
# list of conditions and the following disclaimer.
|
9
|
+
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
10
|
+
# this list of conditions and the following disclaimer in the documentation
|
11
|
+
# and/or other materials provided with the distribution.
|
12
|
+
|
13
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
14
|
+
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
15
|
+
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
16
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
17
|
+
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
18
|
+
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
19
|
+
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
20
|
+
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
21
|
+
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
22
|
+
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
23
|
+
|
24
|
+
# The views and conclusions contained in the software and documentation are those
|
25
|
+
# of the authors and should not be interpreted as representing official policies,
|
26
|
+
# either expressed or implied, of the FreeBSD Project.
|
27
|
+
|
28
|
+
import argparse
|
29
|
+
import binascii
|
30
|
+
import json
|
31
|
+
import sys
|
32
|
+
import time
|
33
|
+
from typing import cast
|
34
|
+
|
35
|
+
from Crypto.Cipher import AES # nosec
|
36
|
+
from Crypto.Cipher.ChaCha20_Poly1305 import ChaCha20Poly1305Cipher # nosec
|
37
|
+
|
38
|
+
from c2cgeoportal_geoportal.scripts import fill_arguments, get_appsettings
|
39
|
+
|
40
|
+
|
41
|
+
def create_token(aeskey: str, user: str, password: str, valid: bool) -> str:
|
42
|
+
"""Create the authenticated URL token."""
|
43
|
+
auth = {"u": user, "p": password, "t": int(time.time()) + valid * 3600 * 24}
|
44
|
+
|
45
|
+
if aeskey is None:
|
46
|
+
print("urllogin is not configured")
|
47
|
+
sys.exit(1)
|
48
|
+
cipher = cast(ChaCha20Poly1305Cipher, AES.new(aeskey.encode("ascii"), AES.MODE_EAX))
|
49
|
+
data = json.dumps(auth)
|
50
|
+
mod_len = len(data) % 16
|
51
|
+
if mod_len != 0:
|
52
|
+
data += "".join([" " for i in range(16 - mod_len)])
|
53
|
+
ciphertext, tag = cipher.encrypt_and_digest(data.encode("utf-8"))
|
54
|
+
return binascii.hexlify(cipher.nonce + tag + ciphertext).decode("ascii")
|
55
|
+
|
56
|
+
|
57
|
+
def get_argparser() -> argparse.ArgumentParser:
|
58
|
+
"""Get the argument parser for this script."""
|
59
|
+
|
60
|
+
parser = argparse.ArgumentParser(description="Generate an auth token")
|
61
|
+
fill_arguments(parser, use_attribute=True)
|
62
|
+
parser.add_argument("user", help="The username")
|
63
|
+
parser.add_argument("password", help="The password")
|
64
|
+
parser.add_argument("valid", type=int, default=1, nargs="?", help="Is valid for, in days")
|
65
|
+
return parser
|
66
|
+
|
67
|
+
|
68
|
+
def main() -> None:
|
69
|
+
"""Run the command."""
|
70
|
+
|
71
|
+
args = get_argparser().parse_args()
|
72
|
+
settings = get_appsettings(args)
|
73
|
+
urllogin = settings.get("urllogin", {})
|
74
|
+
aeskey = urllogin.get("aes_key")
|
75
|
+
auth_enc = create_token(aeskey, args.user, args.password, args.valid)
|
76
|
+
|
77
|
+
print(f"Use: auth={auth_enc}")
|
78
|
+
|
79
|
+
|
80
|
+
if __name__ == "__main__":
|
81
|
+
main()
|
@@ -0,0 +1,90 @@
|
|
1
|
+
<!doctype html>
|
2
|
+
<html lang="${lang}">
|
3
|
+
<head>
|
4
|
+
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
5
|
+
<meta name="Content-Language" content="${lang}" />
|
6
|
+
<title>${_('Login to Geoportal Application')}</title>
|
7
|
+
<style>
|
8
|
+
body {
|
9
|
+
background: #444444;
|
10
|
+
font-family: Helvetica, Arial, sans-serif;
|
11
|
+
}
|
12
|
+
* {
|
13
|
+
padding: 0;
|
14
|
+
margin: 0;
|
15
|
+
}
|
16
|
+
div#content {
|
17
|
+
background: #f5f5ef;
|
18
|
+
padding: 20px 30px;
|
19
|
+
width: 330px;
|
20
|
+
margin: 100px auto auto auto;
|
21
|
+
-webkit-border-radius: 10px;
|
22
|
+
border-radius: 10px;
|
23
|
+
}
|
24
|
+
td.field {
|
25
|
+
padding-top: 20px;
|
26
|
+
}
|
27
|
+
td.field p {
|
28
|
+
font-weight: bold;
|
29
|
+
color: #444444;
|
30
|
+
font-size: 80%;
|
31
|
+
margin-bottom: 3px;
|
32
|
+
}
|
33
|
+
td.field input {
|
34
|
+
-webkit-border-radius: 2px;
|
35
|
+
border-radius: 2px;
|
36
|
+
border: solid 1px #444444;
|
37
|
+
padding: 3px 6px;
|
38
|
+
font-size: 110%;
|
39
|
+
width: 250px;
|
40
|
+
}
|
41
|
+
td.buttons {
|
42
|
+
padding-top: 25px;
|
43
|
+
padding-bottom: 20px;
|
44
|
+
text-align: right;
|
45
|
+
}
|
46
|
+
td.buttons input {
|
47
|
+
padding: 1px 6px;
|
48
|
+
font-weight: bold;
|
49
|
+
color: #444444;
|
50
|
+
}
|
51
|
+
</style>
|
52
|
+
</head>
|
53
|
+
<body>
|
54
|
+
<div id="content">
|
55
|
+
<form method="POST" id="loginForm" action="${request.route_url('login', _query=login_params)}">
|
56
|
+
<table style="margin-left: auto; margin-right: auto">
|
57
|
+
<tbody>
|
58
|
+
<tr>
|
59
|
+
<td class="field">
|
60
|
+
<p>
|
61
|
+
<label for="email">${_('Username')}</label>
|
62
|
+
</p>
|
63
|
+
<input id="login" name="login" type="text" />
|
64
|
+
</td>
|
65
|
+
</tr>
|
66
|
+
<tr>
|
67
|
+
<td class="field">
|
68
|
+
<p>
|
69
|
+
<label for="password">${_('Password')}</label>
|
70
|
+
</p>
|
71
|
+
<input id="password" name="password" type="password" />
|
72
|
+
</td>
|
73
|
+
</tr>
|
74
|
+
% if two_fa:
|
75
|
+
<tr>
|
76
|
+
<td class="field">
|
77
|
+
<p><label for="otp">${_('Authentication code')}</label></p>
|
78
|
+
<input id="otp" name="otp" type="text" autocomplete="off" />
|
79
|
+
</td>
|
80
|
+
</tr>
|
81
|
+
% endif
|
82
|
+
<tr>
|
83
|
+
<td class="buttons"><input tabindex="4" value="${_('Login')}" type="submit" /></td>
|
84
|
+
</tr>
|
85
|
+
</tbody>
|
86
|
+
</table>
|
87
|
+
</form>
|
88
|
+
</div>
|
89
|
+
</body>
|
90
|
+
</html>
|
@@ -0,0 +1,62 @@
|
|
1
|
+
<!doctype html>
|
2
|
+
<html lang="${lang}">
|
3
|
+
<head>
|
4
|
+
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
5
|
+
<meta name="Content-Language" content="${lang}" />
|
6
|
+
<title>${_('Login to Geoportal Application')}</title>
|
7
|
+
<style>
|
8
|
+
body {
|
9
|
+
background: #444444;
|
10
|
+
font-family: Helvetica, Arial, sans-serif;
|
11
|
+
}
|
12
|
+
* {
|
13
|
+
padding: 0;
|
14
|
+
margin: 0;
|
15
|
+
}
|
16
|
+
div#content {
|
17
|
+
background: #f5f5ef;
|
18
|
+
padding: 20px 30px;
|
19
|
+
width: 330px;
|
20
|
+
margin: 100px auto auto auto;
|
21
|
+
-webkit-border-radius: 10px;
|
22
|
+
border-radius: 10px;
|
23
|
+
}
|
24
|
+
td.field {
|
25
|
+
padding-top: 20px;
|
26
|
+
}
|
27
|
+
td.field p {
|
28
|
+
font-weight: bold;
|
29
|
+
color: #444444;
|
30
|
+
font-size: 80%;
|
31
|
+
margin-bottom: 3px;
|
32
|
+
}
|
33
|
+
td.field input {
|
34
|
+
-webkit-border-radius: 2px;
|
35
|
+
border-radius: 2px;
|
36
|
+
border: solid 1px #444444;
|
37
|
+
padding: 3px 6px;
|
38
|
+
font-size: 110%;
|
39
|
+
width: 250px;
|
40
|
+
}
|
41
|
+
td.buttons {
|
42
|
+
padding-top: 25px;
|
43
|
+
padding-bottom: 20px;
|
44
|
+
text-align: right;
|
45
|
+
}
|
46
|
+
td.buttons input {
|
47
|
+
padding: 1px 6px;
|
48
|
+
font-weight: bold;
|
49
|
+
color: #444444;
|
50
|
+
}
|
51
|
+
</style>
|
52
|
+
</head>
|
53
|
+
<body>
|
54
|
+
<div id="content">
|
55
|
+
<p>
|
56
|
+
${_('The user is not correctly initialized you should login in the main application and try '
|
57
|
+
'again.')}
|
58
|
+
</p>
|
59
|
+
<p><a href="${request.route_url('base')}">${_('Main application')}</a></p>
|
60
|
+
</div>
|
61
|
+
</body>
|
62
|
+
</html>
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
3
|
+
<html xmlns="http://www.w3.org/1999/xhtml">
|
4
|
+
<head>
|
5
|
+
<meta charset="UTF-8" />
|
6
|
+
<title>${title}</title>
|
7
|
+
</head>
|
8
|
+
<body>
|
9
|
+
<h1>${title}</h1>
|
10
|
+
<p>${_('my translation test')}</p>
|
11
|
+
</body>
|
12
|
+
</html>
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# Copyright (c) 2011-2023, Camptocamp SA
|
2
|
+
# All rights reserved.
|
3
|
+
|
4
|
+
# Redistribution and use in source and binary forms, with or without
|
5
|
+
# modification, are permitted provided that the following conditions are met:
|
6
|
+
|
7
|
+
# 1. Redistributions of source code must retain the above copyright notice, this
|
8
|
+
# list of conditions and the following disclaimer.
|
9
|
+
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
10
|
+
# this list of conditions and the following disclaimer in the documentation
|
11
|
+
# and/or other materials provided with the distribution.
|
12
|
+
|
13
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
14
|
+
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
15
|
+
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
16
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
17
|
+
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
18
|
+
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
19
|
+
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
20
|
+
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
21
|
+
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
22
|
+
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
23
|
+
|
24
|
+
# The views and conclusions contained in the software and documentation are those
|
25
|
+
# of the authors and should not be interpreted as representing official policies,
|
26
|
+
# either expressed or implied, of the FreeBSD Project.
|
27
|
+
|
28
|
+
|
29
|
+
import pyramid.config
|
30
|
+
import pyramid.request
|
31
|
+
from pyramid.httpexceptions import HTTPFound
|
32
|
+
|
33
|
+
|
34
|
+
def add_ending_slash(request: pyramid.request.Request) -> HTTPFound:
|
35
|
+
"""Add an ending slash view."""
|
36
|
+
return HTTPFound(location=request.path + "/")
|
37
|
+
|
38
|
+
|
39
|
+
def add_redirect(config: pyramid.config.Configurator, name: str, from_: str, to: str) -> None:
|
40
|
+
"""Add a redirect view."""
|
41
|
+
|
42
|
+
def redirect_view(request: pyramid.request.Request) -> HTTPFound:
|
43
|
+
return HTTPFound(location=request.route_url(to))
|
44
|
+
|
45
|
+
config.add_route(name, from_, request_method="GET")
|
46
|
+
config.add_view(redirect_view, route_name=name)
|
47
|
+
|
48
|
+
|
49
|
+
def restrict_headers(headers: dict[str, str], whitelist: list[str], blacklist: list[str]) -> dict[str, str]:
|
50
|
+
"""
|
51
|
+
Filter headers with a whitelist then a blacklist.
|
52
|
+
|
53
|
+
Some default pyramid headers will be added back by pyramid.
|
54
|
+
"""
|
55
|
+
if len(whitelist) > 0:
|
56
|
+
headers = {key: value for key, value in headers.items() if key in whitelist}
|
57
|
+
|
58
|
+
headers = {key: value for key, value in headers.items() if key not in blacklist}
|
59
|
+
return headers
|