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) 2018-2020, Camptocamp SA
1
+ # Copyright (c) 2018-2025, Camptocamp SA
4
2
  # All rights reserved.
5
3
 
6
4
  # Redistribution and use in source and binary forms, with or without
@@ -28,36 +26,37 @@
28
26
  # either expressed or implied, of the FreeBSD Project.
29
27
 
30
28
 
31
- import json
32
29
  import re
33
- from typing import Dict, List, Union
34
30
  import urllib.parse
31
+ from typing import Any, Dict, List, Union, cast
35
32
 
33
+ import pyramid.request
34
+ from pyramid.httpexceptions import HTTPNotFound
36
35
  from pyramid.view import view_config
37
36
  from sqlalchemy import func
38
37
 
39
38
  from c2cgeoportal_commons import models
40
39
  from c2cgeoportal_commons.models import main
41
40
  from c2cgeoportal_geoportal.lib.cacheversion import get_cache_version
42
- from c2cgeoportal_geoportal.lib.caching import NO_CACHE, get_region, set_common_headers
41
+ from c2cgeoportal_geoportal.lib.caching import get_region
42
+ from c2cgeoportal_geoportal.lib.common_headers import Cache, set_common_headers
43
43
 
44
44
  CACHE_REGION = get_region("std")
45
45
 
46
46
 
47
47
  class DynamicView:
48
- def __init__(self, request):
48
+ """The dynamic vies that provide the configuration of the client application."""
49
+
50
+ def __init__(self, request: pyramid.request.Request):
49
51
  self.request = request
50
52
  self.settings = request.registry.settings
51
53
  self.interfaces_config = self.settings["interfaces_config"]
52
- self.default = self.interfaces_config.get("default", {})
53
54
 
54
- def get(self, value, interface):
55
- result = dict(self.default.get(value, {}))
56
- result.update(self.interfaces_config.get(interface, {}).get(value, {}))
57
- return result
55
+ def get(self, value: Dict[str, Any], interface: str) -> Dict[str, Any]:
56
+ return cast(Dict[str, Any], self.interfaces_config.get(interface, {}).get(value, {}))
58
57
 
59
- @CACHE_REGION.cache_on_arguments()
60
- def _fulltextsearch_groups(self): # pylint: disable=no-self-use
58
+ @CACHE_REGION.cache_on_arguments() # type: ignore
59
+ def _fulltextsearch_groups(self) -> List[str]: # pylint: disable=no-self-use
61
60
  return [
62
61
  group[0]
63
62
  for group in models.DBSession.query(func.distinct(main.FullTextSearch.layer_name))
@@ -65,7 +64,34 @@ class DynamicView:
65
64
  .all()
66
65
  ]
67
66
 
68
- def _interface(self, interface_config, interface_name, dynamic, constants):
67
+ def _interface(
68
+ self,
69
+ interface_config: Dict[str, Any],
70
+ interface_name: str,
71
+ original_interface_name: str,
72
+ dynamic: Dict[str, Any],
73
+ ) -> Dict[str, Any]:
74
+ """
75
+ Get the interface configuration.
76
+
77
+ Arguments:
78
+
79
+ interface_config: Current interface configuration
80
+ interface_name: Interface name (we use in the configuration)
81
+ original_interface_name: Original interface name (directly for the query string)
82
+ dynamic: The values that's dynamically generated
83
+ """
84
+
85
+ if "extends" in interface_config:
86
+ constants = self._interface(
87
+ self.interfaces_config[interface_config["extends"]],
88
+ interface_name,
89
+ original_interface_name,
90
+ dynamic,
91
+ )
92
+ else:
93
+ constants = {}
94
+
69
95
  constants.update(interface_config.get("constants", {}))
70
96
  constants.update(
71
97
  {
@@ -81,35 +107,41 @@ class DynamicView:
81
107
  }
82
108
  )
83
109
 
84
- routes = dict(currentInterfaceUrl={"name": interface_name})
85
- routes.update(interface_config.get("routes", {}))
86
- for constant, config in routes.items():
110
+ for constant, config in interface_config.get("routes", {}).items():
111
+ route_name = original_interface_name if config.get("currentInterface", False) else config["name"]
87
112
  params: Dict[str, str] = {}
