diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss
index 91837158a..08bb60faa 100644
--- a/app/assets/stylesheets/application.scss
+++ b/app/assets/stylesheets/application.scss
@@ -30,6 +30,7 @@
@import "legislation";
@import "legislation_process";
@import "legislation_process_form";
+@import "moderation_actions";
@import "notification_item";
@import "community";
@import "stats";
@@ -40,6 +41,7 @@
@import "debates/**/*";
@import "layout/**/*";
@import "machine_learning/**/*";
+@import "moderation/**/*";
@import "proposals/**/*";
@import "relationable/**/*";
@import "sdg/**/*";
diff --git a/app/assets/stylesheets/layout.scss b/app/assets/stylesheets/layout.scss
index 45a7c45df..4c38b27d7 100644
--- a/app/assets/stylesheets/layout.scss
+++ b/app/assets/stylesheets/layout.scss
@@ -1877,6 +1877,10 @@ table {
padding: $line-height / 4;
position: relative;
+ &:empty {
+ display: none;
+ }
+
.divider {
color: $text-light;
display: inline-block;
diff --git a/app/assets/stylesheets/moderation/users/index.scss b/app/assets/stylesheets/moderation/users/index.scss
new file mode 100644
index 000000000..849153b24
--- /dev/null
+++ b/app/assets/stylesheets/moderation/users/index.scss
@@ -0,0 +1,18 @@
+.moderation-users-index {
+ th:last-child,
+ td:last-child {
+ text-align: $global-right;
+ }
+
+ .table-actions {
+ justify-content: flex-end;
+ }
+
+ .hide-link {
+ @include hollow-button($color-warning);
+ }
+
+ .block-link {
+ @include hollow-button($alert-color);
+ }
+}
diff --git a/app/assets/stylesheets/moderation_actions.scss b/app/assets/stylesheets/moderation_actions.scss
new file mode 100644
index 000000000..f3a00d662
--- /dev/null
+++ b/app/assets/stylesheets/moderation_actions.scss
@@ -0,0 +1,36 @@
+.moderation-actions {
+ &,
+ form {
+ display: inline;
+ }
+
+ button {
+ @include link;
+ }
+
+ @mixin separator {
+ content: "";
+ display: inline-block;
+ margin: 0 0.3em;
+ vertical-align: middle;
+ }
+
+ > * + *::before {
+ @include separator;
+ background: currentcolor;
+ height: 1em;
+ opacity: 0.5;
+ width: 1px;
+ }
+
+ .comment & {
+ > *::before {
+ @include separator;
+ background: $text-light;
+ border-radius: 100%;
+ opacity: 1;
+ height: 0.25em;
+ width: 0.25em;
+ }
+ }
+}
diff --git a/app/components/admin/action_component.rb b/app/components/admin/action_component.rb
index 2235bb682..33e00e01d 100644
--- a/app/components/admin/action_component.rb
+++ b/app/components/admin/action_component.rb
@@ -68,6 +68,8 @@ class Admin::ActionComponent < ApplicationComponent
else
t("admin.actions.confirm_action", action: text, name: record_name)
end
+ elsif options[:confirm].respond_to?(:call)
+ options[:confirm].call(record_name)
else
options[:confirm]
end
diff --git a/app/components/moderation/users/index_component.html.erb b/app/components/moderation/users/index_component.html.erb
new file mode 100644
index 000000000..ef5cb7db2
--- /dev/null
+++ b/app/components/moderation/users/index_component.html.erb
@@ -0,0 +1,47 @@
+
+ <%= t("moderation.users.index.title") %>
+
+ <%= render Admin::SearchComponent.new(label: t("moderation.users.index.search_placeholder")) %>
+
+ <% if users.present? %>
+ <%= page_entries_info users %>
+
+
+
+ | <%= t("admin.hidden_users.index.user") %> |
+ <%= t("admin.actions.actions") %> |
+
+
+ <% users.each do |user| %>
+
+ |
+ <%= user.name %>
+ |
+
+ <% if user.hidden? %>
+ <%= status(user) %>
+ <% else %>
+ <%= render Admin::TableActionsComponent.new(user, actions: []) do |actions| %>
+ <%= actions.action(
+ :hide,
+ text: t("moderation.users.index.hide"),
+ confirm: ->(name) { t("moderation.users.index.confirm_hide", name: name) },
+ method: :put
+ ) %>
+ <%= actions.action(
+ :block,
+ text: t("moderation.users.index.block"),
+ confirm: ->(name) { t("moderation.users.index.confirm_block", name: name) },
+ method: :put
+ ) %>
+ <% end %>
+ <% end %>
+ |
+
+ <% end %>
+
+
+
+ <%= paginate users %>
+ <% end %>
+
diff --git a/app/components/moderation/users/index_component.rb b/app/components/moderation/users/index_component.rb
new file mode 100644
index 000000000..ddfa20e85
--- /dev/null
+++ b/app/components/moderation/users/index_component.rb
@@ -0,0 +1,17 @@
+class Moderation::Users::IndexComponent < ApplicationComponent
+ attr_reader :users
+
+ def initialize(users)
+ @users = users
+ end
+
+ private
+
+ def status(user)
+ t("admin.activity.show.actions.#{activity_action(user)}")
+ end
+
+ def activity_action(user)
+ Activity.where(actionable: user, action: [:hide, :block]).last&.action || "block"
+ end
+end
diff --git a/app/components/shared/moderation_actions_component.html.erb b/app/components/shared/moderation_actions_component.html.erb
new file mode 100644
index 000000000..a3aed9369
--- /dev/null
+++ b/app/components/shared/moderation_actions_component.html.erb
@@ -0,0 +1,23 @@
+
+ <% if can? :hide, record %>
+ <%= render Admin::ActionComponent.new(
+ :hide,
+ record,
+ path: hide_path,
+ method: :put,
+ remote: true,
+ confirm: true
+ ) %>
+ <% end %>
+
+ <% if can? :hide, author %>
+ <%= render Admin::ActionComponent.new(
+ :block_author,
+ author,
+ path: block_moderation_user_path(author),
+ id: dom_id(author, "#{dom_id(record)}_block_author"),
+ method: :put,
+ confirm: ->(name) { t("moderation.users.index.confirm_block", name: name) }
+ ) %>
+ <% end %>
+
diff --git a/app/components/shared/moderation_actions_component.rb b/app/components/shared/moderation_actions_component.rb
new file mode 100644
index 000000000..f9f287e09
--- /dev/null
+++ b/app/components/shared/moderation_actions_component.rb
@@ -0,0 +1,22 @@
+class Shared::ModerationActionsComponent < ApplicationComponent
+ attr_reader :record
+ delegate :can?, to: :helpers
+
+ def initialize(record)
+ @record = record
+ end
+
+ def render?
+ can?(:hide, record) || can?(:hide, author)
+ end
+
+ private
+
+ def author
+ record.author
+ end
+
+ def hide_path
+ polymorphic_path([:moderation, record], action: :hide)
+ end
+end
diff --git a/app/controllers/admin/hidden_users_controller.rb b/app/controllers/admin/hidden_users_controller.rb
index 1b5635270..86801fcda 100644
--- a/app/controllers/admin/hidden_users_controller.rb
+++ b/app/controllers/admin/hidden_users_controller.rb
@@ -4,7 +4,7 @@ class Admin::HiddenUsersController < Admin::BaseController
before_action :load_user, only: [:confirm_hide, :restore]
def index
- @users = User.only_hidden.send(@current_filter).page(params[:page])
+ @users = User.only_hidden.send(@current_filter).order(hidden_at: :desc).page(params[:page])
end
def show
diff --git a/app/controllers/moderation/users_controller.rb b/app/controllers/moderation/users_controller.rb
index 2c958eda8..b3a043d96 100644
--- a/app/controllers/moderation/users_controller.rb
+++ b/app/controllers/moderation/users_controller.rb
@@ -6,16 +6,16 @@ class Moderation::UsersController < Moderation::BaseController
def index
end
- def hide_in_moderation_screen
- block_user
+ def hide
+ hide_user
redirect_with_query_params_to({ action: :index }, { notice: I18n.t("moderation.users.notice_hide") })
end
- def hide
+ def block
block_user
- redirect_to debates_path
+ redirect_with_query_params_to index_path_options, { notice: I18n.t("moderation.users.notice_block") }
end
private
@@ -24,8 +24,26 @@ class Moderation::UsersController < Moderation::BaseController
@users = User.with_hidden.search(params[:search]).page(params[:page]).for_render
end
+ def hide_user
+ @user.hide
+ Activity.log(current_user, :hide, @user)
+ end
+
def block_user
@user.block
Activity.log(current_user, :block, @user)
end
+
+ def index_path_options
+ if request.referer
+ referer_params = Rails.application.routes.recognize_path(request.referer)
+
+ referer_params.except(:id).merge({
+ controller: "/#{referer_params[:controller]}",
+ action: :index
+ })
+ else
+ { action: :index }
+ end
+ end
end
diff --git a/app/models/ability.rb b/app/models/ability.rb
index afe6f416e..45207eaae 100644
--- a/app/models/ability.rb
+++ b/app/models/ability.rb
@@ -2,10 +2,6 @@ class Ability
include CanCan::Ability
def initialize(user)
- # If someone can hide something, he can also hide it
- # from the moderation screen
- alias_action :hide_in_moderation_screen, to: :hide
-
if user # logged-in users
merge Abilities::Valuator.new(user) if user.valuator?
diff --git a/app/models/comment.rb b/app/models/comment.rb
index 89e6c88f1..443d2322d 100644
--- a/app/models/comment.rb
+++ b/app/models/comment.rb
@@ -83,6 +83,10 @@ class Comment < ApplicationRecord
self.user = author
end
+ def human_name
+ body.truncate(32)
+ end
+
def total_votes
cached_votes_total
end
diff --git a/app/models/user.rb b/app/models/user.rb
index 0e4be645d..0c6e03bfe 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -241,6 +241,7 @@ class User < ApplicationRecord
Debate.hide_all debate_ids
Comment.hide_all comment_ids
+ Legislation::Proposal.hide_all legislation_proposal_ids
Proposal.hide_all proposal_ids
Budget::Investment.hide_all budget_investment_ids
ProposalNotification.hide_all ProposalNotification.where(author_id: id).ids
@@ -250,6 +251,7 @@ class User < ApplicationRecord
ActiveRecord::Base.transaction do
Debate.restore_all debates.where("hidden_at >= ?", hidden_at)
Comment.restore_all comments.where("hidden_at >= ?", hidden_at)
+ Legislation::Proposal.restore_all legislation_proposals.only_hidden.where("hidden_at >= ?", hidden_at)
Proposal.restore_all proposals.where("hidden_at >= ?", hidden_at)
Budget::Investment.restore_all budget_investments.where("hidden_at >= ?", hidden_at)
ProposalNotification.restore_all(
diff --git a/app/views/budgets/investments/_actions.html.erb b/app/views/budgets/investments/_actions.html.erb
index 9711a8268..8fd2110fa 100644
--- a/app/views/budgets/investments/_actions.html.erb
+++ b/app/views/budgets/investments/_actions.html.erb
@@ -1,10 +1 @@
-<% if can? :hide, investment %>
- <%= link_to t("admin.actions.hide").capitalize, hide_moderation_budget_investment_path(investment),
- method: :put, remote: true, data: { confirm: t("admin.actions.confirm_action", action: t("admin.actions.hide"), name: investment.title) } %>
-<% end %>
-
-<% if can? :hide, investment.author %>
- |
- <%= link_to t("admin.actions.hide_author").capitalize, hide_moderation_user_path(investment.author_id),
- method: :put, data: { confirm: t("admin.actions.confirm_action", action: t("admin.actions.hide_author"), name: investment.author.name) } %>
-<% end %>
+<%= render Shared::ModerationActionsComponent.new(investment) %>
diff --git a/app/views/comments/_actions.html.erb b/app/views/comments/_actions.html.erb
index 13a97c96a..7780d9167 100644
--- a/app/views/comments/_actions.html.erb
+++ b/app/views/comments/_actions.html.erb
@@ -2,23 +2,14 @@
<%= render "shared/flag_actions", flaggable: comment, divider: true %>
-
- <% if can? :hide, comment %>
+<% if can?(:hide, comment) || can?(:hide, comment.user) %>
+ <% if comment.author == current_user %>
•
- <% if comment.author == current_user %>
- <%= link_to t("comments.actions.delete"),
- hide_comment_path(comment),
- method: :put, remote: true, class: "delete-comment",
- data: { confirm: t("comments.actions.confirm_delete") } %>
- <% else %>
- <%= link_to t("admin.actions.hide").capitalize, hide_moderation_comment_path(comment),
- method: :put, remote: true, data: { confirm: t("admin.actions.confirm_action", action: t("admin.actions.hide"), name: comment.body.truncate(32)) } %>
- <% end %>
+ <%= link_to t("comments.actions.delete"),
+ hide_comment_path(comment),
+ method: :put, remote: true, class: "delete-comment",
+ data: { confirm: t("comments.actions.confirm_delete") } %>
+ <% else %>
+ <%= render Shared::ModerationActionsComponent.new(comment) %>
<% end %>
-
- <% if can? :hide, comment.user %>
- •
- <%= link_to t("admin.actions.hide_author").capitalize, hide_moderation_user_path(comment.user_id),
- method: :put, data: { confirm: t("admin.actions.confirm_action", action: t("admin.actions.hide_author"), name: comment.author.name) } %>
- <% end %>
-
+<% end %>
diff --git a/app/views/comments/_comment.html.erb b/app/views/comments/_comment.html.erb
index ae0cb1276..0ea042746 100644
--- a/app/views/comments/_comment.html.erb
+++ b/app/views/comments/_comment.html.erb
@@ -2,7 +2,7 @@
<% cache [locale_and_user_status(comment), comment, commentable_cache_key(comment.commentable), comment.author] do %>
<%= t("comments.comment.deleted") %>
diff --git a/app/views/debates/_actions.html.erb b/app/views/debates/_actions.html.erb index 1959ef29a..3605d3fcf 100644 --- a/app/views/debates/_actions.html.erb +++ b/app/views/debates/_actions.html.erb @@ -1,13 +1,4 @@ -<% if can? :hide, debate %> - <%= link_to t("admin.actions.hide").capitalize, hide_moderation_debate_path(debate), - method: :put, remote: true, data: { confirm: t("admin.actions.confirm_action", action: t("admin.actions.hide"), name: debate.title) } %> -<% end %> - -<% if can? :hide, debate.author %> - | - <%= link_to t("admin.actions.hide_author").capitalize, hide_moderation_user_path(debate.author_id), - method: :put, data: { confirm: t("admin.actions.confirm_action", action: t("admin.actions.hide_author"), name: debate.author.name) } %> -<% end %> +<%= render Shared::ModerationActionsComponent.new(debate) %> <% if can? :mark_featured, debate %> | diff --git a/app/views/legislation/proposals/_actions.html.erb b/app/views/legislation/proposals/_actions.html.erb index a887f422c..a0f59692d 100644 --- a/app/views/legislation/proposals/_actions.html.erb +++ b/app/views/legislation/proposals/_actions.html.erb @@ -1,10 +1 @@ -<% if can? :hide, proposal %> - <%= link_to t("admin.actions.hide").capitalize, hide_moderation_legislation_proposal_path(proposal), - method: :put, remote: true, data: { confirm: t("admin.actions.confirm_action", action: t("admin.actions.hide"), name: proposal.title) } %> -<% end %> - -<% if can? :hide, proposal.author %> - | - <%= link_to t("admin.actions.hide_author").capitalize, hide_moderation_user_path(proposal.author_id), - method: :put, data: { confirm: t("admin.actions.confirm_action", action: t("admin.actions.hide_author"), name: proposal.author.name) } %> -<% end %> +<%= render Shared::ModerationActionsComponent.new(proposal) %> diff --git a/app/views/moderation/users/index.html.erb b/app/views/moderation/users/index.html.erb index 9008f8fec..39b526378 100644 --- a/app/views/moderation/users/index.html.erb +++ b/app/views/moderation/users/index.html.erb @@ -1,29 +1 @@ -<%= t("moderation.users.index.title") %>
- -<%= render Admin::SearchComponent.new(label: t("moderation.users.index.search_placeholder")) %> - -<% if @users.present? %> -<%= page_entries_info @users %>
-<% end %> - -<%= notification.created_at.to_date %>
<%= simple_format sanitize_and_auto_link(notification.body), {}, sanitize: false %> - - <%= render "proposal_notifications/actions", notification: notification %> - + <%= render "proposal_notifications/actions", notification: notification %>