imio.smartweb.core 1.2.12__py3-none-any.whl → 1.2.19__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 (98) hide show
  1. imio/smartweb/core/browser/configure.zcml +1 -1
  2. imio/smartweb/core/browser/dashboards/configure.zcml +0 -2
  3. imio/smartweb/core/browser/dashboards/plausible.py +4 -4
  4. imio/smartweb/core/browser/static/smartweb-edit-compiled.js +1 -1
  5. imio/smartweb/core/browser/static/src/edit.js +5 -0
  6. imio/smartweb/core/browser/utils.py +4 -30
  7. imio/smartweb/core/contents/__init__.py +2 -0
  8. imio/smartweb/core/contents/rest/base.py +12 -0
  9. imio/smartweb/core/contents/rest/configure.zcml +7 -0
  10. imio/smartweb/core/contents/rest/directory/content.py +2 -2
  11. imio/smartweb/core/contents/rest/directory/view.pt +2 -1
  12. imio/smartweb/core/contents/rest/directory/view.py +3 -0
  13. imio/smartweb/core/contents/rest/events/content.py +2 -2
  14. imio/smartweb/core/contents/rest/events/view.pt +2 -1
  15. imio/smartweb/core/contents/rest/events/view.py +3 -0
  16. imio/smartweb/core/contents/rest/news/content.py +2 -2
  17. imio/smartweb/core/contents/rest/news/view.pt +2 -1
  18. imio/smartweb/core/contents/rest/news/view.py +3 -0
  19. imio/smartweb/core/contents/rest/search/endpoint.py +1 -1
  20. imio/smartweb/core/contents/rest/traversal.py +18 -0
  21. imio/smartweb/core/contents/rest/view.py +7 -0
  22. imio/smartweb/core/contents/sections/events/view.py +1 -1
  23. imio/smartweb/core/contents/sections/news/view.py +1 -1
  24. imio/smartweb/core/interfaces.py +4 -0
  25. imio/smartweb/core/profiles/default/actions.xml +15 -0
  26. imio/smartweb/core/profiles/default/metadata.xml +1 -1
  27. imio/smartweb/core/rest/authentic_sources.py +21 -11
  28. imio/smartweb/core/tests/test_rest.py +120 -0
  29. imio/smartweb/core/tests/utils.py +15 -0
  30. imio/smartweb/core/upgrades/configure.zcml +18 -0
  31. imio/smartweb/core/upgrades/profiles/1051_to_1052/actions.xml +20 -0
  32. imio/smartweb/core/utils.py +31 -0
  33. imio/smartweb/core/viewlets/configure.zcml +11 -0
  34. imio/smartweb/core/viewlets/httpheaders.py +13 -0
  35. imio/smartweb/core/viewlets/ogp_tag_header.pt +10 -0
  36. imio/smartweb/core/viewlets/ogptags.py +8 -0
  37. imio/smartweb/core/webcomponents/build/css/54.smartweb-webcomponents-compiled.css +1 -0
  38. imio/smartweb/core/webcomponents/build/css/647.smartweb-webcomponents-compiled.css +1 -0
  39. imio/smartweb/core/webcomponents/build/js/3.smartweb-webcomponents-compiled.js +2 -0
  40. imio/smartweb/core/webcomponents/build/js/323.smartweb-webcomponents-compiled.js +1 -1
  41. imio/smartweb/core/webcomponents/build/js/363.smartweb-webcomponents-compiled.js +2 -0
  42. imio/smartweb/core/webcomponents/build/js/493.smartweb-webcomponents-compiled.js +1 -0
  43. imio/smartweb/core/webcomponents/build/js/54.smartweb-webcomponents-compiled.js +1 -0
  44. imio/smartweb/core/webcomponents/build/js/647.smartweb-webcomponents-compiled.js +2 -0
  45. imio/smartweb/core/webcomponents/build/js/647.smartweb-webcomponents-compiled.js.LICENSE.txt +1 -0
  46. imio/smartweb/core/webcomponents/build/js/smartweb-webcomponents-compiled.js +1 -1
  47. imio/smartweb/core/webcomponents/package.json +14 -17
  48. imio/smartweb/core/webcomponents/src/assets/contentIcon/download.svg +1 -0
  49. imio/smartweb/core/webcomponents/src/components/Annuaire/Annuaire.jsx +85 -84
  50. imio/smartweb/core/webcomponents/src/components/Annuaire/ContactCard/ContactCard.jsx +22 -23
  51. imio/smartweb/core/webcomponents/src/components/Annuaire/ContactContent/ContactContent.jsx +109 -93
  52. imio/smartweb/core/webcomponents/src/components/Annuaire/ContactContent/download.svg +1 -0
  53. imio/smartweb/core/webcomponents/src/components/Annuaire/ContactList/ContactList.jsx +7 -7
  54. imio/smartweb/core/webcomponents/src/components/Events/EventCard/EventCard.jsx +43 -0
  55. imio/smartweb/core/webcomponents/src/components/Events/{ContactContent/ContactContent.jsx → EventContent/EventContent.jsx} +76 -81
  56. imio/smartweb/core/webcomponents/src/components/Events/{ContactList/ContactList.jsx → EventList/EventList.jsx} +9 -9
  57. imio/smartweb/core/webcomponents/src/components/Events/Events.jsx +99 -98
  58. imio/smartweb/core/webcomponents/src/components/Events/Events.scss +1 -1
  59. imio/smartweb/core/webcomponents/src/components/News/News.jsx +23 -25
  60. imio/smartweb/core/webcomponents/src/components/News/News.scss +3 -5
  61. imio/smartweb/core/webcomponents/src/components/News/{ContactCard/ContactCard.jsx → NewsCard/NewsCard.jsx} +14 -27
  62. imio/smartweb/core/webcomponents/src/components/News/{ContactContent/ContactContent.jsx → NewsContent/NewsContent.jsx} +37 -40
  63. imio/smartweb/core/webcomponents/src/components/News/{ContactList/ContactList.jsx → NewsList/NewsList.jsx} +9 -9
  64. imio/smartweb/core/webcomponents/src/components/Search/ContactResult/ContactResult.jsx +5 -5
  65. imio/smartweb/core/webcomponents/src/components/Search/EventsResult/EventsResult.jsx +5 -5
  66. imio/smartweb/core/webcomponents/src/components/Search/NewsResult/NewsResult.jsx +5 -5
  67. imio/smartweb/core/webcomponents/src/components/Search/WebResult/WebResult.jsx +3 -3
  68. imio/smartweb/core/webcomponents/src/{components/Events/ContactMap/ContactMap.jsx → utils/Map.jsx} +60 -64
  69. {imio.smartweb.core-1.2.12.dist-info → imio.smartweb.core-1.2.19.dist-info}/METADATA +59 -1
  70. {imio.smartweb.core-1.2.12.dist-info → imio.smartweb.core-1.2.19.dist-info}/RECORD +80 -82
  71. imio/smartweb/core/webcomponents/build/css/267.smartweb-webcomponents-compiled.css +0 -1
  72. imio/smartweb/core/webcomponents/build/css/779.smartweb-webcomponents-compiled.css +0 -1
  73. imio/smartweb/core/webcomponents/build/js/267.smartweb-webcomponents-compiled.js +0 -1
  74. imio/smartweb/core/webcomponents/build/js/552.smartweb-webcomponents-compiled.js +0 -2
  75. imio/smartweb/core/webcomponents/build/js/565.smartweb-webcomponents-compiled.js +0 -1
  76. imio/smartweb/core/webcomponents/build/js/612.smartweb-webcomponents-compiled.js +0 -2
  77. imio/smartweb/core/webcomponents/build/js/779.smartweb-webcomponents-compiled.js +0 -1
  78. imio/smartweb/core/webcomponents/pnpm-lock.yaml +0 -7066
  79. imio/smartweb/core/webcomponents/src/components/Annuaire/ContactMap/ContactMap.jsx +0 -156
  80. imio/smartweb/core/webcomponents/src/components/Annuaire/Skeleton/LoaderCss.jsx +0 -7
  81. imio/smartweb/core/webcomponents/src/components/Annuaire/Skeleton/Skeleton.jsx +0 -20
  82. imio/smartweb/core/webcomponents/src/components/Events/ContactCard/ContactCard.jsx +0 -49
  83. imio/smartweb/core/webcomponents/src/components/Events/ContactMap/ContactMap.scss +0 -0
  84. imio/smartweb/core/webcomponents/src/components/Events/Skeleton/Skeleton.jsx +0 -20
  85. imio/smartweb/core/webcomponents/src/components/News/ContactMap/ContactMap.jsx +0 -127
  86. imio/smartweb/core/webcomponents/src/components/News/ContactMap/ContactMap.scss +0 -4
  87. imio/smartweb/core/webcomponents/src/components/News/Skeleton/Skeleton.jsx +0 -20
  88. imio/smartweb/core/webcomponents/src/components/Search/Skeleton/Skeleton.jsx +0 -20
  89. /imio/smartweb/core/webcomponents/build/css/{552.smartweb-webcomponents-compiled.css → 363.smartweb-webcomponents-compiled.css} +0 -0
  90. /imio/smartweb/core/webcomponents/build/js/{552.smartweb-webcomponents-compiled.js.LICENSE.txt → 3.smartweb-webcomponents-compiled.js.LICENSE.txt} +0 -0
  91. /imio/smartweb/core/webcomponents/build/js/{612.smartweb-webcomponents-compiled.js.LICENSE.txt → 363.smartweb-webcomponents-compiled.js.LICENSE.txt} +0 -0
  92. /imio/smartweb/core/webcomponents/src/{components/Annuaire/ContactMap/ContactMap.scss → utils/Map.scss} +0 -0
  93. /imio.smartweb.core-1.2.12-py3.10-nspkg.pth → /imio.smartweb.core-1.2.19-py3.10-nspkg.pth +0 -0
  94. {imio.smartweb.core-1.2.12.dist-info → imio.smartweb.core-1.2.19.dist-info}/LICENSE.GPL +0 -0
  95. {imio.smartweb.core-1.2.12.dist-info → imio.smartweb.core-1.2.19.dist-info}/LICENSE.rst +0 -0
  96. {imio.smartweb.core-1.2.12.dist-info → imio.smartweb.core-1.2.19.dist-info}/WHEEL +0 -0
  97. {imio.smartweb.core-1.2.12.dist-info → imio.smartweb.core-1.2.19.dist-info}/namespace_packages.txt +0 -0
  98. {imio.smartweb.core-1.2.12.dist-info → imio.smartweb.core-1.2.19.dist-info}/top_level.txt +0 -0
