decidim-core 0.25.2 → 0.26.0.rc1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of decidim-core might be problematic. Click here for more details.

Files changed (146) hide show
  1. checksums.yaml +4 -4
  2. data/app/cells/decidim/activity_cell.rb +2 -1
  3. data/app/cells/decidim/author/flag_user.erb +1 -1
  4. data/app/cells/decidim/author/profile_inline.erb +1 -1
  5. data/app/cells/decidim/author/withdraw.erb +2 -2
  6. data/app/cells/decidim/author_cell.rb +32 -0
  7. data/app/cells/decidim/card_m_cell.rb +1 -1
  8. data/app/cells/decidim/content_blocks/cta_cell.rb +1 -1
  9. data/app/cells/decidim/content_blocks/hero_cell.rb +1 -1
  10. data/app/cells/decidim/content_blocks/highlighted_content_banner/show.erb +1 -1
  11. data/app/cells/decidim/content_blocks/last_activity_cell.rb +1 -1
  12. data/app/cells/decidim/content_blocks/stats_cell.rb +12 -0
  13. data/app/cells/decidim/endorsers_list_cell.rb +3 -1
  14. data/app/cells/decidim/flag_modal/flag_user.erb +2 -2
  15. data/app/cells/decidim/flag_modal/show.erb +2 -2
  16. data/app/cells/decidim/flag_modal_cell.rb +10 -0
  17. data/app/cells/decidim/notification/show.erb +31 -0
  18. data/app/cells/decidim/notification_cell.rb +20 -0
  19. data/app/cells/decidim/notifications/show.erb +1 -24
  20. data/app/cells/decidim/notifications_cell.rb +0 -1
  21. data/app/cells/decidim/user_conversation/conversation_header.erb +1 -1
  22. data/app/cells/decidim/user_conversation/show.erb +4 -2
  23. data/app/cells/decidim/user_conversations/conversation_item.erb +1 -1
  24. data/app/commands/decidim/create_editor_image.rb +41 -0
  25. data/app/controllers/decidim/cookie_policy_controller.rb +2 -0
  26. data/app/controllers/decidim/editor_images_controller.rb +47 -0
  27. data/app/controllers/decidim/user_activities_controller.rb +2 -1
  28. data/app/forms/decidim/editor_image_form.rb +16 -0
  29. data/app/helpers/decidim/amendments_helper.rb +1 -1
  30. data/app/helpers/decidim/application_helper.rb +2 -2
  31. data/app/helpers/decidim/messaging/conversation_helper.rb +32 -3
  32. data/app/helpers/decidim/resource_versions_helper.rb +1 -1
  33. data/app/helpers/decidim/sanitize_helper.rb +65 -0
  34. data/app/models/decidim/editor_image.rb +14 -0
  35. data/app/models/decidim/messaging/conversation.rb +9 -0
  36. data/app/models/decidim/participatory_space_private_user.rb +16 -0
  37. data/app/models/decidim/user.rb +3 -3
  38. data/app/models/decidim/user_group.rb +40 -0
  39. data/app/packs/entrypoints/decidim_core.js +1 -0
  40. data/app/packs/src/decidim/dialog_mode.js +143 -0
  41. data/app/packs/src/decidim/dialog_mode.test.js +168 -0
  42. data/app/packs/src/decidim/editor.js +56 -14
  43. data/app/packs/src/decidim/form_attachments.js +5 -0
  44. data/app/packs/src/decidim/index.js +4 -0
  45. data/app/packs/src/decidim/vendor/image-resize.min.js +3 -0
  46. data/app/packs/src/decidim/vendor/image-upload.min.js +8 -0
  47. data/app/packs/stylesheets/decidim/extras/_extras.scss +0 -1
  48. data/app/packs/stylesheets/decidim/extras/_quill.scss +7 -0
  49. data/app/packs/stylesheets/decidim/modules/_buttons.scss +11 -4
  50. data/app/packs/stylesheets/decidim/modules/_cards.scss +4 -0
  51. data/app/packs/stylesheets/decidim/modules/_layout.scss +1 -1
  52. data/app/presenters/decidim/nil_presenter.rb +2 -2
  53. data/app/presenters/decidim/notification_presenter.rb +25 -0
  54. data/app/presenters/decidim/official_author_presenter.rb +1 -1
  55. data/app/presenters/decidim/validation_errors_presenter.rb +27 -0
  56. data/app/queries/decidim/similar_emendations.rb +1 -1
  57. data/app/resolvers/decidim/core/metric_resolver.rb +1 -1
  58. data/app/services/decidim/activity_search.rb +2 -2
  59. data/app/services/decidim/email_notification_generator.rb +4 -1
  60. data/app/services/decidim/html_truncation.rb +130 -0
  61. data/app/services/decidim/open_data_exporter.rb +29 -5
  62. data/app/services/decidim/resource_search.rb +1 -1
  63. data/app/uploaders/decidim/editor_image_uploader.rb +6 -0
  64. data/app/validators/password_validator.rb +123 -0
  65. data/app/views/decidim/account/_password_fields.html.erb +1 -1
  66. data/app/views/decidim/devise/passwords/edit.html.erb +1 -1
  67. data/app/views/decidim/devise/registrations/new.html.erb +1 -1
  68. data/app/views/decidim/devise/shared/_omniauth_buttons_mini.html.erb +6 -4
  69. data/app/views/decidim/messaging/conversations/_conversation.html.erb +3 -3
  70. data/app/views/decidim/messaging/conversations/_messages.html.erb +8 -2
  71. data/app/views/decidim/messaging/conversations/_show.html.erb +10 -12
  72. data/app/views/decidim/messaging/conversations/show.html.erb +4 -2
  73. data/app/views/decidim/newsletters/show.html.erb +1 -1
  74. data/app/views/decidim/notification_mailer/event_received.html.erb +17 -0
  75. data/app/views/decidim/pages/_tabbed.html.erb +1 -1
  76. data/app/views/decidim/searches/_filters_small_view.html.erb +3 -3
  77. data/app/views/decidim/shared/_login_modal.html.erb +5 -5
  78. data/app/views/decidim/shared/_orders.html.erb +1 -1
  79. data/app/views/decidim/shared/_results_per_page.html.erb +1 -1
  80. data/app/views/decidim/shared/participatory_space_filters/_filters_small_view.html.erb +3 -3
  81. data/app/views/layouts/decidim/_application.html.erb +1 -12
  82. data/app/views/layouts/decidim/_head.html.erb +4 -0
  83. data/app/views/layouts/decidim/_language_chooser.html.erb +1 -1
  84. data/app/views/layouts/decidim/_meta_tags_config.html.erb +11 -0
  85. data/app/views/layouts/decidim/_wrapper.html.erb +1 -1
  86. data/config/brakeman.ignore +149 -0
  87. data/config/initializers/devise.rb +1 -1
  88. data/config/initializers/rack_attack.rb +23 -21
  89. data/config/locales/ca.yml +2 -0
  90. data/config/locales/cs.yml +60 -0
  91. data/config/locales/en.yml +45 -0
  92. data/config/locales/es.yml +45 -0
  93. data/config/locales/eu.yml +5 -0
  94. data/config/locales/fi-plain.yml +6 -0
  95. data/config/locales/fi.yml +45 -0
  96. data/config/locales/fr-CA.yml +38 -0
  97. data/config/locales/fr.yml +44 -6
  98. data/config/locales/gl.yml +5 -0
  99. data/config/locales/it.yml +11 -0
  100. data/config/locales/ja.yml +72 -36
  101. data/config/locales/lb-LU.yml +1354 -0
  102. data/config/locales/lb.yml +1 -1
  103. data/config/locales/nl.yml +54 -0
  104. data/config/locales/pl.yml +5 -5
  105. data/config/locales/pt-BR.yml +1 -1
  106. data/config/locales/ro-RO.yml +8 -0
  107. data/config/locales/sv.yml +5 -0
  108. data/config/locales/val-ES.yml +1 -0
  109. data/config/routes.rb +2 -0
  110. data/db/migrate/20210730112319_create_decidim_editor_images.rb +12 -0
  111. data/db/migrate/20211126183540_add_timestamps_to_content_blocks.rb +14 -0
  112. data/db/seeds.rb +16 -14
  113. data/lib/decidim/api/functions/user_entity_list.rb +1 -0
  114. data/lib/decidim/api/input_sorts/component_input_sort.rb +1 -1
  115. data/lib/decidim/common_passwords.rb +56 -0
  116. data/lib/decidim/content_parsers/inline_images_parser.rb +68 -0
  117. data/lib/decidim/content_parsers.rb +1 -0
  118. data/lib/decidim/content_renderers/link_renderer.rb +85 -1
  119. data/lib/decidim/content_renderers/user_group_renderer.rb +1 -1
  120. data/lib/decidim/content_renderers/user_renderer.rb +1 -1
  121. data/lib/decidim/core/engine.rb +3 -12
  122. data/lib/decidim/core/test/factories.rb +7 -1
  123. data/lib/decidim/core/test/shared_examples/translated_event_examples.rb +131 -0
  124. data/lib/decidim/core/test.rb +1 -0
  125. data/lib/decidim/core/version.rb +1 -1
  126. data/lib/decidim/core.rb +22 -5
  127. data/lib/decidim/db/common-passwords.txt +128420 -0
  128. data/lib/decidim/etherpad/pad.rb +48 -0
  129. data/lib/decidim/etherpad.rb +7 -0
  130. data/lib/decidim/events/base_event.rb +18 -0
  131. data/lib/decidim/events/machine_translated_event.rb +36 -0
  132. data/lib/decidim/events/user_group_event.rb +1 -3
  133. data/lib/decidim/events.rb +1 -0
  134. data/lib/decidim/exporters/csv.rb +7 -7
  135. data/lib/decidim/faker/localized.rb +15 -6
  136. data/lib/decidim/form_builder.rb +14 -4
  137. data/lib/decidim/has_attachments.rb +11 -4
  138. data/lib/decidim/importers/import_manifest.rb +103 -3
  139. data/lib/decidim/paddable.rb +1 -9
  140. data/lib/decidim/searchable.rb +2 -2
  141. data/lib/decidim/settings_manifest.rb +2 -0
  142. data/lib/decidim/translatable_attributes.rb +6 -6
  143. data/lib/decidim/view_model.rb +10 -0
  144. data/lib/tasks/decidim_active_storage_migration_tasks.rake +68 -0
  145. metadata +56 -65
  146. data/app/packs/stylesheets/decidim/extras/_social_icons_mini.scss +0 -11
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 874945a9b1099eec0e81862510812650bdaef2233da2ab8717150841dc242885
4
- data.tar.gz: 4f951811ef9152312c943efc46c1da849f3686f6af331ebc5b2dfb959b275916
3
+ metadata.gz: dac5187d40c4a753efdf1ca3e005b5a0d6561fcde905fb50bbf054fac2eca159
4
+ data.tar.gz: 6ed72398e69f803c6ab3b328ff9b26ec217769a2878349c00fbadf76b65e120e
5
5
  SHA512:
