decidim-comments 0.24.3 → 0.25.0.rc4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -20
  3. data/app/assets/javascripts/decidim/comments/bundle.js.map +1 -1
  4. data/app/cells/decidim/comments/comment/actions.erb +1 -1
  5. data/app/cells/decidim/comments/comment/deletion_data.erb +1 -0
  6. data/app/cells/decidim/comments/comment/show.erb +30 -21
  7. data/app/cells/decidim/comments/comment/utilities.erb +40 -12
  8. data/app/cells/decidim/comments/comment/votes.erb +6 -6
  9. data/app/cells/decidim/comments/comment_cell.rb +29 -0
  10. data/app/cells/decidim/comments/comment_form/show.erb +1 -1
  11. data/app/cells/decidim/comments/comments/add_comment.erb +10 -6
  12. data/app/cells/decidim/comments/comments/order_control.erb +4 -5
  13. data/app/cells/decidim/comments/comments/show.erb +2 -4
  14. data/app/cells/decidim/comments/comments/user_comments_blocked_warning.erb +5 -1
  15. data/app/cells/decidim/comments/comments_cell.rb +24 -2
  16. data/app/cells/decidim/comments/edit_comment_modal_form/show.erb +29 -0
  17. data/app/cells/decidim/comments/edit_comment_modal_form_cell.rb +53 -0
  18. data/app/commands/decidim/comments/create_comment.rb +2 -1
  19. data/app/commands/decidim/comments/delete_comment.rb +46 -0
  20. data/app/commands/decidim/comments/update_comment.rb +62 -0
  21. data/app/controllers/decidim/comments/comments_controller.rb +63 -6
  22. data/app/events/decidim/comments/comment_voted_event.rb +9 -0
  23. data/app/models/decidim/comments/comment.rb +24 -1
  24. data/app/packs/src/decidim/comments/comments.component.js +300 -0
  25. data/app/{assets/javascripts → packs/src}/decidim/comments/comments.component.test.js +116 -26
  26. data/app/packs/src/decidim/comments/comments.component_for_testing.js +8 -0
  27. data/app/packs/src/decidim/comments/comments.js +1 -0
  28. data/app/permissions/decidim/comments/permissions.rb +10 -1
  29. data/app/queries/decidim/comments/metrics/comment_participants_metric_measure.rb +1 -1
  30. data/app/queries/decidim/comments/metrics/comments_metric_manage.rb +1 -1
  31. data/app/queries/decidim/comments/sorted_comments.rb +8 -6
  32. data/app/views/decidim/comments/comments/_delete.html.erb +5 -0
  33. data/app/views/decidim/comments/comments/_edited_comment.html.erb +1 -0
  34. data/app/views/decidim/comments/comments/create.js.erb +4 -2
  35. data/app/views/decidim/comments/comments/delete.js.erb +17 -0
  36. data/app/views/decidim/comments/comments/deletion_error.js.erb +1 -0
  37. data/app/views/decidim/comments/comments/reload.js.erb +2 -0
  38. data/app/views/decidim/comments/comments/update.js.erb +8 -0
  39. data/app/views/decidim/comments/comments/update_error.js.erb +1 -0
  40. data/config/assets.rb +5 -0
  41. data/config/locales/ar.yml +0 -1
  42. data/config/locales/ca.yml +7 -1
  43. data/config/locales/cs.yml +25 -1
  44. data/config/locales/de.yml +7 -1
  45. data/config/locales/el.yml +0 -1
  46. data/config/locales/en.yml +25 -1
  47. data/config/locales/es-MX.yml +7 -1
  48. data/config/locales/es-PY.yml +7 -1
  49. data/config/locales/es.yml +7 -1
  50. data/config/locales/fi-plain.yml +25 -1
  51. data/config/locales/fi.yml +25 -1
  52. data/config/locales/fr-CA.yml +25 -1
  53. data/config/locales/fr-LU.yml +162 -0
  54. data/config/locales/fr.yml +25 -1
  55. data/config/locales/gl.yml +25 -1
  56. data/config/locales/hu.yml +0 -1
  57. data/config/locales/it.yml +38 -1
  58. data/config/locales/ja.yml +35 -1
  59. data/config/locales/lb-LU.yml +1 -0
  60. data/config/locales/lv.yml +0 -1
  61. data/config/locales/nl.yml +27 -2
  62. data/config/locales/no.yml +0 -1
  63. data/config/locales/pl.yml +7 -1
  64. data/config/locales/pt-BR.yml +61 -0
  65. data/config/locales/pt.yml +0 -1
  66. data/config/locales/ro-RO.yml +25 -1
  67. data/config/locales/sk.yml +0 -1
  68. data/config/locales/sr-CS.yml +0 -1
  69. data/config/locales/sv.yml +25 -1
  70. data/config/locales/tr-TR.yml +0 -1
  71. data/config/locales/zh-CN.yml +0 -1
  72. data/db/migrate/20200706123136_make_comments_handle_i18n.rb +1 -1
  73. data/db/migrate/20210402124534_add_participatory_process_to_comments.rb +12 -0
  74. data/db/migrate/20210529095942_add_deleted_at_column_to_comments.rb +7 -0
  75. data/lib/decidim/comments/commentable.rb +6 -1
  76. data/lib/decidim/comments/commentable_with_component.rb +33 -0
  77. data/lib/decidim/comments/engine.rb +1 -9
  78. data/lib/decidim/comments/test/factories.rb +1 -0
  79. data/lib/decidim/comments/version.rb +1 -1
  80. data/lib/decidim/comments.rb +1 -0
  81. data/lib/tasks/decidim_comments.rake +15 -0
  82. metadata +32 -29
  83. data/app/assets/config/decidim_comments_manifest.js +0 -1
  84. data/app/assets/javascripts/decidim/comments/comments.component.js.es6 +0 -292
  85. data/app/assets/javascripts/decidim/comments/comments.js.erb +0 -10
  86. data/config/locales/ja-JP.yml +0 -120
