decidim-core 0.25.0 → 0.26.0.rc2

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 (165) 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/how_to_participate/show.erb +1 -1
  12. data/app/cells/decidim/content_blocks/last_activity_cell.rb +1 -1
  13. data/app/cells/decidim/content_blocks/stats_cell.rb +12 -0
  14. data/app/cells/decidim/endorsers_list_cell.rb +3 -1
  15. data/app/cells/decidim/flag_modal/flag_user.erb +2 -2
  16. data/app/cells/decidim/flag_modal/show.erb +2 -2
  17. data/app/cells/decidim/flag_modal_cell.rb +10 -0
  18. data/app/cells/decidim/following/show.erb +17 -8
  19. data/app/cells/decidim/following_cell.rb +6 -2
  20. data/app/cells/decidim/notification/show.erb +31 -0
  21. data/app/cells/decidim/notification_cell.rb +20 -0
  22. data/app/cells/decidim/notifications/show.erb +1 -24
  23. data/app/cells/decidim/notifications_cell.rb +0 -1
  24. data/app/cells/decidim/user_conversation/conversation_header.erb +1 -1
  25. data/app/cells/decidim/user_conversation/show.erb +4 -2
  26. data/app/cells/decidim/user_conversations/conversation_item.erb +1 -1
  27. data/app/commands/decidim/create_editor_image.rb +41 -0
  28. data/app/controllers/concerns/decidim/disable_redirection_to_external_host.rb +15 -0
  29. data/app/controllers/concerns/decidim/safe_redirect.rb +14 -3
  30. data/app/controllers/decidim/application_controller.rb +1 -0
  31. data/app/controllers/decidim/cookie_policy_controller.rb +2 -0
  32. data/app/controllers/decidim/editor_images_controller.rb +47 -0
  33. data/app/controllers/decidim/user_activities_controller.rb +2 -1
  34. data/app/forms/decidim/editor_image_form.rb +16 -0
  35. data/app/helpers/decidim/amendments_helper.rb +1 -1
  36. data/app/helpers/decidim/application_helper.rb +2 -2
  37. data/app/helpers/decidim/messaging/conversation_helper.rb +32 -3
  38. data/app/helpers/decidim/resource_versions_helper.rb +1 -1
  39. data/app/helpers/decidim/sanitize_helper.rb +65 -0
  40. data/app/models/decidim/editor_image.rb +14 -0
  41. data/app/models/decidim/messaging/conversation.rb +9 -0
  42. data/app/models/decidim/participatory_space_private_user.rb +16 -0
  43. data/app/models/decidim/user.rb +3 -9
  44. data/app/models/decidim/user_base_entity.rb +24 -13
  45. data/app/models/decidim/user_group.rb +40 -0
  46. data/app/packs/entrypoints/decidim_core.js +1 -0
  47. data/app/packs/src/decidim/dialog_mode.js +143 -0
  48. data/app/packs/src/decidim/dialog_mode.test.js +168 -0
  49. data/app/packs/src/decidim/editor.js +56 -14
  50. data/app/packs/src/decidim/form_attachments.js +5 -0
  51. data/app/packs/src/decidim/geocoding/attach_input.js +11 -2
  52. data/app/packs/src/decidim/index.js +4 -0
  53. data/app/packs/src/decidim/input_emoji.js +10 -1
  54. data/app/packs/src/decidim/vendor/image-resize.min.js +3 -0
  55. data/app/packs/src/decidim/vendor/image-upload.min.js +8 -0
  56. data/app/packs/stylesheets/decidim/extras/_extras.scss +0 -1
  57. data/app/packs/stylesheets/decidim/extras/_quill.scss +7 -0
  58. data/app/packs/stylesheets/decidim/modules/_buttons.scss +11 -4
  59. data/app/packs/stylesheets/decidim/modules/_cards.scss +4 -0
  60. data/app/packs/stylesheets/decidim/modules/_layout.scss +1 -1
  61. data/app/packs/stylesheets/decidim/modules/_timeline.scss +1 -1
  62. data/app/presenters/decidim/nil_presenter.rb +2 -2
  63. data/app/presenters/decidim/notification_presenter.rb +25 -0
  64. data/app/presenters/decidim/official_author_presenter.rb +1 -1
  65. data/app/presenters/decidim/validation_errors_presenter.rb +27 -0
  66. data/app/queries/decidim/similar_emendations.rb +1 -1
  67. data/app/resolvers/decidim/core/metric_resolver.rb +1 -1
  68. data/app/services/decidim/activity_search.rb +2 -2
  69. data/app/services/decidim/email_notification_generator.rb +4 -1
  70. data/app/services/decidim/html_truncation.rb +130 -0
  71. data/app/services/decidim/open_data_exporter.rb +29 -5
  72. data/app/services/decidim/resource_search.rb +1 -1
  73. data/app/uploaders/decidim/editor_image_uploader.rb +6 -0
  74. data/app/validators/password_validator.rb +123 -0
  75. data/app/views/decidim/account/_password_fields.html.erb +1 -1
  76. data/app/views/decidim/devise/passwords/edit.html.erb +1 -1
  77. data/app/views/decidim/devise/registrations/new.html.erb +1 -1
  78. data/app/views/decidim/devise/shared/_omniauth_buttons_mini.html.erb +6 -4
  79. data/app/views/decidim/messaging/conversations/_conversation.html.erb +9 -3
  80. data/app/views/decidim/messaging/conversations/_messages.html.erb +8 -2
  81. data/app/views/decidim/messaging/conversations/_show.html.erb +10 -12
  82. data/app/views/decidim/messaging/conversations/show.html.erb +4 -2
  83. data/app/views/decidim/newsletters/show.html.erb +1 -1
  84. data/app/views/decidim/notification_mailer/event_received.html.erb +17 -0
  85. data/app/views/decidim/pages/_tabbed.html.erb +1 -1
  86. data/app/views/decidim/searches/_filters_small_view.html.erb +3 -3
  87. data/app/views/decidim/shared/_login_modal.html.erb +5 -5
  88. data/app/views/decidim/shared/_orders.html.erb +1 -1
  89. data/app/views/decidim/shared/_results_per_page.html.erb +1 -1
  90. data/app/views/decidim/shared/participatory_space_filters/_filters_small_view.html.erb +3 -3
  91. data/app/views/layouts/decidim/_application.html.erb +1 -12
  92. data/app/views/layouts/decidim/_head.html.erb +4 -0
  93. data/app/views/layouts/decidim/_language_chooser.html.erb +1 -1
  94. data/app/views/layouts/decidim/_meta_tags_config.html.erb +11 -0
  95. data/app/views/layouts/decidim/_wrapper.html.erb +1 -1
  96. data/config/brakeman.ignore +149 -0
  97. data/config/initializers/devise.rb +1 -1
  98. data/config/initializers/rack_attack.rb +23 -21
  99. data/config/locales/ar.yml +8 -0
  100. data/config/locales/ca.yml +43 -0
  101. data/config/locales/cs.yml +61 -0
  102. data/config/locales/en.yml +47 -0
  103. data/config/locales/es-MX.yml +42 -0
  104. data/config/locales/es-PY.yml +42 -0
  105. data/config/locales/es.yml +42 -0
  106. data/config/locales/eu.yml +27 -12
  107. data/config/locales/fi-plain.yml +42 -0
  108. data/config/locales/fi.yml +42 -0
  109. data/config/locales/fr-CA.yml +43 -0
  110. data/config/locales/fr.yml +75 -28
  111. data/config/locales/gl.yml +6 -0
  112. data/config/locales/it.yml +11 -0
  113. data/config/locales/ja.yml +85 -49
  114. data/config/locales/lb-LU.yml +1354 -0
  115. data/config/locales/lb.yml +1 -1
  116. data/config/locales/nl.yml +51 -0
  117. data/config/locales/pl.yml +5 -5
  118. data/config/locales/pt-BR.yml +1 -1
  119. data/config/locales/ro-RO.yml +275 -252
  120. data/config/locales/sv.yml +45 -2
  121. data/config/locales/val-ES.yml +1 -0
  122. data/config/routes.rb +2 -0
  123. data/db/migrate/20210730112319_create_decidim_editor_images.rb +12 -0
  124. data/db/migrate/20211126183540_add_timestamps_to_content_blocks.rb +14 -0
  125. data/db/seeds.rb +16 -14
  126. data/lib/decidim/api/functions/user_entity_finder.rb +2 -1
  127. data/lib/decidim/api/functions/user_entity_list.rb +3 -1
  128. data/lib/decidim/api/input_sorts/component_input_sort.rb +1 -1
  129. data/lib/decidim/common_passwords.rb +56 -0
  130. data/lib/decidim/content_parsers/inline_images_parser.rb +68 -0
  131. data/lib/decidim/content_parsers.rb +1 -0
  132. data/lib/decidim/content_renderers/link_renderer.rb +85 -1
  133. data/lib/decidim/content_renderers/user_group_renderer.rb +1 -1
  134. data/lib/decidim/content_renderers/user_renderer.rb +1 -1
  135. data/lib/decidim/core/engine.rb +7 -12
  136. data/lib/decidim/core/test/factories.rb +7 -1
  137. data/lib/decidim/core/test/shared_examples/translated_event_examples.rb +131 -0
  138. data/lib/decidim/core/test.rb +1 -0
  139. data/lib/decidim/core/version.rb +1 -1
  140. data/lib/decidim/core.rb +33 -5
  141. data/lib/decidim/db/common-passwords.txt +128420 -0
  142. data/lib/decidim/etherpad/pad.rb +48 -0
  143. data/lib/decidim/etherpad.rb +7 -0
  144. data/lib/decidim/events/base_event.rb +18 -0
  145. data/lib/decidim/events/machine_translated_event.rb +36 -0
  146. data/lib/decidim/events/user_group_event.rb +1 -3
  147. data/lib/decidim/events.rb +1 -0
  148. data/lib/decidim/exporters/csv.rb +7 -7
  149. data/lib/decidim/faker/localized.rb +15 -6
  150. data/lib/decidim/form_builder.rb +14 -4
  151. data/lib/decidim/has_attachments.rb +11 -4
  152. data/lib/decidim/has_component.rb +4 -0
  153. data/lib/decidim/importers/import_manifest.rb +103 -3
  154. data/lib/decidim/organization_settings.rb +1 -1
  155. data/lib/decidim/paddable.rb +1 -9
  156. data/lib/decidim/participable.rb +5 -0
  157. data/lib/decidim/resourceable.rb +2 -9
  158. data/lib/decidim/searchable.rb +2 -2
  159. data/lib/decidim/settings_manifest.rb +2 -0
  160. data/lib/decidim/translatable_attributes.rb +6 -6
  161. data/lib/decidim/view_model.rb +10 -0
  162. data/lib/tasks/decidim_active_storage_migration_tasks.rake +68 -0
  163. data/lib/tasks/decidim_webpacker_tasks.rake +4 -10
  164. metadata +70 -78
  165. 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: 42e511f59400c64469c3f38cc07211386f55536c8e8d1b83403a45cf3257feea