6
- metadata.gz: 472a3e9b094066455486eb1d43b504009e8903772fce927950f091b433ff83bc8471847fcb919a6996a2ffb688159f5b4cd5c2611763511fedfc96db045505f3
7
- data.tar.gz: 27d8a8201a9add23103bdc8c6b4173108cb16873cc6b1727be0a487fd88735c871bf9fce41771e1086e40a99df013b305ff04d165b3651d7896fa0e0154df09b
6
+ metadata.gz: 532bcf1725b00692cf50880c865cd74b5e81f13870f65db9d9b61c227fb78b997ad5b1eff984f041a900b9e117a29d3c62d72097506ddd15bd40320c7c839dc2
7
+ data.tar.gz: dfe236abe5ba215792e259e1e93d54a82c8ac60120b2f4af166e1e86343aefc9cf3ba7eb743987ec65b96202accd6c8cf53d8aebc0f4fd9ac3e5d028f4f12ee0
@@ -92,10 +92,11 @@ module Decidim
92
92
 
93
93
  def cache_hash
94
94
  hash = []
95
+ hash << I18n.locale.to_s
95
96
  hash << model.class.name.underscore
96
97
  hash << model.cache_key_with_version
97
98
 
98
- hash.join("/")
99
+ hash.join(Decidim.cache_key_separator)
99
100
  end
