Merge pull request #4214 from carlosiniesta/3552-soft-block-users

Allow hiding users without hiding their content
This commit is contained in:
Javi Martín
2021-12-30 17:04:43 +01:00
committed by GitHub
46 changed files with 536 additions and 169 deletions

View File

@@ -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/**/*";

View File

@@ -1877,6 +1877,10 @@ table {
padding: $line-height / 4;
position: relative;
&:empty {
display: none;
}
.divider {
color: $text-light;
display: inline-block;

View File

@@ -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);
}
}

View File

@@ -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;
}
}
}

View File

@@ -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

View File

@@ -0,0 +1,47 @@
<main class="moderation-users-index">
<h2><%= t("moderation.users.index.title") %></h2>
<%= render Admin::SearchComponent.new(label: t("moderation.users.index.search_placeholder")) %>
<% if users.present? %>
<h3><%= page_entries_info users %></h3>
<table id="moderation_users" class="moderation-users">
<thead>
<th><%= t("admin.hidden_users.index.user") %></th>
<th><%= t("admin.actions.actions") %></th>
</thead>
<tbody>
<% users.each do |user| %>
<tr>
<td>
<%= user.name %>
</td>
<td>
<% 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 %>
</td>
</tr>
<% end %>
</tbody>
</table>
<%= paginate users %>
<% end %>
</main>

View File

@@ -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

View File

@@ -0,0 +1,23 @@
<div class="moderation-actions">
<% 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 %>
</div>

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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?

View File

@@ -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

View File

@@ -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(

View File

@@ -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 %>
&nbsp;|&nbsp;
<%= 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) %>

View File

@@ -2,23 +2,14 @@
<%= render "shared/flag_actions", flaggable: comment, divider: true %>
</span>
<span class="js-moderation-actions">
<% if can? :hide, comment %>
<% if can?(:hide, comment) || can?(:hide, comment.user) %>
<% if comment.author == current_user %>
<span class="divider">&nbsp;&bull;&nbsp;</span>
<% 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 %>
<span class="divider">&nbsp;&bull;&nbsp;</span>
<%= 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 %>
</span>
<% end %>

View File

@@ -2,7 +2,7 @@
<% cache [locale_and_user_status(comment), comment, commentable_cache_key(comment.commentable), comment.author] do %>
<div id="<%= dom_id(comment) %>" class="comment small-12">
<div class="comment-body">
<% if comment.hidden? || comment.user.hidden? %>
<% if comment.hidden? %>
<% if comment.children.size > 0 %>
<div class="callout secondary">
<p><%= t("comments.comment.deleted") %></p>

View File

@@ -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 %>
&nbsp;|&nbsp;
<%= 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 %>
&nbsp;|&nbsp;

View File

@@ -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 %>
&nbsp;|&nbsp;
<%= 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) %>

View File

@@ -1,29 +1 @@
<h2><%= t("moderation.users.index.title") %></h2>
<%= render Admin::SearchComponent.new(label: t("moderation.users.index.search_placeholder")) %>
<% if @users.present? %>
<h3><%= page_entries_info @users %></h3>
<% end %>
<table id="moderation_users">
<tbody>
<% @users.each do |user| %>
<tr>
<td>
<%= user.name %>
</td>
<td class="text-right">
<% if user.hidden? %>
<%= t("moderation.users.index.hidden") %>
<% else %>
<%= link_to t("moderation.users.index.hide"), hide_in_moderation_screen_moderation_user_path(user, request.query_parameters),
method: :put, class: "button hollow alert" %>
</td>
<% end %>
</tr>
<% end %>
</tbody>
</table>
<%= paginate @users %>
<%= render Moderation::Users::IndexComponent.new(@users) %>

View File