4
- data.tar.gz: 1dc8707d02a1971035ff9ef3b809b4f0bcc7af556c6972959d44a17f137cfc39
3
+ metadata.gz: '008fc01a452a6ce6800305e9cd20ebaf12adade8db7b13aa2f62d5d11bf07eb0'
4
+ data.tar.gz: 9acc5acf5b9e95057be4731b089fb383e45f2ac90065d978e7f23f8a97dac4e6
5
5
  SHA512:
6
- metadata.gz: e3c25eaf439667b98da4de8e71676f41a0cbf1e53181c0275e97080ea3a8342605931683a7a6c324296ce4a5f98d9d165a920878957104db179d4c1d61eca4e4
7
- data.tar.gz: fdb4bfcbeab070cd3ad4a8f1b0eb212112f31901422d7ea60cbfbad2f457ed7f802b2a9bd98d83c87e38261b1e4b9d4dc604f12cc11a88f594a4b1a93c42eec8
6
+ metadata.gz: 5edc8e0a59cf89167962340fe5fca99b5ddd5257f1dd936b0e8a9c8e3f620f8cdd8596b1d831c2886750d94764dd009453fa117c347ba00020ceb6eefa8f911f
7
+ data.tar.gz: 7538bffa5a162c3e4777fc9317f529854e664540dcf77da130c6a08362afa37bff8a84d78b29ae78b04cf2f370b6c582da21a8fdeebdbf447cf360cf82419f63
@@ -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">
@@ -41,7 +41,7 @@
41
41
  <div class="row">