@@ -57,7 +57,7 @@
57
57
  for="*"
58
58
  class=".utils.UtilsView"
59
59
  permission="zope2.View"
60
- allowed_attributes="is_previewable_content map_configuration"
60
+ allowed_attributes="is_previewable_content map_configuration is_plausible_set"
61
61
  layer="imio.smartweb.core.interfaces.IImioSmartwebCoreLayer"
62
62
  />
63
63
 
@@ -5,9 +5,7 @@
5
5
  <include package="plone.app.contentmenu" />
6
6
  <browser:page
7
7
  name="stats"
8
- title="Plausible dashboard"
9
8
  template="plausible.pt"
10
- menu="plone_displayviews"
11
9
  for="plone.base.interfaces.siteroot.IPloneSiteRoot"
12
10
  class=".plausible.PlausibleView"
13
11
  permission="cmf.ModifyPortalContent"
@@ -1,18 +1,18 @@
1
1
  from Products.Five.browser import BrowserView
2
- from imio.smartweb.core.browser.utils import get_plausible_vars
2
+ from imio.smartweb.core.utils import get_plausible_vars
3
3
 
4
4
 
5
5
  class PlausibleView(BrowserView):
6
6
  @property
7
7
  def is_plausible_set(self):
8
- return True if get_plausible_vars(self) else False
8
+ return True if get_plausible_vars() else False
9
9
 