@@ -1,7 +1,7 @@
1
1
  <div class="comment__actions">
2
2
  <% if can_reply? %>
3
3
  <button class="comment__reply muted-link" aria-controls="<%= reply_id %>" data-toggle="<%= reply_id %>">
4
- <%= icon "pencil", class: "icon--small", role: "none presentation" %>&nbsp;<%= t("decidim.components.comment.reply") %>
4
+ <%= icon "pencil", class: "icon--small", role: "img", "aria-hidden": true %>&nbsp;<%= t("decidim.components.comment.reply") %>
5
5
  </button>
6
6
  <% end %>
7
7
  </div>
@@ -0,0 +1 @@
1
+ <%= render partial: "decidim/comments/comments/delete.html", locals: { comment: model } %>
@@ -1,36 +1,45 @@
1
1
  <%= content_tag :div, id: "comment_#{model.id}", class: comment_classes, data: { comment_id: model.id } do %>
2
- <div class="comment__header">
3
- <div class="author-data">
4
- <div class="author-data__main">
5
- <%= render :author %>
6
- <span>
7
- <%= time_tag created_at, l(created_at, format: :decidim_short) %>
8
- </span>
9
- </div>
10
- <div class="author-data__extra">
11
- <%= render :utilities %>
2
+ <% if model.deleted? %>
3
+ <%= render :deletion_data %>
4
+ <% else %>
5
+ <div class="comment__header">
6
+ <div class="author-data">
7
+ <div class="author-data__main">
8
+ <%= render :author %>
9
+ <span>
10
+ <%= time_tag created_at, l(created_at, format: :decidim_short) %>
11
+ </span>
12
+ <% if edited? %>
13
+ <div class="author-data__extra">
14
+ <span class="comment__edited">
15
+ <%= t("decidim.components.comment.edited") %>
16
+ </span>
17
+ </div>
18
+ <% end %>
19
+ </div>
12
20
  </div>
21
+ <%= render :utilities %>
13
22
  </div>
14
- </div>
15
- <div class="comment__content">
16
- <%= alignment_badge %>
17
- <%= comment_body %>
18
- </div>
19
- <div class="comment__footer">
20
- <%= render :actions %>
21
- <%= votes %>
22
- </div>
23
+ <div class="comment__content">
24
+ <%= alignment_badge %>
25
+ <%= comment_body %>
26
+ </div>
27
+ <div class="comment__footer">
28
+ <%= render :actions %>
29
+ <%= votes %>
30
+ </div>
31
+ <% end %>
23
32
  <div id="comment-<%= model.id %>-replies">
