c2cgeoportal-geoportal 2.7.1.156__py2.py3-none-any.whl → 2.8.1.87__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 (101) hide show
  1. c2cgeoportal_geoportal/__init__.py +23 -14
  2. c2cgeoportal_geoportal/lib/__init__.py +3 -5
  3. c2cgeoportal_geoportal/lib/authentication.py +10 -14
  4. c2cgeoportal_geoportal/lib/caching.py +8 -6
  5. c2cgeoportal_geoportal/lib/checker.py +10 -6
  6. c2cgeoportal_geoportal/lib/common_headers.py +2 -2
  7. c2cgeoportal_geoportal/lib/dbreflection.py +8 -8
  8. c2cgeoportal_geoportal/lib/filter_capabilities.py +8 -6
  9. c2cgeoportal_geoportal/lib/lingua_extractor.py +11 -12
  10. c2cgeoportal_geoportal/lib/loader.py +1 -1
  11. c2cgeoportal_geoportal/lib/oauth2.py +217 -100
  12. c2cgeoportal_geoportal/lib/wmstparsing.py +8 -12
  13. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/Dockerfile +9 -11
  14. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/development.ini +1 -1
  15. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/gunicorn.conf.py +3 -3
  16. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/requirements.txt +1 -1
  17. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/webpack.api.js +6 -4
  18. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/webpack.apps.js +1 -3
  19. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/webpack.commons.js +1 -0
  20. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/{{cookiecutter.package}}_geoportal/__init__.py +1 -6
  21. c2cgeoportal_geoportal/scaffolds/advance_update/{{cookiecutter.project}}/geoportal/CONST_Makefile +0 -20
  22. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.github/workflows/main.yaml +21 -7
  23. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.github/workflows/rebuild.yaml +1 -1
  24. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.github/workflows/update_l10n.yaml +2 -1
  25. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/Dockerfile +22 -22
  26. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/Makefile +58 -2
  27. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/build +49 -29
  28. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/ci/config.yaml +2 -5
  29. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/ci/docker-compose-check +25 -0
  30. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/ci/requirements.txt +1 -1
  31. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/docker-compose-db.yaml +26 -0
  32. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/docker-compose-lib.yaml +35 -26
  33. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/docker-compose-qgis.yaml +23 -0
  34. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/docker-compose.override.sample.yaml +0 -2
  35. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/docker-compose.yaml +3 -3
  36. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/env.default +21 -2
  37. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/env.project +9 -0
  38. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/geoportal/vars.yaml +38 -14
  39. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/data/Readme.txt +2 -2
  40. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/mapserver.conf +15 -0
  41. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/mapserver/mapserver.map.tmpl +2 -3
  42. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}/A3_Landscape.jrxml +5 -0
  43. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}/A3_Portrait.jrxml +5 -0
  44. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}/A4_Landscape.jrxml +5 -0
  45. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}/A4_Portrait.jrxml +5 -0
  46. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/print/print-apps/{{cookiecutter.package}}/config.yaml.tmpl +6 -0
  47. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/pyproject.toml +4 -0
  48. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/run_alembic.sh +3 -5
  49. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/scripts/db-backup +5 -8
  50. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/scripts/db-restore +5 -8
  51. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/spell-ignore-words.txt +2 -0
  52. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/tests/__init__.py +0 -0
  53. c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/tests/test_app.py +38 -0
  54. c2cgeoportal_geoportal/scaffolds/update/{{cookiecutter.project}}/.upgrade.yaml +2 -132
  55. c2cgeoportal_geoportal/scaffolds/update/{{cookiecutter.project}}/CONST_CHANGELOG.txt +200 -1105
  56. c2cgeoportal_geoportal/scaffolds/update/{{cookiecutter.project}}/CONST_create_template/tests/test_testapp.py +48 -0
  57. c2cgeoportal_geoportal/scaffolds/update/{{cookiecutter.project}}/geoportal/CONST_config-schema.yaml +17 -15
  58. c2cgeoportal_geoportal/scaffolds/update/{{cookiecutter.project}}/geoportal/CONST_vars.yaml +48 -2
  59. c2cgeoportal_geoportal/scripts/__init__.py +3 -5
  60. c2cgeoportal_geoportal/scripts/c2cupgrade.py +1 -2
  61. c2cgeoportal_geoportal/scripts/pcreate.py +8 -10
  62. c2cgeoportal_geoportal/scripts/theme2fts.py +58 -3
  63. c2cgeoportal_geoportal/scripts/urllogin.py +2 -2
  64. c2cgeoportal_geoportal/views/__init__.py +1 -3
  65. c2cgeoportal_geoportal/views/dynamic.py +2 -3
  66. c2cgeoportal_geoportal/views/entry.py +2 -10
  67. c2cgeoportal_geoportal/views/fulltextsearch.py +1 -1
  68. c2cgeoportal_geoportal/views/geometry_processing.py +3 -3
  69. c2cgeoportal_geoportal/views/layers.py +10 -11
  70. c2cgeoportal_geoportal/views/login.py +63 -8
  71. c2cgeoportal_geoportal/views/mapserverproxy.py +3 -4
  72. c2cgeoportal_geoportal/views/ogcproxy.py +6 -2
  73. c2cgeoportal_geoportal/views/pdfreport.py +1 -1
  74. c2cgeoportal_geoportal/views/printproxy.py +6 -8
  75. c2cgeoportal_geoportal/views/profile.py +1 -1
  76. c2cgeoportal_geoportal/views/proxy.py +6 -9
  77. c2cgeoportal_geoportal/views/raster.py +2 -2
  78. c2cgeoportal_geoportal/views/resourceproxy.py +1 -1
  79. c2cgeoportal_geoportal/views/shortener.py +1 -2
  80. c2cgeoportal_geoportal/views/theme.py +97 -61
  81. c2cgeoportal_geoportal/views/tinyowsproxy.py +3 -12
  82. c2cgeoportal_geoportal/views/vector_tiles.py +1 -1
  83. {c2cgeoportal_geoportal-2.7.1.156.dist-info → c2cgeoportal_geoportal-2.8.1.87.dist-info}/METADATA +20 -15
  84. {c2cgeoportal_geoportal-2.7.1.156.dist-info → c2cgeoportal_geoportal-2.8.1.87.dist-info}/RECORD +100 -94
  85. {c2cgeoportal_geoportal-2.7.1.156.dist-info → c2cgeoportal_geoportal-2.8.1.87.dist-info}/entry_points.txt +1 -0
  86. tests/__init__.py +3 -2
  87. tests/test_cachebuster.py +3 -3
  88. tests/test_caching.py +1 -1
  89. tests/test_checker.py +1 -1
  90. tests/test_decimaljson.py +1 -1
  91. tests/test_headerstween.py +1 -1
  92. tests/test_i18n.py +1 -1
  93. tests/test_init.py +14 -15
  94. tests/test_locale_negociator.py +4 -4
  95. tests/test_mapserverproxy_route_predicate.py +1 -2
  96. tests/test_raster.py +15 -15
  97. tests/test_wmstparsing.py +10 -10
  98. tests/xmlstr.py +1 -3
  99. c2cgeoportal_geoportal/scaffolds/advance_create/{{cookiecutter.project}}/geoportal/tools/extract-messages.js +0 -41
  100. {c2cgeoportal_geoportal-2.7.1.156.dist-info → c2cgeoportal_geoportal-2.8.1.87.dist-info}/WHEEL +0 -0
  101. {c2cgeoportal_geoportal-2.7.1.156.dist-info → c2cgeoportal_geoportal-2.8.1.87.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,48 @@
1
+ # This file should be used only on the test project in the c2cgeoportal CI
2
+
3
+ import re
4
+
5
+ import polib
6
+ import pytest
7
+ import requests
8
+
9
+
10
+ @pytest.mark.parametrize("test_number", [0, 1])
11
+ def test_po(test_number: int) -> None:
12
+ """Tests that the generated pot files are identical between the command line and the view."""
13
+ del test_number
14
+
15
+ response = requests.get("https://front/locale.pot", verify=False, timeout=30) # nosec
16
+ assert response.status_code == 200, response.text
17
+ response_keys = {e.msgid for e in polib.pofile(response.text)}
18
+
19
+ with open(
20
+ "geoportal/{{cookiecutter.package}}_geoportal/locale/{{cookiecutter.package}}_geoportal-client.pot",
21
+ encoding="utf-8",
22
+ ) as current_file:
23
+ current_content = current_file.read()
24
+ current_content_keys = {e.msgid for e in polib.pofile(current_content)}
25
+
26
+ if response_keys != current_content_keys:
27
+ assert response.text == current_content
28
+
29
+
30
+ @pytest.mark.parametrize("url", ["https://front/desktop_alt"])
31
+ def test_desktop_alt(url: str) -> None:
32
+ """Tests the desktop alt page."""
33
+ response = requests.get(url, verify=False, timeout=30) # nosec
34
+ assert response.status_code == 200, response.text
35
+
36
+ assert re.search(
37
+ r'<script src="https://front/static-ngeo-dist/desktop\..*\.js" crossorigin="anonymous"></script>',
38
+ response.text,
39
+ ), response.text
40
+ assert re.search(r'<html lang="{{"{{mainCtrl.lang}}"}}" ', response.text), response.text
41
+
42
+
43
+ def test_enum() -> None:
44
+ """Test the enumerations view"""
45
+ response = requests.get("https://front/layers/test/values/type", verify=False, timeout=30) # nosec
46
+ assert response.status_code == 200, response.text
47
+
48
+ assert response.json() == {"items": [{"value": "car"}, {"value": "train"}]}, response.text
@@ -44,6 +44,8 @@ mapping:
44
44
  package:
45
45
  type: str
46
46
  required: True
47
+ main_ogc_server:
48
+ type: str
47
49
  enable_admin_interface:
48
50
  type: scalar
49
51
  required: True
@@ -123,7 +125,7 @@ mapping:
123
125
  required: True
124
126
  type: map
125
127
  mapping:
126
- regex;.+:
128
+ regex;(.+):
127
129
  type: map
128
130
  mapping:
129
131
  extends:
@@ -131,17 +133,17 @@ mapping:
131
133
  constants:
132
134
  type: map
133
135
  mapping:
134
- regex;.+:
136
+ regex;(.+):
135
137
  type: any
136
138
  dynamic_constants:
137
139
  type: map
138
140
  mapping:
139
- regex;.+:
141
+ regex;(.+):
140
142
  type: str
141
143
  routes:
142
144
  type: map
143
145
  mapping:
144
- regex;.+:
146
+ regex;(.+):
145
147
  type: map
146
148
  mapping:
147
149
  name:
@@ -155,22 +157,22 @@ mapping:
155
157
  kw:
156
158
  type: map
157
159
  mapping:
158
- regex;.+:
160
+ regex;(.+):
159
161
  type: str
160
162
  params:
161
163
  type: map
162
164
  mapping:
163
- regex;.+:
165
+ regex;(.+):
164
166
  type: text
165
167
  dynamic_params:
166
168
  type: map
167
169
  mapping:
168
- regex;.+:
170
+ regex;(.+):
169
171
  type: str
170
172
  static:
171
173
  type: map
172
174
  mapping:
173
- regex;.+:
175
+ regex;(.+):
174
176
  type: map
175
177
  mapping:
176
178
  name:
@@ -227,7 +229,7 @@ mapping:
227
229
  type: map
228
230
  required: True
229
231
  mapping:
230
- regex;.+:
232
+ regex;(.+):
231
233
  type: str
232
234
  headers:
233
235
  type: map
@@ -253,7 +255,7 @@ mapping:
253
255
  headers:
254
256
  type: map
255
257
  mapping:
256
- regex;.+:
258
+ regex;(.+):
257
259
  type: str
258
260
  index: *header
259
261
  dynamic: *header
@@ -283,7 +285,7 @@ mapping:
283
285
  type: map
284
286
  required: True
285
287
  mapping:
286
- regex;.+:
288
+ regex;(.+):
287
289
  type: map
288
290
  mapping:
289
291
  backend:
@@ -292,7 +294,7 @@ mapping:
292
294
  arguments:
293
295
  type: map
294
296
  mapping:
295
- regex;.+:
297
+ regex;(.+):
296
298
  type: any
297
299
  admin_interface:
298
300
  type: map
@@ -308,7 +310,7 @@ mapping:
308
310
  sequence:
309
311
  - type: map
310
312
  mapping:
311
- regex;.+:
313
+ regex;(.+):
312
314
  type: any
313
315
  fitSource:
314
316
  type: bool
@@ -344,7 +346,7 @@ mapping:
344
346
  type: str
345
347
  zoom:
346
348
  type: int
347
- regex;.+:
349
+ regex;(.+):
348
350
  type: any
349
351
  available_metadata:
350
352
  type: seq
@@ -417,7 +419,7 @@ mapping:
417
419
  required: True
418
420
  map:
419
421
  <<: *map_config
420
- regex;.+:
422
+ regex;(.+):
421
423
  type: any
422
424
 
423
425
  layers:
@@ -51,6 +51,7 @@ vars:
51
51
  ns:
52
52
  - geomapfish
53
53
  defaultNS: geomapfish
54
+ keySeparator: false
54
55
  debug: false
55
56
  detection:
56
57
  order:
@@ -210,7 +211,7 @@ vars:
210
211
  gmfBackgroundLayerSelectorOptions: {}
211
212
  defaultTheme: Demo
212
213
  defaultLang: en
213
- gmfOptions:
214
+ gmfOptions: &gmfOptions
214
215
  map: {}
215
216
  view:
216
217
  srid: '{srid}'
@@ -219,6 +220,7 @@ vars:
219
220
  resolutions: [250, 100, 50, 20, 10, 5, 2, 1, 0.5, 0.25, 0.1, 0.05]
220
221
  extent: [2420000, 1030000, 2900000, 1350000]
221
222
  constrainRotation: false
223
+ constrainResolution: true
222
224
  gmfSearchOptions:
223
225
  styles:
224
226
  default:
@@ -297,6 +299,11 @@ vars:
297
299
  width: 2
298
300
  zoom:
299
301
  autoRotate: False
302
+ gmfWMSSourceOptions:
303
+ # The default value is 1.5 but it add a slight blur on the layer,
304
+ # 1 is also possible but the application will do a getMap on all the pan.
305
+ ratio: 2
306
+
300
307
  dynamic_constants:
301
308
  interface: interface
302
309
  cacheVersion: cache_version
@@ -343,6 +350,7 @@ vars:
343
350
  redirect_interface: mobile
344
351
  do_redirect: True
345
352
  constants:
353
+ gmfOptions: *gmfOptions
346
354
  ngeoProfileOptions: {}
347
355
  ngeoStreetviewOptions:
348
356
  viewer: 'mapillary'
@@ -363,7 +371,9 @@ vars:
363
371
  LAYERFONTSIZE: '10'
364
372
  ITEMFONTSIZE: '8'
365
373
  hiddenAttributes:
374
+ - debug
366
375
  - timezone
376
+ - username
367
377
  gmfDisplayQueryGridOptions:
368
378
  featuresStyle: *featureStyle
369
379
  selectedFeatureStyle: *selectedFeatureStyle
@@ -392,15 +402,20 @@ vars:
392
402
  radius: 3
393
403
  gmfShareOptions:
394
404
  enableEmail: True
405
+ gmfFitOptions:
406
+ # Padding (in pixels) to be correctly fitted inside the view. Values in the array are top, right, bottom and left padding.
407
+ padding: [50, 10, 50, 50]
395
408
  routes:
396
409
  gmfProfileJsonUrl:
397
410
  name: profile.json
398
411
  gmfPrintUrl:
399
412
  name: printproxy
413
+
400
414
  mobile:
401
415
  extends: default
402
416
  redirect_interface: desktop
403
417
  constants:
418
+ gmfOptions: *gmfOptions
404
419
  gmfMobileMeasureAreaOptions:
405
420
  precision: 2
406
421
  sketchStyle: &mobileMeasureStyle
@@ -440,10 +455,19 @@ vars:
440
455
  radius: 8
441
456
  radius2: 0
442
457
  angle: 0
458
+ gmfFitOptions:
459
+ # Padding (in pixels) to be correctly fitted inside the view. Values in the array are top, right, bottom and left padding.
460
+ padding: [60, 60, 42, 10]
461
+
443
462
  iframe_api:
444
463
  extends: default
445
464
  constants:
465
+ gmfOptions: *gmfOptions
446
466
  gmfSearchGroups: []
467
+ gmfFitOptions:
468
+ # Padding (in pixels) to be correctly fitted inside the view. Values in the array are top, right, bottom and left padding.
469
+ padding: [20, 20, 20, 20]
470
+
447
471
  api:
448
472
  constants:
449
473
  projections: *projections
@@ -469,15 +493,19 @@ vars:
469
493
  cache:
470
494
  std:
471
495
  backend: c2cgeoportal.hybridsentinel
472
- arguments:
496
+ arguments: &redis-cache-arguments
473
497
  lock_timeout: '{REDIS_LOCK_TIMEOUT}' # seconds
474
498
  redis_expiration_time: '{REDIS_EXPIRATION_TIME}' # seconds
475
499
  distributed_lock: True
500
+ thread_local_lock: False
476
501
  service_name: '{REDIS_SERVICENAME}'
477
502
  socket_timeout: '{REDIS_TIMEOUT}' # seconds
478
503
  db: 0
479
504
  obj:
480
505
  backend: dogpile.cache.memory
506
+ ogc-server:
507
+ backend: c2cgeoportal.hybridsentinel
508
+ arguments: *redis-cache-arguments
481
509
 
482
510
  admin_interface:
483
511
  layer_tree_max_nodes: 1000
@@ -493,6 +521,18 @@ vars:
493
521
  tree item will match when searching for the search aliases.
494
522
  relevant_for:
495
523
  - treeitem
524
+ - name: searchLabelPattern
525
+ description: >
526
+ Template string for the label of tree items in the search results, for example: "{name} ({theme})"
527
+ Supported parameters:
528
+ <ul>
529
+ <li>name (name of the tree item)</li>
530
+ <li>parent (parent of the item, may be a group, a block or a theme)</li>
531
+ <li>block (name of the block to which the item belongs)</li>
532
+ <li>theme (name of the theme to which the item belongs)</li>
533
+ </ul>
534
+ relevant_for:
535
+ - treeitem
496
536
  # Layers group
497
537
  - name: exclusiveGroup
498
538
  type: boolean
@@ -935,6 +975,7 @@ vars:
935
975
  content_security_policy_main_script_src: "
936
976
  'self'
937
977
  'unsafe-inline'
978
+ https://cdn.polyfill.io/
938
979
  {content_security_policy_main_script_src_extra}"
939
980
  content_security_policy_main_style_src: "
940
981
  'self'
@@ -987,6 +1028,7 @@ vars:
987
1028
  'self'
988
1029
  'unsafe-inline'
989
1030
  'unsafe-eval'
1031
+ https://cdn.polyfill.io/
990
1032
  {content_security_policy_apihelp_script_src_extra}"
991
1033
  content_security_policy_apihelp_style_src: "
992
1034
  'self'
@@ -1313,6 +1355,10 @@ runtime_postprocess:
1313
1355
  - cache.std.arguments.redis_expiration_time
1314
1356
  - cache.std.arguments.socket_timeout
1315
1357
  - cache.std.arguments.db
1358
+ - cache.ogc-server.arguments.lock_timeout
1359
+ - cache.ogc-server.arguments.redis_expiration_time
1360
+ - cache.ogc-server.arguments.socket_timeout
1361
+ - cache.ogc-server.arguments.db
1316
1362
  - sqlalchemy\.pool_recycle
1317
1363
  - sqlalchemy\.pool_size
1318
1364
  - sqlalchemy\.max_overflow
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2011-2024, Camptocamp SA
1
+ # Copyright (c) 2011-2023, Camptocamp SA
2
2
  # All rights reserved.
3
3
 
4
4
  # Redistribution and use in source and binary forms, with or without
@@ -38,14 +38,12 @@ from sqlalchemy import engine_from_config
38
38
  from sqlalchemy.orm import Session, configure_mappers, sessionmaker
39
39
 
40
40
 
41
- def fill_arguments(parser: ArgumentParser, use_attribute: bool = False) -> None:
41
+ def fill_arguments(parser: ArgumentParser) -> None:
42
42
  """Fill the command line argument description."""
43
43
  default_config_uri = (
44
44
  "c2c://development.ini" if os.path.isfile("development.ini") else "c2c://geoportal/development.ini"
45
45
  )
46
- c2cwsgiutils.setup_process.fill_arguments(
47
- parser, default_config_uri=default_config_uri, use_attribute=use_attribute
48
- )
46
+ c2cwsgiutils.setup_process.fill_arguments(parser, default_config_uri=default_config_uri)
49
47
 
50
48
 
51
49
  def get_appsettings(options: Namespace) -> pyramid.config.Configurator:
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2014-2021, Camptocamp SA
1
+ # Copyright (c) 2014-2023, Camptocamp SA
2
2
  # All rights reserved.
3
3
 
4
4
  # Redistribution and use in source and binary forms, with or without
@@ -247,7 +247,6 @@ class C2cUpgradeTool:
247
247
  except ConnectionRefusedError as exception:
248
248
  return False, "\n".join([f"Connection refused: {exception}", run_curl])
249
249
  if resp.status_code < 200 or resp.status_code >= 300:
250
-
251
250
  print(colorize("=============", Color.RED))
252
251
  print(colorize("Checker error", Color.RED))
253
252
  try:
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2021-2024, Camptocamp SA
1
+ # Copyright (c) 2021-2023, Camptocamp SA
2
2
  # All rights reserved.
3
3
 
4
4
  # Redistribution and use in source and binary forms, with or without
@@ -183,9 +183,9 @@ class PCreateCommand:
183
183
  }