10
10
  @property
11
11
  def get_embedhostjs_src(self):
12
- vars = get_plausible_vars(self)
12
+ vars = get_plausible_vars()
13
13
  return f"https://{vars['plausible_url']}/js/embed.host.js"
14
14
 
15
15
  @property
16
16
  def get_iframe_src(self):
17
- vars = get_plausible_vars(self)
17
+ vars = get_plausible_vars()
18
18
  return f"https://{vars['plausible_url']}/share/{vars['plausible_site']}?auth={vars['plausible_token']}&embed=true&theme=light&background=transparent"
@@ -1 +1 @@
1
- (()=>{"use strict";jQuery(document).ready((function(e){e("#contentview-preview a").click((function(o){e(".hide-in-preview, #section-byline, #global_statusmessage").toggle("fast"),o.preventDefault()})),e("#formfield-form-widgets-svg_icon input").click((function(o){var s=e(this);e(this).attr("checked")?(e(this).prop("checked",!1),e(this).removeAttr("checked"),e(this).css("box-shadow","none"),e(this).css("border-color","#DEE2ED")):e("#formfield-form-widgets-svg_icon input").each((function(o,t){s[0]===t?(e(this).prop("checked",!0),e(this).attr("checked","checked"),e(this).css("border-color","#007a99"),e(this).css("box-shadow","0 0 0 0.25rem rgb(0 122 153 / 25%)")):(e(this).prop("checked",!1),e(this).removeAttr("checked"),e(this).css("box-shadow","none"),e(this).css("border-color","#DEE2ED"))}))}))})),jQuery(window).on("load",(function(e){var o=$("#plone-authentic-sources-menu").wrap("<ul class='plonetoolbar-authentic-sources-menu'>").parent();$(".personaltools-wrapper").prepend(o);var s=$("#plone-smartweb-help-menu").wrap("<ul class='plonetoolbar-smartweb-help-menu'>").parent();$(".personaltools-wrapper").prepend(s)}))})();
1
+ (()=>{"use strict";jQuery(document).ready((function(e){e("#contentview-preview a").click((function(o){e(".hide-in-preview, #section-byline, #global_statusmessage").toggle("fast"),o.preventDefault()})),e("#formfield-form-widgets-svg_icon input").click((function(o){var s=e(this);e(this).attr("checked")?(e(this).prop("checked",!1),e(this).removeAttr("checked"),e(this).css("box-shadow","none"),e(this).css("border-color","#DEE2ED")):e("#formfield-form-widgets-svg_icon input").each((function(o,t){s[0]===t?(e(this).prop("checked",!0),e(this).attr("checked","checked"),e(this).css("border-color","#007a99"),e(this).css("box-shadow","0 0 0 0.25rem rgb(0 122 153 / 25%)")):(e(this).prop("checked",!1),e(this).removeAttr("checked"),e(this).css("box-shadow","none"),e(this).css("border-color","#DEE2ED"))}))}));var o=e("li:has(a[href*='@@stats'])");e("#collapse-personaltools li:eq(0)").after(o)})),jQuery(window).on("load",(function(e){var o=$("#plone-authentic-sources-menu").wrap("<ul class='plonetoolbar-authentic-sources-menu'>").parent();$(".personaltools-wrapper").prepend(o);var s=$("#plone-smartweb-help-menu").wrap("<ul class='plonetoolbar-smartweb-help-menu'>").parent();$(".personaltools-wrapper").prepend(s)}))})();
@@ -32,6 +32,11 @@ jQuery(document).ready(function ($) {
32
32
  })
