decidim-core 0.25.0 → 0.26.0.rc2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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)