88
113
  params.update(config.get("params", {}))
89
114
  for name, dyn in config.get("dynamic_params", {}).items():
90
115
  params[name] = dynamic[dyn]
91
116
  constants[constant] = self.request.route_url(
92
- config["name"], *config.get("elements", []), _query=params, **config.get("kw", {})
117
+ route_name, *config.get("elements", []), _query=params, **config.get("kw", {})
93
118
  )
94
119
 
95
120
  return constants
96
121
 
97
- @view_config(route_name="dynamic", renderer="fast_json")
98
- def dynamic(self):
99
- interfaces_names = [interface["name"] for interface in self.settings.get("interfaces")]
100
- default_interfaces_names = [
101
- interface["name"]
102
- for interface in self.settings.get("interfaces")
103
- if interface.get("default", False)
104
- ]
105
- assert len(default_interfaces_names) == 1, "More than one default interface in: " + json.dumps(
106
- self.settings.get("interfaces")
107
- )
108
- default_interface_name = default_interfaces_names[0]
109
- interface_name = self.request.params.get("interface")
110
- if interface_name not in interfaces_names:
111
- interface_name = default_interface_name
122
+ @view_config(route_name="dynamic", renderer="json") # type: ignore
123
+ def dynamic(self) -> Dict[str, Any]:
124
+ self.request.response.headers["Vary"] = "Host"
125
+ original_interface_name = self.request.params.get("interface")
126
+ interface_name = self.request.get_organization_interface(original_interface_name)
127
+
128
+ if interface_name not in self.interfaces_config:
129
+ raise HTTPNotFound("Interface {} doesn't exists in the 'interfaces_config'.")
130
+
112
131
  interface_config = self.interfaces_config[interface_name]
132
+ lang_urls_suffix = interface_config.get("lang_urls_suffix", "")
133
+
134
+ i18next_configuration = self.settings.get("i18next", {})
135
+ i18next_configuration.setdefault("backend", {})
136
+ if "loadPath" not in i18next_configuration["backend"]:
137
+ path: List[str] = [
138
+ self.request.route_url("base").rstrip("/"),
139
+ "static-{{ns}}",
140
+ get_cache_version(),
141
+ "locales",
142
+ "{{lng}}.json",
143
+ ]
144
+ i18next_configuration["backend"]["loadPath"] = "/".join(path)
113
145
 
114
146
  dynamic = {
115
147
  "interface": interface_name,
@@ -117,23 +149,22 @@ class DynamicView:
117
149
  "two_factor": self.request.registry.settings.get("authentication", {}).get("two_factor", False),
118
150
  "lang_urls": {
119
151
  lang: self.request.static_url(
120
- "/etc/geomapfish/static/{lang}.json".format(lang=lang),
121
- _query={"cache": get_cache_version()},
152
+ f"/etc/geomapfish/static/{lang}{lang_urls_suffix}.json",
122
153
  )
123
154
  for lang in self.request.registry.settings["available_locale_names"]
124
155
  },
156
+ "i18next_configuration": i18next_configuration,
125
157
  "fulltextsearch_groups": self._fulltextsearch_groups(),
126
158
  }
127
159
 
128
- constants = self._interface(self.default, interface_name, dynamic, {})
129
- constants = self._interface(interface_config, interface_name, dynamic, constants)
160
+ constants = self._interface(interface_config, interface_name, original_interface_name, dynamic)
130
161
 
131
162
  do_redirect = False
132
163
  url = None
133
164
  if "redirect_interface" in interface_config:
134
165
  no_redirect_query: Dict[str, Union[str, List[str]]] = {"no_redirect": "t"}
135
166
  if "query" in self.request.params:
136
- query = urllib.parse.parse_qs(self.request.params["query"][1:])
167
+ query = urllib.parse.parse_qs(self.request.params["query"][1:], keep_blank_values=True)
137
168
  no_redirect_query.update(query)
138
169
  else:
139
170
  query = {}
@@ -165,5 +196,5 @@ class DynamicView:
165
196
  else:
166
197
  constants["redirectUrl"] = no_redirect_url
167
198
 
