decidim-core 0.27.5 → 0.27.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (106) hide show
  1. checksums.yaml +4 -4
  2. data/app/cells/decidim/activity_cell.rb +2 -2
  3. data/app/cells/decidim/card_cell.rb +2 -2
  4. data/app/cells/decidim/card_m/top.erb +1 -1
  5. data/app/cells/decidim/card_m_cell.rb +1 -1
  6. data/app/cells/decidim/scopes_picker/scope_picker_values.erb +1 -1
  7. data/app/cells/decidim/tags_cell.rb +3 -1
  8. data/app/cells/decidim/user_profile_cell.rb +1 -1
  9. data/app/commands/decidim/create_omniauth_registration.rb +2 -4
  10. data/app/commands/decidim/messaging/reply_to_conversation.rb +3 -0
  11. data/app/commands/decidim/messaging/start_conversation.rb +3 -0
  12. data/app/controllers/concerns/decidim/devise_authentication_methods.rb +36 -0
  13. data/app/controllers/concerns/decidim/paginable.rb +1 -1
  14. data/app/controllers/decidim/devise/omniauth_registrations_controller.rb +1 -22
  15. data/app/controllers/decidim/devise/sessions_controller.rb +1 -24
  16. data/app/controllers/decidim/widgets_controller.rb +6 -0
  17. data/app/events/decidim/welcome_notification_event.rb +6 -9
  18. data/app/helpers/decidim/cells_paginate_helper.rb +1 -1
  19. data/app/helpers/decidim/check_boxes_tree_helper.rb +4 -4
  20. data/app/helpers/decidim/newsletters_helper.rb +83 -16
  21. data/app/helpers/decidim/resource_helper.rb +1 -1
  22. data/app/helpers/decidim/sanitize_helper.rb +9 -0
  23. data/app/helpers/decidim/user_profile_helper.rb +7 -2
  24. data/app/mailers/decidim/messaging/conversation_mailer.rb +3 -72
  25. data/app/models/decidim/push_notification_message.rb +39 -0
  26. data/app/packs/images/decidim/.keep +0 -0
  27. data/app/packs/src/decidim/input_hashtags.js +1 -1
  28. data/app/packs/src/decidim/input_mentions.js +1 -1
  29. data/app/packs/src/decidim/input_multiple_mentions.js +1 -1
  30. data/app/packs/src/decidim/vizzs/index.js +1 -1
  31. data/app/packs/stylesheets/decidim/plugins/leaflet.scss +118 -114
  32. data/app/presenters/decidim/admin_log/oauth_application_resource_presenter.rb +1 -1
  33. data/app/presenters/decidim/notification_to_mailer_presenter.rb +9 -0
  34. data/app/services/decidim/events_manager.rb +6 -0
  35. data/app/services/decidim/push_notification_message_sender.rb +36 -0
  36. data/app/services/decidim/send_push_notification.rb +22 -8
  37. data/app/views/decidim/devise/registrations/new.html.erb +2 -2
  38. data/app/views/decidim/notifications_digest_mailer/_email_content.html.erb +7 -0
  39. data/app/views/decidim/shared/_address_details.html.erb +2 -2
  40. data/app/views/layouts/decidim/_js_configuration.html.erb +1 -0
  41. data/config/locales/ar.yml +4 -2
  42. data/config/locales/bg.yml +74 -0
  43. data/config/locales/ca.yml +22 -22
  44. data/config/locales/de.yml +25 -25
  45. data/config/locales/el.yml +1 -3
  46. data/config/locales/es-MX.yml +1 -1
  47. data/config/locales/es-PY.yml +1 -1
  48. data/config/locales/es.yml +20 -20
  49. data/config/locales/eu.yml +11 -2
  50. data/config/locales/fi.yml +3 -3
  51. data/config/locales/fr-CA.yml +2 -2
  52. data/config/locales/fr.yml +2 -2
  53. data/config/locales/gl.yml +3 -0
  54. data/config/locales/he-IL.yml +1 -0
  55. data/config/locales/hu.yml +41 -8
  56. data/config/locales/it.yml +1 -3
  57. data/config/locales/ja.yml +3 -2
  58. data/config/locales/lb.yml +1 -3
  59. data/config/locales/lt.yml +0 -3
  60. data/config/locales/no.yml +1 -3
  61. data/config/locales/pl.yml +137 -1
  62. data/config/locales/pt-BR.yml +113 -21
  63. data/config/locales/pt.yml +1 -3
  64. data/config/locales/ro-RO.yml +0 -3
  65. data/config/locales/ru.yml +9 -0
  66. data/config/locales/sk.yml +2 -0
  67. data/config/locales/sv.yml +22 -2
  68. data/config/locales/tr-TR.yml +1 -3
  69. data/config/locales/uk.yml +14 -0
  70. data/config/locales/zh-CN.yml +0 -3
  71. data/config/locales/zh-TW.yml +0 -3
  72. data/decidim-core.gemspec +78 -0
  73. data/lib/decidim/acts_as_tree.rb +14 -1
  74. data/lib/decidim/asset_router/storage.rb +4 -0
  75. data/lib/decidim/attribute_encryptor.rb +6 -4
  76. data/lib/decidim/core/engine.rb +7 -3
  77. data/lib/decidim/core/test/factories.rb +308 -95
  78. data/lib/decidim/core/test/shared_examples/amendable/amendment_created_event_examples.rb +6 -26
  79. data/lib/decidim/core/test/shared_examples/amendable/amendment_promoted_event_examples.rb +8 -26
  80. data/lib/decidim/core/test/shared_examples/comments_examples.rb +32 -0
  81. data/lib/decidim/core/test/shared_examples/embed_resource_examples.rb +187 -11
  82. data/lib/decidim/core/test/shared_examples/has_attachment_collections.rb +8 -6
  83. data/lib/decidim/core/test/shared_examples/has_attachments.rb +4 -4
  84. data/lib/decidim/core/test/shared_examples/has_category.rb +27 -0
  85. data/lib/decidim/core/test/shared_examples/has_reference.rb +1 -1
  86. data/lib/decidim/core/test/shared_examples/has_space_in_mcell_examples.rb +1 -2
  87. data/lib/decidim/core/test/shared_examples/resource_endorsed_event_examples.rb +6 -3
  88. data/lib/decidim/core/test/shared_examples/resource_locator_presenter_examples.rb +134 -0
  89. data/lib/decidim/core/test/shared_examples/searchable_results_examples.rb +1 -1
  90. data/lib/decidim/core/test/shared_examples/simple_event.rb +50 -2
  91. data/lib/decidim/core/test.rb +1 -0
  92. data/lib/decidim/core/version.rb +1 -1
  93. data/lib/decidim/core.rb +1 -0
  94. data/lib/decidim/engine_router.rb +17 -4
  95. data/lib/decidim/events/base_event.rb +5 -2
  96. data/lib/decidim/events/simple_event.rb +3 -17
  97. data/lib/decidim/has_category.rb +1 -1
  98. data/lib/decidim/has_conversations.rb +91 -0
  99. data/lib/decidim/participable.rb +17 -0
  100. data/lib/decidim/view_model.rb +1 -0
  101. data/lib/decidim/webpacker/webpack/.modernizrrc +9 -0
  102. data/lib/premailer/adapter/decidim.rb +5 -4
  103. data/lib/tasks/decidim_reminders_tasks.rake +1 -0
  104. data/lib/tasks/upgrade/decidim_fix_categorization.rake +15 -0
  105. metadata +31 -30
  106. data/config/environment.rb +0 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c9b09dc6caf48cd1318acfd39efaef6e9aa95ed3527ff40c3974a56f409eeff7