@@ -1,16 +1 @@
<% if can? :hide, (notification || notification.author) %>
<div class="reply">
<span class="js-moderation-actions">
<% if can? :hide, notification %>
<%= link_to t("admin.actions.hide").capitalize, hide_moderation_proposal_notification_path(notification),
method: :put, remote: true, data: { confirm: t("admin.actions.confirm_action", action: t("admin.actions.hide"), name: notification.title) } %>
<% end %>
<% if can? :hide, notification.author %>
<span class="divider">&nbsp;&bull;&nbsp;</span>
<%= link_to t("admin.actions.hide_author").capitalize, hide_moderation_user_path(notification.author_id),
method: :put, data: { confirm: t("admin.actions.confirm_action", action: t("admin.actions.hide_author"), name: notification.author.name) } %>
<% end %>
</span>
</div>
<% end %>
<div class="reply"><%= render Shared::ModerationActionsComponent.new(notification) %></div>

View File

@@ -1,10 +1 @@
<% if can? :hide, proposal %>
<%= link_to t("admin.actions.hide").capitalize, hide_moderation_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 %>
&nbsp;|&nbsp;
<%= 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) %>

View File

@@ -13,9 +13,7 @@
<p class="more-info"><%= notification.created_at.to_date %></p>
<%= simple_format sanitize_and_auto_link(notification.body), {}, sanitize: false %>
<span class="js-flag-actions">
<%= render "proposal_notifications/actions", notification: notification %>
</span>
<%= render "proposal_notifications/actions", notification: notification %>
</div>
<% end %>
</div>

View File

@@ -4,12 +4,12 @@ en:
title: Administration
actions:
actions: Actions
block_author: "Block author"
confirm_action: "Are you sure? %{action} \"%{name}\""
confirm_delete: "Are you sure? This action will delete \"%{name}\" and can't be undone."
confirm_hide: Confirm moderation
delete: "Delete"
hide: Hide
hide_author: Hide author
label: "%{action} %{name}"
restore: Restore
mark_featured: Featured

View File

@@ -101,8 +101,11 @@ en:
title: Proposal notifications
users:
index:
hidden: Blocked
hide: Block
block: Block
confirm_block: "Are you sure? This will hide the user \"%{name}\" and all their contents."
confirm_hide: "Are you sure? This will hide the user \"%{name}\" without hiding their contents."
hide: Hide
search_placeholder: email or name of user
title: Block users
notice_hide: User blocked. All of this user's debates and comments have been hidden.
notice_block: The user has been blocked. All contents authored by this user have been hidden.
notice_hide: The user has been hidden. Contents authored by this user are still available.

View File

@@ -4,12 +4,12 @@ es:
title: Administración
actions:
actions: Acciones
block_author: "Bloquear al autor"
confirm_action: "¿Estás seguro? %{action} \"%{name}\""
confirm_delete: "¿Estás seguro? Esta acción borrará \"%{name}\" y no se puede deshacer."
confirm_hide: Confirmar moderación
delete: Borrar
hide: Ocultar
hide_author: Bloquear al autor
label: "%{action} %{name}"
restore: Volver a mostrar
mark_featured: Destacar

View File

@@ -101,8 +101,11 @@ es:
title: Notificaciones de propuestas
users:
index:
hidden: Bloqueado
hide: Bloquear
block: Bloquear
confirm_block: "¿Seguro? Esto ocultará a \"%{name}\" así como todos sus contenidos."
confirm_hide: "¿Seguro? Esto ocultará a \"%{name}\" sin ocultar sus contenidos."
hide: Ocultar
search_placeholder: email o nombre de usuario
title: Bloquear usuarios
notice_hide: Usuario bloqueado. Se han ocultado todos sus debates y comentarios.
notice_block: Usuario bloqueado. Se han ocultado todos sus contenidos y comentarios.
notice_hide: Usuario ocultado. Todos sus contenidos y comentarios siguen disponibles.

View File

@@ -4,7 +4,7 @@ namespace :moderation do
resources :users, only: :index do
member do
put :hide
put :hide_in_moderation_screen
put :block
end
end

View File