33
33
  }
34
34
  });
35
+
36
+ // Move statistics action menu entry as the first element in personaltools menu
37
+ var $stat_link = $("li:has(a[href*='@@stats'])");
38
+ $("#collapse-personaltools li:eq(0)").after($stat_link);
39
+
35
40
  });
36
41
 
37
42
  jQuery(window).on("load", function(e) {
@@ -2,6 +2,7 @@
2
2
  from Products.Five.browser import BrowserView
3
3
  from imio.smartweb.core.contents import IPages
4
4
  from imio.smartweb.core.contents.pages.procedure.utils import sign_url
5
+ from imio.smartweb.core.utils import get_plausible_vars
5
6
  from imio.smartweb.locales import SmartwebMessageFactory as _
6
7
  from plone import api
7
8
  from plone.api.portal import get_registry_record
@@ -75,33 +76,6 @@ class UtilsView(BrowserView):
75
76
  }
76
77
  )
77
78
 
78
-
79
- def get_plausible_vars(self):
80
- env_plausible_url = os.getenv("SMARTWEB_PLAUSIBLE_URL", "")
81
- env_plausible_site = os.getenv("SMARTWEB_PLAUSIBLE_SITE", "")
82
- env_plausible_token = os.getenv("SMARTWEB_PLAUSIBLE_TOKEN", "")
83
-
84
- plausible_url = (
85
- env_plausible_url
86
- if (env_plausible_url and env_plausible_url != "")
87
- else api.portal.get_registry_record("smartweb.plausible_url")
88
- )
89
- plausible_site = (
90
- env_plausible_site
91
- if (env_plausible_site and env_plausible_site != "")
92
- else api.portal.get_registry_record("smartweb.plausible_site")
93
- )
94
- plausible_token = (
95
- env_plausible_token
96
- if (env_plausible_token and env_plausible_token != "")
97
- else api.portal.get_registry_record("smartweb.plausible_token")
98
- )
99
- if all([plausible_site, plausible_url, plausible_token]):
100
- plausible_vars = {
101
- "plausible_url": plausible_url,
102
- "plausible_site": plausible_site,
103
- "plausible_token": plausible_token,
104
- }
105
- return plausible_vars
106
- else:
107
- return None
79
+ def is_plausible_set(self):
80
+ """ """
81
+ return True if get_plausible_vars() else False
@@ -17,6 +17,8 @@ from .pages.portal_page.content import IPortalPage # NOQA
17
17
  from .pages.portal_page.content import PortalPage # NOQA
18
18
  from .pages.procedure.content import IProcedure # NOQA
19
19
  from .pages.procedure.content import Procedure # NOQA
20
+ from .rest.base import RestView # NOQA
21
+ from .rest.base import IRestView # NOQA
20
22
  from .rest.directory.content import DirectoryView # NOQA
21
23
  from .rest.directory.content import IDirectoryView # NOQA
22
24
  from .rest.events.content import EventsView # NOQA
@@ -2,7 +2,10 @@
2
2
 
3
3
  from imio.smartweb.core.utils import get_json
4
4
  from plone import api
5
+ from plone.dexterity.content import Container
5
6
  from plone.rest import Service
7
+ from zope.interface import implementer
8
+ from zope.interface import Interface
6
9
 
7
10
  import json
8
11
 
@@ -71,3 +74,12 @@ class BaseService(Service):
71
74
  indent=2,
72
75
  separators=(", ", ": "),
73
76
  )
77
+
78
+
79
+ class IRestView(Interface):
80
+ """"""
81
+
82
+
83
+ @implementer(IRestView)
84
+ class RestView(Container):
85
+ """Shared base class for REST views contents"""
@@ -6,4 +6,11 @@
6
6
  <include package=".news" />
7
7
  <include package=".search" />
8
8
 
9
+ <adapter
10
+ for="imio.smartweb.core.contents.IRestView
11
+ zope.publisher.interfaces.http.IHTTPRequest"
12
+ provides="zope.publisher.interfaces.IPublishTraverse"
13
+ factory=".traversal.RestViewTraversable"
14
+ />
15
+
9
16
  </configure>
@@ -1,9 +1,9 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
+ from imio.smartweb.core.contents import RestView
3
4
  from imio.smartweb.locales import SmartwebMessageFactory as _