100
101
 
101
102
  private
@@ -1,5 +1,5 @@
1
1
  <% if user_flaggable? && model.try(:id) != current_user.try(:id) %>
2
- <button type="button" class="link-alt" data-open="<%= current_user.present? ? "flagUserModal" : "loginModal" %>" title="<%= t("report", scope: "decidim.proposals.proposals.show") %>" aria-controls="<%= current_user.present? ? "flagUserModal" : "loginModal" %>" aria-haspopup="true" tabindex="0">
2
+ <button type="button" class="link-alt" data-open="<%= current_user.present? ? "flagUserModal" : "loginModal" %>" title="<%= t("report", scope: "decidim.proposals.proposals.show") %>" aria-controls="<%= current_user.present? ? "flagUserModal" : "loginModal" %>" aria-haspopup="dialog" tabindex="0">
3
3
  <%= icon "flag", aria_hidden: true, class: "icon--small", role: "img", "aria-hidden": true %>
4
4
  <span class="show-for-sr">
5
5
  <%= t("report", scope: "decidim.proposals.proposals.show") %>
@@ -1,5 +1,5 @@
1
1
  <span class="author__avatar">
2
- <%= image_tag model.avatar_url, alt: t("decidim.author.avatar", name: decidim_sanitize(author_name)) %>
2
+ <%= image_tag model.avatar_url(:thumb), alt: t("decidim.author.avatar", name: decidim_sanitize(author_name)) %>
3
3
  </span>