@@ -0,0 +1,103 @@
require "rails_helper"
describe Moderation::Users::IndexComponent, controller: Moderation::UsersController do
describe "actions or status" do
let(:component) { Moderation::Users::IndexComponent.new(User.with_hidden.page(1)) }
it "shows actions to block or hide users" do
create(:user)
render_inline component
page.find("table") do |table|
expect(table).to have_button "Hide"
expect(table).to have_button "Block"
expect(table).not_to have_content "Blocked"
expect(table).not_to have_content "Hidden"
end
end
context "for hidden users" do
it "shows 'blocked' when the user has been blocked" do
user = create(:user, :hidden)
Activity.log(nil, :block, user)
render_inline component
page.find("table") do |table|
expect(table).to have_content "Blocked"
expect(table).not_to have_content "Hidden"
expect(table).not_to have_button
end
end
it "shows 'hidden' when the user has been hidden" do
user = create(:user, :hidden)
Activity.log(nil, :hide, user)
render_inline component
page.find("table") do |table|
expect(table).to have_content "Hidden"
expect(table).not_to have_content "Blocked"
expect(table).not_to have_button
end
end
it "shows 'blocked' when there are no activities to hide the user" do
create(:user, :hidden)
render_inline component
page.find("table") do |table|
expect(table).to have_content "Blocked"
end
end
it "is not affected by activities for other users" do
blocked = create(:user, :hidden, username: "Very bad user")
hidden = create(:user, :hidden, username: "Slightly bad user")
Activity.log(nil, :block, blocked)
Activity.log(nil, :hide, hidden)
render_inline component
page.find("tr", text: "Very bad user") do |row|
expect(row).to have_content "Blocked"
end
page.find("tr", text: "Slightly bad user") do |row|
expect(row).to have_content "Hidden"
end
end
it "doesn't consider activities other than block or hide" do
user = create(:user, :hidden)
Activity.log(nil, :block, user)
Activity.log(nil, :restore, user)
render_inline component
page.find("table") do |table|
expect(table).to have_content "Blocked"
end
end
it "shows actions after the user has been restored" do
user = create(:user, :hidden)
Activity.log(nil, :block, user)
user.restore
render_inline component
page.find("table") do |table|
expect(table).to have_button "Hide"
expect(table).to have_button "Block"
expect(table).not_to have_content "Blocked"
expect(table).not_to have_content "Hidden"
end
end
end
end
end

View File

@@ -0,0 +1,68 @@
require "rails_helper"
describe Shared::ModerationActionsComponent do
include Rails.application.routes.url_helpers
before { sign_in(create(:administrator).user) }
describe "Hide button" do
it "is shown for debates" do
debate = create(:debate)
render_inline Shared::ModerationActionsComponent.new(debate)
page.find("form[action='#{hide_moderation_debate_path(debate)}']") do
expect(page).to have_button "Hide"
end
end
it "is shown for proposals" do
proposal = create(:proposal)
render_inline Shared::ModerationActionsComponent.new(proposal)
page.find("form[action='#{hide_moderation_proposal_path(proposal)}']") do
expect(page).to have_button "Hide"
end
end
it "is shown for proposal notifications" do
notification = create(:proposal_notification)
render_inline Shared::ModerationActionsComponent.new(notification)
page.find("form[action='#{hide_moderation_proposal_notification_path(notification)}']") do
expect(page).to have_button "Hide"
end
end
it "is shown for comments" do
comment = create(:comment)
render_inline Shared::ModerationActionsComponent.new(comment)
page.find("form[action='#{hide_moderation_comment_path(comment)}']") do
expect(page).to have_button "Hide"
end
end
it "is shown for budget investments" do
investment = create(:budget_investment)
render_inline Shared::ModerationActionsComponent.new(investment)
page.find("form[action='#{hide_moderation_budget_investment_path(investment)}']") do
expect(page).to have_button "Hide"
end
end
it "is shown for legislation proposals" do
proposal = create(:legislation_proposal)
render_inline Shared::ModerationActionsComponent.new(proposal)
page.find("form[action='#{hide_moderation_legislation_proposal_path(proposal)}']") do
expect(page).to have_button "Hide"
end
end
end
end

View File