168
- set_common_headers(self.request, "dynamic", NO_CACHE)
199
+ set_common_headers(self.request, "dynamic", Cache.PUBLIC_NO)
169
200
  return {"constants": constants, "doRedirect": do_redirect, "redirectUrl": url}
@@ -1,6 +1,4 @@
1
- # -*- coding: utf-8 -*-
2
-
3
- # Copyright (c) 2011-2020, Camptocamp SA
1
+ # Copyright (c) 2011-2023, Camptocamp SA
4
2
  # All rights reserved.
5
3
 
6
4
  # Redistribution and use in source and binary forms, with or without
@@ -28,52 +26,123 @@
28
26
  # either expressed or implied, of the FreeBSD Project.
29
27
 
30
28
 
29
+ import glob
31
30
  import logging
32
- from typing import Dict, Set, Tuple # noqa # pylint: disable=unused-import
33
- import xml.dom.minidom # noqa # pylint: disable=unused-import
31
+ import os
32
+ from typing import Any, Dict, List, Optional
34
33
 
34
+ import pyramid.request
35
35
  from pyramid.i18n import TranslationStringFactory
36
36
  from pyramid.view import view_config
37
37
 
38
- from c2cgeoportal_geoportal.lib.caching import NO_CACHE, PUBLIC_CACHE, set_common_headers
38
+ from c2cgeoportal_geoportal.lib.caching import get_region
39
+ from c2cgeoportal_geoportal.lib.common_headers import Cache, set_common_headers
39
40
 
40
41
  _ = TranslationStringFactory("c2cgeoportal")
41
42
  LOG = logging.getLogger(__name__)
43
+ CACHE_REGION = get_region("std")
42
44
 
43
45
 
44
46
  class Entry:
45
- def __init__(self, request):
47
+ """All the entry points views."""
48
+
49
+ def __init__(self, request: pyramid.request.Request):
46
50
  self.request = request
47
51
 
48
- @view_config(route_name="testi18n", renderer="testi18n.html")
49
- def testi18n(self): # pragma: no cover
52
+ @view_config(route_name="testi18n", renderer="testi18n.html") # type: ignore
53
+ def testi18n(self) -> Dict[str, Any]:
50
54
  _ = self.request.translate
51
55
  return {"title": _("title i18n")}
52
56
 
53
- def get_ngeo_index_vars(self):
54
- set_common_headers(self.request, "index", NO_CACHE, content_type="text/html")
57
+ def get_ngeo_index_vars(self) -> Dict[str, Any]:
58
+ set_common_headers(self.request, "index", Cache.PUBLIC_NO, content_type="text/html")
59
+ # Force urllogin to be converted to cookie when requesting the main HTML page
60
+ self.request.user # noqa
55
61
  return {}
56
62
 
57
- def apijs(self):
58
- set_common_headers(self.request, "api", PUBLIC_CACHE, content_type="application/javascript")
63
+ @staticmethod
64
+ @CACHE_REGION.cache_on_arguments() # type: ignore
65
+ def get_apijs(api_name: Optional[str]) -> str:
66
+ with open("/etc/static-ngeo/api.js", encoding="utf-8") as api_file:
67
+ api = api_file.read().split("\n")
68
+ sourcemap = api.pop(-1)
69
+ if api_name:
70
+ api += [
71
+ f"if (window.{api_name} === undefined && window.geomapfishapp) {{",
72
+ f" window.{api_name} = window.geomapfishapp;",
73
+ "}",
74
+ ]
75
+ api.append(sourcemap)
76
+
77
+ return "\n".join(api)
78
+
79
+ @view_config(route_name="apijs") # type: ignore
80
+ def apijs(self) -> pyramid.response.Response:
81
+ self.request.response.text = self.get_apijs(self.request.registry.settings["api"].get("name"))
82
+ set_common_headers(self.request, "api", Cache.PUBLIC, content_type="application/javascript")
83
+ return self.request.response
84
+
85
+ def favicon(self) -> Dict[str, Any]:
86
+ set_common_headers(self.request, "index", Cache.PUBLIC, content_type="image/vnd.microsoft.icon")
59
87
  return {}
60
88
 