24
33
  <% if has_replies? %>
25
34
  <% replies.each do |reply| %>
26
- <%= cell("decidim/comments/comment", reply, root_depth: root_depth, order: order) %>
35
+ <%= cell("decidim/comments/comment", reply, root_depth: root_depth, order: order, reloaded: reloaded?) %>
27
36
  <% end %>
28
37
  <% end %>
29
38
  </div>
30
39
  <% if can_reply? %>
31
40
  <div class="comment__additionalreply<%= " hide" unless has_replies? %>">
32
41
  <button class="comment__reply muted-link" aria-controls="<%= reply_id %>" data-toggle="<%= reply_id %>">
33
- <%= icon "pencil", class: "icon--small", role: "none presentation" %>&nbsp;<%= t("decidim.components.comment.reply") %>
42
+ <%= icon "pencil", class: "icon--small", role: "img", "aria-hidden": true %>&nbsp;<%= t("decidim.components.comment.reply") %>
34
43
  </button>
35
44
  </div>
36
45
  <div class="add-comment hide" id="<%= reply_id %>" data-toggler=".hide">
@@ -1,13 +1,41 @@
1
- <button type="button" class="link-alt" data-open="<%= current_user.present? ? "flagModalComment#{model.id}" : "loginModal" %>" title="<%= t("decidim.components.comment.report.title") %>" aria-controls="<%= current_user.present? ? "flagModalComment#{model.id}" : "loginModal" %>" aria-haspopup="true" tabindex="0">
2
- <%= icon "flag", aria_hidden: true, class: "icon--small", role: "none presentation", "aria-hidden": true %>
3
- <span class="show-for-sr"><%= t("decidim.components.comment.report.title") %></span>
4
- </button>
5
-
6
- <%= link_to "#{commentable_path("commentId" => model.id)}#comment_#{model.id}", title: t("decidim.components.comment.single_comment_link_title") do %>
7
- <span class="show-for-sr"><%= t("decidim.components.comment.single_comment_link_title") %></span>
8
- <%= icon "link-intact", class: "icon--small", role: "none presentation" %>
9
- <% end %>
10
-
11
- <% if current_user.present? %>
12
- <%= cell("decidim/flag_modal", model, modal_id: "flagModalComment#{model.id}") %>
1
+ <div class="comment__header__context-menu">
2
+ <label for="<%= context_menu_id %>" data-toggle="<%= context_menu_id %>">
3
+ <%= icon "ellipses" %>
4
+ </label>
5
+ <ul id="<%= context_menu_id %>" data-dropdown data-close-on-click="true" data-position="left" data-alignment="top" class="card dropdown-pane comment__header__context-menu__content">
6
+ <li>
7
+ <button type="button" class="link-alt comment__header__context-menu__content-item" data-open="<%= current_user.present? ? "flagModalComment#{model.id}" : "loginModal" %>" title="<%= t("decidim.components.comment.report.title") %>" aria-controls="<%= current_user.present? ? "flagModalComment#{model.id}" : "loginModal" %>" aria-haspopup="true" tabindex="0">
8
+ <%= icon "flag", class: "icon--small", aria_label: t("decidim.components.comment.report.title") %>
9
+ <span><%= t("decidim.components.comment.report.action") %></span>
10
+ </button>
11
+ </li>
12
+ <li>
13
+ <%= link_to "#{commentable_path("commentId" => model.id)}#comment_#{model.id}", target: "_blank", class: "comment__header__context-menu__content-item", title: t("decidim.components.comment.single_comment_link_title") do %>
14
+ <%= icon "link-intact", class: "icon--small", aria_label: t("decidim.components.comment.single_comment_link_title") %>
15
+ <span><%= t("decidim.components.comment.single_comment_link_title") %></span>
16
+ <% end %>
17
+ </li>
18
+ <% if model.authored_by?(current_user) %>
19
+ <li>
20
+ <button type="button" class="link-alt comment__header__context-menu__content-item" data-open="<%= "editCommentModal#{model.id}" %>" title="<%= t("decidim.components.comment.edit") %>" aria-controls="<%= "editCommentModal#{model.id}" %>" aria-haspopup="true" tabindex="0">
21
+ <%= icon "pencil", class: "icon--small", aria_label: t("decidim.components.comment.edit") %>
22
+ <span><%= t("decidim.components.comment.edit") %></span>
23
+ </button>
24
+ </li>
25
+ <li>
26
+ <%= link_to comment_path, remote: true, method: :delete, class: "comment__header__context-menu__content-item", data: { confirm: t("decidim.components.comment.confirm_destroy") } do %>
27
+ <%= icon "trash", class: "icon--small", aria_label: t("decidim.components.comment.delete") %>
28
+ <span><%= t("decidim.components.comment.delete") %></span>
29
+ <% end %>
30
+ </li>
31
+ <% end %>
32
+ </ul>
33
+ </div>
34
+ <% unless reloaded? %>
35
+ <% if current_user.present? %>
36
+ <%= cell("decidim/flag_modal", model, modal_id: "flagModalComment#{model.id}") %>
37
+ <% end %>
38
+ <% if model.authored_by?(current_user) %>
39
+ <%= cell("decidim/comments/edit_comment_modal_form", model, modal_id: "editCommentModal#{model.id}") %>
40
+ <% end %>
13
41
  <% end %>
