c2cgeoportal-admin 2.7.1.156__py3-none-any.whl → 2.8.1.180__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 (52) hide show
  1. c2cgeoportal_admin/__init__.py +16 -1
  2. c2cgeoportal_admin/lib/ogcserver_synchronizer.py +4 -4
  3. c2cgeoportal_admin/routes.py +3 -1
  4. c2cgeoportal_admin/schemas/metadata.py +1 -1
  5. c2cgeoportal_admin/schemas/treegroup.py +2 -2
  6. c2cgeoportal_admin/templates/404.jinja2 +18 -2
  7. c2cgeoportal_admin/templates/widgets/metadata.pt +1 -1
  8. c2cgeoportal_admin/views/__init__.py +29 -0
  9. c2cgeoportal_admin/views/functionalities.py +4 -3
  10. c2cgeoportal_admin/views/interfaces.py +4 -3
  11. c2cgeoportal_admin/views/layer_groups.py +1 -1
  12. c2cgeoportal_admin/views/layers_wms.py +5 -3
  13. c2cgeoportal_admin/views/layers_wmts.py +5 -3
  14. c2cgeoportal_admin/views/layertree.py +2 -2
  15. c2cgeoportal_admin/views/logged_views.py +80 -0
  16. c2cgeoportal_admin/views/logs.py +90 -0
  17. c2cgeoportal_admin/views/oauth2_clients.py +9 -6
  18. c2cgeoportal_admin/views/ogc_servers.py +66 -12
  19. c2cgeoportal_admin/views/restriction_areas.py +4 -3
  20. c2cgeoportal_admin/views/roles.py +4 -3
  21. c2cgeoportal_admin/views/themes.py +1 -1
  22. c2cgeoportal_admin/views/treeitems.py +4 -3
  23. c2cgeoportal_admin/views/users.py +7 -4
  24. c2cgeoportal_admin/widgets.py +2 -2
  25. {c2cgeoportal_admin-2.7.1.156.dist-info → c2cgeoportal_admin-2.8.1.180.dist-info}/METADATA +13 -7
  26. c2cgeoportal_admin-2.8.1.180.dist-info/RECORD +95 -0
  27. {c2cgeoportal_admin-2.7.1.156.dist-info → c2cgeoportal_admin-2.8.1.180.dist-info}/entry_points.txt +1 -0
  28. tests/__init__.py +2 -3
  29. tests/test_edit_url.py +0 -1
  30. tests/test_functionalities.py +29 -4
  31. tests/test_home.py +0 -1
  32. tests/test_interface.py +27 -4
  33. tests/test_layer_groups.py +45 -11
  34. tests/test_layers_vectortiles.py +33 -8
  35. tests/test_layers_wms.py +43 -10
  36. tests/test_layers_wmts.py +33 -8
  37. tests/test_layertree.py +0 -1
  38. tests/test_left_menu.py +0 -1
  39. tests/test_lingua_extractor_config.py +1 -3
  40. tests/test_logs.py +103 -0
  41. tests/test_metadatas.py +0 -1
  42. tests/test_oauth2_clients.py +35 -7
  43. tests/test_ogc_servers.py +65 -27
  44. tests/test_restriction_areas.py +28 -3
  45. tests/test_role.py +33 -8
  46. tests/test_themes.py +33 -6
  47. tests/test_themes_ordering.py +0 -1
  48. tests/test_user.py +33 -4
  49. tests/themes_ordering.py +0 -1
  50. c2cgeoportal_admin-2.7.1.156.dist-info/RECORD +0 -92
  51. {c2cgeoportal_admin-2.7.1.156.dist-info → c2cgeoportal_admin-2.8.1.180.dist-info}/WHEEL +0 -0
  52. {c2cgeoportal_admin-2.7.1.156.dist-info → c2cgeoportal_admin-2.8.1.180.dist-info}/top_level.txt +0 -0
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2017-2021, Camptocamp SA
1
+ # Copyright (c) 2017-2023, Camptocamp SA
2
2
  # All rights reserved.
3
3
 
4
4
  # Redistribution and use in source and binary forms, with or without
@@ -26,29 +26,36 @@
26
26
  # either expressed or implied, of the FreeBSD Project.
27
27
 
28
28
 
29
+ import logging
30
+ import threading
29
31
  from functools import partial
30
- from typing import Any, Dict, List, cast
32
+ from typing import Any, Dict, List, Union, cast
31
33
 
34
+ import requests
32
35
  from c2cgeoform.schema import GeoFormSchemaNode
33
36
  from c2cgeoform.views.abstract_views import AbstractViews, ItemAction, ListField, UserMessage
34
37
  from deform.widget import FormWidget
35
- from pyramid.httpexceptions import HTTPNotFound
38
+ from pyramid.httpexceptions import HTTPFound
36
39
  from pyramid.view import view_config, view_defaults
37
40
  from sqlalchemy import inspect