4
5
  from plone.app.z3cform.widget import SelectFieldWidget
5
6
  from plone.autoform import directives
6
- from plone.dexterity.content import Container
7
7
  from plone.supermodel import model
8
8
  from zope import schema
9
9
  from zope.interface import implementer
@@ -34,5 +34,5 @@ class IDirectoryView(model.Schema):
34
34
 
35
35
 
36
36
  @implementer(IDirectoryView)
37
- class DirectoryView(Container):
37
+ class DirectoryView(RestView):
38
38
  """DirectoryView class"""
@@ -10,7 +10,8 @@
10
10
  propose-url view/propose_url;
11
11
  orientation view/orientation;
12
12
  current-language view/current_language;
13
- display-map view/display_map;"></smartweb-annuaire>
13
+ display-map view/display_map;
14
+ view-path view/view_path;"></smartweb-annuaire>
14
15
  </div>
15
16
  </metal:main>
16
17
  </body>
@@ -1,9 +1,12 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
3
  from imio.smartweb.core.contents.rest.view import BaseRestView
4
+ from imio.smartweb.core.interfaces import IOgpViewUtils
4
5
  from plone import api
6
+ from zope.interface import implementer
5
7
 
6
8
 
9
+ @implementer(IOgpViewUtils)
7
10
  class DirectoryViewView(BaseRestView):
8
11
  """DirectoryView view"""
9
12
 
@@ -1,8 +1,8 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
+ from imio.smartweb.core.contents import RestView
3
4
  from imio.smartweb.locales import SmartwebMessageFactory as _
4
5
  from plone.autoform import directives
5
- from plone.dexterity.content import Container
6
6
  from plone.supermodel import model
7
7
  from z3c.form.browser.checkbox import CheckBoxFieldWidget
8
8
  from zope import schema
@@ -39,5 +39,5 @@ class IEventsView(model.Schema):
39
39
 
40
40
 
41
41
  @implementer(IEventsView)
42
- class EventsView(Container):
42
+ class EventsView(RestView):
43
43
  """EventsView class"""
@@ -11,7 +11,8 @@
11
11
  propose-url view/propose_url;
12
12
  orientation view/orientation;
13
13
  current-language view/current_language;
14
- display-map view/display_map;"></smartweb-events>
14
+ display-map view/display_map;
15
+ view-path view/view_path;"></smartweb-events>
15
16
  </div>
16
17
  </metal:main>
17
18
  </body>
@@ -1,9 +1,12 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
3
  from imio.smartweb.core.contents.rest.view import BaseRestView
4
+ from imio.smartweb.core.interfaces import IOgpViewUtils
4
5
  from plone import api
6
+ from zope.interface import implementer
5
7
 
6
8
 
9
+ @implementer(IOgpViewUtils)
7
10
  class EventsViewView(BaseRestView):
8
11
  """EventsView view"""
9
12
 
@@ -1,7 +1,7 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
+ from imio.smartweb.core.contents import RestView
3
4
  from imio.smartweb.locales import SmartwebMessageFactory as _
4
- from plone.dexterity.content import Container
5
5
  from plone.supermodel import model
6
6
  from zope import schema
7
7
  from zope.interface import implementer
@@ -23,5 +23,5 @@ class INewsView(model.Schema):
23
23
 
24
24
 
25
25
  @implementer(INewsView)
26
- class NewsView(Container):
26
+ class NewsView(RestView):
27
27
  """NewsView class"""
@@ -10,7 +10,8 @@
10
10
  batch-size view/batch_size;
11
11
  propose-url view/propose_url;
12
12
  orientation view/orientation;
13
- current-language view/current_language;"></smartweb-news>
13
+ current-language view/current_language;
14
+ view-path view/view_path;"></smartweb-news>
14
15
  </div>
15
16
  </metal:main>
16
17
  </body>
@@ -1,9 +1,12 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
3
  from imio.smartweb.core.contents.rest.view import BaseRestView
4
+ from imio.smartweb.core.interfaces import IOgpViewUtils
4
5
  from plone import api
6
+ from zope.interface import implementer
5
7
 
6
8
 
9
+ @implementer(IOgpViewUtils)
7
10
  class NewsViewView(BaseRestView):
8
11
  """NewsView view"""
9
12
 
@@ -153,7 +153,7 @@ class ExtendedSearchHandler(SearchHandler):
153
153
  del item[fname]
154
154
  type_mapping = mapping[item["@type"]]
155
155
  base_url = type_mapping.get(item["container_uid"], type_mapping["default"])