@@ -2,14 +2,44 @@ require "rails_helper"
describe Moderation::UsersController do
before { sign_in create(:moderator).user }
let(:user) { create(:user, email: "user@consul.dev") }
describe "PUT hide_in_moderation_screen" do
describe "PUT hide" do
it "keeps query parameters while using protected redirects" do
user = create(:user, email: "user@consul.dev")
get :hide_in_moderation_screen, params: { id: user, search: "user@consul.dev", host: "evil.dev" }
get :hide, params: { id: user, name_or_email: "user@consul.dev", host: "evil.dev" }
expect(response).to redirect_to "/moderation/users?name_or_email=user%40consul.dev"
end
end
describe "PUT block" do
it "keeps query parameters while using protected redirects" do
user = create(:user, email: "user@consul.dev")
get :block, params: { id: user, search: "user@consul.dev", host: "evil.dev" }
expect(response).to redirect_to "/moderation/users?search=user%40consul.dev"
end
it "redirects to the index of the section where it was called with a notice" do
proposal = create(:proposal, author: user)
request.env["HTTP_REFERER"] = proposal_path(proposal)
put :block, params: { id: user }
expect(response).to redirect_to proposals_path
expect(flash[:notice]).to eq "The user has been blocked. All contents authored by this user have been hidden."
end
it "redirects to the index with a nested resource" do
investment = create(:budget_investment, author: user)
request.env["HTTP_REFERER"] = budget_investment_path(investment.budget, investment)
put :block, params: { id: user }
expect(response).to redirect_to budget_investments_path(investment.budget)
end
end
end

View File

@@ -164,5 +164,9 @@ FactoryBot.define do
terms_of_service { "1" }
process factory: :legislation_process
author factory: :user
trait :hidden do
hidden_at { Time.current }
end
end
end

View File

@@ -52,7 +52,6 @@ describe Abilities::Moderator do
let(:ignored_proposal) { create(:proposal, :with_ignored_flag) }
it { should be_able_to(:hide, comment) }
it { should be_able_to(:hide_in_moderation_screen, comment) }
it { should_not be_able_to(:hide, hidden_comment) }
it { should be_able_to(:hide, own_comment) }
@@ -60,12 +59,10 @@ describe Abilities::Moderator do
it { should_not be_able_to(:moderate, own_comment) }
it { should be_able_to(:hide, debate) }
it { should be_able_to(:hide_in_moderation_screen, debate) }
it { should_not be_able_to(:hide, hidden_debate) }
it { should_not be_able_to(:hide, own_debate) }
it { should be_able_to(:hide, proposal) }
it { should be_able_to(:hide_in_moderation_screen, proposal) }
it { should be_able_to(:hide, own_proposal) }
it { should_not be_able_to(:hide, hidden_proposal) }

View File

@@ -758,6 +758,21 @@ describe User do
end
end
describe "#block" do
it "hides legislation proposals created by the user" do
user = create(:user)
other_user = create(:user)
proposal = create(:legislation_proposal, author: user)
other_proposal = create(:legislation_proposal, author: other_user)
user.block
expect(Legislation::Proposal.all).to eq [other_proposal]
expect(Legislation::Proposal.with_hidden).to match_array [proposal, other_proposal]
end
end
describe "#full_restore" do
it "restore all previous hidden user content" do
user = create(:user, :hidden)
@@ -768,18 +783,21 @@ describe User do
investment = create(:budget_investment, :hidden, author: user)
proposal = create(:proposal, :hidden, author: user)
proposal_notification = create(:proposal_notification, :hidden, proposal: proposal)
legislation_proposal = create(:legislation_proposal, :hidden, author: user)
old_hidden_comment = create(:comment, hidden_at: 3.days.ago, author: user)
old_hidden_debate = create(:debate, hidden_at: 3.days.ago, author: user)
old_hidden_investment = create(:budget_investment, hidden_at: 3.days.ago, author: user)
old_hidden_proposal = create(:proposal, hidden_at: 3.days.ago, author: user)
old_hidden_proposal_notification = create(:proposal_notification, hidden_at: 3.days.ago, proposal: proposal)
old_hidden_legislation_proposal = create(:legislation_proposal, hidden_at: 3.days.ago, author: user)
other_user_comment = create(:comment, :hidden, author: other_user)
other_user_debate = create(:debate, :hidden, author: other_user)
other_user_proposal = create(:proposal, :hidden, author: other_user)
other_user_investment = create(:budget_investment, :hidden, author: other_user)
other_user_proposal_notification = create(:proposal_notification, :hidden, proposal: other_user_proposal)
other_user_legislation_proposal = create(:legislation_proposal, :hidden, author: other_user)
user.full_restore
@@ -788,18 +806,21 @@ describe User do
expect(investment.reload).not_to be_hidden
expect(proposal.reload).not_to be_hidden
expect(proposal_notification.reload).not_to be_hidden
expect(legislation_proposal.reload).not_to be_hidden
expect(old_hidden_comment.reload).to be_hidden
expect(old_hidden_debate.reload).to be_hidden
expect(old_hidden_investment.reload).to be_hidden
expect(old_hidden_proposal.reload).to be_hidden
expect(old_hidden_proposal_notification.reload).to be_hidden
expect(old_hidden_legislation_proposal.reload).to be_hidden
expect(other_user_comment.reload).to be_hidden
expect(other_user_debate.reload).to be_hidden
expect(other_user_investment.reload).to be_hidden
expect(other_user_proposal.reload).to be_hidden
expect(other_user_proposal_notification.reload).to be_hidden
expect(other_user_legislation_proposal.reload).to be_hidden
end
end
end