@@ -1,24 +1,24 @@
1
1
  <div class="comment__votes">
2
2
  <% if user_signed_in? %>
3
- <%= button_to decidim_comments.comment_votes_path(model, weight: 1), remote: true, disabled: voted_down?, class: votes_up_classes, title: t("decidim.components.up_vote_button.text") do %>
3
+ <%= vote_button_to decidim_comments.comment_votes_path(model, weight: 1), remote: true, disabled: voted_down?, class: votes_up_classes, title: t("decidim.components.up_vote_button.text") do %>
4
4
  <span class="show-for-sr"><%= t("decidim.components.up_vote_button.text") %></span>
5
- <%= icon "chevron-top", class: "icon--small", role: "none presentation" %>
5
+ <%= icon "chevron-top", class: "icon--small", role: "img", "aria-hidden": true %>
6
6
  <span class="comment__votes--count"><%= up_votes_count %></span>
7
7
  <% end %>
8
- <%= button_to decidim_comments.comment_votes_path(model, weight: -1), remote: true, disabled: voted_up?, class: votes_down_classes, title: t("decidim.components.down_vote_button.text") do %>
8
+ <%= vote_button_to decidim_comments.comment_votes_path(model, weight: -1), remote: true, disabled: voted_up?, class: votes_down_classes, title: t("decidim.components.down_vote_button.text") do %>
9
9
  <span class="show-for-sr"><%= t("decidim.components.down_vote_button.text") %></span>
10
- <%= icon "chevron-bottom", class: "icon--small", role: "none presentation" %>
10
+ <%= icon "chevron-bottom", class: "icon--small", role: "img", "aria-hidden": true %>
11
11
  <span class="comment__votes--count"><%= down_votes_count %></span>
12
12
  <% end %>
13
13
  <% else %>
14
14
  <button class="<%= votes_up_classes %> " title="<%= t("decidim.components.up_vote_button.text") %>" data-open="loginModal">
15
15
  <span class="show-for-sr"><%= t("decidim.components.up_vote_button.text") %></span>
16
- <%= icon "chevron-top", class: "icon--small", role: "none presentation" %>
16
+ <%= icon "chevron-top", class: "icon--small", role: "img", "aria-hidden": true %>
17
17
  <span class="comment__votes--count"><%= up_votes_count %></span>
18
18
  </button>
19
19
  <button class="<%= votes_down_classes %> " title="<%= t("decidim.components.down_vote_button.text") %>" data-open="loginModal">
20
20
  <span class="show-for-sr"><%= t("decidim.components.down_vote_button.text") %></span>
21
- <%= icon "chevron-bottom", class: "icon--small", role: "none presentation" %>
21
+ <%= icon "chevron-bottom", class: "icon--small", role: "img", "aria-hidden": true %>
22
22
  <span class="comment__votes--count"><%= down_votes_count %></span>
23
23
  </button>
