- <% if comment.hidden? %>
+ <% if comment.not_visible? %>
<%= t("debates.comment.deleted") %>
<% else %>
<%= avatar_image(comment.user, size: 32, class: 'left') %>
-
+ <% end %>
diff --git a/app/views/debates/_actions.html.erb b/app/views/debates/_actions.html.erb
index 3300a7b1d..5a51749dc 100644
--- a/app/views/debates/_actions.html.erb
+++ b/app/views/debates/_actions.html.erb
@@ -1,2 +1,8 @@
<%= link_to t("admin.actions.hide").capitalize, hide_moderation_debate_path(debate),
method: :put, remote: true, data: { confirm: t('admin.actions.confirm') } %>
+
+<% unless debate.author.hidden? %>
+ |
+ <%= link_to t("admin.actions.hide_author").capitalize, hide_moderation_user_path(debate.author_id),
+ method: :put, data: { confirm: t('admin.actions.confirm') } %>
+<% end %>
diff --git a/app/views/debates/show.html.erb b/app/views/debates/show.html.erb
index 3a29ec96f..03c7e2c8c 100644
--- a/app/views/debates/show.html.erb
+++ b/app/views/debates/show.html.erb
@@ -14,12 +14,12 @@
<%= avatar_image(@debate.author, size: 32, class: 'author-photo') %>
-
+ <% else %>
<%= @debate.author.name %>
@@ -29,7 +29,7 @@
<%= @debate.author.official_position %>
<% end %>
-
+ <% end %>
<% if @debate.author.verified_organization? %>
•
diff --git a/config/locales/admin.en.yml b/config/locales/admin.en.yml
index 7a3c6969b..151a9fc47 100644
--- a/config/locales/admin.en.yml
+++ b/config/locales/admin.en.yml
@@ -13,6 +13,7 @@ en:
debate_topics: Debate topics
hidden_debates: Hidden debates
hidden_comments: Hidden comments
+ hidden_users: Hidden users
organizations: Organizations
officials: Officials
stats: Statistics
@@ -31,6 +32,7 @@ en:
rejected: Rejected
actions:
hide: Hide
+ hide_author: Ban author
restore: Restore
confirm: 'Are you sure?'
tags:
@@ -53,6 +55,19 @@ en:
back: Back
restore:
success: The debate has been restored
+ users:
+ index:
+ title: Banned users
+ restore: Restore user
+ show:
+ title: "User activity from %{user}"
+ restore: Restore user
+ back: Back
+ email: "Email:"
+ registered_at: "Registered at:"
+ hidden_at: "Hidden at:"
+ restore:
+ success: The user has been restored
officials:
level_0: Level 0
level_1: Level 1
diff --git a/config/locales/admin.es.yml b/config/locales/admin.es.yml
index da29cff28..fbaed7566 100644
--- a/config/locales/admin.es.yml
+++ b/config/locales/admin.es.yml
@@ -13,6 +13,7 @@ es:
debate_topics: Temas de debate
hidden_debates: Debates ocultos
hidden_comments: Comentarios ocultos
+ hidden_users: Usuarios ocultos
organizations: Organizaciones
officials: Cargos públicos
stats: Estadísticas
@@ -31,6 +32,7 @@ es:
rejected: Rechazadas
actions:
hide: Ocultar
+ hide_author: Bloquear al autor
restore: Permitir
confirm: '¿Estás seguro?'
tags:
@@ -53,6 +55,19 @@ es:
back: Volver
restore:
success: El debate ha sido permitido
+ users:
+ index:
+ title: Usuarios bloqueados
+ restore: Restaurar usuario
+ show:
+ title: "Actividad del usuario %{user}"
+ restore: Restaurar usuario
+ back: Volver
+ email: "Email:"
+ registered_at: "Fecha de alta:"
+ hidden_at: "Bloqueado:"
+ restore:
+ success: El usuario y sus contenidos han sido restaurados
officials:
level_0: Nivel 0
level_1: Nivel 1
diff --git a/config/routes.rb b/config/routes.rb
index 66b74546b..7dbe31613 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -36,6 +36,10 @@ Rails.application.routes.draw do
end
end
+ resources :users, only: [:index, :show] do
+ member { put :restore }
+ end
+
resources :debates, only: [:index, :show] do
member { put :restore }
end
@@ -55,11 +59,15 @@ Rails.application.routes.draw do
namespace :moderation do
root to: "dashboard#index"
+ resources :users, only: [] do
+ member { put :hide }
+ end
+
resources :debates, only: [] do
member { put :hide }
end
- resources :comments, only: [:index] do
+ resources :comments, only: [] do
member { put :hide }
end
end
diff --git a/db/migrate/20150819135933_add_hidden_at_to_users.rb b/db/migrate/20150819135933_add_hidden_at_to_users.rb
new file mode 100644
index 000000000..fa54e00e1
--- /dev/null
+++ b/db/migrate/20150819135933_add_hidden_at_to_users.rb
@@ -0,0 +1,6 @@
+class AddHiddenAtToUsers < ActiveRecord::Migration
+ def change
+ add_column :users, :hidden_at, :datetime
+ add_index :users, :hidden_at
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index f2bbe60fc..6d3005fbf 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20150817150457) do
+ActiveRecord::Schema.define(version: 20150819135933) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -137,16 +137,18 @@ ActiveRecord::Schema.define(version: 20150817150457) do
t.datetime "confirmation_sent_at"
t.string "unconfirmed_email"
t.string "nickname"
- t.string "phone_number", limit: 30
- t.boolean "use_nickname", default: false, null: false
- t.boolean "email_on_debate_comment", default: false
- t.boolean "email_on_comment_reply", default: false
+ t.boolean "use_nickname", default: false, null: false
+ t.boolean "email_on_debate_comment", default: false
+ t.boolean "email_on_comment_reply", default: false
t.string "official_position"
- t.integer "official_level", default: 0
+ t.integer "official_level", default: 0
+ t.string "phone_number", limit: 30
+ t.datetime "hidden_at"
end
add_index "users", ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true, using: :btree
add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree
+ add_index "users", ["hidden_at"], name: "index_users_on_hidden_at", using: :btree
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree
create_table "visits", id: :uuid, default: nil, force: :cascade do |t|
diff --git a/lib/acts_as_paranoid_aliases.rb b/lib/acts_as_paranoid_aliases.rb
index 066ce3e29..dbb0d8350 100644
--- a/lib/acts_as_paranoid_aliases.rb
+++ b/lib/acts_as_paranoid_aliases.rb
@@ -20,6 +20,16 @@ module ActsAsParanoidAliases
def only_hidden
only_deleted
end
+
+ def hide_all(ids)
+ return if ids.blank?
+ where(id: ids).update_all(hidden_at: Time.now)
+ end
+
+ def restore_all(ids)
+ return if ids.blank?
+ only_hidden.where(id: ids).update_all(hidden_at: nil)
+ end
end
end
diff --git a/spec/features/admin/users_spec.rb b/spec/features/admin/users_spec.rb
new file mode 100644
index 000000000..ed5c80f34
--- /dev/null
+++ b/spec/features/admin/users_spec.rb
@@ -0,0 +1,66 @@
+require 'rails_helper'
+
+feature 'Admin users' do
+
+ scenario 'Restore hidden user' do
+ citizen = create(:user)
+ admin = create(:administrator)
+ create(:moderator, user: admin.user)
+
+ debate_previously_hidden = create(:debate, :hidden, author: citizen)
+ debate = create(:debate, author: citizen)
+ comment_previously_hidden = create(:comment, :hidden, user: citizen, commentable: debate, body: "You have the manners of a beggar")
+ comment = create(:comment, user: citizen, commentable: debate, body: 'Not Spam')
+
+ login_as(admin.user)
+ visit debate_path(debate)
+
+ within("#debate_#{debate.id}") do
+ click_link 'Ban author'
+ end
+
+ visit debates_path
+ expect(page).to_not have_content(debate.title)
+ expect(page).to_not have_content(debate_previously_hidden)
+
+ click_link "Administration"
+ click_link "Hidden users"
+ click_link "Restore user"
+
+ visit debates_path
+ expect(page).to have_content(debate.title)
+ expect(page).to_not have_content(debate_previously_hidden)
+
+ visit debate_path(debate)
+ expect(page).to have_content(comment.body)
+ expect(page).to_not have_content(comment_previously_hidden.body)
+ end
+
+ scenario 'Show user activity' do
+ citizen = create(:user)
+ admin = create(:administrator)
+ create(:moderator, user: admin.user)
+
+ debate1 = create(:debate, :hidden, author: citizen)
+ debate2 = create(:debate, author: citizen)
+ comment1 = create(:comment, :hidden, user: citizen, commentable: debate2, body: "You have the manners of a beggar")
+ comment2 = create(:comment, user: citizen, commentable: debate2, body: 'Not Spam')
+
+ login_as(admin.user)
+ visit debate_path(debate2)
+
+ within("#debate_#{debate2.id}") do
+ click_link 'Ban author'
+ end
+
+ click_link "Administration"
+ click_link "Hidden users"
+ click_link citizen.name
+
+ expect(page).to have_content(debate1.title)
+ expect(page).to have_content(debate2.title)
+ expect(page).to have_content(comment1.body)
+ expect(page).to have_content(comment2.body)
+ end
+
+end
\ No newline at end of file
diff --git a/spec/features/moderation/users_spec.rb b/spec/features/moderation/users_spec.rb
new file mode 100644
index 000000000..aeea5c088
--- /dev/null
+++ b/spec/features/moderation/users_spec.rb
@@ -0,0 +1,51 @@
+require 'rails_helper'
+
+feature 'Moderate users' do
+
+ scenario 'Hide' do
+ citizen = create(:user)
+ moderator = create(:moderator)
+
+ debate1 = create(:debate, author: citizen)
+ debate2 = create(:debate, author: citizen)
+ debate3 = create(:debate)
+ comment3 = create(:comment, user: citizen, commentable: debate3, body: 'SPAMMER')
+
+ login_as(moderator.user)
+ visit debates_path
+
+ expect(page).to have_content(debate1.title)
+ expect(page).to have_content(debate2.title)
+ expect(page).to have_content(debate3.title)
+
+ visit debate_path(debate3)
+
+ expect(page).to have_content(comment3.body)
+
+ visit debate_path(debate1)
+
+ within("#debate_#{debate1.id}") do
+ click_link 'Ban author'
+ end
+
+ expect(current_path).to eq(debates_path)
+ expect(page).to_not have_content(debate1.title)
+ expect(page).to_not have_content(debate2.title)
+ expect(page).to have_content(debate3.title)
+
+ visit debate_path(debate3)
+
+ expect(page).to_not have_content(comment3.body)
+
+ click_link("Logout")
+
+ click_link 'Log in'
+ fill_in 'user_email', with: citizen.email
+ fill_in 'user_password', with: citizen.password
+ click_button 'Log in'
+
+ expect(page).to have_content 'Invalid email or password'
+ expect(current_path).to eq(new_user_session_path)
+ end
+
+end
\ No newline at end of file
diff --git a/spec/lib/acts_as_paranoid_aliases_spec.rb b/spec/lib/acts_as_paranoid_aliases_spec.rb
new file mode 100644
index 000000000..1c99884f3
--- /dev/null
+++ b/spec/lib/acts_as_paranoid_aliases_spec.rb
@@ -0,0 +1,37 @@
+require 'rails_helper'
+
+describe 'Paranoid methods' do
+
+ describe '#hide_all' do
+ it 'hides all instances in the id list' do
+ debate1 = create(:debate)
+ debate2 = create(:debate)
+ debate3 = create(:debate)
+ debate4 = create(:debate)
+
+ expect(Debate.all.sort).to eq([debate1, debate2, debate3, debate4].sort)
+
+ Debate.hide_all [debate1, debate2, debate4].map(&:id)
+
+ expect(Debate.all).to eq([debate3])
+ end
+ end
+
+ describe '#restore_all' do
+ it 'restores all instances in the id list' do
+ debate1 = create(:debate)
+ debate2 = create(:debate)
+ debate3 = create(:debate)
+
+ debate1.hide
+ debate3.hide
+
+ expect(Debate.all).to eq([debate2])
+
+ Debate.restore_all [debate1, debate3].map(&:id)
+
+ expect(Debate.all.sort).to eq([debate1, debate2, debate3].sort)
+ end
+ end
+
+end
diff --git a/spec/models/ability_spec.rb b/spec/models/ability_spec.rb
index 20a3456d4..b484e9e7c 100644
--- a/spec/models/ability_spec.rb
+++ b/spec/models/ability_spec.rb
@@ -64,6 +64,7 @@ describe Ability do
describe "Moderator" do
let(:user) { create(:user) }
before { create(:moderator, user: user) }
+ let(:other_user) { create(:user) }
it { should be_able_to(:index, Debate) }
it { should be_able_to(:show, debate) }
@@ -88,14 +89,17 @@ describe Ability do
it { should be_able_to(:hide, comment) }
it { should be_able_to(:hide, debate) }
+ it { should be_able_to(:hide, other_user) }
it { should_not be_able_to(:restore, comment) }
it { should_not be_able_to(:restore, debate) }
+ it { should_not be_able_to(:restore, other_user) }
end
describe "Administrator" do
let(:user) { create(:user) }
before { create(:administrator, user: user) }
+ let(:other_user) { create(:user) }
it { should be_able_to(:index, Debate) }
it { should be_able_to(:show, debate) }
@@ -103,5 +107,6 @@ describe Ability do
it { should be_able_to(:restore, comment) }
it { should be_able_to(:restore, debate) }
+ it { should be_able_to(:restore, other_user) }
end
end