c2cgeoportal-geoportal 2.3.5.80__py3-none-any.whl → 2.9rc1__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.
Files changed (197) hide show
  1. c2cgeoportal_geoportal/__init__.py +960 -0
  2. c2cgeoportal_geoportal/lib/__init__.py +256 -0
  3. c2cgeoportal_geoportal/lib/authentication.py +250 -0
  4. c2cgeoportal_geoportal/lib/bashcolor.py +46 -0
  5. c2cgeoportal_geoportal/lib/cacheversion.py +75 -0
  6. c2cgeoportal_geoportal/lib/caching.py +176 -0
  7. c2cgeoportal_geoportal/lib/check_collector.py +80 -0
  8. c2cgeoportal_geoportal/lib/checker.py +295 -0
  9. c2cgeoportal_geoportal/lib/common_headers.py +170 -0
  10. c2cgeoportal_geoportal/lib/dbreflection.py +266 -0
  11. c2cgeoportal_geoportal/lib/filter_capabilities.py +360 -0
  12. c2cgeoportal_geoportal/lib/fulltextsearch.py +50 -0
  13. c2cgeoportal_geoportal/lib/functionality.py +166 -0
  14. c2cgeoportal_geoportal/lib/headers.py +62 -0
  15. c2cgeoportal_geoportal/lib/i18n.py +38 -0
  16. c2cgeoportal_geoportal/lib/layers.py +132 -0
  17. c2cgeoportal_geoportal/lib/lingva_extractor.py +937 -0
  18. c2cgeoportal_geoportal/lib/loader.py +57 -0
  19. c2cgeoportal_geoportal/lib/metrics.py +117 -0
  20. c2cgeoportal_geoportal/lib/oauth2.py +1186 -0
  21. c2cgeoportal_geoportal/lib/oidc.py +302 -0
  22. c2cgeoportal_geoportal/lib/wmstparsing.py +353 -0
  23. c2cgeoportal_geoportal/lib/xsd.py +166 -0
  24. c2cgeoportal_geoportal/py.typed +0 -0
  25. c2cgeoportal_geoportal/resources.py +49 -0
  26. c2cgeoportal_geoportal/scaffolds/advance_create/ci/config.yaml +26 -0
  27. c2cgeoportal_geoportal/scaffolds/advance_create/cookiecutter.json +18 -0
  28. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/.dockerignore +6 -0
  29. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/.eslintrc.yaml +19 -0
  30. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/.prospector.yaml +30 -0
  31. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/Dockerfile +75 -0
  32. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/Makefile +6 -0
  33. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/alembic.ini +58 -0
  34. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/alembic.yaml +19 -0
  35. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/development.ini +121 -0
  36. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/gunicorn.conf.py +139 -0
  37. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/language_mapping +3 -0
  38. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/lingva-client.cfg +5 -0
  39. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/lingva-server.cfg +6 -0
  40. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/production.ini +38 -0
  41. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/requirements.txt +2 -0
  42. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/setup.py +25 -0
  43. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/webpack.api.js +41 -0
  44. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/webpack.apps.js +64 -0
  45. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/webpack.commons.js +11 -0
  46. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/webpack.config.js +22 -0
  47. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/__init__.py +42 -0
  48. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/authentication.py +10 -0
  49. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/dev.py +14 -0
  50. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/models.py +8 -0
  51. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/multi_organization.py +7 -0
  52. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/resources.py +11 -0
  53. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static-ngeo/api/index.js +12 -0
  54. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static-ngeo/js/{{cookiecutter.package}}module.js +25 -0
  55. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/subscribers.py +39 -0
  56. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/views/__init__.py +0 -0
  57. c2cgeoportal_geoportal/scaffolds/advance_update/cookiecutter.json +18 -0
  58. c2cgeoportal_geoportal/scaffolds/advance_update/{{cookiecutter.project}}/geoportal/CONST_Makefile +121 -0
  59. c2cgeoportal_geoportal/scaffolds/create/cookiecutter.json +18 -0
  60. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.dockerignore +14 -0
  61. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.editorconfig +17 -0
  62. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.github/workflows/main.yaml +73 -0
  63. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.github/workflows/rebuild.yaml +50 -0
  64. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.github/workflows/update_l10n.yaml +66 -0
  65. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.gitignore +16 -0
  66. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.pre-commit-config.yaml +35 -0
  67. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.prettierignore +1 -0
  68. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.prettierrc.yaml +2 -0
  69. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/Dockerfile +75 -0
  70. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/Makefile +70 -0
  71. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/README.rst +29 -0
  72. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/build +179 -0
  73. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/ci/config.yaml +22 -0
  74. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/ci/docker-compose-check +25 -0
  75. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/ci/requirements.txt +2 -0
  76. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/docker-compose-db.yaml +24 -0
  77. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/docker-compose-lib.yaml +511 -0
  78. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/docker-compose-qgis.yaml +21 -0
  79. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/docker-compose.override.sample.yaml +59 -0
  80. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/docker-compose.yaml +121 -0
  81. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/env.default +102 -0
  82. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/env.project +69 -0
  83. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/geoportal/vars.yaml +430 -0
  84. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/locale/en/LC_MESSAGES/{{cookiecutter.package}}_geoportal-client.po +6 -0
  85. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static/css/desktop.css +0 -0
  86. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static/css/iframe_api.css +0 -0
  87. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static/css/mobile.css +0 -0
  88. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static/images/banner_left.png +0 -0
  89. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static/images/banner_right.png +0 -0
  90. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static/images/blank.png +0 -0
  91. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static/images/markers/marker-blue.png +0 -0
  92. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static/images/markers/marker-gold.png +0 -0
  93. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static/images/markers/marker-green.png +0 -0
  94. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static/images/markers/marker.png +0 -0
  95. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static/robot.txt.tmpl +3 -0
  96. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/data/Readme.txt +69 -0
  97. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/data/TM_EUROPE_BORDERS-0.3.sql +70 -0
  98. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/demo.map.tmpl +224 -0
  99. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/fonts/Arial.ttf +0 -0
  100. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/fonts/Arialbd.ttf +0 -0
  101. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/fonts/Arialbi.ttf +0 -0
  102. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/fonts/Ariali.ttf +0 -0
  103. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/fonts/NotoSans-Bold.ttf +0 -0
  104. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/fonts/NotoSans-BoldItalic.ttf +0 -0
  105. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/fonts/NotoSans-Italic.ttf +0 -0
  106. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/fonts/NotoSans-Regular.ttf +0 -0
  107. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/fonts/Verdana.ttf +0 -0
  108. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/fonts/Verdanab.ttf +0 -0
  109. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/fonts/Verdanai.ttf +0 -0
  110. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/fonts/Verdanaz.ttf +0 -0
  111. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/fonts.conf +12 -0
  112. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/mapserver.conf +15 -0
  113. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/mapserver.map.tmpl +87 -0
  114. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/tinyows.xml.tmpl +36 -0
  115. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}/A3_Landscape.jrxml +207 -0
  116. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}/A3_Portrait.jrxml +185 -0
  117. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}/A4_Landscape.jrxml +200 -0
  118. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}/A4_Portrait.jrxml +170 -0
  119. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}/config.yaml.tmpl +175 -0
  120. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}/legend.jrxml +109 -0
  121. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}/localisation.properties +4 -0
  122. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}/localisation_fr.properties +4 -0
  123. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}/logo.png +0 -0
  124. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}/north.svg +93 -0
  125. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}/results.jrxml +25 -0
  126. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/project.yaml +18 -0
  127. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/pyproject.toml +7 -0
  128. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/qgisserver/pg_service.conf.tmpl +15 -0
  129. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/run_alembic.sh +11 -0
  130. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/scripts/db-backup +126 -0
  131. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/scripts/db-restore +132 -0
  132. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/setup.cfg +7 -0
  133. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/spell-ignore-words.txt +5 -0
  134. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/tests/__init__.py +0 -0
  135. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/tests/test_app.py +43 -0
  136. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/tilegeneration/config.yaml.tmpl +195 -0
  137. c2cgeoportal_geoportal/scaffolds/update/cookiecutter.json +18 -0
  138. c2cgeoportal_geoportal/scaffolds/update/{{cookiecutter.project}}/.upgrade.yaml +67 -0
  139. c2cgeoportal_geoportal/scaffolds/update/{{cookiecutter.project}}/CONST_CHANGELOG.txt +295 -0
  140. c2cgeoportal_geoportal/scaffolds/update/{{cookiecutter.project}}/CONST_create_template/tests/test_testapp.py +48 -0
  141. c2cgeoportal_geoportal/scaffolds/update/{{cookiecutter.project}}/geoportal/CONST_config-schema.yaml +922 -0
  142. c2cgeoportal_geoportal/scaffolds/update/{{cookiecutter.project}}/geoportal/CONST_vars.yaml +1503 -0
  143. c2cgeoportal_geoportal/scripts/__init__.py +64 -0
  144. c2cgeoportal_geoportal/scripts/c2cupgrade.py +879 -0
  145. c2cgeoportal_geoportal/scripts/create_demo_theme.py +80 -0
  146. c2cgeoportal_geoportal/scripts/manage_users.py +140 -0
  147. c2cgeoportal_geoportal/scripts/pcreate.py +314 -0
  148. c2cgeoportal_geoportal/scripts/theme2fts.py +347 -0
  149. c2cgeoportal_geoportal/scripts/urllogin.py +81 -0
  150. c2cgeoportal_geoportal/templates/login.html +90 -0
  151. c2cgeoportal_geoportal/templates/notlogin.html +62 -0
  152. c2cgeoportal_geoportal/templates/testi18n.html +12 -0
  153. c2cgeoportal_geoportal/views/__init__.py +59 -0
  154. c2cgeoportal_geoportal/views/dev.py +57 -0
  155. c2cgeoportal_geoportal/views/dynamic.py +208 -0
  156. c2cgeoportal_geoportal/views/entry.py +174 -0
  157. c2cgeoportal_geoportal/views/fulltextsearch.py +189 -0
  158. c2cgeoportal_geoportal/views/geometry_processing.py +75 -0
  159. c2cgeoportal_geoportal/views/i18n.py +129 -0
  160. c2cgeoportal_geoportal/views/layers.py +713 -0
  161. c2cgeoportal_geoportal/views/login.py +679 -0
  162. c2cgeoportal_geoportal/views/mapserverproxy.py +191 -0
  163. c2cgeoportal_geoportal/views/memory.py +90 -0
  164. c2cgeoportal_geoportal/views/ogcproxy.py +120 -0
  165. c2cgeoportal_geoportal/views/pdfreport.py +245 -0
  166. c2cgeoportal_geoportal/views/printproxy.py +143 -0
  167. c2cgeoportal_geoportal/views/profile.py +127 -0
  168. c2cgeoportal_geoportal/views/proxy.py +259 -0
  169. c2cgeoportal_geoportal/views/raster.py +193 -0
  170. c2cgeoportal_geoportal/views/resourceproxy.py +73 -0
  171. c2cgeoportal_geoportal/views/shortener.py +152 -0
  172. c2cgeoportal_geoportal/views/theme.py +1322 -0
  173. c2cgeoportal_geoportal/views/tinyowsproxy.py +189 -0
  174. c2cgeoportal_geoportal/views/vector_tiles.py +83 -0
  175. {c2cgeoportal_geoportal-2.3.5.80.dist-info → c2cgeoportal_geoportal-2.9rc1.dist-info}/METADATA +21 -24
  176. c2cgeoportal_geoportal-2.9rc1.dist-info/RECORD +192 -0
  177. {c2cgeoportal_geoportal-2.3.5.80.dist-info → c2cgeoportal_geoportal-2.9rc1.dist-info}/WHEEL +1 -1
  178. c2cgeoportal_geoportal-2.9rc1.dist-info/entry_points.txt +28 -0
  179. c2cgeoportal_geoportal-2.9rc1.dist-info/top_level.txt +2 -0
  180. tests/__init__.py +100 -0
  181. tests/test_cachebuster.py +71 -0
  182. tests/test_caching.py +275 -0
  183. tests/test_checker.py +85 -0
  184. tests/test_decimaljson.py +47 -0
  185. tests/test_headerstween.py +64 -0
  186. tests/test_i18n.py +31 -0
  187. tests/test_init.py +193 -0
  188. tests/test_locale_negociator.py +69 -0
  189. tests/test_mapserverproxy_route_predicate.py +64 -0
  190. tests/test_raster.py +267 -0
  191. tests/test_wmstparsing.py +238 -0
  192. tests/xmlstr.py +103 -0
  193. c2cgeoportal_geoportal-2.3.5.80.dist-info/DESCRIPTION.rst +0 -8
  194. c2cgeoportal_geoportal-2.3.5.80.dist-info/RECORD +0 -7
  195. c2cgeoportal_geoportal-2.3.5.80.dist-info/entry_points.txt +0 -22
  196. c2cgeoportal_geoportal-2.3.5.80.dist-info/metadata.json +0 -1
  197. c2cgeoportal_geoportal-2.3.5.80.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-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.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, public",
65
+ "Content-Length": "0",
66
+ "Content-Type": "text/html; charset=UTF-8",
67
+ "Vary": "Origin, Cookie",
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, public",
75
+ "Content-Length": "0",
76
+ "Content-Type": "text/html; charset=UTF-8",
77
+ "Vary": "Origin, Cookie",
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, public",
86
+ "Content-Length": "0",
87
+ "Content-Type": "text/html; charset=UTF-8",
88
+ "Vary": "Origin, Cookie",
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",
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",
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",
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",
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",
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",
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, public",
206
+ "Content-Length": "0",
207
+ "Content-Type": "text/html; charset=UTF-8",
208
+ "Vary": "Origin, Cookie",
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, public",
221
+ "Content-Length": "0",
222
+ "Content-Type": "text/html; charset=UTF-8",
223
+ "Vary": "Origin, Cookie",
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, public",
234
+ "Content-Length": "0",
235
+ "Content-Type": "text/html; charset=UTF-8",
236
+ "Vary": "Origin, Cookie",
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",
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 == []