61
- def favicon(self):
62
- set_common_headers(self.request, "index", NO_CACHE, content_type="image/vnd.microsoft.icon")
89
+ def robot_txt(self) -> Dict[str, Any]:
90
+ set_common_headers(self.request, "index", Cache.PUBLIC, content_type="text/plain")
63
91
  return {}
64
92
 
65
- def robot_txt(self):
66
- set_common_headers(self.request, "index", NO_CACHE, content_type="text/plain")
93
+ def apijsmap(self) -> Dict[str, Any]:
94
+ set_common_headers(self.request, "api", Cache.PUBLIC, content_type="application/octet-stream")
67
95
  return {}
68
96
 
69
- def apijsmap(self):
70
- set_common_headers(self.request, "api", NO_CACHE, content_type="application/octet-stream")
97
+ def apicss(self) -> Dict[str, Any]:
98
+ set_common_headers(self.request, "api", Cache.PUBLIC, content_type="text/css")
71
99
  return {}
72
100
 
73
- def apicss(self):
74
- set_common_headers(self.request, "api", PUBLIC_CACHE, content_type="text/css")
101
+ def apihelp(self) -> Dict[str, Any]:
102
+ set_common_headers(self.request, "apihelp", Cache.PUBLIC)
75
103
  return {}
76
104
 
77
- def apihelp(self):
78
- set_common_headers(self.request, "apihelp", NO_CACHE)
79
- return {}
105
+
106
+ def _get_ngeo_resources(pattern: str) -> List[str]:
107
+ """Return the list of ngeo dist files matching the pattern."""
108
+ results = glob.glob(f"/opt/c2cgeoportal/geoportal/node_modules/ngeo/dist/{pattern}")
109
+ if not results:
110
+ LOG.error(
111
+ "No file found for pattern %s, in: [%s]",
112
+ pattern,
113
+ ", ".join(os.listdir("/opt/c2cgeoportal/geoportal/node_modules/ngeo/dist/")),
114
+ )
115
+ return results
116
+
117
+
118
+ def canvas_view(request: pyramid.request.Request, interface_config: Dict[str, Any]) -> Dict[str, Any]:
119
+ """Get view used as entry point of a canvas interface."""
120
+
121
+ js_files = _get_ngeo_resources(f"{interface_config.get('layout', interface_config['name'])}*.js")
122
+ css_files = _get_ngeo_resources(f"{interface_config.get('layout', interface_config['name'])}*.css")
123
+ css = "\n ".join(
124
+ [
125
+ f'<link href="{request.static_url(css)}" rel="stylesheet" crossorigin="anonymous">'
126
+ for css in css_files
127
+ ]
128
+ )
129
+
130
+ set_common_headers(request, "index", Cache.PUBLIC_NO, content_type="text/html")
131
+
132
+ spinner = ""
133
+ spinner_filenames = _get_ngeo_resources("spinner*.svg")
134
+ if spinner_filenames:
135
+ with open(spinner_filenames[0], encoding="utf-8") as spinner_file:
136
+ spinner = spinner_file.read()
137
+
138
+ return {
139
+ "request": request,
140
+ "header": f"""
141
+ <meta name="dynamicUrl" content="{request.route_url("dynamic")}">
142
+ <meta name="interface" content="{interface_config['name']}">
143
+ {css}""",
144
+ "footer": "\n ".join(
145
+ [f'<script src="{request.static_url(js)}" crossorigin="anonymous"></script>' for js in js_files]
146
+ ),
147
+ "spinner": spinner,
148
+ }
@@ -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
@@ -29,7 +27,9 @@
29
27
 
30
28
 
31
29
  import re
30
+ from typing import cast
32
31
 
32
+ import pyramid.request
33
33
  from geoalchemy2.shape import to_shape
34
34
  from geojson import Feature, FeatureCollection
35
35
  from pyramid.httpexceptions import HTTPBadRequest, HTTPInternalServerError
@@ -39,37 +39,42 @@ from sqlalchemy import and_, desc, func, or_
39
39
  from c2cgeoportal_commons.models import DBSession
40
40
  from c2cgeoportal_commons.models.main import FullTextSearch, Interface
41
41
  from c2cgeoportal_geoportal import locale_negotiator