View File

@@ -14,7 +14,7 @@ describe "Admin activity" do
visit proposal_path(proposal)
within("#proposal_#{proposal.id}") do
accept_confirm("Are you sure? Hide \"#{proposal.title}\"") { click_link "Hide" }
accept_confirm("Are you sure? Hide \"#{proposal.title}\"") { click_button "Hide" }
end
expect(page).to have_css("#proposal_#{proposal.id}.faded")
@@ -82,7 +82,7 @@ describe "Admin activity" do
visit debate_path(debate)
within("#debate_#{debate.id}") do
accept_confirm("Are you sure? Hide \"#{debate.title}\"") { click_link "Hide" }
accept_confirm("Are you sure? Hide \"#{debate.title}\"") { click_button "Hide" }
end
expect(page).to have_css("#debate_#{debate.id}.faded")
@@ -150,7 +150,7 @@ describe "Admin activity" do
visit debate_path(debate)
within("#comment_#{comment.id}") do
accept_confirm("Are you sure? Hide \"#{comment.body}\"") { click_link "Hide" }
accept_confirm("Are you sure? Hide \"#{comment.body}\"") { click_button "Hide" }
expect(page).to have_css(".faded")
end
@@ -217,9 +217,11 @@ describe "Admin activity" do
visit proposal_path(proposal)
within("#proposal_#{proposal.id}") do
accept_confirm("Are you sure? Hide author \"#{proposal.author.name}\"") { click_link "Hide author" }
accept_confirm("Are you sure? This will hide the user \"#{proposal.author.name}\" and all their contents.") do
click_button "Block author"
end
expect(page).to have_current_path(debates_path)
expect(page).to have_current_path(proposals_path)
end
visit admin_activity_path
@@ -239,9 +241,11 @@ describe "Admin activity" do
visit moderation_users_path(search: user.username)
within("#moderation_users") do
click_link "Block"
accept_confirm { click_button "Block" }
end
expect(page).to have_content "The user has been blocked"
visit admin_activity_path
within first("tbody tr") do

View File

@@ -13,10 +13,12 @@ describe "Admin hidden comments", :admin do
visit proposal_path(proposal)
within("#proposal_#{proposal.id}") do
accept_confirm("Are you sure? Hide author \"#{proposal.author.name}\"") { click_link "Hide author" }
accept_confirm("Are you sure? This will hide the user \"#{proposal.author.name}\" and all their contents.") do
click_button "Block author"
end
end
expect(page).to have_current_path debates_path
expect(page).to have_current_path proposals_path
visit admin_hidden_comments_path

View File

@@ -83,7 +83,7 @@ describe "Admin hidden users", :admin do
visit admin_hidden_users_path(filter: "with_confirmed_hide", page: 2)
accept_confirm("Are you sure? Restore \"#{users[2].name}\"") do
accept_confirm("Are you sure? Restore \"#{users[-3].name}\"") do
click_button "Restore", match: :first, exact: true
end