24
24
  <% end %>
@@ -7,15 +7,18 @@ module Decidim
7
7
  include ActionView::Helpers::DateHelper
8
8
  include Decidim::IconHelper
9
9
  include Decidim::ResourceHelper
10
+ include Cell::ViewModel::Partial
10
11
 
11
12
  delegate :current_user, :user_signed_in?, to: :controller
12
13
 
13
14
  property :root_commentable
14
15
  property :created_at
16
+ property :deleted_at
15
17
  property :alignment
16
18
  property :translated_body
17
19
  property :comment_threads
18
20
  property :accepts_new_comments?
21
+ property :edited?
19
22
 
20
23
  def alignment_badge
21
24
  return unless [-1, 1].include?(alignment)
@@ -51,6 +54,10 @@ module Decidim
51
54
  "comment#{model.id}-reply"
52
55
  end
53
56
 
57
+ def context_menu_id
58
+ "toggle-context-menu-#{model.id}"
59
+ end
60
+
54
61
  def can_reply?
55
62
  user_signed_in? && accepts_new_comments? &&
56
63
  root_commentable.user_allowed_to_comment?(current_user)
@@ -116,6 +123,10 @@ module Decidim
116
123
  end
117
124
  end
118
125
 
126
+ def comment_path
127
+ decidim_comments.comment_path(model)
128
+ end
129
+
119
130
  def up_votes_count
120
131
  model.up_votes.count
121
132
  end
@@ -132,6 +143,10 @@ module Decidim
132
143
  model.depth - root_depth
133
144
  end
134
145
 
146
+ def reloaded?
147
+ options[:reloaded]
148
+ end
149
+
135
150
  def voted_up?
136
151
  model.up_voted_by?(current_user)
137
152
  end
@@ -151,6 +166,20 @@ module Decidim
151
166
  def has_replies?
152
167
  model.comment_threads.any?
153
168
  end
169
+
170
+ # action_authorization_button expects current_component to be available
171
+ def current_component
172
+ root_commentable.try(:component)
173
+ end
174
+
175
+ def vote_button_to(path, params, &block)
176
+ # actions are linked to objects belonging to a component
177
+ # In consultations, a question belong to a participatory_space but it has comments
178
+ # To apply :comment permission, the modal authorizer should be refactored to allow participatory spaces-level comments
179
+ return button_to(path, params, &block) unless current_component
180
+
181
+ action_authorized_button_to(:vote_comment, path, params.merge(resource: root_commentable), &block)
182
+ end
154
183
  end
155
184
  end
156
185
  end
@@ -15,7 +15,7 @@
15
15
  required: true,
16
16
  placeholder: t("decidim.components.add_comment_form.form.body.placeholder"),
17
17
  label: false,
18
- data: { remaining_characters: "##{add_comment_id}-remaining-characters" }
18
+ data: { remaining_characters: "##{add_comment_id}-remaining-characters", input_emoji: true }
19
19
  ) %>
20
20
  </div>
21
21
  <button type="submit" class="button button--sc" disabled="disabled"><%= t("decidim.components.add_comment_form.form.submit") %></button>
@@ -1,18 +1,22 @@
1
1
  <div class="add-comment">
2
- <h4 class="section-heading"><%= t("decidim.components.add_comment_form.title") %></h4>
2
+ <h5 class="section-heading"><%= t("decidim.components.add_comment_form.title") %></h5>
3
3
 
4
4
  <% if user_signed_in? %>
5
5
  <% if alignment_enabled? %>
6
6
  <div class="opinion-toggle button-group">
7
- <button class="button tiny button--muted opinion-toggle--ok">
8
- <%= icon "thumb-up", role: "none presentation" %>
7
+ <span class="show-for-sr"><%= t("decidim.components.add_comment_form.opinion.label") %></span>
8
+ <button aria-pressed="false" class="button tiny button--muted opinion-toggle--ok" data-selected-label="<%= t("decidim.components.add_comment_form.opinion.positive_selected") %>">
9
+ <%= icon "thumb-up", role: "img", "aria-hidden": true %>
10
+ <span class="show-for-sr"><%= t("decidim.components.add_comment_form.opinion.positive") %></span>
9
11
  </button>