42
42
  <div class="columns small-centered small-10
43
43
  smallmedium-8 medium-6 large-4">
44
- <%= link_to t("decidim.pages.home.extended.more_info", resource_name: translated_attribute(current_organization.name, current_organization)), decidim.page_path("faq"), class: "button expanded hollow button--sc" %>
44
+ <%= link_to t("decidim.pages.home.extended.more_info", resource_name: translated_attribute(current_organization.name, current_organization)), decidim.pages_path, class: "button expanded hollow button--sc" %>
45
45
  </div>
46
46
  </div>
47
47
  </div>
@@ -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
@@ -1,9 +1,18 @@
1
- <div class="empty-notifications callout secondary <%= "hide" if followings.any? %>">
2
- <p><%= t("decidim.following.no_followings") %></p>
3
- </div>
4
- <div class="row small-up-1 medium-up-2 card-grid">
5
- <% followings.each do |following| %>
6
- <%= card_for following, context: { label: true, show_space: true } %>
1
+ <% if public_followings.any? %>
2
+ <% if non_public_followings? %>
3
+ <div class="empty-notifications callout secondary">
4
+ <p><%= t("decidim.following.non_public_followings") %></p>
5
+ </div>
7
6
  <% end %>
8
- </div>
9
- <%= decidim_paginate followings %>
7
+
8
+ <div class="row small-up-1 medium-up-2 card-grid">
9
+ <% public_followings.each do |followable| %>
10
+ <%= card_for followable, context: { label: true, show_space: true } %>
11
+ <% end %>
12
+ </div>
13
+ <%= decidim_paginate public_followings %>
14
+ <% else %>
15
+ <div class="empty-notifications callout secondary">
16
+ <p><%= t("decidim.following.no_followings") %></p>
17
+ </div>
18
+ <% end %>
@@ -11,8 +11,12 @@ module Decidim
11
11
  render :show
