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
@@ -42,6 +42,7 @@ from transaction import TransactionManager
42
42
  from translationstring import TranslationStringFactory
43
43
 
44
44
  from c2cgeoportal_admin.subscribers import add_localizer, add_renderer_globals
45
+ from c2cgeoportal_admin.views import IsAdminPredicate
45
46
 
46
47
  search_paths = (resource_filename(__name__, "templates/widgets"),) + c2cgeoform.default_search_paths
47
48
  c2cgeoform.default_search_paths = search_paths
@@ -83,6 +84,19 @@ def main(_, **settings):
83
84
  reify=True,
84
85
  )
85
86
 
87
+ # Add fake user as we do not have authentication from geoportal
88
+ from c2cgeoportal_commons.models.static import User # pylint: disable=import-outside-toplevel
89
+
90
+ config.add_request_method(
91
+ lambda request: User(
92
+ username="test_user",
93
+ ),
94
+ name="user",
95
+ property=True,
96
+ )
97
+
98
+ config.add_route("ogc_server_clear_cache", "/ogc_server_clear_cache/{id}")
99
+
86
100
  config.add_subscriber(add_renderer_globals, BeforeRender)
87
101
  config.add_subscriber(add_localizer, NewRequest)
88
102
 
@@ -118,6 +132,7 @@ def includeme(config: Configurator) -> None:
118
132
  # Use pyramid_tm to hook the transaction lifecycle to the request
119
133
  config.include("pyramid_tm")
120
134
  config.add_translation_dirs("c2cgeoportal_admin:locale")
135
+ config.add_view_predicate("is_admin", IsAdminPredicate)
121
136
 
122
137
  configure_mappers()
123
138
 
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2020-2021, Camptocamp SA
1
+ # Copyright (c) 2020-2023, Camptocamp SA
2
2
  # All rights reserved.
3
3
 
4
4
  # Redistribution and use in source and binary forms, with or without
@@ -357,7 +357,7 @@ class OGCServerSynchronizer:
357
357
 
358
358
  return layer
359
359
 
360
- @functools.lru_cache()
360
+ @functools.lru_cache(maxsize=10)
361
361
  def wms_capabilities(self) -> bytes:
362
362
  errors: Set[str] = set()
363
363
  url = get_url2(
@@ -367,7 +367,7 @@ class OGCServerSynchronizer:
367
367
  errors,
368
368
  )
369
369
  if url is None:
370
- raise Exception("\n".join(errors))
370
+ raise Exception("\n".join(errors)) # pylint: disable=broad-exception-raised
371
371
 
372
372
  # Add functionality params
373
373
  # sparams = get_mapserver_substitution_params(self.request)
@@ -401,7 +401,7 @@ class OGCServerSynchronizer:
401
401
  "application/vnd.ogc.wms_xml",
402
402
  "text/xml",
403
403
  ]:
404
- raise Exception(
404
+ raise Exception( # pylint: disable=broad-exception-raised
405
405
  f"GetCapabilities from URL '{url}' returns a wrong Content-Type: "
406
406
  f"{response.headers.get('Content-Type', '')}\n{response.text}"
407
407
  )
@@ -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
@@ -61,6 +61,7 @@ def includeme(config):
61
61
  LayerVectorTiles,
62
62
  LayerWMS,
63
63
  LayerWMTS,
64
+ Log,
64
65
  OGCServer,
65
66
  RestrictionArea,
66
67
  Role,
@@ -84,6 +85,7 @@ def includeme(config):
84
85
  ("functionalities", Functionality),
85
86
  ("interfaces", Interface),
86
87
  ("oauth2_clients", OAuth2Client),
88
+ ("logs", Log),
87
89
  ]
88
90
 
89
91
  admin_interface_config = config.registry.settings["admin_interface"]
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2018-2021, 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
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2018-2022, Camptocamp SA
1
+ # Copyright (c) 2018-2024, Camptocamp SA
2
2
  # All rights reserved.
3
3
 
4
4
  # Redistribution and use in source and binary forms, with or without
