decidim-core 0.27.5 → 0.27.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/cells/decidim/activity_cell.rb +2 -2
- data/app/cells/decidim/card_cell.rb +2 -2
- data/app/cells/decidim/card_m/top.erb +1 -1
- data/app/cells/decidim/card_m_cell.rb +1 -1
- data/app/cells/decidim/follow_button_cell.rb +1 -1
- data/app/cells/decidim/notification/moderated.erb +24 -0
- data/app/cells/decidim/notification_cell.rb +5 -1
- data/app/cells/decidim/scopes_picker/scope_picker_values.erb +1 -1
- data/app/cells/decidim/tags_cell.rb +3 -1
- data/app/cells/decidim/user_profile_cell.rb +1 -1
- data/app/commands/decidim/create_omniauth_registration.rb +2 -4
- data/app/commands/decidim/messaging/reply_to_conversation.rb +3 -0
- data/app/commands/decidim/messaging/start_conversation.rb +3 -0
- data/app/controllers/concerns/decidim/devise_authentication_methods.rb +36 -0
- data/app/controllers/concerns/decidim/force_authentication.rb +1 -1
- data/app/controllers/concerns/decidim/paginable.rb +1 -1
- data/app/controllers/concerns/decidim/use_organization_time_zone.rb +1 -1
- data/app/controllers/decidim/devise/omniauth_registrations_controller.rb +1 -22
- data/app/controllers/decidim/devise/sessions_controller.rb +1 -24
- data/app/controllers/decidim/links_controller.rb +13 -1
- data/app/controllers/decidim/widgets_controller.rb +6 -0
- data/app/events/decidim/welcome_notification_event.rb +6 -9
- data/app/helpers/decidim/cells_paginate_helper.rb +1 -1
- data/app/helpers/decidim/check_boxes_tree_helper.rb +4 -4
- data/app/helpers/decidim/newsletters_helper.rb +83 -16
- data/app/helpers/decidim/resource_helper.rb +1 -1
- data/app/helpers/decidim/sanitize_helper.rb +9 -0
- data/app/helpers/decidim/user_profile_helper.rb +7 -2
- data/app/mailers/decidim/application_mailer.rb +40 -6
- data/app/mailers/decidim/messaging/conversation_mailer.rb +3 -72
- data/app/models/decidim/push_notification_message.rb +39 -0
- data/app/packs/images/decidim/.keep +0 -0
- data/app/packs/src/decidim/input_hashtags.js +1 -1
- data/app/packs/src/decidim/input_mentions.js +1 -1
- data/app/packs/src/decidim/input_multiple_mentions.js +1 -1
- data/app/packs/src/decidim/vizzs/index.js +1 -1
- data/app/packs/stylesheets/decidim/plugins/leaflet.scss +118 -114
- data/app/presenters/decidim/admin_log/oauth_application_resource_presenter.rb +1 -1
- data/app/presenters/decidim/admin_log/organization_presenter.rb +1 -1
- data/app/presenters/decidim/log/resource_presenter.rb +7 -1
- data/app/presenters/decidim/notification_to_mailer_presenter.rb +9 -0
- data/app/services/decidim/events_manager.rb +6 -0
- data/app/services/decidim/log/diff_changeset_calculator.rb +1 -1
- data/app/services/decidim/push_notification_message_sender.rb +36 -0
- data/app/services/decidim/send_push_notification.rb +22 -8
- data/app/views/decidim/devise/registrations/new.html.erb +2 -2
- data/app/views/decidim/links/new.html.erb +2 -0
- data/app/views/decidim/notifications_digest_mailer/_email_content.html.erb +7 -0
- data/app/views/decidim/shared/_address_details.html.erb +2 -2
- data/app/views/layouts/decidim/_js_configuration.html.erb +1 -0
- data/config/locales/ar.yml +4 -3
- data/config/locales/bg.yml +484 -1
- data/config/locales/ca.yml +23 -22
- data/config/locales/cs.yml +0 -1
- data/config/locales/de.yml +28 -27
- data/config/locales/el.yml +5 -4
- data/config/locales/en.yml +1 -0
- data/config/locales/eo.yml +3 -0
- data/config/locales/es-MX.yml +6 -5
- data/config/locales/es-PY.yml +6 -5
- data/config/locales/es.yml +25 -24
- data/config/locales/eu.yml +12 -2
- data/config/locales/fi-plain.yml +1 -0
- data/config/locales/fi.yml +4 -3
- data/config/locales/fr-CA.yml +5 -4
- data/config/locales/fr.yml +3 -2
- data/config/locales/ga-IE.yml +5 -0
- data/config/locales/gl.yml +3 -0
- data/config/locales/he-IL.yml +1 -0
- data/config/locales/hu.yml +41 -9
- data/config/locales/it.yml +5 -4
- data/config/locales/ja.yml +5 -3
- data/config/locales/lb.yml +5 -4
- data/config/locales/lt.yml +4 -4
- data/config/locales/lv.yml +4 -1
- data/config/locales/nl.yml +4 -1
- data/config/locales/no.yml +5 -4
- data/config/locales/pl.yml +168 -1
- data/config/locales/pt-BR.yml +113 -22
- data/config/locales/pt.yml +5 -4
- data/config/locales/ro-RO.yml +1 -3
- data/config/locales/ru.yml +13 -0
- data/config/locales/sk.yml +6 -1
- data/config/locales/sl.yml +5 -0
- data/config/locales/sv.yml +26 -3
- data/config/locales/tr-TR.yml +3 -3
- data/config/locales/uk.yml +15 -0
- data/config/locales/zh-CN.yml +0 -4
- data/config/locales/zh-TW.yml +4 -4
- data/decidim-core.gemspec +78 -0
- data/lib/decidim/acts_as_tree.rb +14 -1
- data/lib/decidim/asset_router/storage.rb +4 -0
- data/lib/decidim/attribute_encryptor.rb +6 -4
- data/lib/decidim/core/engine.rb +7 -3
- data/lib/decidim/core/test/factories.rb +314 -95
- data/lib/decidim/core/test/shared_examples/amendable/amendment_created_event_examples.rb +6 -26
- data/lib/decidim/core/test/shared_examples/amendable/amendment_promoted_event_examples.rb +8 -26
- data/lib/decidim/core/test/shared_examples/comments_examples.rb +32 -0
- data/lib/decidim/core/test/shared_examples/embed_resource_examples.rb +187 -11
- data/lib/decidim/core/test/shared_examples/has_attachment_collections.rb +8 -6
- data/lib/decidim/core/test/shared_examples/has_attachments.rb +4 -4
- data/lib/decidim/core/test/shared_examples/has_category.rb +27 -0
- data/lib/decidim/core/test/shared_examples/has_reference.rb +1 -1
- data/lib/decidim/core/test/shared_examples/has_space_in_mcell_examples.rb +1 -2
- data/lib/decidim/core/test/shared_examples/resource_endorsed_event_examples.rb +6 -3
- data/lib/decidim/core/test/shared_examples/resource_locator_presenter_examples.rb +134 -0
- data/lib/decidim/core/test/shared_examples/searchable_results_examples.rb +1 -1
- data/lib/decidim/core/test/shared_examples/simple_event.rb +50 -2
- data/lib/decidim/core/test.rb +1 -0
- data/lib/decidim/core/version.rb +1 -1
- data/lib/decidim/core.rb +1 -0
- data/lib/decidim/engine_router.rb +17 -4
- data/lib/decidim/events/base_event.rb +9 -2
- data/lib/decidim/events/simple_event.rb +3 -17
- data/lib/decidim/form_builder.rb +13 -1
- data/lib/decidim/has_category.rb +1 -1
- data/lib/decidim/has_conversations.rb +91 -0
- data/lib/decidim/organization_settings.rb +10 -2
- data/lib/decidim/participable.rb +17 -0
- data/lib/decidim/view_model.rb +1 -0
- data/lib/decidim/webpacker/webpack/.modernizrrc +9 -0
- data/lib/premailer/adapter/decidim.rb +5 -4
- data/lib/tasks/decidim_reminders_tasks.rake +1 -0
- data/lib/tasks/upgrade/decidim_fix_categorization.rake +15 -0
- metadata +29 -27
- data/config/environment.rb +0 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 71d8e583cc9dcd7338a03de09eb24a8a06a913f5e411b74bf16e5c42d9802639
|
4
|
+
data.tar.gz: c7028f8e3b04ab7c04afb94e6c74cbc114af7f734b5e65ff53d6a31bc0b6683e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f7df735fa2c671d915577eee036cb64b06c3ef85f4ecd1c95a65e22affb625f2a136c1596e55a7250f473397165f2364db867bad3287ecc3ffe5231e234cdc44
|
7
|
+
data.tar.gz: fd264b6e1db71ec2e9b1fb0cc31a73ddadf7c3e2a3dbe7209001f87f52a3840bae8f4bd406f5c84767460fea73fbcbf18a9f950b82d91d5b23c47b1bd02f60fa
|
@@ -28,11 +28,11 @@ module Decidim
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def title
|
31
|
-
model.try(:title) || model.try(:name) || ""
|
31
|
+
decidim_escape_translated(model.try(:title) || model.try(:name) || "")
|
32
32
|
end
|
33
33
|
|
34
34
|
def body
|
35
|
-
model.try(:body) || model.try(:about) || ""
|
35
|
+
decidim_escape_translated(model.try(:body) || model.try(:about) || "")
|
36
36
|
end
|
37
37
|
|
38
38
|
def resource_manifest
|
@@ -1,7 +1,7 @@
|
|
1
1
|
<div class="card__top">
|
2
2
|
<% if render_space? %>
|
3
3
|
<div class="card__content text-small">
|
4
|
-
<span class="muted"><%= searchable_resource_human_name(model.participatory_space.class, count: 1) %>:</span> <%= link_to
|
4
|
+
<span class="muted"><%= searchable_resource_human_name(model.participatory_space.class, count: 1) %>:</span> <%= link_to decidim_escape_translated(model.participatory_space.title), Decidim::ResourceLocatorPresenter.new(model.participatory_space).path, class: "card__link text-ellipsis" %>
|
5
5
|
</div>
|
6
6
|
<% end %>
|
7
7
|
</div>
|
@@ -0,0 +1,24 @@
|
|
1
|
+
<div class="card card--widget">
|
2
|
+
<ul class="card-data">
|
3
|
+
<li class="card-data__item">
|
4
|
+
<div class="card__link text-center">
|
5
|
+
<%= resource_icon notification.resource, class: "icon--large" %>
|
6
|
+
<span class="text-medium mt-xs" title="<%= l(notification.created_at) %>" data-tooltip="true" data-disable-hover="false">
|
7
|
+
<%= notification.created_at_in_words %>
|
8
|
+
</span>
|
9
|
+
</div>
|
10
|
+
</li>
|
11
|
+
<li class="card-data__item card-data__item--expand absolutes">
|
12
|
+
<div class="mr-s">
|
13
|
+
<span class="text-small"><%= notification.event_class.constantize.model_name.human %></span>
|
14
|
+
<br>
|
15
|
+
<%= t("decidim.notifications.show.moderated") %>
|
16
|
+
</div>
|
17
|
+
<div class="right center mr-s">
|
18
|
+
<%= link_to model, remote: true, method: :delete, class: "mark-as-read-button" do %>
|
19
|
+
<%= icon "circle-x", class: "card__link", aria_label: t("mark_as_read", scope: "layouts.decidim.notifications_dashboard"), role: "img" %>
|
20
|
+
<% end %>
|
21
|
+
</div>
|
22
|
+
</li>
|
23
|
+
</ul>
|
24
|
+
</div>
|
@@ -1,5 +1,5 @@
|
|
1
1
|
<div class="picker-values">
|
2
2
|
<%- scopes.each do |scope, params| %>
|
3
|
-
<div><%= link_to params[:text], params[:url], data: { picker_value: scope.id } %></div>
|
3
|
+
<div><%= link_to decidim_html_escape(params[:text]), params[:url], data: { picker_value: scope.id } %></div>
|
4
4
|
<% end %>
|
5
5
|
</div>
|
@@ -9,6 +9,8 @@ module Decidim
|
|
9
9
|
# <%= cell("decidim/category", model.category, context: {resource: model}) %>
|
10
10
|
#
|
11
11
|
class TagsCell < Decidim::ViewModel
|
12
|
+
include Decidim::SanitizeHelper
|
13
|
+
|
12
14
|
def show
|
13
15
|
render if category? || scope?
|
14
16
|
end
|
@@ -51,7 +53,7 @@ module Decidim
|
|
51
53
|
end
|
52
54
|
|
53
55
|
def category_name
|
54
|
-
model.category.translated_name
|
56
|
+
decidim_html_escape model.category.translated_name
|
55
57
|
end
|
56
58
|
|
57
59
|
def category_path
|
@@ -57,14 +57,12 @@ module Decidim
|
|
57
57
|
# to be marked confirmed.
|
58
58
|
@user.skip_confirmation! if !@user.confirmed? && @user.email == verified_email
|
59
59
|
else
|
60
|
-
generated_password = SecureRandom.hex
|
61
|
-
|
62
60
|
@user.email = (verified_email || form.email)
|
63
61
|
@user.name = form.name
|
64
62
|
@user.nickname = form.normalized_nickname
|
65
63
|
@user.newsletter_notifications_at = nil
|
66
|
-
@user.password =
|
67
|
-
@user.password_confirmation =
|
64
|
+
@user.password = SecureRandom.hex
|
65
|
+
@user.password_confirmation = @user.password
|
68
66
|
if form.avatar_url.present?
|
69
67
|
url = URI.parse(form.avatar_url)
|
70
68
|
filename = File.basename(url.path)
|
@@ -54,11 +54,13 @@ module Decidim
|
|
54
54
|
notify(manager) do
|
55
55
|
ConversationMailer.new_group_message(sender, manager, conversation, message, recipient).deliver_later
|
56
56
|
end
|
57
|
+
Decidim::PushNotificationMessageSender.new.new_group_message(sender, manager, conversation, message, recipient).deliver
|
57
58
|
end
|
58
59
|
else
|
59
60
|
notify(recipient) do
|
60
61
|
ConversationMailer.new_message(sender, recipient, conversation, message).deliver_later
|
61
62
|
end
|
63
|
+
Decidim::PushNotificationMessageSender.new.new_message(sender, recipient, conversation, message).deliver
|
62
64
|
end
|
63
65
|
end
|
64
66
|
end
|
@@ -68,6 +70,7 @@ module Decidim
|
|
68
70
|
notify(recipient) do
|
69
71
|
ConversationMailer.comanagers_new_message(sender, recipient, conversation, message, form.context.current_user).deliver_later
|
70
72
|
end
|
73
|
+
Decidim::PushNotificationMessageSender.new.comanagers_new_message(sender, recipient, conversation, message, form.context.current_user).deliver
|
71
74
|
end
|
72
75
|
end
|
73
76
|
|
@@ -54,11 +54,13 @@ module Decidim
|
|
54
54
|
notify(manager) do
|
55
55
|
ConversationMailer.new_group_conversation(originator, manager, conversation, recipient).deliver_later
|
56
56
|
end
|
57
|
+
Decidim::PushNotificationMessageSender.new.new_group_conversation(originator, manager, conversation, recipient).deliver
|
57
58
|
end
|
58
59
|
else
|
59
60
|
notify(recipient) do
|
60
61
|
ConversationMailer.new_conversation(originator, recipient, conversation).deliver_later
|
61
62
|
end
|
63
|
+
Decidim::PushNotificationMessageSender.new.new_conversation(originator, recipient, conversation).deliver
|
62
64
|
end
|
63
65
|
end
|
64
66
|
end
|
@@ -68,6 +70,7 @@ module Decidim
|
|
68
70
|
notify(recipient) do
|
69
71
|
ConversationMailer.comanagers_new_conversation(originator, recipient, conversation, form.context.current_user).deliver_later
|
70
72
|
end
|
73
|
+
Decidim::PushNotificationMessageSender.new.comanagers_new_conversation(originator, recipient, conversation, form.context.current_user).deliver
|
71
74
|
end
|
72
75
|
end
|
73
76
|
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/concern"
|
4
|
+
|
5
|
+
module Decidim
|
6
|
+
module DeviseAuthenticationMethods
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
include Decidim::UserBlockedChecker
|
9
|
+
|
10
|
+
included do
|
11
|
+
def after_sign_in_path_for(user)
|
12
|
+
if user.present? && user.blocked?
|
13
|
+
check_user_block_status(user)
|
14
|
+
elsif user.needs_password_update?
|
15
|
+
change_password_path
|
16
|
+
elsif first_login_and_not_authorized?(user) && !user.admin? && !pending_redirect?(user)
|
17
|
+
decidim_verifications.first_login_authorizations_path
|
18
|
+
else
|
19
|
+
super
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Calling the `stored_location_for` method removes the key, so in order
|
24
|
+
# to check if there is any pending redirect after login I need to call
|
25
|
+
# this method and use the value to set a pending redirect. This is the
|
26
|
+
# only way to do this without checking the session directly.
|
27
|
+
def pending_redirect?(user)
|
28
|
+
store_location_for(user, stored_location_for(user))
|
29
|
+
end
|
30
|
+
|
31
|
+
def first_login_and_not_authorized?(user)
|
32
|
+
user.is_a?(User) && user.sign_in_count == 1 && current_organization.available_authorizations.any? && user.verifiable?
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -17,7 +17,7 @@ module Decidim
|
|
17
17
|
# Breaks the request lifecycle, if user is not authenticated.
|
18
18
|
# Otherwise returns.
|
19
19
|
def ensure_authenticated!
|
20
|
-
return true unless current_organization
|
20
|
+
return true unless current_organization&.force_users_to_authenticate_before_access_organization
|
21
21
|
|
22
22
|
# Next stop: Let's check whether auth is ok
|
23
23
|
unless user_signed_in?
|
@@ -6,6 +6,7 @@ module Decidim
|
|
6
6
|
class OmniauthRegistrationsController < ::Devise::OmniauthCallbacksController
|
7
7
|
include FormFactory
|
8
8
|
include Decidim::DeviseControllers
|
9
|
+
include Decidim::DeviseAuthenticationMethods
|
9
10
|
|
10
11
|
def new
|
11
12
|
@form = form(OmniauthRegistrationForm).from_params(params[:user])
|
@@ -45,28 +46,6 @@ module Decidim
|
|
45
46
|
end
|
46
47
|
end
|
47
48
|
|
48
|
-
def after_sign_in_path_for(user)
|
49
|
-
if user.present? && user.blocked?
|
50
|
-
check_user_block_status(user)
|
51
|
-
elsif !pending_redirect?(user) && first_login_and_not_authorized?(user)
|
52
|
-
decidim_verifications.authorizations_path
|
53
|
-
else
|
54
|
-
super
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
# Calling the `stored_location_for` method removes the key, so in order
|
59
|
-
# to check if there's any pending redirect after login I need to call
|
60
|
-
# this method and use the value to set a pending redirect. This is the
|
61
|
-
# only way to do this without checking the session directly.
|
62
|
-
def pending_redirect?(user)
|
63
|
-
store_location_for(user, stored_location_for(user))
|
64
|
-
end
|
65
|
-
|
66
|
-
def first_login_and_not_authorized?(user)
|
67
|
-
user.is_a?(User) && user.sign_in_count == 1 && Decidim::Verifications.workflows.any? && user.verifiable?
|
68
|
-
end
|
69
|
-
|
70
49
|
def action_missing(action_name)
|
71
50
|
return send(:create) if devise_mapping.omniauthable? && current_organization.enabled_omniauth_providers.keys.include?(action_name.to_sym)
|
72
51
|
|
@@ -5,6 +5,7 @@ module Decidim
|
|
5
5
|
# Custom Devise SessionsController to avoid namespace problems.
|
6
6
|
class SessionsController < ::Devise::SessionsController
|
7
7
|
include Decidim::DeviseControllers
|
8
|
+
include Decidim::DeviseAuthenticationMethods
|
8
9
|
|
9
10
|
before_action :check_sign_in_enabled, only: :create
|
10
11
|
|
@@ -35,30 +36,6 @@ module Decidim
|
|
35
36
|
end
|
36
37
|
end
|
37
38
|
|
38
|
-
def after_sign_in_path_for(user)
|
39
|
-
if user.present? && user.blocked?
|
40
|
-
check_user_block_status(user)
|
41
|
-
elsif user.needs_password_update?
|
42
|
-
change_password_path
|
43
|
-
elsif first_login_and_not_authorized?(user) && !user.admin? && !pending_redirect?(user)
|
44
|
-
decidim_verifications.first_login_authorizations_path
|
45
|
-
else
|
46
|
-
super
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
# Calling the `stored_location_for` method removes the key, so in order
|
51
|
-
# to check if there's any pending redirect after login I need to call
|
52
|
-
# this method and use the value to set a pending redirect. This is the
|
53
|
-
# only way to do this without checking the session directly.
|
54
|
-
def pending_redirect?(user)
|
55
|
-
store_location_for(user, stored_location_for(user))
|
56
|
-
end
|
57
|
-
|
58
|
-
def first_login_and_not_authorized?(user)
|
59
|
-
user.is_a?(User) && user.sign_in_count == 1 && current_organization.available_authorizations.any? && user.verifiable?
|
60
|
-
end
|
61
|
-
|
62
39
|
def after_sign_out_path_for(user)
|
63
40
|
request.referer || super
|
64
41
|
end
|
@@ -35,7 +35,19 @@ module Decidim
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def external_url
|
38
|
-
@external_url ||= URI.parse(
|
38
|
+
@external_url ||= URI.parse(escape_url(params[:external_url]))
|
39
|
+
end
|
40
|
+
|
41
|
+
def escape_url(external_url)
|
42
|
+
before_fragment, fragment = external_url.split("#", 2)
|
43
|
+
escaped_before_fragment = URI::Parser.new.escape(before_fragment)
|
44
|
+
|
45
|
+
if fragment
|
46
|
+
escaped_fragment = URI::Parser.new.escape(fragment)
|
47
|
+
"#{escaped_before_fragment}##{escaped_fragment}"
|
48
|
+
else
|
49
|
+
escaped_before_fragment
|
50
|
+
end
|
39
51
|
end
|
40
52
|
end
|
41
53
|
end
|
@@ -11,6 +11,8 @@ module Decidim
|
|
11
11
|
helper_method :model, :iframe_url, :current_participatory_space
|
12
12
|
|
13
13
|
def show
|
14
|
+
raise ActionController::RoutingError, "Not Found" if model.nil?
|
15
|
+
|
14
16
|
respond_to do |format|
|
15
17
|
format.js { render "decidim/widgets/show" }
|
16
18
|
format.html
|
@@ -19,6 +21,10 @@ module Decidim
|
|
19
21
|
|
20
22
|
private
|
21
23
|
|
24
|
+
def current_component
|
25
|
+
@current_component ||= request.env["decidim.current_component"]
|
26
|
+
end
|
27
|
+
|
22
28
|
def current_participatory_space
|
23
29
|
@current_participatory_space ||= model.component.participatory_space
|
24
30
|
end
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "mustache"
|
4
|
-
|
5
3
|
module Decidim
|
6
4
|
class WelcomeNotificationEvent < Decidim::Events::BaseEvent
|
7
5
|
include Decidim::Events::EmailEvent
|
@@ -46,13 +44,12 @@ module Decidim
|
|
46
44
|
private
|
47
45
|
|
48
46
|
def interpolate(template)
|
49
|
-
|
50
|
-
|
51
|
-
organization
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
).html_safe
|
47
|
+
template
|
48
|
+
.gsub("{{name}}", user.name)
|
49
|
+
.gsub("{{organization}}", organization.name)
|
50
|
+
.gsub("{{help_url}}", url_helpers.pages_url(host: organization.host))
|
51
|
+
.gsub("{{badges_url}}", url_helpers.gamification_badges_url(host: organization.host))
|
52
|
+
.html_safe
|
56
53
|
end
|
57
54
|
end
|
58
55
|
end
|
@@ -50,20 +50,20 @@ module Decidim
|
|
50
50
|
organization = current_participatory_space.organization
|
51
51
|
|
52
52
|
sorted_main_categories = current_participatory_space.categories.first_class.includes(:subcategories).sort_by do |category|
|
53
|
-
[category.weight, translated_attribute(category.name, organization)]
|
53
|
+
[category.weight, decidim_html_escape(translated_attribute(category.name, organization))]
|
54
54
|
end
|
55
55
|
|
56
56
|
categories_values = sorted_main_categories.flat_map do |category|
|
57
57
|
sorted_descendant_categories = category.descendants.includes(:subcategories).sort_by do |subcategory|
|
58
|
-
[subcategory.weight, translated_attribute(subcategory.name, organization)]
|
58
|
+
[subcategory.weight, decidim_html_escape(translated_attribute(subcategory.name, organization))]
|
59
59
|
end
|
60
60
|
|
61
61
|
subcategories = sorted_descendant_categories.flat_map do |subcategory|
|
62
|
-
TreePoint.new(subcategory.id.to_s, translated_attribute(subcategory.name, organization))
|
62
|
+
TreePoint.new(subcategory.id.to_s, decidim_html_escape(translated_attribute(subcategory.name, organization)))
|
63
63
|
end
|
64
64
|
|
65
65
|
TreeNode.new(
|
66
|
-
TreePoint.new(category.id.to_s, translated_attribute(category.name, organization)),
|
66
|
+
TreePoint.new(category.id.to_s, decidim_html_escape(translated_attribute(category.name, organization))),
|
67
67
|
subcategories
|
68
68
|
)
|
69
69
|
end
|
@@ -8,28 +8,28 @@ module Decidim
|
|
8
8
|
# for example transform "https://es.lipsum.com/" to "https://es.lipsum.com/?utm_source=localhost&utm_campaign=newsletter_11"
|
9
9
|
# And replace "%{name}" on the subject or content of newsletter to the user Name
|
10
10
|
# for example transform "%{name}" to "User Name"
|
11
|
+
#
|
12
|
+
# @param content [String] - the string to convert
|
13
|
+
# @param user [Decidim::User] - the user to replace
|
14
|
+
# @param id [Integer] - the id of the newsletter to change
|
15
|
+
#
|
16
|
+
# @return [String] - the content converted
|
11
17
|
def parse_interpolations(content, user = nil, id = nil)
|
12
|
-
|
13
|
-
host = user.organization.host.to_s
|
14
|
-
campaign = "newsletter_#{id}"
|
18
|
+
host = user&.organization&.host&.to_s
|
15
19
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
link_replaced = link.first + utm_codes(host, campaign)
|
20
|
-
content = content.gsub(/href\s*=\s*"([^"]*#{link.first})"/, %(href="#{link_replaced}"))
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
if user.present?
|
25
|
-
content.gsub("%{name}", user.name)
|
26
|
-
else
|
27
|
-
content.gsub("%{name}", "")
|
28
|
-
end
|
20
|
+
content = interpret_name(content, user)
|
21
|
+
content = track_newsletter_links(content, id, host)
|
22
|
+
transform_image_urls(content, host)
|
29
23
|
end
|
30
24
|
|
31
25
|
# this method is used to generate the root link on mail with the utm_codes
|
32
26
|
# If the newsletter_id is nil, it returns the root_url
|
27
|
+
#
|
28
|
+
# @param organization [Decidim::Organization] - the Organization of this newsletter
|
29
|
+
# @param newsletter_id [Integer] - the id of the newsletter
|
30
|
+
#
|
31
|
+
# @return [String] - the root_url converted
|
32
|
+
#
|
33
33
|
def custom_url_for_mail_root(organization, newsletter_id = nil)
|
34
34
|
decidim = EngineRouter.new("decidim", {})
|
35
35
|
if newsletter_id.present?
|
@@ -39,10 +39,77 @@ module Decidim
|
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
42
|
+
private
|
43
|
+
|
42
44
|
# Method to specify the utm_codes.
|
43
45
|
# You can change or add utm_codes for track
|
46
|
+
#
|
47
|
+
# @param host [String] - the Decidim::Organization host add to the URL
|
48
|
+
# @param newsletter_id [String] - the ID of the newsletter
|
49
|
+
#
|
50
|
+
# @return [String] - the UTM codes to be added
|
51
|
+
#
|
44
52
|
def utm_codes(host, newsletter_id)
|
45
53
|
"?utm_source=#{host}&utm_campaign=#{newsletter_id}"
|
46
54
|
end
|
55
|
+
|
56
|
+
# Interpret placeholder '%{name}' and replace by the user name
|
57
|
+
# If user is not define, it returns content with blank instead of the placeholder
|
58
|
+
#
|
59
|
+
# @param content [String] - the string to convert
|
60
|
+
# @param user [Decidim::User] - the user to replace
|
61
|
+
#
|
62
|
+
# @return [String] - the content converted
|
63
|
+
#
|
64
|
+
def interpret_name(content, user)
|
65
|
+
return content.gsub("%{name}", "") if user.blank?
|
66
|
+
|
67
|
+
content.gsub("%{name}", user.name)
|
68
|
+
end
|
69
|
+
|
70
|
+
# Find each img HTML tag with relative path in src attribute
|
71
|
+
# For each URL, prepends the decidim.root_url
|
72
|
+
# If host is not defined it returns full content
|
73
|
+
#
|
74
|
+
# @param content [String] - the string to convert
|
75
|
+
# @param host [String] - the Decidim::Organization host to replace
|
76
|
+
#
|
77
|
+
# @return [String] - the content converted
|
78
|
+
#
|
79
|
+
def transform_image_urls(content, host)
|
80
|
+
return content if host.blank?
|
81
|
+
|
82
|
+
content.scan(/src\s*=\s*"([^"]*)"/).each do |src|
|
83
|
+
root_url = decidim.root_url(host: host)[0..-2]
|
84
|
+
src_replaced = "#{root_url}#{src.first}"
|
85
|
+
content = content.gsub(/src\s*=\s*"([^"]*#{src.first})"/, %(src="#{src_replaced}"))
|
86
|
+
end
|
87
|
+
|
88
|
+
content
|
89
|
+
end
|
90
|
+
|
91
|
+
# Add tracking query params to each links
|
92
|
+
#
|
93
|
+
# @param content [String] - the string to convert
|
94
|
+
# @param id [Integer] - the id of the newsletter
|
95
|
+
# @param host [String] - the Decidim::Organization host
|
96
|
+
#
|
97
|
+
# @return [String] - the content converted
|
98
|
+
#
|
99
|
+
def track_newsletter_links(content, id, host)
|
100
|
+
return content unless Decidim.config.track_newsletter_links
|
101
|
+
return content if id.blank?
|
102
|
+
return content if host.blank?
|
103
|
+
|
104
|
+
campaign = "newsletter_#{id}"
|
105
|
+
links = content.scan(/href\s*=\s*"([^"]*)"/)
|
106
|
+
|
107
|
+
links.each do |link|
|
108
|
+
link_replaced = link.first + utm_codes(host, campaign)
|
109
|
+
content = content.gsub(/href\s*=\s*"([^"]*#{link.first})"/, %(href="#{link_replaced}"))
|
110
|
+
end
|
111
|
+
|
112
|
+
content
|
113
|
+
end
|
47
114
|
end
|
48
115
|
end
|
@@ -75,7 +75,7 @@ module Decidim
|
|
75
75
|
# Returns a descriptive title for the resource
|
76
76
|
def resource_title(resource)
|
77
77
|
title = resource.try(:title) || resource.try(:name) || resource.try(:subject) || "#{resource.model_name.human} ##{resource.id}"
|
78
|
-
title =
|
78
|
+
title = decidim_escape_translated(title) if title.is_a?(Hash)
|
79
79
|
title
|
80
80
|
end
|
81
81
|
end
|
@@ -6,6 +6,7 @@ module Decidim
|
|
6
6
|
def self.included(base)
|
7
7
|
base.include ActionView::Helpers::SanitizeHelper
|
8
8
|
base.include ActionView::Helpers::TagHelper
|
9
|
+
base.include Decidim::TranslatableAttributes
|
9
10
|
end
|
10
11
|
|
11
12
|
# Public: It sanitizes a user-inputted string with the
|
@@ -53,6 +54,14 @@ module Decidim
|
|
53
54
|
decidim_html_escape(text).sub(/^javascript:/, "")
|
54
55
|
end
|
55
56
|
|
57
|
+
def decidim_sanitize_translated(text)
|
58
|
+
decidim_sanitize(translated_attribute(text))
|
59
|
+
end
|
60
|
+
|
61
|
+
def decidim_escape_translated(text)
|
62
|
+
decidim_html_escape(translated_attribute(text))
|
63
|
+
end
|
64
|
+
|
56
65
|
private
|
57
66
|
|
58
67
|
# Maintains the paragraphs and lists separations with their bullet points and
|
@@ -14,9 +14,14 @@ module Decidim
|
|
14
14
|
#
|
15
15
|
# Returns a String with the menu tab.
|
16
16
|
def user_profile_tab(text, link, options = {})
|
17
|
-
|
17
|
+
aria = {}
|
18
|
+
cls = %w(tabs-title)
|
19
|
+
if is_active_link?(link, (options[:aria_link_type] || :inclusive))
|
20
|
+
cls << "is-active"
|
21
|
+
aria[:current] = "page"
|
22
|
+
end
|
18
23
|
|
19
|
-
content_tag(:li, class: "
|
24
|
+
content_tag(:li, class: cls.join(" "), aria: aria) do
|
20
25
|
link_to(text, link, options)
|
21
26
|
end
|
22
27
|
end
|