4
- data.tar.gz: bb6ca8ea6d9b57a37d6793757cd8a12bbcffdf63afd27924216f67af1d8acb14
3
+ metadata.gz: 99119ce695e1aa34d4a744deca10b822209b52253058e77548a6399cd78f0069
4
+ data.tar.gz: '052746495077e884e4cb8e5bc33c8bcb6af257efbee57b385b39f62404530fd5'
5
5
  SHA512:
6
- metadata.gz: 4003252d8eeae3f86cb4056380f4fb7aefe8a8e97f3935e97a970513ccdd05e9d6b9ca8658b56147b7bff0e306608472e656db871eae5bbb50ab9cfc1e629d4b
7
- data.tar.gz: ce5aec4bd84ee34b87b5b7cc3f1afb08a1e6bcc3c34ff5cf1afa87d3ded13fe012f29a6a882fead250413f64db4a9b643770ca2c0e643e186ea51bb57a2e6c87
6
+ metadata.gz: e5b7a3d7779697415e7ec9badd7d4d00bd408a1f42e7c667f01b797558ba22524231273b94f3f6beeb644f7aee8692bd5d2d580a7493c84dfaa5eb563241bc58
7
+ data.tar.gz: 193b200909cc1fa784ccad5583b3c9593b8e6a9be31c10ab03c90ee9153075ac0d168566e7fe275bb9140c1bc53a8a42e58f84ffc9b852fe91269deef496d5a3
@@ -38,9 +38,9 @@ module Decidim
38
38
 
39
39
  case resource_title
40
40
  when String
41
- resource_title
41
+ decidim_html_escape(resource_title)
42
42
  when Hash
43
- translated_attribute(resource_title)
43
+ decidim_escape_translated(resource_title)
44
44
  end
45
45
  end
46
46
 
@@ -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>&nbsp;<%= link_to translated_attribute(model.participatory_space.title), Decidim::ResourceLocatorPresenter.new(model.participatory_space).path, class: "card__link text-ellipsis" %>
4
+ <span class="muted"><%= searchable_resource_human_name(model.participatory_space.class, count: 1) %>:</span>&nbsp;<%= 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>
@@ -57,7 +57,7 @@ module Decidim
57
57
  end
58
58
 
59
59
  def title
60
- decidim_html_escape(translated_attribute(model.title))
60
+ decidim_escape_translated(model.title)
61
61
  end