@@ -78,7 +78,7 @@ def treeitems(
78
78
  .distinct()
79
79
  .outerjoin("parents_relation")
80
80
  .filter(TreeItem.item_type != "theme")
81
- .group_by(TreeItem.id)
81
+ .group_by(TreeItem)
82
82
  .order_by(group.desc(), TreeItem.name)
83
83
  )
84
84
 
@@ -24,8 +24,24 @@
24
24
  {% extends "layout.jinja2" %}
25
25
 
26
26
  {% block content %}
27
- <div class="content">
28
- <h1><span class="font-semi-bold">Pyramid</span> <span class="smaller">Alchemy scaffold</span></h1>
27
+ <div class="container-fluid">
28
+ {% if "table" in request.matchdict %}
29
+ {% for table in request.c2cgeoform_application.tables() %}
30
+ {% if table["key"] == request.matchdict["table"] %}
31
+ <h2>
32
+ {{ table["title"] }}
33
+ </h2>
34
+ {% endif %}
35
+ {% endfor %}
36
+ {% endif %}
37
+ {% if context.detail %}
38
+ <p>{{ context.detail }}</p>
39
+ {% else %}
40
+ {% if "id" in request.matchdict and "table" in request.matchdict %}
41
+ <p>{{ _("Element id '{}' not found, probably deleted.").format(request.matchdict["id"]) }}</p>
42
+ {% else %}
29
43
  <p class="lead"><span class="font-semi-bold">404</span> Page Not Found</p>
44
+ {% endif %}
45
+ {% endif %}
30
46
  </div>
31
47
  {% endblock content %}
@@ -87,7 +87,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
87
87
  $typedFormgroup.find('.form-control').attr('disabled', false);
88
88
 
89
89
  $helpBlock = $typedFormgroup.find('p.help-block');
90
- $helpBlock.text(description);
90
+ $helpBlock.html(description);
91
91
  };
