imio.smartweb.core 1.2.90__py3-none-any.whl → 1.3__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 (96) hide show
  1. imio/smartweb/core/browser/controlpanel.py +42 -5
  2. imio/smartweb/core/browser/utils.py +4 -1
  3. imio/smartweb/core/configure.zcml +5 -1
  4. imio/smartweb/core/contents/__init__.py +2 -0
  5. imio/smartweb/core/contents/rest/campaign/__init__.py +0 -0
  6. imio/smartweb/core/contents/rest/campaign/configure.zcml +80 -0
  7. imio/smartweb/core/contents/rest/campaign/content.py +83 -0
  8. imio/smartweb/core/contents/rest/campaign/endpoint.py +211 -0
  9. imio/smartweb/core/contents/rest/campaign/view.pt +19 -0
  10. imio/smartweb/core/contents/rest/campaign/view.py +29 -0
  11. imio/smartweb/core/contents/rest/configure.zcml +1 -0
  12. imio/smartweb/core/interfaces.py +4 -0
  13. imio/smartweb/core/overrides.zcml +10 -0
  14. imio/smartweb/core/profiles/default/metadata.xml +1 -1
  15. imio/smartweb/core/profiles/ideabox/browserlayer.xml +7 -0
  16. imio/smartweb/core/profiles/ideabox/metadata.xml +5 -0
  17. imio/smartweb/core/profiles/ideabox/registry/iaideabox.xml +9 -0
  18. imio/smartweb/core/profiles/ideabox/types/imio.smartweb.CampaignView.xml +40 -0
  19. imio/smartweb/core/profiles/ideabox/types/imio.smartweb.Folder.xml +71 -0
  20. imio/smartweb/core/profiles/ideabox/types.xml +17 -0
  21. imio/smartweb/core/profiles/ideabox_uninstall/browserlayer.xml +7 -0
  22. imio/smartweb/core/profiles/ideabox_uninstall/types/imio.smartweb.Folder.xml +25 -0
  23. imio/smartweb/core/profiles/ideabox_uninstall/types.xml +4 -0
  24. imio/smartweb/core/profiles/testing/metadata.xml +1 -0
  25. imio/smartweb/core/profiles/testing/registry.xml +2 -2
  26. imio/smartweb/core/profiles.zcml +18 -0
  27. imio/smartweb/core/subscribers.py +27 -1
  28. imio/smartweb/core/subscribers.zcml +8 -0
  29. imio/smartweb/core/tests/resources/json_ideabox_campaign.json +222 -0
  30. imio/smartweb/core/tests/resources/json_ideabox_campaigns.json +425 -0
  31. imio/smartweb/core/tests/resources/json_ideabox_projects.json +1871 -0
  32. imio/smartweb/core/tests/test_iadeliberations.py +38 -40
  33. imio/smartweb/core/tests/test_ideabox.py +120 -0
  34. imio/smartweb/core/tests/test_procedure.py +7 -3
  35. imio/smartweb/core/tests/test_rest.py +7 -0
  36. imio/smartweb/core/tests/test_vocabularies.py +8 -10
  37. imio/smartweb/core/upgrades/configure.zcml +16 -1
  38. imio/smartweb/core/upgrades/upgrades.py +64 -0
  39. imio/smartweb/core/utils.py +33 -0
  40. imio/smartweb/core/viewlets/actions.py +10 -0
  41. imio/smartweb/core/viewlets/header_actions.pt +2 -0
  42. imio/smartweb/core/viewlets/offcanvas.pt +31 -6
  43. imio/smartweb/core/viewlets/ogptags.py +9 -0
  44. imio/smartweb/core/viewlets/subsite_logo.pt +1 -1
  45. imio/smartweb/core/vocabularies.py +35 -4
  46. imio/smartweb/core/vocabularies.zcml +6 -0
  47. imio/smartweb/core/webcomponents/build/css/373.smartweb-webcomponents-compiled.css +1 -1
  48. imio/smartweb/core/webcomponents/build/css/420.smartweb-webcomponents-compiled.css +1 -0
  49. imio/smartweb/core/webcomponents/build/css/486.smartweb-webcomponents-compiled.css +1 -1
  50. imio/smartweb/core/webcomponents/build/css/666.smartweb-webcomponents-compiled.css +1 -0
  51. imio/smartweb/core/webcomponents/build/css/884.smartweb-webcomponents-compiled.css +1 -1
  52. imio/smartweb/core/webcomponents/build/css/smartweb-webcomponents-compiled.css +1 -1
  53. imio/smartweb/core/webcomponents/build/js/141.smartweb-webcomponents-compiled.js +2 -0
  54. imio/smartweb/core/webcomponents/build/js/{828.smartweb-webcomponents-compiled.js.LICENSE.txt → 141.smartweb-webcomponents-compiled.js.LICENSE.txt} +3 -3
  55. imio/smartweb/core/webcomponents/build/js/15.smartweb-webcomponents-compiled.js +2 -0
  56. imio/smartweb/core/webcomponents/build/js/21.smartweb-webcomponents-compiled.js +1 -0
  57. imio/smartweb/core/webcomponents/build/js/218.smartweb-webcomponents-compiled.js +1 -1
  58. imio/smartweb/core/webcomponents/build/js/218.smartweb-webcomponents-compiled.js.LICENSE.txt +0 -5
  59. imio/smartweb/core/webcomponents/build/js/373.smartweb-webcomponents-compiled.js +1 -1
  60. imio/smartweb/core/webcomponents/build/js/486.smartweb-webcomponents-compiled.js +1 -1
  61. imio/smartweb/core/webcomponents/build/js/666.smartweb-webcomponents-compiled.js +1 -0
  62. imio/smartweb/core/webcomponents/build/js/799.smartweb-webcomponents-compiled.js +1 -1
  63. imio/smartweb/core/webcomponents/build/js/824.smartweb-webcomponents-compiled.js +1 -1
  64. imio/smartweb/core/webcomponents/build/js/884.smartweb-webcomponents-compiled.js +1 -1
  65. imio/smartweb/core/webcomponents/build/js/919.smartweb-webcomponents-compiled.js +1 -1
  66. imio/smartweb/core/webcomponents/build/js/922.smartweb-webcomponents-compiled.js +1 -0
  67. imio/smartweb/core/webcomponents/build/js/smartweb-webcomponents-compiled.js +1 -1
  68. imio/smartweb/core/webcomponents/package.json +80 -80
  69. imio/smartweb/core/webcomponents/src/components/Annuaire/Annuaire.scss +1 -0
  70. imio/smartweb/core/webcomponents/src/components/Campaign/Campaign.jsx +306 -0
  71. imio/smartweb/core/webcomponents/src/components/Campaign/Campaign.scss +672 -0
  72. imio/smartweb/core/webcomponents/src/components/Campaign/CampaignCard/CampaignCard.jsx +79 -0
  73. imio/smartweb/core/webcomponents/src/components/Campaign/CampaignContent/CampaignContent.jsx +193 -0
  74. imio/smartweb/core/webcomponents/src/components/Campaign/CampaignList/CampaignList.jsx +67 -0
  75. imio/smartweb/core/webcomponents/src/components/Campaign/Filters/Filter.jsx +259 -0
  76. imio/smartweb/core/webcomponents/src/components/Campaign/index.js +2 -0
  77. imio/smartweb/core/webcomponents/src/components/Filters/MainFilter.scss +1 -0
  78. imio/smartweb/core/webcomponents/src/components/News/NewsContent/NewsContent.jsx +0 -1
  79. imio/smartweb/core/webcomponents/src/hooks/useAxios.js +45 -9
  80. imio/smartweb/core/webcomponents/src/index.jsx +2 -0
  81. imio/smartweb/core/webcomponents/src/index.scss +2 -2
  82. imio/smartweb/core/webcomponents/src/utils/CampaignMap.jsx +177 -0
  83. imio/smartweb/core/webcomponents/src/utils/Map.jsx +1 -1
  84. imio/smartweb/core/webcomponents/src/utils/Map.scss +15 -1
  85. imio/smartweb/core/webcomponents/src/utils/translation.js +235 -199
  86. {imio.smartweb.core-1.2.90.dist-info → imio.smartweb.core-1.3.dist-info}/METADATA +18 -1
  87. {imio.smartweb.core-1.2.90.dist-info → imio.smartweb.core-1.3.dist-info}/RECORD +94 -61
  88. imio/smartweb/core/webcomponents/build/js/499.smartweb-webcomponents-compiled.js +0 -2
  89. imio/smartweb/core/webcomponents/build/js/828.smartweb-webcomponents-compiled.js +0 -2
  90. /imio/smartweb/core/webcomponents/build/js/{499.smartweb-webcomponents-compiled.js.LICENSE.txt → 15.smartweb-webcomponents-compiled.js.LICENSE.txt} +0 -0
  91. /imio.smartweb.core-1.2.90-py3.12-nspkg.pth → /imio.smartweb.core-1.3-py3.12-nspkg.pth +0 -0
  92. {imio.smartweb.core-1.2.90.dist-info → imio.smartweb.core-1.3.dist-info}/LICENSE.GPL +0 -0
  93. {imio.smartweb.core-1.2.90.dist-info → imio.smartweb.core-1.3.dist-info}/LICENSE.rst +0 -0
  94. {imio.smartweb.core-1.2.90.dist-info → imio.smartweb.core-1.3.dist-info}/WHEEL +0 -0
  95. {imio.smartweb.core-1.2.90.dist-info → imio.smartweb.core-1.3.dist-info}/namespace_packages.txt +0 -0
  96. {imio.smartweb.core-1.2.90.dist-info → imio.smartweb.core-1.3.dist-info}/top_level.txt +0 -0