184
184
  context.update(self.read_project_file())
185
185
  if os.environ.get("CI") == "true":
186
- context["authtkt_secret"] = ( # nosec
187
- "io7heoDui8xaikie1rushaeGeiph8Bequei6ohchaequob6viejei0xooWeuvohf"
188
- )
186
+ context[ # nosec
187
+ "authtkt_secret"
188
+ ] = "io7heoDui8xaikie1rushaeGeiph8Bequei6ohchaequob6viejei0xooWeuvohf"
189
189
 
190
190
  self.get_var(context, "srid", "Spatial Reference System Identifier (e.g. 2056): ", int)
191
191
  srid = cast(int, context["srid"])
@@ -193,12 +193,10 @@ class PCreateCommand:
193
193
  self.get_var(
194
194
  context,
195
195
  "extent",
196
- (
197
- f"Extent (minx miny maxx maxy): in EPSG: {srid} projection, default is "
198
- f"[{extent[0]} {extent[1]} {extent[2]} {extent[3]}]: "
199
- if extent
200
- else f"Extent (minx miny maxx maxy): in EPSG: {srid} projection: "
201
- ),
196
+ f"Extent (minx miny maxx maxy): in EPSG: {srid} projection, default is "
197
+ f"[{extent[0]} {extent[1]} {extent[2]} {extent[3]}]: "
198
+ if extent
199
+ else f"Extent (minx miny maxx maxy): in EPSG: {srid} projection: ",
202
200
  )