42
- from c2cgeoportal_geoportal.lib.caching import NO_CACHE, get_region, set_common_headers
42
+ from c2cgeoportal_geoportal.lib.caching import get_region
43
+ from c2cgeoportal_geoportal.lib.common_headers import Cache, set_common_headers
44
+ from c2cgeoportal_geoportal.lib.fulltextsearch import Normalize
43
45
 
44
46
  CACHE_REGION = get_region("std")
45
- IGNORED_CHARS_RE = re.compile(r"[()&|!:<>]")
47
+ IGNORED_CHARS_RE = re.compile(r"[()&|!:<>\t]")
46
48
  IGNORED_STARTUP_CHARS_RE = re.compile(r"^[']*")
47
49
 
48
50
 
49
51
  class FullTextSearchView:
50
- def __init__(self, request):
52
+ """All the full-text search view."""
53
+
54
+ def __init__(self, request: pyramid.request.Request):
51
55
  self.request = request
52
- set_common_headers(request, "fulltextsearch", NO_CACHE)
56
+ set_common_headers(request, "fulltextsearch", Cache.PUBLIC_NO)
53
57
  self.settings = request.registry.settings.get("fulltextsearch", {})
54
58
  self.languages = self.settings.get("languages", {})
59
+ self.fts_normalizer = Normalize(self.settings)
55
60
 
56
61
  @staticmethod
57
- @CACHE_REGION.cache_on_arguments()
58
- def _get_interface_id(interface):
59
- return DBSession.query(Interface).filter_by(name=interface).one().id
62
+ @CACHE_REGION.cache_on_arguments() # type: ignore
63
+ def _get_interface_id(interface: str) -> int:
64
+ return cast(int, DBSession.query(Interface).filter_by(name=interface).one().id)
60
65
 
61
- @view_config(route_name="fulltextsearch", renderer="geojson")
62
- def fulltextsearch(self):
66
+ @view_config(route_name="fulltextsearch", renderer="geojson") # type: ignore
67
+ def fulltextsearch(self) -> FeatureCollection:
63
68
  lang = locale_negotiator(self.request)
64
69
 
65
70
  try:
66
71
  language = self.languages[lang]
67
72
  except KeyError:
68
- return HTTPInternalServerError(detail="{0!s} not defined in languages".format(lang))
73
+ return HTTPInternalServerError(detail=f"{lang!s} not defined in languages")
69
74
 
70
75
  if "query" not in self.request.params:
71
76
  return HTTPBadRequest(detail="no query")
72
- terms = self.request.params.get("query")
77
+ terms = self.fts_normalizer(self.request.params.get("query"))
73
78
 
74
79
  maxlimit = self.settings.get("maxlimit", 200)
75
80
 
@@ -77,21 +82,18 @@ class FullTextSearchView:
77
82
  limit = int(self.request.params.get("limit", self.settings.get("defaultlimit", 30)))
78
83
  except ValueError:
79
84
  return HTTPBadRequest(detail="limit value is incorrect")
80
- if limit > maxlimit:
81
- limit = maxlimit
85
+ limit = min(limit, maxlimit)
82
86
 
83
87
  try:
84
88
  partitionlimit = int(self.request.params.get("partitionlimit", 0))
85
89
  except ValueError:
86
90
  return HTTPBadRequest(detail="partitionlimit value is incorrect")
87
- if partitionlimit > maxlimit:
88
- partitionlimit = maxlimit
89
-
90
- terms_ts = "&".join(
91
- w + ":*"
92
- for w in IGNORED_STARTUP_CHARS_RE.sub("", IGNORED_CHARS_RE.sub(" ", terms)).split(" ")
93
- if w != ""
94
- )
91
+ partitionlimit = min(partitionlimit, maxlimit)
92
+
93
+ terms_array = [
94
+ IGNORED_STARTUP_CHARS_RE.sub("", elem) for elem in IGNORED_CHARS_RE.sub(" ", terms).split(" ")
95
+ ]
96
+ terms_ts = "&".join(w + ":*" for w in terms_array if w != "")
95
97
  _filter = FullTextSearch.ts.op("@@")(func.to_tsquery(language, terms_ts))
96
98
 
97
99
  if self.request.user is None:
@@ -143,21 +145,26 @@ class FullTextSearchView:
143
145
  .over(partition_by=FullTextSearch.layer_name, order_by=(desc(rank), FullTextSearch.label))
144
146
  .label("row_number")
145
147
  )
146
- subq = DBSession.query(FullTextSearch).add_columns(row_number).filter(_filter).subquery()
148
+ sub_query = DBSession.query(FullTextSearch).add_columns(row_number).filter(_filter).subquery()
147
149
  query = DBSession.query(
148
- subq.c.id, subq.c.label, subq.c.params, subq.c.layer_name, subq.c.the_geom, subq.c.actions
150
+ sub_query.c.id,
151
+ sub_query.c.label,
152
+ sub_query.c.params,
153
+ sub_query.c.layer_name,
154
+ sub_query.c.the_geom,
155
+ sub_query.c.actions,
149
156
  )
150
- query = query.filter(subq.c.row_number <= partitionlimit)
157
+ query = query.filter(sub_query.c.row_number <= partitionlimit)
151
158
  else:
152
159
  query = DBSession.query(FullTextSearch).filter(_filter)
153
160
  query = query.order_by(desc(rank))
154
161
  query = query.order_by(FullTextSearch.label)
155
162
 
156
163
  query = query.limit(limit)
157
- objs = query.all()
164
+ objects = query.all()
158
165
 
159
166
  features = []
160
- for o in objs:
167
+ for o in objects:
161
168
  properties = {"label": o.label}
162
169
  if o.layer_name is not None:
163
170
  properties["layer_name"] = o.layer_name
@@ -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
@@ -28,28 +26,38 @@
28
26
  # either expressed or implied, of the FreeBSD Project.
29
27
 
30
28
 
29
+ from typing import Optional
30
+
31
+ import pyramid.request
31
32
  from geoalchemy2.shape import from_shape, to_shape
32
33
  from geojson import loads
33
34
  from pyramid.httpexceptions import HTTPBadRequest
34
35
  from pyramid.view import view_config
35
36
  from shapely.geometry import asShape
37
+ from shapely.geometry.base import BaseGeometry
36
38
  from sqlalchemy import func
37
39
 
38
40
  from c2cgeoportal_commons.models import DBSession
39
41
 
40
42
 
41
43
  class GeometryProcessing:
42
- def __init__(self, request):
44
+ """
45
+ View used to provide processing on a geometry.
46
+
47
+ Currently only difference between geometries.
48
+ """
49
+
50
+ def __init__(self, request: pyramid.request.Request):
43
51
  self.request = request
44
52
 
45
- @view_config(route_name="difference", renderer="geojson")
46
- def difference(self):
53
+ @view_config(route_name="difference", renderer="geojson") # type: ignore
54
+ def difference(self) -> Optional[BaseGeometry]:
47
55
  body = loads(self.request.body)