156
- item["_url"] = "{base}#/content?u={item_uid}".format(
156
+ item["_url"] = "{base}/content?u={item_uid}".format(
157
157
  base=base_url,
158
158
  item_uid=item["UID"],
159
159
  )
@@ -0,0 +1,18 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ from imio.smartweb.core.contents import IRestView
4
+ from ZPublisher.BaseRequest import DefaultPublishTraverse
5
+ from zope.component import adapts
6
+ from zope.publisher.interfaces.http import IHTTPRequest
7
+
8
+
9
+ class RestViewTraversable(DefaultPublishTraverse):
10
+ """ """
11
+
12
+ adapts(IRestView, IHTTPRequest)
13
+
14
+ def publishTraverse(self, request, name):
15
+ if "u" in self.request.form and name != "view":
16
+ return self.context
17
+
18
+ return super(RestViewTraversable, self).publishTraverse(request, name)
@@ -3,6 +3,7 @@
3
3
  from imio.smartweb.core.interfaces import IViewWithoutLeadImage
4
4
  from plone import api
5
5
  from Products.Five import BrowserView
6
+ from urllib.parse import urlsplit
6
7
  from zope.interface import implementer
7
8
 
8
9
 
@@ -29,3 +30,9 @@ class BaseRestView(BrowserView):
29
30
  @property
30
31
  def current_language(self):
31
32
  return api.portal.get_current_language()[:2]
33
+
34
+ @property
35
+ def view_path(self):
36
+ url = self.context.absolute_url()
37
+ parsed = urlsplit(url)
38
+ return url.replace(f"{parsed.scheme}://{parsed.netloc}", "")
@@ -68,7 +68,7 @@ class EventsView(CarouselOrTableSectionView, HashableJsonSectionView):
68
68
  "description": item["description"],
69
69
  "category": item["category_title"],
70
70
  "event_date": date_dict,
71
- "url": f"{linking_view_url}#/{item_id}?u={item_uid}",
71
+ "url": f"{linking_view_url}/{item_id}?u={item_uid}",
72
72
  "has_image": item["has_leadimage"],
73
73
  "image": f"{item_url}/@@images/image/{orientation}_{image_scale}?cache_key={modified_hash}",
74
74
  }
@@ -61,7 +61,7 @@ class NewsView(CarouselOrTableSectionView, HashableJsonSectionView):
61
61
  "description": item["description"],
62
62
  "category": item["category_title"],
63
63
  "effective": item["effective"],
64
- "url": f"{linking_view_url}#/{item_id}?u={item_uid}",
64
+ "url": f"{linking_view_url}/{item_id}?u={item_uid}",
65
65
  "has_image": item["has_leadimage"],
66
66
  "image": f"{item_url}/@@images/image/{orientation}_{image_scale}?cache_key={modified_hash}",
67
67
  }
@@ -31,3 +31,7 @@ class IArcgisViewUtils(Interface):
31
31
 
32
32
  def get_portal_item_id():
33
33
  """Return id of a map"""
34
+
35
+
36
+ class IOgpViewUtils(Interface):
37
+ """ """
@@ -88,6 +88,21 @@
88
88
  </object>
89
89
  </object>
90
90
 
91
+ <object meta_type="CMF Action Category" name="user">
92
+ <object meta_type="CMF Action" name="dashboard" i18n:domain="plone" remove="True" />
93
+ <object meta_type="CMF Action" name="statistics" i18n:domain="imio.smartweb">
94
+ <property name="title" i18n:translate="">Statistics</property>
95
+ <property name="description" i18n:translate=""/>
96
+ <property name="url_expr">string:$portal_url/@@stats</property>
97
+ <property name="icon_expr">string:activity</property>
98
+ <property name="available_expr">portal/@@utils/is_plausible_set</property>
99
+ <property name="permissions">
100
+ <element value="Add portal content"/>
101
+ </property>
102
+ <property name="visible">True</property>
103
+ </object>
104
+ </object>
105
+
91
106
  <object name="header_actions" meta_type="CMF Action Category">
92
107
  <object name="account" meta_type="CMF Action" i18n:domain="imio.smartweb">
93
108
  <property name="title" i18n:translate="">My account</property>
@@ -1,6 +1,6 @@
1
1
  <?xml version='1.0' encoding='UTF-8'?>
2
2
  <metadata>
3
- <version>1051</version>
3
+ <version>1052</version>
4
4
  <dependencies>
5
5
  <dependency>profile-plone.app.dexterity:default</dependency>
6
6
  <dependency>profile-plone.app.imagecropping:default</dependency>
@@ -39,34 +39,44 @@ class BaseRequestForwarder(Service):
39
39
  token = get_wca_token(self.client_id, self.client_secret)
40
40
  headers = {"Accept": "application/json", "Authorization": token}
41
41
  params = self.request.form
42
- params = self.add_missing_metadatas(params)
42
+ if method == "GET":
43
+ params = self.add_missing_metadatas(params)
43
44
  data = json_body(self.request)
44
45
 
45
46
  # Forward the request to the authentic source
46
47
  auth_source_response = requests.request(
47
- method, url, params=params, headers=headers, data=data
48
+ method, url, params=params, headers=headers, json=data
48
49
  )
49
-
50
50
  response = self.request.response
51
51
  # Set the status code and headers from the authentic source server response
52
52
  response.setStatus(auth_source_response.status_code)
