c2cgeoportal-geoportal 2.3.5.79__py3-none-any.whl → 2.9rc44__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- c2cgeoportal_geoportal/__init__.py +960 -0
- c2cgeoportal_geoportal/lib/__init__.py +256 -0
- c2cgeoportal_geoportal/lib/authentication.py +250 -0
- c2cgeoportal_geoportal/lib/bashcolor.py +46 -0
- c2cgeoportal_geoportal/lib/cacheversion.py +77 -0
- c2cgeoportal_geoportal/lib/caching.py +176 -0
- c2cgeoportal_geoportal/lib/check_collector.py +80 -0
- c2cgeoportal_geoportal/lib/checker.py +295 -0
- c2cgeoportal_geoportal/lib/common_headers.py +172 -0
- c2cgeoportal_geoportal/lib/dbreflection.py +266 -0
- c2cgeoportal_geoportal/lib/filter_capabilities.py +360 -0
- c2cgeoportal_geoportal/lib/fulltextsearch.py +50 -0
- c2cgeoportal_geoportal/lib/functionality.py +166 -0
- c2cgeoportal_geoportal/lib/headers.py +62 -0
- c2cgeoportal_geoportal/lib/i18n.py +38 -0
- c2cgeoportal_geoportal/lib/layers.py +132 -0
- c2cgeoportal_geoportal/lib/lingva_extractor.py +937 -0
- c2cgeoportal_geoportal/lib/loader.py +57 -0
- c2cgeoportal_geoportal/lib/metrics.py +117 -0
- c2cgeoportal_geoportal/lib/oauth2.py +1186 -0
- c2cgeoportal_geoportal/lib/oidc.py +304 -0
- c2cgeoportal_geoportal/lib/wmstparsing.py +353 -0
- c2cgeoportal_geoportal/lib/xsd.py +166 -0
- c2cgeoportal_geoportal/py.typed +0 -0
- c2cgeoportal_geoportal/resources.py +49 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/ci/config.yaml +26 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/cookiecutter.json +18 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/.dockerignore +6 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/.eslintrc.yaml +19 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/.prospector.yaml +30 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/Dockerfile +75 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/Makefile +6 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/alembic.ini +58 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/alembic.yaml +19 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/development.ini +121 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/gunicorn.conf.py +139 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/language_mapping +3 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/lingva-client.cfg +5 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/lingva-server.cfg +6 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/production.ini +38 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/requirements.txt +2 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/setup.py +25 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/webpack.api.js +41 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/webpack.apps.js +64 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/webpack.commons.js +11 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/webpack.config.js +22 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/__init__.py +42 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/authentication.py +10 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/dev.py +14 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/models.py +8 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/multi_organization.py +7 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/resources.py +11 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static-ngeo/api/index.js +12 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static-ngeo/js/{{cookiecutter.package}}module.js +25 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/subscribers.py +39 -0
- c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/views/__init__.py +0 -0
- c2cgeoportal_geoportal/scaffolds/advance_update/cookiecutter.json +18 -0
- c2cgeoportal_geoportal/scaffolds/advance_update/{{cookiecutter.project}}/geoportal/CONST_Makefile +121 -0
- c2cgeoportal_geoportal/scaffolds/create/cookiecutter.json +18 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.dockerignore +14 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.editorconfig +17 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.github/workflows/main.yaml +73 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.github/workflows/rebuild.yaml +50 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.github/workflows/update_l10n.yaml +66 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.gitignore +16 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.pre-commit-config.yaml +35 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.prettierignore +1 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.prettierrc.yaml +2 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/Dockerfile +75 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/Makefile +70 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/README.rst +29 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/build +179 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/ci/config.yaml +22 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/ci/docker-compose-check +25 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/ci/requirements.txt +2 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/docker-compose-db.yaml +24 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/docker-compose-lib.yaml +513 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/docker-compose-qgis.yaml +21 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/docker-compose.override.sample.yaml +65 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/docker-compose.yaml +121 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/env.default +102 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/env.project +69 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/geoportal/vars.yaml +430 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/locale/en/LC_MESSAGES/{{cookiecutter.package}}_geoportal-client.po +6 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static/css/desktop.css +0 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static/css/iframe_api.css +0 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static/css/mobile.css +0 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static/images/banner_left.png +0 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static/images/banner_right.png +0 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static/images/blank.png +0 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static/images/markers/marker-blue.png +0 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static/images/markers/marker-gold.png +0 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static/images/markers/marker-green.png +0 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static/images/markers/marker.png +0 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static/robot.txt.tmpl +3 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/data/Readme.txt +69 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/data/TM_EUROPE_BORDERS-0.3.sql +70 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/demo.map.tmpl +224 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/fonts/Arial.ttf +0 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/fonts/Arialbd.ttf +0 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/fonts/Arialbi.ttf +0 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/fonts/Ariali.ttf +0 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/fonts/NotoSans-Bold.ttf +0 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/fonts/NotoSans-BoldItalic.ttf +0 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/fonts/NotoSans-Italic.ttf +0 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/fonts/NotoSans-Regular.ttf +0 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/fonts/Verdana.ttf +0 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/fonts/Verdanab.ttf +0 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/fonts/Verdanai.ttf +0 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/fonts/Verdanaz.ttf +0 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/fonts.conf +12 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/mapserver.conf +16 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/mapserver.map.tmpl +87 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/tinyows.xml.tmpl +36 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}/A3_Landscape.jrxml +207 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}/A3_Portrait.jrxml +185 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}/A4_Landscape.jrxml +200 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}/A4_Portrait.jrxml +170 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}/config.yaml.tmpl +175 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}/legend.jrxml +109 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}/localisation.properties +4 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}/localisation_fr.properties +4 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}/logo.png +0 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}/north.svg +93 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}/results.jrxml +25 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/project.yaml +18 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/pyproject.toml +7 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/qgisserver/pg_service.conf.tmpl +15 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/run_alembic.sh +11 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/scripts/db-backup +126 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/scripts/db-restore +132 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/setup.cfg +7 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/spell-ignore-words.txt +5 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/tests/__init__.py +0 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/tests/test_app.py +78 -0
- c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/tilegeneration/config.yaml.tmpl +195 -0
- c2cgeoportal_geoportal/scaffolds/update/cookiecutter.json +18 -0
- c2cgeoportal_geoportal/scaffolds/update/{{cookiecutter.project}}/.upgrade.yaml +67 -0
- c2cgeoportal_geoportal/scaffolds/update/{{cookiecutter.project}}/CONST_CHANGELOG.txt +304 -0
- c2cgeoportal_geoportal/scaffolds/update/{{cookiecutter.project}}/CONST_create_template/tests/test_testapp.py +48 -0
- c2cgeoportal_geoportal/scaffolds/update/{{cookiecutter.project}}/geoportal/.CONST_vars.yaml.swp +0 -0
- c2cgeoportal_geoportal/scaffolds/update/{{cookiecutter.project}}/geoportal/CONST_config-schema.yaml +927 -0
- c2cgeoportal_geoportal/scaffolds/update/{{cookiecutter.project}}/geoportal/CONST_vars.yaml +1503 -0
- c2cgeoportal_geoportal/scripts/__init__.py +64 -0
- c2cgeoportal_geoportal/scripts/c2cupgrade.py +879 -0
- c2cgeoportal_geoportal/scripts/create_demo_theme.py +83 -0
- c2cgeoportal_geoportal/scripts/manage_users.py +140 -0
- c2cgeoportal_geoportal/scripts/pcreate.py +296 -0
- c2cgeoportal_geoportal/scripts/theme2fts.py +347 -0
- c2cgeoportal_geoportal/scripts/urllogin.py +81 -0
- c2cgeoportal_geoportal/templates/login.html +90 -0
- c2cgeoportal_geoportal/templates/notlogin.html +62 -0
- c2cgeoportal_geoportal/templates/testi18n.html +12 -0
- c2cgeoportal_geoportal/views/__init__.py +59 -0
- c2cgeoportal_geoportal/views/dev.py +57 -0
- c2cgeoportal_geoportal/views/dynamic.py +208 -0
- c2cgeoportal_geoportal/views/entry.py +174 -0
- c2cgeoportal_geoportal/views/fulltextsearch.py +189 -0
- c2cgeoportal_geoportal/views/geometry_processing.py +75 -0
- c2cgeoportal_geoportal/views/i18n.py +129 -0
- c2cgeoportal_geoportal/views/layers.py +713 -0
- c2cgeoportal_geoportal/views/login.py +684 -0
- c2cgeoportal_geoportal/views/mapserverproxy.py +234 -0
- c2cgeoportal_geoportal/views/memory.py +90 -0
- c2cgeoportal_geoportal/views/ogcproxy.py +120 -0
- c2cgeoportal_geoportal/views/pdfreport.py +245 -0
- c2cgeoportal_geoportal/views/printproxy.py +143 -0
- c2cgeoportal_geoportal/views/profile.py +192 -0
- c2cgeoportal_geoportal/views/proxy.py +261 -0
- c2cgeoportal_geoportal/views/raster.py +233 -0
- c2cgeoportal_geoportal/views/resourceproxy.py +73 -0
- c2cgeoportal_geoportal/views/shortener.py +152 -0
- c2cgeoportal_geoportal/views/theme.py +1322 -0
- c2cgeoportal_geoportal/views/tinyowsproxy.py +189 -0
- c2cgeoportal_geoportal/views/vector_tiles.py +83 -0
- {c2cgeoportal_geoportal-2.3.5.79.dist-info → c2cgeoportal_geoportal-2.9rc44.dist-info}/METADATA +21 -24
- c2cgeoportal_geoportal-2.9rc44.dist-info/RECORD +193 -0
- {c2cgeoportal_geoportal-2.3.5.79.dist-info → c2cgeoportal_geoportal-2.9rc44.dist-info}/WHEEL +1 -1
- c2cgeoportal_geoportal-2.9rc44.dist-info/entry_points.txt +28 -0
- c2cgeoportal_geoportal-2.9rc44.dist-info/top_level.txt +2 -0
- tests/__init__.py +100 -0
- tests/test_cachebuster.py +71 -0
- tests/test_caching.py +275 -0
- tests/test_checker.py +85 -0
- tests/test_decimaljson.py +47 -0
- tests/test_headerstween.py +64 -0
- tests/test_i18n.py +31 -0
- tests/test_init.py +193 -0
- tests/test_locale_negociator.py +69 -0
- tests/test_mapserverproxy_route_predicate.py +64 -0
- tests/test_raster.py +267 -0
- tests/test_wmstparsing.py +238 -0
- tests/xmlstr.py +103 -0
- c2cgeoportal_geoportal-2.3.5.79.dist-info/DESCRIPTION.rst +0 -8
- c2cgeoportal_geoportal-2.3.5.79.dist-info/RECORD +0 -7
- c2cgeoportal_geoportal-2.3.5.79.dist-info/entry_points.txt +0 -22
- c2cgeoportal_geoportal-2.3.5.79.dist-info/metadata.json +0 -1
- c2cgeoportal_geoportal-2.3.5.79.dist-info/top_level.txt +0 -1
tests/__init__.py
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
# Copyright (c) 2011-2023, Camptocamp SA
|
2
|
+
# All rights reserved.
|
3
|
+
|
4
|
+
# Redistribution and use in source and binary forms, with or without
|
5
|
+
# modification, are permitted provided that the following conditions are met:
|
6
|
+
|
7
|
+
# 1. Redistributions of source code must retain the above copyright notice, this
|
8
|
+
# list of conditions and the following disclaimer.
|
9
|
+
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
10
|
+
# this list of conditions and the following disclaimer in the documentation
|
11
|
+
# and/or other materials provided with the distribution.
|
12
|
+
|
13
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
14
|
+
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
15
|
+
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
16
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
17
|
+
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
18
|
+
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
19
|
+
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
20
|
+
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
21
|
+
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
22
|
+
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
23
|
+
|
24
|
+
# The views and conclusions contained in the software and documentation are those
|
25
|
+
# of the authors and should not be interpreted as representing official policies,
|
26
|
+
# either expressed or implied, of the FreeBSD Project.
|
27
|
+
|
28
|
+
|
29
|
+
"""
|
30
|
+
Pyramid application test package.
|
31
|
+
"""
|
32
|
+
|
33
|
+
import logging
|
34
|
+
import os
|
35
|
+
import urllib.parse
|
36
|
+
import warnings
|
37
|
+
|
38
|
+
import sqlalchemy.exc
|
39
|
+
from pyramid.testing import DummyRequest as PyramidDummyRequest
|
40
|
+
|
41
|
+
from c2cgeoportal_geoportal.lib import caching
|
42
|
+
|
43
|
+
with warnings.catch_warnings():
|
44
|
+
warnings.simplefilter("ignore", category=sqlalchemy.exc.SAWarning)
|
45
|
+
|
46
|
+
|
47
|
+
class DummyRequest(PyramidDummyRequest):
|
48
|
+
def __init__(self, *args, **kwargs):
|
49
|
+
super().__init__(*args, **kwargs)
|
50
|
+
self.client_addr = "1.1.1.1"
|
51
|
+
self.referrer = None
|
52
|
+
if self.registry.settings is None:
|
53
|
+
self.registry.settings = {}
|
54
|
+
|
55
|
+
|
56
|
+
def setup_common():
|
57
|
+
logging.getLogger("c2cgeoportal_geoportal").setLevel(logging.DEBUG)
|
58
|
+
|
59
|
+
caching.init_region({"backend": "dogpile.cache.null"}, "std")
|
60
|
+
caching.init_region({"backend": "dogpile.cache.null"}, "obj")
|
61
|
+
caching.init_region({"backend": "dogpile.cache.null"}, "ogc-server")
|
62
|
+
|
63
|
+
|
64
|
+
def create_dummy_request(additional_settings=None, *args, **kargs):
|
65
|
+
if additional_settings is None:
|
66
|
+
additional_settings = {}
|
67
|
+
request = DummyRequest(*args, **kargs)
|
68
|
+
request.registry.settings = {
|
69
|
+
"available_locale_names": ["en", "fr", "de"],
|
70
|
+
"default_locale_name": "fr",
|
71
|
+
"default_max_age": 1000,
|
72
|
+
"package": "package_for_test",
|
73
|
+
}
|
74
|
+
request.registry.settings.update(additional_settings)
|
75
|
+
request.is_valid_referer = True
|
76
|
+
request.scheme = "https"
|
77
|
+
request.static_url = lambda url: "http://example.com/dummy/static/url"
|
78
|
+
request.route_url = (
|
79
|
+
lambda name, **kwargs: "http://example.com/"
|
80
|
+
+ name
|
81
|
+
+ "/view?"
|
82
|
+
+ urllib.parse.urlencode(kwargs.get("_query", {}))
|
83
|
+
)
|
84
|
+
request.current_route_url = lambda **kwargs: "http://example.com/current/view?" + urllib.parse.urlencode(
|
85
|
+
kwargs.get("_query", {})
|
86
|
+
)
|
87
|
+
request.get_organization_role = lambda role_type: role_type
|
88
|
+
request.get_organization_interface = lambda interface: interface
|
89
|
+
|
90
|
+
return request
|
91
|
+
|
92
|
+
|
93
|
+
def load_binfile(file_name):
|
94
|
+
with open(os.path.join("/opt/c2cgeoportal/geoportal", file_name), "rb") as file_:
|
95
|
+
return file_.read()
|
96
|
+
|
97
|
+
|
98
|
+
def load_file(file_name):
|
99
|
+
with open(os.path.join("/opt/c2cgeoportal/geoportal", file_name)) as file_:
|
100
|
+
return file_.read()
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# Copyright (c) 2011-2023, Camptocamp SA
|
2
|
+
# All rights reserved.
|
3
|
+
|
4
|
+
# Redistribution and use in source and binary forms, with or without
|
5
|
+
# modification, are permitted provided that the following conditions are met:
|
6
|
+
|
7
|
+
# 1. Redistributions of source code must retain the above copyright notice, this
|
8
|
+
# list of conditions and the following disclaimer.
|
9
|
+
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
10
|
+
# this list of conditions and the following disclaimer in the documentation
|
11
|
+
# and/or other materials provided with the distribution.
|
12
|
+
|
13
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
14
|
+
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
15
|
+
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
16
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
17
|
+
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
18
|
+
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
19
|
+
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
20
|
+
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
21
|
+
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
22
|
+
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
23
|
+
|
24
|
+
# The views and conclusions contained in the software and documentation are those
|
25
|
+
# of the authors and should not be interpreted as representing official policies,
|
26
|
+
# either expressed or implied, of the FreeBSD Project.
|
27
|
+
|
28
|
+
# pylint: disable=missing-docstring,attribute-defined-outside-init,protected-access
|
29
|
+
|
30
|
+
|
31
|
+
from unittest import TestCase
|
32
|
+
|
33
|
+
import pyramid.registry
|
34
|
+
from tests import DummyRequest
|
35
|
+
|
36
|
+
from c2cgeoportal_geoportal.lib.caching import init_region
|
37
|
+
|
38
|
+
|
39
|
+
def handler(request):
|
40
|
+
return request.response
|
41
|
+
|
42
|
+
|
43
|
+
class MyRequest(DummyRequest):
|
44
|
+
def __init__(self, path_info):
|
45
|
+
self.path_info = path_info
|
46
|
+
|
47
|
+
|
48
|
+
class TestCacheBuster(TestCase):
|
49
|
+
def setup_class(self):
|
50
|
+
init_region({"backend": "dogpile.cache.memory"}, "std")
|
51
|
+
init_region({"backend": "dogpile.cache.memory"}, "obj")
|
52
|
+
|
53
|
+
def test_replace(self):
|
54
|
+
from c2cgeoportal_geoportal.lib.cacheversion import CachebusterTween
|
55
|
+
|
56
|
+
registry = pyramid.registry.Registry()
|
57
|
+
registry.settings = {"cache_path": ["test"]}
|
58
|
+
ctf = CachebusterTween(handler, registry)
|
59
|
+
request = MyRequest("/test/123456/build.css")
|
60
|
+
ctf(request)
|
61
|
+
assert request.path_info == "/test/build.css"
|
62
|
+
|
63
|
+
def test_noreplace(self):
|
64
|
+
from c2cgeoportal_geoportal.lib.cacheversion import CachebusterTween
|
65
|
+
|
66
|
+
registry = pyramid.registry.Registry()
|
67
|
+
registry.settings = {"cache_path": ["test"]}
|
68
|
+
ctf = CachebusterTween(handler, registry)
|
69
|
+
request = MyRequest("/test2/123456/build.css")
|
70
|
+
ctf(request)
|
71
|
+
assert request.path_info == "/test2/123456/build.css"
|
tests/test_caching.py
ADDED
@@ -0,0 +1,275 @@
|
|
1
|
+
# Copyright (c) 2015-2025, 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
|
+
# pylint: disable=missing-docstring,attribute-defined-outside-init,protected-access
|
29
|
+
|
30
|
+
|
31
|
+
from unittest import TestCase
|
32
|
+
|
33
|
+
from tests import DummyRequest
|
34
|
+
|
35
|
+
from c2cgeoportal_geoportal.lib.cacheversion import get_cache_version
|
36
|
+
from c2cgeoportal_geoportal.lib.caching import init_region, invalidate_region
|
37
|
+
from c2cgeoportal_geoportal.lib.common_headers import CORS_METHODS, Cache, set_common_headers
|
38
|
+
|
39
|
+
|
40
|
+
class TestSetCorsHeaders(TestCase):
|
41
|
+
ORIGIN1 = "http://www.example.com"
|
42
|
+
ORIGIN2 = "http://www.friend.com"
|
43
|
+
MAX_AGE = "1234"
|
44
|
+
SETTINGS = {"access_control_allow_origin": [ORIGIN1, ORIGIN2], "access_control_max_age": MAX_AGE}
|
45
|
+
|
46
|
+
@staticmethod
|
47
|
+
def _do(method, headers, credentials=False, settings=SETTINGS):
|
48
|
+
request = DummyRequest({}, method=method, headers=headers)
|
49
|
+
if settings is not None:
|
50
|
+
request.registry.settings = {"headers": {"foo": settings}}
|
51
|
+
else:
|
52
|
+
request.registry.settings = {"headers": {}}
|
53
|
+
set_common_headers(request, "foo", Cache.PRIVATE_NO, credentials=credentials)
|
54
|
+
|
55
|
+
return dict(request.response.headers)
|
56
|
+
|
57
|
+
def test_simple(self):
|
58
|
+
"""
|
59
|
+
Tests specified in http://www.w3.org/TR/cors/#resource-requests.
|
60
|
+
"""
|
61
|
+
# 1. If the Origin header is not present terminate this set of steps.
|
62
|
+
# The request is outside the scope of this specification.
|
63
|
+
assert self._do("POST", {}) == {
|
64
|
+
"Cache-Control": "max-age=10, private",
|
65
|
+
"Content-Length": "0",
|
66
|
+
"Content-Type": "text/html; charset=UTF-8",
|
67
|
+
"Vary": "Origin, Access-Control-Request-Headers, Cookie, Authorization",
|
68
|
+
}
|
69
|
+
|
70
|
+
# 2. If the value of the Origin header is not a case-sensitive match for
|
71
|
+
# any of the values in list of origins, do not set any additional
|
72
|
+
# headers and terminate this set of steps.
|
73
|
+
assert self._do("POST", {"Origin": "http://foe.com"}) == {
|
74
|
+
"Cache-Control": "max-age=10, private",
|
75
|
+
"Content-Length": "0",
|
76
|
+
"Content-Type": "text/html; charset=UTF-8",
|
77
|
+
"Vary": "Origin, Access-Control-Request-Headers, Cookie, Authorization",
|
78
|
+
}
|
79
|
+
|
80
|
+
# 3. If the resource supports credentials add a single
|
81
|
+
# Access-Control-Allow-Origin header, with the value of the Origin
|
82
|
+
# header as value, and add a single Access-Control-Allow-Credentials
|
83
|
+
# header with the case-sensitive string "true" as value.
|
84
|
+
assert self._do("POST", {"Origin": self.ORIGIN2}, credentials=True) == {
|
85
|
+
"Cache-Control": "max-age=10, private",
|
86
|
+
"Content-Length": "0",
|
87
|
+
"Content-Type": "text/html; charset=UTF-8",
|
88
|
+
"Vary": "Origin, Access-Control-Request-Headers, Cookie, Authorization",
|
89
|
+
"Access-Control-Max-Age": self.MAX_AGE,
|
90
|
+
"Access-Control-Allow-Origin": self.ORIGIN2,
|
91
|
+
"Access-Control-Allow-Methods": CORS_METHODS,
|
92
|
+
"Access-Control-Allow-Credentials": "true",
|
93
|
+
}
|
94
|
+
|
95
|
+
# 3. Otherwise, add a single Access-Control-Allow-Origin header, with
|
96
|
+
# either the value of the Origin header or the string "*" as value.
|
97
|
+
# tested in test_match_all
|
98
|
+
|
99
|
+
# 4. If the list of exposed headers is not empty add one or more
|
100
|
+
# Access-Control-Expose-Headers headers, with as values the header
|
101
|
+
# field names given in the list of exposed headers.
|
102
|
+
# Not implemented
|
103
|
+
|
104
|
+
def test_preflight(self):
|
105
|
+
"""
|
106
|
+
Tests specified in http://www.w3.org/TR/cors/#resource-preflight-requests.
|
107
|
+
"""
|
108
|
+
# 1. If the Origin header is not present terminate this set of steps.
|
109
|
+
# The request is outside the scope of this specification.
|
110
|
+
assert self._do("OPTIONS", {"Access-Control-Request-Method": "GET"}) == {
|
111
|
+
"Content-Length": "0",
|
112
|
+
"Content-Type": "text/html; charset=UTF-8",
|
113
|
+
"Vary": "Origin, Access-Control-Request-Headers, Access-Control-Request-Method",
|
114
|
+
}
|
115
|
+
|
116
|
+
# 2. If the value of the Origin header is not a case-sensitive match for
|
117
|
+
# any of the values in list of origins do not set any additional
|
118
|
+
# headers and terminate this set of steps.
|
119
|
+
assert self._do("OPTIONS", {"Origin": "http://foe.com", "Access-Control-Request-Method": "GET"}) == {
|
120
|
+
"Content-Length": "0",
|
121
|
+
"Content-Type": "text/html; charset=UTF-8",
|
122
|
+
"Vary": "Origin, Access-Control-Request-Headers, Access-Control-Request-Method",
|
123
|
+
}
|
124
|
+
|
125
|
+
# 3. If there is no Access-Control-Request-Method header or if parsing
|
126
|
+
# failed, do not set any additional headers and terminate this set
|
127
|
+
# of steps. The request is outside the scope of this specification.
|
128
|
+
assert self._do("OPTIONS", {"Origin": self.ORIGIN1}) == {
|
129
|
+
"Content-Length": "0",
|
130
|
+
"Content-Type": "text/html; charset=UTF-8",
|
131
|
+
"Vary": "Origin, Access-Control-Request-Headers, Access-Control-Request-Method",
|
132
|
+
}
|
133
|
+
|
134
|
+
# 4. If there are no Access-Control-Request-Headers headers let header
|
135
|
+
# field-names be the empty list.
|
136
|
+
assert self._do("OPTIONS", {"Origin": self.ORIGIN1, "Access-Control-Request-Method": "GET"}) == {
|
137
|
+
"Content-Length": "0",
|
138
|
+
"Content-Type": "text/html; charset=UTF-8",
|
139
|
+
"Vary": "Origin, Access-Control-Request-Headers, Access-Control-Request-Method",
|
140
|
+
"Access-Control-Allow-Origin": self.ORIGIN1,
|
141
|
+
"Access-Control-Max-Age": self.MAX_AGE,
|
142
|
+
"Access-Control-Allow-Methods": CORS_METHODS,
|
143
|
+
"Cache-Control": "max-age=" + self.MAX_AGE,
|
144
|
+
}
|
145
|
+
|
146
|
+
# 5. If method is not a case-sensitive match for any of the values in
|
147
|
+
# list of methods do not set any additional headers and terminate
|
148
|
+
# this set of steps.
|
149
|
+
# Not implemented
|
150
|
+
|
151
|
+
# 6. If any of the header field-names is not a ASCII case-insensitive
|
152
|
+
# match for any of the values in list of headers do not set any
|
153
|
+
# additional headers and terminate this set of steps.
|
154
|
+
# Not implemented
|
155
|
+
|
156
|
+
# 7. If the resource supports credentials add a single
|
157
|
+
# Access-Control-Allow-Origin header, with the value of the Origin
|
158
|
+
# header as value, and add a single Access-Control-Allow-Credentials
|
159
|
+
# header with the case-sensitive string "true" as value.
|
160
|
+
assert self._do(
|
161
|
+
"OPTIONS", {"Origin": self.ORIGIN1, "Access-Control-Request-Method": "GET"}, credentials=True
|
162
|
+
) == {
|
163
|
+
"Content-Length": "0",
|
164
|
+
"Content-Type": "text/html; charset=UTF-8",
|
165
|
+
"Vary": "Origin, Access-Control-Request-Headers, Access-Control-Request-Method",
|
166
|
+
"Access-Control-Allow-Origin": self.ORIGIN1,
|
167
|
+
"Access-Control-Allow-Credentials": "true",
|
168
|
+
"Access-Control-Max-Age": self.MAX_AGE,
|
169
|
+
"Access-Control-Allow-Methods": CORS_METHODS,
|
170
|
+
"Cache-Control": "max-age=" + self.MAX_AGE,
|
171
|
+
}
|
172
|
+
|
173
|
+
# 8. Optionally add a single Access-Control-Max-Age header with as value
|
174
|
+
# the amount of seconds the user agent is allowed to cache the result
|
175
|
+
# of the request.
|
176
|
+
# Already tested
|
177
|
+
|
178
|
+
# 9. Add one or more Access-Control-Allow-Methods headers consisting of
|
179
|
+
# (a subset of) the list of methods.
|
180
|
+
# Already tested
|
181
|
+
|
182
|
+
# 10. Add one or more Access-Control-Allow-Headers headers consisting of
|
183
|
+
# (a subset of) the list of headers.
|
184
|
+
assert self._do(
|
185
|
+
"OPTIONS",
|
186
|
+
{
|
187
|
+
"Origin": self.ORIGIN1,
|
188
|
+
"Access-Control-Request-Method": "GET",
|
189
|
+
"Access-Control-Request-Headers": "X-Foo, X-Bar",
|
190
|
+
},
|
191
|
+
) == {
|
192
|
+
"Content-Length": "0",
|
193
|
+
"Content-Type": "text/html; charset=UTF-8",
|
194
|
+
"Vary": "Origin, Access-Control-Request-Headers, Access-Control-Request-Method",
|
195
|
+
"Access-Control-Allow-Origin": self.ORIGIN1,
|
196
|
+
"Access-Control-Max-Age": self.MAX_AGE,
|
197
|
+
"Access-Control-Allow-Methods": CORS_METHODS,
|
198
|
+
"Access-Control-Allow-Headers": "X-Foo, X-Bar",
|
199
|
+
"Cache-Control": "max-age=" + self.MAX_AGE,
|
200
|
+
}
|
201
|
+
|
202
|
+
def test_not_configured(self):
|
203
|
+
# If the service is not configured, then no CORS head.
|
204
|
+
assert self._do("GET", {"Origin": self.ORIGIN1}, settings=None) == {
|
205
|
+
"Cache-Control": "max-age=10, private",
|
206
|
+
"Content-Length": "0",
|
207
|
+
"Content-Type": "text/html; charset=UTF-8",
|
208
|
+
"Vary": "Origin, Access-Control-Request-Headers, Cookie, Authorization",
|
209
|
+
}
|
210
|
+
|
211
|
+
def test_match_all(self):
|
212
|
+
settings = {
|
213
|
+
"access_control_allow_origin": [self.ORIGIN1, "*"],
|
214
|
+
"access_control_max_age": self.MAX_AGE,
|
215
|
+
}
|
216
|
+
|
217
|
+
# An origin included in the access_control_allow_origin list is OK with
|
218
|
+
# credentials
|
219
|
+
assert self._do("POST", {"Origin": self.ORIGIN1}, credentials=True, settings=settings) == {
|
220
|
+
"Cache-Control": "max-age=10, private",
|
221
|
+
"Content-Length": "0",
|
222
|
+
"Content-Type": "text/html; charset=UTF-8",
|
223
|
+
"Vary": "Origin, Access-Control-Request-Headers, Cookie, Authorization",
|
224
|
+
"Access-Control-Max-Age": self.MAX_AGE,
|
225
|
+
"Access-Control-Allow-Origin": self.ORIGIN1,
|
226
|
+
"Access-Control-Allow-Methods": CORS_METHODS,
|
227
|
+
"Access-Control-Allow-Credentials": "true",
|
228
|
+
}
|
229
|
+
|
230
|
+
# 3. Otherwise, add a single Access-Control-Allow-Origin header, with
|
231
|
+
# either the value of the Origin header or the string "*" as value.
|
232
|
+
assert self._do("POST", {"Origin": "http://www.guest.com"}, settings=settings) == {
|
233
|
+
"Cache-Control": "max-age=10, private",
|
234
|
+
"Content-Length": "0",
|
235
|
+
"Content-Type": "text/html; charset=UTF-8",
|
236
|
+
"Vary": "Origin, Access-Control-Request-Headers, Cookie, Authorization",
|
237
|
+
"Access-Control-Max-Age": self.MAX_AGE,
|
238
|
+
"Access-Control-Allow-Origin": "*",
|
239
|
+
"Access-Control-Allow-Methods": CORS_METHODS,
|
240
|
+
}
|
241
|
+
|
242
|
+
# 7. If the resource supports credentials add a single
|
243
|
+
# Access-Control-Allow-Origin header, with the value of the Origin
|
244
|
+
# header as value, and add a single Access-Control-Allow-Credentials
|
245
|
+
# header with the case-sensitive string "true" as value.
|
246
|
+
# but out of the allow list
|
247
|
+
assert self._do(
|
248
|
+
"OPTIONS",
|
249
|
+
{"Origin": "http://www.guest.com", "Access-Control-Request-Method": "GET"},
|
250
|
+
credentials=True,
|
251
|
+
settings=settings,
|
252
|
+
) == {
|
253
|
+
"Content-Length": "0",
|
254
|
+
"Content-Type": "text/html; charset=UTF-8",
|
255
|
+
"Vary": "Origin, Access-Control-Request-Headers, Access-Control-Request-Method",
|
256
|
+
"Access-Control-Allow-Origin": "*",
|
257
|
+
"Access-Control-Max-Age": self.MAX_AGE,
|
258
|
+
"Access-Control-Allow-Methods": CORS_METHODS,
|
259
|
+
"Cache-Control": "max-age=" + self.MAX_AGE,
|
260
|
+
}
|
261
|
+
|
262
|
+
def test_cache(self):
|
263
|
+
init_region({"backend": "dogpile.cache.memory"}, "std")
|
264
|
+
cache_version = get_cache_version()
|
265
|
+
assert cache_version == get_cache_version()
|
266
|
+
|
267
|
+
def test_cache_invalidation(self):
|
268
|
+
init_region({"backend": "dogpile.cache.memory"}, "std")
|
269
|
+
cache_version = get_cache_version()
|
270
|
+
invalidate_region()
|
271
|
+
assert cache_version != get_cache_version()
|
272
|
+
|
273
|
+
def test_nocache(self):
|
274
|
+
init_region({"backend": "dogpile.cache.null"}, "std")
|
275
|
+
assert get_cache_version() != get_cache_version()
|
tests/test_checker.py
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
# Copyright (c) 2013-2023, Camptocamp SA
|
2
|
+
# All rights reserved.
|
3
|
+
|
4
|
+
# Redistribution and use in source and binary forms, with or without
|
5
|
+
# modification, are permitted provided that the following conditions are met:
|
6
|
+
|
7
|
+
# 1. Redistributions of source code must retain the above copyright notice, this
|
8
|
+
# list of conditions and the following disclaimer.
|
9
|
+
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
10
|
+
# this list of conditions and the following disclaimer in the documentation
|
11
|
+
# and/or other materials provided with the distribution.
|
12
|
+
|
13
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
14
|
+
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
15
|
+
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
16
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
17
|
+
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
18
|
+
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
19
|
+
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
20
|
+
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
21
|
+
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
22
|
+
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
23
|
+
|
24
|
+
# The views and conclusions contained in the software and documentation are those
|
25
|
+
# of the authors and should not be interpreted as representing official policies,
|
26
|
+
# either expressed or implied, of the FreeBSD Project.
|
27
|
+
|
28
|
+
# pylint: disable=missing-docstring,attribute-defined-outside-init,protected-access
|
29
|
+
|
30
|
+
|
31
|
+
from unittest import TestCase
|
32
|
+
|
33
|
+
from tests import DummyRequest
|
34
|
+
|
35
|
+
from c2cgeoportal_geoportal.lib.checker import build_url
|
36
|
+
|
37
|
+
|
38
|
+
class TestExportCSVView(TestCase):
|
39
|
+
def test_build_url_docker(self):
|
40
|
+
request = DummyRequest()
|
41
|
+
request.registry.settings = {"checker": {"base_internal_url": "http://localhost:8080"}}
|
42
|
+
self.assertEqual(
|
43
|
+
build_url("Test", "/toto?titi#tutu", request),
|
44
|
+
{"url": "http://localhost:8080/toto?titi#tutu", "headers": {"Cache-Control": "no-cache"}},
|
45
|
+
)
|
46
|
+
|
47
|
+
def test_build_url_http(self):
|
48
|
+
request = DummyRequest()
|
49
|
+
request.registry.settings = {
|
50
|
+
"checker": {"base_internal_url": "http://localhost", "forward_host": True}
|
51
|
+
}
|
52
|
+
self.assertEqual(
|
53
|
+
build_url("Test", "/toto?titi#tutu", request),
|
54
|
+
{
|
55
|
+
"url": "http://localhost/toto?titi#tutu",
|
56
|
+
"headers": {"Cache-Control": "no-cache", "Host": "example.com:80"},
|
57
|
+
},
|
58
|
+
)
|
59
|
+
|
60
|
+
def test_build_url_https(self):
|
61
|
+
request = DummyRequest()
|
62
|
+
request.registry.settings = {
|
63
|
+
"checker": {"base_internal_url": "https://localhost", "forward_host": True}
|
64
|
+
}
|
65
|
+
self.assertEqual(
|
66
|
+
build_url("Test", "/toto?titi#tutu", request),
|
67
|
+
{
|
68
|
+
"url": "https://localhost/toto?titi#tutu",
|
69
|
+
"headers": {"Cache-Control": "no-cache", "Host": "example.com:80"},
|
70
|
+
},
|
71
|
+
)
|
72
|
+
|
73
|
+
def test_build_url_forward_headers(self):
|
74
|
+
request = DummyRequest()
|
75
|
+
request.registry.settings = {
|
76
|
+
"checker": {"base_internal_url": "http://localhost", "forward_headers": ["Cookie"]}
|
77
|
+
}
|
78
|
+
request.headers["Cookie"] = "test"
|
79
|
+
self.assertEqual(
|
80
|
+
build_url("Test", "/toto?titi#tutu", request),
|
81
|
+
{
|
82
|
+
"url": "http://localhost/toto?titi#tutu",
|
83
|
+
"headers": {"Cache-Control": "no-cache", "Cookie": "test"},
|
84
|
+
},
|
85
|
+
)
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# Copyright (c) 2011-2023, Camptocamp SA
|
2
|
+
# All rights reserved.
|
3
|
+
|
4
|
+
# Redistribution and use in source and binary forms, with or without
|
5
|
+
# modification, are permitted provided that the following conditions are met:
|
6
|
+
|
7
|
+
# 1. Redistributions of source code must retain the above copyright notice, this
|
8
|
+
# list of conditions and the following disclaimer.
|
9
|
+
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
10
|
+
# this list of conditions and the following disclaimer in the documentation
|
11
|
+
# and/or other materials provided with the distribution.
|
12
|
+
|
13
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
14
|
+
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
15
|
+
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
16
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
17
|
+
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
18
|
+
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
19
|
+
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
20
|
+
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
21
|
+
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
22
|
+
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
23
|
+
|
24
|
+
# The views and conclusions contained in the software and documentation are those
|
25
|
+
# of the authors and should not be interpreted as representing official policies,
|
26
|
+
# either expressed or implied, of the FreeBSD Project.
|
27
|
+
|
28
|
+
# pylint: disable=missing-docstring,attribute-defined-outside-init,protected-access
|
29
|
+
|
30
|
+
|
31
|
+
import decimal
|
32
|
+
import json
|
33
|
+
from unittest import TestCase
|
34
|
+
|
35
|
+
from c2cwsgiutils.pretty_json import _FastDumps as FastDumps
|
36
|
+
|
37
|
+
|
38
|
+
class TestDecimalJSON(TestCase):
|
39
|
+
def test_decimal(self):
|
40
|
+
value = {"str": "an str", "int": 1, "dec": decimal.Decimal("1.2")}
|
41
|
+
fast_dumps = FastDumps(False, False)
|
42
|
+
result = fast_dumps(value)
|
43
|
+
self.assertEqual(json.loads(result), {"int": 1, "dec": 1.2, "str": "an str"})
|
44
|
+
|
45
|
+
def test_decimal_json(self):
|
46
|
+
fast_dumps = FastDumps(False, False)
|
47
|
+
assert fast_dumps({"a": decimal.Decimal("3.3")}) == '{"a":3.3}'
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# Copyright (c) 2018-2023, Camptocamp SA
|
2
|
+
# All rights reserved.
|
3
|
+
|
4
|
+
# Redistribution and use in source and binary forms, with or without
|
5
|
+
# modification, are permitted provided that the following conditions are met:
|
6
|
+
|
7
|
+
# 1. Redistributions of source code must retain the above copyright notice, this
|
8
|
+
# list of conditions and the following disclaimer.
|
9
|
+
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
10
|
+
# this list of conditions and the following disclaimer in the documentation
|
11
|
+
# and/or other materials provided with the distribution.
|
12
|
+
|
13
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
14
|
+
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
15
|
+
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
16
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
17
|
+
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
18
|
+
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
19
|
+
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
20
|
+
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
21
|
+
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
22
|
+
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
23
|
+
|
24
|
+
# The views and conclusions contained in the software and documentation are those
|
25
|
+
# of the authors and should not be interpreted as representing official policies,
|
26
|
+
# either expressed or implied, of the FreeBSD Project.
|
27
|
+
|
28
|
+
# pylint: disable=missing-docstring,attribute-defined-outside-init,protected-access
|
29
|
+
|
30
|
+
|
31
|
+
from unittest import TestCase
|
32
|
+
|
33
|
+
import pyramid.registry
|
34
|
+
from tests import DummyRequest
|
35
|
+
|
36
|
+
|
37
|
+
def handler(request):
|
38
|
+
return request.response
|
39
|
+
|
40
|
+
|
41
|
+
class MyRequest(DummyRequest):
|
42
|
+
def __init__(self, path_info):
|
43
|
+
self.path_info = path_info
|
44
|
+
|
45
|
+
|
46
|
+
class TestCacheBuster(TestCase):
|
47
|
+
@classmethod
|
48
|
+
def setup_class(cls):
|
49
|
+
pass
|
50
|
+
|
51
|
+
def test_tween(self):
|
52
|
+
from c2cgeoportal_geoportal.lib.headers import HeadersTween
|
53
|
+
|
54
|
+
registry = pyramid.registry.Registry()
|
55
|
+
registry.settings = {"global_headers": [{"pattern": "^/test/.*", "headers": {"X-Test": "TOTO"}}]}
|
56
|
+
ht = HeadersTween(handler, registry)
|
57
|
+
|
58
|
+
request = MyRequest("/test/titi")
|
59
|
+
response = ht(request)
|
60
|
+
assert response.headers["X-Test"] == "TOTO"
|
61
|
+
|
62
|
+
request = MyRequest("/test2/titi")
|
63
|
+
response = ht(request)
|
64
|
+
assert "X-Test" not in response.headers
|
tests/test_i18n.py
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
from unittest import TestCase
|
2
|
+
from unittest.mock import patch
|
3
|
+
|
4
|
+
from c2cgeoportal_geoportal.lib.i18n import available_locale_names
|
5
|
+
|
6
|
+
example_locale_content = {
|
7
|
+
("de", True),
|
8
|
+
("en", True),
|
9
|
+
("fr", True),
|
10
|
+
(".emptyfolder", False),
|
11
|
+
("geomapfish_geoportal-client.pot", False),
|
12
|
+
}
|
13
|
+
|
14
|
+
|
15
|
+
class TestI18n(TestCase):
|
16
|
+
@patch("c2cgeoportal_geoportal.lib.i18n.os.path.exists", return_value=True)
|
17
|
+
@patch(
|
18
|
+
"c2cgeoportal_geoportal.lib.i18n.os.listdir",
|
19
|
+
return_value=[locale[0] for locale in example_locale_content],
|
20
|
+
)
|
21
|
+
@patch(
|
22
|
+
"c2cgeoportal_geoportal.lib.i18n.os.path.isdir",
|
23
|
+
side_effect=[locale[1] for locale in example_locale_content],
|
24
|
+
)
|
25
|
+
def test_available_locale_names(self, isdir_mock, listdir_mock, exists_mock):
|
26
|
+
locales = available_locale_names()
|
27
|
+
self.assertEqual(set(locales), {"de", "en", "fr"})
|
28
|
+
|
29
|
+
def test_available_locale_names_no_dir(self):
|
30
|
+
locales = available_locale_names()
|
31
|
+
assert locales == []
|