decidim-core 0.31.4 → 0.31.6
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.
- checksums.yaml +4 -4
- data/app/cells/decidim/amendable/amend_button_card/show.erb +2 -2
- data/app/cells/decidim/author_cell.rb +0 -4
- data/app/cells/decidim/content_blocks/cta_settings_form/show.erb +1 -1
- data/app/cells/decidim/content_blocks/hero_settings_form/show.erb +2 -2
- data/app/cells/decidim/content_blocks/highlighted_content_banner_cell.rb +1 -1
- data/app/cells/decidim/content_blocks/highlighted_content_banner_settings_form/show.erb +1 -1
- data/app/cells/decidim/content_blocks/highlighted_participatory_spaces_cell.rb +1 -1
- data/app/cells/decidim/content_blocks/html_cell.rb +1 -1
- data/app/cells/decidim/content_blocks/participatory_space_hero_settings_form/show.erb +1 -1
- data/app/cells/decidim/content_blocks/static_page/section_cell.rb +1 -1
- data/app/cells/decidim/content_blocks/static_page/section_settings_form/show.erb +3 -1
- data/app/cells/decidim/content_blocks/static_page/summary_cell.rb +1 -1
- data/app/cells/decidim/content_blocks/static_page/summary_settings_form/show.erb +3 -1
- data/app/cells/decidim/content_blocks/static_page/two_pane_section_cell.rb +2 -2
- data/app/cells/decidim/content_blocks/static_page/two_pane_section_settings_form/show.erb +4 -2
- data/app/cells/decidim/data_consent/category.erb +5 -5
- data/app/cells/decidim/resource_types_filter/show.erb +2 -2
- data/app/cells/decidim/upload_modal_cell.rb +5 -0
- data/app/commands/decidim/destroy_account.rb +12 -1
- data/app/commands/decidim/multiple_attachments_methods.rb +28 -27
- data/app/controllers/concerns/decidim/devise_controllers.rb +10 -0
- data/app/controllers/decidim/download_your_data_controller.rb +1 -1
- data/app/controllers/decidim/notifications_subscriptions_controller.rb +8 -0
- data/app/controllers/decidim/private_downloads_controller.rb +29 -0
- data/app/jobs/decidim/process_inactive_participant_job.rb +0 -7
- data/app/mailers/decidim/delete_user_mailer.rb +14 -0
- data/app/mailers/decidim/participants_account_mailer.rb +0 -16
- data/app/models/decidim/attachment.rb +20 -2
- data/app/models/decidim/authorization.rb +7 -0
- data/app/models/decidim/moderation.rb +1 -1
- data/app/models/decidim/participatory_space_private_user.rb +1 -1
- data/app/models/decidim/private_download.rb +61 -0
- data/app/models/decidim/private_export.rb +6 -0
- data/app/models/decidim/user_base_entity.rb +17 -2
- data/app/models/decidim/user_moderation.rb +1 -1
- data/app/packs/src/decidim/controllers/form_validator/form_validator.js +6 -6
- data/app/packs/src/decidim/controllers/form_validator/form_validator.test.js +23 -1
- data/app/packs/src/decidim/controllers/mention/controller.js +296 -140
- data/app/packs/src/decidim/controllers/mention/input_mentions.test.js +120 -457
- data/app/packs/src/decidim/controllers/multiple_mentions/controller.js +68 -32
- data/app/packs/src/decidim/controllers/multiple_mentions/input_multiple_mentions.test.js +30 -23
- data/app/packs/src/decidim/direct_uploads/upload_field.js +4 -4
- data/app/packs/src/decidim/direct_uploads/upload_modal.js +11 -7
- data/app/packs/src/decidim/geocoding/reverse_geocoding.js +15 -5
- data/app/packs/src/decidim/geocoding/reverse_geocoding.test.js +197 -0
- data/app/packs/src/decidim/index.js +4 -3
- data/app/packs/src/decidim/sw/push-permissions.js +48 -13
- data/app/packs/src/decidim/sw/sw.js +1 -1
- data/app/packs/src/decidim/utilities/text.js +6 -6
- data/app/packs/stylesheets/decidim/_conversations.scss +14 -0
- data/app/packs/stylesheets/decidim/_editor_suggestions.scss +49 -0
- data/app/packs/stylesheets/decidim/_floating_help.scss +1 -1
- data/app/packs/stylesheets/decidim/_tom_select.scss +23 -0
- data/app/packs/stylesheets/decidim/application.scss +2 -0
- data/app/packs/stylesheets/decidim/editor.scss +2 -33
- data/app/packs/stylesheets/decidim/geocoding_addons.scss +10 -2
- data/app/presenters/decidim/menu_item_presenter.rb +9 -3
- data/app/presenters/decidim/stats_presenter.rb +1 -1
- data/app/services/decidim/notifications_subscriptions_persistor.rb +6 -0
- data/app/services/decidim/push_subscription_endpoint_validator.rb +34 -0
- data/app/services/decidim/send_push_notification.rb +5 -1
- data/app/uploaders/decidim/image_uploader.rb +1 -1
- data/app/views/decidim/delete_user_mailer/delete.html.erb +6 -0
- data/app/views/decidim/gamification/badges/index.html.erb +1 -1
- data/app/views/decidim/homepage/show.html.erb +1 -1
- data/app/views/decidim/last_activities/index.html.erb +1 -1
- data/app/views/decidim/messaging/conversations/_error_modal.html.erb +11 -19
- data/app/views/decidim/messaging/conversations/error.js.erb +12 -7
- data/app/views/decidim/newsletters/unsubscribe.html.erb +1 -1
- data/app/views/decidim/notifications_settings/show.html.erb +5 -5
- data/app/views/decidim/offline/show.html.erb +1 -1
- data/app/views/decidim/pages/index.html.erb +1 -1
- data/app/views/decidim/profiles/show.html.erb +1 -1
- data/app/views/decidim/shared/_resource_actions.html.erb +4 -4
- data/app/views/decidim/user_activities/index.html.erb +1 -1
- data/app/views/layouts/decidim/_wrapper.html.erb +2 -2
- data/app/views/layouts/decidim/header/_menu_breadcrumb_mobile_tablet.html.erb +1 -1
- data/app/views/layouts/decidim/shared/_layout_center.html.erb +1 -1
- data/app/views/layouts/decidim/shared/_layout_item.html.erb +1 -1
- data/app/views/layouts/decidim/shared/_layout_two_col.html.erb +1 -1
- data/config/locales/ar.yml +0 -5
- data/config/locales/bg.yml +0 -6
- data/config/locales/ca-IT.yml +10 -10
- data/config/locales/ca.yml +10 -10
- data/config/locales/cs.yml +4 -13
- data/config/locales/de.yml +5 -17
- data/config/locales/el.yml +0 -4
- data/config/locales/en.yml +9 -9
- data/config/locales/es-MX.yml +9 -9
- data/config/locales/es-PY.yml +9 -9
- data/config/locales/es.yml +9 -9
- data/config/locales/eu.yml +49 -49
- data/config/locales/fi-plain.yml +9 -9
- data/config/locales/fi.yml +11 -11
- data/config/locales/fr-CA.yml +10 -9
- data/config/locales/fr.yml +10 -9
- data/config/locales/gl.yml +0 -3
- data/config/locales/hu.yml +0 -5
- data/config/locales/id-ID.yml +0 -3
- data/config/locales/it.yml +11 -3
- data/config/locales/ja.yml +24 -21
- data/config/locales/lb.yml +0 -5
- data/config/locales/lt.yml +0 -5
- data/config/locales/lv.yml +0 -3
- data/config/locales/nl.yml +0 -5
- data/config/locales/no.yml +0 -5
- data/config/locales/pl.yml +2 -8
- data/config/locales/pt-BR.yml +3 -16
- data/config/locales/pt.yml +0 -5
- data/config/locales/ro-RO.yml +1 -14
- data/config/locales/sk.yml +1408 -4
- data/config/locales/sv.yml +3 -11
- data/config/locales/tr-TR.yml +0 -6
- data/config/locales/zh-CN.yml +0 -5
- data/config/locales/zh-TW.yml +0 -5
- data/config/routes.rb +1 -0
- data/lib/decidim/api/functions/user_entity_list.rb +2 -0
- data/lib/decidim/attachment_attributes.rb +58 -9
- data/lib/decidim/command.rb +1 -1
- data/lib/decidim/content_renderers/base_renderer.rb +112 -0
- data/lib/decidim/content_renderers/blob_renderer.rb +4 -7
- data/lib/decidim/content_renderers/mention_resource_renderer.rb +10 -6
- data/lib/decidim/content_renderers/resource_renderer.rb +16 -7
- data/lib/decidim/content_renderers/user_renderer.rb +11 -9
- data/lib/decidim/core/content_blocks/registry_manager.rb +4 -4
- data/lib/decidim/core/engine.rb +8 -0
- data/lib/decidim/core/test/factories.rb +3 -0
- data/lib/decidim/core/test/shared_examples/admin_resource_gallery_examples.rb +10 -10
- data/lib/decidim/core/test/shared_examples/comments_examples.rb +6 -6
- data/lib/decidim/core/version.rb +1 -1
- data/lib/decidim/map/autocomplete.rb +4 -3
- data/lib/decidim/searchable.rb +5 -0
- data/lib/decidim/view_model.rb +1 -1
- data/lib/tasks/decidim_mailers_tasks.rake +31 -9
- metadata +14 -10
- data/app/commands/decidim/gallery_methods.rb +0 -107
- data/app/packs/src/decidim/vendor/tribute.js +0 -1890
- data/app/packs/stylesheets/decidim/_tribute.scss +0 -36
- data/app/views/decidim/participants_account_mailer/removal_notification.html.erb +0 -11
|
@@ -1,16 +1,38 @@
|
|
|
1
|
-
|
|
1
|
+
document.addEventListener("turbo:load", async () => {
|
|
2
2
|
const GRANTED_PERMISSION = "granted"
|
|
3
3
|
|
|
4
4
|
const hideReminder = function() {
|
|
5
|
-
const reminder = document.querySelector("
|
|
5
|
+
const reminder = document.querySelector("[data-push-notifications-reminder]")
|
|
6
|
+
if (!reminder) {
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
|
|
6
10
|
reminder.classList.add("hide")
|
|
7
11
|
}
|
|
8
12
|
|
|
13
|
+
const showError = (message) => {
|
|
14
|
+
const container = document.querySelector("[data-push-notifications-container]")
|
|
15
|
+
if (!container) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const existingError = container.querySelector("[data-push-notifications-error]")
|
|
20
|
+
if (existingError) {
|
|
21
|
+
existingError.remove()
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const errorElement = document.createElement("div")
|
|
25
|
+
errorElement.dataset.pushNotificationsError = "true"
|
|
26
|
+
errorElement.classList.add("flash", "alert", "push-notifications__error")
|
|
27
|
+
errorElement.innerText = message
|
|
28
|
+
container.prepend(errorElement)
|
|
29
|
+
}
|
|
30
|
+
|
|
9
31
|
const subscribeToNotifications = async (registration) => {
|
|
10
32
|
const permission = await window.Notification.requestPermission();
|
|
11
33
|
|
|
12
34
|
if (registration && permission === GRANTED_PERMISSION) {
|
|
13
|
-
const vapidElement = document.querySelector("
|
|
35
|
+
const vapidElement = document.querySelector("[data-push-vapid-public-key]")
|
|
14
36
|
// element could not exist in DOM
|
|
15
37
|
if (vapidElement) {
|
|
16
38
|
const vapidPublicKeyElement = JSON.parse(vapidElement.value)
|
|
@@ -20,7 +42,7 @@ window.addEventListener("turbo:load", async () => {
|
|
|
20
42
|
});
|
|
21
43
|
|
|
22
44
|
if (subscription) {
|
|
23
|
-
await fetch("/notifications_subscriptions", {
|
|
45
|
+
const response = await fetch("/notifications_subscriptions", {
|
|
24
46
|
headers: {
|
|
25
47
|
"Content-Type": "application/json",
|
|
26
48
|
"X-CSRF-Token": document.querySelector("meta[name=csrf-token]")?.content
|
|
@@ -28,6 +50,11 @@ window.addEventListener("turbo:load", async () => {
|
|
|
28
50
|
method: "POST",
|
|
29
51
|
body: JSON.stringify(subscription)
|
|
30
52
|
});
|
|
53
|
+
|
|
54
|
+
if (!response.ok) {
|
|
55
|
+
const body = await response.json()
|
|
56
|
+
throw new Error(body.error)
|
|
57
|
+
}
|
|
31
58
|
}
|
|
32
59
|
}
|
|
33
60
|
hideReminder()
|
|
@@ -57,10 +84,13 @@ window.addEventListener("turbo:load", async () => {
|
|
|
57
84
|
hideReminder()
|
|
58
85
|
if (currentSubscription) {
|
|
59
86
|
const auth = currentSubscription.toJSON().keys.auth
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
87
|
+
const subKeysElement = document.querySelector("[data-push-sub-keys]")
|
|
88
|
+
if (subKeysElement) {
|
|
89
|
+
const subKeys = JSON.parse(subKeysElement.value)
|
|
90
|
+
// Subscribed && browser notifications enabled
|
|
91
|
+
if (subKeys.includes(auth)) {
|
|
92
|
+
toggleChecked = true
|
|
93
|
+
}
|
|
64
94
|
}
|
|
65
95
|
}
|
|
66
96
|
}
|
|
@@ -68,7 +98,7 @@ window.addEventListener("turbo:load", async () => {
|
|
|
68
98
|
}
|
|
69
99
|
|
|
70
100
|
if ("serviceWorker" in navigator) {
|
|
71
|
-
const toggle = document.
|
|
101
|
+
const toggle = document.querySelector("[data-push-notifications-toggle]")
|
|
72
102
|
|
|
73
103
|
if (toggle) {
|
|
74
104
|
const registration = await navigator.serviceWorker.ready
|
|
@@ -76,10 +106,15 @@ window.addEventListener("turbo:load", async () => {
|
|
|
76
106
|
setToggleState(registration, toggle)
|
|
77
107
|
|
|
78
108
|
toggle.addEventListener("change", async ({ target }) => {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
109
|
+
try {
|
|
110
|
+
if (target.checked) {
|
|
111
|
+
await subscribeToNotifications(registration)
|
|
112
|
+
} else {
|
|
113
|
+
await unsubscribeFromNotifications(registration)
|
|
114
|
+
}
|
|
115
|
+
} catch (error) {
|
|
116
|
+
target.checked = false
|
|
117
|
+
showError(error.message)
|
|
83
118
|
}
|
|
84
119
|
})
|
|
85
120
|
}
|
|
@@ -53,7 +53,7 @@ self.addEventListener("notificationclick", (event) => {
|
|
|
53
53
|
// avoid caching admin or users paths
|
|
54
54
|
registerRoute(
|
|
55
55
|
({ url }) =>
|
|
56
|
-
["
|
|
56
|
+
["admin", "users"].some((pathSegment) => url.pathname.split("/").includes(pathSegment)),
|
|
57
57
|
new NetworkOnly()
|
|
58
58
|
);
|
|
59
59
|
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
|
|
1
|
+
const escapeQuotes = (text) => {
|
|
2
2
|
if (!text) {
|
|
3
3
|
return "";
|
|
4
4
|
}
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
el.appendChild(document.createTextNode(text));
|
|
8
|
-
return el.innerHTML;
|
|
6
|
+
return text.replace(/"/g, """);
|
|
9
7
|
}
|
|
10
8
|
|
|
11
|
-
export const
|
|
9
|
+
export const escapeHtml = (text) => {
|
|
12
10
|
if (!text) {
|
|
13
11
|
return "";
|
|
14
12
|
}
|
|
15
13
|
|
|
16
|
-
|
|
14
|
+
const el = document.createElement("div");
|
|
15
|
+
el.appendChild(document.createTextNode(text));
|
|
16
|
+
return escapeQuotes(el.innerHTML);
|
|
17
17
|
}
|
|
@@ -88,6 +88,20 @@
|
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
&__modal {
|
|
91
|
+
&-error {
|
|
92
|
+
[data-dialog-closable] {
|
|
93
|
+
@apply top-6 right-6;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
[data-dialog-container] {
|
|
97
|
+
@apply inline grid-cols-none;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
[data-dialog-title] {
|
|
101
|
+
@apply col-span-2 md:col-span-1 md:col-start-2 grid grid-cols-[auto_1fr] items-start md:items-center gap-2 pb-4 text-left text-xl text-gray-2 md:border-b md:border-gray-3;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
91
105
|
&-results {
|
|
92
106
|
@apply mb-20 flex flex-wrap gap-x-8 gap-y-4;
|
|
93
107
|
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
.editor-suggestions-props {
|
|
2
|
+
--editor-suggestions-border-color: #000;
|
|
3
|
+
--editor-suggestions-background-color: #eee;
|
|
4
|
+
--editor-suggestions-selected-highlight-color: #ccc;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.editor-suggestions {
|
|
8
|
+
@apply editor-suggestions-props border-0 bg-[var(--editor-suggestions-background-color)] max-w-sm drop-shadow-md rounded-md;
|
|
9
|
+
|
|
10
|
+
&:hover {
|
|
11
|
+
.editor-suggestions-item[data-selected]:not(:hover) {
|
|
12
|
+
@apply bg-transparent;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.editor-suggestions-item {
|
|
17
|
+
@apply flex items-center gap-2 w-full text-left py-[0.375rem] px-1.5 border-0 rounded-none text-sm;
|
|
18
|
+
|
|
19
|
+
&:first-child {
|
|
20
|
+
@apply rounded-t-md;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
&:last-child {
|
|
24
|
+
@apply rounded-b-md;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
&:hover,
|
|
28
|
+
&[data-selected] {
|
|
29
|
+
@apply bg-[var(--editor-suggestions-selected-highlight-color)];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.editor-suggestions-item-avatar {
|
|
33
|
+
@apply rounded-full w-6 h-6 object-cover flex-none;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.editor-suggestions-item-label {
|
|
37
|
+
@apply truncate;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.editor-suggestions-item-disabled {
|
|
42
|
+
@apply cursor-default;
|
|
43
|
+
|
|
44
|
+
&:hover,
|
|
45
|
+
&[data-selected] {
|
|
46
|
+
@apply bg-transparent;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
[data-floating-help] {
|
|
2
|
-
@apply absolute z-10 top-
|
|
2
|
+
@apply absolute z-10 top-20 md:top-10 right-0 [&_button]:bg-background [&_button]:px-2 [&_button]:rounded-r-none [&_svg]:text-gray [&_svg]:fill-current;
|
|
3
3
|
|
|
4
4
|
&:hover {
|
|
5
5
|
@apply [&_svg]:text-white [&_button]:text-white [&_button]:bg-secondary [&_button]:no-underline;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
@use "tom-select/dist/scss/tom-select";
|
|
2
|
+
|
|
3
|
+
.ts {
|
|
4
|
+
&-control {
|
|
5
|
+
@apply border-gray text-md min-h-[40px];
|
|
6
|
+
|
|
7
|
+
input {
|
|
8
|
+
@apply font-normal text-black text-md;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
&-dropdown {
|
|
13
|
+
@apply text-md text-gray-2 font-normal;
|
|
14
|
+
|
|
15
|
+
.option img {
|
|
16
|
+
@apply inline;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.active {
|
|
20
|
+
@apply bg-gray-3;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
// Datepicker
|
|
7
7
|
@use "stylesheets/decidim/vendor/datepicker_light";
|
|
8
8
|
@use "stylesheets/decidim/datepicker";
|
|
9
|
+
// TomSelect
|
|
10
|
+
@use "stylesheets/decidim/tom_select";
|
|
9
11
|
// On the other hand, the following styles match with specific routes
|
|
10
12
|
@use "stylesheets/decidim/header";
|
|
11
13
|
@use "stylesheets/decidim/footer";
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
@use "stylesheets/decidim/editor_suggestions";
|
|
2
|
+
|
|
1
3
|
.editor-props {
|
|
2
4
|
--editor-active-color: #487bda;
|
|
3
5
|
--editor-disabled-color: #eee;
|
|
@@ -5,12 +7,6 @@
|
|
|
5
7
|
--editor-bubble-shadow-color: #333;
|
|
6
8
|
}
|
|
7
9
|
|
|
8
|
-
.editor-suggestions-props {
|
|
9
|
-
--editor-suggestions-border-color: #000;
|
|
10
|
-
--editor-suggestions-background-color: #eee;
|
|
11
|
-
--editor-suggestions-selected-highlight-color: #ccc;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
10
|
.editor-active {
|
|
15
11
|
@apply outline outline-4 outline-[var(--editor-active-color)];
|
|
16
12
|
}
|
|
@@ -186,30 +182,3 @@
|
|
|
186
182
|
}
|
|
187
183
|
}
|
|
188
184
|
}
|
|
189
|
-
|
|
190
|
-
.editor-suggestions {
|
|
191
|
-
@apply editor-suggestions-props border-0 bg-[var(--editor-suggestions-background-color)] max-w-sm drop-shadow-md rounded-md;
|
|
192
|
-
|
|
193
|
-
&:hover {
|
|
194
|
-
.editor-suggestions-item[data-selected]:not(:hover) {
|
|
195
|
-
@apply bg-transparent;
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
.editor-suggestions-item {
|
|
200
|
-
@apply block w-full text-left py-[0.375rem] px-1.5 border-0 rounded-none truncate text-sm;
|
|
201
|
-
|
|
202
|
-
&:first-child {
|
|
203
|
-
@apply rounded-t-md;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
&:last-child {
|
|
207
|
-
@apply rounded-b-md;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
&:hover,
|
|
211
|
-
&[data-selected] {
|
|
212
|
-
@apply bg-[var(--editor-suggestions-selected-highlight-color)];
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
}
|
|
@@ -1,5 +1,13 @@
|
|
|
1
|
-
.geocoding
|
|
2
|
-
.
|
|
1
|
+
.geocoding {
|
|
2
|
+
&__locate .geocoding__button {
|
|
3
3
|
@apply mt-4;
|
|
4
|
+
|
|
5
|
+
&--locating {
|
|
6
|
+
@apply opacity-70 cursor-wait;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.geocoding__spinner {
|
|
10
|
+
@apply inline-block w-4 h-4 rounded-full animate-spin border-2 border-l-transparent border-y-transparent border-r-secondary align-middle;
|
|
11
|
+
}
|
|
4
12
|
}
|
|
5
13
|
}
|
|
@@ -29,9 +29,9 @@ module Decidim
|
|
|
29
29
|
delegate :content_tag, :safe_join, :link_to, :active_link_to_class, :is_active_link?, :icon, to: :@view
|
|
30
30
|
|
|
31
31
|
def render
|
|
32
|
-
content_tag :li, role:
|
|
32
|
+
content_tag :li, role: wrapper_role, class: link_wrapper_classes do
|
|
33
33
|
output = if url == "#"
|
|
34
|
-
[content_tag(:span, composed_label, class: "sidebar-menu__item-disabled")]
|
|
34
|
+
[content_tag(:span, composed_label, class: "sidebar-menu__item-disabled", role: menuitem_role)]
|
|
35
35
|
else
|
|
36
36
|
[link_to(composed_label, url, link_options)]
|
|
37
37
|
end
|
|
@@ -52,7 +52,7 @@ module Decidim
|
|
|
52
52
|
{ aria: { current: "page" } }
|
|
53
53
|
else
|
|
54
54
|
{}
|
|
55
|
-
end.merge({ class: link_classes })
|
|
55
|
+
end.merge({ class: link_classes, role: menuitem_role })
|
|
56
56
|
end
|
|
57
57
|
|
|
58
58
|
def composed_label
|
|
@@ -75,6 +75,12 @@ module Decidim
|
|
|
75
75
|
@options.role || :menuitem
|
|
76
76
|
end
|
|
77
77
|
|
|
78
|
+
def wrapper_role
|
|
79
|
+
return if menuitem_role.blank?
|
|
80
|
+
|
|
81
|
+
:presentation
|
|
82
|
+
end
|
|
83
|
+
|
|
78
84
|
def active_class
|
|
79
85
|
active_link_to_class(
|
|
80
86
|
url,
|
|
@@ -4,6 +4,10 @@ module Decidim
|
|
|
4
4
|
# This class manages the creation and deletion of user notifications
|
|
5
5
|
|
|
6
6
|
class NotificationsSubscriptionsPersistor
|
|
7
|
+
include PushSubscriptionEndpointValidator
|
|
8
|
+
|
|
9
|
+
class UnsupportedPushSubscriptionEndpointError < StandardError; end
|
|
10
|
+
|
|
7
11
|
attr_reader :user
|
|
8
12
|
|
|
9
13
|
def initialize(user)
|
|
@@ -11,6 +15,8 @@ module Decidim
|
|
|
11
15
|
end
|
|
12
16
|
|
|
13
17
|
def add_subscription(params)
|
|
18
|
+
raise UnsupportedPushSubscriptionEndpointError unless supported_push_subscription_endpoint?(params[:endpoint])
|
|
19
|
+
|
|
14
20
|
subscriptions = user.notification_settings["subscriptions"] || {}
|
|
15
21
|
filtered_params = filter_params(params)
|
|
16
22
|
new_subscription = { filtered_params[:auth] => filtered_params }
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
# Shared validation for browser push subscription endpoints.
|
|
5
|
+
module PushSubscriptionEndpointValidator
|
|
6
|
+
private
|
|
7
|
+
|
|
8
|
+
def supported_push_subscription_endpoint?(endpoint)
|
|
9
|
+
return false if endpoint.blank?
|
|
10
|
+
|
|
11
|
+
uri = URI.parse(endpoint)
|
|
12
|
+
return false unless uri.is_a?(URI::HTTPS)
|
|
13
|
+
|
|
14
|
+
host = uri.host&.downcase
|
|
15
|
+
return false if host.blank?
|
|
16
|
+
|
|
17
|
+
allowed_push_subscription_endpoint_patterns.any? { |pattern| pattern.match?(host) }
|
|
18
|
+
rescue URI::InvalidURIError
|
|
19
|
+
false
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Override this method to customize the browser push endpoint allowlist.
|
|
23
|
+
def allowed_push_subscription_endpoint_patterns
|
|
24
|
+
[
|
|
25
|
+
/\A(?:.*\.)?push\.services\.mozilla\.com\z/,
|
|
26
|
+
/\A(?:.*\.)?fcm\.googleapis\.com\z/,
|
|
27
|
+
/\A(?:.*\.)?android\.googleapis\.com\z/,
|
|
28
|
+
/\A(?:.*\.)?push\.apple\.com\z/,
|
|
29
|
+
/\A(?:.*\.)?opera\.com\z/,
|
|
30
|
+
/\A(?:.*\.)?notify\.windows\.com\z/
|
|
31
|
+
]
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -10,6 +10,7 @@ module Decidim
|
|
|
10
10
|
|
|
11
11
|
class SendPushNotification
|
|
12
12
|
include ActionView::Helpers::UrlHelper
|
|
13
|
+
include PushSubscriptionEndpointValidator
|
|
13
14
|
|
|
14
15
|
# Send the push notification. Returns `nil` if the user did not allowed push notifications
|
|
15
16
|
# or if the subscription to push notifications does not exist
|
|
@@ -24,9 +25,12 @@ module Decidim
|
|
|
24
25
|
raise ArgumentError, "Need to provide a title if the notification is a PushNotificationMessage" if notification.is_a?(Decidim::PushNotificationMessage) && title.nil?
|
|
25
26
|
|
|
26
27
|
user = notification.user
|
|
28
|
+
subscriptions = user.notifications_subscriptions.values.select do |subscription|
|
|
29
|
+
supported_push_subscription_endpoint?(subscription["endpoint"])
|
|
30
|
+
end
|
|
27
31
|
|
|
28
32
|
I18n.with_locale(user.locale || user.organization.default_locale) do
|
|
29
|
-
|
|
33
|
+
subscriptions.map do |subscription|
|
|
30
34
|
payload = build_payload(message_params(notification, title), subscription)
|
|
31
35
|
# Capture webpush exceptions in order to avoid this call to be repeated by the background job runner
|
|
32
36
|
# Webpush::Error class is the parent class of all defined errors
|
|
@@ -8,7 +8,7 @@ module Decidim
|
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
def content_type_allowlist
|
|
11
|
-
extension_allowlist.
|
|
11
|
+
extension_allowlist.filter_map { |ext| MiniMime.lookup_by_extension(ext)&.content_type }.uniq
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
# Fetches info about different variants, their processors and dimensions
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<p class="email-greeting"><%= t(".hello", username: @user_name) %></p>
|
|
2
|
+
|
|
3
|
+
<p class="email-instructions"><%= t ".body_1" %></p>
|
|
4
|
+
<p class="email-instructions"><%= t ".body_2" %></p>
|
|
5
|
+
|
|
6
|
+
<p class="email-closing"><%= t(".greetings_html", organization_name: organization_name(@organization), organization_url: decidim.root_url(host: @organization.host)) %></p>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<% add_decidim_page_title(t("last_activity", scope: "decidim.last_activities.index")) %>
|
|
2
2
|
|
|
3
3
|
<%# NOTE: this page does not use a regular layout %>
|
|
4
|
-
<main class="container">
|
|
4
|
+
<main class="container" role="main">
|
|
5
5
|
<h1 class="title-decorator my-12"><%= t("last_activity", scope: "decidim.last_activities.index") %></h1>
|
|
6
6
|
|
|
7
7
|
<div class="profile__activity pb-16">
|
|
@@ -1,21 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
<div>
|
|
3
|
-
<h2><%= error %></h2>
|
|
4
|
-
<
|
|
5
|
-
|
|
6
|
-
<
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
<p>
|
|
12
|
-
<%= messages.join("<br>") %>
|
|
13
|
-
</p>
|
|
14
|
-
<p><%= t(".correct_errors") %></p>
|
|
15
|
-
</div>
|
|
16
|
-
<div>
|
|
17
|
-
<div>
|
|
18
|
-
<a class="button" role="button" href="#" data-close aria-label="<%= t(".ok") %>"><%= t(".ok") %></a>
|
|
1
|
+
<%= decidim_modal id: "messageErrorModal", class: "conversation__modal-error" do %>
|
|
2
|
+
<div data-dialog-container>
|
|
3
|
+
<h2 id="dialog-title-messageErrorModal" tabindex="-1" data-dialog-title><%= error %></h2>
|
|
4
|
+
<div id="dialog-desc-messageErrorModal" class="mt-4">
|
|
5
|
+
<p><%= t(".intro") %></p>
|
|
6
|
+
<p><%= safe_join(messages, tag.br) %></p>
|
|
7
|
+
<p><%= t(".correct_errors") %></p>
|
|
8
|
+
</div>
|
|
9
|
+
<div data-dialog-actions>
|
|
10
|
+
<button type="button" class="button button__sm lg:button__lg button__secondary" data-dialog-close="messageErrorModal" aria-label="<%= t(".ok") %>"><%= t(".ok") %></button>
|
|
19
11
|
</div>
|
|
20
12
|
</div>
|
|
21
|
-
|
|
13
|
+
<% end %>
|
|
@@ -1,10 +1,15 @@
|
|
|
1
|
-
var
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
var messageError = document.getElementById("messageErrorModal")
|
|
2
|
+
|
|
3
|
+
if (messageError) {
|
|
4
|
+
messageError.remove();
|
|
4
5
|
}
|
|
6
|
+
document.body.insertAdjacentHTML("beforeend", "<%= j(render "error_modal", error:, messages:).html_safe %>");
|
|
5
7
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
+
messageError = document.getElementById("messageErrorModal")
|
|
9
|
+
if (messageError) {
|
|
10
|
+
window.createDialog(messageError);
|
|
8
11
|
|
|
9
|
-
|
|
10
|
-
|
|
12
|
+
if (Decidim.currentDialogs.messageErrorModal) {
|
|
13
|
+
window.Decidim.currentDialogs.messageErrorModal.open();
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -167,20 +167,20 @@
|
|
|
167
167
|
<% end %>
|
|
168
168
|
|
|
169
169
|
<% if @notifications_settings.meet_push_notifications_requirements? %>
|
|
170
|
-
<div class="push-notifications js-sw-mandatory">
|
|
170
|
+
<div class="push-notifications js-sw-mandatory" data-push-notifications-container>
|
|
171
171
|
<label>
|
|
172
172
|
<%= t("push_notifications", scope: "decidim.notifications_settings.show") %>
|
|
173
173
|
</label>
|
|
174
|
-
<p id="push-notifications-reminder" class="push-notifications__reminder block my-4">
|
|
174
|
+
<p id="push-notifications-reminder" class="push-notifications__reminder block my-4" data-push-notifications-reminder>
|
|
175
175
|
<%= t("push_notifications_reminder", scope: "decidim.notifications_settings.show") %>
|
|
176
176
|
</p>
|
|
177
177
|
<div class="toggle__switch-trigger">
|
|
178
178
|
<label class="toggle__switch-toggle" for="allow_push_notifications">
|
|
179
179
|
<span>
|
|
180
180
|
<input
|
|
181
|
-
<%== %(checked="checked") if @notifications_settings.meet_push_notifications_requirements? %>
|
|
182
181
|
id="allow_push_notifications"
|
|
183
182
|
type="checkbox"
|
|
183
|
+
data-push-notifications-toggle
|
|
184
184
|
name="allow_push_notifications">
|
|
185
185
|
<span class="toggle__switch-toggle-content">
|
|
186
186
|
</span>
|
|
@@ -194,8 +194,8 @@
|
|
|
194
194
|
</div>
|
|
195
195
|
</div>
|
|
196
196
|
|
|
197
|
-
<input id="vapidPublicKey" name="vapid_public_key" type="hidden" value="<%= Base64.urlsafe_decode64(Decidim.vapid_public_key.to_s).bytes %>">
|
|
198
|
-
<input id="subKeys" name="sub_key" type="hidden" value="<%= current_user.notifications_subscriptions.keys %>">
|
|
197
|
+
<input id="vapidPublicKey" name="vapid_public_key" data-push-vapid-public-key type="hidden" value="<%= Base64.urlsafe_decode64(Decidim.vapid_public_key.to_s).bytes.to_json %>">
|
|
198
|
+
<input id="subKeys" name="sub_key" data-push-sub-keys type="hidden" value="<%= current_user.notifications_subscriptions.keys.to_json %>">
|
|
199
199
|
<% end %>
|
|
200
200
|
|
|
201
201
|
<div class="form__wrapper-block">
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<% add_decidim_page_title(t("decidim.offline.name")) %>
|
|
2
2
|
|
|
3
|
-
<main id="offline-fallback-html" class="text-center my-8">
|
|
3
|
+
<main id="offline-fallback-html" class="text-center my-8" role="main">
|
|
4
4
|
<div class="flex justify-center">
|
|
5
5
|
<svg xmlns="http://www.w3.org/2000/svg" width="5rem" height="r5em" viewBox="0 0 25 25">
|
|
6
6
|
<path
|
|
@@ -42,7 +42,7 @@ edit_link(
|
|
|
42
42
|
<div id="accordion-panel-<%= ix %>" class="page__accordion-panel" aria-hidden="true">
|
|
43
43
|
<ul role="menu">
|
|
44
44
|
<% topic.pages.each do |page| %>
|
|
45
|
-
<li role="
|
|
45
|
+
<li role="presentation"><%= link_to translated_attribute(page.title), page_path(page), class: "text-secondary", role: "menuitem" %></li>
|
|
46
46
|
<% end %>
|
|
47
47
|
</ul>
|
|
48
48
|
</div>
|
|
@@ -12,12 +12,12 @@
|
|
|
12
12
|
<ul class="dropdown dropdown__bottom divide-y divide-gray-3" role="menu">
|
|
13
13
|
<%= yield %>
|
|
14
14
|
<% unless defined?(skip_report) && skip_report %>
|
|
15
|
-
<li role="
|
|
16
|
-
<%= cell "decidim/report_button", resource, button_classes: "dropdown__button" %>
|
|
15
|
+
<li role="presentation" class="dropdown__item">
|
|
16
|
+
<%= cell "decidim/report_button", resource, button_classes: "dropdown__button", html_options: { role: "menuitem" } %>
|
|
17
17
|
</li>
|
|
18
18
|
<% end %>
|
|
19
|
-
<li role="
|
|
20
|
-
<%= cell "decidim/follow_button", resource, large: false, button_classes: "dropdown__button" %>
|
|
19
|
+
<li role="presentation" class="dropdown__item">
|
|
20
|
+
<%= cell "decidim/follow_button", resource, large: false, button_classes: "dropdown__button", html_options: { role: "menuitem" } %>
|
|
21
21
|
</li>
|
|
22
22
|
</ul>
|
|
23
23
|
</div>
|