53
53
  for header, value in auth_source_response.headers.items():
54
54
  response.setHeader(header, value)
55
55
 
56
+ if auth_source_response.status_code == 204 or auth_source_response.text == "":
57
+ # Empty response
58
+ return ""
59
+
56
60
  return auth_source_response.json()
57
61
 
62
+ def construct_url(self, view_url, item):
63
+ # we can construct a Smartweb-related URL for item
64
+ # TODO: handle other views & translations (use/refactor code in
65
+ # search endpoint)
66
+ item_uid = item["UID"]
67
+ item_id = item.get("id", "content")
68
+ item["smartweb_url"] = f"{view_url}/{item_id}?u={item_uid}"
69
+
58
70
  def add_smartweb_urls(self, json_data):
59
- if "items" not in json_data:
71
+ if "items" not in json_data and "@id" not in json_data:
72
+ return json_data
73
+ default_view_url = get_default_view_url(self.request_type)
74
+ if "@id" in json_data and "UID" in json_data:
75
+ self.construct_url(default_view_url, json_data)
60
76
  return json_data
61
77
  for item in json_data.get("items", []):
62
78
  if "@id" in item and "UID" in item:
63
- # we can construct a Smartweb-related URL for item
64
- # TODO: handle other views & translations (use/refactor code in
65
- # search endpoint)
66
- default_view_url = get_default_view_url(self.request_type)
67
- item_uid = item["UID"]
68
- item_id = item["id"]
69
- item["smartweb_url"] = f"{default_view_url}#/{item_id}?u={item_uid}"
79
+ self.construct_url(default_view_url, item)
70
80
  return json_data
71
81
 
72
82
  def add_missing_metadatas(self, params):
@@ -1,5 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
+ from base64 import b64encode
3
4
  from freezegun import freeze_time
4
5
  from imio.smartweb.core import config
5
6
  from imio.smartweb.core.contents.rest.base import BaseEndpoint
@@ -8,16 +9,20 @@ from imio.smartweb.core.contents.rest.events.endpoint import EventsEndpoint
8
9
  from imio.smartweb.core.contents.rest.news.endpoint import NewsEndpoint
9
10
  from imio.smartweb.core.testing import IMIO_SMARTWEB_CORE_ACCEPTANCE_TESTING
10
11
  from imio.smartweb.core.testing import ImioSmartwebTestCase
12
+ from imio.smartweb.core.tests.utils import FakeResponse
11
13
  from imio.smartweb.core.tests.utils import get_json
12
14
  from plone import api
13
15
  from plone.app.testing import setRoles
14
16
  from plone.app.testing import TEST_USER_ID
17
+ from plone.app.testing import TEST_USER_PASSWORD
15
18
  from plone.restapi.testing import RelativeSession
16
19
  from unittest.mock import patch
17
20
  from urllib.parse import urlparse
18
21
  from urllib.parse import parse_qs
19
22
  from zope.component import queryMultiAdapter
23
+ from zope.event import notify
20
24
  from zope.publisher.browser import TestRequest
25
+ from ZPublisher.pubevents import PubStart
21
26
 
22
27
  import json
23
28
  import requests_mock
@@ -73,6 +78,21 @@ class SectionsFunctionalTest(ImioSmartwebTestCase):
73
78
  def tearDown(self):
74
79
  self.api_session.close()
75
80
 
81
+ def traverse(self, path="/plone", method="GET"):
82
+ request = self.layer["request"]
83
+ request.environ["PATH_INFO"] = path
84
+ request.environ["PATH_TRANSLATED"] = path
85
+ request.environ["HTTP_ACCEPT"] = "application/json"
86
+ request.environ["REQUEST_METHOD"] = method
87
+ request.other["ACTUAL_URL"] = ""
88
+ request.other["URL"] = ""
89
+ request.method = method
90
+ request.form = {}
91
+ auth = f"{TEST_USER_ID}:{TEST_USER_PASSWORD}"
92
+ request._auth = "Basic %s" % b64encode(auth.encode("utf8")).decode("utf8")
93
+ notify(PubStart(request))
94
+ return request.traverse(path)
95
+
76
96
  @freeze_time("2021-09-14 8:00:00")
77
97
  def test_convert_cached_image_scales(self):
78
98
  endpoint = BaseEndpoint(self.portal, self.request)
@@ -366,3 +386,103 @@ class SectionsFunctionalTest(ImioSmartwebTestCase):
366
386
  self.rest_events.display_map = True
367
387
  view = queryMultiAdapter((self.rest_events, self.request), name="view")
368
388
  self.assertIn('display-map="True"', view())
