c2cgeoportal-geoportal 2.6.0__py2.py3-none-any.whl → 2.7.1.86__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 +224 -84
- c2cgeoportal_geoportal/lib/__init__.py +64 -42
- c2cgeoportal_geoportal/lib/authentication.py +50 -22
- c2cgeoportal_geoportal/lib/bashcolor.py +17 -13
- c2cgeoportal_geoportal/lib/cacheversion.py +16 -8
- c2cgeoportal_geoportal/lib/caching.py +61 -191
- c2cgeoportal_geoportal/lib/check_collector.py +17 -10
- c2cgeoportal_geoportal/lib/checker.py +61 -63
- c2cgeoportal_geoportal/lib/common_headers.py +170 -0
- c2cgeoportal_geoportal/lib/dbreflection.py +54 -39
- c2cgeoportal_geoportal/lib/filter_capabilities.py +119 -87
- 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 +361 -237
- c2cgeoportal_geoportal/lib/loader.py +10 -15
- c2cgeoportal_geoportal/lib/metrics.py +28 -17
- c2cgeoportal_geoportal/lib/oauth2.py +214 -145
- c2cgeoportal_geoportal/lib/wmstparsing.py +115 -90
- 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} +18 -9
- 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 +104 -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/advance_create/{{cookiecutter.project}}/geoportal/requirements.txt +2 -0
- c2cgeoportal_geoportal/scaffolds/{create/geoportal/setup.py_tmpl → advance_create/{{cookiecutter.project}}/geoportal/setup.py} +6 -7
- c2cgeoportal_geoportal/scaffolds/{create → advance_create/{{cookiecutter.project}}}/geoportal/tools/extract-messages.js +8 -6
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/tsconfig.json +8 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/webpack.api.js +75 -0
- c2cgeoportal_geoportal/scaffolds/{create/geoportal/webpack.apps.js_tmpl → advance_create/{{cookiecutter.project}}/geoportal/webpack.apps.js} +31 -28
- c2cgeoportal_geoportal/scaffolds/{create → advance_create/{{cookiecutter.project}}}/geoportal/webpack.commons.js +3 -7
- c2cgeoportal_geoportal/scaffolds/{create → advance_create/{{cookiecutter.project}}}/geoportal/webpack.config.js +1 -1
- c2cgeoportal_geoportal/scaffolds/{create/geoportal/+package+_geoportal/__init__.py_tmpl → advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/__init__.py} +11 -22
- 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 -7
- 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 +43 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.github/workflows/rebuild.yaml +46 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.github/workflows/update_l10n.yaml +65 -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/{Dockerfile_tmpl → {{cookiecutter.project}}/Dockerfile} +20 -11
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/Makefile +14 -0
- c2cgeoportal_geoportal/scaffolds/create/{README.rst_tmpl → {{cookiecutter.project}}/README.rst} +4 -4
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/build +158 -0
- c2cgeoportal_geoportal/scaffolds/create/{ci/config.yaml_tmpl → {{cookiecutter.project}}/ci/config.yaml} +7 -5
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/ci/requirements.txt +1 -0
- c2cgeoportal_geoportal/scaffolds/create/{docker-compose-lib.yaml → {{cookiecutter.project}}/docker-compose-lib.yaml} +133 -17
- 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} +17 -12
- c2cgeoportal_geoportal/scaffolds/create/{env.default_tmpl → {{cookiecutter.project}}/env.default} +29 -14
- c2cgeoportal_geoportal/scaffolds/create/{env.project_tmpl → {{cookiecutter.project}}/env.project} +16 -4
- c2cgeoportal_geoportal/scaffolds/create/{geoportal/vars.yaml_tmpl → {{cookiecutter.project}}/geoportal/vars.yaml} +93 -27
- 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 +1 -1
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/demo.map.tmpl +224 -0
- c2cgeoportal_geoportal/scaffolds/create/{mapserver/mapserver.map.tmpl_tmpl → {{cookiecutter.project}}/mapserver/mapserver.map.tmpl} +7 -15
- c2cgeoportal_geoportal/scaffolds/create/{print/print-apps/+package+ → {{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}}/A3_Landscape.jrxml +8 -8
- c2cgeoportal_geoportal/scaffolds/create/{print/print-apps/+package+ → {{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}}/A3_Portrait.jrxml +8 -8
- c2cgeoportal_geoportal/scaffolds/create/{print/print-apps/+package+ → {{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}}/A4_Landscape.jrxml +8 -8
- c2cgeoportal_geoportal/scaffolds/create/{print/print-apps/+package+ → {{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}}/A4_Portrait.jrxml +8 -8
- c2cgeoportal_geoportal/scaffolds/create/{print/print-apps/+package+ → {{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}}/config.yaml.tmpl +5 -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/{qgisserver/pg_service.conf.tmpl_tmpl → {{cookiecutter.project}}/qgisserver/pg_service.conf.tmpl} +2 -2
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/scripts/db-backup +107 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/scripts/db-restore +111 -0
- c2cgeoportal_geoportal/scaffolds/create/{setup.cfg_tmpl → {{cookiecutter.project}}/setup.cfg} +1 -1
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/spell-ignore-words.txt +3 -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/{+dot+upgrade.yaml_tmpl → {{cookiecutter.project}}/.upgrade.yaml} +49 -39
- c2cgeoportal_geoportal/scaffolds/update/{{cookiecutter.project}}/CONST_CHANGELOG.txt +1153 -0
- c2cgeoportal_geoportal/scaffolds/update/{geoportal → {{cookiecutter.project}}/geoportal}/CONST_config-schema.yaml +47 -2
- c2cgeoportal_geoportal/scaffolds/update/{geoportal/CONST_vars.yaml_tmpl → {{cookiecutter.project}}/geoportal/CONST_vars.yaml} +350 -15
- c2cgeoportal_geoportal/scripts/__init__.py +15 -31
- c2cgeoportal_geoportal/scripts/c2cupgrade.py +271 -232
- c2cgeoportal_geoportal/scripts/create_demo_theme.py +3 -6
- c2cgeoportal_geoportal/scripts/manage_users.py +34 -39
- c2cgeoportal_geoportal/scripts/pcreate.py +312 -0
- c2cgeoportal_geoportal/scripts/theme2fts.py +72 -23
- c2cgeoportal_geoportal/scripts/urllogin.py +17 -9
- 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 -4
- c2cgeoportal_geoportal/views/dev.py +9 -7
- c2cgeoportal_geoportal/views/dynamic.py +54 -18
- c2cgeoportal_geoportal/views/entry.py +93 -24
- c2cgeoportal_geoportal/views/fulltextsearch.py +28 -22
- c2cgeoportal_geoportal/views/geometry_processing.py +15 -7
- c2cgeoportal_geoportal/views/i18n.py +91 -9
- c2cgeoportal_geoportal/views/layers.py +160 -126
- c2cgeoportal_geoportal/views/login.py +106 -93
- c2cgeoportal_geoportal/views/mapserverproxy.py +45 -28
- c2cgeoportal_geoportal/views/memory.py +12 -12
- c2cgeoportal_geoportal/views/ogcproxy.py +48 -30
- c2cgeoportal_geoportal/views/pdfreport.py +26 -22
- c2cgeoportal_geoportal/views/printproxy.py +56 -50
- c2cgeoportal_geoportal/views/profile.py +24 -23
- c2cgeoportal_geoportal/views/proxy.py +84 -67
- c2cgeoportal_geoportal/views/raster.py +35 -24
- c2cgeoportal_geoportal/views/resourceproxy.py +13 -11
- c2cgeoportal_geoportal/views/shortener.py +27 -24
- c2cgeoportal_geoportal/views/theme.py +427 -321
- c2cgeoportal_geoportal/views/tinyowsproxy.py +46 -39
- c2cgeoportal_geoportal/views/vector_tiles.py +80 -0
- {c2cgeoportal_geoportal-2.6.0.dist-info → c2cgeoportal_geoportal-2.7.1.86.dist-info}/METADATA +24 -20
- c2cgeoportal_geoportal-2.7.1.86.dist-info/RECORD +185 -0
- {c2cgeoportal_geoportal-2.6.0.dist-info → c2cgeoportal_geoportal-2.7.1.86.dist-info}/WHEEL +1 -1
- {c2cgeoportal_geoportal-2.6.0.dist-info → c2cgeoportal_geoportal-2.7.1.86.dist-info}/entry_points.txt +3 -1
- tests/__init__.py +7 -3
- tests/test_cachebuster.py +0 -2
- tests/test_caching.py +17 -25
- tests/test_checker.py +0 -2
- tests/test_decimaljson.py +4 -4
- tests/test_headerstween.py +0 -2
- tests/test_i18n.py +1 -1
- tests/test_init.py +4 -7
- tests/test_locale_negociator.py +0 -2
- tests/test_mapserverproxy_route_predicate.py +0 -2
- tests/test_raster.py +0 -2
- tests/test_wmstparsing.py +0 -2
- 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/Makefile +0 -3
- c2cgeoportal_geoportal/scaffolds/create/build_tmpl +0 -167
- 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/geoportal/+dot+dockerignore_tmpl +0 -6
- c2cgeoportal_geoportal/scaffolds/create/geoportal/+dot+eslintrc_tmpl +0 -15
- 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/requirements.txt +0 -2
- 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/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/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/scaffolds/create/{pyproject.toml → {{cookiecutter.project}}/pyproject.toml} +0 -0
- /c2cgeoportal_geoportal/scaffolds/create/{run_alembic.sh → {{cookiecutter.project}}/run_alembic.sh} +0 -0
- {c2cgeoportal_geoportal-2.6.0.dist-info → c2cgeoportal_geoportal-2.7.1.86.dist-info}/top_level.txt +0 -0
@@ -1,5 +1,3 @@
|
|
1
|
-
# -*- coding: utf-8 -*-
|
2
|
-
|
3
1
|
# Copyright (c) 2011-2021, Camptocamp SA
|
4
2
|
# All rights reserved.
|
5
3
|
|
@@ -32,17 +30,21 @@ import logging
|
|
32
30
|
import os
|
33
31
|
import subprocess
|
34
32
|
from time import sleep
|
35
|
-
from typing import Dict
|
33
|
+
from typing import Any, Dict, List, Mapping, Optional, Union, cast
|
36
34
|
from urllib.parse import urljoin
|
37
35
|
|
38
36
|
import c2cwsgiutils.health_check
|
37
|
+
import pyramid.config
|
38
|
+
import pyramid.request
|
39
39
|
import requests
|
40
40
|
|
41
41
|
LOG = logging.getLogger(__name__)
|
42
42
|
|
43
43
|
|
44
|
-
def build_url(
|
45
|
-
|
44
|
+
def build_url(
|
45
|
+
name: str, path: str, request: pyramid.request.Request, headers: Optional[Dict[str, str]] = None
|
46
|
+
) -> Dict[str, Union[str, Dict[str, str]]]:
|
47
|
+
"""Build an URL and headers for the checkers."""
|
46
48
|
base_internal_url = request.registry.settings["checker"]["base_internal_url"]
|
47
49
|
url = urljoin(base_internal_url, path)
|
48
50
|
|
@@ -55,7 +57,9 @@ def build_url(name, path, request, headers=None):
|
|
55
57
|
return {"url": url, "headers": headers}
|
56
58
|
|
57
59
|
|
58
|
-
def _build_headers(
|
60
|
+
def _build_headers(
|
61
|
+
request: pyramid.request.Request, headers: Optional[Dict[str, str]] = None
|
62
|
+
) -> Dict[str, str]:
|
59
63
|
if headers is None:
|
60
64
|
headers = {}
|
61
65
|
headers["Cache-Control"] = "no-cache"
|
@@ -67,45 +71,43 @@ def _build_headers(request, headers=None):
|
|
67
71
|
return headers
|
68
72
|
|
69
73
|
|
70
|
-
def _routes(settings, health_check):
|
74
|
+
def _routes(settings: Dict[str, Any], health_check: c2cwsgiutils.health_check.HealthCheck) -> None:
|
71
75
|
routes_settings = settings["routes"]
|
72
76
|
for route in routes_settings["routes"]:
|
73
77
|
if route.get("checker_name", route["name"]) not in routes_settings["disable"]:
|
74
78
|
name = "checker_routes_" + route.get("checker_name", route["name"])
|
75
79
|
|
76
80
|
class GetRequest:
|
77
|
-
"""
|
78
|
-
Get the request information about the current route name
|
79
|
-
"""
|
81
|
+
"""Get the request information about the current route name."""
|
80
82
|
|
81
|
-
def __init__(self, route_name, type_):
|
83
|
+
def __init__(self, route_name: str, type_: str) -> None:
|
82
84
|
self.route_name = route_name
|
83
85
|
self.type = type_
|
84
86
|
|
85
|
-
def __call__(self, request):
|
87
|
+
def __call__(self, request: pyramid.request.Request) -> Union[str, Dict[str, str]]:
|
86
88
|
return build_url("route", request.route_path(self.route_name), request)[self.type]
|
87
89
|
|
88
90
|
health_check.add_url_check(
|
89
|
-
url=GetRequest(route["name"], "url"),
|
91
|
+
url=GetRequest(route["name"], "url"), # type: ignore
|
90
92
|
name=name,
|
91
93
|
params=route.get("params", None),
|
92
|
-
headers=GetRequest(route["name"], "headers"),
|
94
|
+
headers=GetRequest(route["name"], "headers"), # type: ignore
|
93
95
|
level=route["level"],
|
94
96
|
timeout=30,
|
95
97
|
)
|
96
98
|
|
97
99
|
|
98
|
-
def _pdf3(settings, health_check):
|
100
|
+
def _pdf3(settings: Dict[str, Any], health_check: c2cwsgiutils.health_check.HealthCheck) -> None:
|
99
101
|
print_settings = settings["print"]
|
100
102
|
if "spec" not in print_settings:
|
101
103
|
return
|
102
104
|
|
103
|
-
def check(request):
|
105
|
+
def check(request: pyramid.request.Request) -> None:
|
104
106
|
path = request.route_path("printproxy_report_create", format="pdf")
|
105
107
|
url_headers = build_url("Check the printproxy request (create)", path, request)
|
106
108
|
|
107
109
|
session = requests.session()
|
108
|
-
resp = session.post(json=print_settings["spec"], timeout=30, **url_headers)
|
110
|
+
resp = session.post(json=print_settings["spec"], timeout=30, **url_headers) # type: ignore
|
109
111
|
resp.raise_for_status()
|
110
112
|
|
111
113
|
job = resp.json()
|
@@ -115,44 +117,44 @@ def _pdf3(settings, health_check):
|
|
115
117
|
done = False
|
116
118
|
while not done:
|
117
119
|
sleep(1)
|
118
|
-
resp = session.get(timeout=30, **url_headers)
|
120
|
+
resp = session.get(timeout=30, **url_headers) # type: ignore
|
119
121
|
resp.raise_for_status()
|
120
122
|
|
121
123
|
status = resp.json()
|
122
124
|
if "error" in status:
|
123
|
-
raise Exception("Failed to do the printing: {
|
125
|
+
raise Exception(f"Failed to do the printing: {status['error']}")
|
124
126
|
done = status["done"]
|
125
127
|
|
126
128
|
path = request.route_path("printproxy_report_get", ref=job["ref"])
|
127
129
|
url_headers = build_url("Check the printproxy pdf retrieve", path, request)
|
128
|
-
resp = session.get(timeout=30, **url_headers)
|
130
|
+
resp = session.get(timeout=30, **url_headers) # type: ignore
|
129
131
|
resp.raise_for_status()
|
130
132
|
|
131
133
|
health_check.add_custom_check(name="checker_print", check_cb=check, level=print_settings["level"])
|
132
134
|
|
133
135
|
|
134
|
-
def _fts(settings, health_check):
|
136
|
+
def _fts(settings: Dict[str, Any], health_check: c2cwsgiutils.health_check.HealthCheck) -> None:
|
135
137
|
fts_settings = settings["fulltextsearch"]
|
136
138
|
if fts_settings.get("disable", False):
|
137
139
|
return
|
138
140
|
|
139
|
-
def get_both(request):
|
141
|
+
def get_both(request: pyramid.request.Request) -> Dict[str, Union[str, Dict[str, str]]]:
|
140
142
|
return build_url("Check the fulltextsearch", request.route_path("fulltextsearch"), request)
|
141
143
|
|
142
|
-
def check(_request, response):
|
144
|
+
def check(_request: pyramid.request.Request, response: pyramid.response.Response) -> None:
|
143
145
|
assert response.json()["features"], "No result"
|
144
146
|
|
145
147
|
health_check.add_url_check(
|
146
148
|
name="checker_fulltextsearch",
|
147
|
-
url=lambda r: get_both(r)["url"],
|
148
|
-
headers=lambda r: get_both(r)["headers"],
|
149
|
+
url=lambda r: get_both(r)["url"], # type: ignore
|
150
|
+
headers=lambda r: get_both(r)["headers"], # type: ignore
|
149
151
|
params={"query": fts_settings["search"], "limit": "1"},
|
150
152
|
check_cb=check,
|
151
153
|
level=fts_settings["level"],
|
152
154
|
)
|
153
155
|
|
154
156
|
|
155
|
-
def _themes_errors(settings, health_check):
|
157
|
+
def _themes_errors(settings: Dict[str, Any], health_check: c2cwsgiutils.health_check.HealthCheck) -> None:
|
156
158
|
from c2cgeoportal_commons.models import DBSession # pylint: disable=import-outside-toplevel
|
157
159
|
from c2cgeoportal_commons.models.main import Interface # pylint: disable=import-outside-toplevel
|
158
160
|
|
@@ -160,7 +162,7 @@ def _themes_errors(settings, health_check):
|
|
160
162
|
default_params = themes_settings.get("params", {})
|
161
163
|
interfaces_settings = themes_settings["interfaces"]
|
162
164
|
|
163
|
-
def check(request):
|
165
|
+
def check(request: pyramid.request.Request) -> None:
|
164
166
|
path = request.route_path("themes")
|
165
167
|
session = requests.session()
|
166
168
|
for (interface,) in DBSession.query(Interface.name).all():
|
@@ -171,52 +173,51 @@ def _themes_errors(settings, health_check):
|
|
171
173
|
|
172
174
|
interface_url_headers = build_url("checker_themes " + interface, path, request)
|
173
175
|
|
174
|
-
response = session.get(params=params, timeout=120, **interface_url_headers)
|
176
|
+
response = session.get(params=params, timeout=120, **interface_url_headers) # type: ignore
|
175
177
|
response.raise_for_status()
|
176
178
|
|
177
179
|
result = response.json()
|
178
180
|
if result["errors"]:
|
179
181
|
raise c2cwsgiutils.health_check.JsonCheckException(
|
180
|
-
"Interface '{}' has error in Theme."
|
182
|
+
f"Interface '{interface}' has error in Theme.", result["errors"]
|
181
183
|
)
|
182
184
|
|
183
185
|
health_check.add_custom_check(name="checker_themes", check_cb=check, level=themes_settings["level"])
|
184
186
|
|
185
187
|
|
186
|
-
def _lang_files(
|
188
|
+
def _lang_files(
|
189
|
+
global_settings: Dict[str, Any],
|
190
|
+
settings: Dict[str, Any],
|
191
|
+
health_check: c2cwsgiutils.health_check.HealthCheck,
|
192
|
+
) -> None:
|
187
193
|
lang_settings = settings["lang"]
|
188
194
|
available_locale_names = global_settings["available_locale_names"]
|
189
195
|
|
190
196
|
default_name = global_settings["default_locale_name"]
|
191
|
-
assert (
|
192
|
-
default_name in available_locale_names
|
193
|
-
|
194
|
-
default_name, ", ".join(available_locale_names)
|
197
|
+
assert default_name in available_locale_names, (
|
198
|
+
f"default_locale_name '{default_name}' not in available_locale_names: "
|
199
|
+
f"{', '.join(available_locale_names)}"
|
195
200
|
)
|
196
201
|
|
197
202
|
for type_ in lang_settings.get("files", []):
|
198
203
|
for lang in available_locale_names:
|
199
204
|
if type_ == "ngeo":
|
200
|
-
url = "/etc/geomapfish/static/{lang}.json"
|
205
|
+
url = f"/etc/geomapfish/static/{lang}.json"
|
201
206
|
else:
|
202
|
-
raise Exception(
|
203
|
-
"Your language type value '%s' is not valid, " "available values [ngeo]" % type_
|
204
|
-
)
|
207
|
+
raise Exception(f"Your language type value '{type_}' is not valid, available values [ngeo]")
|
205
208
|
|
206
|
-
name = "checker_lang_{}_{}"
|
209
|
+
name = f"checker_lang_{type_}_{lang}"
|
207
210
|
|
208
211
|
class GetRequest:
|
209
|
-
"""
|
210
|
-
Get the request information about the current route name
|
211
|
-
"""
|
212
|
+
"""Get the request information about the current route name."""
|
212
213
|
|
213
|
-
def __init__(self, name, url, lang, type_):
|
214
|
+
def __init__(self, name: str, url: str, lang: str, type_: str) -> None:
|
214
215
|
self.name = name
|
215
216
|
self.url = url
|
216
217
|
self.lang = lang
|
217
218
|
self.type = type_
|
218
219
|
|
219
|
-
def __call__(self, request):
|
220
|
+
def __call__(self, request: pyramid.request.Request) -> Union[str, Mapping[str, str]]:
|
220
221
|
return build_url(
|
221
222
|
self.name,
|
222
223
|
request.static_path(
|
@@ -227,27 +228,27 @@ def _lang_files(global_settings, settings, health_check):
|
|
227
228
|
|
228
229
|
health_check.add_url_check(
|
229
230
|
name=name,
|
230
|
-
url=GetRequest(name, url, lang, "url"),
|
231
|
-
headers=GetRequest(name, url, lang, "headers"),
|
231
|
+
url=GetRequest(name, url, lang, "url"), # type: ignore
|
232
|
+
headers=GetRequest(name, url, lang, "headers"), # type: ignore
|
232
233
|
level=lang_settings["level"],
|
233
234
|
)
|
234
235
|
|
235
236
|
|
236
|
-
def _phantomjs(settings, health_check):
|
237
|
+
def _phantomjs(settings: Dict[str, Any], health_check: c2cwsgiutils.health_check.HealthCheck) -> None:
|
237
238
|
phantomjs_settings = settings["phantomjs"]
|
238
239
|
for route in phantomjs_settings["routes"]:
|
239
240
|
if route.get("checker_name", route["name"]) in phantomjs_settings["disable"]:
|
240
241
|
continue
|
241
242
|
|
242
243
|
class _Check:
|
243
|
-
def __init__(self, route):
|
244
|
+
def __init__(self, route: Dict[str, Any]) -> None:
|
244
245
|
self.route = route
|
245
246
|
|
246
|
-
def __call__(self, request):
|
247
|
+
def __call__(self, request: pyramid.request.Request) -> None:
|
247
248
|
path = request.route_path(self.route["name"], _query=self.route.get("params", {}))
|
248
|
-
url = build_url("Check", path, request)["url"]
|
249
|
+
url: str = cast(str, build_url("Check", path, request)["url"])
|
249
250
|
|
250
|
-
cmd = ["node", "/usr/bin/check-example.js", url]
|
251
|
+
cmd: List[str] = ["node", "/usr/bin/check-example.js", url]
|
251
252
|
env = dict(os.environ)
|
252
253
|
for name, value in self.route.get("environment", {}).items():
|
253
254
|
if isinstance(value, (list, dict)):
|
@@ -260,26 +261,23 @@ def _phantomjs(settings, health_check):
|
|
260
261
|
subprocess.check_output(cmd, env=env, timeout=70)
|
261
262
|
except subprocess.CalledProcessError as exception:
|
262
263
|
raise Exception(
|
263
|
-
"{} exit with code: {}\n
|
264
|
-
|
265
|
-
|
266
|
-
)
|
264
|
+
f"{' '.join(exception.cmd)} exit with code: {exception.returncode}\n"
|
265
|
+
f"{exception.output.decode('utf-8')[:10000]}"
|
266
|
+
) from exception
|
267
267
|
except subprocess.TimeoutExpired as exception:
|
268
268
|
raise Exception(
|
269
|
-
"""Timeout:
|
270
|
-
command: {}
|
269
|
+
f"""Timeout:
|
270
|
+
command: {' '.join(exception.cmd)}
|
271
271
|
output:
|
272
|
-
{}"""
|
273
|
-
|
274
|
-
)
|
275
|
-
)
|
272
|
+
{exception.output.decode('utf-8')}"""
|
273
|
+
) from exception
|
276
274
|
|
277
275
|
name = "checker_phantomjs_" + route.get("checker_name", route["name"])
|
278
276
|
health_check.add_custom_check(name=name, check_cb=_Check(route), level=route["level"])
|
279
277
|
|
280
278
|
|
281
|
-
def init(config, health_check):
|
282
|
-
"""
|
279
|
+
def init(config: pyramid.config.Configurator, health_check: c2cwsgiutils.health_check.HealthCheck) -> None:
|
280
|
+
"""Initialize the checkers."""
|
283
281
|
global_settings = config.get_settings()
|
284
282
|
if "checker" not in global_settings:
|
285
283
|
return
|
@@ -0,0 +1,170 @@
|
|
1
|
+
# Copyright (c) 2012-2021, 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 logging
|
30
|
+
from enum import Enum
|
31
|
+
from typing import Any, Dict, List, Optional, cast
|
32
|
+
|
33
|
+
import pyramid.request
|
34
|
+
import pyramid.response
|
35
|
+
|
36
|
+
from c2cgeoportal_geoportal.lib import is_intranet
|
37
|
+
|
38
|
+
_LOG = logging.getLogger(__name__)
|
39
|
+
|
40
|
+
|
41
|
+
class Cache(Enum):
|
42
|
+
"""Enumeration for the possible cache values."""
|
43
|
+
|
44
|
+
# For responses that do not depend on authentication
|
45
|
+
PUBLIC = 0
|
46
|
+
# For responses that do not depends on authentication
|
47
|
+
# We use a small cache (e.g. 10s) instead of no cache to protect the service against too high traffic.
|
48
|
+
PUBLIC_NO = 1
|
49
|
+
# For responses that can depend on authentication
|
50
|
+
PRIVATE = 2
|
51
|
+
# See PUBLIC_NO and PRIVATE
|
52
|
+
PRIVATE_NO = 3
|
53
|
+
|
54
|
+
|
55
|
+
CORS_METHODS = "HEAD, GET, POST, PUT, DELETE"
|
56
|
+
|
57
|
+
|
58
|
+
def _set_cors_headers(
|
59
|
+
request: pyramid.request.Request,
|
60
|
+
response: pyramid.response.Response,
|
61
|
+
service_name: str,
|
62
|
+
service_headers_settings: Dict[str, Any],
|
63
|
+
credentials: bool,
|
64
|
+
) -> None:
|
65
|
+
"""Handle CORS requests, as specified in https://www.w3.org/TR/cors/."""
|
66
|
+
response.vary = (response.vary or ()) + ("Origin",)
|
67
|
+
|
68
|
+
if "Origin" not in request.headers:
|
69
|
+
return # Not a CORS request if this header is missing
|
70
|
+
origin = request.headers["Origin"]
|
71
|
+
|
72
|
+
if request.method == "OPTIONS" and "Access-Control-Request-Method" not in request.headers:
|
73
|
+
_LOG.warning("CORS preflight query missing the Access-Control-Request-Method header")
|
74
|
+
return
|
75
|
+
|
76
|
+
allowed_origins = cast(List[str], service_headers_settings.get("access_control_allow_origin", []))
|
77
|
+
if origin not in allowed_origins:
|
78
|
+
if "*" in allowed_origins:
|
79
|
+
origin = "*"
|
80
|
+
credentials = False # Force no credentials
|
81
|
+
else:
|
82
|
+
_LOG.warning("CORS query not allowed for origin=%s, service=%s", origin, service_name)
|
83
|
+
return
|
84
|
+
|
85
|
+
response.headers.update(
|
86
|
+
{"Access-Control-Allow-Origin": origin, "Access-Control-Allow-Methods": CORS_METHODS}
|
87
|
+
)
|
88
|
+
|
89
|
+
max_age = service_headers_settings.get("access_control_max_age", 3600)
|
90
|
+
response.headers["Access-Control-Max-Age"] = str(max_age)
|
91
|
+
|
92
|
+
if credentials:
|
93
|
+
response.headers["Access-Control-Allow-Credentials"] = "true"
|
94
|
+
|
95
|
+
if request.method != "OPTIONS":
|
96
|
+
return
|
97
|
+
|
98
|
+
response.cache_control.max_age = max_age
|
99
|
+
|
100
|
+
if not service_headers_settings or "access_control_allow_origin" not in service_headers_settings:
|
101
|
+
_LOG.warning("CORS query not configured for service=%s", service_name)
|
102
|
+
return
|
103
|
+
|
104
|
+
requested_headers = request.headers.get("Access-Control-Request-Headers", False)
|
105
|
+
if requested_headers:
|
106
|
+
# For the moment, we allow all requested headers
|
107
|
+
response.headers["Access-Control-Allow-Headers"] = requested_headers
|
108
|
+
|
109
|
+
# If we start using headers in responses, we'll have to add
|
110
|
+
# Access-Control-Expose-Headers
|
111
|
+
|
112
|
+
|
113
|
+
def _set_common_headers(
|
114
|
+
request: pyramid.request.Request,
|
115
|
+
response: pyramid.response.Response,
|
116
|
+
service_headers_settings: Dict[str, Dict[str, str]],
|
117
|
+
cache: Cache,
|
118
|
+
content_type: Optional[str],
|
119
|
+
) -> pyramid.response.Response:
|
120
|
+
"""Set the common headers."""
|
121
|
+
|
122
|
+
response.headers.update(service_headers_settings.get("headers", {}))
|
123
|
+
|
124
|
+
if cache in (Cache.PRIVATE, Cache.PRIVATE_NO):
|
125
|
+
response.vary = (response.vary or ()) + ("Cookie",)
|
126
|
+
|
127
|
+
maxage = (
|
128
|
+
service_headers_settings.get("cache_control_max_age", 3600)
|
129
|
+
if cache in (Cache.PUBLIC, Cache.PRIVATE)
|
130
|
+
else service_headers_settings.get("cache_control_max_age_nocache", 10)
|
131
|
+
)
|
132
|
+
response.cache_control.max_age = maxage
|
133
|
+
if maxage == 0:
|
134
|
+
response.cache_control.no_cache = True
|
135
|
+
response.cache_control.no_store = True
|
136
|
+
elif cache in (Cache.PUBLIC, Cache.PUBLIC_NO):
|
137
|
+
response.cache_control.public = True
|
138
|
+
elif cache in (Cache.PRIVATE, Cache.PRIVATE_NO):
|
139
|
+
if hasattr(request, "user") and request.user is not None or is_intranet(request):
|
140
|
+
response.cache_control.private = True
|
141
|
+
else:
|
142
|
+
response.cache_control.public = True
|
143
|
+
else:
|
144
|
+
raise Exception("Invalid cache type")
|
145
|
+
|
146
|
+
if content_type is not None:
|
147
|
+
response.content_type = content_type
|
148
|
+
|
149
|
+
return response
|
150
|
+
|
151
|
+
|
152
|
+
def set_common_headers(
|
153
|
+
request: pyramid.request.Request,
|
154
|
+
service_name: str,
|
155
|
+
cache: Cache,
|
156
|
+
response: pyramid.response.Response = None,
|
157
|
+
credentials: bool = True,
|
158
|
+
content_type: Optional[str] = None,
|
159
|
+
) -> pyramid.response.Response:
|
160
|
+
"""Set the common headers."""
|
161
|
+
if response is None:
|
162
|
+
response = request.response
|
163
|
+
|
164
|
+
headers_settings = request.registry.settings.get("headers", {})
|
165
|
+
service_headers_settings = headers_settings.get(service_name, {})
|
166
|
+
|
167
|
+
_set_cors_headers(request, response, service_name, service_headers_settings, credentials)
|
168
|
+
if request.method == "OPTIONS":
|
169
|
+
return response
|
170
|
+
return _set_common_headers(request, response, service_headers_settings, cache, content_type)
|
@@ -1,5 +1,3 @@
|
|
1
|
-
# -*- coding: utf-8 -*-
|
2
|
-
|
3
1
|
# Copyright (c) 2011-2021, Camptocamp SA
|
4
2
|
# All rights reserved.
|
5
3
|
|
@@ -26,15 +24,18 @@
|
|
26
24
|
# The views and conclusions contained in the software and documentation are those
|
27
25
|
# of the authors and should not be interpreted as representing official policies,
|
28
26
|
# either expressed or implied, of the FreeBSD Project.
|
27
|
+
|
28
|
+
import random
|
29
29
|
import threading
|
30
30
|
import warnings
|
31
|
-
from typing import Dict,
|
31
|
+
from typing import Dict, Iterable, List, Optional, Tuple, Union
|
32
32
|
|
33
|
+
import sqlalchemy.ext.declarative
|
33
34
|
from papyrus.geo_interface import GeoInterface
|
34
35
|
from sqlalchemy import Column, Integer, MetaData, Table
|
35
36
|
from sqlalchemy.exc import SAWarning
|
36
|
-
from sqlalchemy.ext.declarative.api import DeclarativeMeta # noqa, pylint: disable=unused-import
|
37
37
|
from sqlalchemy.orm import relationship
|
38
|
+
from sqlalchemy.orm.session import Session
|
38
39
|
from sqlalchemy.orm.util import class_mapper
|
39
40
|
|
40
41
|
from c2cgeoportal_geoportal.lib.caching import get_region
|
@@ -53,13 +54,17 @@ SQL_GEOMETRY_COLUMNS = """
|
|
53
54
|
class _AssociationProxy:
|
54
55
|
# A specific "association proxy" implementation
|
55
56
|
|
56
|
-
def __init__(self, target, value_attr, nullable=True, order_by=None):
|
57
|
+
def __init__(self, target: str, value_attr: str, nullable: bool = True, order_by: Optional[str] = None):
|
57
58
|
self.target = target
|
58
59
|
self.value_attr = value_attr
|
59
60
|
self.nullable = nullable
|
60
61
|
self.order_by = order_by
|
61
62
|
|
62
|
-
def __get__(
|
63
|
+
def __get__(
|
64
|
+
self,
|
65
|
+
obj: sqlalchemy.ext.declarative.ConcreteBase,
|
66
|
+
type_: sqlalchemy.ext.declarative.DeclarativeMeta = None,
|
67
|
+
) -> Optional[Union["_AssociationProxy", str]]:
|
63
68
|
if obj is None:
|
64
69
|
# For "hybrid" descriptors that work both at the instance
|
65
70
|
# and class levels we could return an SQL expression here.
|
@@ -69,7 +74,7 @@ class _AssociationProxy:
|
|
69
74
|
target = getattr(obj, self.target)
|
70
75
|
return getattr(target, self.value_attr) if target else None
|
71
76
|
|
72
|
-
def __set__(self, obj, val):
|
77
|
+
def __set__(self, obj: str, val: str) -> None:
|
73
78
|
from c2cgeoportal_commons.models import DBSession # pylint: disable=import-outside-toplevel
|
74
79
|
|
75
80
|
o = getattr(obj, self.target)
|
@@ -83,7 +88,7 @@ class _AssociationProxy:
|
|
83
88
|
setattr(obj, self.target, o)
|
84
89
|
|
85
90
|
|
86
|
-
def _get_schema(tablename):
|
91
|
+
def _get_schema(tablename: str) -> Tuple[str, str]:
|
87
92
|
if "." in tablename:
|
88
93
|
schema, tablename = tablename.split(".", 1)
|
89
94
|
else:
|
@@ -95,7 +100,13 @@ def _get_schema(tablename):
|
|
95
100
|
_get_table_lock = threading.RLock()
|
96
101
|
|
97
102
|
|
98
|
-
def get_table(
|
103
|
+
def get_table(
|
104
|
+
tablename: str,
|
105
|
+
schema: Optional[str] = None,
|
106
|
+
session: Optional[Session] = None,
|
107
|
+
primary_key: Optional[str] = None,
|
108
|
+
) -> Table:
|
109
|
+
"""Build an SQLAlchemy table."""
|
99
110
|
if schema is None:
|
100
111
|
tablename, schema = _get_schema(tablename)
|
101
112
|
|
@@ -103,8 +114,8 @@ def get_table(tablename, schema=None, session=None, primary_key=None):
|
|
103
114
|
engine = session.bind.engine
|
104
115
|
metadata = MetaData(bind=engine)
|
105
116
|
else:
|
117
|
+
from c2cgeoportal_commons.models import Base # pylint: disable=import-outside-toplevel
|
106
118
|
from c2cgeoportal_commons.models import DBSession # pylint: disable=import-outside-toplevel
|
107
|
-
from c2cgeoportal_commons.models.main import Base # pylint: disable=import-outside-toplevel
|
108
119
|
|
109
120
|
engine = DBSession.bind.engine
|
110
121
|
metadata = Base.metadata
|
@@ -121,21 +132,21 @@ def get_table(tablename, schema=None, session=None, primary_key=None):
|
|
121
132
|
return table
|
122
133
|
|
123
134
|
|
124
|
-
@CACHE_REGION_OBJ.cache_on_arguments()
|
135
|
+
@CACHE_REGION_OBJ.cache_on_arguments() # type: ignore
|
125
136
|
def get_class(
|
126
|
-
tablename,
|
127
|
-
exclude_properties=None,
|
128
|
-
primary_key=None,
|
129
|
-
attributes_order=None,
|
130
|
-
enumerations_config=None,
|
131
|
-
readonly_attributes=None,
|
132
|
-
):
|
137
|
+
tablename: str,
|
138
|
+
exclude_properties: Optional[List[str]] = None,
|
139
|
+
primary_key: Optional[str] = None,
|
140
|
+
attributes_order: Optional[List[str]] = None,
|
141
|
+
enumerations_config: Optional[Dict[str, str]] = None,
|
142
|
+
readonly_attributes: Optional[List[str]] = None,
|
143
|
+
) -> sqlalchemy.ext.declarative.DeclarativeMeta:
|
133
144
|
"""
|
134
|
-
Get the SQLAlchemy mapped class for "tablename".
|
135
|
-
|
136
|
-
|
137
|
-
tablename in the database a NoSuchTableError SQLAlchemy
|
138
|
-
is raised.
|
145
|
+
Get the SQLAlchemy mapped class for "tablename".
|
146
|
+
|
147
|
+
If no class exists for "tablename" one is created, and added to the cache. "tablename" must reference a
|
148
|
+
valid string. If there is no table identified by tablename in the database a NoSuchTableError SQLAlchemy
|
149
|
+
exception is raised.
|
139
150
|
"""
|
140
151
|
|
141
152
|
tablename, schema = _get_schema(tablename)
|
@@ -155,14 +166,14 @@ def get_class(
|
|
155
166
|
|
156
167
|
|
157
168
|
def _create_class(
|
158
|
-
table,
|
159
|
-
exclude_properties=None,
|
160
|
-
attributes_order=None,
|
161
|
-
enumerations_config=None,
|
162
|
-
readonly_attributes=None,
|
163
|
-
pk_name=None,
|
164
|
-
):
|
165
|
-
from c2cgeoportal_commons.models
|
169
|
+
table: Table,
|
170
|
+
exclude_properties: Optional[Iterable[str]] = None,
|
171
|
+
attributes_order: Optional[List[str]] = None,
|
172
|
+
enumerations_config: Optional[Dict[str, str]] = None,
|
173
|
+
readonly_attributes: Optional[List[str]] = None,
|
174
|
+
pk_name: Optional[str] = None,
|
175
|
+
) -> sqlalchemy.ext.declarative.DeclarativeMeta:
|
176
|
+
from c2cgeoportal_commons.models import Base # pylint: disable=import-outside-toplevel
|
166
177
|
|
167
178
|
exclude_properties = exclude_properties or ()
|
168
179
|
attributes = dict(
|
@@ -173,7 +184,11 @@ def _create_class(
|
|
173
184
|
)
|
174
185
|
if pk_name is not None:
|
175
186
|
attributes[pk_name] = Column(Integer, primary_key=True)
|
176
|
-
|
187
|
+
# The randint is to fix the SAWarning: This declarative base already contains a class with the same
|
188
|
+
# class name and module nam
|
189
|
+
cls = type(
|
190
|
+
f"{table.name.capitalize()}_{random.randint(0, 9999999)}", (GeoInterface, Base), attributes # nosec
|
191
|
+
)
|
177
192
|
|
178
193
|
for col in table.columns:
|
179
194
|
if col.name in (readonly_attributes or []):
|
@@ -184,8 +199,10 @@ def _create_class(
|
|
184
199
|
return cls
|
185
200
|
|
186
201
|
|
187
|
-
def _add_association_proxy(
|
188
|
-
|
202
|
+
def _add_association_proxy(
|
203
|
+
cls: sqlalchemy.ext.declarative.DeclarativeMeta, col: sqlalchemy.sql.schema.Column
|
204
|
+
) -> None:
|
205
|
+
if len(col.foreign_keys) != 1:
|
189
206
|
raise NotImplementedError
|
190
207
|
|
191
208
|
fk = next(iter(col.foreign_keys))
|
@@ -193,10 +210,8 @@ def _add_association_proxy(cls, col):
|
|
193
210
|
child_cls = get_class(child_tablename)
|
194
211
|
|
195
212
|
try:
|
196
|
-
|
197
|
-
|
198
|
-
# fmt: on
|
199
|
-
except ValueError: # pragma: no cover
|
213
|
+
proxy = col.name[0 : col.name.rindex("_id")]
|
214
|
+
except ValueError:
|
200
215
|
proxy = col.name + "_"
|
201
216
|
|
202
217
|
# The following is a workaround for a bug in the geojson lib. The
|
@@ -204,7 +219,7 @@ def _add_association_proxy(cls, col):
|
|
204
219
|
# (this is a GeoJSON keyword), and produces a UnicodeEncodeError
|
205
220
|
# if the property includes non-ascii characters.
|
206
221
|
if proxy == "type":
|
207
|
-
proxy = "type_"
|
222
|
+
proxy = "type_"
|
208
223
|
|
209
224
|
rel = proxy + "_"
|
210
225
|
primaryjoin = getattr(cls, col.name) == getattr(child_cls, child_pk)
|