diff --git a/app/controllers/admin/activity_controller.rb b/app/controllers/admin/activity_controller.rb
new file mode 100644
index 000000000..8f7993a09
--- /dev/null
+++ b/app/controllers/admin/activity_controller.rb
@@ -0,0 +1,8 @@
+class Admin::ActivityController < Admin::BaseController
+ has_filters %w{all on_users on_proposals on_debates on_comments}
+
+ def show
+ @activity = Activity.for_render.send(@current_filter).order(created_at: :desc).page(params[:page])
+ end
+
+end
diff --git a/app/controllers/admin/comments_controller.rb b/app/controllers/admin/comments_controller.rb
index ebe2f1066..3a9c360f5 100644
--- a/app/controllers/admin/comments_controller.rb
+++ b/app/controllers/admin/comments_controller.rb
@@ -14,6 +14,7 @@ class Admin::CommentsController < Admin::BaseController
def restore
@comment.restore
+ Activity.log(current_user, :restore, @comment)
redirect_to request.query_parameters.merge(action: :index)
end
diff --git a/app/controllers/admin/debates_controller.rb b/app/controllers/admin/debates_controller.rb
index 544c3f23d..41e5af848 100644
--- a/app/controllers/admin/debates_controller.rb
+++ b/app/controllers/admin/debates_controller.rb
@@ -14,6 +14,7 @@ class Admin::DebatesController < Admin::BaseController
def restore
@debate.restore
+ Activity.log(current_user, :restore, @debate)
redirect_to request.query_parameters.merge(action: :index)
end
diff --git a/app/controllers/admin/proposals_controller.rb b/app/controllers/admin/proposals_controller.rb
index 4f399bff7..57e8809e2 100644
--- a/app/controllers/admin/proposals_controller.rb
+++ b/app/controllers/admin/proposals_controller.rb
@@ -14,6 +14,7 @@ class Admin::ProposalsController < Admin::BaseController
def restore
@proposal.restore
+ Activity.log(current_user, :restore, @proposal)
redirect_to request.query_parameters.merge(action: :index)
end
diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb
index 013fe4e90..eed1c4fea 100644
--- a/app/controllers/admin/users_controller.rb
+++ b/app/controllers/admin/users_controller.rb
@@ -20,6 +20,7 @@ class Admin::UsersController < Admin::BaseController
def restore
@user.restore
+ Activity.log(current_user, :restore, @user)
redirect_to request.query_parameters.merge(action: :index)
end
diff --git a/app/controllers/moderation/comments_controller.rb b/app/controllers/moderation/comments_controller.rb
index 07c0201ee..7177911e8 100644
--- a/app/controllers/moderation/comments_controller.rb
+++ b/app/controllers/moderation/comments_controller.rb
@@ -14,21 +14,21 @@ class Moderation::CommentsController < Moderation::BaseController
end
def hide
- @comment.hide
+ hide_comment @comment
end
def moderate
@comments = @comments.where(id: params[:comment_ids])
if params[:hide_comments].present?
- @comments.accessible_by(current_ability, :hide).each(&:hide)
+ @comments.accessible_by(current_ability, :hide).each {|comment| hide_comment comment}
elsif params[:ignore_flags].present?
@comments.accessible_by(current_ability, :ignore_flag).each(&:ignore_flag)
elsif params[:block_authors].present?
author_ids = @comments.pluck(:user_id).uniq
- User.where(id: author_ids).accessible_by(current_ability, :block).each(&:block)
+ User.where(id: author_ids).accessible_by(current_ability, :block).each {|user| block_user user}
end
redirect_to request.query_parameters.merge(action: :index)
@@ -40,4 +40,14 @@ class Moderation::CommentsController < Moderation::BaseController
@comments = Comment.accessible_by(current_ability, :moderate)
end
+ def hide_comment(comment)
+ comment.hide
+ Activity.log(current_user, :hide, comment)
+ end
+
+ def block_user(user)
+ user.block
+ Activity.log(current_user, :block, user)
+ end
+
end
diff --git a/app/controllers/moderation/debates_controller.rb b/app/controllers/moderation/debates_controller.rb
index 1fe3eb4b4..57c6a0e05 100644
--- a/app/controllers/moderation/debates_controller.rb
+++ b/app/controllers/moderation/debates_controller.rb
@@ -14,21 +14,21 @@ class Moderation::DebatesController < Moderation::BaseController
end
def hide
- @debate.hide
+ hide_debate @debate
end
def moderate
@debates = @debates.where(id: params[:debate_ids])
if params[:hide_debates].present?
- @debates.accessible_by(current_ability, :hide).each(&:hide)
+ @debates.accessible_by(current_ability, :hide).each {|debate| hide_debate debate}
elsif params[:ignore_flags].present?
@debates.accessible_by(current_ability, :ignore_flag).each(&:ignore_flag)
elsif params[:block_authors].present?
author_ids = @debates.pluck(:author_id).uniq
- User.where(id: author_ids).accessible_by(current_ability, :block).each(&:block)
+ User.where(id: author_ids).accessible_by(current_ability, :block).each {|user| block_user user}
end
redirect_to request.query_parameters.merge(action: :index)
@@ -40,4 +40,14 @@ class Moderation::DebatesController < Moderation::BaseController
@debates = Debate.accessible_by(current_ability, :moderate)
end
+ def hide_debate(debate)
+ debate.hide
+ Activity.log(current_user, :hide, debate)
+ end
+
+ def block_user(user)
+ user.block
+ Activity.log(current_user, :block, user)
+ end
+
end
diff --git a/app/controllers/moderation/proposals_controller.rb b/app/controllers/moderation/proposals_controller.rb
index e7cf86043..e59f3c79f 100644
--- a/app/controllers/moderation/proposals_controller.rb
+++ b/app/controllers/moderation/proposals_controller.rb
@@ -15,21 +15,21 @@ class Moderation::ProposalsController < Moderation::BaseController
end
def hide
- @proposal.hide
+ hide_proposal @proposal
end
def moderate
@proposals = @proposals.where(id: params[:proposal_ids])
if params[:hide_proposals].present?
- @proposals.accessible_by(current_ability, :hide).each(&:hide)
+ @proposals.accessible_by(current_ability, :hide).each {|proposal| hide_proposal proposal}
elsif params[:ignore_flags].present?
@proposals.accessible_by(current_ability, :ignore_flag).each(&:ignore_flag)
elsif params[:block_authors].present?
author_ids = @proposals.pluck(:author_id).uniq
- User.where(id: author_ids).accessible_by(current_ability, :block).each(&:block)
+ User.where(id: author_ids).accessible_by(current_ability, :block).each {|user| block_user user}
end
redirect_to request.query_parameters.merge(action: :index)
@@ -41,4 +41,14 @@ class Moderation::ProposalsController < Moderation::BaseController
@proposals = Proposal.accessible_by(current_ability, :moderate)
end
+ def hide_proposal(proposal)
+ proposal.hide
+ Activity.log(current_user, :hide, proposal)
+ end
+
+ def block_user(user)
+ user.block
+ Activity.log(current_user, :block, user)
+ end
+
end
diff --git a/app/controllers/moderation/users_controller.rb b/app/controllers/moderation/users_controller.rb
index 39f4c200a..fc8b4488e 100644
--- a/app/controllers/moderation/users_controller.rb
+++ b/app/controllers/moderation/users_controller.rb
@@ -8,12 +8,14 @@ class Moderation::UsersController < Moderation::BaseController
end
def hide_in_moderation_screen
- @user.block
+ block_user
+
redirect_to request.query_parameters.merge(action: :index), notice: I18n.t('moderation.users.notice_hide')
end
def hide
- @user.block
+ block_user
+
redirect_to debates_path
end
@@ -23,4 +25,9 @@ class Moderation::UsersController < Moderation::BaseController
@users = User.with_hidden.search(params[:name_or_email]).page(params[:page]).for_render
end
+ def block_user
+ @user.block
+ Activity.log(current_user, :block, @user)
+ end
+
end
diff --git a/app/models/activity.rb b/app/models/activity.rb
new file mode 100644
index 000000000..977204669
--- /dev/null
+++ b/app/models/activity.rb
@@ -0,0 +1,28 @@
+class Activity < ActiveRecord::Base
+
+ belongs_to :actionable, -> { with_hidden }, polymorphic: true
+ belongs_to :user, -> { with_hidden }
+
+ VALID_ACTIONS = %w( hide block restore )
+
+ validates :action, inclusion: {in: VALID_ACTIONS}
+
+ scope :on_proposals, -> { where(actionable_type: 'Proposal') }
+ scope :on_debates, -> { where(actionable_type: 'Debate') }
+ scope :on_users, -> { where(actionable_type: 'User') }
+ scope :on_comments, -> { where(actionable_type: 'Comment') }
+ scope :for_render, -> { includes(user: [:moderator, :administrator]).includes(:actionable) }
+
+ def self.log(user, action, actionable)
+ create(user: user, action: action.to_s, actionable: actionable)
+ end
+
+ def self.on(actionable)
+ where(actionable: actionable)
+ end
+
+ def self.by(user)
+ where(user: user)
+ end
+
+end
diff --git a/app/models/comment.rb b/app/models/comment.rb
index 6a3125285..187e35037 100644
--- a/app/models/comment.rb
+++ b/app/models/comment.rb
@@ -73,11 +73,11 @@ class Comment < ActiveRecord::Base
end
def after_hide
- commentable_type.constantize.reset_counters(commentable_id, :comments)
+ commentable_type.constantize.with_hidden.reset_counters(commentable_id, :comments)
end
def after_restore
- commentable_type.constantize.reset_counters(commentable_id, :comments)
+ commentable_type.constantize.with_hidden.reset_counters(commentable_id, :comments)
end
def reply?
diff --git a/app/views/admin/_menu.html.erb b/app/views/admin/_menu.html.erb
index 42d979209..89e1b6641 100644
--- a/app/views/admin/_menu.html.erb
+++ b/app/views/admin/_menu.html.erb
@@ -60,6 +60,13 @@
<% end %>
+
>
+ <%= link_to admin_activity_path do %>
+
+ <%= t('admin.menu.activity') %>
+ <% end %>
+
+
>
<%= link_to admin_settings_path do %>
diff --git a/app/views/admin/activity/show.html.erb b/app/views/admin/activity/show.html.erb
new file mode 100644
index 000000000..0f422cfa8
--- /dev/null
+++ b/app/views/admin/activity/show.html.erb
@@ -0,0 +1,43 @@
+<%= t("admin.activity.show.title") %>
+
+<%= render 'shared/filter_subnav', i18n_namespace: "admin.activity.show" %>
+
+<%= page_entries_info @activity %>
+
+
+
+ | <%= t("admin.activity.show.type") %> |
+ <%= t("admin.activity.show.action") %> |
+ |
+ <%= t("admin.activity.show.by") %> |
+
+ <% @activity.each do |activity| %>
+
+
+ <%= activity.actionable_type.constantize.model_name.human %>
+ <%= l activity.actionable.created_at.to_date %>
+ |
+
+ <%= t("admin.activity.show.actions.#{activity.action}") %>
+ <%= l activity.created_at.to_date %>
+ |
+
+ <% case activity.actionable_type %>
+ <% when "User" %>
+ <%= activity.actionable.username %> (<%= activity.actionable.email %>)
+ <% when "Comment" %>
+ <%= activity.actionable.body %>
+ <% else %>
+ <%= activity.actionable.title %>
+
+
+ <%= activity.actionable.description %>
+
+ <% end %>
+ |
+ <%= activity.user.name %> (<%= activity.user.email %>) |
+
+ <% end %>
+
+
+<%= paginate @activity %>
diff --git a/app/views/admin/users/index.html.erb b/app/views/admin/users/index.html.erb
index b3c0ad40b..bb71fcd8f 100644
--- a/app/views/admin/users/index.html.erb
+++ b/app/views/admin/users/index.html.erb
@@ -6,7 +6,7 @@
<% @users.each do |user| %>
- -
+
-
<%= link_to user.name, admin_user_path(user) %>
<%= link_to t("admin.actions.restore"),
diff --git a/config/i18n-tasks.yml b/config/i18n-tasks.yml
index 6173538ef..b1fa6d362 100644
--- a/config/i18n-tasks.yml
+++ b/config/i18n-tasks.yml
@@ -108,6 +108,7 @@ ignore_unused:
- 'admin.proposals.index.filter*'
- 'admin.organizations.index.filter*'
- 'admin.users.index.filter*'
+ - 'admin.activity.show.filter*'
- 'admin.comments.index.hidden_*'
- 'moderation.comments.index.filter*'
- 'moderation.comments.index.order*'
diff --git a/config/locales/activerecord.en.yml b/config/locales/activerecord.en.yml
index f17dc73de..303bd5ded 100644
--- a/config/locales/activerecord.en.yml
+++ b/config/locales/activerecord.en.yml
@@ -1,6 +1,7 @@
en:
activerecord:
models:
+ activity: Activity
comment: Comment
debate: Debate
proposal: Proposal
diff --git a/config/locales/activerecord.es.yml b/config/locales/activerecord.es.yml
index 0d6ecba40..3ba5e7cca 100644
--- a/config/locales/activerecord.es.yml
+++ b/config/locales/activerecord.es.yml
@@ -1,6 +1,9 @@
es:
activerecord:
models:
+ activity:
+ one: actividad
+ other: actividades
comment:
one: Comentario
other: Comentarios
diff --git a/config/locales/admin.en.yml b/config/locales/admin.en.yml
index 7317b2a31..c5d5616a4 100644
--- a/config/locales/admin.en.yml
+++ b/config/locales/admin.en.yml
@@ -20,6 +20,7 @@ en:
officials: Officials
moderators: Moderators
stats: Statistics
+ activity: Moderation Activity
organizations:
index:
title: Organizations
@@ -129,4 +130,20 @@ en:
moderator:
delete: Delete
add: Add
-
+ activity:
+ show:
+ title: Activity of Moderators
+ action: Action
+ by: Moderated by
+ type: Type
+ filter: Show
+ filters:
+ all: All
+ on_proposals: On Proposals
+ on_debates: On Debates
+ on_comments: On Comments
+ on_users: On Users
+ actions:
+ hide: Hidden
+ restore: Restored
+ block: Blocked
diff --git a/config/locales/admin.es.yml b/config/locales/admin.es.yml
index 01117ff42..0e7903934 100644
--- a/config/locales/admin.es.yml
+++ b/config/locales/admin.es.yml
@@ -20,6 +20,7 @@ es:
officials: Cargos públicos
moderators: Moderadores
stats: Estadísticas
+ activity: Actividad de moderadores
organizations:
index:
title: Organizaciones
@@ -129,3 +130,20 @@ es:
moderator:
delete: Borrar
add: Añadir
+ activity:
+ show:
+ title: Actividad de los Moderadores
+ action: 'Acción'
+ by: Moderado por
+ type: Tipo
+ filter: Mostrar
+ filters:
+ all: Todo
+ on_proposals: Propuestas
+ on_debates: Debates
+ on_comments: Comentarios
+ on_users: Usuarios
+ actions:
+ hide: Ocultado
+ restore: Restaurado
+ block: Bloqueado
diff --git a/config/routes.rb b/config/routes.rb
index ae52181bb..e60b50ca8 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -112,6 +112,8 @@ Rails.application.routes.draw do
resources :moderators, only: [:index, :create, :destroy] do
collection { get :search }
end
+
+ resource :activity, controller: :activity, only: :show
end
namespace :moderation do
diff --git a/db/migrate/20150921095553_create_activities.rb b/db/migrate/20150921095553_create_activities.rb
new file mode 100644
index 000000000..3fff14205
--- /dev/null
+++ b/db/migrate/20150921095553_create_activities.rb
@@ -0,0 +1,13 @@
+class CreateActivities < ActiveRecord::Migration
+ def change
+ create_table :activities do |t|
+ t.integer :user_id
+ t.string :action
+ t.belongs_to :actionable, polymorphic: true
+ t.timestamps
+ end
+
+ add_index :activities, [:actionable_id, :actionable_type]
+ add_index :activities, :user_id
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 741f82940..22b6b730c 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,11 +11,23 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20150917102718) do
+ActiveRecord::Schema.define(version: 20150921095553) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
+ create_table "activities", force: :cascade do |t|
+ t.integer "user_id"
+ t.string "action"
+ t.integer "actionable_id"
+ t.string "actionable_type"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ end
+
+ add_index "activities", ["actionable_id", "actionable_type"], name: "index_activities_on_actionable_id_and_actionable_type", using: :btree
+ add_index "activities", ["user_id"], name: "index_activities_on_user_id", using: :btree
+
create_table "addresses", force: :cascade do |t|
t.integer "user_id"
t.string "street"
diff --git a/spec/factories.rb b/spec/factories.rb
index cda9c01a8..caec0d6d9 100644
--- a/spec/factories.rb
+++ b/spec/factories.rb
@@ -33,6 +33,12 @@ FactoryGirl.define do
uid "MyString"
end
+ factory :activity do
+ user
+ action "hide"
+ association :actionable, factory: :proposal
+ end
+
factory :verification_residence, class: Verification::Residence do
user
document_number '12345678Z'
diff --git a/spec/features/admin/activity_spec.rb b/spec/features/admin/activity_spec.rb
new file mode 100644
index 000000000..d2836b2d1
--- /dev/null
+++ b/spec/features/admin/activity_spec.rb
@@ -0,0 +1,334 @@
+require 'rails_helper'
+
+feature 'Admin activity' do
+
+ background do
+ @admin = create(:administrator)
+ login_as(@admin.user)
+ end
+
+ context "Proposals" do
+ scenario "Shows moderation activity on proposals", :js do
+ proposal = create(:proposal)
+
+ visit proposal_path(proposal)
+
+ within("#proposal_#{proposal.id}") do
+ click_link 'Hide'
+ end
+
+ visit admin_activity_path
+
+ within("#activity_#{Activity.last.id}") do
+ expect(page).to have_content(proposal.title)
+ expect(page).to have_content("Hidden")
+ expect(page).to have_content(@admin.user.username)
+ end
+ end
+
+ scenario "Shows moderation activity from moderation screen" do
+ proposal1 = create(:proposal)
+ proposal2 = create(:proposal)
+ proposal3 = create(:proposal)
+
+ visit moderation_proposals_path(filter: 'all')
+
+ within("#proposal_#{proposal1.id}") do
+ check "proposal_#{proposal1.id}_check"
+ end
+
+ within("#proposal_#{proposal3.id}") do
+ check "proposal_#{proposal3.id}_check"
+ end
+
+ click_on "Hide proposals"
+
+ visit admin_activity_path
+
+ expect(page).to have_content(proposal1.title)
+ expect(page).to_not have_content(proposal2.title)
+ expect(page).to have_content(proposal3.title)
+ end
+
+ scenario "Shows admin restores" do
+ proposal = create(:proposal, :hidden)
+
+ visit admin_proposals_path
+
+ within("#proposal_#{proposal.id}") do
+ click_on "Restore"
+ end
+
+ visit admin_activity_path
+
+ within("#activity_#{Activity.last.id}") do
+ expect(page).to have_content(proposal.title)
+ expect(page).to have_content("Restored")
+ expect(page).to have_content(@admin.user.username)
+ end
+ end
+ end
+
+ context "Debates" do
+ scenario "Shows moderation activity on debates", :js do
+ debate = create(:debate)
+
+ visit debate_path(debate)
+
+ within("#debate_#{debate.id}") do
+ click_link 'Hide'
+ end
+
+ visit admin_activity_path
+
+ within("#activity_#{Activity.last.id}") do
+ expect(page).to have_content(debate.title)
+ expect(page).to have_content("Hidden")
+ expect(page).to have_content(@admin.user.username)
+ end
+ end
+
+ scenario "Shows moderation activity from moderation screen" do
+ debate1 = create(:debate)
+ debate2 = create(:debate)
+ debate3 = create(:debate)
+
+ visit moderation_debates_path(filter: 'all')
+
+ within("#debate_#{debate1.id}") do
+ check "debate_#{debate1.id}_check"
+ end
+
+ within("#debate_#{debate3.id}") do
+ check "debate_#{debate3.id}_check"
+ end
+
+ click_on "Hide debates"
+
+ visit admin_activity_path
+
+ expect(page).to have_content(debate1.title)
+ expect(page).to_not have_content(debate2.title)
+ expect(page).to have_content(debate3.title)
+ end
+
+ scenario "Shows admin restores" do
+ debate = create(:debate, :hidden)
+
+ visit admin_debates_path
+
+ within("#debate_#{debate.id}") do
+ click_on "Restore"
+ end
+
+ visit admin_activity_path
+
+ within("#activity_#{Activity.last.id}") do
+ expect(page).to have_content(debate.title)
+ expect(page).to have_content("Restored")
+ expect(page).to have_content(@admin.user.username)
+ end
+ end
+ end
+
+ context "Comments" do
+ scenario "Shows moderation activity on comments", :js do
+ debate = create(:debate)
+ comment = create(:comment, commentable: debate)
+
+ visit debate_path(debate)
+
+ within("#comment_#{comment.id}") do
+ click_link 'Hide'
+ end
+
+ visit admin_activity_path
+
+ within("#activity_#{Activity.last.id}") do
+ expect(page).to have_content(comment.body)
+ expect(page).to have_content("Hidden")
+ expect(page).to have_content(@admin.user.username)
+ end
+ end
+
+ scenario "Shows moderation activity from moderation screen" do
+ comment1 = create(:comment, body: "SPAM")
+ comment2 = create(:comment)
+ comment3 = create(:comment, body: "Offensive!")
+
+ visit moderation_comments_path(filter: 'all')
+
+ within("#comment_#{comment1.id}") do
+ check "comment_#{comment1.id}_check"
+ end
+
+ within("#comment_#{comment3.id}") do
+ check "comment_#{comment3.id}_check"
+ end
+
+ click_on "Hide comments"
+
+ visit admin_activity_path
+
+ expect(page).to have_content(comment1.body)
+ expect(page).to_not have_content(comment2.body)
+ expect(page).to have_content(comment3.body)
+ end
+
+ scenario "Shows admin restores" do
+ comment = create(:comment, :hidden)
+
+ visit admin_comments_path
+
+ within("#comment_#{comment.id}") do
+ click_on "Restore"
+ end
+
+ visit admin_activity_path
+
+ within("#activity_#{Activity.last.id}") do
+ expect(page).to have_content(comment.body)
+ expect(page).to have_content("Restored")
+ expect(page).to have_content(@admin.user.username)
+ end
+ end
+ end
+
+ context "User" do
+ scenario "Shows moderation activity on users" do
+ proposal = create(:proposal)
+
+ visit proposal_path(proposal)
+
+ within("#proposal_#{proposal.id}") do
+ click_link 'Ban author'
+ end
+
+ visit admin_activity_path
+
+ within("#activity_#{Activity.last.id}") do
+ expect(page).to have_content("Blocked")
+ expect(page).to have_content(proposal.author.username)
+ expect(page).to have_content(proposal.author.email)
+ expect(page).to have_content(@admin.user.username)
+ expect(page).not_to have_content(proposal.title)
+ end
+ end
+
+ scenario "Shows moderation activity from moderation screen" do
+ user = create(:user)
+
+ visit moderation_users_path(name_or_email: user.username)
+
+ within(".admin-list") do
+ click_link 'Ban'
+ end
+
+ visit admin_activity_path
+
+ within("#activity_#{Activity.last.id}") do
+ expect(page).to have_content(user.username)
+ expect(page).to have_content(user.email)
+ expect(page).to have_content(@admin.user.username)
+ end
+ end
+
+ scenario "Shows moderation activity from proposals moderation screen" do
+ proposal1 = create(:proposal)
+ proposal2 = create(:proposal)
+ proposal3 = create(:proposal)
+
+ visit moderation_proposals_path(filter: 'all')
+
+ within("#proposal_#{proposal1.id}") do
+ check "proposal_#{proposal1.id}_check"
+ end
+
+ within("#proposal_#{proposal3.id}") do
+ check "proposal_#{proposal3.id}_check"
+ end
+
+ click_on "Block authors"
+
+ visit admin_activity_path
+
+ expect(page).to have_content(proposal1.author.username)
+ expect(page).to have_content(proposal1.author.email)
+ expect(page).to have_content(proposal3.author.username)
+ expect(page).to have_content(proposal3.author.email)
+ expect(page).to_not have_content(proposal2.author.username)
+ end
+
+ scenario "Shows moderation activity from debates moderation screen" do
+ debate1 = create(:debate)
+ debate2 = create(:debate)
+ debate3 = create(:debate)
+
+ visit moderation_debates_path(filter: 'all')
+
+ within("#debate_#{debate1.id}") do
+ check "debate_#{debate1.id}_check"
+ end
+
+ within("#debate_#{debate3.id}") do
+ check "debate_#{debate3.id}_check"
+ end
+
+ click_on "Block authors"
+
+ visit admin_activity_path
+
+ expect(page).to have_content(debate1.author.username)
+ expect(page).to have_content(debate1.author.email)
+ expect(page).to have_content(debate3.author.username)
+ expect(page).to have_content(debate3.author.email)
+ expect(page).to_not have_content(debate2.author.username)
+ end
+
+ scenario "Shows moderation activity from comments moderation screen" do
+ comment1 = create(:comment, body: "SPAM")
+ comment2 = create(:comment)
+ comment3 = create(:comment, body: "Offensive!")
+
+ visit moderation_comments_path(filter: 'all')
+
+ within("#comment_#{comment1.id}") do
+ check "comment_#{comment1.id}_check"
+ end
+
+ within("#comment_#{comment3.id}") do
+ check "comment_#{comment3.id}_check"
+ end
+
+ click_on "Block authors"
+
+ visit admin_activity_path
+
+ expect(page).to have_content(comment1.author.username)
+ expect(page).to have_content(comment1.author.email)
+ expect(page).to have_content(comment3.author.username)
+ expect(page).to have_content(comment3.author.email)
+ expect(page).to_not have_content(comment2.author.username)
+ end
+
+ scenario "Shows admin restores" do
+ user = create(:user, :hidden)
+
+ visit admin_users_path
+
+ within("#user_#{user.id}") do
+ click_on "Restore"
+ end
+
+ visit admin_activity_path
+
+ within("#activity_#{Activity.last.id}") do
+ expect(page).to have_content(user.username)
+ expect(page).to have_content(user.email)
+ expect(page).to have_content("Restored")
+ expect(page).to have_content(@admin.user.username)
+ end
+ end
+ end
+
+end
\ No newline at end of file
diff --git a/spec/models/activity_spec.rb b/spec/models/activity_spec.rb
new file mode 100644
index 000000000..0c7b99027
--- /dev/null
+++ b/spec/models/activity_spec.rb
@@ -0,0 +1,88 @@
+require 'rails_helper'
+
+describe Activity do
+
+ it "should be valid for different actionables" do
+ expect(build(:activity, actionable: create(:proposal))).to be_valid
+ expect(build(:activity, actionable: create(:debate))).to be_valid
+ expect(build(:activity, actionable: create(:comment))).to be_valid
+ expect(build(:activity, actionable: create(:user))).to be_valid
+ end
+
+ it "should be a valid only with allowed actions" do
+ expect(build(:activity, action: "hide")).to be_valid
+ expect(build(:activity, action: "block")).to be_valid
+ expect(build(:activity, action: "restore")).to be_valid
+ expect(build(:activity, action: "dissapear")).to_not be_valid
+ end
+
+ describe "log" do
+ it "should create an activity entry" do
+ user = create(:user)
+ proposal = create(:proposal)
+
+ expect{ Activity.log(user, :hide, proposal) }.to change { Activity.count }.by(1)
+
+ activity = Activity.last
+ expect(activity.user_id).to eq(user.id)
+ expect(activity.action).to eq("hide")
+ expect(activity.actionable).to eq(proposal)
+ end
+ end
+
+ describe "on" do
+ it "should list all activity on an actionable object" do
+ proposal = create(:proposal)
+ activity1 = create(:activity, action: "hide", actionable: proposal)
+ activity2 = create(:activity, action: "restore", actionable: proposal)
+ activity3 = create(:activity, action: "hide", actionable: proposal)
+ create(:activity, action: "restore", actionable: create(:debate))
+ create(:activity, action: "hide", actionable: create(:proposal))
+ create(:activity, action: "hide", actionable: create(:comment))
+ create(:activity, action: "block", actionable: create(:user))
+
+ expect(Activity.on(proposal).size).to eq 3
+ [activity1, activity2, activity3].each do |a|
+ expect(Activity.on(proposal)).to include(a)
+ end
+ end
+ end
+
+ describe "by" do
+ it "should list all activity of a user" do
+ user1 = create(:user)
+ activity1 = create(:activity, user: user1)
+ activity2 = create(:activity, user: user1, action: "restore", actionable: create(:debate))
+ activity3 = create(:activity, user: user1, action: "hide", actionable: create(:proposal))
+ activity4 = create(:activity, user: user1, action: "hide", actionable: create(:comment))
+ activity5 = create(:activity, user: user1, action: "block", actionable: create(:user))
+ create_list(:activity, 3)
+
+ expect(Activity.by(user1).size).to eq 5
+
+ [activity1, activity2, activity3, activity4, activity5].each do |a|
+ expect(Activity.by(user1)).to include(a)
+ end
+ end
+ end
+
+ describe "scopes by actionable" do
+ it "should filter by actionable type" do
+ on_proposal = create(:activity, actionable: create(:proposal))
+ on_debate = create(:activity, actionable: create(:debate))
+ on_comment = create(:activity, actionable: create(:comment))
+ on_user = create(:activity, actionable: create(:user))
+
+ expect(Activity.on_proposals.size).to eq 1
+ expect(Activity.on_debates.size).to eq 1
+ expect(Activity.on_comments.size).to eq 1
+ expect(Activity.on_users.size).to eq 1
+
+ expect(Activity.on_proposals.first).to eq on_proposal
+ expect(Activity.on_debates.first).to eq on_debate
+ expect(Activity.on_comments.first).to eq on_comment
+ expect(Activity.on_users.first).to eq on_user
+ end
+ end
+
+end