62
62
 
63
63
  def description
@@ -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
@@ -29,7 +29,7 @@ module Decidim
29
29
  delegate :badge, to: :presented_resource
30
30
 
31
31
  def description
32
- html_truncate(decidim_html_escape(user.about.to_s), length: 100)
32
+ html_truncate(decidim_escape_translated(user.about), length: 100)
33
33
  end
34
34
 
35
35
  def avatar
@@ -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 = generated_password
67
- @user.password_confirmation = generated_password
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
@@ -19,7 +19,7 @@ module Decidim
19
19
 
20
20
  def per_page
21
21
  if OPTIONS.include?(params[:per_page])
22
- params[:per_page]
22
+ params[:per_page].to_i
23
23
  elsif params[:per_page]
24
24
  sorted = OPTIONS.sort
25
25
  params[:per_page].to_i.clamp(sorted.first, sorted.last)
@@ -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
@@ -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
- Mustache.render(
50
- template.to_s,
51
- organization: organization.name,
52
- name: user.name,
53
- help_url: url_helpers.pages_url(host: organization.host),
54
- badges_url: url_helpers.gamification_badges_url(host: organization.host)
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
@@ -14,7 +14,7 @@ module Decidim
14
14
  end
15
15
 
16
16
  def per_page
17
- params[:per_page] || Decidim::Paginable::OPTIONS.first
17
+ params[:per_page].to_i || Decidim::Paginable::OPTIONS.first
18
18
  end
19
19
  end
20
20
  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
- if Decidim.config.track_newsletter_links && id.present? && user.present?
13
- host = user.organization.host.to_s
14
- campaign = "newsletter_#{id}"
18
+ host = user&.organization&.host&.to_s
15
19
 
16
- links = content.scan(/href\s*=\s*"([^"]*)"/)
17
-
18
- links.each do |link|
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 = translated_attribute(title) if title.is_a?(Hash)
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
- active = is_active_link?(link, (options[:aria_link_type] || :inclusive))
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: "tabs-title#{active ? " is-active" : nil}") do
24
+ content_tag(:li, class: cls.join(" "), aria: aria) do
20
25
  link_to(text, link, options)
21
26
  end
22
27
  end
@@ -5,74 +5,12 @@ module Decidim
5
5
  # A custom mailer for sending notifications to users when they receive
6
6
  # private messages
7
7
  class ConversationMailer < Decidim::ApplicationMailer
8
- def new_conversation(originator, user, conversation)
9
- notification_mail(
10
- from: originator,
11
- to: user,
12
- conversation: conversation,
13
- message: conversation.messages.first.body,
14
- action: "new_conversation"
15
- )
16
- end
17
-
18
- def new_group_conversation(originator, manager, conversation, group)
19
- notification_mail(
20
- from: originator,
21
- to: manager,
22
- conversation: conversation,
23
- message: conversation.messages.first.body,
24
- action: "new_group_conversation",
25
- third_party: group
26
- )
27
- end
28
-
29
- def comanagers_new_conversation(group, user, conversation, manager)
30
- notification_mail(
31
- from: group,
32
- to: user,
33
- conversation: conversation,
34
- message: conversation.messages.first.body,
35
- action: "comanagers_new_conversation",
36
- third_party: manager
37
- )
38
- end
39
-
40
- def new_message(sender, user, conversation, message)
41
- notification_mail(
42
- from: sender,
43
- to: user,
44
- conversation: conversation,
45
- message: message.body,
46
- action: "new_message"
47
- )
48
- end
49
-
50
- def new_group_message(sender, user, conversation, message, group)
51
- notification_mail(
52
- from: sender,
53
- to: user,
54
- conversation: conversation,
55
- message: message.body,
56
- action: "new_group_message",
57
- third_party: group
58
- )
59
- end
60
-
61
- def comanagers_new_message(sender, user, conversation, message, manager)
62
- notification_mail(
63
- from: sender,
64
- to: user,
65
- conversation: conversation,
66
- message: message.body,
67
- action: "comanagers_new_message",
68
- third_party: manager
69
- )
70
- end
8
+ include HasConversations
71
9
 
72
10
  private
73
11
 
74
12
  # rubocop:disable Metrics/ParameterLists
75
- def notification_mail(from:, to:, conversation:, action:, message: nil, third_party: nil)
13
+ def send_notification(from:, to:, conversation:, action:, message: nil, third_party: nil)
76
14
  with_user(to) do
77
15
  @organization = to.organization
78
16
  @conversation = conversation
@@ -81,14 +19,7 @@ module Decidim
81
19
  @third_party = third_party
82
20
  @message = message
83
21
  @host = @organization.host
84
-
85
- subject = I18n.t(
86
- "conversation_mailer.#{action}.subject",
87
- scope: "decidim.messaging",
88
- sender: @sender.name,
89
- manager: @third_party&.name,
90
- group: @third_party&.name
91
- )
22
+ subject = get_subject(action: action, sender: @sender, third_party: @third_party)
92
23
 
93
24
  mail(to: to.email, subject: subject)
94
25
  end