389
+
390
+ @patch("imio.smartweb.core.rest.authentic_sources.get_wca_token")
391
+ @patch("imio.smartweb.core.rest.authentic_sources.requests.request")
392
+ @patch("imio.smartweb.core.rest.authentic_sources.get_default_view_url")
393
+ def test_request_forwarder(self, mock_view_url, mock_request, mock_get_wca_token):
394
+ mock_view_url.return_value = "http://view-url"
395
+ mock_get_wca_token.return_value = "kamoulox"
396
+ mock_request.return_value = FakeResponse(
397
+ status_code=200,
398
+ headers={"test-header": "True"},
399
+ )
400
+
401
+ # traversal stack
402
+ service = self.traverse("/plone/@news_request_forwarder/belleville/@search")
403
+ self.assertListEqual(service.traversal_stack, ["belleville", "@search"])
404
+
405
+ # add_smartweb_urls
406
+ json_data = {}
407
+ self.assertEqual(service.add_smartweb_urls(json_data), json_data)
408
+ json_data = {"foo": "bar"}
409
+ self.assertEqual(service.add_smartweb_urls(json_data), json_data)
410
+ json_data = {"@id": "http://news/my-news"}
411
+ self.assertEqual(service.add_smartweb_urls(json_data), json_data)
412
+ json_data = {"@id": "http://news/my-news", "UID": "12345678"}
413
+ json_result = service.add_smartweb_urls(json_data)
414
+ self.assertEqual(
415
+ json_result["smartweb_url"], "http://view-url/content?u=12345678"
416
+ )
417
+ json_data = {"items": []}
418
+ self.assertEqual(service.add_smartweb_urls(json_data), json_data)
419
+ json_data = {"items": [{"@id": "http://news/my-news"}]}
420
+ self.assertEqual(service.add_smartweb_urls(json_data), json_data)
421
+ json_data = {"items": [{"@id": "http://news/my-news", "UID": "12345678"}]}
422
+ json_result = service.add_smartweb_urls(json_data)
423
+ self.assertIn("smartweb_url", json_result["items"][0])
424
+ self.assertEqual(
425
+ json_data["items"][0]["smartweb_url"], "http://view-url/content?u=12345678"
426
+ )
427
+
428
+ # add_missing_metadatas
429
+ params = {}
430
+ self.assertEqual(
431
+ service.add_missing_metadatas(params), {"metadata_fields": ["id", "UID"]}
432
+ )
433
+ params = {"fullobjects": 1}
434
+ self.assertEqual(service.add_missing_metadatas(params), params)
435
+ params = {"metadata_fields": ["other", "UID"]}
436
+ self.assertEqual(
437
+ service.add_missing_metadatas(params),
438
+ {"metadata_fields": ["other", "UID", "id"]},
439
+ )
440
+ params = {"metadata_fields": ["other", "id"]}
441
+ self.assertEqual(
442
+ service.add_missing_metadatas(params),
443
+ {"metadata_fields": ["other", "id", "UID"]},
444
+ )
445
+
446
+ # reply
447
+ response = service.reply()
448
+ mock_request.assert_called_with(
449
+ "GET",
450
+ "http://localhost:8080/Plone/belleville/@search",
451
+ params={"metadata_fields": ["id", "UID"]},
452
+ headers={"Accept": "application/json", "Authorization": "kamoulox"},
453
+ json={},
454
+ )
455
+ self.assertEqual(response, {})
456
+ self.assertEqual(self.request.response.status, 200)
457
+ self.assertEqual(self.request.response.headers, {"test-header": "True"})
458
+
459
+ service = self.traverse(
460
+ "/plone/@events_request_forwarder/belleville/", method="POST"
461
+ )
462
+ service.reply()
463
+ mock_request.assert_called_with(
464
+ "POST",
465
+ "http://localhost:8080/Plone/belleville",
466
+ params={},
467
+ headers={"Accept": "application/json", "Authorization": "kamoulox"},
468
+ json={},
469
+ )
470
+
471
+ mock_request.side_effect = None
472
+ mock_request.return_value = FakeResponse(status_code=204)
473
+ service = self.traverse(
474
+ "/plone/@events_request_forwarder/belleville/", method="PATCH"
475
+ )
476
+ response = service.reply()
477
+ self.assertEqual(response, "")
478
+ self.assertEqual(self.request.response.status, 204)
479
+
480
+ self.assertEqual(
481
+ self.api_session.get("/@directory_request_forwarder/foo/bar").text, ""
482
+ )
483
+ self.assertEqual(
484
+ self.api_session.get("/@events_request_forwarder/foo/bar").text, ""
485
+ )
486
+ self.assertEqual(
487
+ self.api_session.get("/@news_request_forwarder/foo/bar").text, ""
488
+ )
@@ -94,3 +94,18 @@ def make_named_image(filename="plone.png"):
94
94
  with open(path, "rb") as f:
95
95
  image_data = f.read()
96
96
  return {"filename": filename, "data": image_data}
97
+
98
+
99
+ class FakeResponse:
100
+ status_code = 404
101
+ headers = {}
102
+ text = "{}"
103
+
104
+ def __init__(self, status_code=None, headers=None):
105
+ if status_code:
106
+ self.status_code = status_code
107
+ if headers:
108
+ self.headers = headers
109
+
110
+ def json(self):
111
+ return json.loads(self.text)