10
- <button class="button tiny button--muted opinion-toggle--meh is-active">
12
+ <button aria-pressed="true" class="button tiny button--muted opinion-toggle--meh is-active" data-selected-label="<%= t("decidim.components.add_comment_form.opinion.neutral_selected") %>">
11
13
  <%= t("decidim.components.add_comment_form.opinion.neutral") %>
12
14
  </button>
13
- <button class="button tiny button--muted opinion-toggle--ko">
14
- <%= icon "thumb-down", role: "none presentation" %>
15
+ <button aria-pressed="false" class="button tiny button--muted opinion-toggle--ko" data-selected-label="<%= t("decidim.components.add_comment_form.opinion.negative_selected") %>">
16
+ <%= icon "thumb-down", role: "img", "aria-hidden": true %>
17
+ <span class="show-for-sr"><%= t("decidim.components.add_comment_form.opinion.negative") %></span>
15
18
  </button>
19
+ <div role="alert" aria-live="assertive" aria-atomic="true" class="selected-state show-for-sr"></div>
16
20
  </div>
17
21
  <% end %>
18
22
  <%== cell("decidim/comments/comment_form", model, root_depth: root_depth) %>
@@ -1,14 +1,14 @@
1
1
  <div class="order-by__dropdown order-by__dropdown--right">
2
2
  <span class="order-by__text"><%= t("decidim.components.comment_order_selector.title") %></span>
3
- <ul class="dropdown menu"
3
+ <ul id="comments-order-menu"
4
+ class="dropdown menu"
4
5
  data-dropdown-menu="data-dropdown-menu"
5
6
  data-autoclose="false"
6
7
  data-disable-hover="true"
7
8
  data-click-open="true"
8
9
  data-close-on-click="true"
9
- tabindex="-1"
10
10
  role="menubar">
11
- <li class="is-dropdown-submenu-parent opens-right" tabindex="-1" role="none">
11
+ <li class="is-dropdown-submenu-parent opens-right" role="presentation">
12
12
  <a href="#" id="comments-order-menu-control"
13
13
  aria-label="<%= t("decidim.components.comment_order_selector.title") %>"
14
14
  aria-controls="comments-order-menu"
@@ -18,10 +18,9 @@
18
18
  id="comments-order-chooser-menu"
19
19
  role="menu"
20
20
  aria-labelledby="comments-order-menu-control"
21
- tabindex="-1"
22
21
  data-submenu="">
23
22
  <% available_orders.each do |order_value| %>
