c2cgeoportal-geoportal 2.5.0.100__py2.py3-none-any.whl → 2.7.1.156__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (224) hide show
  1. c2cgeoportal_geoportal/__init__.py +261 -130
  2. c2cgeoportal_geoportal/lib/__init__.py +74 -120
  3. c2cgeoportal_geoportal/lib/authentication.py +170 -21
  4. c2cgeoportal_geoportal/lib/bashcolor.py +17 -13
  5. c2cgeoportal_geoportal/lib/cacheversion.py +19 -11
  6. c2cgeoportal_geoportal/lib/caching.py +66 -160
  7. c2cgeoportal_geoportal/lib/check_collector.py +17 -10
  8. c2cgeoportal_geoportal/lib/checker.py +62 -64
  9. c2cgeoportal_geoportal/lib/common_headers.py +170 -0
  10. c2cgeoportal_geoportal/lib/dbreflection.py +70 -31
  11. c2cgeoportal_geoportal/lib/filter_capabilities.py +127 -97
  12. c2cgeoportal_geoportal/lib/fulltextsearch.py +50 -0
  13. c2cgeoportal_geoportal/lib/functionality.py +36 -21
  14. c2cgeoportal_geoportal/lib/headers.py +14 -5
  15. c2cgeoportal_geoportal/lib/i18n.py +39 -0
  16. c2cgeoportal_geoportal/lib/layers.py +29 -10
  17. c2cgeoportal_geoportal/lib/lingua_extractor.py +408 -211
  18. c2cgeoportal_geoportal/lib/loader.py +18 -16
  19. c2cgeoportal_geoportal/lib/metrics.py +29 -18
  20. c2cgeoportal_geoportal/lib/oauth2.py +1036 -0
  21. c2cgeoportal_geoportal/lib/wmstparsing.py +115 -90
  22. c2cgeoportal_geoportal/lib/xsd.py +29 -19
  23. c2cgeoportal_geoportal/resources.py +15 -9
  24. c2cgeoportal_geoportal/scaffolds/advance_create/ci/config.yaml +26 -0
  25. c2cgeoportal_geoportal/scaffolds/advance_create/cookiecutter.json +18 -0
  26. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/.dockerignore +6 -0
  27. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/.eslintrc.yaml +19 -0
  28. c2cgeoportal_geoportal/scaffolds/{create/+dot+prospector.yaml → advance_create/{{cookiecutter.project}}/geoportal/.prospector.yaml} +8 -4
  29. c2cgeoportal_geoportal/scaffolds/{create/geoportal/Dockerfile_tmpl → advance_create/{{cookiecutter.project}}/geoportal/Dockerfile} +24 -15
  30. c2cgeoportal_geoportal/scaffolds/{create → advance_create/{{cookiecutter.project}}}/geoportal/alembic.ini +1 -0
  31. c2cgeoportal_geoportal/scaffolds/{create/geoportal/alembic.yaml_tmpl → advance_create/{{cookiecutter.project}}/geoportal/alembic.yaml} +1 -1
  32. c2cgeoportal_geoportal/scaffolds/{create/geoportal/development.ini_tmpl → advance_create/{{cookiecutter.project}}/geoportal/development.ini} +34 -15
  33. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/gunicorn.conf.py +102 -0
  34. c2cgeoportal_geoportal/scaffolds/{create → advance_create/{{cookiecutter.project}}}/geoportal/lingua-client.cfg +1 -0
  35. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/production.ini +38 -0
  36. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/requirements.txt +2 -0
  37. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/setup.py +25 -0
  38. c2cgeoportal_geoportal/scaffolds/{create → advance_create/{{cookiecutter.project}}}/geoportal/tools/extract-messages.js +8 -6
  39. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/tsconfig.json +8 -0
  40. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/webpack.api.js +75 -0
  41. c2cgeoportal_geoportal/scaffolds/{create/geoportal/webpack.apps.js_tmpl → advance_create/{{cookiecutter.project}}/geoportal/webpack.apps.js} +31 -28
  42. c2cgeoportal_geoportal/scaffolds/{create → advance_create/{{cookiecutter.project}}}/geoportal/webpack.commons.js +3 -7
  43. c2cgeoportal_geoportal/scaffolds/{create → advance_create/{{cookiecutter.project}}}/geoportal/webpack.config.js +4 -4
  44. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/__init__.py +47 -0
  45. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/authentication.py +10 -0
  46. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/dev.py +14 -0
  47. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/models.py +8 -0
  48. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/multi_organization.py +7 -0
  49. c2cgeoportal_geoportal/scaffolds/{create/geoportal/+package+_geoportal → advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal}/resources.py +4 -3
  50. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static-ngeo/api/index.js +12 -0
  51. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static-ngeo/js/{{cookiecutter.package}}module.js +25 -0
  52. c2cgeoportal_geoportal/scaffolds/{create/geoportal/+package+_geoportal/subscribers.py_tmpl → advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/subscribers.py} +3 -6
  53. c2cgeoportal_geoportal/scaffolds/advance_update/cookiecutter.json +18 -0
  54. c2cgeoportal_geoportal/scaffolds/{update/geoportal/CONST_Makefile_tmpl → advance_update/{{cookiecutter.project}}/geoportal/CONST_Makefile} +32 -20
  55. c2cgeoportal_geoportal/scaffolds/create/cookiecutter.json +18 -0
  56. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.dockerignore +14 -0
  57. c2cgeoportal_geoportal/scaffolds/create/{+dot+editorconfig → {{cookiecutter.project}}/.editorconfig} +4 -8
  58. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.github/workflows/main.yaml +43 -0
  59. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.github/workflows/rebuild.yaml +46 -0
  60. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.github/workflows/update_l10n.yaml +65 -0
  61. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.gitignore +16 -0
  62. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.prettierignore +1 -0
  63. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.prettierrc.yaml +2 -0
  64. c2cgeoportal_geoportal/scaffolds/create/{Dockerfile_tmpl → {{cookiecutter.project}}/Dockerfile} +34 -24
  65. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/Makefile +14 -0
  66. c2cgeoportal_geoportal/scaffolds/create/{README.rst_tmpl → {{cookiecutter.project}}/README.rst} +4 -4
  67. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/build +162 -0
  68. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/ci/config.yaml +25 -0
  69. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/ci/requirements.txt +1 -0
  70. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/docker-compose-lib.yaml +474 -0
  71. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/docker-compose.override.sample.yaml +67 -0
  72. c2cgeoportal_geoportal/scaffolds/create/{docker-compose.yaml → {{cookiecutter.project}}/docker-compose.yaml} +43 -18
  73. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/env.default +82 -0
  74. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/env.project +60 -0
  75. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/geoportal/vars.yaml +396 -0
  76. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static/css/mobile.css +0 -0
  77. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static/images/markers/marker-blue.png +0 -0
  78. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static/images/markers/marker-gold.png +0 -0
  79. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static/images/markers/marker-green.png +0 -0
  80. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static/images/markers/marker.png +0 -0
  81. c2cgeoportal_geoportal/scaffolds/create/{mapserver → {{cookiecutter.project}}/mapserver}/data/Readme.txt +1 -1
  82. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/demo.map.tmpl +224 -0
  83. c2cgeoportal_geoportal/scaffolds/create/{mapserver/mapserver.map.tmpl_tmpl → {{cookiecutter.project}}/mapserver/mapserver.map.tmpl} +7 -15
  84. c2cgeoportal_geoportal/scaffolds/create/{print/print-apps/+package+ → {{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}}/A3_Landscape.jrxml +17 -9
  85. c2cgeoportal_geoportal/scaffolds/create/{print/print-apps/+package+ → {{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}}/A3_Portrait.jrxml +17 -9
  86. c2cgeoportal_geoportal/scaffolds/create/{print/print-apps/+package+ → {{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}}/A4_Landscape.jrxml +17 -9
  87. c2cgeoportal_geoportal/scaffolds/create/{print/print-apps/+package+ → {{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}}/A4_Portrait.jrxml +17 -9
  88. c2cgeoportal_geoportal/scaffolds/create/{print/print-apps/+package+ → {{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}}/config.yaml.tmpl +30 -27
  89. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}/legend.jrxml +109 -0
  90. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}/localisation.properties +4 -0
  91. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}/localisation_fr.properties +4 -0
  92. c2cgeoportal_geoportal/scaffolds/create/{project.yaml_tmpl → {{cookiecutter.project}}/project.yaml} +6 -6
  93. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/pyproject.toml +3 -0
  94. c2cgeoportal_geoportal/scaffolds/create/{qgisserver/pg_service.conf.tmpl_tmpl → {{cookiecutter.project}}/qgisserver/pg_service.conf.tmpl} +2 -2
  95. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/scripts/db-backup +110 -0
  96. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/scripts/db-restore +114 -0
  97. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/setup.cfg +7 -0
  98. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/spell-ignore-words.txt +3 -0
  99. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/tilegeneration/config.yaml.tmpl +195 -0
  100. c2cgeoportal_geoportal/scaffolds/update/cookiecutter.json +18 -0
  101. c2cgeoportal_geoportal/scaffolds/update/{{cookiecutter.project}}/.upgrade.yaml +191 -0
  102. c2cgeoportal_geoportal/scaffolds/update/{{cookiecutter.project}}/CONST_CHANGELOG.txt +1160 -0
  103. c2cgeoportal_geoportal/scaffolds/update/{geoportal → {{cookiecutter.project}}/geoportal}/CONST_config-schema.yaml +99 -47
  104. c2cgeoportal_geoportal/scaffolds/update/{{cookiecutter.project}}/geoportal/CONST_vars.yaml +1410 -0
  105. c2cgeoportal_geoportal/scripts/__init__.py +18 -32
  106. c2cgeoportal_geoportal/scripts/c2cupgrade.py +295 -200
  107. c2cgeoportal_geoportal/scripts/create_demo_theme.py +5 -6
  108. c2cgeoportal_geoportal/scripts/manage_users.py +34 -37
  109. c2cgeoportal_geoportal/scripts/pcreate.py +312 -0
  110. c2cgeoportal_geoportal/scripts/theme2fts.py +92 -25
  111. c2cgeoportal_geoportal/scripts/urllogin.py +23 -17
  112. c2cgeoportal_geoportal/templates/login.html +88 -84
  113. c2cgeoportal_geoportal/templates/notlogin.html +62 -0
  114. c2cgeoportal_geoportal/templates/testi18n.html +6 -8
  115. c2cgeoportal_geoportal/views/__init__.py +23 -4
  116. c2cgeoportal_geoportal/views/dev.py +9 -7
  117. c2cgeoportal_geoportal/views/dynamic.py +71 -40
  118. c2cgeoportal_geoportal/views/entry.py +93 -24
  119. c2cgeoportal_geoportal/views/fulltextsearch.py +36 -29
  120. c2cgeoportal_geoportal/views/geometry_processing.py +15 -7
  121. c2cgeoportal_geoportal/views/i18n.py +91 -9
  122. c2cgeoportal_geoportal/views/layers.py +173 -134
  123. c2cgeoportal_geoportal/views/login.py +206 -87
  124. c2cgeoportal_geoportal/views/mapserverproxy.py +59 -35
  125. c2cgeoportal_geoportal/views/memory.py +13 -13
  126. c2cgeoportal_geoportal/views/ogcproxy.py +48 -30
  127. c2cgeoportal_geoportal/views/pdfreport.py +31 -27
  128. c2cgeoportal_geoportal/views/printproxy.py +70 -54
  129. c2cgeoportal_geoportal/views/profile.py +25 -24
  130. c2cgeoportal_geoportal/views/proxy.py +100 -70
  131. c2cgeoportal_geoportal/views/raster.py +47 -29
  132. c2cgeoportal_geoportal/views/resourceproxy.py +13 -11
  133. c2cgeoportal_geoportal/views/shortener.py +31 -24
  134. c2cgeoportal_geoportal/views/theme.py +475 -365
  135. c2cgeoportal_geoportal/views/tinyowsproxy.py +46 -39
  136. c2cgeoportal_geoportal/views/vector_tiles.py +80 -0
  137. {c2cgeoportal_geoportal-2.5.0.100.dist-info → c2cgeoportal_geoportal-2.7.1.156.dist-info}/METADATA +17 -11
  138. c2cgeoportal_geoportal-2.7.1.156.dist-info/RECORD +185 -0
  139. {c2cgeoportal_geoportal-2.5.0.100.dist-info → c2cgeoportal_geoportal-2.7.1.156.dist-info}/WHEEL +1 -1
  140. {c2cgeoportal_geoportal-2.5.0.100.dist-info → c2cgeoportal_geoportal-2.7.1.156.dist-info}/entry_points.txt +3 -1
  141. tests/__init__.py +24 -3
  142. tests/test_cachebuster.py +1 -3
  143. tests/test_caching.py +19 -26
  144. tests/test_checker.py +2 -3
  145. tests/test_decimaljson.py +4 -4
  146. tests/test_headerstween.py +0 -3
  147. tests/test_i18n.py +31 -0
  148. tests/test_init.py +12 -27
  149. tests/test_locale_negociator.py +6 -6
  150. tests/test_mapserverproxy_route_predicate.py +0 -2
  151. tests/test_raster.py +18 -5
  152. tests/test_wmstparsing.py +7 -8
  153. c2cgeoportal_geoportal/scaffolds/__init__.py +0 -226
  154. c2cgeoportal_geoportal/scaffolds/create/+dot+dockerignore_tmpl +0 -11
  155. c2cgeoportal_geoportal/scaffolds/create/+dot+github/workflows/ci.yaml_tmpl +0 -56
  156. c2cgeoportal_geoportal/scaffolds/create/+dot+gitignore_tmpl +0 -12
  157. c2cgeoportal_geoportal/scaffolds/create/build_tmpl +0 -144
  158. c2cgeoportal_geoportal/scaffolds/create/docker-compose-lib.yaml_tmpl +0 -302
  159. c2cgeoportal_geoportal/scaffolds/create/docker-compose.override.sample.yaml_tmpl +0 -54
  160. c2cgeoportal_geoportal/scaffolds/create/env.default_tmpl +0 -49
  161. c2cgeoportal_geoportal/scaffolds/create/env.project_tmpl +0 -39
  162. c2cgeoportal_geoportal/scaffolds/create/geoportal/+dot+dockerignore_tmpl +0 -5
  163. c2cgeoportal_geoportal/scaffolds/create/geoportal/+dot+eslintrc_tmpl +0 -19
  164. c2cgeoportal_geoportal/scaffolds/create/geoportal/+package+_geoportal/__init__.py_tmpl +0 -48
  165. c2cgeoportal_geoportal/scaffolds/create/geoportal/+package+_geoportal/models.py_tmpl +0 -10
  166. c2cgeoportal_geoportal/scaffolds/create/geoportal/+package+_geoportal/static/images/favicon.ico +0 -0
  167. c2cgeoportal_geoportal/scaffolds/create/geoportal/+package+_geoportal/static/robot.txt +0 -3
  168. c2cgeoportal_geoportal/scaffolds/create/geoportal/+package+_geoportal/static-ngeo/api/index.js_tmpl +0 -37
  169. c2cgeoportal_geoportal/scaffolds/create/geoportal/+package+_geoportal/static-ngeo/js/+package+module.js_tmpl +0 -22
  170. c2cgeoportal_geoportal/scaffolds/create/geoportal/production.ini_tmpl +0 -106
  171. c2cgeoportal_geoportal/scaffolds/create/geoportal/requirements.txt +0 -2
  172. c2cgeoportal_geoportal/scaffolds/create/geoportal/setup.py_tmpl +0 -18
  173. c2cgeoportal_geoportal/scaffolds/create/geoportal/tsconfig.json_tmpl +0 -9
  174. c2cgeoportal_geoportal/scaffolds/create/geoportal/vars.yaml_tmpl +0 -224
  175. c2cgeoportal_geoportal/scaffolds/create/geoportal/webpack.api.js_tmpl +0 -71
  176. c2cgeoportal_geoportal/scaffolds/create/mapserver/demo.map.tmpl_tmpl +0 -262
  177. c2cgeoportal_geoportal/scaffolds/create/mapserver/tinyows.xml +0 -36
  178. c2cgeoportal_geoportal/scaffolds/create/print/print-apps/+package+/config.yaml +0 -166
  179. c2cgeoportal_geoportal/scaffolds/create/print/print-apps/+package+/legend.jrxml +0 -27
  180. c2cgeoportal_geoportal/scaffolds/create/qgisserver/geomapfish.yaml.tmpl_tmpl +0 -29
  181. c2cgeoportal_geoportal/scaffolds/create/scripts/publish-docker +0 -124
  182. c2cgeoportal_geoportal/scaffolds/create/setup.cfg_tmpl +0 -3
  183. c2cgeoportal_geoportal/scaffolds/create/spell-ignore-words.txt +0 -1
  184. c2cgeoportal_geoportal/scaffolds/create/tilegeneration/config.yaml.tmpl_tmpl +0 -169
  185. c2cgeoportal_geoportal/scaffolds/create/yamllint.yaml +0 -11
  186. c2cgeoportal_geoportal/scaffolds/update/+dot+upgrade.yaml_tmpl +0 -171
  187. c2cgeoportal_geoportal/scaffolds/update/CONST_CHANGELOG.txt_tmpl +0 -64
  188. c2cgeoportal_geoportal/scaffolds/update/geoportal/CONST_vars.yaml_tmpl +0 -783
  189. c2cgeoportal_geoportal/templates/dynamic.js +0 -21
  190. c2cgeoportal_geoportal-2.5.0.100.dist-info/RECORD +0 -162
  191. tests/test_get_url.py +0 -96
  192. tests/test_lib.py +0 -77
  193. /c2cgeoportal_geoportal/{scaffolds/create/geoportal/+package+_geoportal/static/css/desktop.css → py.typed} +0 -0
  194. /c2cgeoportal_geoportal/scaffolds/{create/geoportal/Makefile_tmpl → advance_create/{{cookiecutter.project}}/geoportal/Makefile} +0 -0
  195. /c2cgeoportal_geoportal/scaffolds/{create → advance_create/{{cookiecutter.project}}}/geoportal/language_mapping +0 -0
  196. /c2cgeoportal_geoportal/scaffolds/{create → advance_create/{{cookiecutter.project}}}/geoportal/lingua-server.cfg +0 -0
  197. /c2cgeoportal_geoportal/scaffolds/{create/geoportal/+package+_geoportal → advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal}/views/__init__.py +0 -0
  198. /c2cgeoportal_geoportal/scaffolds/create/{geoportal/+package+_geoportal/locale/en/LC_MESSAGES/+package+_geoportal-client.po → {{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/locale/en/LC_MESSAGES/{{cookiecutter.package}}_geoportal-client.po} +0 -0
  199. /c2cgeoportal_geoportal/scaffolds/create/{geoportal/+package+_geoportal/static/css/iframe_api.css → {{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static/css/desktop.css} +0 -0
  200. /c2cgeoportal_geoportal/scaffolds/create/{geoportal/+package+_geoportal/static/css/mobile.css → {{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/static/css/iframe_api.css} +0 -0
  201. /c2cgeoportal_geoportal/scaffolds/create/{geoportal/+package+_geoportal → {{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal}/static/images/banner_left.png +0 -0
  202. /c2cgeoportal_geoportal/scaffolds/create/{geoportal/+package+_geoportal → {{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal}/static/images/banner_right.png +0 -0
  203. /c2cgeoportal_geoportal/scaffolds/create/{geoportal/+package+_geoportal → {{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal}/static/images/blank.png +0 -0
  204. /c2cgeoportal_geoportal/scaffolds/create/{geoportal/+package+_geoportal → {{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal}/static/robot.txt.tmpl +0 -0
  205. /c2cgeoportal_geoportal/scaffolds/create/{mapserver → {{cookiecutter.project}}/mapserver}/data/TM_EUROPE_BORDERS-0.3.sql +0 -0
  206. /c2cgeoportal_geoportal/scaffolds/create/{mapserver → {{cookiecutter.project}}/mapserver}/fonts/Arial.ttf +0 -0
  207. /c2cgeoportal_geoportal/scaffolds/create/{mapserver → {{cookiecutter.project}}/mapserver}/fonts/Arialbd.ttf +0 -0
  208. /c2cgeoportal_geoportal/scaffolds/create/{mapserver → {{cookiecutter.project}}/mapserver}/fonts/Arialbi.ttf +0 -0
  209. /c2cgeoportal_geoportal/scaffolds/create/{mapserver → {{cookiecutter.project}}/mapserver}/fonts/Ariali.ttf +0 -0
  210. /c2cgeoportal_geoportal/scaffolds/create/{mapserver → {{cookiecutter.project}}/mapserver}/fonts/NotoSans-Bold.ttf +0 -0
  211. /c2cgeoportal_geoportal/scaffolds/create/{mapserver → {{cookiecutter.project}}/mapserver}/fonts/NotoSans-BoldItalic.ttf +0 -0
  212. /c2cgeoportal_geoportal/scaffolds/create/{mapserver → {{cookiecutter.project}}/mapserver}/fonts/NotoSans-Italic.ttf +0 -0
  213. /c2cgeoportal_geoportal/scaffolds/create/{mapserver → {{cookiecutter.project}}/mapserver}/fonts/NotoSans-Regular.ttf +0 -0
  214. /c2cgeoportal_geoportal/scaffolds/create/{mapserver → {{cookiecutter.project}}/mapserver}/fonts/Verdana.ttf +0 -0
  215. /c2cgeoportal_geoportal/scaffolds/create/{mapserver → {{cookiecutter.project}}/mapserver}/fonts/Verdanab.ttf +0 -0
  216. /c2cgeoportal_geoportal/scaffolds/create/{mapserver → {{cookiecutter.project}}/mapserver}/fonts/Verdanai.ttf +0 -0
  217. /c2cgeoportal_geoportal/scaffolds/create/{mapserver → {{cookiecutter.project}}/mapserver}/fonts/Verdanaz.ttf +0 -0
  218. /c2cgeoportal_geoportal/scaffolds/create/{mapserver → {{cookiecutter.project}}/mapserver}/fonts.conf +0 -0
  219. /c2cgeoportal_geoportal/scaffolds/create/{mapserver → {{cookiecutter.project}}/mapserver}/tinyows.xml.tmpl +0 -0
  220. /c2cgeoportal_geoportal/scaffolds/create/{print/print-apps/+package+ → {{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}}/logo.png +0 -0
  221. /c2cgeoportal_geoportal/scaffolds/create/{print/print-apps/+package+ → {{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}}/north.svg +0 -0
  222. /c2cgeoportal_geoportal/scaffolds/create/{print/print-apps/+package+ → {{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}}/results.jrxml +0 -0
  223. /c2cgeoportal_geoportal/scaffolds/create/{run_alembic.sh → {{cookiecutter.project}}/run_alembic.sh} +0 -0
  224. {c2cgeoportal_geoportal-2.5.0.100.dist-info → c2cgeoportal_geoportal-2.7.1.156.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,4 @@
1
- # -*- coding: utf-8 -*-
2
-
3
- # Copyright (c) 2011-2020, Camptocamp SA
1
+ # Copyright (c) 2011-2021, Camptocamp SA
4
2
  # All rights reserved.
5
3
 
6
4
  # Redistribution and use in source and binary forms, with or without
@@ -27,46 +25,53 @@
27
25
  # of the authors and should not be interpreted as representing official policies,
28
26
  # either expressed or implied, of the FreeBSD Project.
29
27
 
30
- import binascii
31
28
  import importlib
32
- import json
33
29
  import logging
34
30
  import os
35
- import re
36
- import time
31
+ from functools import partial
32
+ from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, cast
37
33
  from urllib.parse import urlsplit
38
34
 
39
- from Crypto.Cipher import AES # nosec
40
35
  import c2cgeoform
41
- from c2cgeoform import Form, translator
42
36
  import c2cwsgiutils
43
37
  import c2cwsgiutils.db
44
- from c2cwsgiutils.health_check import HealthCheck
45
38
  import c2cwsgiutils.index
39
+ import pyramid.config
40
+ import pyramid.renderers
41
+ import pyramid.request
42
+ import pyramid.response
43
+ import pyramid.security
44
+ import zope.event.classhandler
45
+ from c2cgeoform import Form, translator
46
+ from c2cwsgiutils.broadcast import decorator
47
+ from c2cwsgiutils.health_check import HealthCheck
46
48
  from c2cwsgiutils.metrics import MemoryMapProvider, add_provider
47
49
  from dogpile.cache import register_backend
48
50
  from papyrus.renderers import GeoJSON
49
51
  from pyramid.config import Configurator
50
52
  from pyramid.httpexceptions import HTTPException
51
53
  from pyramid.path import AssetResolver
52
- import pyramid.security
53
54
  from pyramid_mako import add_mako_renderer
54
- from sqlalchemy.orm import Session
55
- import zope.event.classhandler
55
+ from sqlalchemy.orm import Session, joinedload
56
56
 
57
57
  import c2cgeoportal_commons.models
58
+ import c2cgeoportal_geoportal.views
58
59
  from c2cgeoportal_commons.models import InvalidateCacheEvent
59
60
  from c2cgeoportal_geoportal.lib import C2CPregenerator, caching, check_collector, checker
60
61
  from c2cgeoportal_geoportal.lib.cacheversion import version_cache_buster
61
- from c2cgeoportal_geoportal.lib.caching import NO_CACHE, set_common_headers
62
+ from c2cgeoportal_geoportal.lib.common_headers import Cache, set_common_headers
63
+ from c2cgeoportal_geoportal.lib.i18n import available_locale_names
62
64
  from c2cgeoportal_geoportal.lib.metrics import (
63
65
  MemoryCacheSizeProvider,
64
66
  RasterDataSizeProvider,
65
67
  TotalPythonObjectMemoryProvider,
66
68
  )
67
69
  from c2cgeoportal_geoportal.lib.xsd import XSD
68
- import c2cgeoportal_geoportal.views
69
- from c2cgeoportal_geoportal.views.entry import Entry
70
+ from c2cgeoportal_geoportal.views.entry import Entry, canvas_view
71
+
72
+ if TYPE_CHECKING:
73
+ from c2cgeoportal_commons.models import static # pylint: disable=ungrouped-imports,useless-suppression
74
+
70
75
 
71
76
  LOG = logging.getLogger(__name__)
72
77
 
@@ -76,64 +81,145 @@ GEOJSON_CONTENT_TYPE = r"Content-Type:application/geo\+json"
76
81
 
77
82
 
78
83
  class AssetRendererFactory:
79
- def __init__(self, info):
84
+ """Get a renderer for the assets."""
85
+
86
+ def __init__(self, info: Any):
80
87
  del info # unused
81
88
  self.resolver = AssetResolver("c2cgeoportal_geoportal")
82
89
 
83
- def __call__(self, value, system):
90
+ def __call__(self, value: Any, system: Dict[str, str]) -> bytes:
91
+ del value
84
92
  asset = self.resolver.resolve(system["renderer_name"])
85
- return asset.stream().read()
93
+ return cast(bytes, asset.stream().read())
86
94
 
87
95
 
88
96
  INTERFACE_TYPE_NGEO = "ngeo"
97
+ INTERFACE_TYPE_CANVAS = "canvas"
89
98
 
90
99
 
91
- def add_interface(
92
- config, interface_name="desktop", interface_type=INTERFACE_TYPE_NGEO, default=False, **kwargs
93
- ): # pragma: no cover
94
- del interface_type # unused
95
- route = "/" if default else "/{}".format(interface_name)
96
- add_interface_ngeo(
100
+ def add_interface_config(config: pyramid.config.Configurator, interface_config: Dict[str, Any]) -> None:
101
+ """Add the interface (desktop, mobile, ...) views and routes with only the config."""
102
+ add_interface(
97
103
  config,
98
- route_name=interface_name,
99
- route=route,
100
- renderer="/etc/static-ngeo/{}.html".format(interface_name),
101
- **kwargs,
104
+ interface_config["name"],
105
+ interface_config.get("type", INTERFACE_TYPE_NGEO),
106
+ interface_config,
107
+ default=interface_config.get("default", False),
102
108
  )
103
109
 
104
110
 
105
- def add_interface_ngeo(config, route_name, route, renderer=None, permission=None): # pragma: no cover
111
+ def add_interface(
112
+ config: pyramid.config.Configurator,
113
+ interface_name: str = "desktop",
114
+ interface_type: str = INTERFACE_TYPE_NGEO,
115
+ interface_config: Optional[Dict[str, Any]] = None,
116
+ default: bool = False,
117
+ **kwargs: Any,
118
+ ) -> None:
119
+ """Add the interface (desktop, mobile, ...) views and routes."""
120
+ route = "/" if default else f"/{interface_name}"
121
+ if interface_type == INTERFACE_TYPE_NGEO:
122
+ add_interface_ngeo(
123
+ config,
124
+ route_name=interface_name,
125
+ route=route,
126
+ renderer=f"/etc/static-ngeo/{interface_name}.html",
127
+ **kwargs,
128
+ )
129
+ elif interface_type == INTERFACE_TYPE_CANVAS:
130
+ assert interface_config is not None
131
+ add_interface_canvas(
132
+ config,
133
+ route_name=interface_name,
134
+ route=route,
135
+ interface_config=interface_config,
136
+ **kwargs,
137
+ )
138
+ else:
139
+ LOG.error(
140
+ "Unknown interface type '%s', should be '%s' or '%s'.",
141
+ interface_type,
142
+ INTERFACE_TYPE_NGEO,
143
+ INTERFACE_TYPE_CANVAS,
144
+ )
145
+
146
+
147
+ def add_interface_ngeo(
148
+ config: pyramid.config.Configurator,
149
+ route_name: str,
150
+ route: str,
151
+ renderer: Optional[str] = None,
152
+ permission: Optional[str] = None,
153
+ ) -> None:
154
+ """Add the ngeo interfaces views and routes."""
106
155
 
107
156
  config.add_route(route_name, route, request_method="GET")
108
- config.add_view(
109
- Entry, attr="get_ngeo_index_vars", route_name=route_name, renderer=renderer, permission=permission
110
- )
111
157
  # Permalink theme: recover the theme for generating custom viewer.js url
112
158
  config.add_route(
113
- "{}theme".format(route_name),
114
- "{}{}theme/{{themes}}".format(route, "" if route[-1] == "/" else "/"),
159
+ f"{route_name}theme",
160
+ f"{route}{'' if route[-1] == '/' else '/'}theme/{{themes}}",
115
161
  request_method="GET",
116
162
  )
163
+ config.add_view(
164
+ Entry, attr="get_ngeo_index_vars", route_name=route_name, renderer=renderer, permission=permission
165
+ )
117
166
  config.add_view(
118
167
  Entry,
119
168
  attr="get_ngeo_index_vars",
120
- route_name="{}theme".format(route_name),
169
+ route_name=f"{route_name}theme",
170
+ renderer=renderer,
171
+ permission=permission,
172
+ )
173
+
174
+
175
+ def add_interface_canvas(
176
+ config: pyramid.config.Configurator,
177
+ route_name: str,
178
+ route: str,
179
+ interface_config: Dict[str, Any],
180
+ permission: Optional[str] = None,
181
+ ) -> None:
182
+ """Add the ngeo interfaces views and routes."""
183
+
184
+ renderer = f"/etc/geomapfish/interfaces/{route_name}.html.mako"
185
+ config.add_route(route_name, route, request_method="GET")
186
+ # Permalink theme: recover the theme for generating custom viewer.js URL
187
+ config.add_route(
188
+ f"{route_name}theme",
189
+ f"{route}{'' if route[-1] == '/' else '/'}theme/{{themes}}",
190
+ request_method="GET",
191
+ )
192
+ view = partial(canvas_view, interface_config=interface_config)
193
+ view.__module__ = canvas_view.__module__
194
+ config.add_view(
195
+ view,
196
+ route_name=route_name,
197
+ renderer=renderer,
198
+ permission=permission,
199
+ )
200
+ config.add_view(
201
+ view,
202
+ route_name=f"{route_name}theme",
121
203
  renderer=renderer,
122
204
  permission=permission,
123
205
  )
124
206
 
125
207
 
126
- def add_admin_interface(config):
208
+ def add_admin_interface(config: pyramid.config.Configurator) -> None:
209
+ """Add the administration interface views and routes."""
127
210
  if config.get_settings().get("enable_admin_interface", False):
128
211
  config.add_request_method(
129
- lambda request: c2cgeoportal_commons.models.DBSession(), "dbsession", reify=True,
212
+ lambda request: c2cgeoportal_commons.models.DBSession(),
213
+ "dbsession",
214
+ reify=True,
130
215
  )
131
216
  config.add_view(c2cgeoportal_geoportal.views.add_ending_slash, route_name="admin_add_ending_slash")
132
217
  config.add_route("admin_add_ending_slash", "/admin", request_method="GET")
133
218
  config.include("c2cgeoportal_admin")
134
219
 
135
220
 
136
- def add_getitfixed(config):
221
+ def add_getitfixed(config: pyramid.config.Configurator) -> None:
222
+ """Add the get it fixed views and routes."""
137
223
  if config.get_settings()["getitfixed"].get("enabled", False):
138
224
  for route_name, pattern in (
139
225
  ("getitfixed_add_ending_slash", "/getitfixed"),
@@ -146,8 +232,9 @@ def add_getitfixed(config):
146
232
  Form.set_zpt_renderer(c2cgeoform.default_search_paths, translator=translator)
147
233
 
148
234
 
149
- def locale_negotiator(request):
150
- lang = request.params.get("lang")
235
+ def locale_negotiator(request: pyramid.request.Request) -> str:
236
+ """Get the current language."""
237
+ lang: str = request.params.get("lang")
151
238
  if lang is None:
152
239
  lang = request.cookies.get("_LOCALE_")
153
240
  else:
@@ -161,30 +248,34 @@ def locale_negotiator(request):
161
248
  return lang
162
249
 
163
250
 
164
- def _match_url_start(reference, value):
165
- """
166
- Checks that the val URL starts like the ref URL.
167
- """
251
+ def _match_url_start(reference: str, value: List[str]) -> bool:
252
+ """Check that the val URL starts like the ref URL."""
168
253
  reference_parts = reference.rstrip("/").split("/")
169
- # fmt: off
170
- value_parts = value[0:len(reference_parts)]
171
- # fmt: on
254
+ value_parts = value[0 : len(reference_parts)]
172
255
  return reference_parts == value_parts
173
256
 
174
257
 
175
- def is_valid_referer(request, settings=None):
258
+ def is_valid_referrer(request: pyramid.request.Request, settings: Optional[Dict[str, Any]] = None) -> bool:
259
+ """Check if the referrer is valid."""
176
260
  if request.referer is not None:
177
- referer = urlsplit(request.referer)._replace(query="", fragment="").geturl().rstrip("/").split("/")
261
+ referrer = urlsplit(request.referer)._replace(query="", fragment="").geturl().rstrip("/").split("/")
178
262
  if settings is None:
179
263
  settings = request.registry.settings
180
264
  list_ = settings.get("authorized_referers", [])
181
- return any(_match_url_start(e, referer) for e in list_)
265
+ return any(_match_url_start(e, referrer) for e in list_)
182
266
  return True
183
267
 
184
268
 
185
- def create_get_user_from_request(settings):
186
- def get_user_from_request(request, username=None):
187
- """ Return the User object for the request.
269
+ def create_get_user_from_request(
270
+ settings: Dict[str, Any]
271
+ ) -> Callable[[pyramid.request.Request, Optional[str]], Optional["static.User"]]:
272
+ """Get the get_user_from_request function."""
273
+
274
+ def get_user_from_request(
275
+ request: pyramid.request.Request, username: Optional[str] = None
276
+ ) -> Optional["static.User"]:
277
+ """
278
+ Return the User object for the request.
188
279
 
189
280
  Return ``None`` if:
190
281
  * user is anonymous
@@ -194,35 +285,8 @@ def create_get_user_from_request(settings):
194
285
  from c2cgeoportal_commons.models import DBSession # pylint: disable=import-outside-toplevel
195
286
  from c2cgeoportal_commons.models.static import User # pylint: disable=import-outside-toplevel
196
287
 
197
- try:
198
- if request.method == "GET" and "auth" in request.params:
199
- auth_enc = request.params.get("auth")
200
-
201
- if auth_enc is not None:
202
- urllogin = request.registry.settings.get("urllogin", {})
203
- aeskey = urllogin.get("aes_key")
204
- if aeskey is None: # pragma: nocover
205
- raise Exception("urllogin is not configured")
206
- now = int(time.time())
207
- data = binascii.unhexlify(auth_enc.encode("ascii"))
208
- nonce = data[0:16]
209
- tag = data[16:32]
210
- ciphertext = data[32:]
211
- cipher = AES.new(aeskey.encode("ascii"), AES.MODE_EAX, nonce)
212
- auth = json.loads(
213
- cipher.decrypt_and_verify(ciphertext, tag).decode("utf-8") # type: ignore
214
- )
215
-
216
- if "t" in auth and "u" in auth and "p" in auth:
217
- timestamp = int(auth["t"])
218
- if now < timestamp and request.registry.validate_user(request, auth["u"], auth["p"]):
219
- headers = pyramid.security.remember(request, auth["u"])
220
- request.response.headerlist.extend(headers)
221
- except Exception as e:
222
- LOG.error("URL login error: %s.", e, exc_info=True)
223
-
224
288
  if not hasattr(request, "is_valid_referer"):
225
- request.is_valid_referer = is_valid_referer(request, settings)
289
+ request.is_valid_referer = is_valid_referrer(request, settings)
226
290
  if not request.is_valid_referer:
227
291
  LOG.debug("Invalid referer for %s: %s", request.path_qs, repr(request.referer))
228
292
  return None
@@ -234,15 +298,20 @@ def create_get_user_from_request(settings):
234
298
  if username is not None:
235
299
  # We know we will need the role object of the
236
300
  # user so we use joined loading
237
- request.user_ = DBSession.query(User).filter_by(username=username).first()
301
+ request.user_ = (
302
+ DBSession.query(User).filter_by(username=username).options(joinedload("roles")).first()
303
+ )
238
304
 
239
- return request.user_
305
+ return cast(User, request.user_)
240
306
 
241
307
  return get_user_from_request
242
308
 
243
309
 
244
- def set_user_validator(config, user_validator):
245
- """ Call this function to register a user validator function.
310
+ def set_user_validator(
311
+ config: pyramid.config.Configurator, user_validator: Callable[[pyramid.request.Request, str, str], str]
312
+ ) -> None:
313
+ """
314
+ Call this function to register a user validator function.
246
315
 
247
316
  The validator function is passed three arguments: ``request``,
248
317
  ``username``, and ``password``. The function should return the
@@ -258,11 +327,12 @@ def set_user_validator(config, user_validator):
258
327
  config.action("user_validator", register)
259
328
 
260
329
 
261
- def default_user_validator(request, username, password):
330
+ def default_user_validator(request: pyramid.request.Request, username: str, password: str) -> Optional[str]:
262
331
  """
263
- Validate the username/password. This is c2cgeoportal's
264
- default user validator.
265
- Return None if we are anonymous, the string to remember otherwise.
332
+ Validate the username/password.
333
+
334
+ This is c2cgeoportal's default user validator. Return None if we are anonymous, the string to remember
335
+ otherwise.
266
336
  """
267
337
  del request # unused
268
338
  from c2cgeoportal_commons.models import DBSession # pylint: disable=import-outside-toplevel
@@ -270,7 +340,7 @@ def default_user_validator(request, username, password):
270
340
 
271
341
  user = DBSession.query(User).filter_by(username=username).first()
272
342
  if user is None:
273
- LOG.info('Unknow user "%s" tried to log in', username)
343
+ LOG.info('Unknown user "%s" tried to log in', username)
274
344
  return None
275
345
  if user.deactivated:
276
346
  LOG.info('Deactivated user "%s" tried to log in', username)
@@ -285,49 +355,52 @@ def default_user_validator(request, username, password):
285
355
 
286
356
 
287
357
  class MapserverproxyRoutePredicate:
288
- """ Serve as a custom route predicate function for mapserverproxy.
289
- If the hide_capabilities setting is set and is true then we want to
290
- return 404s on GetCapabilities requests."""
358
+ """
359
+ Serve as a custom route predicate function for mapserverproxy.
360
+
361
+ If the hide_capabilities setting is set and is true then we want to return 404s on GetCapabilities
362
+ requests.
363
+ """
291
364
 
292
- def __init__(self, val, config):
293
- pass
365
+ def __init__(self, val: Any, config: pyramid.config.Configurator) -> None:
366
+ del val, config
294
367
 
295
- def __call__(self, context, request):
368
+ def __call__(self, context: Any, request: pyramid.request.Request) -> bool:
369
+ del context
296
370
  hide_capabilities = request.registry.settings.get("hide_capabilities")
297
371
  if not hide_capabilities:
298
372
  return True
299
- params = dict((k.lower(), v.lower()) for k, v in request.params.items())
373
+ params = {k.lower(): v.lower() for k, v in request.params.items()}
300
374
  return "request" not in params or params["request"] not in ("getcapabilities", "capabilities")
301
375
 
302
376
  @staticmethod
303
- def text():
377
+ def text() -> str:
304
378
  return "mapserverproxy"
305
379
 
306
380
  phash = text
307
381
 
308
382
 
309
- def add_cors_route(config, pattern, service):
310
- """
311
- Add the OPTIONS route and view need for services supporting CORS.
312
- """
383
+ def add_cors_route(config: pyramid.config.Configurator, pattern: str, service: str) -> None:
384
+ """Add the OPTIONS route and view need for services supporting CORS."""
313
385
 
314
- def view(request): # pragma: no cover
315
- return set_common_headers(request, service, NO_CACHE)
386
+ def view(request: pyramid.request.Request) -> pyramid.response.Response:
387
+ return set_common_headers(request, service, Cache.PRIVATE_NO)
316
388
 
317
389
  name = pattern + "_options"
318
390
  config.add_route(name, pattern, request_method="OPTIONS")
319
391
  config.add_view(view, route_name=name)
320
392
 
321
393
 
322
- def error_handler(http_exception, request): # pragma: no cover
323
- """
324
- View callable for handling all the exceptions that are not already handled.
325
- """
394
+ def error_handler(
395
+ http_exception: HTTPException, request: pyramid.request.Request
396
+ ) -> pyramid.response.Response:
397
+ """View callable for handling all the exceptions that are not already handled."""
326
398
  LOG.warning("%s returned status code %s", request.url, http_exception.status_code)
327
- return caching.set_common_headers(request, "error", caching.NO_CACHE, http_exception)
399
+ return set_common_headers(request, "error", Cache.PRIVATE_NO, http_exception)
328
400
 
329
401
 
330
- def call_hook(settings, name, *args, **kwargs):
402
+ def call_hook(settings: pyramid.config.Configurator, name: str, *args: Any, **kwargs: Any) -> None:
403
+ """Call the hook defined in the settings."""
331
404
  hooks = settings.get("hooks", {})
332
405
  hook = hooks.get(name)
333
406
  if hook is None:
@@ -338,24 +411,32 @@ def call_hook(settings, name, *args, **kwargs):
338
411
  function_(*args, **kwargs)
339
412
 
340
413
 
341
- def includeme(config: pyramid.config.Configurator):
342
- """
343
- This function returns a Pyramid WSGI application.
344
- """
345
-
414
+ def includeme(config: pyramid.config.Configurator) -> None:
415
+ """Get the Pyramid WSGI application."""
346
416
  settings = config.get_settings()
347
417
 
348
- config.include("c2cgeoportal_commons")
418
+ if "available_locale_names" not in settings:
419
+ settings["available_locale_names"] = available_locale_names()
349
420
 
350
421
  call_hook(settings, "after_settings", settings)
351
422
 
352
423
  get_user_from_request = create_get_user_from_request(settings)
353
424
  config.add_request_method(get_user_from_request, name="user", property=True)
354
425
  config.add_request_method(get_user_from_request, name="get_user")
426
+ # Be able for an organization to override the method to use alternate:
427
+ # - Organization roles name for the standard roles 'anonymous', 'registered' and 'intranet'.
428
+ config.add_request_method(lambda request, role_type: role_type, name="get_organization_role")
429
+ # - Organization print URL
430
+ config.add_request_method(
431
+ lambda request: request.registry.settings["print_url"], name="get_organization_print_url"
432
+ )
433
+ # - Organization interface name (in the config and in the admin interface)
434
+ config.add_request_method(lambda request, interface: interface, name="get_organization_interface")
355
435
 
356
436
  # Configure 'locale' dir as the translation dir for c2cgeoportal app
357
437
  config.add_translation_dirs("c2cgeoportal_geoportal:locale/")
358
438
 
439
+ config.include("pyramid_mako")
359
440
  config.include("c2cwsgiutils.pyramid.includeme")
360
441
  health_check = HealthCheck(config)
361
442
  config.registry["health_check"] = health_check
@@ -373,28 +454,31 @@ def includeme(config: pyramid.config.Configurator):
373
454
  add_provider(TotalPythonObjectMemoryProvider())
374
455
 
375
456
  # Initialise DBSessions
376
- init_dbsessions(settings, config, health_check)
457
+ init_db_sessions(settings, config, health_check)
377
458
 
378
459
  checker.init(config, health_check)
379
460
  check_collector.init(config, health_check)
380
461
 
381
462
  # dogpile.cache configuration
382
463
  if "cache" in settings:
383
- register_backend("c2cgeoportal.hybrid", "c2cgeoportal_geoportal.lib.caching", "HybridBackend")
464
+ register_backend("c2cgeoportal.hybrid", "c2cgeoportal_geoportal.lib.caching", "HybridRedisBackend")
465
+ register_backend(
466
+ "c2cgeoportal.hybridsentinel", "c2cgeoportal_geoportal.lib.caching", "HybridRedisSentinelBackend"
467
+ )
384
468
  for name, cache_config in settings["cache"].items():
385
469
  caching.init_region(cache_config, name)
386
470
 
387
- @zope.event.classhandler.handler(InvalidateCacheEvent)
388
- def handle(event: InvalidateCacheEvent): # pylint: disable=unused-variable
471
+ @zope.event.classhandler.handler(InvalidateCacheEvent) # type: ignore
472
+ def handle(event: InvalidateCacheEvent) -> None:
389
473
  del event
390
474
  caching.invalidate_region()
391
475
  if caching.MEMORY_CACHE_DICT:
392
- caching.get_region("std").delete_multi(caching.MEMORY_CACHE_DICT.keys())
476
+ caching.get_region("std").delete_multi(list(caching.MEMORY_CACHE_DICT.keys()))
393
477
  caching.MEMORY_CACHE_DICT.clear()
394
478
 
395
479
  # Register a tween to get back the cache buster path.
396
480
  if "cache_path" not in config.get_settings():
397
- config.get_settings()["cache_path"] = ["static"]
481
+ config.get_settings()["cache_path"] = ["static", "static-geomapfish"]
398
482
  config.add_tween("c2cgeoportal_geoportal.lib.cacheversion.CachebusterTween")
399
483
  config.add_tween("c2cgeoportal_geoportal.lib.headers.HeadersTween")
400
484
 
@@ -412,6 +496,10 @@ def includeme(config: pyramid.config.Configurator):
412
496
  config.add_directive("set_user_validator", set_user_validator)
413
497
  config.set_user_validator(default_user_validator)
414
498
 
499
+ config.add_route("oauth2token", "/oauth/token", request_method="POST")
500
+ config.add_route("oauth2loginform", "/oauth/login", request_method="GET")
501
+ config.add_route("notlogin", "/notlogin", request_method="GET")
502
+
415
503
  config.add_route("dynamic", "/dynamic.json", request_method="GET")
416
504
 
417
505
  # Add routes to the mapserver proxy
@@ -430,6 +518,22 @@ def includeme(config: pyramid.config.Configurator):
430
518
  pregenerator=C2CPregenerator(role=True),
431
519
  request_method="POST",
432
520
  )
521
+ # The tow next views are used to serve the application on the URL /mapserv_proxy/<ogc server name>
522
+ # instead of /mapserv_proxy?ogcserver=<ogc server name>, required for QGIS server landing page
523
+ config.add_route(
524
+ "mapserverproxy_get_path",
525
+ "/mapserv_proxy/{ogcserver}/*path",
526
+ mapserverproxy=True,
527
+ pregenerator=C2CPregenerator(role=True),
528
+ request_method="GET",
529
+ )
530
+ config.add_route(
531
+ "mapserverproxy_post_path",
532
+ "/mapserv_proxy/{ogcserver}/*path",
533
+ mapserverproxy=True,
534
+ pregenerator=C2CPregenerator(role=True),
535
+ request_method="POST",
536
+ )
433
537
  add_cors_route(config, "/mapserv_proxy", "mapserver")
434
538
 
435
539
  # Add route to the tinyows proxy
@@ -454,14 +558,15 @@ def includeme(config: pyramid.config.Configurator):
454
558
  config.add_renderer(".css", AssetRendererFactory)
455
559
  config.add_renderer(".ico", AssetRendererFactory)
456
560
  config.add_route("localejson", "/locale.json", request_method="GET")
561
+ config.add_route("localepot", "/locale.pot", request_method="GET")
457
562
 
458
- def add_static_route(name: str, attr: str, path: str, renderer: str):
563
+ def add_static_route(name: str, attr: str, path: str, renderer: str) -> None:
459
564
  config.add_route(name, path, request_method="GET")
460
565
  config.add_view(Entry, attr=attr, route_name=name, renderer=renderer)
461
566
 
462
567
  add_static_route("favicon", "favicon", "/favicon.ico", "/etc/geomapfish/static/images/favicon.ico")
463
568
  add_static_route("robot.txt", "robot_txt", "/robot.txt", "/etc/geomapfish/static/robot.txt")
464
- add_static_route("apijs", "apijs", "/api.js", "/etc/static-ngeo/api.js")
569
+ config.add_route("apijs", "/api.js", request_method="GET")
465
570
  add_static_route("apijsmap", "apijsmap", "/api.js.map", "/etc/static-ngeo/api.js.map")
466
571
  add_static_route("apicss", "apicss", "/api.css", "/etc/static-ngeo/api.css")
467
572
  add_static_route("apihelp", "apihelp", "/apihelp/index.html", "/etc/geomapfish/static/apihelp/index.html")
@@ -501,6 +606,13 @@ def includeme(config: pyramid.config.Configurator):
501
606
  add_cors_route(config, "/profile.json", "profile")
502
607
  config.add_route("profile.json", "/profile.json", request_method="POST")
503
608
 
609
+ # Access to vector tiles
610
+ add_cors_route(config, "/vector_tiles", "vector_tiles")
611
+ config.add_route("vector_tiles", "/vector_tiles/{layer_name}/{z}/{x}/{y}.pbf", request_method="GET")
612
+ # There is no view corresponding to that route, it is to be used from
613
+ # mako templates to get the root of the "vector_tiles" web service
614
+ config.add_route("vector_tiles_root", "/vector_tiles", request_method="HEAD")
615
+
504
616
  # Shortener
505
617
  add_cors_route(config, "/short/create", "shortener")
506
618
  config.add_route("shortener_create", "/short/create", request_method="POST")
@@ -581,13 +693,29 @@ def includeme(config: pyramid.config.Configurator):
581
693
  cache_max_age=int(config.get_settings()["default_max_age"]),
582
694
  )
583
695
 
696
+ # Add the c2cgeoportal static view with cache buster
697
+ config.add_static_view(
698
+ name="static-geomapfish",
699
+ path="c2cgeoportal_geoportal:static",
700
+ cache_max_age=int(config.get_settings()["default_max_age"]),
701
+ )
702
+ config.add_cache_buster("c2cgeoportal_geoportal:static", version_cache_buster)
703
+
704
+ # Add the project static view without cache buster
705
+ config.add_static_view(
706
+ name="static-ngeo-dist",
707
+ path="/opt/c2cgeoportal/geoportal/node_modules/ngeo/dist",
708
+ cache_max_age=int(config.get_settings()["default_max_age"]),
709
+ )
710
+
584
711
  # Handles the other HTTP errors raised by the views. Without that,
585
712
  # the client receives a status=200 without content.
586
713
  config.add_view(error_handler, context=HTTPException)
587
714
 
588
715
  c2cwsgiutils.index.additional_title = (
589
- '<div class="row"><div class="col-lg-3"><h2>GeoMapFish</h2>' '</div><div class="col-lg">'
716
+ '<div class="row"><div class="col-lg-3"><h2>GeoMapFish</h2></div><div class="col-lg">'
590
717
  )
718
+
591
719
  c2cwsgiutils.index.additional_auth.extend(
592
720
  [
593
721
  '<a href="../tiles/admin/">TileCloud chain admin</a><br>',
@@ -612,10 +740,13 @@ def includeme(config: pyramid.config.Configurator):
612
740
  c2cwsgiutils.index.additional_noauth.append("</div></div><hr>")
613
741
 
614
742
 
615
- def init_dbsessions(settings: dict, config: Configurator, health_check: HealthCheck = None) -> None:
743
+ def init_db_sessions(
744
+ settings: Dict[str, Any], config: Configurator, health_check: Optional[HealthCheck] = None
745
+ ) -> None:
746
+ """Initialize the database sessions."""
616
747
  db_chooser = settings.get("db_chooser", {})
617
- master_paths = [re.compile(i.replace("//", "/")) for i in db_chooser.get("master", [])]
618
- slave_paths = [re.compile(i.replace("//", "/")) for i in db_chooser.get("slave", [])]
748
+ master_paths = [i.replace("//", "/") for i in db_chooser.get("master", [])]
749
+ slave_paths = [i.replace("//", "/") for i in db_chooser.get("slave", [])]
619
750
 
620
751
  slave_prefix = "sqlalchemy_slave" if "sqlalchemy_slave.url" in settings else None
621
752
 
@@ -653,7 +784,7 @@ def init_dbsessions(settings: dict, config: Configurator, health_check: HealthCh
653
784
  version_schema=settings["schema_static"],
654
785
  level=1,
655
786
  )
656
- else: # pragma: no cover
787
+ else:
657
788
 
658
789
  def check(session_: Session) -> None:
659
790
  session_.execute("SELECT 1")