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.
- imio/smartweb/core/browser/controlpanel.py +42 -5
- imio/smartweb/core/browser/utils.py +4 -1
- imio/smartweb/core/configure.zcml +5 -1
- imio/smartweb/core/contents/__init__.py +2 -0
- imio/smartweb/core/contents/rest/campaign/__init__.py +0 -0
- imio/smartweb/core/contents/rest/campaign/configure.zcml +80 -0
- imio/smartweb/core/contents/rest/campaign/content.py +83 -0
- imio/smartweb/core/contents/rest/campaign/endpoint.py +211 -0
- imio/smartweb/core/contents/rest/campaign/view.pt +19 -0
- imio/smartweb/core/contents/rest/campaign/view.py +29 -0
- imio/smartweb/core/contents/rest/configure.zcml +1 -0
- imio/smartweb/core/interfaces.py +4 -0
- imio/smartweb/core/overrides.zcml +10 -0
- imio/smartweb/core/profiles/default/metadata.xml +1 -1
- imio/smartweb/core/profiles/ideabox/browserlayer.xml +7 -0
- imio/smartweb/core/profiles/ideabox/metadata.xml +5 -0
- imio/smartweb/core/profiles/ideabox/registry/iaideabox.xml +9 -0
- imio/smartweb/core/profiles/ideabox/types/imio.smartweb.CampaignView.xml +40 -0
- imio/smartweb/core/profiles/ideabox/types/imio.smartweb.Folder.xml +71 -0
- imio/smartweb/core/profiles/ideabox/types.xml +17 -0
- imio/smartweb/core/profiles/ideabox_uninstall/browserlayer.xml +7 -0
- imio/smartweb/core/profiles/ideabox_uninstall/types/imio.smartweb.Folder.xml +25 -0
- imio/smartweb/core/profiles/ideabox_uninstall/types.xml +4 -0
- imio/smartweb/core/profiles/testing/metadata.xml +1 -0
- imio/smartweb/core/profiles/testing/registry.xml +2 -2
- imio/smartweb/core/profiles.zcml +18 -0
- imio/smartweb/core/subscribers.py +27 -1
- imio/smartweb/core/subscribers.zcml +8 -0
- imio/smartweb/core/tests/resources/json_ideabox_campaign.json +222 -0
- imio/smartweb/core/tests/resources/json_ideabox_campaigns.json +425 -0
- imio/smartweb/core/tests/resources/json_ideabox_projects.json +1871 -0
- imio/smartweb/core/tests/test_iadeliberations.py +38 -40
- imio/smartweb/core/tests/test_ideabox.py +120 -0
- imio/smartweb/core/tests/test_procedure.py +7 -3
- imio/smartweb/core/tests/test_rest.py +7 -0
- imio/smartweb/core/tests/test_vocabularies.py +8 -10
- imio/smartweb/core/upgrades/configure.zcml +16 -1
- imio/smartweb/core/upgrades/upgrades.py +64 -0
- imio/smartweb/core/utils.py +33 -0
- imio/smartweb/core/viewlets/actions.py +10 -0
- imio/smartweb/core/viewlets/header_actions.pt +2 -0
- imio/smartweb/core/viewlets/offcanvas.pt +31 -6
- imio/smartweb/core/viewlets/ogptags.py +9 -0
- imio/smartweb/core/viewlets/subsite_logo.pt +1 -1
- imio/smartweb/core/vocabularies.py +35 -4
- imio/smartweb/core/vocabularies.zcml +6 -0
- imio/smartweb/core/webcomponents/build/css/373.smartweb-webcomponents-compiled.css +1 -1
- imio/smartweb/core/webcomponents/build/css/420.smartweb-webcomponents-compiled.css +1 -0
- imio/smartweb/core/webcomponents/build/css/486.smartweb-webcomponents-compiled.css +1 -1
- imio/smartweb/core/webcomponents/build/css/666.smartweb-webcomponents-compiled.css +1 -0
- imio/smartweb/core/webcomponents/build/css/884.smartweb-webcomponents-compiled.css +1 -1
- imio/smartweb/core/webcomponents/build/css/smartweb-webcomponents-compiled.css +1 -1
- imio/smartweb/core/webcomponents/build/js/141.smartweb-webcomponents-compiled.js +2 -0
- imio/smartweb/core/webcomponents/build/js/{828.smartweb-webcomponents-compiled.js.LICENSE.txt → 141.smartweb-webcomponents-compiled.js.LICENSE.txt} +3 -3
- imio/smartweb/core/webcomponents/build/js/15.smartweb-webcomponents-compiled.js +2 -0
- imio/smartweb/core/webcomponents/build/js/21.smartweb-webcomponents-compiled.js +1 -0
- imio/smartweb/core/webcomponents/build/js/218.smartweb-webcomponents-compiled.js +1 -1
- imio/smartweb/core/webcomponents/build/js/218.smartweb-webcomponents-compiled.js.LICENSE.txt +0 -5
- imio/smartweb/core/webcomponents/build/js/373.smartweb-webcomponents-compiled.js +1 -1
- imio/smartweb/core/webcomponents/build/js/486.smartweb-webcomponents-compiled.js +1 -1
- imio/smartweb/core/webcomponents/build/js/666.smartweb-webcomponents-compiled.js +1 -0
- imio/smartweb/core/webcomponents/build/js/799.smartweb-webcomponents-compiled.js +1 -1
- imio/smartweb/core/webcomponents/build/js/824.smartweb-webcomponents-compiled.js +1 -1
- imio/smartweb/core/webcomponents/build/js/884.smartweb-webcomponents-compiled.js +1 -1
- imio/smartweb/core/webcomponents/build/js/919.smartweb-webcomponents-compiled.js +1 -1
- imio/smartweb/core/webcomponents/build/js/922.smartweb-webcomponents-compiled.js +1 -0
- imio/smartweb/core/webcomponents/build/js/smartweb-webcomponents-compiled.js +1 -1
- imio/smartweb/core/webcomponents/package.json +80 -80
- imio/smartweb/core/webcomponents/src/components/Annuaire/Annuaire.scss +1 -0
- imio/smartweb/core/webcomponents/src/components/Campaign/Campaign.jsx +306 -0
- imio/smartweb/core/webcomponents/src/components/Campaign/Campaign.scss +672 -0
- imio/smartweb/core/webcomponents/src/components/Campaign/CampaignCard/CampaignCard.jsx +79 -0
- imio/smartweb/core/webcomponents/src/components/Campaign/CampaignContent/CampaignContent.jsx +193 -0
- imio/smartweb/core/webcomponents/src/components/Campaign/CampaignList/CampaignList.jsx +67 -0
- imio/smartweb/core/webcomponents/src/components/Campaign/Filters/Filter.jsx +259 -0
- imio/smartweb/core/webcomponents/src/components/Campaign/index.js +2 -0
- imio/smartweb/core/webcomponents/src/components/Filters/MainFilter.scss +1 -0
- imio/smartweb/core/webcomponents/src/components/News/NewsContent/NewsContent.jsx +0 -1
- imio/smartweb/core/webcomponents/src/hooks/useAxios.js +45 -9
- imio/smartweb/core/webcomponents/src/index.jsx +2 -0
- imio/smartweb/core/webcomponents/src/index.scss +2 -2
- imio/smartweb/core/webcomponents/src/utils/CampaignMap.jsx +177 -0
- imio/smartweb/core/webcomponents/src/utils/Map.jsx +1 -1
- imio/smartweb/core/webcomponents/src/utils/Map.scss +15 -1
- imio/smartweb/core/webcomponents/src/utils/translation.js +235 -199
- {imio.smartweb.core-1.2.90.dist-info → imio.smartweb.core-1.3.dist-info}/METADATA +18 -1
- {imio.smartweb.core-1.2.90.dist-info → imio.smartweb.core-1.3.dist-info}/RECORD +94 -61
- imio/smartweb/core/webcomponents/build/js/499.smartweb-webcomponents-compiled.js +0 -2
- imio/smartweb/core/webcomponents/build/js/828.smartweb-webcomponents-compiled.js +0 -2
- /imio/smartweb/core/webcomponents/build/js/{499.smartweb-webcomponents-compiled.js.LICENSE.txt → 15.smartweb-webcomponents-compiled.js.LICENSE.txt} +0 -0
- /imio.smartweb.core-1.2.90-py3.12-nspkg.pth → /imio.smartweb.core-1.3-py3.12-nspkg.pth +0 -0
- {imio.smartweb.core-1.2.90.dist-info → imio.smartweb.core-1.3.dist-info}/LICENSE.GPL +0 -0
- {imio.smartweb.core-1.2.90.dist-info → imio.smartweb.core-1.3.dist-info}/LICENSE.rst +0 -0
- {imio.smartweb.core-1.2.90.dist-info → imio.smartweb.core-1.3.dist-info}/WHEEL +0 -0
- {imio.smartweb.core-1.2.90.dist-info → imio.smartweb.core-1.3.dist-info}/namespace_packages.txt +0 -0
- {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
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
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
|
-
|
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"
|
imio/smartweb/core/interfaces.py
CHANGED
@@ -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>
|
@@ -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>
|