c2cgeoportal-admin 2.5.0.100__py3-none-any.whl → 2.7.1.156__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 (91) hide show
  1. c2cgeoportal_admin/__init__.py +19 -12
  2. c2cgeoportal_admin/lib/__init__.py +0 -0
  3. c2cgeoportal_admin/lib/lingua_extractor.py +77 -0
  4. c2cgeoportal_admin/lib/ogcserver_synchronizer.py +409 -0
  5. c2cgeoportal_admin/py.typed +0 -0
  6. c2cgeoportal_admin/routes.py +18 -10
  7. c2cgeoportal_admin/schemas/dimensions.py +13 -11
  8. c2cgeoportal_admin/schemas/functionalities.py +63 -22
  9. c2cgeoportal_admin/schemas/interfaces.py +23 -19
  10. c2cgeoportal_admin/schemas/metadata.py +121 -47
  11. c2cgeoportal_admin/schemas/restriction_areas.py +22 -20
  12. c2cgeoportal_admin/schemas/roles.py +8 -6
  13. c2cgeoportal_admin/schemas/treegroup.py +84 -18
  14. c2cgeoportal_admin/schemas/treeitem.py +2 -3
  15. c2cgeoportal_admin/static/layertree.css +26 -4
  16. c2cgeoportal_admin/static/navbar.css +59 -36
  17. c2cgeoportal_admin/static/theme.css +48 -11
  18. c2cgeoportal_admin/subscribers.py +3 -3
  19. c2cgeoportal_admin/templates/404.jinja2 +23 -0
  20. c2cgeoportal_admin/templates/edit.jinja2 +23 -0
  21. c2cgeoportal_admin/templates/home.jinja2 +23 -0
  22. c2cgeoportal_admin/templates/index.jinja2 +23 -0
  23. c2cgeoportal_admin/templates/layertree.jinja2 +55 -11
  24. c2cgeoportal_admin/templates/layout.jinja2 +23 -0
  25. c2cgeoportal_admin/templates/navigation_navbar.jinja2 +56 -0
  26. c2cgeoportal_admin/templates/ogcserver_synchronize.jinja2 +90 -0
  27. c2cgeoportal_admin/templates/widgets/child.pt +35 -3
  28. c2cgeoportal_admin/templates/widgets/children.pt +121 -92
  29. c2cgeoportal_admin/templates/widgets/dimension.pt +23 -0
  30. c2cgeoportal_admin/templates/widgets/dimensions.pt +23 -0
  31. c2cgeoportal_admin/templates/widgets/functionality_fields.pt +51 -0
  32. c2cgeoportal_admin/templates/widgets/layer_fields.pt +23 -0
  33. c2cgeoportal_admin/templates/widgets/layer_group_fields.pt +23 -0
  34. c2cgeoportal_admin/templates/widgets/layer_v1_fields.pt +23 -0
  35. c2cgeoportal_admin/templates/widgets/metadata.pt +30 -1
  36. c2cgeoportal_admin/templates/widgets/metadatas.pt +23 -0
  37. c2cgeoportal_admin/templates/widgets/ogcserver_fields.pt +23 -0
  38. c2cgeoportal_admin/templates/widgets/restriction_area_fields.pt +25 -9
  39. c2cgeoportal_admin/templates/widgets/role_fields.pt +52 -25
  40. c2cgeoportal_admin/templates/widgets/theme_fields.pt +23 -0
  41. c2cgeoportal_admin/templates/widgets/user_fields.pt +23 -0
  42. c2cgeoportal_admin/views/dimension_layers.py +7 -6
  43. c2cgeoportal_admin/views/functionalities.py +31 -5
  44. c2cgeoportal_admin/views/home.py +5 -5
  45. c2cgeoportal_admin/views/interfaces.py +8 -8
  46. c2cgeoportal_admin/views/layer_groups.py +9 -11
  47. c2cgeoportal_admin/views/layers.py +8 -7
  48. c2cgeoportal_admin/views/layers_vectortiles.py +30 -10
  49. c2cgeoportal_admin/views/layers_wms.py +45 -37
  50. c2cgeoportal_admin/views/layers_wmts.py +39 -33
  51. c2cgeoportal_admin/views/layertree.py +34 -26
  52. c2cgeoportal_admin/views/oauth2_clients.py +89 -0
  53. c2cgeoportal_admin/views/ogc_servers.py +130 -27
  54. c2cgeoportal_admin/views/restriction_areas.py +50 -8
  55. c2cgeoportal_admin/views/roles.py +60 -8
  56. c2cgeoportal_admin/views/themes.py +15 -14
  57. c2cgeoportal_admin/views/themes_ordering.py +38 -18
  58. c2cgeoportal_admin/views/treeitems.py +12 -11
  59. c2cgeoportal_admin/views/users.py +7 -5
  60. c2cgeoportal_admin/widgets.py +79 -28
  61. {c2cgeoportal_admin-2.5.0.100.dist-info → c2cgeoportal_admin-2.7.1.156.dist-info}/METADATA +16 -11
  62. c2cgeoportal_admin-2.7.1.156.dist-info/RECORD +92 -0
  63. {c2cgeoportal_admin-2.5.0.100.dist-info → c2cgeoportal_admin-2.7.1.156.dist-info}/WHEEL +1 -1
  64. c2cgeoportal_admin-2.7.1.156.dist-info/entry_points.txt +5 -0
  65. tests/__init__.py +23 -18
  66. tests/conftest.py +4 -15
  67. tests/test_edit_url.py +16 -18
  68. tests/test_functionalities.py +23 -10
  69. tests/test_interface.py +8 -8
  70. tests/test_layer_groups.py +15 -23
  71. tests/test_layers_vectortiles.py +16 -20
  72. tests/test_layers_wms.py +37 -75
  73. tests/test_layers_wmts.py +20 -24
  74. tests/test_layertree.py +107 -100
  75. tests/test_learn.py +1 -1
  76. tests/test_lingua_extractor_config.py +66 -0
  77. tests/test_main.py +4 -2
  78. tests/test_metadatas.py +79 -70
  79. tests/test_oauth2_clients.py +157 -0
  80. tests/test_ogc_servers.py +51 -7
  81. tests/test_restriction_areas.py +81 -17
  82. tests/test_role.py +110 -76
  83. tests/test_themes.py +44 -37
  84. tests/test_themes_ordering.py +1 -1
  85. tests/test_treegroup.py +2 -2
  86. tests/test_user.py +31 -64
  87. tests/themes_ordering.py +1 -1
  88. c2cgeoportal_admin/templates/navigation_vertical.jinja2 +0 -10
  89. c2cgeoportal_admin-2.5.0.100.dist-info/RECORD +0 -84
  90. c2cgeoportal_admin-2.5.0.100.dist-info/entry_points.txt +0 -3
  91. {c2cgeoportal_admin-2.5.0.100.dist-info → c2cgeoportal_admin-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-2024, Camptocamp SA
4
2
  # All rights reserved.
5
3
 
6
4
  # Redistribution and use in source and binary forms, with or without
@@ -27,12 +25,16 @@
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
 
28
+ from typing import Any, Optional
30
29
 
31
30
  import colander
31
+ import pyramid.request
32
32
  from colander import Mapping, SchemaNode
33
33
  from deform import widget
34
34
  from deform.widget import MappingWidget, SequenceWidget
35
35
 
36
+ from c2cgeoportal_commons.models.main import TreeItem
37
+
36
38
  registry = widget.default_resource_registry
37
39
  registry.set_js_resources(
38
40
  "magicsuggest", None, "c2cgeoportal_admin:node_modules/magicsuggest-alpine/magicsuggest-min.js"
@@ -52,51 +54,100 @@ widget.DateTimeInputWidget._pstruct_schema = SchemaNode( # pylint: disable=prot
52
54
  )
53
55
 
54
56
 
55
- class ChildWidget(MappingWidget):
57
+ class ChildWidget(MappingWidget): # type: ignore
58
+ """
59
+ Extension of the widget ````deform.widget.MappingWidget``.
56
60
 
57
- template = "child"
61
+ To be used in conjunction with ChildrenWidget, to manage n-m relationships.
58
62
 
59
- def serialize(self, field, cstruct, **kw):
60
- from c2cgeoportal_commons.models.main import TreeItem # pylint: disable=import-outside-toplevel
63
+ Do not embed complete children forms, but just an hidden input for child primary key.
61
64
 
62
- if cstruct["treeitem_id"] == colander.null:
63
- kw["treeitem"] = TreeItem()
64
- else:
65
- kw["treeitem"] = field.schema.dbsession.query(TreeItem).get(int(cstruct["treeitem_id"]))
66
- return super().serialize(field, cstruct, **kw)
65
+ **Attributes/Arguments**
66
+
67
+ input_name (required)
68
+ Form input name namely the name of the schema field identifying the child in the relation.
69
+
70
+ model (required)
71
+ The child model class.
72
+
73
+ label_field (required)
74
+ The name of the field used for display.
75
+
76
+ icon_class (optional)
77
+ A function which takes a child as parameter and returns a CSS class.
67
78
 
79
+ edit_url (optional)
80
+ A function taking request and child as parameter and returning
81
+ an URL to the corresponding resource.
68
82
 
69
- class ThemeOrderWidget(MappingWidget):
83
+ For further attributes, please refer to the documentation of
84
+ ``deform.widget.MappingWidget`` in the deform documentation:
85
+ <https://deform.readthedocs.org/en/latest/api.html>
86
+ """
70
87
 
71
88
  template = "child"
89
+ input_name = "treeitem_id"
90
+ model = TreeItem
91
+ label_field = "name"
72
92
 
73
- def serialize(self, field, cstruct, **kw):
74
- from c2cgeoportal_commons.models.main import TreeItem # pylint: disable=import-outside-toplevel
93
+ def icon_class(self, child: Any) -> Optional[str]: # pylint: disable=no-self-use,useless-return
94
+ del child
95
+ return None
96
+
97
+ def edit_url( # pylint: disable=no-self-use,useless-return
98
+ self, request: pyramid.request.Request, child: Any
99
+ ) -> Optional[str]:
100
+ del request
101
+ del child
102
+ return None
75
103
 
76
- if cstruct["id"] == colander.null:
77
- kw["treeitem"] = TreeItem()
104
+ def serialize(self, field, cstruct, **kw):
105
+ if cstruct[self.input_name] == colander.null:
106
+ kw["child"] = self.model()
78
107
  else:
79
- kw["treeitem"] = field.schema.dbsession.query(TreeItem).get(int(cstruct["id"]))
108
+ kw["child"] = field.schema.dbsession.query(self.model).get(int(cstruct[self.input_name]))
80
109
  return super().serialize(field, cstruct, **kw)
81
110
 
82
111
 
83
- class ChildrenWidget(SequenceWidget):
112
+ class ChildrenWidget(SequenceWidget): # type: ignore
113
+ """
114
+ Extension of the widget ````deform.widget.SequenceWidget``.
115
+
116
+ To be used in conjunction with ChildWidget, to manage n-m relationships.
117
+
118
+ Use Magicsuggest for searching into parent schema candidates property, which should be a list of
119
+ dictionaries of the form:
120
+ {
121
+ "id": "Value to be set in child identifier input (child_input_name)",
122
+ "label": "The text to display in MagicSuggest",
123
+ "icon_class": "An optional icon class for the MagisSuggest entries",
124
+ "edit_url": "An optional url to edit the child resource",
125
+ "group": "An optional group name for grouping entries in MagicSuggest",
126
+ }
127
+
128
+ **Attributes/Arguments**
129
+
130
+ child_input_name (required)
131
+ The name of the child input to fill with selected child primary key.
132
+
133
+ For further attributes, please refer to the documentation of
134
+ ``deform.widget.SequenceWidget`` in the deform documentation:
135
+ <https://deform.readthedocs.org/en/latest/api.html>
136
+ """
84
137
 
85
138
  template = "children"
139
+ category = "structural"
86
140
  add_subitem = True
141
+ orderable = True
142
+ child_input_name = "treeitem_id"
87
143
  requirements = SequenceWidget.requirements + (("magicsuggest", None),)
88
144
 
89
- def __init__(self, **kw):
90
- SequenceWidget.__init__(self, orderable=True, **kw)
91
-
92
145
  def deserialize(self, field, pstruct):
93
- for i, dict_ in enumerate(pstruct):
94
- dict_["ordering"] = str(i)
146
+ if self.orderable and pstruct != colander.null:
147
+ for i, dict_ in enumerate(pstruct):
148
+ dict_["ordering"] = str(i)
95
149
  return super().deserialize(field, pstruct)
96
150
 
97
151
  def serialize(self, field, cstruct, **kw):
98
- kw["treeitems"] = [
99
- {"id": item.id, "name": item.name, "item_type": item.item_type, "group": group}
100
- for item, group in field.schema.treeitems
101
- ]
152
+ kw["candidates"] = field.schema.candidates
102
153
  return super().serialize(field, cstruct, **kw)
@@ -1,19 +1,22 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: c2cgeoportal-admin
3
- Version: 2.5.0.100
3
+ Version: 2.7.1.156
4
4
  Summary: c2cgeoportal admin
5
- Home-page: https://www.camptocamp.com/solutions/geospatial/
5
+ Home-page: https://github.com/camptocamp/c2cgeoportal/
6
6
  Author: Camptocamp
7
7
  Author-email: info@camptocamp.com
8
- License: UNKNOWN
9
- Platform: UNKNOWN
8
+ Keywords: web gis geoportail c2cgeoportal geocommune pyramid
9
+ Classifier: Development Status :: 6 - Mature
10
+ Classifier: Environment :: Web Environment
11
+ Classifier: Framework :: Pyramid
12
+ Classifier: Intended Audience :: Other Audience
13
+ Classifier: License :: OSI Approved :: BSD License
14
+ Classifier: Operating System :: OS Independent
10
15
  Classifier: Programming Language :: Python
11
16
  Classifier: Programming Language :: Python :: 3
12
- Classifier: Programming Language :: Python :: 3.5
13
- Classifier: Programming Language :: Python :: 3.6
14
- Classifier: Framework :: Pyramid
15
- Classifier: Topic :: Internet :: WWW/HTTP
16
- Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Application
17
+ Classifier: Programming Language :: Python :: 3.8
18
+ Classifier: Topic :: Scientific/Engineering :: GIS
19
+ Classifier: Typing :: Typed
17
20
  Description-Content-Type: text/markdown
18
21
  Requires-Dist: c2cgeoform
19
22
  Requires-Dist: c2cwsgiutils
@@ -28,6 +31,10 @@ Requires-Dist: pyramid-tm
28
31
  Requires-Dist: sqlalchemy
29
32
  Requires-Dist: zope.event
30
33
  Requires-Dist: translationstring
34
+ Requires-Dist: jinja2 (>=2.11.3)
35
+ Requires-Dist: pygments (>=2.7.4)
36
+ Requires-Dist: setuptools (>=65.5.1)
37
+ Requires-Dist: requests (>=2.31.0)
31
38
 
32
39
  # c2cgeoportal admin interface
33
40
 
@@ -41,5 +48,3 @@ make serve
41
48
  ```
42
49
 
43
50
  Now open http://localhost:8888/ in your favorite browser.
44
-
45
-
@@ -0,0 +1,92 @@
1
+ c2cgeoportal_admin/__init__.py,sha256=4UYLGCcfxd8mfHojIalTFmaYNgD67WFbgVhw2sl5yok,4959
2
+ c2cgeoportal_admin/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ c2cgeoportal_admin/routes.py,sha256=So17Lj2v8UigkxVwfYJrK_piDejRkvekPiFibyr3qiw,4676
4
+ c2cgeoportal_admin/subscribers.py,sha256=P1CaccDTpuxrWak_gMN2qBurz3OrAZ6aZ1LA7P3avu8,2430
5
+ c2cgeoportal_admin/widgets.py,sha256=tW6brDW-95LuRnSsRd_8xVRKNAkwkYtdi8zQ44TBj18,6132
6
+ c2cgeoportal_admin/lib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
+ c2cgeoportal_admin/lib/lingua_extractor.py,sha256=Dw4vo46TcUnJ7vvxgFezPYidfEdL2pHJUM0qxAaJ1KE,3380
8
+ c2cgeoportal_admin/lib/ogcserver_synchronizer.py,sha256=NuCV8EpUso01to2PYbh6NpXPcD702pQOSslah__Bzus,15421
9
+ c2cgeoportal_admin/schemas/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
+ c2cgeoportal_admin/schemas/dimensions.py,sha256=rPMEuIdGiVGS5e0xqXUu-COVKlrWg9rpp-xe-8aHbOQ,2290
11
+ c2cgeoportal_admin/schemas/functionalities.py,sha256=AptqKn2oyy74qivzihNfeNvmaDILsl36bSoJdSNXh9Y,3941
12
+ c2cgeoportal_admin/schemas/interfaces.py,sha256=0NCRDZOqbw7Bwj-l3GNsVwYDHck4F0q1fCSo1kTYoOY,2578
13
+ c2cgeoportal_admin/schemas/metadata.py,sha256=px0Teh0vtyimQfzL7zXHXIEkWtBbD00OsadfDDeqSkY,8991
14
+ c2cgeoportal_admin/schemas/restriction_areas.py,sha256=48hFUgFznl_1bYsl490YSXLbXfjCY_f6gURQtB_7eIk,2598
15
+ c2cgeoportal_admin/schemas/roles.py,sha256=4JJrgZNKsj_wru_YGOWxZTEXGVm0hahbAkYf2aePGzI,2507
16
+ c2cgeoportal_admin/schemas/treegroup.py,sha256=-s_aKAzwYwS9zVsuqQAp_7M_-c00LVq-R6dC8BiUWk0,7039
17
+ c2cgeoportal_admin/schemas/treeitem.py,sha256=qnjrLd2LD7NCBjXqzw7aRn83cw_hYZbepJdLzOz0rBk,2117
18
+ c2cgeoportal_admin/static/layertree.css,sha256=tk54KGW0yRRmdrY35gOCZG3qTsqWtGNEwvBYPQKhaVs,3177
19
+ c2cgeoportal_admin/static/navbar.css,sha256=QIaAQsb4n17OfwdKEQdmNDVPCP23Yu-oGW4xsSaHyW0,2307
20
+ c2cgeoportal_admin/static/theme.css,sha256=eHtBEJcBtDhyZJvCKNxE5hgril0VpLtcDKfNFdgCSVw,2025
21
+ c2cgeoportal_admin/templates/404.jinja2,sha256=F05OZUzJljcieoCFMP7Oz1F6Jb-VZ06hTOSc9mrb87g,1420
22
+ c2cgeoportal_admin/templates/edit.jinja2,sha256=rkBQiz0JZdL7VDq8XrhRLTv6JaiFt_QB8CwP3NMHWQY,1302
23
+ c2cgeoportal_admin/templates/home.jinja2,sha256=WDQwmBGMZxsiOLw9YeYPLuca_mjjntjrTh529euzd1o,1516
24
+ c2cgeoportal_admin/templates/index.jinja2,sha256=HPgilbqh5dv-yc_T_bc1hV2DEtV2wD617_aAERC2VSk,2005
25
+ c2cgeoportal_admin/templates/layertree.jinja2,sha256=1ys5XDY3nb4gAu8JazkwSFeJUdGRadT7WaBuvin_hYg,9830
26
+ c2cgeoportal_admin/templates/layout.jinja2,sha256=KCDwATUYBu-ZXv7ijo0S0PlTmKtU-JxW8gMhvPA_kAE,4105
27
+ c2cgeoportal_admin/templates/navigation_navbar.jinja2,sha256=XzVQDpo3ClIiRxWf5eDULHZi9u-veYOmndiE_Twqxog,4166
28
+ c2cgeoportal_admin/templates/ogcserver_synchronize.jinja2,sha256=rdQfbHBzrV5VUq5TC97QR7pv8bRvrdKaUUZpnQyldoE,4327
29
+ c2cgeoportal_admin/templates/widgets/child.pt,sha256=JjxI0oVADhS3SoFgg0iN8P4ca1I_UGr7fWRp3wpZXsE,2159
30
+ c2cgeoportal_admin/templates/widgets/children.pt,sha256=0TPpatvmZcU2TxbcZMjDz8VQcLGtoHkuDJ-eAGvjXho,6625
31
+ c2cgeoportal_admin/templates/widgets/dimension.pt,sha256=1BXmE7s9JpzaJSHAQEtZk0DHB11pQ4FNQPaG_4c8CYo,2627
32
+ c2cgeoportal_admin/templates/widgets/dimensions.pt,sha256=LjWjsgdcFYZxpB_30-3NOfvq5KYkKTu49F-P-r9d5Jg,1211
33
+ c2cgeoportal_admin/templates/widgets/functionality_fields.pt,sha256=8TvwXCmQOtYFkiqsa4AHFUYsWk92LLnthz8bDrLmMBc,1969
34
+ c2cgeoportal_admin/templates/widgets/layer_fields.pt,sha256=RJBYt8ji6YQp9ZaNZJD-caLgy856a6rzlKSMnuZWphw,3223
35
+ c2cgeoportal_admin/templates/widgets/layer_group_fields.pt,sha256=xnqIqFjPPan81OqLwKeDnvNtlhEvYss6h2J9txH5neE,2459
36
+ c2cgeoportal_admin/templates/widgets/layer_v1_fields.pt,sha256=w-MujUevHWmnOkOTbbvES6alDoL_UO1eiMj8SCxcQEY,3956
37
+ c2cgeoportal_admin/templates/widgets/metadata.pt,sha256=jWiLmS0J-cwFkqUxxZwKnkPNX9ShTG2zj0tUCq4TMjQ,3735
38
+ c2cgeoportal_admin/templates/widgets/metadatas.pt,sha256=ErgAH0DA94MO7gqEJ2iZdQ9LRptP2YKH78yze-jdl2Q,1476
39
+ c2cgeoportal_admin/templates/widgets/ogcserver_fields.pt,sha256=x0bDmgrnj9SA6RCVpg3k2lTkkXPkuBFPKMScDgDeyGU,1724
40
+ c2cgeoportal_admin/templates/widgets/restriction_area_fields.pt,sha256=pZVE0KcitAF7HXc3ZlniLr0QwSD05TOhlgieLUR1i7Q,1731
41
+ c2cgeoportal_admin/templates/widgets/role_fields.pt,sha256=gVd9eRYaqw8fGmZauqEUS_Igmyxaa71qcmdC1KUx5nY,2623
42
+ c2cgeoportal_admin/templates/widgets/theme_fields.pt,sha256=68G1Ya8-Dc6pCeP-taQ0ofCIpnY_v0rouazkFhfQflU,3083
43
+ c2cgeoportal_admin/templates/widgets/user_fields.pt,sha256=twmajhUYL1xa47Eu-iATKifNPA5lu3SGpqdKajH6gL8,1753
44
+ c2cgeoportal_admin/views/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
45
+ c2cgeoportal_admin/views/dimension_layers.py,sha256=jupwqX_kO37ukcWE-SsO290JdKENEmfoYxk4sRWb25Y,2598
46
+ c2cgeoportal_admin/views/functionalities.py,sha256=U51DvRd6Jg40VQm66kyVy363cDGGEol0WwaQC8b2ZKM,4002
47
+ c2cgeoportal_admin/views/home.py,sha256=h_hJWIKpzJeSmXl58J0nvZdEg7avSYOOVUEEnlV-r0k,1943
48
+ c2cgeoportal_admin/views/interfaces.py,sha256=3Sl-57PchMlUw_RrvL7F4KTpa57ifpNjOxk-nWqMXpk,3465
49
+ c2cgeoportal_admin/views/layer_groups.py,sha256=CbuURDXMcRXnWbW9aEhXP9nSiSiFq4m3JdtgQS6agxs,3956
50
+ c2cgeoportal_admin/views/layers.py,sha256=xjvcRvKVpeD-LRuVwE8PGkDT-Kih9ADX0beEDcOP1bE,3039
51
+ c2cgeoportal_admin/views/layers_vectortiles.py,sha256=lREdMc7bo2TVqdf-s6MzNXZoauReqFS_K-Hng49NUT4,4932
52
+ c2cgeoportal_admin/views/layers_wms.py,sha256=p3g2zc2waMBBrlFQjgTUn9YTg3WcXQofx5Yw1b3ozAg,7954
53
+ c2cgeoportal_admin/views/layers_wmts.py,sha256=IxvF_knk3HYsa8gKhIaZsyi5Uhmv_Qrmd50gU8BPla8,7731
54
+ c2cgeoportal_admin/views/layertree.py,sha256=x1nTVwyf-ZK7M0gIDpsDdySMZm3XmE6yGEE9j8VYQ4Y,8589
55
+ c2cgeoportal_admin/views/oauth2_clients.py,sha256=hovhxGKK3et_Lny7UuXsterP_OUSZ1HW7YqhawEXrOw,3740
56
+ c2cgeoportal_admin/views/ogc_servers.py,sha256=rK0dIS2XLTc5EDeGrnDf_mpHlNXJsCEyUpci_lIexR8,7476
57
+ c2cgeoportal_admin/views/restriction_areas.py,sha256=0Zpo8p5Zsw3JdPCH8kqWr020boBpNiKMhARKcgCsOVU,5549
58
+ c2cgeoportal_admin/views/roles.py,sha256=7BjQ0zLcsf6JW8OgBKJukaMRksUB-VKTeILfhP9bLG0,5858
59
+ c2cgeoportal_admin/views/themes.py,sha256=Qv6sZ7op90JEd7ASGuTU68rjTdsRrGlf0clYqqumuFI,5710
60
+ c2cgeoportal_admin/views/themes_ordering.py,sha256=NYN3I2tDwLW5E4G-695DwV0dCbHUAObWVFYZ8Bir1-o,5590
61
+ c2cgeoportal_admin/views/treeitems.py,sha256=p-Ba_v3UFtUZEmlct4MZmkwv7jzMoxNKnCVa_FX2hxg,3860
62
+ c2cgeoportal_admin/views/users.py,sha256=YzyKYDDTVn69NQPkrlkmbpgrtsIkK_cxqlcWa6utAVA,5355
63
+ tests/__init__.py,sha256=JbVMbOZgS0u5_MhWBnyzT1gdv3cXwhkXyLQgDqpZAik,9525
64
+ tests/conftest.py,sha256=ah7JmR2epDZul2rmMH5wuUzkSpXIjm8dd-cgGjK6_k0,2119
65
+ tests/test_edit_url.py,sha256=00Q9E3QOtsEEB0YJQehllFr1ztQCU3wc9OyayXCHYI4,4495
66
+ tests/test_functionalities.py,sha256=CPHxBueoCt8W76VJN2sCouxQyc7LD7ccusRah5UK2ys,4126
67
+ tests/test_home.py,sha256=oA4i-V9jJQQgHD9Gz79mgIEMUCRw3tmIQVqdhM9Q2Fo,426
68
+ tests/test_interface.py,sha256=ml1yM4t1o6jIQEHZRwMywjt7mjkUhP-34VKBgHOmWes,4704
69
+ tests/test_layer_groups.py,sha256=Bb1Rsy8QkzGee6edY4UQY8hcxvp54PE7gXUcHoi__JA,11062
70
+ tests/test_layers_vectortiles.py,sha256=DjOLkm3o8nPJJbd010Xi_pwHTK5roiHoQBYAuNaZW5c,9395
71
+ tests/test_layers_wms.py,sha256=MISvkAjEZ4oSD1xg7Zah_GKiBHNu60D8kT03f241wuc,18175
72
+ tests/test_layers_wmts.py,sha256=jjO3AbOQgHgC2yXdYke339W11Ygz1b8DpuAn4OXLnxE,11185
73
+ tests/test_layertree.py,sha256=uu-2AzVtqr87eqq9w_5EWPR_KIXFFjEipEA0_ImnkCU,11336
74
+ tests/test_learn.py,sha256=gQwe-Bim0eihZH0rbBWDn6_rIBxvQD_lyu9MlOljupM,2307
75
+ tests/test_left_menu.py,sha256=-K_429ZcW5Hsz317StIRVz8VtU7GDMH7UCTzZDfckUo,920
76
+ tests/test_lingua_extractor_config.py,sha256=3dqgIdCB1M3YPzXrgDCFQ74t0t4QRXwdQZSy6AMqKp8,2515
77
+ tests/test_main.py,sha256=_gUdMrMMAEzvGIf1QwkoHQkd0eBACz05ycTidCHP5Ao,365
78
+ tests/test_metadatas.py,sha256=dawAKLxyWy4Ok3TWAR5zsB_IN_Ci_VJdjNE9fU5NVjE,12089
79
+ tests/test_oauth2_clients.py,sha256=UaTz7jE0-V2JJ4VkjA3W0FlzgkfacI1jchiynXNNYbc,5782
80
+ tests/test_ogc_servers.py,sha256=qPrbLFw8zaPOpk-fbydJUtfgLl9nxA81jOUNd1l8EUI,6436
81
+ tests/test_restriction_areas.py,sha256=S97lbxHghyhz9h8Sv78jYt2EOQEgwlUp8zCfOtmV-OU,7925
82
+ tests/test_role.py,sha256=99Rk4PCTtoVzbiTP3cR3cVkuIArdLywBl2Hx8Pk5lnE,11820
83
+ tests/test_themes.py,sha256=e-OGon6beHfY4q8xOGsYjW-_pm0-wTA18DPBOz6F9iM,15181
84
+ tests/test_themes_ordering.py,sha256=qIEgLgIjSYpWqMVXBAhOk6BKBUAPXkiXsxWB_A1Dy4s,2244
85
+ tests/test_treegroup.py,sha256=Plv119G4TWlurWLE7Z1mWGeHHPScK_fWKcDmDzMUlIU,576
86
+ tests/test_user.py,sha256=pW2Fsbw8wIP2H3BxAMUojSonhMMyr63jsWFmEteaogk,11659
87
+ tests/themes_ordering.py,sha256=mbjTJHl63UVdv5SsfgDrjOx-1z6C5L4wDSCzIh7LPAE,1343
88
+ c2cgeoportal_admin-2.7.1.156.dist-info/METADATA,sha256=cRegyrlS02-K1HNMG99ohp7l0WSyWQpqnPMJC7zInU4,1492
89
+ c2cgeoportal_admin-2.7.1.156.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
90
+ c2cgeoportal_admin-2.7.1.156.dist-info/entry_points.txt,sha256=ZF-xnP-Q_zr7y6yRmVqjIGVZ1L2iKi5uaOxjxJQBuG4,164
91
+ c2cgeoportal_admin-2.7.1.156.dist-info/top_level.txt,sha256=DgcTJgTvpJUB8HqwYB14PdLBPAOAFk0B8oqnSTFoAU4,25
92
+ c2cgeoportal_admin-2.7.1.156.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.34.2)
2
+ Generator: bdist_wheel (0.40.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -0,0 +1,5 @@
1
+ [lingua.extractors]
2
+ geomapfish-admin-config = c2cgeoportal_admin.lib.lingua_extractor:GeomapfishConfigExtractor
3
+
4
+ [paste.app_factory]
5
+ main = c2cgeoportal_admin:main
tests/__init__.py CHANGED
@@ -9,7 +9,7 @@ skip_if_ci = pytest.mark.skipif(os.environ.get("CI", "false") == "true", reason=
9
9
 
10
10
 
11
11
  def get_test_default_layers(dbsession, default_ogc_server):
12
- from c2cgeoportal_commons.models.main import LayerWMTS, LayerWMS, LayerVectorTiles
12
+ from c2cgeoportal_commons.models.main import LayerVectorTiles, LayerWMS, LayerWMTS
13
13
 
14
14
  default_wms = LayerWMS("wms-defaults")
15
15
  default_wms.ogc_server = default_ogc_server
@@ -30,15 +30,15 @@ def get_test_default_layers(dbsession, default_ogc_server):
30
30
 
31
31
  def factory_build_layers(layer_builder, dbsession, add_dimension=True):
32
32
  from c2cgeoportal_commons.models.main import (
33
- RestrictionArea,
34
- LayergroupTreeitem,
35
- Interface,
36
33
  Dimension,
37
- Metadata,
34
+ Interface,
38
35
  LayerGroup,
36
+ LayergroupTreeitem,
37
+ Metadata,
38
+ RestrictionArea,
39
39
  )
40
40
 
41
- restrictionareas = [RestrictionArea(name="restrictionarea_{}".format(i)) for i in range(0, 5)]
41
+ restrictionareas = [RestrictionArea(name=f"restrictionarea_{i}") for i in range(0, 5)]
42
42
 
43
43
  interfaces = [Interface(name) for name in ["desktop", "mobile", "edit", "routing"]]
44
44
 
@@ -50,7 +50,7 @@ def factory_build_layers(layer_builder, dbsession, add_dimension=True):
50
50
  ("snappingConfig", '{"tolerance": 50}'),
51
51
  ]
52
52
 
53
- groups = [LayerGroup(name="layer_group_{}".format(i)) for i in range(0, 5)]
53
+ groups = [LayerGroup(name=f"layer_group_{i}") for i in range(0, 5)]
54
54
 
55
55
  layers = []
56
56
  for i in range(0, 25):
@@ -91,25 +91,25 @@ def factory_build_layers(layer_builder, dbsession, add_dimension=True):
91
91
 
92
92
  class AbstractViewsTests:
93
93
 
94
- _prefix = None # url prefix (index view url). Example : /users
94
+ _prefix = None # url prefix (index view url). Example: /users
95
95
 
96
96
  def get(self, test_app, path="", locale="en", status=200, **kwargs):
97
97
  return test_app.get(
98
- "{}{}".format(self._prefix, path),
99
- headers={"Cookie": "_LOCALE_={}".format(locale)},
98
+ f"{self._prefix}{path}",
99
+ headers={"Cookie": f"_LOCALE_={locale}"},
100
100
  status=status,
101
101
  **kwargs,
102
102
  )
103
103
 
104
104
  def get_item(self, test_app, item_id, **kwargs):
105
- return self.get(test_app, "/{}".format(item_id), **kwargs)
105
+ return self.get(test_app, f"/{item_id}", **kwargs)
106
106
 
107
107
  def check_left_menu(self, resp, title):
108
108
  link = resp.html.select_one(".navbar li.active a")
109
- assert "http://localhost{}".format(self._prefix) == link.attrs["href"]
109
+ assert f"http://localhost{self._prefix}" == link.attrs["href"]
110
110
  assert title == link.getText()
111
111
 
112
- def check_grid_headers(self, resp, expected_col_headers):
112
+ def check_grid_headers(self, resp, expected_col_headers, new="New"):
113
113
  pp = pprint.PrettyPrinter(indent=4)
114
114
  effective_cols = [
115
115
  (th.attrs["data-field"], th.getText(), th.attrs["data-sortable"]) for th in resp.html.select("th")
@@ -120,11 +120,11 @@ class AbstractViewsTests:
120
120
  )
121
121
  actions = resp.html.select_one('th[data-field="actions"]')
122
122
  assert "false" == actions.attrs["data-sortable"]
123
- assert 1 == len(list(filter(lambda x: next(x.stripped_strings) == "New", resp.html.findAll("a"))))
123
+ assert 1 == len(list(filter(lambda x: next(x.stripped_strings) == new, resp.html.findAll("a"))))
124
124
 
125
125
  def check_search(self, test_app, search="", offset=0, limit=10, sort="", order="", total=None):
126
126
  json = test_app.post(
127
- "{}/grid.json".format(self._prefix),
127
+ f"{self._prefix}/grid.json",
128
128
  params={"offset": offset, "limit": limit, "search": search, "sort": sort, "order": order},
129
129
  status=200,
130
130
  ).json
@@ -135,8 +135,8 @@ class AbstractViewsTests:
135
135
  def check_checkboxes(self, form, name, expected):
136
136
  for i, exp in enumerate(expected):
137
137
  field = form.get(name, index=i)
138
- checkbox = form.html.select_one("#{}".format(field.id))
139
- label = form.html.select_one("label[for={}]".format(field.id))
138
+ checkbox = form.html.select_one(f"#{field.id}")
139
+ label = form.html.select_one(f"label[for={field.id}]")
140
140
  assert exp["label"] == list(label.stripped_strings)[0]
141
141
  assert exp["value"] == checkbox["value"]
142
142
  assert exp["checked"] == field.checked
@@ -187,7 +187,12 @@ class AbstractViewsTests:
187
187
  for exp in expected:
188
188
  input_tag = mapping_item.select_one('[name="{}"]'.format(exp["name"]))
189
189
  if "value" in exp:
190
- if input_tag.name == "select":
190
+ if input_tag.attrs.get("type") == "checkbox":
191
+ if exp["value"] is True:
192
+ assert input_tag.attrs.get("checked") == "checked"
193
+ else:
194
+ assert input_tag.attrs.get("checked") is None
195
+ elif input_tag.name == "select":
191
196
  self._check_select(input_tag, exp["value"])
192
197
  elif input_tag.name == "textarea":
193
198
  assert (exp["value"] or "") == (input_tag.string or "")
tests/conftest.py CHANGED
@@ -1,11 +1,8 @@
1
- import threading
2
- from wsgiref.simple_server import make_server
3
-
1
+ import pytest
2
+ import transaction
4
3
  from pyramid import testing
5
4
  from pyramid.paster import bootstrap
6
- import pytest
7
5
  from sqlalchemy.exc import DBAPIError
8
- import transaction
9
6
  from webtest import TestApp as WebTestApp # Avoid warning with pytest
10
7
 
11
8
  from c2cgeoportal_commons.testing import generate_mappers, get_engine, get_session_factory, get_tm_session
@@ -59,6 +56,7 @@ def app(app_env, dbsession):
59
56
  config.add_request_method(lambda request: dbsession, "dbsession", reify=True)
60
57
  config.add_route("user_add", "user_add")
61
58
  config.add_route("users_nb", "users_nb")
59
+ config.add_route("base", "/", static=True)
62
60
  config.scan(package="tests")
63
61
  app = config.make_wsgi_app()
64
62
  yield app
@@ -70,17 +68,8 @@ def settings(app_env):
70
68
  yield app_env.get("registry").settings
71
69
 
72
70
 
73
- @pytest.fixture(scope="session") # noqa: F811
71
+ @pytest.fixture(scope="session") # noqa: ignore=F811
74
72
  @pytest.mark.usefixtures("app")
75
73
  def test_app(request, app):
76
74
  testapp = WebTestApp(app)
77
75
  yield testapp
78
-
79
-
80
- @pytest.fixture(scope="session") # noqa: F811
81
- @pytest.mark.usefixtures("app")
82
- def selenium_app(app):
83
- srv = make_server("", 6544, app)
84
- threading.Thread(target=srv.serve_forever).start()
85
- yield ("http://localhost:6544")
86
- srv.shutdown()
tests/test_edit_url.py CHANGED
@@ -13,23 +13,23 @@ def edit_url_test_data(dbsession, transact):
13
13
  del transact
14
14
 
15
15
  from c2cgeoportal_commons.models.main import (
16
+ Functionality,
17
+ Interface,
18
+ LayerGroup,
19
+ LayerWMS,
16
20
  LayerWMTS,
21
+ OGCServer,
17
22
  RestrictionArea,
18
- Interface,
19
23
  Role,
20
- LayerWMS,
21
- LayerGroup,
22
24
  Theme,
23
- OGCServer,
24
- Functionality,
25
25
  )
26
26
 
27
- restrictionareas = [RestrictionArea(name="restrictionarea_{}".format(i)) for i in range(0, 5)]
27
+ restrictionareas = [RestrictionArea(name=f"restrictionarea_{i}") for i in range(0, 5)]
28
28
  functionalities = {}
29
- for name in ("default_basemap", "location"):
29
+ for name in ("default_basemap", "default_theme"):
30
30
  functionalities[name] = []
31
31
  for v in range(0, 4):
32
- functionality = Functionality(name=name, value="value_{}".format(v))
32
+ functionality = Functionality(name=name, value=f"value_{v}")
33
33
  dbsession.add(functionality)
34
34
  functionalities[name].append(functionality)
35
35
 
@@ -38,10 +38,10 @@ def edit_url_test_data(dbsession, transact):
38
38
 
39
39
  layers_wmts = []
40
40
  for i in range(0, 5):
41
- name = "layer_wmts_{}".format(i)
41
+ name = f"layer_wmts_{i}"
42
42
  layer_wmts = LayerWMTS(name=name)
43
43
  layer_wmts.layer = name
44
- layer_wmts.url = "https://server{}.net/wmts".format(i)
44
+ layer_wmts.url = f"https://server{i}.net/wmts"
45
45
  layer_wmts.restrictionareas = [restrictionareas[i % 5], restrictionareas[(i + 2) % 5]]
46
46
  if i % 10 != 1:
47
47
  layer_wmts.interfaces = [interfaces[i % 4], interfaces[(i + 2) % 4]]
@@ -52,8 +52,8 @@ def edit_url_test_data(dbsession, transact):
52
52
 
53
53
  layers_wms = []
54
54
  for i in range(0, 5):
55
- layer_wms = LayerWMS(name="layer_wms_{}".format(i))
56
- layer_wms.layer = "wms_layer_{}".format(i)
55
+ layer_wms = LayerWMS(name=f"layer_wms_{i}")
56
+ layer_wms.layer = f"wms_layer_{i}"
57
57
  layer_wms.ogc_server = ogc_server
58
58
  layers_wms.append(layer_wms)
59
59
  dbsession.add(layer_wms)
@@ -63,9 +63,7 @@ def edit_url_test_data(dbsession, transact):
63
63
  for i in range(0, 5):
64
64
  role = Role("secretary_" + str(i))
65
65
  role.functionalities = [
66
- functionalities["default_basemap"][0],
67
- functionalities["location"][0],
68
- functionalities["location"][1],
66
+ functionalities["default_theme"][0],
69
67
  ]
70
68
  role.restrictionareas = [restrictionareas[0], restrictionareas[1]]
71
69
  dbsession.add(role)
@@ -98,12 +96,12 @@ class TestUrlEdit(AbstractViewsTests):
98
96
  _prefix = "/admin/"
99
97
 
100
98
  def _get(self, test_app, tablename, pk):
101
- path = "/{}/{}".format(tablename, pk)
99
+ path = f"/{tablename}/{pk}"
102
100
  return test_app.get(path, status=200)
103
101
 
104
102
  def _check_link(self, test_app, resp, item, table, status):
105
- link = resp.html.select_one(".form-group.item-{} a".format(item))
106
- assert re.match(r"http://localhost/admin/{}/\d+".format(table), link["href"]) is not None
103
+ link = resp.html.select_one(f".form-group.item-{item} a")
104
+ assert re.match(rf"http://localhost/admin/{table}/\d+", link["href"]) is not None
107
105
  test_app.get(link.get("href"), status=status)
108
106
 
109
107
  def test_layer_wms_edit(self, edit_url_test_data, test_app):
@@ -9,15 +9,18 @@ from . import AbstractViewsTests
9
9
 
10
10
  @pytest.fixture(scope="function")
11
11
  @pytest.mark.usefixtures("dbsession", "transact")
12
- def functionality_test_data(dbsession, transact):
12
+ def functionality_test_data(dbsession, transact, settings):
13
13
  del transact
14
14
 
15
15
  from c2cgeoportal_commons.models.main import Functionality
16
16
 
17
17
  functionalities = []
18
18
  for i in range(0, 4):
19
- functionality = Functionality(name="functionality_{}".format(i), value="value_{}".format(i))
20
- functionality.description = "description_{}".format(i)
19
+ functionality = Functionality(
20
+ settings["admin_interface"]["available_functionalities"][i]["name"],
21
+ value=f"value_{i}",
22
+ )
23
+ functionality.description = f"description_{i}"
21
24
  dbsession.add(functionality)
22
25
  functionalities.append(functionality)
23
26
 
@@ -47,7 +50,7 @@ class TestFunctionality(AbstractViewsTests):
47
50
 
48
51
  def test_grid_search(self, test_app):
49
52
  # search on functionality name
50
- self.check_search(test_app, "functionality_0", total=1)
53
+ self.check_search(test_app, "default_basemap", total=1)
51
54
 
52
55
  def test_submit_new(self, dbsession, test_app):
53
56
  from c2cgeoportal_commons.models.main import Functionality
@@ -65,7 +68,7 @@ class TestFunctionality(AbstractViewsTests):
65
68
 
66
69
  def test_edit(self, test_app, functionality_test_data):
67
70
  functionality = functionality_test_data["functionalities"][0]
68
- resp = test_app.get("/admin/functionalities/{}".format(functionality.id), status=200)
71
+ resp = test_app.get(f"/admin/functionalities/{functionality.id}", status=200)
69
72
  form = resp.form
70
73
  assert str(functionality.id) == self.get_first_field_named(form, "id").value
71
74
  assert "hidden" == self.get_first_field_named(form, "id").attrs["type"]
@@ -79,20 +82,30 @@ class TestFunctionality(AbstractViewsTests):
79
82
 
80
83
  functionality = functionality_test_data["functionalities"][0]
81
84
  deleted_id = functionality.id
82
- test_app.delete("/admin/functionalities/{}".format(deleted_id), status=200)
85
+ test_app.delete(f"/admin/functionalities/{deleted_id}", status=200)
83
86
  assert dbsession.query(Functionality).get(deleted_id) is None
84
87
 
85
88
  def test_duplicate(self, functionality_test_data, test_app, dbsession):
86
89
  from c2cgeoportal_commons.models.main import Functionality
87
90
 
88
91
  functionality = functionality_test_data["functionalities"][3]
89
- resp = test_app.get("/admin/functionalities/{}/duplicate".format(functionality.id), status=200)
92
+
93
+ resp = test_app.get(f"/admin/functionalities/{functionality.id}/duplicate", status=200)
94
+
90
95
  form = resp.form
91
- assert "" == self.get_first_field_named(form, "id").value
92
- self.set_first_field_named(form, "name", "clone")
96
+ assert form["name"].value == functionality.name
97
+ assert form["description"].value == functionality.description
98
+ assert form["value"].value == functionality.value
99
+ form["value"].value = "another_value"
93
100
  resp = form.submit("submit")
101
+
94
102
  assert resp.status_int == 302
95
- functionality = dbsession.query(Functionality).filter(Functionality.name == "clone").one()
103
+ functionality = (
104
+ dbsession.query(Functionality)
105
+ .filter(Functionality.name == functionality.name)
106
+ .filter(Functionality.value == "another_value")
107
+ .one()
108
+ )
96
109
  assert str(functionality.id) == re.match(
97
110
  r"http://localhost/admin/functionalities/(.*)\?msg_col=submit_ok", resp.location
98
111
  ).group(1)