4
4
 
5
5
  <% if model.deleted? %>
@@ -1,6 +1,6 @@
1
1
  <% if withdrawable? %>
2
- <%= action_authorized_link_to :withdraw, withdraw_path, method: :put, class: "title-action__action button small hollow", title: t("withdraw_btn_hint", scope: "decidim.proposals.proposals.show"), data: { confirm: t("withdraw_confirmation_html", scope: "decidim.proposals.proposals.show") } do %>
3
- <%= t("withdraw_proposal", scope: "decidim.proposals.proposals.show") %>
2
+ <%= action_authorized_link_to :withdraw, withdraw_path, method: :put, class: "title-action__action button small hollow", title: t("withdraw_btn_hint", scope: resource_i18n_scope ), data: { confirm: t("withdraw_confirmation_html", scope: resource_i18n_scope ) } do %>
3
+ <%= t("withdraw_#{resource_name}", scope: resource_i18n_scope) %>
4
4
  <%= icon "x", role: "img", "aria-hidden": true %>
5
5
  <% end %>
6
6
  <% end %>
@@ -55,8 +55,28 @@ module Decidim
55
55
  render
56
56
  end
57
57
 
58
+ def perform_caching?
59
+ true
60
+ end
61
+
58
62
  private
59
63
 
64
+ def cache_hash
65
+ hash = []
66
+
67
+ hash.push(I18n.locale)
68
+ hash.push(model.cache_key_with_version) if model.respond_to?(:cache_key_with_version)
69
+ hash.push(current_user.try(:id))
70
+ hash.push(current_user.present?)
71
+ hash.push(commentable?)
72
+ hash.push(endorsable?)
73
+ hash.push(actionable?)
74
+ hash.push(withdrawable?)
75
+ hash.push(flaggable?)
76
+ hash.push(profile_path?)
77
+ hash.join(Decidim.cache_key_separator)
78
+ end
79
+
60
80
  def from_context_path
61
81
  resource_locator(from_context).path
62
82
  end
@@ -111,5 +131,17 @@ module Decidim
111
131
  def raw_model
112
132
  model.try(:__getobj__) || model
113
133
  end
134
+
135
+ def resource_i18n_scope
136
+ @resource_i18n_scope ||= [
137
+ from_context.class.name.deconstantize.underscore.gsub("/", "."),
138
+ resource_name.pluralize,
139
+ :show
140
+ ].join(".")
141
+ end
142
+
143
+ def resource_name
144
+ @resource_name ||= from_context.class.name.demodulize.underscore
145
+ end
114
146
  end
115
147
  end
@@ -64,7 +64,7 @@ module Decidim
64
64
  attribute = model.try(:short_description) || model.try(:body) || model.description
65
65
  text = translated_attribute(attribute)
66
66
 
67
- decidim_sanitize(html_truncate(text, length: 100))
67
+ decidim_sanitize_editor(html_truncate(text, length: 100))
68
68
  end
69
69
 
70
70
  def has_authors?
@@ -16,7 +16,7 @@ module Decidim
16
16
  end
17
17
 
18
18
  def translated_description
19
- @translated_description ||= decidim_sanitize(translated_attribute(model.settings.description))
19
+ @translated_description ||= decidim_sanitize_editor(translated_attribute(model.settings.description))
20
20
  end
21
21
 
22
22
  def button_url
@@ -30,7 +30,7 @@ module Decidim
30
30
  hash << current_organization.cache_key_with_version
31
31
  hash << I18n.locale.to_s
32
32
 
33
- hash.join("/")
33
+ hash.join(Decidim.cache_key_separator)
34
34
  end
35
35
  end
36
36
  end
@@ -7,7 +7,7 @@
7
7
  <%= translated_attribute current_organization.highlighted_content_banner_title %>
8
8
  </h1>
9
9
  <span class="text-highlight">
10
- <%= decidim_sanitize translated_attribute current_organization.highlighted_content_banner_short_description %>
10
+ <%= decidim_sanitize_editor translated_attribute current_organization.highlighted_content_banner_short_description %>
11
11
  </span>
12
12
  </div>
13
13
  <div class="columns large-2">
@@ -52,7 +52,7 @@ module Decidim
52
52
  hash << Digest::MD5.hexdigest(valid_activities.map(&:cache_key_with_version).to_s)
53
53
  hash << I18n.locale.to_s
54
54
 
55
- hash.join("/")
55
+ hash.join(Decidim.cache_key_separator)
56
56
  end
57
57
 
58
58
  def activities
@@ -3,9 +3,21 @@
3
3
  module Decidim
4
4
  module ContentBlocks