24
- <li role="none" class="is-submenu-item is-dropdown-submenu-item">
23
+ <li role="presentation" class="is-submenu-item is-dropdown-submenu-item">
25
24
  <%= link_to(
26
25
  t("decidim.components.comment_order_selector.order.#{order_value}"),
27
26
  decidim_comments.comments_path(commentable_gid: model.to_signed_global_id.to_s, order: order_value, reload: 1),
@@ -2,7 +2,7 @@
2
2
  <div class="columns large-9 comments-container" id="comments">
3
3
  <div class="comments">
4
4
  <div class="row collapse order-by">
5
- <h2 class="order-by__text section-heading">
5
+ <h4 class="order-by__text section-heading">
6
6
  <% if single_comment? %>
7
7
  <%= t("decidim.components.comments.comment_details_title") %>
8
8
  <% else %>
@@ -10,7 +10,7 @@
10
10
  <%= t("decidim.components.comments.title", count: comments_count) %>
11
11
  </span>
12
12
  <% end %>
13
- </h2>
13
+ </h4>
14
14
  <%= render :order_control %>
15
15
  </div>
16
16
  <%= single_comment_warning %>
@@ -28,5 +28,3 @@
28
28
  </div>
29
29
  </div>
30
30
  <% end %>
31
-
32
- <%= javascript_include_tag("decidim/comments/comments") %>
@@ -1,3 +1,7 @@
1
1
  <div class="callout warning">
2
- <p><%= t("decidim.components.comments.blocked_comments_for_user_warning") %></p>
2
+ <% if comment_permissions? %>
3
+ <p><%= blocked_comments_for_unauthorized_user_warning_link %></p>
4
+ <% else %>
5
+ <p><%= t("decidim.components.comments.blocked_comments_for_user_warning") %></p>
6
+ <% end %>
3
7
  </div>
@@ -51,7 +51,7 @@ module Decidim
51
51
  end
52
52
 
53
53
  def comments_count
54
- model.comments.count
54
+ model.comments_count
55
55
  end
56
56
 
57
57
  def root_depth
@@ -113,7 +113,7 @@ module Decidim
113
113
  def single_comment
114
114
  return if options[:single_comment].blank?
115
115
 
116
- @single_comment ||= model.comments.find_by(id: options[:single_comment])
116
+ @single_comment ||= SortedComments.for(model, id: options[:single_comment], order_by: order).first
117
117
  end
118
118
 
119
119
  def machine_translations_toggled?
@@ -129,6 +129,28 @@ module Decidim
129
129
 
130
130
  !model.user_allowed_to_comment?(current_user)
131
131
  end
132
+
133
+ def comment_permissions?
134
+ [model, current_component].any? do |resource|
135
+ resource.try(:permissions).try(:[], "comment")
136
+ end
137
+ end
138
+
139
+ # action_authorization_link expects current_component to be available
140
+ def current_component
141
+ model.try(:component)
142
+ end
143
+
144
+ def blocked_comments_for_unauthorized_user_warning_link
145
+ options = if current_component.present?
146
+ { resource: model }
147
+ else
148
+ { resource: model, permissions_holder: model }
149
+ end
150
+ action_authorized_link_to(:comment, commentable_path, options) do
151
+ t("decidim.components.comments.blocked_comments_for_unauthorized_user_warning")
152
+ end
153
+ end
132
154
  end
133
155
  end
134
156
  end
@@ -0,0 +1,29 @@
1
+ <div class="reveal edit-comment-modal" id="<%= "editCommentModal#{model.id}" %>" data-reveal>
2
+ <div class="reveal__header">
3
+ <h3 class="reveal__title"><%= t("decidim.components.edit_comment_modal_form.title") %></h3>
4
+ <button class="close-button" data-close aria-label="<%= t("decidim.components.edit_comment_modal_form.close") %>" type="button">
5
+ <span aria-hidden="true">&times;</span>
6
+ </button>
7
+ </div>
8
+ <%= form_for(form_object, url: decidim_comments.comment_path(comment), method: :put, remote: true, html: { id: form_id }) do |form| %>
9
+ <div class="field">
10
+ <label class="show-for-sr" for="<%= form_id %>">
11
+ <%= t("decidim.components.edit_comment_modal_form.form.body.label") %>
12
+ </label>
13
+ <div class="hashtags__container">
14
+ <%= form.text_area(
15
+ :body,
16
+ id: form_id,
17
+ rows: 4,
18
+ maxlength: comments_max_length,
19
+ required: true,
20
+ placeholder: t("decidim.components.edit_comment_modal_form.form.body.placeholder"),
21
+ label: false,
22
+ data: { remaining_characters: "##{form_id}-remaining-characters" }
23
+ ) %>
24
+ </div>
25
+ <button type="submit" data-close class="button button--sc"><%= t("decidim.components.edit_comment_modal_form.form.submit") %></button>
26
+ <span id="<%= form_id %>-remaining-characters" class="remaining-character-count"></span>
27
+ </div>
28
+ <% end %>
29
+ </div>
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Comments
5
+ # A cell to display a form for edditing a comment.
6
+ class EditCommentModalFormCell < Decidim::ViewModel
7
+ delegate :current_user, :user_signed_in?, to: :controller
8
+ alias comment model
9
+
10
+ private
11
+
12
+ def decidim_comments
13
+ Decidim::Comments::Engine.routes.url_helpers
14
+ end
15
+
16
+ def form_id
17
+ "edit_comment_#{comment.id}"
18
+ end
19
+
20
+ def form_object
21
+ Decidim::Comments::CommentForm.new(
22
+ body: comment.translated_body
23
+ )
24
+ end
25
+
26
+ def comments_max_length
27
+ return 1000 unless model.respond_to?(:component)
28
+ return component_comments_max_length if component_comments_max_length
29
+ return organization_comments_max_length if organization_comments_max_length
30
+
31
+ 1000
32
+ end
33
+
34
+ def component_comments_max_length
35
+ return unless model.component&.settings.respond_to?(:comments_max_length)
36
+
37
+ model.component.settings.comments_max_length if model.component.settings.comments_max_length.positive?
38
+ end
39
+
40
+ def organization_comments_max_length
41
+ return unless organization
42
+
43
+ organization.comments_max_length if organization.comments_max_length.positive?
44
+ end
45
+
46
+ def organization
47
+ return model.organization if model.respond_to?(:organization)
48
+
49
+ model.component.organization if model.component.organization.comments_max_length.positive?
50
+ end
51
+ end
52
+ end
53
+ end
@@ -39,7 +39,8 @@ module Decidim
39
39
  root_commentable: root_commentable(form.commentable),
40
40
  body: { I18n.locale => parsed.rewrite },
41
41
  alignment: form.alignment,
42
- decidim_user_group_id: form.user_group_id
42
+ decidim_user_group_id: form.user_group_id,
43
+ participatory_space: form.current_component.try(:participatory_space)
43
44
  }