38
41
 
39
42
  from c2cgeoportal_admin import _
40
43
  from c2cgeoportal_admin.lib.ogcserver_synchronizer import OGCServerSynchronizer
44
+ from c2cgeoportal_admin.views.logged_views import LoggedViews
41
45
  from c2cgeoportal_commons.lib.literal import Literal
42
- from c2cgeoportal_commons.models.main import OGCServer
46
+ from c2cgeoportal_commons.models import cache_invalidate_cb
47
+ from c2cgeoportal_commons.models.main import LogAction, OGCServer
43
48
 
44
49
  _list_field = partial(ListField, OGCServer)
45
50
 
46
51
  base_schema = GeoFormSchemaNode(OGCServer, widget=FormWidget(fields_template="ogcserver_fields"))
47
52
  base_schema.add_unique_validator(OGCServer.name, OGCServer.id)
48
53
 
54
+ LOG = logging.getLogger(__name__)
55
+
49
56
 
50
57
  @view_defaults(match_param="table=ogc_servers")
51
- class OGCServerViews(AbstractViews): # type: ignore
58
+ class OGCServerViews(LoggedViews):
52
59
  """The OGC server administration view."""
53
60
 
54
61
  _list_fields = [
@@ -84,10 +91,7 @@ class OGCServerViews(AbstractViews): # type: ignore
84
91
  return super().grid() # type: ignore
85
92
 
86
93
  def schema(self) -> GeoFormSchemaNode:
87
- try:
88
- obj = self._get_object()
89
- except HTTPNotFound:
90
- obj = None
94
+ obj = self._get_object()
91
95
 
92
96
  schema = self._base_schema.clone()
93
97
  schema["url"].description = Literal(
@@ -107,6 +111,22 @@ class OGCServerViews(AbstractViews): # type: ignore
107
111
  def _item_actions(self, item: OGCServer, readonly: bool = False) -> List[Any]:
108
112
  actions = cast(List[Any], super()._item_actions(item, readonly))
109
113
  if inspect(item).persistent:
114
+ actions.insert(
115
+ next((i for i, v in enumerate(actions) if v.name() == "delete")),
116
+ ItemAction(
117
+ name="clear-cache",
118
+ label=_("Clear the cache"),
119
+ icon="glyphicon glyphicon-hdd",
120
+ url=self._request.route_url(
121
+ "ogc_server_clear_cache",
122
+ id=getattr(item, self._id_field),
123
+ _query={
124
+ "came_from": self._request.current_route_url(),
125
+ },
126
+ ),
127
+ confirmation=_("The current changes will be lost."),
128
+ ),
129
+ )
110
130
  actions.insert(
111
131
  next((i for i, v in enumerate(actions) if v.name() == "delete")),
112
132
  ItemAction(
@@ -127,8 +147,11 @@ class OGCServerViews(AbstractViews): # type: ignore
127
147
  @view_config( # type: ignore
128
148
  route_name="c2cgeoform_item", request_method="POST", renderer="../templates/edit.jinja2"
129
149
  )
130
- def save(self) -> Dict[str, Any]:
131
- return super().save() # type: ignore
150
+ def save(self) -> Union[HTTPFound, Dict[str, Any]]:
151
+ result: Union[HTTPFound, Dict[str, Any]] = super().save()
152
+ if isinstance(result, HTTPFound):
153
+ self._update_cache(self._obj)
154
+ return result
132
155
 
133
156
  @view_config(route_name="c2cgeoform_item", request_method="DELETE", renderer="fast_json") # type: ignore
134
157
  def delete(self) -> Dict[str, Any]:
@@ -143,7 +166,9 @@ class OGCServerViews(AbstractViews): # type: ignore
143
166
  _query=[("msg_col", "cannot_delete")],
144
167
  ),
145
168
  }
146
- return super().delete() # type: ignore
169
+ result: Dict[str, Any] = super().delete()
170
+ cache_invalidate_cb()
171
+ return result
147
172
 
148
173
  @view_config( # type: ignore
149
174
  route_name="c2cgeoform_item_duplicate", request_method="GET", renderer="../templates/edit.jinja2"
@@ -176,16 +201,45 @@ class OGCServerViews(AbstractViews): # type: ignore
176
201
  force_ordering=force_ordering,
177
202
  clean=clean,
178
203
  )
204
+
179
205
  if "check" in self._request.params:
180
206
  synchronizer.check_layers()
207
+
181
208
  elif "dry-run" in self._request.params:
182
209
  synchronizer.synchronize(dry_run=True)
210
+
183
211
  elif "synchronize" in self._request.params:
184
212
  synchronizer.synchronize()
213
+
214
+ self._create_log(LogAction.SYNCHRONIZE, obj)
215
+
185
216
  return {
186
217
  "ogcserver": obj,
187
218
  "success": True,
188
219
  "report": synchronizer.report(),
189
220
  }
190
221
 
222
+ self._update_cache(obj)
223
+
191
224
  return {}
225
+
226
+ def _update_cache(self, ogc_server: OGCServer) -> None:
227
+ try:
228
+ ogc_server_id = ogc_server.id
229
+
230
+ def update_cache() -> None:
231
+ response = requests.get(
232
+ self._request.route_url(
233
+ "ogc_server_clear_cache",
234
+ id=ogc_server_id,
235
+ _query={
236
+ "came_from": self._request.current_route_url(),
237
+ },
238
+ )
239
+ )
240
+ if not response.ok:
241
+ LOG.error("Error while cleaning the OGC server cache:\n%s", response.text)
242
+
243
+ threading.Thread(target=update_cache).start()
244
+ except Exception:
245
+ LOG.error("Error on cleaning the OGC server cache", exc_info=True)
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2017-2021, Camptocamp SA
1
+ # Copyright (c) 2017-2023, Camptocamp SA
2
2
  # All rights reserved.
3
3
 
4
4
  # Redistribution and use in source and binary forms, with or without
@@ -30,13 +30,14 @@ from functools import partial
30
30
 
31
31
  import colander
32
32
  from c2cgeoform.schema import GeoFormManyToManySchemaNode, GeoFormSchemaNode
33
- from c2cgeoform.views.abstract_views import AbstractViews, ListField
33
+ from c2cgeoform.views.abstract_views import ListField
34
34
  from deform.widget import FormWidget
35
35
  from pyramid.view import view_config, view_defaults
36
36
  from sqlalchemy.orm import subqueryload
37
37
 
38
38
  from c2cgeoportal_admin.schemas.roles import roles_schema_node
39
39
  from c2cgeoportal_admin.schemas.treegroup import treeitem_edit_url
40
+ from c2cgeoportal_admin.views.logged_views import LoggedViews
40
41
  from c2cgeoportal_admin.widgets import ChildrenWidget, ChildWidget
41
42
  from c2cgeoportal_commons.models.main import Layer, RestrictionArea
42
43
 
@@ -87,7 +88,7 @@ base_schema.add(
87
88
 
88
89
 
89
90
  @view_defaults(match_param="table=restriction_areas")
90
- class RestrictionAreaViews(AbstractViews): # type: ignore
91
+ class RestrictionAreaViews(LoggedViews):
91
92
  """The restriction area administration view."""
92
93
 
93
94
  _list_fields = [
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2017-2021, Camptocamp SA
1
+ # Copyright (c) 2017-2023, Camptocamp SA
2
2
  # All rights reserved.
3
3
 
4
4
  # Redistribution and use in source and binary forms, with or without
@@ -30,13 +30,14 @@ from functools import partial
30
30
 
31
31
  import colander
32
32
  from c2cgeoform.schema import GeoFormManyToManySchemaNode, GeoFormSchemaNode
33
- from c2cgeoform.views.abstract_views import AbstractViews, ListField
33
+ from c2cgeoform.views.abstract_views import ListField
34
34
  from deform.widget import FormWidget
35
35
  from pyramid.view import view_config, view_defaults
36
36
  from sqlalchemy.orm import subqueryload
37
37
 
38
38
  from c2cgeoportal_admin.schemas.functionalities import functionalities_schema_node
39
39
  from c2cgeoportal_admin.schemas.restriction_areas import restrictionareas_schema_node
40
+ from c2cgeoportal_admin.views.logged_views import LoggedViews
40
41
  from c2cgeoportal_admin.widgets import ChildrenWidget, ChildWidget
41
42
  from c2cgeoportal_commons.models.main import Role
42
43
  from c2cgeoportal_commons.models.static import User
@@ -99,7 +100,7 @@ base_schema["users"].children[0].description = ""
99
100
 
100
101
 
101
102
  @view_defaults(match_param="table=roles")
102
- class RoleViews(AbstractViews): # type: ignore
103
+ class RoleViews(LoggedViews):
103
104
  """The roles administration view."""
104
105
 
105
106
  _list_fields = [
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2017-2021, Camptocamp SA
1
+ # Copyright (c) 2017-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) 2017-2021, Camptocamp SA
1
+ # Copyright (c) 2017-2023, Camptocamp SA
2
2
  # All rights reserved.
3
3
 
4
4
  # Redistribution and use in source and binary forms, with or without
@@ -29,17 +29,18 @@
29
29
  from functools import partial
30
30
 
31
31
  import sqlalchemy
32
- from c2cgeoform.views.abstract_views import AbstractViews, ListField
32
+ from c2cgeoform.views.abstract_views import ListField
33
33
  from pyramid.view import view_config
34
34
  from sqlalchemy.orm import subqueryload
35
35
  from sqlalchemy.sql.functions import concat
36
36
 
37
+ from c2cgeoportal_admin.views.logged_views import LoggedViews
37
38
  from c2cgeoportal_commons.models.main import LayergroupTreeitem, Metadata, TreeGroup, TreeItem
38
39
 
39
40
  _list_field = partial(ListField, TreeItem)
40
41
 
41
42
 
42
- class TreeItemViews(AbstractViews): # type: ignore
43
+ class TreeItemViews(LoggedViews):
43
44
  """The admin tree item view."""
44
45
 
45
46
  _list_fields = [
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2017-2022, Camptocamp SA
1
+ # Copyright (c) 2017-2023, Camptocamp SA
2
2
  # All rights reserved.
3
3
 
4
4
  # Redistribution and use in source and binary forms, with or without
@@ -29,7 +29,7 @@
29
29
  from functools import partial
30
30
 
31
31
  from c2cgeoform.schema import GeoFormSchemaNode
32
- from c2cgeoform.views.abstract_views import AbstractViews, ListField
32
+ from c2cgeoform.views.abstract_views import ListField
33
33
  from deform.widget import FormWidget
34
34
  from passwordgenerator import pwgenerator
35
35
  from pyramid.httpexceptions import HTTPFound
@@ -37,9 +37,10 @@ from pyramid.view import view_config, view_defaults
37
37
  from sqlalchemy.orm import aliased, subqueryload
38
38
 
39
39
  from c2cgeoportal_admin.schemas.roles import roles_schema_node
40
+ from c2cgeoportal_admin.views.logged_views import LoggedViews
40
41
  from c2cgeoportal_commons.lib.email_ import send_email_config
41
42
  from c2cgeoportal_commons.models.main import Role
42
- from c2cgeoportal_commons.models.static import User
43
+ from c2cgeoportal_commons.models.static import Log, User
43
44
 
44
45
  _list_field = partial(ListField, User)
45
46
 
@@ -51,7 +52,7 @@ settings_role = aliased(Role)
51
52
 
52
53
 
53
54
  @view_defaults(match_param="table=users")
54
- class UserViews(AbstractViews): # type: ignore
55
+ class UserViews(LoggedViews):
55
56
  """The admin user view."""
56
57
 
57
58
  _list_fields = [
@@ -76,6 +77,8 @@ class UserViews(AbstractViews): # type: ignore
76
77
  _id_field = "id"
77
78
  _model = User
78
79
  _base_schema = base_schema
80
+ _log_model = Log
81
+ _name_field = "username"
79
82
 
80
83
  def _base_query(self):
81
84
  return (
@@ -90,11 +90,11 @@ class ChildWidget(MappingWidget): # type: ignore
90
90
  model = TreeItem
91
91
  label_field = "name"
92
92
 
93
- def icon_class(self, child: Any) -> Optional[str]: # pylint: disable=no-self-use,useless-return
93
+ def icon_class(self, child: Any) -> Optional[str]: # pylint: disable=useless-return
94
94
  del child
95
95
  return None
96
96
 
97
- def edit_url( # pylint: disable=no-self-use,useless-return
97
+ def edit_url( # pylint: disable=useless-return
98
98
  self, request: pyramid.request.Request, child: Any
99
99
  ) -> Optional[str]:
100
100
  del request
@@ -1,11 +1,13 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: c2cgeoportal-admin
3
- Version: 2.7.1.156
3
+ Version: 2.8.1.180
4
4
  Summary: c2cgeoportal admin
5
5
  Home-page: https://github.com/camptocamp/c2cgeoportal/
6
6
  Author: Camptocamp
7
7
  Author-email: info@camptocamp.com
8
+ License: UNKNOWN
8
9
  Keywords: web gis geoportail c2cgeoportal geocommune pyramid
10
+ Platform: UNKNOWN
9
11
  Classifier: Development Status :: 6 - Mature
10
12
  Classifier: Environment :: Web Environment
11
13
  Classifier: Framework :: Pyramid
@@ -18,23 +20,25 @@ Classifier: Programming Language :: Python :: 3.8
18
20
  Classifier: Topic :: Scientific/Engineering :: GIS
19
21
  Classifier: Typing :: Typed
20
22
  Description-Content-Type: text/markdown
23
+ Requires-Dist: babel (>=2.9.1)
21
24
  Requires-Dist: c2cgeoform
22
25
  Requires-Dist: c2cwsgiutils
26
+ Requires-Dist: certifi (>=2022.12.7)
23
27
  Requires-Dist: colander
24
28
  Requires-Dist: deform
29
+ Requires-Dist: idna (>=3.7)
25
30
  Requires-Dist: passwordgenerator
31
+ Requires-Dist: pygments (>=2.15.0)
26
32
  Requires-Dist: pyproj
27
33
  Requires-Dist: pyramid
28
34
  Requires-Dist: pyramid-debugtoolbar
29
35
  Requires-Dist: pyramid-jinja2
30
36
  Requires-Dist: pyramid-tm
37
+ Requires-Dist: requests (>=2.32.0)
31
38
  Requires-Dist: sqlalchemy
32
- Requires-Dist: zope.event
33
39
  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)
40
+ Requires-Dist: urllib3 (>=1.26.17)
41
+ Requires-Dist: zope.event
38
42
 
39
43
  # c2cgeoportal admin interface
40
44
 
@@ -47,4 +51,6 @@ make preparedev
47
51
  make serve
48
52
  ```
49
53
 
50
- Now open http://localhost:8888/ in your favorite browser.
54
+ Now open http://localhost:8888/admin/ in your favorite browser.
55
+
56
+
@@ -0,0 +1,95 @@
1
+ c2cgeoportal_admin/__init__.py,sha256=uuW2AC81qIXn7bH7MLHzf9fhEK4liGg3Zi-TosyzKNs,5478
2
+ c2cgeoportal_admin/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ c2cgeoportal_admin/routes.py,sha256=tgLP5uKhgX80a2gLCpu6C92UtmqwVkOkmJ-tPxEP3QE,4712
4
+ c2cgeoportal_admin/subscribers.py,sha256=P1CaccDTpuxrWak_gMN2qBurz3OrAZ6aZ1LA7P3avu8,2430
5
+ c2cgeoportal_admin/widgets.py,sha256=bjMlC4mqx_bAjzIzzu-zqdQ7bc6tVo7mKOMbpmbeN38,6108
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=Px9SzBAv5qDTtF1xu6IRzr1u77TA8eAC3cjgI0Rxgks,15515
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=EOr9hWYBPBJ3iaUmPFgtWnBaNWadX0g9UQ0eeJ6N84E,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=8_aDM5xhtT7m-amaccEgH8T5O-SoRtFYIcGZ01VwHr0,7036
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=KSpqCNFwv37rKSmX6kL_VvCnn5egcT1eRD6kIKwWx34,1807
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=P8noHX8YAv3m6EGh0IDUJCFsyeZDX88HtlqOWab8DAU,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=jtI6CdoXJwizznjwb8ClYySgq4kbwhTIJYutSw89PAw,683
45
+ c2cgeoportal_admin/views/dimension_layers.py,sha256=jupwqX_kO37ukcWE-SsO290JdKENEmfoYxk4sRWb25Y,2598
46
+ c2cgeoportal_admin/views/functionalities.py,sha256=4oZYgs2_M0Usb3GBi40gCP6XvTbR-1PhCDZXiBnhsuk,4031
47
+ c2cgeoportal_admin/views/home.py,sha256=h_hJWIKpzJeSmXl58J0nvZdEg7avSYOOVUEEnlV-r0k,1943
48
+ c2cgeoportal_admin/views/interfaces.py,sha256=gzIRrd4D64iSH7NVaR-9oQh8-iMzjZOW5QfTfpQeYU4,3494
49
+ c2cgeoportal_admin/views/layer_groups.py,sha256=Zcdr26jyo4ZZw7sr6hYOjo6PuI9-StQ5KQ7OlIxSEtY,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=Kpgr-eWME9zxahkf-re1w6wkToKBqyInmqd_DHhj9Kc,8040
53
+ c2cgeoportal_admin/views/layers_wmts.py,sha256=HNZalKLLhPF7aXLxuFP07yr9-MGnJTg-CVD-GeokvMM,7815
54
+ c2cgeoportal_admin/views/layertree.py,sha256=plb5fL9vTaSe9EFp8VmUWl5iD9FuiQ-3TuStKAGjIKo,8587
55
+ c2cgeoportal_admin/views/logged_views.py,sha256=_XHoIl7Lw3SV_1T0c0JUeIhkluzNnjNrSUgimfk993E,3169
56
+ c2cgeoportal_admin/views/logs.py,sha256=I4ZnfNtBZmriDLIzLpLiX5HPm3Y1UvIQehemPbC2rL0,3616
57
+ c2cgeoportal_admin/views/oauth2_clients.py,sha256=lfMSwZW7pybQx3PR1btRY7XFLfx1TOx7ooVgllOqK-s,3798
58
+ c2cgeoportal_admin/views/ogc_servers.py,sha256=nGTs_pDr2knS_NAakqvxmjZE2ulrWxn2puWA_uNqgaY,9412
59
+ c2cgeoportal_admin/views/restriction_areas.py,sha256=uzfQQVRFCP-OCg1sdGzQCTkO35C1H8DZNMWIquFQqRw,5578
60
+ c2cgeoportal_admin/views/roles.py,sha256=VP0OEsW2_l99YnxGO5mdOkvPBs4Hs3nyRSbetIKtx14,5887
61
+ c2cgeoportal_admin/views/themes.py,sha256=mxpf56KXwCKG5tCYgV7xgPtQqlCU67iOBOLB7cHD-Hc,5710
62
+ c2cgeoportal_admin/views/themes_ordering.py,sha256=NYN3I2tDwLW5E4G-695DwV0dCbHUAObWVFYZ8Bir1-o,5590
63
+ c2cgeoportal_admin/views/treeitems.py,sha256=C-vjScmb_HI5QOowx3MGZBJqAHDkGTG90vshPG7FvgA,3889
64
+ c2cgeoportal_admin/views/users.py,sha256=sXCgVluLLnbbQTG8Q7tmaVfnEcHj5fBiHFCG7owVp1w,5439
65
+ tests/__init__.py,sha256=oo8kqGfoSh8AV0HhTqQfC0izcIQ8ZQPkNmONSEUUby4,9556
66
+ tests/conftest.py,sha256=ah7JmR2epDZul2rmMH5wuUzkSpXIjm8dd-cgGjK6_k0,2119
67
+ tests/test_edit_url.py,sha256=Mo_Vo5xvdpPasfjvhQUif5F3nKVpJ6GQJ_x_Hj5VNY8,4494
68
+ tests/test_functionalities.py,sha256=tGQbEsQWjr_oExI3vWhLIioxylDaoUaOfEas42YPw50,5191
69
+ tests/test_home.py,sha256=oWsKaWqRicNpUdaca54YvLIBRaGYnsXlv_Tjqv7guEQ,425
70
+ tests/test_interface.py,sha256=z1jpRzW0R2e9BJWWurE-j-YkG5yhorn7h1XRIauUQ7A,5669
71
+ tests/test_layer_groups.py,sha256=bisbaDY0SiyBc0rexYajbcvfdDt8Kux6VqXIEBLSULM,12191
72
+ tests/test_layers_vectortiles.py,sha256=PpnR8wJyRcsByPTOrrtltQUYzzQ0qRzQM2no1z1rLgU,10404
73
+ tests/test_layers_wms.py,sha256=ynqO1cnXk2ZbSXR3l9hp0IyG8PMXbmR4eyubnwRvRfU,19494
74
+ tests/test_layers_wmts.py,sha256=7zye_pZ_e0RyJdoT8oeHKPoYJMKWfTg0K8lEgMIu77Q,12181
75
+ tests/test_layertree.py,sha256=Dxe10OwuilQ-AEgVIDU4Ns9U6PQ4kPWTxwItdBE7nSg,11335
76
+ tests/test_learn.py,sha256=gQwe-Bim0eihZH0rbBWDn6_rIBxvQD_lyu9MlOljupM,2307
77
+ tests/test_left_menu.py,sha256=xnlv5sD0k3wpCChKCnbpYRN0TA895pg8k6wVvjf99-4,919
78
+ tests/test_lingua_extractor_config.py,sha256=vAfunJ4tVuqTJg4xinPwlB0EvA4sYhjY_iDBfMq8EW4,2495
79
+ tests/test_logs.py,sha256=sUBC61rCSIfg9HBavhT6c0QPmPYUnEfDm91bUaUF4Q8,3147
80
+ tests/test_main.py,sha256=_gUdMrMMAEzvGIf1QwkoHQkd0eBACz05ycTidCHP5Ao,365
81
+ tests/test_metadatas.py,sha256=bVNxvZRKNRMmjQGr7Al1d4H85EjEaoesRpxytyld4Fw,12088
82
+ tests/test_oauth2_clients.py,sha256=-aowsa2Dw77lxzuBb9ULW4iEJSB9yut-eYGP7YptT0M,7000
83
+ tests/test_ogc_servers.py,sha256=DGSMVIzYnw3bJT53VFGuPYIPMPCyHJDb5ZPJj1VM3Bo,8204
84
+ tests/test_restriction_areas.py,sha256=5VhO9ZvtFQPy1kVFm96Mh_vf1LCI5oeIdl0dfvS6JD8,9003
85
+ tests/test_role.py,sha256=eD7dXwP7RjCg14T9ncTfJuMUU4caY9yW3l5ka-gtCd4,12776
86
+ tests/test_themes.py,sha256=uhzHe2TbuNoLnL4VdYATPnOqtnZWWPKsvUTq6GUxwiU,16207
87
+ tests/test_themes_ordering.py,sha256=T4Esr0C3EN5UdeEyYLa4ePvEn-bx3RNPkGBK3lDFoBo,2243
88
+ tests/test_treegroup.py,sha256=Plv119G4TWlurWLE7Z1mWGeHHPScK_fWKcDmDzMUlIU,576
89
+ tests/test_user.py,sha256=xD0yoJa_babVK69hHQzDkTs6wRWBMXFGD8k0-DfOd-4,12814
90
+ tests/themes_ordering.py,sha256=UdydcRIzWC6RRnTMfl2JM_250DHuAhGC7rijHqfy7lk,1342
91
+ c2cgeoportal_admin-2.8.1.180.dist-info/METADATA,sha256=4IZ5Bu5mH3ErjEWDbuTwu1xItrt3UDnOtbtmZXLYQxQ,1597
92
+ c2cgeoportal_admin-2.8.1.180.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
93
+ c2cgeoportal_admin-2.8.1.180.dist-info/entry_points.txt,sha256=kz-7AnYsbtK04jTpGUtcOeu2NbQiXW3CQV3AjyC32tw,165
94
+ c2cgeoportal_admin-2.8.1.180.dist-info/top_level.txt,sha256=DgcTJgTvpJUB8HqwYB14PdLBPAOAFk0B8oqnSTFoAU4,25
95
+ c2cgeoportal_admin-2.8.1.180.dist-info/RECORD,,
@@ -3,3 +3,4 @@ geomapfish-admin-config = c2cgeoportal_admin.lib.lingua_extractor:GeomapfishConf
3
3
 
4
4
  [paste.app_factory]
5
5
  main = c2cgeoportal_admin:main
6
+
tests/__init__.py CHANGED
@@ -54,7 +54,6 @@ def factory_build_layers(layer_builder, dbsession, add_dimension=True):
54
54
 
55
55
  layers = []
56
56
  for i in range(0, 25):
57
-
58
57
  layer = layer_builder(i)
59
58
 
60
59
  if add_dimension:
@@ -90,7 +89,6 @@ def factory_build_layers(layer_builder, dbsession, add_dimension=True):
90
89
 
91
90
 
92
91
  class AbstractViewsTests:
93
-
94
92
  _prefix = None # url prefix (index view url). Example: /users
95
93
 
96
94
  def get(self, test_app, path="", locale="en", status=200, **kwargs):
@@ -120,7 +118,8 @@ class AbstractViewsTests:
120
118
  )
121
119
  actions = resp.html.select_one('th[data-field="actions"]')
122
120
  assert "false" == actions.attrs["data-sortable"]
123
- assert 1 == len(list(filter(lambda x: next(x.stripped_strings) == new, resp.html.findAll("a"))))
121
+ if new is not False:
122
+ assert 1 == len(list(filter(lambda x: next(x.stripped_strings) == new, resp.html.findAll("a"))))
124
123
 
125
124
  def check_search(self, test_app, search="", offset=0, limit=10, sort="", order="", total=None):
126
125
  json = test_app.post(
tests/test_edit_url.py CHANGED
@@ -92,7 +92,6 @@ def edit_url_test_data(dbsession, transact):
92
92
 
93
93
  @pytest.mark.usefixtures("edit_url_test_data", "test_app")
94
94
  class TestUrlEdit(AbstractViewsTests):
95
-
96
95
  _prefix = "/admin/"
97
96
 
98
97
  def _get(self, test_app, tablename, pk):
@@ -31,7 +31,6 @@ def functionality_test_data(dbsession, transact, settings):
31
31
 
32
32
  @pytest.mark.usefixtures("functionality_test_data", "test_app")
33
33
  class TestFunctionality(AbstractViewsTests):
34
-
35
34
  _prefix = "/admin/functionalities"
36
35
 
37
36
  def test_index_rendering(self, test_app):
@@ -53,7 +52,7 @@ class TestFunctionality(AbstractViewsTests):
53
52
  self.check_search(test_app, "default_basemap", total=1)
54
53
 
55
54
  def test_submit_new(self, dbsession, test_app):
56
- from c2cgeoportal_commons.models.main import Functionality
55
+ from c2cgeoportal_commons.models.main import Functionality, Log, LogAction
57
56
 
58
57
  resp = test_app.post(
59
58
  "/admin/functionalities/new",
@@ -66,7 +65,17 @@ class TestFunctionality(AbstractViewsTests):
66
65
  ).group(1)
67
66
  assert functionality.name == "new_name"
68
67
 
69
- def test_edit(self, test_app, functionality_test_data):
68
+ log = dbsession.query(Log).one()
69
+ assert log.date != None
70
+ assert log.action == LogAction.INSERT
71
+ assert log.element_type == "functionality"
72
+ assert log.element_id == functionality.id
73
+ assert log.element_name == functionality.name
74
+ assert log.username == "test_user"
75
+
76
+ def test_edit(self, test_app, functionality_test_data, dbsession):
77
+ from c2cgeoportal_commons.models.main import Log, LogAction
78
+
70
79
  functionality = functionality_test_data["functionalities"][0]
71
80
  resp = test_app.get(f"/admin/functionalities/{functionality.id}", status=200)
72
81
  form = resp.form
@@ -77,14 +86,30 @@ class TestFunctionality(AbstractViewsTests):
77
86
  assert form.submit().status_int == 302
78
87
  assert functionality.description == "new_description"
79
88
 
89
+ log = dbsession.query(Log).one()
90
+ assert log.date != None
91
+ assert log.action == LogAction.UPDATE
92
+ assert log.element_type == "functionality"
93
+ assert log.element_id == functionality.id
94
+ assert log.element_name == functionality.name
95
+ assert log.username == "test_user"
96
+
80
97
  def test_delete(self, test_app, functionality_test_data, dbsession):
81
- from c2cgeoportal_commons.models.main import Functionality
98
+ from c2cgeoportal_commons.models.main import Functionality, Log, LogAction
82
99
 
83
100
  functionality = functionality_test_data["functionalities"][0]
84
101
  deleted_id = functionality.id
85
102
  test_app.delete(f"/admin/functionalities/{deleted_id}", status=200)
86
103
  assert dbsession.query(Functionality).get(deleted_id) is None
87
104
 
105
+ log = dbsession.query(Log).one()
106
+ assert log.date != None
107
+ assert log.action == LogAction.DELETE
108
+ assert log.element_type == "functionality"
109
+ assert log.element_id == functionality.id
110
+ assert log.element_name == functionality.name
111
+ assert log.username == "test_user"
112
+
88
113
  def test_duplicate(self, functionality_test_data, test_app, dbsession):
89
114
  from c2cgeoportal_commons.models.main import Functionality
90
115
 
tests/test_home.py CHANGED
@@ -5,7 +5,6 @@ from . import AbstractViewsTests
5
5
 
6
6
  @pytest.mark.usefixtures("test_app")
7
7
  class TestHome(AbstractViewsTests):
8
-
9
8
  _prefix = "/admin/"
10
9
 
11
10
  def test_index_rendering(self, test_app):
tests/test_interface.py CHANGED
@@ -45,7 +45,6 @@ def interface_test_data(dbsession, transact):
45
45
 
46
46
  @pytest.mark.usefixtures("interface_test_data", "test_app")
47
47
  class TestInterface(AbstractViewsTests):
48
-
49
48
  _prefix = "/admin/interfaces"
50
49
 
51
50
  def test_index_rendering(self, test_app):
@@ -82,7 +81,7 @@ class TestInterface(AbstractViewsTests):
82
81
  self.check_search(test_app, "interface_0", total=1)
83
82
 
84
83
  def test_submit_new(self, dbsession, test_app):
85
- from c2cgeoportal_commons.models.main import Interface
84
+ from c2cgeoportal_commons.models.main import Interface, Log, LogAction
86
85
 
87
86
  resp = test_app.post(
88
87
  "/admin/interfaces/new", {"name": "new_name", "description": "new description"}, status=302
@@ -94,8 +93,16 @@ class TestInterface(AbstractViewsTests):
94
93
  ).group(1)
95
94
  assert interface.name == "new_name"
96
95
 
96
+ log = dbsession.query(Log).one()
97
+ assert log.date != None
98
+ assert log.action == LogAction.INSERT
99
+ assert log.element_type == "interface"
100
+ assert log.element_id == interface.id
101
+ assert log.element_name == interface.name
102
+ assert log.username == "test_user"
103
+
97
104
  def test_edit(self, test_app, interface_test_data, dbsession):
98
- from c2cgeoportal_commons.models.main import Interface
105
+ from c2cgeoportal_commons.models.main import Interface, Log, LogAction
99
106
 
100
107
  interface = interface_test_data["interfaces"][0]
101
108
  descriptions = "{}, {}".format(
@@ -110,13 +117,29 @@ class TestInterface(AbstractViewsTests):
110
117
  assert form.submit().status_int == 302
111
118
  assert len(dbsession.query(Interface).filter(Interface.description == descriptions).all()) == 1
112
119
 
120
+ log = dbsession.query(Log).one()
121
+ assert log.date != None
122
+ assert log.action == LogAction.UPDATE
123
+ assert log.element_type == "interface"
124
+ assert log.element_id == interface.id
125
+ assert log.element_name == interface.name
126
+ assert log.username == "test_user"
127
+
113
128
  def test_delete(self, test_app, interface_test_data, dbsession):
114
- from c2cgeoportal_commons.models.main import Interface
129
+ from c2cgeoportal_commons.models.main import Interface, Log, LogAction
115
130
 
116
131
  interface = interface_test_data["interfaces"][0]
117
132
  test_app.delete(f"/admin/interfaces/{interface.id}", status=200)
118
133
  assert len(dbsession.query(Interface).filter(Interface.id == interface.id).all()) == 0
119
134
 
135
+ log = dbsession.query(Log).one()
136
+ assert log.date != None
137
+ assert log.action == LogAction.DELETE
138
+ assert log.element_type == "interface"
139
+ assert log.element_id == interface.id
140
+ assert log.element_name == interface.name
141
+ assert log.username == "test_user"
142
+
120
143
  def test_duplicate(self, interface_test_data, test_app):
121
144
  interface = interface_test_data["interfaces"][3]
122
145
  resp = test_app.get(f"/admin/interfaces/{interface.id}/duplicate", status=200)