5
5
  class StatsCell < Decidim::ViewModel
6
+ cache :show, expires_in: 10.minutes, if: :perform_caching? do
7
+ cache_hash
8
+ end
9
+
6
10
  def stats
7
11
  @stats ||= HomeStatsPresenter.new(organization: current_organization)
8
12
  end
13
+
14
+ private
15
+
16
+ def cache_hash
17
+ hash = []
18
+ hash.push(I18n.locale)
19
+ hash.join(Decidim.cache_key_separator)
20
+ end
9
21
  end
10
22
  end
11
23
  end
@@ -23,7 +23,9 @@ module Decidim
23
23
  #
24
24
  # Returns an Array of presented Users/UserGroups
25
25
  def endorsers
26
- @endorsers ||= model.endorsements.for_listing.map { |identity| present(identity.normalized_author) }
26
+ @endorsers ||= model.endorsements.for_listing
27
+ .includes(:author, :user_group)
28
+ .map { |identity| present(identity.normalized_author) }
27
29
  end
28
30
  end
29
31
  end
@@ -1,6 +1,6 @@
1
- <div class="reveal flag-modal" id="flagUserModal" data-reveal>
1
+ <div class="reveal flag-modal" id="flagUserModal" data-reveal role="dialog" aria-modal="true" aria-labelledby="flagUserModal-label">
2
2
  <div class="reveal__header">
3
- <h3 class="reveal__title"><%= t("decidim.shared.flag_user_modal.title") %></h3>
3
+ <h3 id="flagUserModal-label" class="reveal__title"><%= t("decidim.shared.flag_user_modal.title") %></h3>
4
4
  <button class="close-button" data-close aria-label="<%= t("decidim.shared.flag_user_modal.close") %>" type="button">
5
5
  <span aria-hidden="true">&times;</span>
6
6
  </button>
@@ -1,6 +1,6 @@
1
- <div class="reveal flag-modal" id="<%= modal_id %>" data-reveal>
1
+ <div class="reveal flag-modal" id="<%= modal_id %>" data-reveal role="dialog" aria-modal="true" aria-labelledby="<%= modal_id %>-label">
2
2
  <div class="reveal__header">
3
- <h3 class="reveal__title"><%= t("decidim.shared.flag_modal.title") %></h3>
3
+ <h3 id="<%= modal_id %>-label" class="reveal__title"><%= t("decidim.shared.flag_modal.title") %></h3>
4
4
  <button class="close-button" data-close aria-label="<%= t("decidim.shared.flag_modal.close") %>" type="button">
5
5
  <span aria-hidden="true">&times;</span>
6
6
  </button>
@@ -8,6 +8,16 @@ module Decidim
8
8
  render
9
9
  end
10
10
 
11
+ def cache_hash
12
+ hash = []
13
+ hash.push(I18n.locale)
14
+ hash.push(current_user.try(:id))
15
+ hash.push(model.reported_by?(current_user) ? 1 : 0)
16
+ hash.push(model.class.name.gsub("::", ":"))
17
+ hash.push(model.id)
18
+ hash.join(Decidim.cache_key_separator)
19
+ end
20
+
11
21
  private
12
22
 
13
23
  def user_report_form
@@ -0,0 +1,31 @@
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
+ <span>
16
+ <%= notification.event_class_instance.notification_title %>
17
+ </span>
18
+ <% if notification.display_resource_text? %>
19
+ <p>
20
+ <em><%= notification.resource_text %></em>
21
+ </p>
22
+ <% end %>
23
+ </div>
24
+ <div class="right center mr-s">
25
+ <%= link_to model, remote: true, method: :delete, class: "mark-as-read-button" do %>
26
+ <%= icon "circle-x", class: "card__link", aria_label: t("mark_as_read", scope: "layouts.decidim.notifications_dashboard"), role: "img" %>
27
+ <% end %>
28
+ </div>
29
+ </li>
30
+ </ul>
31
+ </div>
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ # This cell renders a notification from a notifications collection
5
+
6
+ class NotificationCell < Decidim::ViewModel
7
+ include Decidim::IconHelper
8
+ include Decidim::Core::Engine.routes.url_helpers
9
+
10
+ def show
11
+ render :show
12
+ end
13
+
14
+ private
15
+
16
+ def notification
17
+ @notification ||= Decidim::NotificationPresenter.new(model)
18
+ end
19
+ end
20
+ end
@@ -17,30 +17,7 @@
17
17
  </div>
18
18
 
19
19
  <% notifications.select(&:resource).each do |notification| %>