44
45
 
45
46
  @comment = Decidim.traceability.create!(
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Comments
5
+ # A command with all the business logic to delete a comment
6
+ class DeleteComment < Rectify::Command
7
+ # Public: Initializes the command.
8
+ #
9
+ # comment - The comment to delete.
10
+ # current_user - The user performing the action.
11
+ def initialize(comment, current_user)
12
+ @comment = comment
13
+ @current_user = current_user
14
+ end
15
+
16
+ # Executes the command. Broadcasts these events:
17
+ #
18
+ # - :ok when everything is valid.
19
+ # - :invalid if comment isn't authored by current_user.
20
+ #
21
+ # Returns nothing.
22
+ def call
23
+ return broadcast(:invalid) unless comment.authored_by?(current_user)
24
+
25
+ delete_comment
26
+
27
+ broadcast(:ok)
28
+ end
29
+
30
+ private
31
+
32
+ attr_reader :comment, :current_user
33
+
34
+ def delete_comment
35
+ Decidim.traceability.perform_action!(
36
+ :delete,
37
+ comment,
38
+ current_user,
39
+ visibility: "public-only"
40
+ ) do
41
+ comment.delete!
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Comments
5
+ # A command with all the business logic to update an existing comment
6
+ class UpdateComment < Rectify::Command
7
+ # Public: Initializes the command.
8
+ #
9
+ # comment - Decidim::Comments::Comment
10
+ # current_user - Decidim::User
11
+ # form - A form object with the params.
12
+ def initialize(comment, current_user, form)
13
+ @comment = comment
14
+ @current_user = current_user
15
+ @form = form
16
+ end
17
+
18
+ # Executes the command. Broadcasts these events:
19
+ #
20
+ # - :ok when everything is valid.
21
+ # - :invalid if the form wasn't valid and we couldn't proceed.
22
+ #
23
+ # Returns nothing.
24
+ def call
25
+ return broadcast(:invalid) if form.invalid? || !comment.authored_by?(current_user)
26
+
27
+ update_comment
28
+
29
+ broadcast(:ok)
30
+ end
31
+
32
+ private
33
+
34
+ attr_reader :form, :comment, :current_user
35
+
36
+ def update_comment
37
+ parsed = Decidim::ContentProcessor.parse(form.body, current_organization: form.current_organization)
38
+
39
+ params = {
40
+ body: { I18n.locale => parsed.rewrite }
41
+ }
42
+
43
+ @comment = Decidim.traceability.update!(
44
+ comment,
45
+ current_user,
46
+ params,
47
+ visibility: "public-only",
48
+ edit: true
49
+ )
50
+
51
+ mentioned_users = parsed.metadata[:user].users
52
+ mentioned_groups = parsed.metadata[:user_group].groups
53
+ CommentCreation.publish(@comment, parsed.metadata)
54
+ send_notifications(mentioned_users, mentioned_groups)
55
+ end
56
+
57
+ def send_notifications(mentioned_users, mentioned_groups)
58
+ NewCommentNotificationCreator.new(comment, mentioned_users, mentioned_groups).create
59
+ end
60
+ end
61
+ end
62
+ end