c2cgeoportal-geoportal 2.6.0__py2.py3-none-any.whl → 2.8.1.180__py2.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 +245 -95
- c2cgeoportal_geoportal/lib/__init__.py +67 -43
- c2cgeoportal_geoportal/lib/authentication.py +50 -26
- c2cgeoportal_geoportal/lib/bashcolor.py +17 -13
- c2cgeoportal_geoportal/lib/cacheversion.py +16 -8
- c2cgeoportal_geoportal/lib/caching.py +65 -193
- c2cgeoportal_geoportal/lib/check_collector.py +17 -10
- c2cgeoportal_geoportal/lib/checker.py +67 -65
- c2cgeoportal_geoportal/lib/common_headers.py +167 -0
- c2cgeoportal_geoportal/lib/dbreflection.py +61 -46
- c2cgeoportal_geoportal/lib/filter_capabilities.py +126 -88
- c2cgeoportal_geoportal/lib/fulltextsearch.py +6 -5
- c2cgeoportal_geoportal/lib/functionality.py +20 -17
- c2cgeoportal_geoportal/lib/headers.py +14 -5
- c2cgeoportal_geoportal/lib/i18n.py +4 -4
- c2cgeoportal_geoportal/lib/layers.py +30 -11
- c2cgeoportal_geoportal/lib/lingua_extractor.py +363 -240
- c2cgeoportal_geoportal/lib/loader.py +11 -16
- c2cgeoportal_geoportal/lib/metrics.py +28 -17
- c2cgeoportal_geoportal/lib/oauth2.py +392 -206
- c2cgeoportal_geoportal/lib/wmstparsing.py +105 -84
- c2cgeoportal_geoportal/lib/xsd.py +26 -16
- c2cgeoportal_geoportal/resources.py +15 -9
- 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/{create/geoportal/+dot+prospector.yaml → advance_create/{{cookiecutter.project}}/geoportal/.prospector.yaml} +8 -2
- c2cgeoportal_geoportal/scaffolds/{create/geoportal/Dockerfile_tmpl → advance_create/{{cookiecutter.project}}/geoportal/Dockerfile} +22 -15
- c2cgeoportal_geoportal/scaffolds/{create/geoportal/alembic.yaml_tmpl → advance_create/{{cookiecutter.project}}/geoportal/alembic.yaml} +1 -1
- c2cgeoportal_geoportal/scaffolds/{create/geoportal/development.ini_tmpl → advance_create/{{cookiecutter.project}}/geoportal/development.ini} +34 -15
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/gunicorn.conf.py +100 -0
- c2cgeoportal_geoportal/scaffolds/{create → advance_create/{{cookiecutter.project}}}/geoportal/lingua-client.cfg +1 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/production.ini +38 -0
- c2cgeoportal_geoportal/scaffolds/{create/geoportal/setup.py_tmpl → advance_create/{{cookiecutter.project}}/geoportal/setup.py} +6 -7
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/tsconfig.json +8 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/webpack.api.js +77 -0
- c2cgeoportal_geoportal/scaffolds/{create/geoportal/webpack.apps.js_tmpl → advance_create/{{cookiecutter.project}}/geoportal/webpack.apps.js} +29 -28
- c2cgeoportal_geoportal/scaffolds/{create → advance_create/{{cookiecutter.project}}}/geoportal/webpack.commons.js +4 -7
- c2cgeoportal_geoportal/scaffolds/{create → advance_create/{{cookiecutter.project}}}/geoportal/webpack.config.js +1 -1
- 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/{create/geoportal/+package+_geoportal → advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal}/resources.py +4 -3
- c2cgeoportal_geoportal/scaffolds/{create/geoportal/+package+_geoportal/static-ngeo/api/index.js_tmpl → advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static-ngeo/api/index.js} +1 -2
- c2cgeoportal_geoportal/scaffolds/{create/geoportal/+package+_geoportal/static-ngeo/js/+package+module.js_tmpl → advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static-ngeo/js/{{cookiecutter.package}}module.js} +4 -4
- c2cgeoportal_geoportal/scaffolds/{create/geoportal/+package+_geoportal/subscribers.py_tmpl → advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/subscribers.py} +1 -3
- c2cgeoportal_geoportal/scaffolds/advance_update/cookiecutter.json +18 -0
- c2cgeoportal_geoportal/scaffolds/{update/geoportal/CONST_Makefile_tmpl → advance_update/{{cookiecutter.project}}/geoportal/CONST_Makefile} +3 -27
- c2cgeoportal_geoportal/scaffolds/create/cookiecutter.json +18 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.dockerignore +14 -0
- c2cgeoportal_geoportal/scaffolds/create/{+dot+editorconfig → {{cookiecutter.project}}/.editorconfig} +2 -5
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.github/workflows/main.yaml +57 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.github/workflows/rebuild.yaml +46 -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}}/.prettierignore +1 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.prettierrc.yaml +2 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/Dockerfile +76 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/Makefile +70 -0
- c2cgeoportal_geoportal/scaffolds/create/{README.rst_tmpl → {{cookiecutter.project}}/README.rst} +4 -4
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/build +186 -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 +1 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/docker-compose-db.yaml +26 -0
- c2cgeoportal_geoportal/scaffolds/create/{docker-compose-lib.yaml → {{cookiecutter.project}}/docker-compose-lib.yaml} +165 -22
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/docker-compose-qgis.yaml +23 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/docker-compose.override.sample.yaml +66 -0
- c2cgeoportal_geoportal/scaffolds/create/{docker-compose.yaml → {{cookiecutter.project}}/docker-compose.yaml} +20 -15
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/env.default +101 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/env.project +69 -0
- c2cgeoportal_geoportal/scaffolds/create/{geoportal/vars.yaml_tmpl → {{cookiecutter.project}}/geoportal/vars.yaml} +126 -36
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static/css/mobile.css +0 -0
- c2cgeoportal_geoportal/scaffolds/create/{mapserver → {{cookiecutter.project}}/mapserver}/data/Readme.txt +3 -3
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/demo.map.tmpl +224 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/mapserver.conf +15 -0
- c2cgeoportal_geoportal/scaffolds/create/{mapserver/mapserver.map.tmpl_tmpl → {{cookiecutter.project}}/mapserver/mapserver.map.tmpl} +9 -18
- c2cgeoportal_geoportal/scaffolds/create/{print/print-apps/+package+ → {{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}}/A3_Landscape.jrxml +13 -8
- c2cgeoportal_geoportal/scaffolds/create/{print/print-apps/+package+ → {{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}}/A3_Portrait.jrxml +13 -8
- c2cgeoportal_geoportal/scaffolds/create/{print/print-apps/+package+ → {{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}}/A4_Landscape.jrxml +13 -8
- c2cgeoportal_geoportal/scaffolds/create/{print/print-apps/+package+ → {{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}}/A4_Portrait.jrxml +13 -8
- c2cgeoportal_geoportal/scaffolds/create/{print/print-apps/+package+ → {{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}}/config.yaml.tmpl +11 -4
- 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/{project.yaml_tmpl → {{cookiecutter.project}}/project.yaml} +6 -6
- c2cgeoportal_geoportal/scaffolds/create/{pyproject.toml → {{cookiecutter.project}}/pyproject.toml} +4 -0
- c2cgeoportal_geoportal/scaffolds/create/{qgisserver/pg_service.conf.tmpl_tmpl → {{cookiecutter.project}}/qgisserver/pg_service.conf.tmpl} +2 -2
- c2cgeoportal_geoportal/scaffolds/create/{run_alembic.sh → {{cookiecutter.project}}/run_alembic.sh} +3 -5
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/scripts/db-backup +110 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/scripts/db-restore +114 -0
- c2cgeoportal_geoportal/scaffolds/create/{setup.cfg_tmpl → {{cookiecutter.project}}/setup.cfg} +1 -1
- 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 +38 -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 +61 -0
- c2cgeoportal_geoportal/scaffolds/update/{{cookiecutter.project}}/CONST_CHANGELOG.txt +273 -0
- c2cgeoportal_geoportal/scaffolds/update/{{cookiecutter.project}}/CONST_create_template/tests/test_testapp.py +48 -0
- c2cgeoportal_geoportal/scaffolds/update/{geoportal → {{cookiecutter.project}}/geoportal}/CONST_config-schema.yaml +64 -17
- c2cgeoportal_geoportal/scaffolds/update/{geoportal/CONST_vars.yaml_tmpl → {{cookiecutter.project}}/geoportal/CONST_vars.yaml} +396 -19
- c2cgeoportal_geoportal/scripts/__init__.py +16 -30
- c2cgeoportal_geoportal/scripts/c2cupgrade.py +272 -234
- c2cgeoportal_geoportal/scripts/create_demo_theme.py +3 -6
- c2cgeoportal_geoportal/scripts/manage_users.py +34 -39
- c2cgeoportal_geoportal/scripts/pcreate.py +310 -0
- c2cgeoportal_geoportal/scripts/theme2fts.py +128 -24
- c2cgeoportal_geoportal/scripts/urllogin.py +19 -11
- c2cgeoportal_geoportal/templates/login.html +88 -84
- c2cgeoportal_geoportal/templates/notlogin.html +59 -59
- c2cgeoportal_geoportal/templates/testi18n.html +6 -8
- c2cgeoportal_geoportal/views/__init__.py +23 -6
- c2cgeoportal_geoportal/views/dev.py +9 -7
- c2cgeoportal_geoportal/views/dynamic.py +56 -19
- c2cgeoportal_geoportal/views/entry.py +85 -24
- c2cgeoportal_geoportal/views/fulltextsearch.py +29 -23
- c2cgeoportal_geoportal/views/geometry_processing.py +17 -9
- c2cgeoportal_geoportal/views/i18n.py +91 -9
- c2cgeoportal_geoportal/views/layers.py +166 -133
- c2cgeoportal_geoportal/views/login.py +161 -93
- c2cgeoportal_geoportal/views/mapserverproxy.py +47 -31
- c2cgeoportal_geoportal/views/memory.py +12 -12
- c2cgeoportal_geoportal/views/ogcproxy.py +52 -30
- c2cgeoportal_geoportal/views/pdfreport.py +30 -26
- c2cgeoportal_geoportal/views/printproxy.py +60 -52
- c2cgeoportal_geoportal/views/profile.py +24 -23
- c2cgeoportal_geoportal/views/proxy.py +88 -72
- c2cgeoportal_geoportal/views/raster.py +37 -26
- c2cgeoportal_geoportal/views/resourceproxy.py +13 -11
- c2cgeoportal_geoportal/views/shortener.py +27 -25
- c2cgeoportal_geoportal/views/theme.py +472 -332
- c2cgeoportal_geoportal/views/tinyowsproxy.py +42 -44
- c2cgeoportal_geoportal/views/vector_tiles.py +80 -0
- {c2cgeoportal_geoportal-2.6.0.dist-info → c2cgeoportal_geoportal-2.8.1.180.dist-info}/METADATA +19 -8
- c2cgeoportal_geoportal-2.8.1.180.dist-info/RECORD +191 -0
- {c2cgeoportal_geoportal-2.6.0.dist-info → c2cgeoportal_geoportal-2.8.1.180.dist-info}/WHEEL +1 -1
- {c2cgeoportal_geoportal-2.6.0.dist-info → c2cgeoportal_geoportal-2.8.1.180.dist-info}/entry_points.txt +3 -0
- tests/__init__.py +10 -5
- tests/test_cachebuster.py +3 -5
- tests/test_caching.py +18 -26
- tests/test_checker.py +1 -3
- tests/test_decimaljson.py +5 -5
- tests/test_headerstween.py +1 -3
- tests/test_i18n.py +2 -2
- tests/test_init.py +16 -20
- tests/test_locale_negociator.py +4 -6
- tests/test_mapserverproxy_route_predicate.py +1 -4
- tests/test_raster.py +15 -17
- tests/test_wmstparsing.py +10 -12
- tests/xmlstr.py +1 -3
- c2cgeoportal_geoportal/scaffolds/__init__.py +0 -227
- c2cgeoportal_geoportal/scaffolds/create/+dot+dockerignore_tmpl +0 -12
- c2cgeoportal_geoportal/scaffolds/create/+dot+github/workflows/main.yaml_tmpl +0 -89
- c2cgeoportal_geoportal/scaffolds/create/+dot+github/workflows/rebuild.yaml_tmpl +0 -78
- c2cgeoportal_geoportal/scaffolds/create/+dot+gitignore_tmpl +0 -16
- c2cgeoportal_geoportal/scaffolds/create/Dockerfile_tmpl +0 -67
- c2cgeoportal_geoportal/scaffolds/create/Makefile +0 -3
- c2cgeoportal_geoportal/scaffolds/create/build_tmpl +0 -167
- c2cgeoportal_geoportal/scaffolds/create/ci/config.yaml_tmpl +0 -23
- c2cgeoportal_geoportal/scaffolds/create/ci/requirements.txt +0 -1
- c2cgeoportal_geoportal/scaffolds/create/ci/trigger +0 -68
- c2cgeoportal_geoportal/scaffolds/create/docker-compose.override.sample.yaml +0 -54
- c2cgeoportal_geoportal/scaffolds/create/env.default_tmpl +0 -67
- c2cgeoportal_geoportal/scaffolds/create/env.project_tmpl +0 -48
- c2cgeoportal_geoportal/scaffolds/create/geoportal/+dot+dockerignore_tmpl +0 -6
- c2cgeoportal_geoportal/scaffolds/create/geoportal/+dot+eslintrc_tmpl +0 -15
- c2cgeoportal_geoportal/scaffolds/create/geoportal/+package+_geoportal/__init__.py_tmpl +0 -58
- c2cgeoportal_geoportal/scaffolds/create/geoportal/+package+_geoportal/models.py_tmpl +0 -10
- c2cgeoportal_geoportal/scaffolds/create/geoportal/+package+_geoportal/static/robot.txt +0 -3
- c2cgeoportal_geoportal/scaffolds/create/geoportal/production.ini_tmpl +0 -106
- c2cgeoportal_geoportal/scaffolds/create/geoportal/tools/extract-messages.js +0 -39
- c2cgeoportal_geoportal/scaffolds/create/geoportal/tsconfig.json_tmpl +0 -9
- c2cgeoportal_geoportal/scaffolds/create/geoportal/webpack.api.js_tmpl +0 -72
- c2cgeoportal_geoportal/scaffolds/create/mapserver/demo.map.tmpl_tmpl +0 -262
- c2cgeoportal_geoportal/scaffolds/create/mapserver/tinyows.xml +0 -36
- c2cgeoportal_geoportal/scaffolds/create/print/print-apps/+package+/config.yaml +0 -168
- c2cgeoportal_geoportal/scaffolds/create/qgisserver/geomapfish.yaml.tmpl_tmpl +0 -16
- c2cgeoportal_geoportal/scaffolds/create/spell-ignore-words.txt +0 -1
- c2cgeoportal_geoportal/scaffolds/create/tilegeneration/config.yaml.tmpl_tmpl +0 -185
- c2cgeoportal_geoportal/scaffolds/create/yamllint.yaml +0 -11
- c2cgeoportal_geoportal/scaffolds/update/+dot+upgrade.yaml_tmpl +0 -181
- c2cgeoportal_geoportal/scaffolds/update/CONST_CHANGELOG.txt_tmpl +0 -454
- c2cgeoportal_geoportal/templates/dynamic.js +0 -21
- c2cgeoportal_geoportal-2.6.0.dist-info/RECORD +0 -173
- /c2cgeoportal_geoportal/{scaffolds/create/geoportal/+package+_geoportal/static/css/desktop.css → py.typed} +0 -0
- /c2cgeoportal_geoportal/scaffolds/{create/geoportal/Makefile_tmpl → advance_create/{{cookiecutter.project}}/geoportal/Makefile} +0 -0
- /c2cgeoportal_geoportal/scaffolds/{create → advance_create/{{cookiecutter.project}}}/geoportal/alembic.ini +0 -0
- /c2cgeoportal_geoportal/scaffolds/{create → advance_create/{{cookiecutter.project}}}/geoportal/language_mapping +0 -0
- /c2cgeoportal_geoportal/scaffolds/{create → advance_create/{{cookiecutter.project}}}/geoportal/lingua-server.cfg +0 -0
- /c2cgeoportal_geoportal/scaffolds/{create → advance_create/{{cookiecutter.project}}}/geoportal/requirements.txt +0 -0
- /c2cgeoportal_geoportal/scaffolds/{create/geoportal/+package+_geoportal → advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal}/views/__init__.py +0 -0
- /c2cgeoportal_geoportal/scaffolds/create/{geoportal/+package+_geoportal/locale/en/LC_MESSAGES/+package+_geoportal-client.po → {{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/locale/en/LC_MESSAGES/{{cookiecutter.package}}_geoportal-client.po} +0 -0
- /c2cgeoportal_geoportal/scaffolds/create/{geoportal/+package+_geoportal/static/css/iframe_api.css → {{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static/css/desktop.css} +0 -0
- /c2cgeoportal_geoportal/scaffolds/create/{geoportal/+package+_geoportal/static/css/mobile.css → {{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static/css/iframe_api.css} +0 -0
- /c2cgeoportal_geoportal/scaffolds/create/{geoportal/+package+_geoportal → {{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal}/static/images/banner_left.png +0 -0
- /c2cgeoportal_geoportal/scaffolds/create/{geoportal/+package+_geoportal → {{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal}/static/images/banner_right.png +0 -0
- /c2cgeoportal_geoportal/scaffolds/create/{geoportal/+package+_geoportal → {{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal}/static/images/blank.png +0 -0
- /c2cgeoportal_geoportal/scaffolds/create/{geoportal/+package+_geoportal → {{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal}/static/images/markers/marker-blue.png +0 -0
- /c2cgeoportal_geoportal/scaffolds/create/{geoportal/+package+_geoportal → {{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal}/static/images/markers/marker-gold.png +0 -0
- /c2cgeoportal_geoportal/scaffolds/create/{geoportal/+package+_geoportal → {{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal}/static/images/markers/marker-green.png +0 -0
- /c2cgeoportal_geoportal/scaffolds/create/{geoportal/+package+_geoportal → {{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal}/static/images/markers/marker.png +0 -0
- /c2cgeoportal_geoportal/scaffolds/create/{geoportal/+package+_geoportal → {{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal}/static/robot.txt.tmpl +0 -0
- /c2cgeoportal_geoportal/scaffolds/create/{mapserver → {{cookiecutter.project}}/mapserver}/data/TM_EUROPE_BORDERS-0.3.sql +0 -0
- /c2cgeoportal_geoportal/scaffolds/create/{mapserver → {{cookiecutter.project}}/mapserver}/fonts/Arial.ttf +0 -0
- /c2cgeoportal_geoportal/scaffolds/create/{mapserver → {{cookiecutter.project}}/mapserver}/fonts/Arialbd.ttf +0 -0
- /c2cgeoportal_geoportal/scaffolds/create/{mapserver → {{cookiecutter.project}}/mapserver}/fonts/Arialbi.ttf +0 -0
- /c2cgeoportal_geoportal/scaffolds/create/{mapserver → {{cookiecutter.project}}/mapserver}/fonts/Ariali.ttf +0 -0
- /c2cgeoportal_geoportal/scaffolds/create/{mapserver → {{cookiecutter.project}}/mapserver}/fonts/NotoSans-Bold.ttf +0 -0
- /c2cgeoportal_geoportal/scaffolds/create/{mapserver → {{cookiecutter.project}}/mapserver}/fonts/NotoSans-BoldItalic.ttf +0 -0
- /c2cgeoportal_geoportal/scaffolds/create/{mapserver → {{cookiecutter.project}}/mapserver}/fonts/NotoSans-Italic.ttf +0 -0
- /c2cgeoportal_geoportal/scaffolds/create/{mapserver → {{cookiecutter.project}}/mapserver}/fonts/NotoSans-Regular.ttf +0 -0
- /c2cgeoportal_geoportal/scaffolds/create/{mapserver → {{cookiecutter.project}}/mapserver}/fonts/Verdana.ttf +0 -0
- /c2cgeoportal_geoportal/scaffolds/create/{mapserver → {{cookiecutter.project}}/mapserver}/fonts/Verdanab.ttf +0 -0
- /c2cgeoportal_geoportal/scaffolds/create/{mapserver → {{cookiecutter.project}}/mapserver}/fonts/Verdanai.ttf +0 -0
- /c2cgeoportal_geoportal/scaffolds/create/{mapserver → {{cookiecutter.project}}/mapserver}/fonts/Verdanaz.ttf +0 -0
- /c2cgeoportal_geoportal/scaffolds/create/{mapserver → {{cookiecutter.project}}/mapserver}/fonts.conf +0 -0
- /c2cgeoportal_geoportal/scaffolds/create/{mapserver → {{cookiecutter.project}}/mapserver}/tinyows.xml.tmpl +0 -0
- /c2cgeoportal_geoportal/scaffolds/create/{print/print-apps/+package+ → {{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}}/legend.jrxml +0 -0
- /c2cgeoportal_geoportal/scaffolds/create/{print/print-apps/+package+ → {{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}}/logo.png +0 -0
- /c2cgeoportal_geoportal/scaffolds/create/{print/print-apps/+package+ → {{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}}/north.svg +0 -0
- /c2cgeoportal_geoportal/scaffolds/create/{print/print-apps/+package+ → {{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}}/results.jrxml +0 -0
- {c2cgeoportal_geoportal-2.6.0.dist-info → c2cgeoportal_geoportal-2.8.1.180.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,4 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
# Copyright (c) 2011-2021, Camptocamp SA
|
1
|
+
# Copyright (c) 2011-2024, Camptocamp SA
|
4
2
|
# All rights reserved.
|
5
3
|
|
6
4
|
# Redistribution and use in source and binary forms, with or without
|
@@ -32,10 +30,13 @@ import datetime
|
|
32
30
|
import ipaddress
|
33
31
|
import json
|
34
32
|
import logging
|
33
|
+
import re
|
35
34
|
from string import Formatter
|
36
|
-
from typing import Any, Dict, List, Set, Union
|
35
|
+
from typing import Any, Dict, Iterable, List, Optional, Set, Tuple, Union, cast
|
37
36
|
|
38
37
|
import dateutil
|
38
|
+
import pyramid.request
|
39
|
+
import pyramid.response
|
39
40
|
from pyramid.interfaces import IRoutePregenerator
|
40
41
|
from zope.interface import implementer
|
41
42
|
|
@@ -48,18 +49,25 @@ CACHE_REGION = get_region("std")
|
|
48
49
|
CACHE_REGION_OBJ = get_region("obj")
|
49
50
|
|
50
51
|
|
51
|
-
def get_types_map(types_array):
|
52
|
+
def get_types_map(types_array: List[Dict[str, Any]]) -> Dict[str, Dict[str, Any]]:
|
53
|
+
"""Get the type name of a metadata or a functionality."""
|
52
54
|
return {type_["name"]: type_ for type_ in types_array}
|
53
55
|
|
54
56
|
|
55
57
|
def get_typed(
|
56
|
-
name
|
58
|
+
name: str,
|
59
|
+
value: str,
|
60
|
+
types: Dict[str, Any],
|
61
|
+
request: pyramid.request.Request,
|
62
|
+
errors: Set[str],
|
63
|
+
layer_name: Optional[str] = None,
|
57
64
|
) -> Union[str, int, float, bool, None, List[Any], Dict[str, Any]]:
|
58
|
-
|
65
|
+
"""Get the typed (parsed) value of a metadata or a functionality."""
|
66
|
+
prefix = f"Layer '{layer_name}': " if layer_name is not None else ""
|
59
67
|
type_ = {"type": "not init"}
|
60
68
|
try:
|
61
69
|
if name not in types:
|
62
|
-
errors.add("{}Type '{}' not defined."
|
70
|
+
errors.add(f"{prefix}Type '{name}' not defined.")
|
63
71
|
return None
|
64
72
|
type_ = types[name]
|
65
73
|
if type_.get("type", "string") == "string":
|
@@ -73,8 +81,8 @@ def get_typed(
|
|
73
81
|
if value in ["no", "n", "off", "0", "false"]:
|
74
82
|
return False
|
75
83
|
errors.add(
|
76
|
-
"{}The boolean attribute '{}'='{}' is not in "
|
77
|
-
"[yes, y, on, 1, true, no, n, off, 0, false]."
|
84
|
+
f"{prefix}The boolean attribute '{name}'='{value.lower()}' is not in "
|
85
|
+
"[yes, y, on, 1, true, no, n, off, 0, false]."
|
78
86
|
)
|
79
87
|
elif type_["type"] == "integer":
|
80
88
|
return int(value)
|
@@ -83,43 +91,47 @@ def get_typed(
|
|
83
91
|
elif type_["type"] == "date":
|
84
92
|
date = dateutil.parser.parse(value, default=datetime.datetime(1, 1, 1, 0, 0, 0)) # type: ignore
|
85
93
|
if date.time() != datetime.time(0, 0, 0):
|
86
|
-
errors.add(
|
87
|
-
"{}The date attribute '{}'='{}' should not have any time".format(prefix, name, value)
|
88
|
-
)
|
94
|
+
errors.add(f"{prefix}The date attribute '{name}'='{value}' should not have any time")
|
89
95
|
else:
|
90
96
|
return datetime.date.strftime(date.date(), "%Y-%m-%d")
|
91
97
|
elif type_["type"] == "time":
|
92
98
|
date = dateutil.parser.parse(value, default=datetime.datetime(1, 1, 1, 0, 0, 0)) # type: ignore
|
93
99
|
if date.date() != datetime.date(1, 1, 1):
|
94
|
-
errors.add(
|
95
|
-
"{}The time attribute '{}'='{}' should not have any date".format(prefix, name, value)
|
96
|
-
)
|
100
|
+
errors.add(f"{prefix}The time attribute '{name}'='{value}' should not have any date")
|
97
101
|
else:
|
98
102
|
return datetime.time.strftime(date.time(), "%H:%M:%S")
|
99
103
|
elif type_["type"] == "datetime":
|
100
104
|
date = dateutil.parser.parse(value, default=datetime.datetime(1, 1, 1, 0, 0, 0)) # type: ignore
|
101
105
|
return datetime.datetime.strftime(date, "%Y-%m-%dT%H:%M:%S")
|
102
106
|
elif type_["type"] == "url":
|
103
|
-
|
107
|
+
url = get_url2(f"{prefix}The attribute '{name}'", value, request, errors)
|
108
|
+
return url.url() if url else ""
|
104
109
|
elif type_["type"] == "json":
|
105
110
|
try:
|
106
|
-
return json.loads(value)
|
111
|
+
return cast(Dict[str, Any], json.loads(value))
|
107
112
|
except Exception as e:
|
108
|
-
errors.
|
109
|
-
|
113
|
+
errors.add(f"{prefix}The attribute '{name}'='{value}' has an error: {str(e)}")
|
114
|
+
elif type_["type"] == "regex":
|
115
|
+
pattern = type_["regex"]
|
116
|
+
if re.match(pattern, value) is None:
|
117
|
+
errors.add(
|
118
|
+
f"{prefix}The regex attribute '{name}'='{value}' "
|
119
|
+
f"does not match expected pattern '{pattern}'."
|
110
120
|
)
|
121
|
+
else:
|
122
|
+
return value
|
111
123
|
else:
|
112
|
-
errors.add("{}Unknown type '{}'."
|
124
|
+
errors.add(f"{prefix}Unknown type '{type_['type']}'.")
|
113
125
|
except Exception as e:
|
114
126
|
errors.add(
|
115
|
-
"{}Unable to parse the attribute '{}'='{}' with the type
|
116
|
-
|
117
|
-
)
|
127
|
+
f"{prefix}Unable to parse the attribute '{name}'='{value}' with the type "
|
128
|
+
f"'{type_.get('type', 'string')}', error:\n{e!s}"
|
118
129
|
)
|
119
130
|
return None
|
120
131
|
|
121
132
|
|
122
|
-
def get_setting(settings, path, default=None):
|
133
|
+
def get_setting(settings: Any, path: Iterable[str], default: Any = None) -> Any:
|
134
|
+
"""Get the settings."""
|
123
135
|
value = settings
|
124
136
|
for p in path:
|
125
137
|
if value and p in value:
|
@@ -129,42 +141,48 @@ def get_setting(settings, path, default=None):
|
|
129
141
|
return value if value else default
|
130
142
|
|
131
143
|
|
132
|
-
@CACHE_REGION_OBJ.cache_on_arguments()
|
133
|
-
def get_ogc_server_wms_url_ids(request):
|
144
|
+
@CACHE_REGION_OBJ.cache_on_arguments() # type: ignore
|
145
|
+
def get_ogc_server_wms_url_ids(request: pyramid.request.Request, host: str) -> Dict[str, List[int]]:
|
146
|
+
"""Get the OGCServer ids mapped on the WMS URL."""
|
134
147
|
from c2cgeoportal_commons.models import DBSession # pylint: disable=import-outside-toplevel
|
135
148
|
from c2cgeoportal_commons.models.main import OGCServer # pylint: disable=import-outside-toplevel
|
136
149
|
|
150
|
+
del host # used for cache
|
137
151
|
errors: Set[str] = set()
|
138
152
|
servers: Dict[str, List[int]] = {}
|
139
153
|
for ogc_server in DBSession.query(OGCServer).all():
|
140
154
|
url = get_url2(ogc_server.name, ogc_server.url, request, errors)
|
141
155
|
if url is not None:
|
142
|
-
servers.setdefault(url, []).append(ogc_server.id)
|
156
|
+
servers.setdefault(url.url(), []).append(ogc_server.id)
|
143
157
|
return servers
|
144
158
|
|
145
159
|
|
146
|
-
@CACHE_REGION_OBJ.cache_on_arguments()
|
147
|
-
def get_ogc_server_wfs_url_ids(request):
|
160
|
+
@CACHE_REGION_OBJ.cache_on_arguments() # type: ignore
|
161
|
+
def get_ogc_server_wfs_url_ids(request: pyramid.request.Request, host: str) -> Dict[str, List[int]]:
|
162
|
+
"""Get the OGCServer ids mapped on the WFS URL."""
|
148
163
|
from c2cgeoportal_commons.models import DBSession # pylint: disable=import-outside-toplevel
|
149
164
|
from c2cgeoportal_commons.models.main import OGCServer # pylint: disable=import-outside-toplevel
|
150
165
|
|
166
|
+
del host # used for cache
|
151
167
|
errors: Set[str] = set()
|
152
168
|
servers: Dict[str, List[int]] = {}
|
153
169
|
for ogc_server in DBSession.query(OGCServer).all():
|
154
170
|
url = get_url2(ogc_server.name, ogc_server.url_wfs or ogc_server.url, request, errors)
|
155
171
|
if url is not None:
|
156
|
-
servers.setdefault(url, []).append(ogc_server.id)
|
172
|
+
servers.setdefault(url.url(), []).append(ogc_server.id)
|
157
173
|
return servers
|
158
174
|
|
159
175
|
|
160
176
|
@implementer(IRoutePregenerator)
|
161
|
-
class C2CPregenerator:
|
162
|
-
|
177
|
+
class C2CPregenerator:
|
178
|
+
"""The custom pyramid pregenerator that manage the cache version."""
|
179
|
+
|
180
|
+
def __init__(self, version: bool = True, role: bool = False):
|
163
181
|
self.version = version
|
164
182
|
self.role = role
|
165
183
|
|
166
|
-
def __call__(self, request, elements, kw):
|
167
|
-
query = kw.get("_query", {})
|
184
|
+
def __call__(self, request: pyramid.request.Request, elements: Any, kw: Any) -> Tuple[Any, Any]:
|
185
|
+
query = {**kw.get("_query", {})}
|
168
186
|
|
169
187
|
if self.version:
|
170
188
|
query["cache_version"] = get_cache_version()
|
@@ -182,22 +200,26 @@ class C2CPregenerator: # pragma: no cover
|
|
182
200
|
_formatter = Formatter()
|
183
201
|
|
184
202
|
|
185
|
-
@CACHE_REGION_OBJ.cache_on_arguments()
|
186
|
-
def _get_intranet_networks(
|
203
|
+
@CACHE_REGION_OBJ.cache_on_arguments() # type: ignore
|
204
|
+
def _get_intranet_networks(
|
205
|
+
request: pyramid.request.Request,
|
206
|
+
) -> List[Union[ipaddress.IPv4Network, ipaddress.IPv6Network]]:
|
187
207
|
return [
|
188
208
|
ipaddress.ip_network(network, strict=False)
|
189
209
|
for network in request.registry.settings.get("intranet", {}).get("networks", [])
|
190
210
|
]
|
191
211
|
|
192
212
|
|
193
|
-
@CACHE_REGION.cache_on_arguments()
|
194
|
-
def get_role_id(name):
|
213
|
+
@CACHE_REGION.cache_on_arguments() # type: ignore
|
214
|
+
def get_role_id(name: str) -> int:
|
215
|
+
"""Get the role ID."""
|
195
216
|
from c2cgeoportal_commons.models import DBSession, main # pylint: disable=import-outside-toplevel
|
196
217
|
|
197
|
-
return DBSession.query(main.Role.id).filter(main.Role.name == name).one()[0]
|
218
|
+
return cast(int, DBSession.query(main.Role.id).filter(main.Role.name == name).one()[0])
|
198
219
|
|
199
220
|
|
200
|
-
def get_roles_id(request):
|
221
|
+
def get_roles_id(request: pyramid.request.Request) -> List[int]:
|
222
|
+
"""Get the user roles ID."""
|
201
223
|
result = [get_role_id(request.get_organization_role("anonymous"))]
|
202
224
|
if is_intranet(request):
|
203
225
|
result.append(get_role_id(request.get_organization_role("intranet")))
|
@@ -207,7 +229,8 @@ def get_roles_id(request):
|
|
207
229
|
return result
|
208
230
|
|
209
231
|
|
210
|
-
def get_roles_name(request):
|
232
|
+
def get_roles_name(request: pyramid.request.Request) -> pyramid.response.Response:
|
233
|
+
"""Get the user roles name."""
|
211
234
|
result = [request.get_organization_role("anonymous")]
|
212
235
|
if is_intranet(request):
|
213
236
|
result.append(request.get_organization_role("intranet"))
|
@@ -217,7 +240,8 @@ def get_roles_name(request):
|
|
217
240
|
return result
|
218
241
|
|
219
242
|
|
220
|
-
def is_intranet(request):
|
243
|
+
def is_intranet(request: pyramid.request.Request) -> bool:
|
244
|
+
"""Get if it's an intranet user."""
|
221
245
|
address = ipaddress.ip_address(request.client_addr)
|
222
246
|
for network in _get_intranet_networks(request):
|
223
247
|
if address in network:
|
@@ -1,6 +1,4 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
# Copyright (c) 2014-2021, Camptocamp SA
|
1
|
+
# Copyright (c) 2014-2023, Camptocamp SA
|
4
2
|
# All rights reserved.
|
5
3
|
|
6
4
|
# Redistribution and use in source and binary forms, with or without
|
@@ -31,8 +29,11 @@
|
|
31
29
|
import binascii
|
32
30
|
import json
|
33
31
|
import logging
|
32
|
+
import os
|
34
33
|
import time
|
34
|
+
from typing import Any, Callable, Dict, List, Optional, cast
|
35
35
|
|
36
|
+
import pyramid.request
|
36
37
|
from Crypto.Cipher import AES # nosec
|
37
38
|
from pyramid.authentication import (
|
38
39
|
AuthTktAuthenticationPolicy,
|
@@ -51,13 +52,17 @@ LOG = logging.getLogger(__name__)
|
|
51
52
|
|
52
53
|
|
53
54
|
@implementer(IAuthenticationPolicy)
|
54
|
-
class UrlAuthenticationPolicy(CallbackAuthenticationPolicy):
|
55
|
-
|
55
|
+
class UrlAuthenticationPolicy(CallbackAuthenticationPolicy): # type: ignore
|
56
|
+
"""An authentication policy based on information given in the URL."""
|
57
|
+
|
58
|
+
def __init__(
|
59
|
+
self, aes_key: str, callback: Optional[Callable[[str, Any], List[str]]] = None, debug: bool = False
|
60
|
+
):
|
56
61
|
self.aeskey = aes_key
|
57
62
|
self.callback = callback
|
58
63
|
self.debug = debug
|
59
64
|
|
60
|
-
def unauthenticated_userid(self, request):
|
65
|
+
def unauthenticated_userid(self, request: pyramid.request.Request) -> Optional[str]:
|
61
66
|
if not request.method == "GET" or "auth" not in request.params:
|
62
67
|
return None
|
63
68
|
auth_enc = request.params.get("auth")
|
@@ -65,14 +70,14 @@ class UrlAuthenticationPolicy(CallbackAuthenticationPolicy):
|
|
65
70
|
return None
|
66
71
|
try:
|
67
72
|
if self.aeskey is None: # pragma: nocover
|
68
|
-
raise Exception("urllogin is not configured")
|
73
|
+
raise Exception("urllogin is not configured") # pylint: disable=broad-exception-raised
|
69
74
|
now = int(time.time())
|
70
75
|
data = binascii.unhexlify(auth_enc.encode("ascii"))
|
71
76
|
nonce = data[0:16]
|
72
77
|
tag = data[16:32]
|
73
78
|
ciphertext = data[32:]
|
74
79
|
cipher = AES.new(self.aeskey.encode("ascii"), AES.MODE_EAX, nonce)
|
75
|
-
auth = json.loads(cipher.decrypt_and_verify(ciphertext, tag).decode("utf-8"))
|
80
|
+
auth = json.loads(cipher.decrypt_and_verify(ciphertext, tag).decode("utf-8"))
|
76
81
|
|
77
82
|
if "t" in auth and "u" in auth and "p" in auth:
|
78
83
|
timestamp = int(auth["t"])
|
@@ -80,33 +85,35 @@ class UrlAuthenticationPolicy(CallbackAuthenticationPolicy):
|
|
80
85
|
if now < timestamp and request.registry.validate_user(request, auth["u"], auth["p"]):
|
81
86
|
headers = remember(request, auth["u"])
|
82
87
|
request.response.headerlist.extend(headers)
|
83
|
-
return auth["u"]
|
88
|
+
return cast(str, auth["u"])
|
84
89
|
|
85
90
|
except Exception as e:
|
86
91
|
LOG.error("URL login error: %s.", e, exc_info=True)
|
87
92
|
|
88
93
|
return None
|
89
94
|
|
90
|
-
def remember(self, request, userid, **kw
|
91
|
-
"""
|
95
|
+
def remember(self, request: pyramid.request.Request, userid: str, **kw: Any) -> List[Dict[str, str]]:
|
96
|
+
"""Do no-op."""
|
92
97
|
del request, userid, kw
|
93
98
|
return []
|
94
99
|
|
95
|
-
def forget(self, request
|
96
|
-
"""
|
100
|
+
def forget(self, request: pyramid.request.Request) -> List[Dict[str, str]]:
|
101
|
+
"""Do no-op."""
|
97
102
|
del request
|
98
103
|
return []
|
99
104
|
|
100
105
|
|
101
106
|
@implementer(IAuthenticationPolicy)
|
102
|
-
class OAuth2AuthenticationPolicy(CallbackAuthenticationPolicy):
|
107
|
+
class OAuth2AuthenticationPolicy(CallbackAuthenticationPolicy): # type: ignore
|
108
|
+
"""The oauth2 authentication policy."""
|
109
|
+
|
103
110
|
@staticmethod
|
104
|
-
def unauthenticated_userid(request):
|
111
|
+
def unauthenticated_userid(request: pyramid.request.Request) -> Optional[str]:
|
105
112
|
route_url = ""
|
106
113
|
try:
|
107
|
-
route_url = request.current_route_url(_query=request.GET)
|
114
|
+
route_url = request.current_route_url(_query={**request.GET})
|
108
115
|
except ValueError:
|
109
|
-
route_url = request.route_url("base", _query=request.GET)
|
116
|
+
route_url = request.route_url("base", _query={**request.GET})
|
110
117
|
|
111
118
|
LOG.debug(
|
112
119
|
"Call OAuth verify_request with:\nurl: %s\nmethod: %s\nbody:\n%s",
|
@@ -125,21 +132,33 @@ class OAuth2AuthenticationPolicy(CallbackAuthenticationPolicy):
|
|
125
132
|
if valid:
|
126
133
|
request.user_ = oauth2_request.user
|
127
134
|
|
128
|
-
return request.
|
135
|
+
return cast(str, request.user.username)
|
129
136
|
return None
|
130
137
|
|
131
|
-
def remember(self, request, userid, **kw
|
132
|
-
"""
|
138
|
+
def remember(self, request: pyramid.request.Request, userid: str, **kw: Any) -> List[Dict[str, str]]:
|
139
|
+
"""Do no-op."""
|
133
140
|
del request, userid, kw
|
134
141
|
return []
|
135
142
|
|
136
|
-
def forget(self, request
|
137
|
-
"""
|
143
|
+
def forget(self, request: pyramid.request.Request) -> List[Dict[str, str]]:
|
144
|
+
"""Do no-op."""
|
138
145
|
del request
|
139
146
|
return []
|
140
147
|
|
141
148
|
|
142
|
-
|
149
|
+
@implementer(IAuthenticationPolicy)
|
150
|
+
class DevAuthenticationPolicy(CallbackAuthenticationPolicy): # type: ignore
|
151
|
+
"""An authentication policy for the dev base on an environment variable."""
|
152
|
+
|
153
|
+
@staticmethod
|
154
|
+
def unauthenticated_userid(request: pyramid.request.Request) -> Optional[str]:
|
155
|
+
"""Get the user name from the environment variable."""
|
156
|
+
del request
|
157
|
+
return os.environ["DEV_LOGINNAME"]
|
158
|
+
|
159
|
+
|
160
|
+
def create_authentication(settings: Dict[str, Any]) -> MultiAuthenticationPolicy:
|
161
|
+
"""Create all the authentication policies."""
|
143
162
|
timeout = settings.get("authtkt_timeout")
|
144
163
|
timeout = None if timeout is None or timeout.lower() == "none" else int(timeout)
|
145
164
|
reissue_time = settings.get("authtkt_reissue_time")
|
@@ -154,7 +173,7 @@ def create_authentication(settings):
|
|
154
173
|
secret = settings["authtkt_secret"]
|
155
174
|
basicauth = settings.get("basicauth", "False").lower() in ("true", "yes", "1")
|
156
175
|
if len(secret) < 64:
|
157
|
-
raise Exception(
|
176
|
+
raise Exception( # pylint: disable=broad-exception-raised
|
158
177
|
'"authtkt_secret should be at least 64 characters.'
|
159
178
|
"See https://docs.pylonsproject.org/projects/pyramid/en/latest/api/session.html"
|
160
179
|
)
|
@@ -188,17 +207,22 @@ def create_authentication(settings):
|
|
188
207
|
if basicauth:
|
189
208
|
if settings["authentication"].get("two_factor", False):
|
190
209
|
LOG.warning(
|
191
|
-
"Basic auth and
|
210
|
+
"Basic auth and two factor auth should not be enable together, "
|
192
211
|
"you should use OAuth2 instead of Basic auth"
|
193
212
|
)
|
194
213
|
|
195
214
|
basic_authentication_policy = BasicAuthAuthenticationPolicy(c2cgeoportal_check)
|
196
215
|
policies.append(basic_authentication_policy)
|
197
216
|
|
217
|
+
# Consider empty string as not configured
|
218
|
+
if "DEV_LOGINNAME" in os.environ and os.environ["DEV_LOGINNAME"]:
|
219
|
+
policies.append(DevAuthenticationPolicy())
|
220
|
+
|
198
221
|
return MultiAuthenticationPolicy(policies)
|
199
222
|
|
200
223
|
|
201
|
-
def c2cgeoportal_check(username, password, request
|
224
|
+
def c2cgeoportal_check(username: str, password: str, request: pyramid.request.Request) -> Optional[List[str]]:
|
225
|
+
"""Check the user authentication."""
|
202
226
|
if request.registry.validate_user(request, username, password):
|
203
227
|
return defaultgroupsfinder(username, request)
|
204
228
|
return None
|
@@ -1,6 +1,4 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
# Copyright (c) 2013-2020, Camptocamp SA
|
1
|
+
# Copyright (c) 2013-2021, Camptocamp SA
|
4
2
|
# All rights reserved.
|
5
3
|
|
6
4
|
# Redistribution and use in source and binary forms, with or without
|
@@ -27,16 +25,22 @@
|
|
27
25
|
# of the authors and should not be interpreted as representing official policies,
|
28
26
|
# either expressed or implied, of the FreeBSD Project.
|
29
27
|
|
28
|
+
from enum import Enum
|
29
|
+
|
30
|
+
|
31
|
+
class Color(Enum):
|
32
|
+
"""The available colors."""
|
30
33
|
|
31
|
-
BLACK = 0
|
32
|
-
RED = 1
|
33
|
-
GREEN = 2
|
34
|
-
YELLOW = 3
|
35
|
-
BLUE = 4
|
36
|
-
MAGENTA = 5
|
37
|
-
CYAN = 6
|
38
|
-
WHITE = 7
|
34
|
+
BLACK = 0
|
35
|
+
RED = 1
|
36
|
+
GREEN = 2
|
37
|
+
YELLOW = 3
|
38
|
+
BLUE = 4
|
39
|
+
MAGENTA = 5
|
40
|
+
CYAN = 6
|
41
|
+
WHITE = 7
|
39
42
|
|
40
43
|
|
41
|
-
def colorize(text, color
|
42
|
-
|
44
|
+
def colorize(text: str, color: Color) -> str:
|
45
|
+
"""Colorize a text for the bash."""
|
46
|
+
return f"\x1b[01;3{color.value}m{text}\x1b[0m"
|
@@ -1,5 +1,3 @@
|
|
1
|
-
# -*- coding: utf-8 -*-
|
2
|
-
|
3
1
|
# Copyright (c) 2011-2021, Camptocamp SA
|
4
2
|
# All rights reserved.
|
5
3
|
|
@@ -29,22 +27,28 @@
|
|
29
27
|
|
30
28
|
|
31
29
|
import uuid
|
30
|
+
from typing import Any, Callable, Dict, Tuple
|
32
31
|
from urllib.parse import urljoin
|
33
32
|
|
34
33
|
import pyramid.registry
|
34
|
+
import pyramid.request
|
35
|
+
import pyramid.response
|
35
36
|
|
36
37
|
from c2cgeoportal_geoportal.lib.caching import get_region
|
37
38
|
|
38
39
|
CACHE_REGION = get_region("std")
|
39
40
|
|
40
41
|
|
41
|
-
@CACHE_REGION.cache_on_arguments()
|
42
|
-
def get_cache_version():
|
43
|
-
"""Return a cache version that is regenerate after each cache invalidation"""
|
42
|
+
@CACHE_REGION.cache_on_arguments() # type: ignore
|
43
|
+
def get_cache_version() -> str:
|
44
|
+
"""Return a cache version that is regenerate after each cache invalidation."""
|
44
45
|
return uuid.uuid4().hex
|
45
46
|
|
46
47
|
|
47
|
-
def version_cache_buster(
|
48
|
+
def version_cache_buster(
|
49
|
+
request: pyramid.request.Request, subpath: str, kw: Dict[str, Any]
|
50
|
+
) -> Tuple[str, Dict[str, Any]]:
|
51
|
+
"""Join the cash buster version with the sub path."""
|
48
52
|
del request # unused
|
49
53
|
return urljoin(get_cache_version() + "/", subpath), kw
|
50
54
|
|
@@ -52,11 +56,15 @@ def version_cache_buster(request, subpath, kw): # pragma: no cover
|
|
52
56
|
class CachebusterTween:
|
53
57
|
"""Get back the cachebuster URL."""
|
54
58
|
|
55
|
-
def __init__(
|
59
|
+
def __init__(
|
60
|
+
self,
|
61
|
+
handler: Callable[[pyramid.request.Request], pyramid.response.Response],
|
62
|
+
registry: pyramid.registry.Registry,
|
63
|
+
):
|
56
64
|
self.handler = handler
|
57
65
|
self.cache_path = registry.settings["cache_path"]
|
58
66
|
|
59
|
-
def __call__(self, request):
|
67
|
+
def __call__(self, request: pyramid.request.Request) -> pyramid.response.Response:
|
60
68
|
path = request.path_info.split("/")
|
61
69
|
if len(path) > 1 and path[1] in self.cache_path:
|
62
70
|
# remove the cache buster
|