20
- <div class="card card--widget">
21
- <ul class="card-data">
22
- <li class="card-data__item">
23
- <div class="card__link text-center">
24
- <%= resource_icon notification.resource, class: "icon--large" %>
25
- <span class="text-medium mt-xs"><%= l notification.created_at, format: :day_of_week_long %></span>
26
- </div>
27
- </li>
28
- <li class="card-data__item card-data__item--expand absolutes">
29
- <div class="mr-s">
30
- <span class="text-small"><%= notification.event_class.constantize.model_name.human %></span>
31
- <br>
32
- <span>
33
- <%= notification.event_class_instance.notification_title %>
34
- </span>
35
- </div>
36
- <div class="right center mr-s">
37
- <%= link_to notification, remote: true, method: :delete, class: "mark-as-read-button" do %>
38
- <%= icon "circle-x", class: "card__link", aria_label: t("mark_as_read", scope: "layouts.decidim.notifications_dashboard"), role: "img" %>
39
- <% end %>
40
- </div>
41
- </li>
42
- </ul>
43
- </div>
20
+ <%= cell("decidim/notification", notification) %>
44
21
  <% end %>
45
22
  </div>
46
23
 
@@ -3,7 +3,6 @@
3
3
  module Decidim
4
4
  class NotificationsCell < Decidim::ViewModel
5
5
  include Decidim::CellsPaginateHelper
6
- include Decidim::IconHelper
7
6
  include Decidim::Core::Engine.routes.url_helpers
8
7
 
9
8
  helper_method :notifications
@@ -9,6 +9,6 @@
9
9
  <% end %>
10
10
 
11
11
  <div class="ml-s">
12
- <%= t("decidim.user_conversations.show.title", usernames: interlocutors_names) %>
12
+ <%= t("decidim.user_conversations.show.title", usernames: interlocutors_names).html_safe %>
13
13
  </div>
14
14
  </div>
@@ -10,10 +10,12 @@
10
10
  <% end %>
11
11
  </div>
12
12
 
13
- <% if conversation.accept_user?(user) %>
13
+ <% if conversation.with_deleted_users?(user) %>
14
+ <div class="callout warning margin-top-2"><%= t "decidim.user_conversations.show.deleted_accounts" %></div>
15
+ <% elsif conversation.accept_user?(user) %>
14
16
  <%= render view: :reply, locals: { title: t("decidim.user_conversations.reply.title_reply") } %>
15
17
  <% else %>
16
- <em><%= t "decidim.user_conversations.show.not_allowed" %></em>
18
+ <div class="callout warning margin-top-2"><%= t "decidim.user_conversations.show.not_allowed" %></div>
17
19
  <% end %>
18
20
  </div>
19
21
  </div>
@@ -10,7 +10,7 @@
10
10
  </li>
11
11
  <li class="card-data__item card--list__item card-data__item--expand absolutes">
12
12
  <div class="mr-s">
13
- <%= t("decidim.user_conversations.index.from") %>: <strong><%= conversation_interlocutors(conversation) %></strong>
13
+ <%= t("decidim.user_conversations.index.from") %>: <strong><%= conversation_interlocutors(conversation).html_safe %></strong>
14
14
  <br>
15
15
  <span class="muted">
16
16
  <%= truncate conversation.last_message.body, length: 150 %>
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ # A command with all the business logic to create an editor image.
5
+ class CreateEditorImage < Rectify::Command
6
+ # Public: Initializes the command.
7
+ #
8
+ # form - A form object with the params.
9
+ def initialize(form)
10
+ @form = form
11
+ end
12
+
13
+ # Executes the command. Broadcasts these events:
14
+ #
15
+ # - :ok when everything is valid.
16
+ # - :invalid if the form wasn't valid and we couldn't proceed.
17
+ #
18
+ # Returns nothing.
19
+ def call
20
+ return broadcast(:invalid) if form.invalid?
21
+
22
+ transaction do
23
+ create_editor_image
24
+ end
25
+
26
+ broadcast(:ok, @editor_image)
27
+ end
28
+
29
+ private
30
+
31
+ attr_reader :form
32
+
33
+ def create_editor_image
34
+ @editor_image = EditorImage.create!(
35
+ decidim_author_id: form.current_user.id,
36
+ organization: form.organization,
37
+ file: form.file
38
+ )
39
+ end
40
+ end
41
+ end
@@ -10,6 +10,8 @@ module Decidim
10
10
  Decidim.config.consent_cookie_name,
11
11
  value: "true",
12
12
  path: "/",
13
+ httponly: true,
14
+ secure: request.session_options[:secure],
13
15
  expires: 1.year.from_now.utc
14
16
  )