48
56
  if (
49
57
  "geometries" not in body
50
58
  or not isinstance(body["geometries"], list)
51
59
  or len(body["geometries"]) != 2
52
- ): # pragma: no cover
60
+ ):
53
61
  raise HTTPBadRequest(
54
62
  """Wrong body, it should be like that:
55
63
  {
@@ -1,6 +1,4 @@
1
- # -*- coding: utf-8 -*-
2
-
3
- # Copyright (c) 2019-2020, Camptocamp SA
1
+ # Copyright (c) 2019-2022, Camptocamp SA
4
2
  # All rights reserved.
5
3
 
6
4
  # Redistribution and use in source and binary forms, with or without
@@ -28,20 +26,104 @@
28
26
  # either expressed or implied, of the FreeBSD Project.
29
27
 
30
28
 
31
- from pyramid.httpexceptions import HTTPFound
29
+ import glob
30
+ import logging
31
+
32
+ import pyramid.request
33
+ import pyramid.response
34
+ from lingua.extract import ( # strip_linenumbers,
35
+ ExtractorOptions,
36
+ POEntry,
37
+ create_catalog,
38
+ find_file,
39
+ list_files,
40
+ no_duplicates,
41
+ read_config,
42
+ )
43
+ from lingua.extractors import get_extractor, register_extractors
44
+ from lingua.extractors.babel import register_babel_plugins
45
+ from pyramid.httpexceptions import HTTPFound, HTTPInternalServerError
32
46
  from pyramid.view import view_config
33
47
 
34
48
  from c2cgeoportal_geoportal.lib.cacheversion import get_cache_version
35
- from c2cgeoportal_geoportal.lib.caching import NO_CACHE, set_common_headers
49
+ from c2cgeoportal_geoportal.lib.common_headers import Cache, set_common_headers
36
50
 
51
+ LOG = logging.getLogger(__name__)
52
+ _INITIALIZED = False
37
53
 
38
- @view_config(route_name="localejson")
39
- def locale(request):
54
+
55
+ @view_config(route_name="localejson") # type: ignore
56
+ def locale(request: pyramid.request.Request) -> pyramid.response.Response:
57
+ """Get the locale json file for the API."""
40
58
  response = HTTPFound(
41
59
  request.static_url(
42
- "/etc/geomapfish/static/{lang}.json".format(lang=request.locale_name),
60
+ f"/etc/geomapfish/static/{request.locale_name}.json",
43
61
  _query={"cache": get_cache_version()},
44
62
  )
45
63
  )
46
- set_common_headers(request, "api", NO_CACHE, response=response)
64
+ set_common_headers(request, "api", Cache.PUBLIC_NO, response=response)
47
65
  return response
66
+
67
+
68
+ @view_config(route_name="localepot") # type: ignore
69
+ def localepot(request: pyramid.request.Request) -> pyramid.response.Response:
70
+ """Get the pot from an HTTP request."""
71
+
72
+ # Build the list of files to be processed
73
+ sources = []
74
+ sources += glob.glob(f"/app/{request.registry.package_name}/static-ngeo/js/apps/*.html.ejs")
75
+ sources += glob.glob(f"/app/{request.registry.package_name}/static-ngeo/js/**/*.js", recursive=True)
76
+ sources += glob.glob(f"/app/{request.registry.package_name}/static-ngeo/js/**/*.html", recursive=True)
77
+ sources += glob.glob("/usr/local/tomcat/webapps/ROOT/**/config.yaml", recursive=True)
78
+ sources += ["/etc/geomapfish/config.yaml", "/app/development.ini"]
79
+
80
+ # The following code is a modified version of the main function of this file:
81
+ # https://github.com/wichert/lingua/blob/master/src/lingua/extract.py
82
+
83
+ global _INITIALIZED
84
+ if not _INITIALIZED:
85
+ register_extractors()
86
+ register_babel_plugins()
87
+ _INITIALIZED = True
88
+
89
+ with open("/app/lingua-client.cfg", encoding="utf-8") as config_file:
90
+ read_config(config_file)
91
+ _INITIALIZED = True
92
+
93
+ catalog = create_catalog(
94
+ width=110,
95
+ copyright_holder="",
96
+ package_name="GeoMapFish-project",
97
+ package_version="1.0",
98
+ msgid_bugs_address=None,
99
+ )
100
+
101
+ for filename in no_duplicates(list_files(None, sources)):
102
+ real_filename = find_file(filename)
103
+ if real_filename is None:
104
+ LOG.error("Can not find file %s", filename)
105
+ raise HTTPInternalServerError(f"Can not find file {filename}")
106
+ extractor = get_extractor(real_filename)
107
+ if extractor is None:
108
+ LOG.error("No extractor available for file %s", filename)
109
+ raise HTTPInternalServerError(f"No extractor available for file {filename}")
110
+
111
+ extractor_options = ExtractorOptions(
112
+ comment_tag=True,
113
+ domain=None,
114
+ keywords=None,
115
+ )
116
+ for message in extractor(real_filename, extractor_options):
117
+ entry = catalog.find(message.msgid, msgctxt=message.msgctxt)
118
+ if entry is None:
119
+ entry = POEntry(msgctxt=message.msgctxt, msgid=message.msgid)
120
+ catalog.append(entry)
121
+ entry.update(message)
122
+
123
+ # for entry in catalog:
124
+ # strip_linenumbers(entry)
125
+
126
+ # Build the response
127
+ request.response.text = catalog.__unicode__()
128
+ set_common_headers(request, "api", Cache.PUBLIC, content_type="text/x-gettext-translation")
129
+ return request.response