203
201
  match = re.match(
204
202
  r"([\d.]+)[,; ] *([\d.]+)[,; ] *([\d.]+)[,; ] *([\d.]+)",
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2014-2021, Camptocamp SA
1
+ # Copyright (c) 2014-2023, Camptocamp SA
2
2
  # All rights reserved.
3
3
 
4
4
  # Redistribution and use in source and binary forms, with or without
@@ -30,7 +30,7 @@ import gettext
30
30
  import os
31
31
  import sys
32
32
  from argparse import ArgumentParser, Namespace
33
- from typing import TYPE_CHECKING, Any, Dict, List, Optional, Set
33
+ from typing import TYPE_CHECKING, Any, Dict, Iterator, List, Optional, Set
34
34
 
35
35
  import pyramid.config
36
36
  import transaction
@@ -190,7 +190,7 @@ class Import:
190
190
  self.imported.add(key)
191
191
  for lang in self.languages:
192
192
  fts = FullTextSearch()
193
- fts.label = self._[lang].gettext(item.name)
193
+ fts.label = self._render_label(item, lang)
194
194
  fts.role = role
195
195
  fts.interface = interface
196
196
  fts.lang = lang
@@ -289,3 +289,58 @@ class Import:
289
289
  self._add_fts(layer, interface, "add_layer", role)
290
290
 
291
291
  return fill
292
+
293
+ def _render_label(
294
+ self,
295
+ item: "c2cgeoportal_commons.models.main.TreeItem",
296
+ lang: str,
297
+ ) -> str:
298
+ patterns = item.get_metadata("searchLabelPattern")
299
+ if not patterns:
300
+ return self._[lang].gettext(item.name)
301
+ pattern = patterns[0]
302
+ assert isinstance(pattern.value, str)
303
+ tree_paths = list(self._get_paths(item))
304
+ # Remove paths where the last element isn't a theme
305
+ tree_paths = [p for p in tree_paths if p[-1].item_type == "theme"]
306
+ result = None
307
+ current_result = None
308
+ if tree_paths:
309
+ for path in tree_paths:
310
+ if len(path) == 2:
311
+ current_result = pattern.value.format(
312
+ name=self._[lang].gettext(item.name),
313
+ theme=self._[lang].gettext(path[-1].name),
314
+ parent=self._[lang].gettext(path[1].name),
315
+ )
316
+ elif len(path) > 2:
317
+ current_result = pattern.value.format(
318
+ name=self._[lang].gettext(item.name),
319
+ theme=self._[lang].gettext(path[-1].name),
320
+ parent=self._[lang].gettext(path[1].name),
321
+ block=self._[lang].gettext(path[-2].name),
322
+ )
323
+ if result and current_result != result:
324
+ sys.stderr.write(
325
+ f"WARNING: the item {item.name} (id: {item.id}) has a label pattern and inconsistent "
326
+ f"multiple parents\n"
327
+ )
328
+ return self._[lang].gettext(item.name)
329
+ result = current_result
330
+ return result or pattern.value.format(
331
+ name=self._[lang].gettext(item.name),
332
+ theme=self._[lang].gettext(item.name),
333
+ )
334
+
335
+ def _get_paths(
336
+ self,
337
+ item: "c2cgeoportal_commons.models.main.TreeItem",
338
+ ) -> Iterator[List["c2cgeoportal_commons.models.main.TreeItem"]]:
339
+ if item is None:
340
+ return
341
+ if any(item.parents):
342
+ for parent in item.parents:
343
+ for path in self._get_paths(parent):
344
+ yield [item, *path]
345
+ else:
346
+ yield [item]
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2012-2024, Camptocamp SA
1
+ # Copyright (c) 2012-2023, Camptocamp SA
2
2
  # All rights reserved.
3
3
 
4
4
  # Redistribution and use in source and binary forms, with or without
@@ -58,7 +58,7 @@ def get_argparser() -> argparse.ArgumentParser:
58
58
  """Get the argument parser for this script."""
59
59
 
60
60
  parser = argparse.ArgumentParser(description="Generate an auth token")
61
- fill_arguments(parser, use_attribute=True)
61
+ fill_arguments(parser)
62
62
  parser.add_argument("user", help="The username")
63
63
  parser.add_argument("password", help="The password")
64
64
  parser.add_argument("valid", type=int, default=1, nargs="?", help="Is valid for, in days")
@@ -1,6 +1,4 @@
1
- # -*- coding: utf-8 -*-
2
-
3
- # Copyright (c) 2011-2021, 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
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2018-2025, Camptocamp SA
1
+ # Copyright (c) 2018-2023, Camptocamp SA
2
2
  # All rights reserved.
3
3
 
4
4
  # Redistribution and use in source and binary forms, with or without
@@ -56,7 +56,7 @@ class DynamicView:
56
56
  return cast(Dict[str, Any], self.interfaces_config.get(interface, {}).get(value, {}))
57
57
 
58
58
  @CACHE_REGION.cache_on_arguments() # type: ignore
59
- def _fulltextsearch_groups(self) -> List[str]: # pylint: disable=no-self-use
59
+ def _fulltextsearch_groups(self) -> List[str]:
60
60
  return [
61
61
  group[0]
62
62
  for group in models.DBSession.query(func.distinct(main.FullTextSearch.layer_name))
@@ -121,7 +121,6 @@ class DynamicView:
121
121
 
122
122
  @view_config(route_name="dynamic", renderer="json") # type: ignore
123
123
  def dynamic(self) -> Dict[str, Any]:
124
- self.request.response.headers["Vary"] = "Host"
125
124
  original_interface_name = self.request.params.get("interface")
126
125
  interface_name = self.request.get_organization_interface(original_interface_name)
127
126
 
@@ -28,7 +28,6 @@
28
28
 
29
29
  import glob
30
30
  import logging
31
- import os
32
31
  from typing import Any, Dict, List, Optional
33
32
 
34
33
  import pyramid.request
@@ -57,7 +56,7 @@ class Entry:
57
56
  def get_ngeo_index_vars(self) -> Dict[str, Any]:
58
57
  set_common_headers(self.request, "index", Cache.PUBLIC_NO, content_type="text/html")
59
58
  # Force urllogin to be converted to cookie when requesting the main HTML page
60
- self.request.user # noqa
59
+ self.request.user # pylint: disable=pointless-statement
61
60
  return {}
62
61
 
63
62
  @staticmethod
@@ -105,14 +104,7 @@ class Entry:
105
104
 
106
105
  def _get_ngeo_resources(pattern: str) -> List[str]:
107
106
  """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
107
+ return glob.glob(f"/opt/c2cgeoportal/geoportal/node_modules/ngeo/dist/{pattern}")
116
108
 
117
109
 
118
110
  def canvas_view(request: pyramid.request.Request, interface_config: Dict[str, Any]) -> Dict[str, Any]:
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2011-2021, Camptocamp SA
1
+ # Copyright (c) 2011-2023, Camptocamp SA
2
2
  # All rights reserved.
3
3
 
4
4
  # Redistribution and use in source and binary forms, with or without
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2011-2021, Camptocamp SA
1
+ # Copyright (c) 2011-2023, Camptocamp SA
2
2
  # All rights reserved.
3
3
 
4
4
  # Redistribution and use in source and binary forms, with or without
@@ -33,7 +33,7 @@ from geoalchemy2.shape import from_shape, to_shape
33
33
  from geojson import loads
34
34
  from pyramid.httpexceptions import HTTPBadRequest
35
35
  from pyramid.view import view_config
36
- from shapely.geometry import asShape
36
+ from shapely.geometry import shape
37
37
  from shapely.geometry.base import BaseGeometry
38
38
  from sqlalchemy import func
39
39
 
@@ -69,7 +69,7 @@ class GeometryProcessing:
69
69
  return to_shape(
70
70
  DBSession.query(
71
71
  func.ST_Difference(
72
- from_shape(asShape(body["geometries"][0])), from_shape(asShape(body["geometries"][1]))
72
+ from_shape(shape(body["geometries"][0])), from_shape(shape(body["geometries"][1]))
73
73
  )
74
74
  ).scalar()
75
75
  )