View File

@@ -275,7 +275,7 @@ describe "Internal valuation comments on Budget::Investments" do
expect(page).to have_no_css(".comment-votes")
expect(page).to have_no_css(".js-flag-actions")
expect(page).to have_no_css(".js-moderation-actions")
expect(page).to have_no_css(".moderation-actions")
end
end

View File

@@ -371,6 +371,16 @@ describe "Commenting debates" do
end
end
scenario "Show comment when the author is hidden" do
create(:comment, body: "This is pointless", commentable: debate, author: create(:user, :hidden))
visit debate_path(debate)
within ".comment", text: "This is pointless" do
expect(page).to have_content "User deleted"
end
end
scenario "Errors on reply" do
comment = create(:comment, commentable: debate, user: user)

View File

@@ -10,7 +10,7 @@ describe "Moderate budget investments" do
login_as(mod.user)
visit budget_investment_path(budget, investment)
accept_confirm("Are you sure? Hide \"#{investment.title}\"") { click_link "Hide" }
accept_confirm("Are you sure? Hide \"#{investment.title}\"") { click_button "Hide" }
expect(page).to have_css(".faded", count: 2)
@@ -23,12 +23,11 @@ describe "Moderate budget investments" do
login_as(mod.user)
visit budget_investment_path(budget, investment)
accept_confirm("Are you sure? Hide author \"#{investment.author.name}\"") { click_link "Hide author" }
expect(page).to have_current_path(debates_path)
visit budget_investments_path(budget.id, heading_id: heading.id)
accept_confirm("Are you sure? This will hide the user \"#{investment.author.name}\" and all their contents.") do
click_button "Block author"
end
expect(page).to have_current_path(budget_investments_path(budget))
expect(page).not_to have_content(investment.title)
end
@@ -39,8 +38,8 @@ describe "Moderate budget investments" do
visit budget_investment_path(budget, investment)
within "#budget_investment_#{investment.id}" do
expect(page).not_to have_link("Hide")
expect(page).not_to have_link("Hide author")
expect(page).not_to have_button "Hide"
expect(page).not_to have_button "Block author"
end
end
@@ -75,7 +74,7 @@ describe "Moderate budget investments" do
click_button "Search"
within "tr", text: investment.author.name do
expect(page).to have_link "Block"
expect(page).to have_button "Block"
end
end

View File

@@ -11,7 +11,7 @@ describe "Moderate comments" do
visit debate_path(comment.commentable)
within("#comment_#{comment.id}") do
accept_confirm("Are you sure? Hide") { click_link "Hide" }
accept_confirm("Are you sure? Hide") { click_button "Hide" }
expect(page).to have_css(".comment .faded")
end
@@ -31,8 +31,8 @@ describe "Moderate comments" do
visit debate_path(comment.commentable)
within("#comment_#{comment.id}") do
expect(page).not_to have_link("Hide")
expect(page).not_to have_link("Block author")
expect(page).not_to have_button "Hide"
expect(page).not_to have_button "Block author"
end
end
@@ -95,7 +95,7 @@ describe "Moderate comments" do
click_button "Search"
within "tr", text: comment.user.name do
expect(page).to have_link "Block"
expect(page).to have_button "Block"
end
end

View File

@@ -11,7 +11,7 @@ describe "Moderate debates" do
visit debate_path(debate)
within("#debate_#{debate.id}") do
accept_confirm("Are you sure? Hide") { click_link "Hide" }
accept_confirm("Are you sure? Hide") { click_button "Hide" }
end
expect(find("div#debate_#{debate.id}.faded")).to have_text debate.title
@@ -30,8 +30,8 @@ describe "Moderate debates" do
visit debate_path(debate)
within("#debate_#{debate.id}") do
expect(page).not_to have_link("Hide")
expect(page).not_to have_link("Block author")
expect(page).not_to have_button "Hide"
expect(page).not_to have_button "Block author"
end
end
@@ -66,7 +66,7 @@ describe "Moderate debates" do
click_button "Search"
within "tr", text: debate.author.name do
expect(page).to have_link "Block"
expect(page).to have_button "Block"
end
end

