c2cgeoportal-geoportal 2.3.5.79__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.79.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.79.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.79.dist-info/DESCRIPTION.rst +0 -8
  194. c2cgeoportal_geoportal-2.3.5.79.dist-info/RECORD +0 -7
  195. c2cgeoportal_geoportal-2.3.5.79.dist-info/entry_points.txt +0 -22
  196. c2cgeoportal_geoportal-2.3.5.79.dist-info/metadata.json +0 -1
  197. c2cgeoportal_geoportal-2.3.5.79.dist-info/top_level.txt +0 -1
@@ -0,0 +1,193 @@
1
+ # Copyright (c) 2012-2024, Camptocamp SA
2
+ # All rights reserved.
3
+
4
+ # Redistribution and use in source and binary forms, with or without
5
+ # modification, are permitted provided that the following conditions are met:
6
+
7
+ # 1. Redistributions of source code must retain the above copyright notice, this
8
+ # list of conditions and the following disclaimer.
9
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
10
+ # this list of conditions and the following disclaimer in the documentation
11
+ # and/or other materials provided with the distribution.
12
+
13
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
14
+ # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15
+ # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
17
+ # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18
+ # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19
+ # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20
+ # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21
+ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22
+ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23
+
24
+ # The views and conclusions contained in the software and documentation are those
25
+ # of the authors and should not be interpreted as representing official policies,
26
+ # either expressed or implied, of the FreeBSD Project.
27
+
28
+
29
+ import decimal
30
+ import logging
31
+ import math
32
+ import os
33
+ import traceback
34
+ from typing import TYPE_CHECKING, Any
35
+
36
+ import numpy
37
+ import pyramid.request
38
+ import zope.event.classhandler
39
+ from pyramid.httpexceptions import HTTPBadRequest, HTTPNotFound
40
+ from pyramid.view import view_config
41
+ from rasterio.io import DatasetReader
42
+
43
+ from c2cgeoportal_commons.models import InvalidateCacheEvent
44
+ from c2cgeoportal_geoportal.lib.common_headers import Cache, set_common_headers
45
+
46
+ if TYPE_CHECKING:
47
+ import fiona.collection
48
+
49
+ _LOG = logging.getLogger(__name__)
50
+
51
+
52
+ class Raster:
53
+ """All the view concerned the raster (point, not the profile profile)."""
54
+
55
+ data: dict[str, "fiona.collection.Collection"] = {}
56
+
57
+ def __init__(self, request: pyramid.request.Request):
58
+ self.request = request
59
+ self.rasters = self.request.registry.settings["raster"]
60
+
61
+ @zope.event.classhandler.handler(InvalidateCacheEvent) # type: ignore
62
+ def handle(event: InvalidateCacheEvent) -> None:
63
+ del event
64
+ for _, v in Raster.data.items():
65
+ v.close()
66
+ Raster.data = {}
67
+
68
+ def _get_required_finite_float_param(self, name: str) -> float:
69
+ if name not in self.request.params:
70
+ raise HTTPBadRequest(f"'{name}' should be in the query string parameters")
71
+ try:
72
+ result = float(self.request.params[name])
73
+ except ValueError:
74
+ raise HTTPBadRequest( # pylint: disable=raise-missing-from
75
+ f"'{name}' ({self.request.params[name]}) parameters should be a number"
76
+ )
77
+ if not math.isfinite(result):
78
+ raise HTTPBadRequest(
79
+ f"'{name}' ({self.request.params[name]}) parameters should be a finite number"
80
+ )
81
+ return result
82
+
83
+ @view_config(route_name="raster", renderer="fast_json") # type: ignore
84
+ def raster(self) -> dict[str, Any]:
85
+ lon = self._get_required_finite_float_param("lon")
86
+ lat = self._get_required_finite_float_param("lat")
87
+
88
+ if "layers" in self.request.params:
89
+ rasters = {}
90
+ layers = self.request.params["layers"].split(",")
91
+ for layer in layers:
92
+ if layer in self.rasters:
93
+ rasters[layer] = self.rasters[layer]
94
+ else:
95
+ raise HTTPNotFound(f"Layer {layer} not found")
96
+ else:
97
+ rasters = self.rasters
98
+
99
+ result = {}
100
+ for ref in list(rasters.keys()):
101
+ result[ref] = self._get_raster_value(rasters[ref], ref, lon, lat)
102
+
103
+ set_common_headers(self.request, "raster", Cache.PUBLIC_NO)
104
+ return result
105
+
106
+ def _get_data(self, layer: dict[str, Any], name: str) -> "fiona.collection.Collection":
107
+ if name not in self.data:
108
+ path = layer["file"]
109
+ if layer.get("type", "shp_index") == "shp_index":
110
+ # Avoid loading if not needed
111
+ from fiona.collection import Collection # pylint: disable=import-outside-toplevel
112
+
113
+ self.data[name] = Collection(path)
114
+ elif layer.get("type") == "gdal":
115
+ # Avoid loading if not needed
116
+ import rasterio # pylint: disable=import-outside-toplevel
117
+
118
+ self.data[name] = rasterio.open(path)
119
+
120
+ return self.data[name]
121
+
122
+ def _get_raster_value(
123
+ self, layer: dict[str, Any], name: str, lon: float, lat: float
124
+ ) -> decimal.Decimal | None:
125
+ data = self._get_data(layer, name)
126
+ type_ = layer.get("type", "shp_index")
127
+ if type_ == "shp_index":
128
+ tiles = list(data.filter(mask={"type": "Point", "coordinates": [lon, lat]}))
129
+
130
+ if not tiles:
131
+ return None
132
+
133
+ path = os.path.join(os.path.dirname(layer["file"]), tiles[0]["properties"]["location"])
134
+
135
+ # Avoid loading if not needed
136
+ import rasterio # pylint: disable=import-outside-toplevel
137
+
138
+ with rasterio.open(path) as dataset:
139
+ result = self._get_value(layer, name, dataset, lon, lat)
140
+ elif type_ == "gdal":
141
+ result = self._get_value(layer, name, data, lon, lat)
142
+ else:
143
+ raise ValueError("Unsupported type " + type_)
144
+
145
+ result_d = None
146
+ if "round" in layer and result is not None:
147
+ result_d = self._round(result, layer["round"])
148
+ elif result is not None:
149
+ result_d = decimal.Decimal(str(result))
150
+
151
+ return result_d
152
+
153
+ @staticmethod
154
+ def _get_value(
155
+ layer: dict[str, Any], name: str, dataset: DatasetReader, lon: float, lat: float
156
+ ) -> numpy.float32 | None:
157
+ index = dataset.index(lon, lat)
158
+
159
+ shape = dataset.shape
160
+ result: numpy.float32 | None
161
+ if 0 <= index[0] < shape[0] and 0 <= index[1] < shape[1]:
162
+
163
+ def get_index(index_: int) -> tuple[int, int]:
164
+ return index_, index_ + 1
165
+
166
+ result = dataset.read(1, window=(get_index(index[0]), get_index(index[1])))[0][0]
167
+ result = None if result == layer.get("nodata", dataset.nodata) else result
168
+ else:
169
+ _LOG.debug(
170
+ "Out of index for layer: %s (%s), lon/lat: %dx%d, index: %dx%d, shape: %dx%d.",
171
+ name,
172
+ layer["file"],
173
+ lon,
174
+ lat,
175
+ index[0],
176
+ index[1],
177
+ dataset.shape[0],
178
+ dataset.shape[1],
179
+ )
180
+ result = None
181
+
182
+ return result
183
+
184
+ @staticmethod
185
+ def _round(value: numpy.float32, round_to: float) -> decimal.Decimal | None:
186
+ if value is not None:
187
+ decimal_value = decimal.Decimal(str(value))
188
+ try:
189
+ return decimal_value.quantize(decimal.Decimal(str(round_to)))
190
+ except decimal.InvalidOperation:
191
+ _LOG.info("Error on rounding %s: %s", decimal_value, traceback.format_exc())
192
+ return decimal_value
193
+ return None
@@ -0,0 +1,73 @@
1
+ # Copyright (c) 2011-2024, Camptocamp SA
2
+ # All rights reserved.
3
+
4
+ # Redistribution and use in source and binary forms, with or without
5
+ # modification, are permitted provided that the following conditions are met:
6
+
7
+ # 1. Redistributions of source code must retain the above copyright notice, this
8
+ # list of conditions and the following disclaimer.
9
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
10
+ # this list of conditions and the following disclaimer in the documentation
11
+ # and/or other materials provided with the distribution.
12
+
13
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
14
+ # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15
+ # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
17
+ # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18
+ # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19
+ # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20
+ # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21
+ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22
+ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23
+
24
+ # The views and conclusions contained in the software and documentation are those
25
+ # of the authors and should not be interpreted as representing official policies,
26
+ # either expressed or implied, of the FreeBSD Project.
27
+
28
+
29
+ import ast
30
+ import logging
31
+
32
+ import pyramid.request
33
+ import pyramid.response
34
+ from pyramid.httpexceptions import HTTPBadRequest
35
+ from pyramid.view import view_config
36
+
37
+ from c2cgeoportal_geoportal.lib.common_headers import Cache
38
+ from c2cgeoportal_geoportal.views.proxy import Proxy
39
+
40
+ _LOG = logging.getLogger(__name__)
41
+
42
+
43
+ class ResourceProxy(Proxy):
44
+ """All the views concerned the resources (it's a kind of proxy)."""
45
+
46
+ def __init__(self, request: pyramid.request.Request):
47
+ Proxy.__init__(self, request)
48
+ self.request = request
49
+ self.settings = request.registry.settings.get("resourceproxy", {})
50
+
51
+ @view_config(route_name="resourceproxy") # type: ignore
52
+ def proxy(self) -> pyramid.response.Response:
53
+ target = self.request.params.get("target", "")
54
+ targets = self.settings.get("targets", [])
55
+ if target in targets:
56
+ url = targets[target]
57
+ values = ast.literal_eval(self.request.params.get("values"))
58
+ url = url % values
59
+
60
+ response = self._proxy(url=url)
61
+
62
+ cache_control = Cache.PRIVATE_NO
63
+ content_type = response.headers["Content-Type"]
64
+
65
+ response = self._build_response(
66
+ response, response.content, cache_control, "externalresource", content_type=content_type
67
+ )
68
+ for header in response.headers.keys():
69
+ if header not in self.settings["allowed_headers"]:
70
+ response.headers.pop(header)
71
+ return response
72
+ _LOG.warning("Target URL not found: %s", target)
73
+ return HTTPBadRequest("URL not allowed")
@@ -0,0 +1,152 @@
1
+ # Copyright (c) 2013-2024, Camptocamp SA
2
+ # All rights reserved.
3
+
4
+ # Redistribution and use in source and binary forms, with or without
5
+ # modification, are permitted provided that the following conditions are met:
6
+
7
+ # 1. Redistributions of source code must retain the above copyright notice, this
8
+ # list of conditions and the following disclaimer.
9
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
10
+ # this list of conditions and the following disclaimer in the documentation
11
+ # and/or other materials provided with the distribution.
12
+
13
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
14
+ # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15
+ # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
17
+ # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18
+ # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19
+ # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20
+ # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21
+ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22
+ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23
+
24
+ # The views and conclusions contained in the software and documentation are those
25
+ # of the authors and should not be interpreted as representing official policies,
26
+ # either expressed or implied, of the FreeBSD Project.
27
+
28
+
29
+ import logging
30
+ import random
31
+ import string
32
+ from datetime import datetime
33
+ from typing import cast
34
+ from urllib.parse import urlparse
35
+
36
+ import pyramid.request
37
+ from pyramid.httpexceptions import HTTPBadRequest, HTTPFound, HTTPInternalServerError, HTTPNotFound
38
+ from pyramid.view import view_config
39
+
40
+ from c2cgeoportal_commons.lib.email_ import send_email_config
41
+ from c2cgeoportal_commons.models import DBSession, static
42
+ from c2cgeoportal_geoportal import is_allowed_url
43
+ from c2cgeoportal_geoportal.lib.common_headers import Cache, set_common_headers
44
+
45
+ logger = logging.getLogger(__name__)
46
+
47
+
48
+ class Shortener:
49
+ """All the views conserne the shortener."""
50
+
51
+ def __init__(self, request: pyramid.request.Request):
52
+ self.request = request
53
+ self.settings = request.registry.settings.get("shortener", {})
54
+ self.short_bases = [self.request.route_url("shortener_get", ref="")]
55
+ if "base_url" in self.settings:
56
+ self.short_bases.append(self.settings["base_url"])
57
+
58
+ @view_config(route_name="shortener_get") # type: ignore
59
+ def get(self) -> HTTPFound:
60
+ assert DBSession is not None
61
+
62
+ ref = self.request.matchdict["ref"]
63
+ short_urls = DBSession.query(static.Shorturl).filter(static.Shorturl.ref == ref).all()
64
+
65
+ if len(short_urls) != 1:
66
+ raise HTTPNotFound(f"Ref '{ref!s}' not found")
67
+
68
+ short_urls[0].nb_hits += 1
69
+ short_urls[0].last_hit = datetime.now()
70
+
71
+ set_common_headers(self.request, "shortener", Cache.PUBLIC_NO)
72
+ return HTTPFound(location=short_urls[0].url)
73
+
74
+ @view_config(route_name="shortener_create", renderer="json") # type: ignore
75
+ def create(self) -> dict[str, str]:
76
+ assert DBSession is not None
77
+
78
+ if "url" not in self.request.params:
79
+ raise HTTPBadRequest("The parameter url is required")
80
+
81
+ url = self.request.params["url"]
82
+
83
+ # see: https://httpd.apache.org/docs/2.2/mod/core.html#limitrequestline
84
+ if len(url) > 8190:
85
+ raise HTTPBadRequest(f"The parameter url is too long ({len(url)} > {8190})")
86
+
87
+ allowed_hosts = self.settings.get("allowed_hosts", [])
88
+ url_hostname, ok = is_allowed_url(self.request, url, allowed_hosts)
89
+ if not ok:
90
+ message = (
91
+ f"Invalid requested host '{url_hostname}', "
92
+ f"is not the current host '{self.request.host}' "
93
+ f"or part of allowed hosts: {', '.join(allowed_hosts)}"
94
+ )
95
+ logging.debug(message)
96
+ raise HTTPBadRequest(message)
97
+
98
+ shortened = False
99
+
100
+ uri_parts = urlparse(url)
101
+ for base in self.short_bases:
102
+ base_parts = urlparse(base)
103
+ if uri_parts.path.startswith(base_parts.path):
104
+ shortened = True
105
+ ref = uri_parts.path.split("/")[-1]
106
+
107
+ tries = 0
108
+ while not shortened:
109
+ ref = "".join(
110
+ random.choice(string.ascii_letters + string.digits) # nosec
111
+ for i in range(self.settings.get("length", 4))
112
+ )
113
+ test_url = DBSession.query(static.Shorturl).filter(static.Shorturl.ref == ref).all()
114
+ if not test_url:
115
+ break
116
+ tries += 1
117
+ if tries > 20:
118
+ message = "No free ref found, considered to increase the length"
119
+ logger.error(message)
120
+ raise HTTPInternalServerError(message)
121
+
122
+ user_email = cast(static.User, self.request.user).email if self.request.user is not None else None
123
+ email = self.request.params.get("email")
124
+ if not shortened:
125
+ short_url = static.Shorturl()
126
+ short_url.url = url
127
+ short_url.ref = ref
128
+ short_url.creator_email = user_email
129
+ short_url.creation = datetime.now()
130
+ short_url.nb_hits = 0
131
+
132
+ DBSession.add(short_url)
133
+
134
+ if "base_url" in self.settings:
135
+ s_url = self.settings["base_url"] + ref
136
+ else:
137
+ s_url = self.request.route_url("shortener_get", ref=ref)
138
+
139
+ if email is not None:
140
+ send_email_config(
141
+ self.request.registry.settings,
142
+ "shortener",
143
+ email,
144
+ full_url=url,
145
+ short_url=s_url,
146
+ message=self.request.params.get("message", ""),
147
+ application_url=self.request.route_url("base"),
148
+ current_url=self.request.current_route_url(),
149
+ )
150
+
151
+ set_common_headers(self.request, "shortener", Cache.PRIVATE_NO)
152
+ return {"short_url": s_url}