12
12
  end
13
13
 
14
- def followings
15
- @followings ||= Kaminari.paginate_array(model.following).page(params[:page]).per(20)
14
+ def public_followings
15
+ @public_followings ||= Kaminari.paginate_array(model.public_followings).page(params[:page]).per(20)
16
+ end
17
+
18
+ def non_public_followings?
19
+ public_followings.count < model.following_count
16
20
  end
17
21
  end
18
22
  end
@@ -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
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/concern"
4
+
5
+ module Decidim
6
+ module DisableRedirectionToExternalHost
7
+ extend ActiveSupport::Concern
8
+
9
+ included do
10
+ def redirect_back(fallback_location:, allow_other_host: true, **args) # rubocop:disable Lint/UnusedMethodArgument
11
+ super fallback_location: fallback_location, allow_other_host: Decidim.allow_open_redirects, **args
12
+ end
13
+ end
14
+ end
15
+ end
@@ -14,10 +14,21 @@ module Decidim
14
14
  # that match the current organization.
15
15
  def redirect_url
16
16
  return if params[:redirect_url].blank?
17
- return params[:redirect_url] unless params[:redirect_url].start_with?("http")
18
- return if URI.parse(params[:redirect_url]).host != current_organization.host
19
17
 
20
- params[:redirect_url]
18
+ # Parse given URL
19
+ target_uri = URI.parse(params[:redirect_url])
20
+
21
+ # Add the organization host to the URL if not present
22
+ target_uri = URI.join("#{request.scheme}://#{current_organization.host}", target_uri) unless target_uri.host
23
+
24
+ # Don't allow URLs without host or with a different host than the organization one
25
+ return if target_uri.host != current_organization.host
26
+
27
+ # Convert the URI to relative
28
+ target_uri.scheme = target_uri.host = target_uri.port = nil
29
+
30
+ # Return the relative URL
31
+ target_uri.to_s
21
32
  end
22
33
  end
23
34
  end
@@ -19,6 +19,7 @@ module Decidim
19
19
  include SafeRedirect
20
20
  include NeedsSnippets
21
21
  include UserBlockedChecker
22
+ include DisableRedirectionToExternalHost
22
23
 
23
24
  helper Decidim::MetaTagsHelper
24
25
  helper Decidim::DecidimFormHelper
@@ -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)