View File

@@ -11,7 +11,7 @@ describe "Moderate legislation proposals" do
visit legislation_process_proposal_path(legislation_process, legislation_proposal)
within("#legislation_proposal_#{legislation_proposal.id}") do
accept_confirm("Are you sure? Hide \"#{legislation_proposal.title}\"") { click_link "Hide" }
accept_confirm("Are you sure? Hide \"#{legislation_proposal.title}\"") { click_button "Hide" }
end
expect(page).to have_css("#legislation_proposal_#{legislation_proposal.id}.faded")
@@ -21,6 +21,6 @@ describe "Moderate legislation proposals" do
visit legislation_process_proposals_path(legislation_process)
expect(page).to have_css(".proposal-content", count: 0)
expect(page).not_to have_link("Hide")
expect(page).not_to have_button "Hide"
end
end

View File

@@ -12,7 +12,7 @@ describe "Moderate proposal notifications" do
click_link "Notifications (1)"
within("#proposal_notification_#{proposal_notification.id}") do
accept_confirm("Are you sure? Hide") { click_link "Hide" }
accept_confirm("Are you sure? Hide") { click_button "Hide" }
end
expect(page).to have_css("#proposal_notification_#{proposal_notification.id}.faded")
@@ -34,8 +34,8 @@ describe "Moderate proposal notifications" do
click_link "Notifications (1)"
within("#proposal_notification_#{proposal_notification.id}") do
expect(page).not_to have_link("Hide")
expect(page).not_to have_link("Block author")
expect(page).not_to have_button "Hide"
expect(page).not_to have_button "Block author"
end
end
@@ -70,7 +70,7 @@ describe "Moderate proposal notifications" do
click_button "Search"
within "tr", text: proposal_notification.author.name do
expect(page).to have_link "Block"
expect(page).to have_button "Block"
end
end

View File

@@ -10,7 +10,7 @@ describe "Moderate proposals" do
visit proposal_path(proposal)
within("#proposal_#{proposal.id}") do
accept_confirm("Are you sure? Hide") { click_link "Hide" }
accept_confirm("Are you sure? Hide") { click_button "Hide" }
end
expect(page).to have_css("#proposal_#{proposal.id}.faded")
@@ -29,8 +29,8 @@ describe "Moderate proposals" do
visit proposal_path(proposal)
within("#proposal_#{proposal.id}") do
expect(page).to have_link("Hide")
expect(page).not_to have_link("Block author")
expect(page).to have_button "Hide"
expect(page).not_to have_button "Block author"
end
end
@@ -65,7 +65,7 @@ describe "Moderate proposals" do
click_button "Search"
within "tr", text: proposal.author.name do
expect(page).to have_link "Block"
expect(page).to have_button "Block"
end
end

View File

@@ -24,7 +24,9 @@ describe "Moderate users" do
visit debate_path(debate1)
within("#debate_#{debate1.id}") do
accept_confirm("Are you sure? Hide author \"#{debate1.author.name}\"") { click_link "Hide author" }
accept_confirm("Are you sure? This will hide the user \"#{debate1.author.name}\" and all their contents.") do
click_button "Block author"
end
end
expect(page).to have_current_path(debates_path)
@@ -64,7 +66,8 @@ describe "Moderate users" do
within("#moderation_users") do
expect(page).to have_content citizen.name
expect(page).not_to have_content "Blocked"
click_link "Block"
accept_confirm { click_button "Block" }
end
within("#moderation_users") do
@@ -72,4 +75,23 @@ describe "Moderate users" do
expect(page).to have_content "Blocked"
end
end
scenario "Hide users in the moderation section" do
create(:user, username: "Rick")
login_as(create(:moderator).user)
visit moderation_users_path(search: "Rick")
within("#moderation_users") do
accept_confirm('This will hide the user "Rick" without hiding their contents') do
click_button "Hide"
end
end
expect(page).to have_content "The user has been hidden"
within("#moderation_users") do
expect(page).to have_content "Hidden"
end
end
end