92
92
  $name.change(function() {
93
93
  updateType();
@@ -0,0 +1,29 @@
1
+ import pyramid.httpexceptions
2
+ import pyramid.request
3
+ from pyramid.view import view_config
4
+
5
+
6
+ class IsAdminPredicate:
7
+ """
8
+ A custom predicate that checks if the request is for the admin interface.
9
+ """
10
+
11
+ def __init__(self, val, info):
12
+ del info
13
+
14
+ self.val = val
15
+
16
+ def text(self):
17
+ return f"is_admin = {self.val}"
18
+
19
+ phash = text
20
+
21
+ def __call__(self, context, request):
22
+ return request.path.startswith("/admin/") or request.path == "/admin"
23
+
24
+
25
+ @view_config(context=pyramid.httpexceptions.HTTPNotFound, is_admin=True, renderer="../templates/404.jinja2")
26
+ def _not_found_view(request=pyramid.request.Request):
27
+ del request
28
+
29
+ return {}
@@ -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
@@ -32,11 +32,12 @@ from typing import Any, Dict
32
32
  import colander
33
33
  import pyramid.request
34
34
  from c2cgeoform.schema import GeoFormSchemaNode
35
- from c2cgeoform.views.abstract_views import AbstractViews, ListField
35
+ from c2cgeoform.views.abstract_views import ListField
36
36
  from deform.widget import FormWidget
37
37
  from pyramid.view import view_config, view_defaults
38
38
 
39
39
  from c2cgeoportal_admin import _
40
+ from c2cgeoportal_admin.views.logged_views import LoggedViews
40
41
  from c2cgeoportal_commons.models.main import Functionality
41
42
 
42
43
  _list_field = partial(ListField, Functionality)
@@ -66,7 +67,7 @@ base_schema = GeoFormSchemaNode(
66
67
 
67
68
 
68
69
  @view_defaults(match_param="table=functionalities")
69
- class FunctionalityViews(AbstractViews): # type: ignore
70
+ class FunctionalityViews(LoggedViews):
70
71
  """The functionality administration view."""
71
72
 
72
73
  _list_fields = [_list_field("id"), _list_field("name"), _list_field("description"), _list_field("value")]
@@ -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,9 +29,10 @@
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 pyramid.view import view_config, view_defaults
34
34
 
35
+ from c2cgeoportal_admin.views.logged_views import LoggedViews
35
36
  from c2cgeoportal_commons.models.main import Interface
36
37
 
37
38
  _list_field = partial(ListField, Interface)
@@ -40,7 +41,7 @@ base_schema = GeoFormSchemaNode(Interface)
40
41
 
41
42
 
42
43
  @view_defaults(match_param="table=interfaces")
43
- class InterfacesViews(AbstractViews): # type: ignore
44
+ class InterfacesViews(LoggedViews):
44
45
  """The interface administration view."""
45
46
 
46
47
  _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
@@ -44,7 +44,7 @@ from c2cgeoportal_admin.schemas.metadata import metadata_schema_node
44
44
  from c2cgeoportal_admin.schemas.restriction_areas import restrictionareas_schema_node
45
45
  from c2cgeoportal_admin.schemas.treeitem import parent_id_node
46
46
  from c2cgeoportal_admin.views.dimension_layers import DimensionLayerViews
47
- from c2cgeoportal_commons.models.main import LayerGroup, LayerWMS, LayerWMTS, OGCServer, TreeItem
47
+ from c2cgeoportal_commons.models.main import LayerGroup, LayerWMS, LayerWMTS, LogAction, OGCServer, TreeItem
48
48
 
49
49
  _list_field = partial(ListField, LayerWMS)
50
50
 
@@ -130,7 +130,7 @@ class LayerWmsViews(DimensionLayerViews):
130
130
 
131
131
  @view_config(route_name="c2cgeoform_item", request_method="DELETE", renderer="fast_json") # type: ignore
132
132
  def delete(self) -> Dict[str, Any]:
133
- return super().delete() # type: ignore
133
+ return super().delete()
134
134
 
135
135
  @view_config( # type: ignore
136
136
  route_name="c2cgeoform_item_duplicate", request_method="GET", renderer="../templates/edit.jinja2"
@@ -172,6 +172,8 @@ class LayerWmsViews(DimensionLayerViews):
172
172
  dbsession.flush()
173
173
  mark_changed(dbsession)
174
174
 
175
+ self._create_log(LogAction.CONVERT_TO_WMTS, src, element_url_table="layers_wmts")
176
+
175
177
  return {
176
178
  "success": True,
177
179
  "redirect": self._request.route_url(
@@ -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
@@ -44,7 +44,7 @@ from c2cgeoportal_admin.schemas.metadata import metadata_schema_node
44
44
  from c2cgeoportal_admin.schemas.restriction_areas import restrictionareas_schema_node
45
45
  from c2cgeoportal_admin.schemas.treeitem import parent_id_node
46
46
  from c2cgeoportal_admin.views.dimension_layers import DimensionLayerViews
47
- from c2cgeoportal_commons.models.main import LayerGroup, LayerWMS, LayerWMTS, OGCServer, TreeItem
47
+ from c2cgeoportal_commons.models.main import LayerGroup, LayerWMS, LayerWMTS, LogAction, OGCServer, TreeItem
48
48
 
49
49
  _list_field = partial(ListField, LayerWMTS)
50
50
 
@@ -122,7 +122,7 @@ class LayerWmtsViews(DimensionLayerViews):
122
122
 
123
123
  @view_config(route_name="c2cgeoform_item", request_method="DELETE", renderer="fast_json") # type: ignore
124
124
  def delete(self) -> Dict[str, Any]:
125
- return super().delete() # type: ignore
125
+ return super().delete()
126
126
 
127
127
  @view_config( # type: ignore
128
128
  route_name="c2cgeoform_item_duplicate", request_method="GET", renderer="../templates/edit.jinja2"
@@ -165,6 +165,8 @@ class LayerWmtsViews(DimensionLayerViews):
165
165
  dbsession.flush()
166
166
  mark_changed(dbsession)
167
167
 
168
+ self._create_log(LogAction.CONVERT_TO_WMS, src, element_url_table="layers_wms")
169
+
168
170
  return {
169
171
  "success": True,
170
172
  "redirect": self._request.route_url(
@@ -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
@@ -45,7 +45,7 @@ itemtypes_tables = {
45
45
  }
46
46
 
47
47
 
48
- @view_defaults(match_param=("application=admin"))
48
+ @view_defaults(match_param="application=admin")
49
49
  class LayerTreeViews:
50
50
  """The layer tree administration view."""
51
51
 
@@ -0,0 +1,80 @@
1
+ # Copyright (c) 2023-2023, Camptocamp SA
2
+ # All rights reserved.
3
+
4
+ # Redistribution and use in source and binary forms, with or without
5
+ # modification, are permitted provided that the following conditions are met:
6
+
7
+ # 1. Redistributions of source code must retain the above copyright notice, this
8
+ # list of conditions and the following disclaimer.
9
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
10
+ # this list of conditions and the following disclaimer in the documentation
11
+ # and/or other materials provided with the distribution.
12
+
13
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
14
+ # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15
+ # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
17
+ # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18
+ # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19
+ # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20
+ # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21
+ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22
+ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23
+
24
+ # The views and conclusions contained in the software and documentation are those
25
+ # of the authors and should not be interpreted as representing official policies,
26
+ # either expressed or implied, of the FreeBSD Project.
27
+
28
+ import datetime
29
+ from typing import Any, Dict, Optional, Union
30
+
31
+ import pytz
32
+ from c2cgeoform.views.abstract_views import AbstractViews
33
+ from pyramid.httpexceptions import HTTPFound
34
+
35
+ from c2cgeoportal_commons.models import Base
36
+ from c2cgeoportal_commons.models.main import Log, LogAction
37
+
38
+
39
+ class LoggedViews(AbstractViews): # type: ignore
40
+ """Extension of AbstractViews which log actions in a table."""
41
+
42
+ _log_model = Log # main.Log or static.Log
43
+ _name_field = "name"
44
+
45
+ def save(self) -> Union[HTTPFound, Dict[str, Any]]:
46
+ response = super().save()
47
+
48
+ if isinstance(response, HTTPFound):
49
+ self._create_log(
50
+ action=LogAction.INSERT if self._is_new() else LogAction.UPDATE,
51
+ obj=self._obj,
52
+ )
53
+
54
+ return response
55
+
56
+ def delete(self) -> Dict[str, Any]:
57
+ obj = self._get_object()
58
+
59
+ response = super().delete()
60
+
61
+ self._create_log(LogAction.DELETE, obj)
62
+
63
+ return response # type: ignore
64
+
65
+ def _create_log(
66
+ self,
67
+ action: LogAction,
68
+ obj: Base,
69
+ element_url_table: Optional[str] = None,
70
+ ) -> None:
71
+ log = self._log_model(
72
+ date=datetime.datetime.now(pytz.utc),
73
+ action=action,
74
+ element_type=self._model.__tablename__,
75
+ element_id=getattr(obj, self._id_field),
76
+ element_name=getattr(obj, self._name_field),
77
+ element_url_table=element_url_table or self._request.matchdict.get("table", None),
78
+ username=self._request.user.username,
79
+ )
80
+ self._request.dbsession.add(log)
@@ -0,0 +1,90 @@
1
+ # Copyright (c) 2023-2023, Camptocamp SA
2
+ # All rights reserved.
3
+
4
+ # Redistribution and use in source and binary forms, with or without
5
+ # modification, are permitted provided that the following conditions are met:
6
+
7
+ # 1. Redistributions of source code must retain the above copyright notice, this
8
+ # list of conditions and the following disclaimer.
9
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
10
+ # this list of conditions and the following disclaimer in the documentation
11
+ # and/or other materials provided with the distribution.
12
+
13
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
14
+ # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15
+ # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
17
+ # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18
+ # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19
+ # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20
+ # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21
+ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22
+ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23
+
24
+ # The views and conclusions contained in the software and documentation are those
25
+ # of the authors and should not be interpreted as representing official policies,
26
+ # either expressed or implied, of the FreeBSD Project.
27
+
28
+ from functools import partial
29
+
30
+ from c2cgeoform.views.abstract_views import AbstractViews, ItemAction, ListField
31
+ from pyramid.view import view_config, view_defaults
32
+
33
+ from c2cgeoportal_commons.models import _
34
+ from c2cgeoportal_commons.models.main import AbstractLog
35
+
36
+ _list_field = partial(ListField, AbstractLog)
37
+
38
+
39
+ @view_defaults(match_param="table=logs")
40
+ class LogViews(AbstractViews): # type: ignore
41
+ """The theme administration view."""
42
+
43
+ # We pass labels explicitly because actually we are not able to get info
44
+ # from InstrumentedAttribute created from AbstractConcreteBase.
45
+ _list_fields = [
46
+ _list_field("id"),
47
+ _list_field("date", label=_("Date")),
48
+ _list_field("username", label=_("Username")),
49
+ _list_field("action", label=_("Action"), renderer=lambda log: log.action.name),
50
+ _list_field("element_type", label=_("Element type")),
51
+ _list_field("element_id", label=_("Element identifier")),
52
+ _list_field("element_name", label=_("Element name")),
53
+ ]
54
+ _list_ordered_fields = [AbstractLog.date.desc()]
55
+
56
+ _id_field = "id"
57
+ _model = AbstractLog
58
+
59
+ @view_config(route_name="c2cgeoform_index", renderer="../templates/index.jinja2")
60
+ def index(self):
61
+ return super().index()
62
+
63
+ @view_config(route_name="c2cgeoform_grid", renderer="fast_json")
64
+ def grid(self):
65
+ return super().grid()
66
+
67
+ def _grid_actions(self):
68
+ return []
69
+
70
+ def _grid_item_actions(self, item):
71
+ element_url = self._request.route_url(
72
+ "c2cgeoform_item",
73
+ table=item.element_url_table,
74
+ id=item.element_id,
75
+ )
76
+
77
+ return {
78
+ "dblclick": element_url,
79
+ "dropdown": [
80
+ ItemAction(
81
+ name="edit_element",
82
+ label=_("Edit element"),
83
+ icon="glyphicon glyphicon-pencil",
84
+ url=element_url,
85
+ ).to_dict(self._request)
86
+ ],
87
+ }
88
+
89
+ def _item_actions(self, item, readonly=False):
90
+ return []
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2021, 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
@@ -30,10 +30,11 @@ from functools import partial
30
30
  from typing import Any, Dict
31
31
 
32
32
  from c2cgeoform.schema import GeoFormSchemaNode
33
- from c2cgeoform.views.abstract_views import AbstractViews, ListField
33
+ from c2cgeoform.views.abstract_views import ListField
34
34
  from pyramid.view import view_config, view_defaults
35
35
 
36
- from c2cgeoportal_commons.models.static import OAuth2Client
36
+ from c2cgeoportal_admin.views.logged_views import LoggedViews
37
+ from c2cgeoportal_commons.models.static import Log, OAuth2Client
37
38
 
38
39
  _list_field = partial(ListField, OAuth2Client)
39
40
 
@@ -42,7 +43,7 @@ base_schema.add_unique_validator(OAuth2Client.client_id, OAuth2Client.id)
42
43
 
43
44
 
44
45
  @view_defaults(match_param="table=oauth2_clients")
45
- class OAuth2ClientViews(AbstractViews): # type: ignore
46
+ class OAuth2ClientViews(LoggedViews):
46
47
  """The oAuth2 client administration view."""
47
48
 
48
49
  _list_fields = [
@@ -54,6 +55,8 @@ class OAuth2ClientViews(AbstractViews): # type: ignore
54
55
  _id_field = "id"
55
56
  _model = OAuth2Client
56
57
  _base_schema = base_schema
58
+ _log_model = Log
59
+ _name_field = "client_id"
57
60
 
58
61
  def _base_query(self):
59
62
  return self._request.dbsession.query(OAuth2Client)
@@ -76,11 +79,11 @@ class OAuth2ClientViews(AbstractViews): # type: ignore
76
79
  route_name="c2cgeoform_item", request_method="POST", renderer="../templates/edit.jinja2"
77
80
  )
78
81
  def save(self) -> Dict[str, Any]:
79
- return super().save() # type: ignore
82
+ return super().save()
80
83
 
81
84
  @view_config(route_name="c2cgeoform_item", request_method="DELETE", renderer="fast_json") # type: ignore
82
85
  def delete(self) -> Dict[str, Any]:
83
- return super().delete() # type: ignore
86
+ return super().delete()
84
87
 
85
88
  @view_config( # type: ignore
86
89
  route_name="c2cgeoform_item_duplicate", request_method="GET", renderer="../templates/edit.jinja2"