15
17
 
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ class EditorImagesController < Decidim::ApplicationController
5
+ include FormFactory
6
+
7
+ # overwrite original rescue_from to ensure we print messages from ajax methods (update)
8
+ rescue_from Decidim::ActionForbidden, with: :ajax_user_has_no_permission
9
+
10
+ def create
11
+ enforce_permission_to :create, :editor_image
12
+
13
+ @form = form(EditorImageForm).from_params(form_values)
14
+
15
+ CreateEditorImage.call(@form) do
16
+ on(:ok) do |image|
17
+ render json: { url: image.attached_uploader(:file).path, message: I18n.t("success", scope: "decidim.editor_images.create") }
18
+ end
19
+
20
+ on(:invalid) do |_message|
21
+ render json: { message: I18n.t("error", scope: "decidim.editor_images.create") }, status: :unprocessable_entity
22
+ end
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ # Rescue ajax calls and print the update.js view which prints the info on the message ajax form
29
+ # Only if the request is AJAX, otherwise behave as Decidim standards
30
+ def ajax_user_has_no_permission
31
+ return user_has_no_permission unless request.xhr?
32
+
33
+ render json: { message: I18n.t("actions.unauthorized", scope: "decidim.core") }, status: :unprocessable_entity
34
+ end
35
+
36
+ def form_values
37
+ {
38
+ file: params[:image],
39
+ author_id: current_user.id
40
+ }
41
+ end
42
+
43
+ def permission_scope
44
+ :admin
45
+ end
46
+ end
47
+ end
@@ -12,7 +12,8 @@ module Decidim
12
12
  helper_method :activities, :resource_types, :user
13
13
 
14
14
  def index
15
- raise ActionController::RoutingError, "Blocked User" if user&.blocked? && !current_user&.admin?
15
+ raise ActionController::RoutingError, "Missing user: #{params[:nickname]}" unless user
16
+ raise ActionController::RoutingError, "Blocked User" if user.blocked? && !current_user&.admin?
16
17
  end
17
18
 
18
19
  private
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ class EditorImageForm < Decidim::Form
5
+ mimic :editor_image
6
+
7
+ attribute :file
8
+ attribute :author_id, Integer
9
+
10
+ validates :author_id, presence: true
11
+ validates :file, presence: true
12
+ validates :file, passthru: { to: Decidim::EditorImage }
13
+
14
+ alias organization current_organization
15
+ end
16
+ end
@@ -136,7 +136,7 @@ module Decidim
136
136
 
137
137
  return body unless rich_text_editor_in_public_views?
138
138
 
139
- decidim_sanitize(body)
139
+ decidim_sanitize_editor(body)
140
140
  end
141
141
 
142
142
  # Return the edited field value or presents the original attribute value in a form.
@@ -15,7 +15,7 @@ module Decidim
15
15
  # options - A Hash with the options to truncate the text (default: {}):
16
16
  # :length - An Integer number with the max length of the text.
17
17
  # :separator - A String to append to the text when it's being
18
- # truncated. See `truncato` gem for more options.
18
+ # truncated.
19
19
  #
20
20
  # Returns a String.
21
21
  def html_truncate(text, options = {})
@@ -25,7 +25,7 @@ module Decidim
25
25
  options[:count_tail] ||= false
26
26
  options[:tail_before_final_tag] = true unless options.has_key?(:tail_before_final_tag)
27
27
 
28
- Truncato.truncate(text, options)
28
+ Decidim::HtmlTruncation.new(text, options).perform
29
29
  end
30
30
 
31
31
  def present(object, presenter_class: nil)
@@ -3,14 +3,43 @@
3
3
  module Decidim
4
4
  module Messaging
5
5
  module ConversationHelper
6
+ def conversation_name_for(users)
7
+ return content_tag(:span, t("decidim.profile.deleted"), class: "label label--small label--basic") if users.first.deleted?
8
+
9
+ content_tag = content_tag(:strong, users.first.name)
10
+ content_tag << tag.br
11
+ content_tag << content_tag(:span, "@#{users.first.nickname}", class: "muted")
12
+ content_tag
13
+ end
14
+
15
+ def conversation_label_for(participants)
16
+ return t("title", scope: "decidim.messaging.conversations.show", usernames: username_list(participants)) unless participants.count == 1
17
+
18
+ chat_with_user = if participants.first.deleted?
19
+ t("decidim.profile.deleted")
20
+ else
21
+ "#{participants.first.name} (@#{participants.first.nickname})"
22
+ end
23
+
24
+ "#{t("chat_with", scope: "decidim.messaging.conversations.show")} #{chat_with_user}"
25
+ end
26
+
6
27
  #
7
28
  # Generates a visualization of users for listing conversations threads
8
29
  #
9
30
  def username_list(users, shorten: false)