@@ -22,11 +22,10 @@ class ISendinblueTextRowSchema(Interface):
22
22
 
23
23
 
24
24
  class ISmartwebControlPanel(Interface):
25
- url_formdefs_api = schema.TextLine(
26
- title=_("Url to get forms from your e-guichet"),
27
- description=_(
28
- "Example : https://COMMUNE-formulaires.guichet-citoyen.be/api/formdefs/"
29
- ),
25
+ # https://COMMUNE-formulaires.guichet-citoyen.be/api
26
+ url_ts = schema.TextLine(
27
+ title=_("Url to e-guichet"),
28
+ description=_("Example : https://COMMUNE.guichet-citoyen.be"),
30
29
  required=False,
31
30
  )
32
31
 
@@ -36,6 +35,21 @@ class ISmartwebControlPanel(Interface):
36
35
  required=False,
37
36
  )
38
37
 
38
+ iaideabox_api_username = schema.TextLine(
39
+ title=_(
40
+ "Username to consume e-guichet ideabox API (get Campaign, projects,...)"
41
+ ),
42
+ default="ideabox",
43
+ required=False,
44
+ )
45
+
46
+ iaideabox_api_password = schema.Password(
47
+ title=_(
48
+ "Password to consume e-guichet ideabox API (get Campaign, projects,...)"
49
+ ),
50
+ required=False,
51
+ )
52
+
39
53
  propose_directory_url = schema.URI(
40
54
  title=_("Url to propose a new citizen contact"),
41
55
  required=False,
@@ -203,17 +217,40 @@ class SmartwebControlPanelForm(RegistryEditForm):
203
217
  iadeliberation_pwd = api.portal.get_registry_record(
204
218
  "smartweb.iadeliberation_api_password"
205
219
  )
220
+
221
+ iaideabox_pwd = api.portal.get_registry_record(
222
+ "smartweb.iaideabox_api_password"
223
+ )
224
+
206
225
  secret_key_api = api.portal.get_registry_record("smartweb.secret_key_api")
207
226
 
208
227
  # if data is None when we apply changes for password fields we keep password from registry
209
228
  if not data.get("iadeliberation_api_password"):
210
229
  data["iadeliberation_api_password"] = iadeliberation_pwd
211
230
 
231
+ if not data.get("iaideabox_api_password"):
232
+ data["iaideabox_api_password"] = iaideabox_pwd
233
+
212
234
  if not data.get("secret_key_api"):
213
235
  data["secret_key_api"] = secret_key_api
214
236
 
215
237
  return super().applyChanges(data)
216
238
 
239
+ def updateFields(self):
240
+ """Override updateFields to hide fields based on ideabox profile installation."""
241
+ super(SmartwebControlPanelForm, self).updateFields()
242
+
243
+ # Check if the 'ideabox' profile is installed
244
+ portal_setup = api.portal.get_tool(name="portal_setup")
245
+ profile_version = portal_setup.getLastVersionForProfile(
246
+ "imio.smartweb.core:ideabox"
247
+ )
248
+
249
+ if profile_version == "unknown":
250
+ # Hide the field related to Idea Box if the profile is not installed
251
+ self.fields = self.fields.omit("iaideabox_api_username")
252
+ self.fields = self.fields.omit("iaideabox_api_password")
253
+
217
254
 
218
255
  SmartwebControlPanelView = layout.wrap_form(
219
256
  SmartwebControlPanelForm, ControlPanelFormWrapper
@@ -2,6 +2,8 @@
2
2
  from imio.smartweb.core.contents import IPages
3
3
  from imio.smartweb.core.contents.pages.procedure.utils import sign_url
4
4
  from imio.smartweb.core.utils import get_plausible_vars
5
+ from imio.smartweb.core.utils import get_ts_api_url
6
+ from imio.smartweb.core.utils import get_value_from_registry
5
7
  from imio.smartweb.locales import SmartwebMessageFactory as _
6
8
  from plone import api
7
9
  from plone.api.portal import get_registry_record
@@ -54,7 +56,8 @@ class UtilsView(BrowserView):
54
56
 
55
57
  def is_eguichet_aware(self):
56
58
  self.request.response.setHeader("Content-Type", "application/json")
57
- url = api.portal.get_registry_record("smartweb.url_formdefs_api")
59
+ wcs_api = get_ts_api_url("wcs")
60
+ url = f"{wcs_api}/formdefs/"
58
61
  key = api.portal.get_registry_record("smartweb.secret_key_api")
59
62
  orig = "ia.smartweb"
60
63
  if not url:
@@ -14,7 +14,10 @@
14
14
  <include package="collective.solr" />
15
15
  <include package="collective.taxonomy" />
16
16
  <include package="collective.z3cform.datagridfield" />
17
-
17
+
18
+ <!-- Call this one before overrides adapter zope.container.interfaces.INameChooser-->
19
+ <include package="plone.app.content" />
20
+
18
21
  <!-- Temporary fix for plone.gallery 1.0.1 -->
19
22
  <include package="plone.app.contentmenu" />
20
23
  <include package="plone.gallery" />
@@ -24,6 +27,7 @@
24
27
  <include package="imio.smartweb.locales" />
25
28
 
26
29
  <include file="indexers.zcml" />
30
+ <include file="overrides.zcml" />
27
31
  <include file="permissions.zcml" />
28
32
  <include file="profiles.zcml" />
29
33
  <include file="subscribers.zcml" />
@@ -21,6 +21,8 @@ from .publication.content import Publication # NOQA
21
21
  from .publication.content import IPublication # NOQA
22
22
  from .rest.base import RestView # NOQA
23
23
  from .rest.base import IRestView # NOQA
24
+ from .rest.campaign.content import CampaignView # NOQA
25
+ from .rest.campaign.content import ICampaignView # NOQA
24
26
  from .rest.directory.content import DirectoryView # NOQA
25
27
  from .rest.directory.content import IDirectoryView # NOQA
26
28
  from .rest.events.content import EventsView # NOQA
File without changes
@@ -0,0 +1,80 @@
1
+ <configure
2
+ xmlns="http://namespaces.zope.org/zope"
3
+ xmlns:browser="http://namespaces.zope.org/browser"
4
+ xmlns:plone="http://namespaces.plone.org/plone"
5
+ i18n_domain="imio.smartweb">
6
+
7
+ <browser:page
8
+ name="view"
9
+ for="imio.smartweb.core.contents.ICampaignView"
10
+ class=".view.CampaignViewView"
11
+ template="view.pt"
12
+ permission="zope2.View"
13
+ layer="imio.smartweb.core.interfaces.IImioSmartwebCoreLayer"
14
+ />
15
+
16
+ <plone:service
17
+ name="@results"
18
+ method="GET"
19
+ accept="application/json"
20
+ for="imio.smartweb.core.contents.ICampaignView"
21
+ factory=".endpoint.CampaignEndpointGet"
22
+ permission="zope2.View"
23
+ layer="imio.smartweb.core.interfaces.IImioSmartwebCoreLayer"
24
+ />
25
+
26
+ <plone:service
27
+ name="@auth"
28
+ method="GET"
29
+ accept="text/plain"
30
+ for="imio.smartweb.core.contents.ICampaignView"
31
+ factory=".endpoint.AuthCampaignEndpointGet"
32
+ permission="zope.Public"
33
+ layer="imio.smartweb.core.interfaces.IImioSmartwebCoreLayer"
34
+ />
35
+
36
+ <plone:service
37
+ name="@zones"
38
+ method="GET"
39
+ accept="application/json"
40
+ for="imio.smartweb.core.contents.ICampaignView"
41
+ factory=".endpoint.ZonesEndpointGet"
42
+ permission="zope2.View"
43
+ layer="imio.smartweb.core.interfaces.IImioSmartwebCoreLayer"
44
+ />
45
+
46
+
47
+ <!-- endpoint to get topics from TS -->
48
+ <plone:service
49
+ name="@ts_topics"
50
+ method="GET"
51
+ accept="application/json"
52
+ for="imio.smartweb.core.contents.ICampaignView"
53
+ factory=".endpoint.TsTopicsEndpointGet"
54
+ permission="zope2.View"
55
+ layer="imio.smartweb.core.interfaces.IImioSmartwebCoreLayer"
56
+ />
57
+
58
+ <!-- endpoint to expose smartweb topics to TS -->
59
+ <plone:service
60
+ name="@topics"
61
+ method="GET"
62
+ accept="application/json"
63
+ for="plone.dexterity.interfaces.IDexterityContent"
64
+ factory=".endpoint.TopicsEndpointGet"
65
+ permission="zope2.View"
66
+ layer="imio.smartweb.core.interfaces.IImioSmartwebCoreLayer"
67
+ />
68
+
69
+ <!-- endpoint to expose smartweb AND TS topics to campaign view -->
70
+ <plone:service
71
+ name="@all_topics"
72
+ method="GET"
73
+ accept="application/json"
74
+ for="imio.smartweb.core.contents.ICampaignView"
75
+ factory=".endpoint.AllTopicsEndpointGet"
76
+ permission="zope2.View"
77
+ layer="imio.smartweb.core.interfaces.IImioSmartwebCoreLayer"
78
+ />
79
+
80
+ </configure>
@@ -0,0 +1,83 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ from collective.instancebehavior.interfaces import IInstanceBehaviorAssignableContent
4
+ from imio.smartweb.core.contents import RestView
5
+ from imio.smartweb.core.utils import get_basic_auth_json
6
+ from imio.smartweb.core.utils import get_ts_api_url
7
+ from imio.smartweb.core.utils import get_value_from_registry
8
+ from imio.smartweb.locales import SmartwebMessageFactory as _
9
+ from plone import api
10
+ from plone.app.content.namechooser import NormalizingNameChooser
11
+ from plone.i18n.normalizer import idnormalizer
12
+ from plone.supermodel import model
13
+ from zope import schema
14
+ from zope.component import getUtility
15
+ from zope.container.interfaces import INameChooser
16
+ from zope.interface import implementer
17
+
18
+ import logging
19
+
20
+ logger = logging.getLogger("imio.smartweb.core")
21
+
22
+
23
+ class ICampaignView(model.Schema):
24
+ """ """
25
+
26
+ linked_campaign = schema.Choice(
27
+ vocabulary="imio.smartweb.vocabulary.PublikCampaigns",
28
+ title=_("E-Guichet campaign"),
29
+ required=False,
30
+ default=None,
31
+ )
32
+
33
+ propose_project_url = schema.TextLine(
34
+ title=_("Propose project URL"),
35
+ description=_("URL to propose a project"),
36
+ required=False,
37
+ )
38
+
39
+ nb_results = schema.Int(
40
+ title=_("Number of items to display"), default=20, required=True
41
+ )
42
+
43
+ display_map = schema.Bool(
44
+ title=_("Display map"),
45
+ description=_("If selected, map will be displayed"),
46
+ required=False,
47
+ default=True,
48
+ )
49
+
50
+
51
+ @implementer(ICampaignView, IInstanceBehaviorAssignableContent)
52
+ class CampaignView(RestView):
53
+ """Campaign class"""
54
+
55
+
56
+ @implementer(INameChooser)
57
+ class CampaignNameChooser(NormalizingNameChooser):
58
+ def chooseName(self, name, obj):
59
+ """Génère un ID basé sur le titre récupéré de l'API."""
60
+ if ICampaignView.providedBy(obj):
61
+ if not obj.title:
62
+ # Récupération du titre via l'API
63
+ wcs_api = get_ts_api_url("wcs")
64
+ ts_campaign_endpoint = "imio-ideabox-campagne"
65
+ url = f"{wcs_api}/cards/{ts_campaign_endpoint}/{obj.linked_campaign}"
66
+ user = get_value_from_registry("smartweb.iaideabox_api_username")
67
+ pwd = get_value_from_registry("smartweb.iaideabox_api_password")
68
+ json_campaign = get_basic_auth_json(url, user, pwd)
69
+
70
+ if json_campaign and "fields" in json_campaign:
71
+ obj.title = json_campaign["fields"].get(
72
+ "titre", "campagne-sans-nom"
73
+ )
74
+ else:
75
+ obj.title = "campaign-without-name"
76
+
77
+ # Normaliser l'ID en utilisant le titre
78
+ normalized_id = idnormalizer.normalize(obj.title)
79
+
80
+ # Vérifier que l'ID généré est bien unique dans le conteneur
81
+ return super().chooseName(normalized_id, obj)
82
+
83
+ return super().chooseName(name, obj)
@@ -0,0 +1,211 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ from imio.smartweb.common.utils import get_vocabulary
4
+ from imio.smartweb.core.contents.rest.base import BaseEndpoint
5
+ from imio.smartweb.core.contents.rest.base import BaseService
6
+ from imio.smartweb.core.utils import get_basic_auth_json
7
+ from imio.smartweb.core.utils import get_ts_api_url
8
+ from plone import api
9
+ from plone.i18n.normalizer import idnormalizer
10
+ from plone.restapi.interfaces import IExpandableElement
11
+ from zope.component import adapter
12
+ from zope.i18n import translate
13
+ from zope.interface import implementer
14
+ from zope.interface import Interface
15
+
16
+ import base64
17
+ import requests
18
+
19
+
20
+ def get_ideabox_basic_auth_header() -> str:
21
+ user = api.portal.get_registry_record("smartweb.iaideabox_api_username")
22
+ pwd = api.portal.get_registry_record("smartweb.iaideabox_api_password")
23
+ usrPass = f"{user}:{pwd}".encode("utf-8")
24
+ b64Val = base64.b64encode(usrPass)
25
+ return f"Basic {b64Val.decode('utf-8')}"
26
+
27
+
28
+ class BaseTsEndpoint(BaseEndpoint):
29
+ def __init__(self, *args, **kwargs):
30
+ super(BaseTsEndpoint, self).__init__(*args, **kwargs)
31
+ self.user = api.portal.get_registry_record("smartweb.iaideabox_api_username")
32
+ self.pwd = api.portal.get_registry_record("smartweb.iaideabox_api_password")
33
+
34
+ def _get_json(self, url):
35
+ return get_basic_auth_json(url, self.user, self.pwd)
36
+
37
+ @property
38
+ def query_url(self):
39
+ raise NotImplementedError("query_url must be defined in subclasses")
40
+
41
+
42
+ @implementer(IExpandableElement)
43
+ @adapter(Interface, Interface)
44
+ class CampaignEndpoint(BaseTsEndpoint):
45
+
46
+ def __call__(self):
47
+ require_keys = [
48
+ "uuid",
49
+ "id",
50
+ "display_name",
51
+ "text",
52
+ "url",
53
+ "api_url",
54
+ "fields",
55
+ "workflow",
56
+ ]
57
+ json = self._get_json(self.query_url)
58
+ json_res = {}
59
+ if not json:
60
+ return {}
61
+ elif "data" in json:
62
+ # list of projects
63
+ json["data"] = self.add_b64_image_to_data(json.get("data"))
64
+ projects = [
65
+ {k: v for k, v in d.items() if k in require_keys}
66
+ for d in json.get("data")
67
+ ]
68
+ json_res["items"] = projects
69
+ json_res["items_total"] = json.get("count")
70
+
71
+ else:
72
+ # single project
73
+ json.pop("evolution")
74
+ json.pop("roles")
75
+ json.pop("submission")
76
+ json.pop("user")
77
+ json_res = json
78
+ # Return a json which represents a project or which contains a list of projects
79
+ return json_res
80
+
81
+ def add_b64_image_to_data(self, data):
82
+ for d in data:
83
+ # get image
84
+ image_url = d.get("fields").get("images_raw")[0].get("image").get("url")
85
+ content = self.get_image(image_url).content
86
+ b64_content = base64.b64encode(content).decode("utf-8")
87
+ d["fields"]["images_raw"][0]["image"]["content"] = b64_content
88
+ return data
89
+
90
+ def get_image(self, image_url):
91
+ if not image_url:
92
+ return
93
+ headers = {"Accept": "image/*"}
94
+ headers["Authorization"] = get_ideabox_basic_auth_header()
95
+ response = requests.get(image_url, headers=headers)
96
+ return response
97
+
98
+ @property
99
+ def query_url(self):
100
+ wcs_api = get_ts_api_url("wcs")
101
+ if "id" in self.request.form:
102
+ # we want a specific project
103
+ project_id = self.request.form.get("id")
104
+ url = f"{wcs_api}/cards/imio-ideabox-projet/{project_id}?full=on"
105
+ else:
106
+ # we want (filtered) list of projects for a specific campaign with eventually extra pamams (zone, topic, ...)
107
+ extra_params = [f"{k}={v}" for k, v in self.request.form.items()]
108
+ extra_params = "&".join(extra_params)
109
+ campaign_id = self.context.linked_campaign
110
+ url = f"{wcs_api}/cards/imio-ideabox-projet/list?campagne={campaign_id}&full=on&filter-statut=Vote|Enregistr%C3%A9e&filter-statut-operator=in&{extra_params}"
111
+ return url
112
+
113
+
114
+ @implementer(IExpandableElement)
115
+ @adapter(Interface, Interface)
116
+ class ZonesEndpoint(BaseTsEndpoint):
117
+
118
+ def __call__(self):
119
+ json = self._get_json(self.query_url)
120
+ json_res = {"items": json["data"], "items_total": json.get("count")}
121
+ return json_res
122
+
123
+ @property
124
+ def query_url(self):
125
+ wcs_api = get_ts_api_url("wcs")
126
+ campaign_id = self.context.linked_campaign
127
+ return f"{wcs_api}/cards/imio-ideabox-zone/list?campagne={campaign_id}"
128
+
129
+
130
+ @implementer(IExpandableElement)
131
+ @adapter(Interface, Interface)
132
+ class TsTopicsEndpoint(BaseTsEndpoint):
133
+
134
+ def __call__(self):
135
+ json = self._get_json(self.query_url)
136
+ json_res = {"items": json["data"], "items_total": json.get("count")}
137
+ return json_res
138
+
139
+ @property
140
+ def query_url(self):
141
+ wcs_api = get_ts_api_url("wcs")
142
+ campaign_id = self.context.linked_campaign
143
+ return f"{wcs_api}/cards/imio-ideabox-theme/list?campagne={campaign_id}"
144
+
145
+
146
+ @implementer(IExpandableElement)
147
+ @adapter(Interface, Interface)
148
+ class TopicsEndpoint(BaseEndpoint):
149
+
150
+ def __call__(self):
151
+ # get all topics from smartweb vocabulary (populate select in React campaign view)
152
+ topics_vocabulary = get_vocabulary("imio.smartweb.vocabulary.Topics")
153
+ current_lang = api.portal.get_current_language()[:2]
154
+ json_res = {
155
+ "items": [
156
+ {
157
+ "value": term.value,
158
+ "title": translate(term.title, target_language=current_lang),
159
+ }
160
+ for term in topics_vocabulary
161
+ ],
162
+ "items_total": len(topics_vocabulary),
163
+ }
164
+ return json_res
165
+
166
+
167
+ @implementer(IExpandableElement)
168
+ @adapter(Interface, Interface)
169
+ class AllTopicsEndpoint(TopicsEndpoint):
170
+
171
+ def __call__(self):
172
+ topics = super(AllTopicsEndpoint, self).__call__()
173
+ ts_endpoint = TsTopicsEndpoint(self.context, self.request)
174
+ ts_topics = ts_endpoint()
175
+ ts_topics = [
176
+ {"title": i.get("text"), "value": i.get("id")} for i in ts_topics["items"]
177
+ ]
178
+ topics["items"].extend(ts_topics)
179
+ topics["items"].sort(key=lambda x: idnormalizer.normalize(x["title"]))
180
+ topics["items_total"] += len(ts_topics)
181
+ return topics
182
+
183
+
184
+ class CampaignEndpointGet(BaseService):
185
+ def reply(self):
186
+ return CampaignEndpoint(self.context, self.request)()
187
+
188
+
189
+ class AuthCampaignEndpointGet(BaseService):
190
+ def reply(self):
191
+ return get_ideabox_basic_auth_header()
192
+
193
+
194
+ class ZonesEndpointGet(BaseService):
195
+ def reply(self):
196
+ return ZonesEndpoint(self.context, self.request)()
197
+
198
+
199
+ class TsTopicsEndpointGet(BaseService):
200
+ def reply(self):
201
+ return ZonesEndpoint(self.context, self.request)()
202
+
203
+
204
+ class TopicsEndpointGet(BaseService):
205
+ def reply(self):
206
+ return TopicsEndpoint(self.context, self.request)()
207
+
208
+
209
+ class AllTopicsEndpointGet(BaseService):
210
+ def reply(self):
211
+ return AllTopicsEndpoint(self.context, self.request)()
@@ -0,0 +1,19 @@
1
+ <html
2
+ metal:use-macro="context/main_template/macros/master"
3
+ i18n:domain="imio.smartweb">
4
+ <body>
5
+ <metal:main fill-slot="content-core">
6
+ <div class="full-width">
7
+ <smartweb-campaign tal:attributes="query-url view/local_query_url;
8
+ query-zones-url view/local_query_zones_url;
9
+ query-topics-url view/local_query_topics_url;
10
+ batch-size view/batch_size;
11
+ propose-url view/propose_url;
12
+ current-language view/current_language;
13
+ display-map view/display_map;
14
+ view-path view/view_path;
15
+ context-authenticated-user view/context_authenticated_user;"></smartweb-campaign>
16
+ </div>
17
+ </metal:main>
18
+ </body>
19
+ </html>
@@ -0,0 +1,29 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ from imio.smartweb.core.contents.rest.view import BaseRestView
4
+ from imio.smartweb.core.interfaces import IOgpViewUtils
5
+ from plone import api
6
+ from zope.interface import implementer
7
+
8
+
9
+ @implementer(IOgpViewUtils)
10
+ class CampaignViewView(BaseRestView):
11
+ """CampaignView view"""
12
+
13
+ @property
14
+ def propose_url(self):
15
+ return self.context.propose_project_url
16
+
17
+ @property
18
+ def display_map(self):
19
+ return self.context.display_map
20
+
21
+ @property
22
+ def local_query_zones_url(self):
23
+ base_url = self.context.absolute_url()
24
+ return f"{base_url}/@zones"
25
+
26
+ @property
27
+ def local_query_topics_url(self):
28
+ base_url = self.context.absolute_url()
29
+ return f"{base_url}/@all_topics"
@@ -1,6 +1,7 @@
1
1
  <configure
2
2
  xmlns="http://namespaces.zope.org/zope">
3
3
 
4
+ <include package=".campaign" />
4
5
  <include package=".directory" />
5
6
  <include package=".events" />
6
7
  <include package=".news" />
@@ -26,6 +26,10 @@ class IImioSmartwebCoreLayer(
26
26
  """Marker interface that defines a browser layer."""
27
27
 
28
28
 
29
+ class IImioIdeaboxLayer(Interface):
30
+ """Marker interface that defines a browser layer."""
31
+
32
+
29
33
  class IArcgisViewUtils(Interface):
30
34
  """ """
31
35
 
@@ -0,0 +1,10 @@
1
+ <configure
2
+ xmlns="http://namespaces.zope.org/zope">
3
+
4
+ <adapter
5
+ for="plone.dexterity.interfaces.IDexterityContainer"
6
+ factory="imio.smartweb.core.contents.rest.campaign.content.CampaignNameChooser"
7
+ provides="zope.container.interfaces.INameChooser"
8
+ />
9
+
10
+ </configure>
@@ -1,6 +1,6 @@
1
1
  <?xml version='1.0' encoding='UTF-8'?>
2
2
  <metadata>
3
- <version>1064</version>
3
+ <version>1066</version>
4
4
  <dependencies>
5
5
  <dependency>profile-plone.app.dexterity:default</dependency>
6
6
  <dependency>profile-plone.app.imagecropping:default</dependency>
@@ -0,0 +1,7 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <layers>
3
+ <layer
4
+ name="imio.smartweb.core.ideabox"
5
+ interface="imio.smartweb.core.interfaces.IImioIdeaboxLayer"
6
+ />
7
+ </layers>
@@ -0,0 +1,5 @@
1
+ <?xml version='1.0' encoding='UTF-8'?>
2
+ <metadata>
3
+ <version>1062</version>
4
+ <description>Profile to enable Ideabox on an existing Plone6 site</description>
5
+ </metadata>
@@ -0,0 +1,9 @@
1
+ <?xml version="1.0"?>
2
+ <registry
3
+ xmlns:i18n="http://xml.zope.org/namespaces/i18n"
4
+ i18n:domain="imio.smartweb">
5
+
6
+ <records interface="imio.smartweb.core.browser.controlpanel.ISmartwebControlPanel"
7
+ prefix="smartweb" />
8
+
9
+ </registry>
@@ -0,0 +1,40 @@
1
+ <?xml version="1.0"?>
2
+ <object xmlns:i18n="http://xml.zope.org/namespaces/i18n"
3
+ name="imio.smartweb.CampaignView"
4
+ meta_type="Dexterity FTI"
5
+ i18n:domain="imio.smartweb">
6
+
7
+ <!-- Basic properties -->
8
+ <property
9
+ i18n:translate=""
10
+ name="title">Campaign view</property>
11
+ <property
12
+ i18n:translate=""
13
+ name="description">Display projects from a campaign coming from e-guichet.</property>
14
+
15
+ <property name="icon_expr">string:file-earmark-person</property>
16
+
17
+ <!-- Hierarchy control -->
18
+ <property name="global_allow">True</property>
19
+ <!-- Schema, class and security -->
20
+ <property name="add_permission">imio.smartweb.core.ManageRestViews</property>
21
+ <property name="klass">imio.smartweb.core.contents.CampaignView</property>
22
+ <property name="schema">imio.smartweb.core.contents.ICampaignView</property>
23
+
24
+ <!-- Enabled behaviors -->
25
+ <property name="behaviors" purge="false">
26
+ <element value="plone.excludefromnavigation"/>
27
+ <element value="plone.shortname"/>
28
+ <element value="plone.publication"/>
29
+ <element value="plone.locking"/>
30
+ <element value="plone.leadimage"/>
31
+ <element value="plone.imagecropping"/>
32
+ <element value="imio.smartweb.listing"/>
33
+ <element value="imio.smartweb.topics"/>
34
+ <element value="imio.smartweb.iam"/>
35
+ <element value="plone.categorization"/>
36
+ <element value="collective.autopublishing.behavior.IAutoPublishing"/>
37
+ <element value="solr.fields" />
38
+ </property>
39
+
40
+ </object>