10
- return users.pluck(:name).join(", ") unless shorten
11
- return users.pluck(:name).join(", ") unless users.count > 3
31
+ content_tags = []
32
+ first_users = shorten ? users.first(3) : users
33
+ deleted_user_tag = content_tag(:span, t("decidim.profile.deleted"), class: "label label--small label--basic")
34
+ first_users.each do |u|
35
+ content_tags.push(u.deleted? ? deleted_user_tag : content_tag(:strong, u.name))
36
+ end
37
+
38
+ return content_tags.join(", ") unless shorten
39
+ return content_tags.join(", ") unless users.count > 3
12
40
 
13
- "#{users.first(3).pluck(:name).join(", ")} + #{users.count - 3}"
41
+ content_tags.push(content_tag(:strong, " + #{users.count - 3}"))
42
+ content_tags.join(", ")
14
43
  end
15
44
 
16
45
  #
@@ -13,7 +13,7 @@ module Decidim
13
13
  #
14
14
  # Returns a String.
15
15
  def resource_version(resource, options = {})
16
- return unless resource.respond_to?(:versions) && resource.versions.present?
16
+ return unless resource.respond_to?(:versions) && resource.versions_count.positive?
17
17
 
18
18
  html = []
19
19
  html << resource_version_number(resource.versions_count)
@@ -5,6 +5,7 @@ module Decidim
5
5
  module SanitizeHelper
6
6
  def self.included(base)
7
7
  base.include ActionView::Helpers::SanitizeHelper
8
+ base.include ActionView::Helpers::TagHelper
8
9
  end
9
10
 
10
11
  # Public: It sanitizes a user-inputted string with the
@@ -30,6 +31,10 @@ module Decidim
30
31
  end
31
32
  end
32
33
 
34
+ def decidim_sanitize_editor(html, options = {})
35
+ content_tag(:div, decidim_sanitize(html, options), class: %w(ql-editor ql-reset-decidim))
36
+ end
37
+
33
38
  def decidim_html_escape(text)
34
39
  ERB::Util.unwrapped_html_escape(text.to_str)
35
40
  end
@@ -37,5 +42,65 @@ module Decidim
37
42
  def decidim_url_escape(text)
38
43
  decidim_html_escape(text).sub(/^javascript:/, "")
39
44
  end
45
+
46
+ private
47
+
48
+ # Maintains the paragraphs and lists separations with their bullet points and
49
+ # list numberings where appropriate.
50
+ #
51
+ # Returns a String.
52
+ def sanitize_text(text)
53
+ add_line_feeds(sanitize_ordered_lists(sanitize_unordered_lists(text)))
54
+ end
55
+
56
+ def sanitize_unordered_lists(text)
57
+ text.gsub(%r{(?=.*</ul>)(?!.*?<li>.*?</ol>.*?</ul>)<li>}) { |li| "#{li}• " }
58
+ end
59
+
60
+ def sanitize_ordered_lists(text)
61
+ i = 0
62
+
63
+ text.gsub(%r{(?=.*</ol>)(?!.*?<li>.*?</ul>.*?</ol>)<li>}) do |li|
64
+ i += 1
65
+
66
+ li + "#{i}. "
67
+ end
68
+ end
69
+
70
+ def add_line_feeds_to_paragraphs(text)
71
+ text.gsub("</p>") { |p| "#{p}\n\n" }
72
+ end
73
+
74
+ def add_line_feeds_to_list_items(text)
75
+ text.gsub("</li>") { |li| "#{li}\n" }
76
+ end
77
+
78
+ # Adds line feeds after the paragraph and list item closing tags.
79
+ #
80
+ # Returns a String.
81
+ def add_line_feeds(text)
82
+ add_line_feeds_to_paragraphs(add_line_feeds_to_list_items(text))
83
+ end
84
+
85
+ def content_handle_locale(body, all_locales, extras, links, strip_tags)
86
+ handle_locales(body, all_locales) do |content|
87
+ content = strip_tags(sanitize_text(content)) if strip_tags
88
+
89
+ renderer = Decidim::ContentRenderers::HashtagRenderer.new(content)
90
+ content = renderer.render(links: links, extras: extras).html_safe
91
+
92
+ content = Decidim::ContentRenderers::LinkRenderer.new(content).render if links
93
+ content
94
+ end
95
+ end
96
+
97
+ def render_sanitized_content(resource, method)
98
+ content = present(resource).send(method, links: true, strip_tags: !safe_content?)
99
+ content = simple_format(content, {}, sanitize: false)
100
+
101
+ return content unless safe_content?
102
+
103
+ decidim_sanitize_editor(content)
104
+ end
40
105
  end
41
106
  end