Merge pull request #267 from AyuntamientoMadrid/flag-renaming

Admin users/comments/debates
This commit is contained in:
Juanjo Bazán
2015-08-28 12:20:56 +02:00
55 changed files with 753 additions and 469 deletions

View File

@@ -164,6 +164,11 @@ body.admin {
font-size: rem-calc(12);
}
.ignored {
color: $text-medium;
font-size: rem-calc(12);
}
.rejected {
color: $delete;
}

View File

@@ -1,13 +1,35 @@
class Admin::CommentsController < Admin::BaseController
before_filter :set_valid_filters, only: :index
before_filter :parse_filter, only: :index
before_filter :load_comment, only: [:confirm_hide, :restore]
def index
@comments = Comment.only_hidden.page(params[:page])
@comments = Comment.only_hidden.send(@filter).page(params[:page])
end
def confirm_hide
@comment.confirm_hide
redirect_to request.query_parameters.merge(action: :index)
end
def restore
@comment = Comment.with_hidden.find(params[:id])
@comment.restore
redirect_to admin_comments_path, notice: t('admin.comments.restore.success')
redirect_to request.query_parameters.merge(action: :index)
end
end
private
def load_comment
@comment = Comment.with_hidden.find(params[:id])
end
def set_valid_filters
@valid_filters = %w{all with_confirmed_hide}
end
def parse_filter
@filter = params[:filter]
@filter = 'all' unless @valid_filters.include?(@filter)
end
end

View File

@@ -1,16 +1,36 @@
class Admin::DebatesController < Admin::BaseController
before_filter :set_valid_filters, only: :index
before_filter :parse_filter, only: :index
before_filter :load_debate, only: [:confirm_hide, :restore]
def index
@debates = Debate.only_hidden.page(params[:page])
@debates = Debate.only_hidden.send(@filter).page(params[:page])
end
def show
@debate = Debate.with_hidden.find(params[:id])
def confirm_hide
@debate.confirm_hide
redirect_to request.query_parameters.merge(action: :index)
end
def restore
@debate = Debate.with_hidden.find(params[:id])
@debate.restore
redirect_to admin_debates_path, notice: t('admin.debates.restore.success')
redirect_to request.query_parameters.merge(action: :index)
end
end
private
def load_debate
@debate = Debate.with_hidden.find(params[:id])
end
def set_valid_filters
@valid_filters = %w{all with_confirmed_hide}
end
def parse_filter
@filter = params[:filter]
@filter = 'all' unless @valid_filters.include?(@filter)
end
end

View File

@@ -1,25 +1,42 @@
class Admin::UsersController < Admin::BaseController
before_filter :set_valid_filters, only: :index
before_filter :parse_filter, only: :index
before_filter :load_user, only: [:confirm_hide, :restore]
def index
@users = User.only_hidden.page(params[:page])
@users = User.only_hidden.send(@filter).page(params[:page])
end
def show
@user = User.with_hidden.find(params[:id])
@debates = Debate.where(author_id: @user.id).with_hidden.page(params[:page])
@comments = Comment.where(user_id: @user.id).with_hidden.page(params[:page])
@debates = @user.debates.with_hidden.page(params[:page])
@comments = @user.comments.with_hidden.page(params[:page])
end
def confirm_hide
@user.confirm_hide
redirect_to request.query_parameters.merge(action: :index)
end
def restore
user = User.with_hidden.find(params[:id])
if hidden_at = user.hidden_at
debates_ids = Debate.only_hidden.where(author_id: user.id).where("debates.hidden_at > ?", hidden_at).pluck(:id)
comments_ids = Comment.only_hidden.where(user_id: user.id).where("comments.hidden_at > ?", hidden_at).pluck(:id)
user.restore
Debate.restore_all debates_ids
Comment.restore_all comments_ids
end
redirect_to admin_users_path, notice: t('admin.users.restore.success')
@user.restore
redirect_to request.query_parameters.merge(action: :index)
end
end
private
def load_user
@user = User.with_hidden.find(params[:id])
end
def set_valid_filters
@valid_filters = %w{all with_confirmed_hide}
end
def parse_filter
@filter = params[:filter]
@filter = 'all' unless @valid_filters.include?(@filter)
end
end

View File

@@ -22,14 +22,14 @@ class CommentsController < ApplicationController
respond_with @comment
end
def flag_as_inappropiate
InappropiateFlag.flag!(current_user, @comment)
respond_with @comment, template: 'comments/_refresh_flag_as_inappropiate_actions'
def flag
Flag.flag!(current_user, @comment)
respond_with @comment, template: 'comments/_refresh_flag_actions'
end
def undo_flag_as_inappropiate
InappropiateFlag.unflag!(current_user, @comment)
respond_with @comment, template: 'comments/_refresh_flag_as_inappropiate_actions'
def unflag
Flag.unflag!(current_user, @comment)
respond_with @comment, template: 'comments/_refresh_flag_actions'
end
private

View File

@@ -52,14 +52,14 @@ class DebatesController < ApplicationController
set_debate_votes(@debate)
end
def flag_as_inappropiate
InappropiateFlag.flag!(current_user, @debate)
respond_with @debate, template: 'debates/_refresh_flag_as_inappropiate_actions'
def flag
Flag.flag!(current_user, @debate)
respond_with @debate, template: 'debates/_refresh_flag_actions'
end
def undo_flag_as_inappropiate
InappropiateFlag.unflag!(current_user, @debate)
respond_with @debate, template: 'debates/_refresh_flag_as_inappropiate_actions'
def unflag
Flag.unflag!(current_user, @debate)
respond_with @debate, template: 'debates/_refresh_flag_actions'
end
private

View File

@@ -19,19 +19,19 @@ class Moderation::CommentsController < Moderation::BaseController
redirect_to request.query_parameters.merge(action: :index)
end
def archive
@comment.archive
def ignore_flag
@comment.ignore_flag
redirect_to request.query_parameters.merge(action: :index)
end
private
def load_comments
@comments = Comment.accessible_by(current_ability, :hide).flagged_as_inappropiate.sorted_for_moderation.includes(:commentable)
@comments = Comment.accessible_by(current_ability, :hide).flagged.sorted_for_moderation.includes(:commentable)
end
def set_valid_filters
@valid_filters = %w{all pending archived}
@valid_filters = %w{all pending_flag_review with_ignored_flag}
end
def parse_filter

View File

@@ -19,19 +19,19 @@ class Moderation::DebatesController < Moderation::BaseController
redirect_to request.query_parameters.merge(action: :index)
end
def archive
@debate.archive
def ignore_flag
@debate.ignore_flag
redirect_to request.query_parameters.merge(action: :index)
end
private
def load_debates
@debates = Debate.accessible_by(current_ability, :hide).flagged_as_inappropiate.sorted_for_moderation
@debates = Debate.accessible_by(current_ability, :hide).flagged.sorted_for_moderation
end
def set_valid_filters
@valid_filters = %w{all pending archived}
@valid_filters = %w{all pending_flag_review with_ignored_flag}
end
def parse_filter

View File

@@ -22,20 +22,20 @@ class Ability
can :create, Comment
can :create, Debate
can :flag_as_inappropiate, Comment do |comment|
comment.author_id != user.id && !InappropiateFlag.flagged?(user, comment)
can :flag, Comment do |comment|
comment.author_id != user.id && !Flag.flagged?(user, comment)
end
can :undo_flag_as_inappropiate, Comment do |comment|
comment.author_id != user.id && InappropiateFlag.flagged?(user, comment)
can :unflag, Comment do |comment|
comment.author_id != user.id && Flag.flagged?(user, comment)
end
can :flag_as_inappropiate, Debate do |debate|
debate.author_id != user.id && !InappropiateFlag.flagged?(user, debate)
can :flag, Debate do |debate|
debate.author_id != user.id && !Flag.flagged?(user, debate)
end
can :undo_flag_as_inappropiate, Debate do |debate|
debate.author_id != user.id && InappropiateFlag.flagged?(user, debate)
can :unflag, Debate do |debate|
debate.author_id != user.id && Flag.flagged?(user, debate)
end
unless user.organization?
@@ -53,14 +53,14 @@ class Ability
can :hide, Comment, hidden_at: nil
cannot :hide, Comment, user_id: user.id
can :archive, Comment, archived_at: nil, hidden_at: nil
cannot :archive, Comment, user_id: user.id
can :ignore_flag, Comment, ignored_flag_at: nil, hidden_at: nil
cannot :ignore_flag, Comment, user_id: user.id
can :hide, Debate, hidden_at: nil
cannot :hide, Debate, author_id: user.id
can :archive, Debate, archived_at: nil, hidden_at: nil
cannot :archive, Debate, author_id: user.id
can :ignore_flag, Debate, ignored_flag_at: nil, hidden_at: nil
cannot :ignore_flag, Debate, author_id: user.id
can :hide, User
cannot :hide, User, id: user.id
@@ -72,8 +72,23 @@ class Ability
if user.administrator?
can :restore, Comment
cannot :restore, Comment, hidden_at: nil
can :restore, Debate
cannot :restore, Debate, hidden_at: nil
can :restore, User
cannot :restore, User, hidden_at: nil
can :confirm_hide, Comment
cannot :confirm_hide, Comment, hidden_at: nil
can :confirm_hide, Debate
cannot :confirm_hide, Debate, hidden_at: nil
can :confirm_hide, User
cannot :confirm_hide, User, hidden_at: nil
can :comment_as_administrator, [Debate, Comment]
end
end

View File

@@ -1,7 +1,7 @@
class Comment < ActiveRecord::Base
include ActsAsParanoidAliases
acts_as_nested_set scope: [:commentable_id, :commentable_type], counter_cache: :children_count
acts_as_paranoid column: :hidden_at
include ActsAsParanoidAliases
acts_as_votable
attr_accessor :as_moderator, :as_administrator
@@ -12,14 +12,14 @@ class Comment < ActiveRecord::Base
belongs_to :commentable, polymorphic: true, counter_cache: true
belongs_to :user, -> { with_hidden }
has_many :inappropiate_flags, :as => :flaggable
has_many :flags, :as => :flaggable
scope :recent, -> { order(id: :desc) }
scope :sorted_for_moderation, -> { order(inappropiate_flags_count: :desc, updated_at: :desc) }
scope :pending, -> { where(archived_at: nil, hidden_at: nil) }
scope :archived, -> { where("archived_at IS NOT NULL AND hidden_at IS NULL") }
scope :flagged_as_inappropiate, -> { where("inappropiate_flags_count > 0") }
scope :sorted_for_moderation, -> { order(flags_count: :desc, updated_at: :desc) }
scope :pending_flag_review, -> { where(ignored_flag_at: nil, hidden_at: nil) }
scope :with_ignored_flag, -> { where("ignored_flag_at IS NOT NULL AND hidden_at IS NULL") }
scope :flagged, -> { where("flags_count > 0") }
scope :for_render, -> { with_hidden.includes(user: :organization) }
@@ -65,8 +65,12 @@ class Comment < ActiveRecord::Base
hidden? || user.hidden?
end
def archived?
archived_at.present?
def ignored_flag?
ignored_flag_at.present?
end
def ignore_flag
update(ignored_flag_at: Time.now)
end
def as_administrator?
@@ -77,10 +81,6 @@ class Comment < ActiveRecord::Base
moderator_id.present?
end
def archive
update(archived_at: Time.now)
end
# TODO: faking counter cache since there is a bug with acts_as_nested_set :counter_cache
# Remove when https://github.com/collectiveidea/awesome_nested_set/issues/294 is fixed
# and reset counters using

View File

@@ -1,6 +1,5 @@
require 'numeric'
class Debate < ActiveRecord::Base
include ActsAsParanoidAliases
default_scope { order(created_at: :desc) }
apply_simple_captcha
@@ -10,9 +9,10 @@ class Debate < ActiveRecord::Base
acts_as_commentable
acts_as_taggable
acts_as_paranoid column: :hidden_at
include ActsAsParanoidAliases
belongs_to :author, -> { with_hidden }, class_name: 'User', foreign_key: 'author_id'
has_many :inappropiate_flags, :as => :flaggable
has_many :flags, :as => :flaggable
validates :title, presence: true
validates :description, presence: true
@@ -23,10 +23,10 @@ class Debate < ActiveRecord::Base
before_validation :sanitize_description
before_validation :sanitize_tag_list
scope :sorted_for_moderation, -> { order(inappropiate_flags_count: :desc, updated_at: :desc) }
scope :pending, -> { where(archived_at: nil, hidden_at: nil) }
scope :archived, -> { where("archived_at IS NOT NULL AND hidden_at IS NULL") }
scope :flagged_as_inappropiate, -> { where("inappropiate_flags_count > 0") }
scope :sorted_for_moderation, -> { order(flags_count: :desc, updated_at: :desc) }
scope :pending_flag_review, -> { where(ignored_flag_at: nil, hidden_at: nil) }
scope :with_ignored_flag, -> { where("ignored_flag_at IS NOT NULL AND hidden_at IS NULL") }
scope :flagged, -> { where("flags_count > 0") }
scope :for_render, -> { includes(:tags) }
scope :sort_by_total_votes, -> { reorder(cached_votes_total: :desc) }
scope :sort_by_likes , -> { reorder(cached_votes_up: :desc) }
@@ -79,12 +79,12 @@ class Debate < ActiveRecord::Base
count < 0 ? 0 : count
end
def archived?
archived_at.present?
def ignored_flag?
ignored_flag_at.present?
end
def archive
update(archived_at: Time.now)
def ignore_flag
update(ignored_flag_at: Time.now)
end
protected

View File

@@ -1,7 +1,7 @@
class InappropiateFlag < ActiveRecord::Base
class Flag < ActiveRecord::Base
belongs_to :user
belongs_to :flaggable, polymorphic: true, counter_cache: true, touch: :flagged_as_inappropiate_at
belongs_to :flaggable, polymorphic: true, counter_cache: true
scope(:by_user_and_flaggable, lambda do |user, flaggable|
where(user_id: user.id,
@@ -12,13 +12,13 @@ class InappropiateFlag < ActiveRecord::Base
class AlreadyFlaggedError < StandardError
def initialize
super "The flaggable was already flagged as inappropiate by this user"
super "The flaggable was already flagged by this user"
end
end
class NotFlaggedError < StandardError
def initialize
super "The flaggable was not flagged as inappropiate by this user"
super "The flaggable was not flagged by this user"
end
end

View File

@@ -1,5 +1,4 @@
class User < ActiveRecord::Base
include ActsAsParanoidAliases
OMNIAUTH_EMAIL_PREFIX = 'omniauth@participacion'
OMNIAUTH_EMAIL_REGEX = /\A#{OMNIAUTH_EMAIL_PREFIX}/
@@ -10,12 +9,15 @@ class User < ActiveRecord::Base
acts_as_voter
acts_as_paranoid column: :hidden_at
include ActsAsParanoidAliases
has_one :administrator
has_one :moderator
has_one :organization
has_many :inappropiate_flags
has_many :flags
has_many :identities, dependent: :destroy
has_many :debates, -> { with_hidden }, foreign_key: :author_id
has_many :comments, -> { with_hidden }
validates :username, presence: true, unless: :organization?
validates :official_level, inclusion: {in: 0..5}
@@ -114,4 +116,5 @@ class User < ActiveRecord::Base
!!(email && email !~ OMNIAUTH_EMAIL_REGEX) ||
!!(unconfirmed_email && unconfirmed_email !~ OMNIAUTH_EMAIL_REGEX)
end
end

View File

@@ -1,13 +1,17 @@
<h2><%= t("admin.comments.index.title") %></h2>
<!-- Filters for pending and archived comments (example on "/admin/organizations/index.html.erb")-->
<dl class="sub-nav">
<dt><%= t("admin.comments.index.filter") %>:</dt>
<dd class="active"><%= t("admin.comments.filters.all") %></dd>
<dd><%= t("admin.comments.filters.pending") %></dd>
<dd><%= t("admin.comments.filters.archived") %></dd>
<% @valid_filters.each do |filter| %>
<% if @filter == filter %>
<dd class="active"><%= t("admin.comments.index.filters.#{filter}") %></dd>
<% else %>
<dd><%= link_to t("admin.comments.index.filters.#{filter}"),
admin_comments_path(filter: filter) %></dd>
<% end %>
<% end %>
</dl>
<!-- Filters for pending and archived comments (example on "/admin/organizations/index.html.erb")-->
<h3><%= page_entries_info @comments %></h3>
@@ -17,17 +21,19 @@
<div class="row">
<div class="small-12 medium-8 column">
<%= comment.body %>
<!-- Link to debate of this comment -->
<%= link_to t("admin.comments.index.show_debate"), "#" %>
<!-- /. Link to debate of this comment -->
<%= link_to comment.commentable.title, comment.commentable %>
</div>
<div class="small-6 medium-4 column text-right">
<!-- Link to archive this comment -->
<%= link_to t("admin.actions.archive"), "#", class: "button radius tiny warning" %>
<!-- /. Link to archive this comment -->
<%= link_to t("admin.actions.restore"), restore_admin_comment_path(comment),
method: :put, data: { confirm: t("admin.actions.confirm") },
class: "button radius tiny success" %>
<%= link_to t("admin.actions.restore"),
restore_admin_comment_path(comment, request.query_parameters),
method: :put,
data: { confirm: t("admin.actions.confirm") },
class: "button radius tiny success right" %>
<%= link_to t("admin.actions.confirm_hide"),
confirm_hide_admin_comment_path(comment, request.query_parameters),
method: :put,
class: "button radius tiny warning right" %>
</div>
</div>
</li>

View File

@@ -1,30 +1,37 @@
<h2><%= t("admin.debates.index.title") %></h2>
<!-- Filters for pending and archived debates (example on "/admin/organizations/index.html.erb")-->
<dl class="sub-nav">
<dt><%= t("admin.debates.index.filter") %>:</dt>
<dd class="active"><%= t("admin.debates.filters.all") %></dd>
<dd><%= t("admin.debates.filters.pending") %></dd>
<dd><%= t("admin.debates.filters.archived") %></dd>
<% @valid_filters.each do |filter| %>
<% if @filter == filter %>
<dd class="active"><%= t("admin.debates.index.filters.#{filter}") %></dd>
<% else %>
<dd><%= link_to t("admin.debates.index.filters.#{filter}"),
admin_debates_path(filter: filter) %></dd>
<% end %>
<% end %>
</dl>
<!-- Filters for pending and archived debates (example on "/admin/organizations/index.html.erb")-->
<h3><%= page_entries_info @debates %></h3>
<ul class="admin-list">
<% @debates.each do |debate| %>
<li id="<%= dom_id(debate) %>">
<%= link_to debate.title, admin_debate_path(debate) %>
<%= link_to debate.title, debate_path(debate) %>
<%= link_to t("admin.actions.restore"), restore_admin_debate_path(debate),
method: :put, data: { confirm: t("admin.actions.confirm") },
<%= link_to t("admin.actions.restore"),
restore_admin_debate_path(debate, request.query_parameters),
method: :put,
data: { confirm: t("admin.actions.confirm") },
class: "button radius tiny success right" %>
<!-- Link to archive this debate -->
<%= link_to t("admin.actions.archive"), "#", class: "button radius tiny warning right" %>
<!-- /. Link to archive this debate -->
<%= link_to t("admin.actions.confirm_hide"),
confirm_hide_admin_debate_path(debate, request.query_parameters),
method: :put,
class: "button radius tiny warning right" %>
</li>
<% end %>
</ul>
<%= paginate @debates %>
<%= paginate @debates %>

View File

@@ -1,12 +0,0 @@
<h2><%= t("admin.debates.index.title") %></h2>
<h3><%= @debate.title %></h3>
<div><%= @debate.description %></div>
<%= link_to t("admin.debates.show.back"), admin_debates_path,
class: "button radius small secondary" %>
<%= link_to t("admin.actions.restore"), restore_admin_debate_path(@debate),
method: :put, data: { confirm: t("admin.actions.confirm") },
class: "button radius small success" %>

View File

@@ -1,5 +1,18 @@
<h2><%= t("admin.users.index.title") %></h2>
<dl class="sub-nav">
<dt><%= t("admin.users.index.filter") %>:</dt>
<% @valid_filters.each do |filter| %>
<% if @filter == filter %>
<dd class="active"><%= t("admin.users.index.filters.#{filter}") %></dd>
<% else %>
<dd><%= link_to t("admin.users.index.filters.#{filter}"),
admin_users_path(filter: filter) %></dd>
<% end %>
<% end %>
</dl>
<h3><%= page_entries_info @users %></h3>
<ul class="admin-list">
@@ -7,8 +20,16 @@
<li>
<%= link_to user.name, admin_user_path(user) %>
<%= link_to t("admin.users.index.restore"), restore_admin_user_path(user),
method: :put, data: { confirm: t('admin.actions.confirm') }, class: "button radius tiny right" %>
<%= link_to t("admin.actions.restore"),
restore_admin_user_path(user, request.query_parameters),
method: :put,
data: { confirm: t("admin.actions.confirm") },
class: "button radius tiny success right" %>
<%= link_to t("admin.actions.confirm_hide"),
confirm_hide_admin_user_path(user, request.query_parameters),
method: :put,
class: "button radius tiny warning right" %>
</li>
<% end %>
</ul>

View File

@@ -6,8 +6,6 @@
<strong><%= t("admin.users.show.hidden_at") %></strong> <%= @user.hidden_at %>
</p>
<p>
<%= link_to t("admin.users.show.restore"), restore_admin_user_path(@user),
method: :put, data: { confirm: t('admin.actions.confirm') }, class: "button radius tiny" %>
<%= link_to t("admin.users.show.back"), admin_users_path,
class: "button radius tiny secondary" %>
</p>
@@ -19,7 +17,7 @@
<ul class="admin-list">
<% @debates.each do |debate| %>
<li>
<%= link_to debate.title, admin_debate_path(debate) %>
<%= link_to debate.title, debate_path(debate) %>
</li>
<% end %>
</ul>

View File

@@ -1,5 +1,5 @@
<span class="js-flag-as-inappropiate-actions">
<%= render 'comments/flag_as_inappropiate_actions', comment: comment %>
<span class="js-flag-actions">
<%= render 'comments/flag_actions', comment: comment %>
</span>
<span class='js-moderation-actions'>

View File

@@ -1,23 +1,23 @@
<% if can? :flag_as_inappropiate, comment %>
<% if can? :flag, comment %>
<span class="divider">&nbsp;|&nbsp;</span>
<a id="flag-expand-comment-<%= comment.id %>" data-dropdown="flag-drop-comment-<%= comment.id %>" aria-controls="flag-drop-comment-<%= comment.id %>" aria-expanded="false" title="<%= t('shared.flag_as_inappropiate') %>">
<a id="flag-expand-comment-<%= comment.id %>" data-dropdown="flag-drop-comment-<%= comment.id %>" aria-controls="flag-drop-comment-<%= comment.id %>" aria-expanded="false" title="<%= t('shared.flag') %>">
&nbsp;<i class="icon-flag flag-disable"></i>&nbsp;&nbsp;
</a>
<ul id="flag-drop-comment-<%= comment.id %>" class="f-dropdown" data-dropdown-content aria-hidden="true" tabindex="-1">
<li>
<%= link_to t("shared.flag_as_inappropiate"), flag_as_inappropiate_comment_path(comment), method: :put, remote: true, id: "flag-comment-#{comment.id}" %>
<%= link_to t("shared.flag"), flag_comment_path(comment), method: :put, remote: true, id: "flag-comment-#{comment.id}" %>
</li>
</ul>
<% end %>
<% if can? :undo_flag_as_inappropiate, comment %>
<% if can? :unflag, comment %>
<span class="divider">&nbsp;|&nbsp;</span>
<a id="unflag-expand-comment-<%= comment.id %>" data-dropdown="unflag-drop-comment-<%= comment.id %>" aria-controls="unflag-drop-comment-<%= comment.id %>" aria-expanded="false" title="<%= t('shared.undo_flag_as_inappropiate') %>">
<a id="unflag-expand-comment-<%= comment.id %>" data-dropdown="unflag-drop-comment-<%= comment.id %>" aria-controls="unflag-drop-comment-<%= comment.id %>" aria-expanded="false" title="<%= t('shared.unflag') %>">
&nbsp;<i class="icon-flag flag-active"></i>&nbsp;&nbsp;
</a>
<ul id="unflag-drop-comment-<%= comment.id %>" class="f-dropdown" data-dropdown-content aria-hidden="true" tabindex="-1">
<li>
<%= link_to t("shared.undo_flag_as_inappropiate"), undo_flag_as_inappropiate_comment_path(comment), method: :put, remote: true, id: "unflag-comment-#{comment.id}" %>
<%= link_to t("shared.unflag"), unflag_comment_path(comment), method: :put, remote: true, id: "unflag-comment-#{comment.id}" %>
</li>
</ul>
<% end %>

View File

@@ -0,0 +1 @@
$("#<%= dom_id(@comment) %> .js-flag-actions").html('<%= j render("comments/flag_actions", comment: @comment) %>');

View File

@@ -1 +0,0 @@
$("#<%= dom_id(@comment) %> .js-flag-as-inappropiate-actions").html('<%= j render("comments/flag_as_inappropiate_actions", comment: @comment) %>');

View File

@@ -1,21 +1,21 @@
<% if can? :flag_as_inappropiate, debate %>
<a id="flag-expand-debate-<%= debate.id %>" data-dropdown="flag-drop-debate-<%= debate.id %>" aria-controls="flag-drop-debate-<%= debate.id %>" aria-expanded="false" title="<%= t('shared.flag_as_inappropiate') %>">
<% if can? :flag, debate %>
<a id="flag-expand-debate-<%= debate.id %>" data-dropdown="flag-drop-debate-<%= debate.id %>" aria-controls="flag-drop-debate-<%= debate.id %>" aria-expanded="false" title="<%= t('shared.flag') %>">
&nbsp;<i class="icon-flag flag-disable"></i>&nbsp;&nbsp;
</a>
<ul id="flag-drop-debate-<%= debate.id %>" class="f-dropdown" data-dropdown-content aria-hidden="true" tabindex="-1">
<li>
<%= link_to t('shared.flag_as_inappropiate'), flag_as_inappropiate_debate_path(debate), method: :put, remote: true, id: "flag-debate-#{ debate.id }" %>
<%= link_to t('shared.flag'), flag_debate_path(debate), method: :put, remote: true, id: "flag-debate-#{ debate.id }" %>
</li>
</ul>
<% end %>
<% if can? :undo_flag_as_inappropiate, debate %>
<a id="unflag-expand-debate-<%= debate.id %>" data-dropdown="unflag-drop-debate-<%= debate.id %>" aria-controls="unflag-drop-debate-<%= debate.id %>" aria-expanded="false" title="<%= t('shared.undo_flag_as_inappropiate') %>">
<% if can? :unflag, debate %>
<a id="unflag-expand-debate-<%= debate.id %>" data-dropdown="unflag-drop-debate-<%= debate.id %>" aria-controls="unflag-drop-debate-<%= debate.id %>" aria-expanded="false" title="<%= t('shared.unflag') %>">
&nbsp;<i class="icon-flag flag-active"></i>&nbsp;&nbsp;
</a>
<ul id="unflag-drop-debate-<%= debate.id %>" class="f-dropdown" data-dropdown-content aria-hidden="true" tabindex="-1">
<li>
<%= link_to t('shared.undo_flag_as_inappropiate'), undo_flag_as_inappropiate_debate_path(debate), method: :put, remote: true, id: "unflag-debate-#{ debate.id }" %>
<%= link_to t('shared.unflag'), unflag_debate_path(debate), method: :put, remote: true, id: "unflag-debate-#{ debate.id }" %>
</li>
</ul>
<% end %>

View File

@@ -0,0 +1 @@
$("#<%= dom_id(@debate) %> .js-flag-actions").html('<%= j render("debates/flag_actions", debate: @debate) %>');

View File

@@ -1 +0,0 @@
$("#<%= dom_id(@debate) %> .js-flag-as-inappropiate-actions").html('<%= j render("debates/flag_as_inappropiate_actions", debate: @debate) %>');

View File

@@ -42,8 +42,8 @@
<i class="icon-comments"></i>&nbsp;
<%= link_to t("debates.show.comments", count: @debate.comments_count), "#comments" %>
<span class="bullet">&nbsp;&bullet;&nbsp;</span>
<span class="js-flag-as-inappropiate-actions">
<%= render 'debates/flag_as_inappropiate_actions', debate: @debate %>
<span class="js-flag-actions">
<%= render 'debates/flag_actions', debate: @debate %>
</span>
</div>

View File

@@ -35,18 +35,18 @@
<span class="date"><%= l comment.updated_at.to_date %></span>
</td>
<td><%= comment.body %></td>
<td class="text-center"><%= comment.inappropiate_flags_count %></td>
<td class="text-center"><%= comment.flags_count %></td>
<td>
<%= link_to t("moderation.comments.index.hide"), hide_in_moderation_screen_moderation_comment_path(comment, request.query_parameters), method: :put, class: "delete" %>
</td>
<% if can? :archive, comment %>
<% if can? :ignore_flag, comment %>
<td>
<%= link_to t("moderation.comments.index.archive"), archive_moderation_comment_path(comment, request.query_parameters), method: :put, class: "button radius tiny warning" %>
<%= link_to t("moderation.comments.index.ignore_flag"), ignore_flag_moderation_comment_path(comment, request.query_parameters), method: :put, class: "button radius tiny warning" %>
</td>
<% end %>
<% if comment.archived? %>
<td class="archived">
<%= t("moderation.comments.index.archived") %>
<% if comment.ignored_flag? %>
<td class="ignored">
<%= t("moderation.comments.index.ignored_flag") %>
</td>
<% end %>
</tr>

View File

@@ -34,18 +34,18 @@
<br>
<%= debate.description %>
</td>
<td class="text-center"><%= debate.inappropiate_flags_count %></td>
<td class="text-center"><%= debate.flags_count %></td>
<td>
<%= link_to t("moderation.debates.index.hide"), hide_in_moderation_screen_moderation_debate_path(debate, request.query_parameters), method: :put, class: "delete" %>
</td>
<% if can? :archive, debate %>
<% if can? :ignore_flag, debate %>
<td>
<%= link_to t("moderation.debates.index.archive"), archive_moderation_debate_path(debate, request.query_parameters), method: :put, class: "button radius tiny warning" %>
<%= link_to t("moderation.debates.index.ignore_flag"), ignore_flag_moderation_debate_path(debate, request.query_parameters), method: :put, class: "button radius tiny warning" %>
</td>
<% end %>
<% if debate.archived? %>
<td class="archived">
<%= t("moderation.debates.index.archived") %>
<% if debate.ignored_flag? %>
<td class="ignored">
<%= t("moderation.debates.index.ignored_flag") %>
</td>
<% end %>
</tr>

View File

@@ -36,7 +36,7 @@ en:
hide_author: Ban author
restore: Restore
confirm: 'Are you sure?'
archive: Archive
confirm_hide: Confirm
tags:
index:
title: 'Debate topics'
@@ -48,39 +48,30 @@ en:
comments:
index:
title: Hidden comments
show_debate: Show debate
filter: Filter
restore:
success: The comment has been restored
filters:
all: All
pending: Pending
archived: Archived
filters:
all: All
with_confirmed_hide: Confirmed
debates:
index:
title: Hidden debates
filter: Filter
show:
back: Back
restore:
success: The debate has been restored
filters:
all: All
pending: Pending
archived: Archived
filters:
all: All
with_confirmed_hide: Confirmed
users:
index:
title: Banned users
restore: Restore user
filter: Filter
filters:
all: All
with_confirmed_hide: Confirmed
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

View File

@@ -36,7 +36,7 @@ es:
hide_author: Bloquear al autor
restore: Volver a mostrar
confirm: '¿Estás seguro?'
archive: Archivar
confirm_hide: Confirmar
tags:
index:
title: 'Temas de debate'
@@ -48,39 +48,30 @@ es:
comments:
index:
title: Comentarios ocultos
show_debate: Ver debate
filter: Filtro
restore:
success: El comentario ha sido permitido
filters:
all: Todos
pending: Pendientes
archived: Archivados
filter: Firar
filters:
all: Todos
with_confirmed_hide: Confirmados
debates:
index:
title: Debates ocultos
filter: Filtro
show:
back: Volver
restore:
success: El debate ha sido permitido
filters:
all: Todos
pending: Pendientes
archived: Archivados
filters:
all: Todos
with_confirmed_hide: Confirmados
users:
index:
title: Usuarios bloqueados
restore: Restaurar usuario
filter: Filro
filters:
all: Todos
with_confirmed_hide: Confirmados
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

View File

@@ -159,8 +159,8 @@ en:
shared:
tags_cloud:
tags: Topics
flag_as_inappropiate: Flag as inappropriate
undo_flag_as_inappropiate: Undo flag
flag: Flag as inappropriate
unflag: Undo flag
collective: Collective
mailer:
comment:

View File

@@ -159,8 +159,8 @@ es:
shared:
tags_cloud:
tags: Temas
flag_as_inappropiate: Denunciar como inapropiado
undo_flag_as_inappropiate: Deshacer denuncia
flag: Denunciar como inapropiado
unflag: Deshacer denuncia
collective: Colectivo
mailer:
comment:

View File

@@ -16,13 +16,13 @@ en:
commentable: Root
comment: Comment
hide: Hide
archive: Archive
archived: Archived
ignore_flag: Ignore
ignored_flag: Ignored
filter: Filter
filters:
all: All
pending: Pending
archived: Archived
pending_flag_review: Pending
with_ignored_flag: Ignored
debates:
index:
title: Debates flagged as inappropriate
@@ -33,10 +33,10 @@ en:
description: Description
actions: Actions
hide: Hide
archive: Archive
archived: Archived
ignore_flag: Ignore
ignored_flag: Ignored
filter: Filter
filters:
all: All
pending: Pending
archived: Archived
pending_flag_review: Pending
with_ignored_flag: Ignored

View File

@@ -16,13 +16,13 @@ es:
commentable: Raíz
comment: Comentario
hide: Ocultar
archive: Archivar
archived: Archivado
ignore_flag: Ignorar
ignored_flag: Ignorado
filter: Filtrar
filters:
all: Todos
pending: Pendientes
archived: Archivados
pending_flag_review: Pendientes
with_ignored_flag: Ignorados
debates:
index:
title: Debates denunciados como inapropiados
@@ -33,10 +33,10 @@ es:
description: Descripción
actions: Acciones
hide: Ocultar
archive: Archivar
archived: Archivado
ignore_flag: Ignorar
ignored_flag: Ignorado
filter: Filtrar
filters:
all: Todos
pending: Pendientes
archived: Archivados
pending_flag_review: Pendientes
with_ignored_flag: Ignorados

View File

@@ -28,15 +28,15 @@ Rails.application.routes.draw do
resources :debates do
member do
post :vote
put :flag_as_inappropiate
put :undo_flag_as_inappropiate
put :flag
put :unflag
end
resources :comments, only: :create, shallow: true do
member do
post :vote
put :flag_as_inappropiate
put :undo_flag_as_inappropiate
put :flag
put :unflag
end
end
end
@@ -58,15 +58,24 @@ Rails.application.routes.draw do
end
resources :users, only: [:index, :show] do
member { put :restore }
member do
put :restore
put :confirm_hide
end
end
resources :debates, only: [:index, :show] do
member { put :restore }
resources :debates, only: :index do
member do
put :restore
put :confirm_hide
end
end
resources :comments, only: :index do
member { put :restore }
member do
put :restore
put :confirm_hide
end
end
resources :tags, only: [:index, :create, :update, :destroy]
@@ -88,7 +97,7 @@ Rails.application.routes.draw do
member do
put :hide
put :hide_in_moderation_screen
put :archive
put :ignore_flag
end
end
@@ -96,7 +105,7 @@ Rails.application.routes.draw do
member do
put :hide
put :hide_in_moderation_screen
put :archive
put :ignore_flag
end
end
end

View File

@@ -0,0 +1,5 @@
class RenameInappropiateFlagsAsFlags < ActiveRecord::Migration
def change
rename_table :inappropiate_flags, :flags
end
end

View File

@@ -0,0 +1,6 @@
class RenameArchivedAtToIgnoredFlagAtInCommentsAndDebates < ActiveRecord::Migration
def change
rename_column :comments, :archived_at, :ignored_flag_at
rename_column :debates, :archived_at, :ignored_flag_at
end
end

View File

@@ -0,0 +1,6 @@
class AddConfirmedHideAtToCommentsAndDebates < ActiveRecord::Migration
def change
add_column :debates, :confirmed_hide_at, :datetime
add_column :comments, :confirmed_hide_at, :datetime
end
end

View File

@@ -0,0 +1,6 @@
class RenameInappropiateFlagsCountToFlagsCountInDebatesAndComments < ActiveRecord::Migration
def change
rename_column :debates, :inappropiate_flags_count, :flags_count
rename_column :comments, :inappropiate_flags_count, :flags_count
end
end

View File

@@ -0,0 +1,6 @@
class RemoveFlaggedAsInappropiateAtFromCommentsAndDebates < ActiveRecord::Migration
def change
remove_column :debates, :flagged_as_inappropiate_at
remove_column :comments, :flagged_as_inappropiate_at
end
end

View File

@@ -0,0 +1,5 @@
class AddConfirmedHideAtToUsers < ActiveRecord::Migration
def change
add_column :users, :confirmed_hide_at, :datetime
end
end

View File

@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20150826112500) do
ActiveRecord::Schema.define(version: 20150828085718) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -41,22 +41,22 @@ ActiveRecord::Schema.define(version: 20150826112500) do
t.string "title"
t.text "body"
t.string "subject"
t.integer "user_id", null: false
t.integer "user_id", null: false
t.integer "parent_id"
t.integer "lft"
t.integer "rgt"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "children_count", default: 0
t.integer "children_count", default: 0
t.datetime "hidden_at"
t.datetime "flagged_as_inappropiate_at"
t.integer "inappropiate_flags_count", default: 0
t.datetime "archived_at"
t.integer "flags_count", default: 0
t.datetime "ignored_flag_at"
t.integer "moderator_id"
t.integer "administrator_id"
t.integer "cached_votes_total", default: 0
t.integer "cached_votes_up", default: 0
t.integer "cached_votes_down", default: 0
t.integer "cached_votes_total", default: 0
t.integer "cached_votes_up", default: 0
t.integer "cached_votes_down", default: 0
t.datetime "confirmed_hide_at"
end
add_index "comments", ["cached_votes_down"], name: "index_comments_on_cached_votes_down", using: :btree
@@ -67,20 +67,20 @@ ActiveRecord::Schema.define(version: 20150826112500) do
add_index "comments", ["user_id"], name: "index_comments_on_user_id", using: :btree
create_table "debates", force: :cascade do |t|
t.string "title", limit: 80
t.string "title", limit: 80
t.text "description"
t.integer "author_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.datetime "hidden_at"
t.string "visit_id"
t.datetime "flagged_as_inappropiate_at"
t.integer "inappropiate_flags_count", default: 0
t.integer "cached_votes_total", default: 0
t.integer "cached_votes_up", default: 0
t.integer "cached_votes_down", default: 0
t.datetime "archived_at"
t.integer "comments_count", default: 0
t.integer "flags_count", default: 0
t.integer "cached_votes_total", default: 0
t.integer "cached_votes_up", default: 0
t.integer "cached_votes_down", default: 0
t.datetime "ignored_flag_at"
t.integer "comments_count", default: 0
t.datetime "confirmed_hide_at"
end
add_index "debates", ["cached_votes_down"], name: "index_debates_on_cached_votes_down", using: :btree
@@ -88,6 +88,18 @@ ActiveRecord::Schema.define(version: 20150826112500) do
add_index "debates", ["cached_votes_up"], name: "index_debates_on_cached_votes_up", using: :btree
add_index "debates", ["hidden_at"], name: "index_debates_on_hidden_at", using: :btree
create_table "flags", force: :cascade do |t|
t.integer "user_id"
t.string "flaggable_type"
t.integer "flaggable_id"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "flags", ["flaggable_type", "flaggable_id"], name: "index_flags_on_flaggable_type_and_flaggable_id", using: :btree
add_index "flags", ["user_id", "flaggable_type", "flaggable_id"], name: "access_inappropiate_flags", using: :btree
add_index "flags", ["user_id"], name: "index_flags_on_user_id", using: :btree
create_table "identities", force: :cascade do |t|
t.integer "user_id"
t.string "provider"
@@ -98,18 +110,6 @@ ActiveRecord::Schema.define(version: 20150826112500) do
add_index "identities", ["user_id"], name: "index_identities_on_user_id", using: :btree
create_table "inappropiate_flags", force: :cascade do |t|
t.integer "user_id"
t.string "flaggable_type"
t.integer "flaggable_id"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "inappropiate_flags", ["flaggable_type", "flaggable_id"], name: "index_inappropiate_flags_on_flaggable_type_and_flaggable_id", using: :btree
add_index "inappropiate_flags", ["user_id", "flaggable_type", "flaggable_id"], name: "access_inappropiate_flags", using: :btree
add_index "inappropiate_flags", ["user_id"], name: "index_inappropiate_flags_on_user_id", using: :btree
create_table "moderators", force: :cascade do |t|
t.integer "user_id"
end
@@ -184,6 +184,7 @@ ActiveRecord::Schema.define(version: 20150826112500) do
t.datetime "hidden_at"
t.string "phone_number", limit: 30
t.string "username"
t.datetime "confirmed_hide_at"
end
add_index "users", ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true, using: :btree
@@ -237,8 +238,8 @@ ActiveRecord::Schema.define(version: 20150826112500) do
add_index "votes", ["voter_id", "voter_type", "vote_scope"], name: "index_votes_on_voter_id_and_voter_type_and_vote_scope", using: :btree
add_foreign_key "administrators", "users"
add_foreign_key "flags", "users"
add_foreign_key "identities", "users"
add_foreign_key "inappropiate_flags", "users"
add_foreign_key "moderators", "users"
add_foreign_key "organizations", "users"
end
end

View File

@@ -14,9 +14,26 @@ module ActsAsParanoidAliases
def after_hide
end
def confirmed_hide?
confirmed_hide_at.present?
end
def confirm_hide
update_attribute(:confirmed_hide_at, Time.now)
end
def restore(opts={})
super(opts)
update_attribute(:confirmed_hide_at, nil)
end
end
module ClassMethods
def with_confirmed_hide
where("confirmed_hide_at IS NOT NULL")
end
def with_hidden
with_deleted
end
@@ -35,9 +52,5 @@ module ActsAsParanoidAliases
only_hidden.where(id: ids).update_all(hidden_at: nil)
end
end
end
module ActsAsParanoid
include ActsAsParanoidAliases
end

View File

@@ -4,6 +4,14 @@ FactoryGirl.define do
sequence(:email) { |n| "manuela#{n}@madrid.es" }
password 'judgmentday'
confirmed_at { Time.now }
trait :hidden do
hidden_at Time.now
end
trait :with_confirmed_hide do
confirmed_hide_at Time.now
end
end
factory :identity do
@@ -22,13 +30,17 @@ FactoryGirl.define do
hidden_at Time.now
end
trait :archived do
archived_at Time.now
trait :with_ignored_flag do
ignored_flag_at Time.now
end
trait :flagged_as_inappropiate do
trait :with_confirmed_hide do
confirmed_hide_at Time.now
end
trait :flagged do
after :create do |debate|
InappropiateFlag.flag!(FactoryGirl.create(:user), debate)
Flag.flag!(FactoryGirl.create(:user), debate)
end
end
end
@@ -51,13 +63,17 @@ FactoryGirl.define do
hidden_at Time.now
end
trait :archived do
archived_at Time.now
trait :with_ignored_flag do
ignored_flag_at Time.now
end
trait :flagged_as_inappropiate do
trait :with_confirmed_hide do
confirmed_hide_at Time.now
end
trait :flagged do
after :create do |debate|
InappropiateFlag.flag!(FactoryGirl.create(:user), debate)
Flag.flag!(FactoryGirl.create(:user), debate)
end
end
end

View File

@@ -2,27 +2,71 @@ require 'rails_helper'
feature 'Admin comments' do
scenario 'Restore', :js do
citizen = create(:user)
background do
admin = create(:administrator)
debate = create(:debate)
comment = create(:comment, :hidden, commentable: debate, body: 'Not really SPAM')
login_as(admin.user)
visit admin_comments_path
within("#comment_#{comment.id}") do
first(:link, "Restore").click
end
expect(page).to have_content 'The comment has been restored'
login_as(citizen)
visit debate_path(debate)
expect(page).to have_css('.comment', count: 1)
expect(page).to have_content('Not really SPAM')
end
end
scenario 'Restore', :js do
comment = create(:comment, :hidden, body: 'Not really SPAM')
visit admin_comments_path
click_link 'Restore'
expect(page).to_not have_content(comment.body)
expect(comment.reload).to_not be_hidden
end
scenario 'Confirm hide' do
comment = create(:comment, :hidden, body: 'SPAM')
visit admin_comments_path
click_link 'Confirm'
expect(page).to have_content(comment.body)
expect(page).to have_content('Confirmed')
expect(comment.reload).to be_confirmed_hide
end
scenario "Current filter is properly highlighted" do
visit admin_comments_path
expect(page).to_not have_link('All')
expect(page).to have_link('Confirmed')
visit admin_comments_path(filter: 'all')
expect(page).to_not have_link('All')
expect(page).to have_link('Confirmed')
visit admin_comments_path(filter: 'with_confirmed_hide')
expect(page).to have_link('All')
expect(page).to_not have_link('Confirmed')
end
scenario "Filtering comments" do
create(:comment, :hidden, body: "Unconfirmed comment")
create(:comment, :hidden, :with_confirmed_hide, body: "Confirmed comment")
visit admin_comments_path(filter: 'all')
expect(page).to have_content('Unconfirmed comment')
expect(page).to have_content('Confirmed comment')
visit admin_comments_path(filter: 'with_confirmed_hide')
expect(page).to_not have_content('Unconfirmed comment')
expect(page).to have_content('Confirmed comment')
end
scenario "Action links remember the pagination setting and the filter" do
per_page = Kaminari.config.default_per_page
(per_page + 2).times { create(:comment, :hidden, :with_confirmed_hide) }
visit admin_comments_path(filter: 'with_confirmed_hide', page: 2)
click_on('Restore', match: :first, exact: true)
expect(current_url).to include('filter=with_confirmed_hide')
expect(current_url).to include('page=2')
end
end

View File

@@ -2,22 +2,71 @@ require 'rails_helper'
feature 'Admin debates' do
scenario 'Restore', :js do
citizen = create(:user)
background do
admin = create(:administrator)
debate = create(:debate, :hidden)
login_as(admin.user)
visit admin_debate_path(debate)
end
scenario 'Restore' do
debate = create(:debate, :hidden)
visit admin_debates_path
click_link 'Restore'
expect(page).to have_content 'The debate has been restored'
expect(page).to_not have_content(debate.title)
login_as(citizen)
visit debates_path
expect(page).to have_css('.debate', count: 1)
expect(debate.reload).to_not be_hidden
end
scenario 'Confirm hide' do
debate = create(:debate, :hidden)
visit admin_debates_path
click_link 'Confirm'
expect(page).to have_content(debate.title)
expect(page).to have_content('Confirmed')
expect(debate.reload).to be_confirmed_hide
end
scenario "Current filter is properly highlighted" do
visit admin_debates_path
expect(page).to_not have_link('All')
expect(page).to have_link('Confirmed')
visit admin_debates_path(filter: 'all')
expect(page).to_not have_link('All')
expect(page).to have_link('Confirmed')
visit admin_debates_path(filter: 'with_confirmed_hide')
expect(page).to have_link('All')
expect(page).to_not have_link('Confirmed')
end
scenario "Filtering debates" do
create(:debate, :hidden, title: "Unconfirmed debate")
create(:debate, :hidden, :with_confirmed_hide, title: "Confirmed debate")
visit admin_debates_path(filter: 'all')
expect(page).to have_content('Unconfirmed debate')
expect(page).to have_content('Confirmed debate')
visit admin_debates_path(filter: 'with_confirmed_hide')
expect(page).to_not have_content('Unconfirmed debate')
expect(page).to have_content('Confirmed debate')
end
scenario "Action links remember the pagination setting and the filter" do
per_page = Kaminari.config.default_per_page
(per_page + 2).times { create(:debate, :hidden, :with_confirmed_hide) }
visit admin_debates_path(filter: 'with_confirmed_hide', page: 2)
click_on('Restore', match: :first, exact: true)
expect(current_url).to include('filter=with_confirmed_hide')
expect(current_url).to include('page=2')
end
end

View File

@@ -119,11 +119,8 @@ feature 'Admin::Organizations' do
click_on('Verify', match: :first)
uri = URI.parse(current_url)
query_params = Rack::Utils.parse_nested_query(uri.query).symbolize_keys
expect(query_params[:filter]).to eq('pending')
expect(query_params[:page]).to eq('2')
expect(current_url).to include('filter=pending')
expect(current_url).to include('page=2')
end
end

View File

@@ -2,60 +2,20 @@ require 'rails_helper'
feature 'Admin users' do
scenario 'Restore hidden user' do
citizen = create(:user)
background do
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)
user = create(:user, :hidden)
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')
debate1 = create(:debate, :hidden, author: user)
debate2 = create(:debate, author: user)
comment1 = create(:comment, :hidden, user: user, commentable: debate2, body: "You have the manners of a beggar")
comment2 = create(:comment, user: user, 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
visit admin_user_path(user)
expect(page).to have_content(debate1.title)
expect(page).to have_content(debate2.title)
@@ -63,4 +23,66 @@ feature 'Admin users' do
expect(page).to have_content(comment2.body)
end
end
scenario 'Restore' do
user = create(:user, :hidden)
visit admin_users_path
click_link 'Restore'
expect(page).to_not have_content(user.username)
expect(user.reload).to_not be_hidden
end
scenario 'Confirm hide' do
user = create(:user, :hidden)
visit admin_users_path
click_link 'Confirm'
expect(page).to have_content(user.username)
expect(page).to have_content('Confirmed')
expect(user.reload).to be_confirmed_hide
end
scenario "Current filter is properly highlighted" do
visit admin_users_path
expect(page).to_not have_link('All')
expect(page).to have_link('Confirmed')
visit admin_users_path(filter: 'all')
expect(page).to_not have_link('All')
expect(page).to have_link('Confirmed')
visit admin_users_path(filter: 'with_confirmed_hide')
expect(page).to have_link('All')
expect(page).to_not have_link('Confirmed')
end
scenario "Filtering users" do
create(:user, :hidden, username: "Unconfirmed")
create(:user, :hidden, :with_confirmed_hide, username: "Confirmed user")
visit admin_users_path(filter: 'all')
expect(page).to have_content('Unconfirmed')
expect(page).to have_content('Confirmed user')
visit admin_users_path(filter: 'with_confirmed_hide')
expect(page).to_not have_content('Unconfirmed')
expect(page).to have_content('Confirmed user')
end
scenario "Action links remember the pagination setting and the filter" do
per_page = Kaminari.config.default_per_page
(per_page + 2).times { create(:user, :hidden, :with_confirmed_hide) }
visit admin_users_path(filter: 'with_confirmed_hide', page: 2)
click_on('Restore', match: :first, exact: true)
expect(current_url).to include('filter=with_confirmed_hide')
expect(current_url).to include('page=2')
end
end

View File

@@ -148,14 +148,14 @@ feature 'Comments' do
expect(page).to have_css("#unflag-expand-comment-#{comment.id}")
end
expect(InappropiateFlag.flagged?(user, comment)).to be
expect(Flag.flagged?(user, comment)).to be
end
scenario "Undoing flagging as inappropriate", :js do
user = create(:user)
debate = create(:debate)
comment = create(:comment, commentable: debate)
InappropiateFlag.flag!(user, comment)
Flag.flag!(user, comment)
login_as(user)
visit debate_path(debate)
@@ -167,7 +167,7 @@ feature 'Comments' do
expect(page).to have_css("#flag-expand-comment-#{comment.id}")
end
expect(InappropiateFlag.flagged?(user, comment)).to_not be
expect(Flag.flagged?(user, comment)).to_not be
end
feature "Moderators" do

View File

@@ -315,7 +315,7 @@ feature 'Debates' do
end
end
scenario "Flagging as inappropiate", :js do
scenario "Flagging", :js do
user = create(:user)
debate = create(:debate)
@@ -329,13 +329,13 @@ feature 'Debates' do
expect(page).to have_css("#unflag-expand-debate-#{debate.id}")
end
expect(InappropiateFlag.flagged?(user, debate)).to be
expect(Flag.flagged?(user, debate)).to be
end
scenario "Undoing flagging as inappropiate", :js do
scenario "Unflagging", :js do
user = create(:user)
debate = create(:debate)
InappropiateFlag.flag!(user, debate)
Flag.flag!(user, debate)
login_as(user)
visit debate_path(debate)
@@ -347,7 +347,7 @@ feature 'Debates' do
expect(page).to have_css("#flag-expand-debate-#{debate.id}")
end
expect(InappropiateFlag.flagged?(user, debate)).to_not be
expect(Flag.flagged?(user, debate)).to_not be
end
feature 'Debate index order filters', :js do

View File

@@ -104,65 +104,62 @@ feature 'Moderate Comments' do
visit moderation_comments_path
expect(page).to_not have_link('All')
expect(page).to have_link('Pending')
expect(page).to have_link('Archived')
expect(page).to have_link('Ignored')
visit moderation_comments_path(filter: 'all')
expect(page).to_not have_link('All')
expect(page).to have_link('Pending')
expect(page).to have_link('Archived')
expect(page).to have_link('Ignored')
visit moderation_comments_path(filter: 'pending')
visit moderation_comments_path(filter: 'pending_flag_review')
expect(page).to have_link('All')
expect(page).to_not have_link('Pending')
expect(page).to have_link('Archived')
expect(page).to have_link('Ignored')
visit moderation_comments_path(filter: 'archived')
visit moderation_comments_path(filter: 'with_ignored_flag')
expect(page).to have_link('All')
expect(page).to have_link('Pending')
expect(page).to_not have_link('Archived')
expect(page).to_not have_link('Ignored')
end
scenario "Filtering comments" do
create(:comment, :flagged_as_inappropiate, body: "Pending comment")
create(:comment, :flagged_as_inappropiate, :hidden, body: "Hidden comment")
create(:comment, :flagged_as_inappropiate, :archived, body: "Archived comment")
create(:comment, :flagged, body: "Pending comment")
create(:comment, :flagged, :hidden, body: "Hidden comment")
create(:comment, :flagged, :with_ignored_flag, body: "Ignored comment")
visit moderation_comments_path(filter: 'all')
expect(page).to have_content('Pending comment')
expect(page).to_not have_content('Hidden comment')
expect(page).to have_content('Archived comment')
expect(page).to have_content('Ignored comment')
visit moderation_comments_path(filter: 'pending')
visit moderation_comments_path(filter: 'pending_flag_review')
expect(page).to have_content('Pending comment')
expect(page).to_not have_content('Hidden comment')
expect(page).to_not have_content('Archived comment')
expect(page).to_not have_content('Ignored comment')
visit moderation_comments_path(filter: 'archived')
visit moderation_comments_path(filter: 'with_ignored_flag')
expect(page).to_not have_content('Pending comment')
expect(page).to_not have_content('Hidden comment')
expect(page).to have_content('Archived comment')
expect(page).to have_content('Ignored comment')
end
scenario "Reviewing links remember the pagination setting and the filter" do
per_page = Kaminari.config.default_per_page
(per_page + 2).times { create(:comment, :flagged_as_inappropiate) }
(per_page + 2).times { create(:comment, :flagged) }
visit moderation_comments_path(filter: 'pending', page: 2)
visit moderation_comments_path(filter: 'pending_flag_review', page: 2)
click_link('Archive', match: :first, exact: true)
click_link('Ignore', match: :first, exact: true)
uri = URI.parse(current_url)
query_params = Rack::Utils.parse_nested_query(uri.query).symbolize_keys
expect(query_params[:filter]).to eq('pending')
expect(query_params[:page]).to eq('2')
expect(current_url).to include('filter=pending_flag_review')
expect(current_url).to include('page=2')
end
feature 'A flagged comment exists' do
background do
debate = create(:debate, title: 'Democracy')
@comment = create(:comment, :flagged_as_inappropiate, commentable: debate, body: 'spammy spam')
@comment = create(:comment, :flagged, commentable: debate, body: 'spammy spam')
visit moderation_comments_path
end
@@ -172,7 +169,7 @@ feature 'Moderate Comments' do
expect(page).to have_content('spammy spam')
expect(page).to have_content('1')
expect(page).to have_link('Hide')
expect(page).to have_link('Archive')
expect(page).to have_link('Ignore')
end
end
@@ -187,18 +184,18 @@ feature 'Moderate Comments' do
expect(@comment.reload).to be_hidden
end
scenario 'Marking the comment as archived' do
scenario 'Marking the comment as ignored' do
within("#comment_#{@comment.id}") do
click_link('Archive')
click_link('Ignore')
end
expect(current_path).to eq(moderation_comments_path)
within("#comment_#{@comment.id}") do
expect(page).to have_content('Archived')
expect(page).to have_content('Ignored')
end
expect(@comment.reload).to be_archived
expect(@comment.reload).to be_ignored_flag
end
end
end

View File

@@ -47,64 +47,61 @@ feature 'Moderate debates' do
visit moderation_debates_path
expect(page).to_not have_link('All')
expect(page).to have_link('Pending')
expect(page).to have_link('Archived')
expect(page).to have_link('Ignored')
visit moderation_debates_path(filter: 'all')
expect(page).to_not have_link('All')
expect(page).to have_link('Pending')
expect(page).to have_link('Archived')
expect(page).to have_link('Ignored')
visit moderation_debates_path(filter: 'pending')
visit moderation_debates_path(filter: 'pending_flag_review')
expect(page).to have_link('All')
expect(page).to_not have_link('Pending')
expect(page).to have_link('Archived')
expect(page).to have_link('Ignored')
visit moderation_debates_path(filter: 'archived')
visit moderation_debates_path(filter: 'with_ignored_flag')
expect(page).to have_link('All')
expect(page).to have_link('Pending')
expect(page).to_not have_link('Archived')
expect(page).to_not have_link('Ignored')
end
scenario "Filtering debates" do
create(:debate, :flagged_as_inappropiate, title: "Pending debate")
create(:debate, :flagged_as_inappropiate, :hidden, title: "Hidden debate")
create(:debate, :flagged_as_inappropiate, :archived, title: "Archived debate")
create(:debate, :flagged, title: "Pending debate")
create(:debate, :flagged, :hidden, title: "Hidden debate")
create(:debate, :flagged, :with_ignored_flag, title: "Ignored debate")
visit moderation_debates_path(filter: 'all')
expect(page).to have_content('Pending debate')
expect(page).to_not have_content('Hidden debate')
expect(page).to have_content('Archived debate')
expect(page).to have_content('Ignored debate')
visit moderation_debates_path(filter: 'pending')
visit moderation_debates_path(filter: 'pending_flag_review')
expect(page).to have_content('Pending debate')
expect(page).to_not have_content('Hidden debate')
expect(page).to_not have_content('Archived debate')
expect(page).to_not have_content('Ignored debate')
visit moderation_debates_path(filter: 'archived')
visit moderation_debates_path(filter: 'with_ignored_flag')
expect(page).to_not have_content('Pending debate')
expect(page).to_not have_content('Hidden debate')
expect(page).to have_content('Archived debate')
expect(page).to have_content('Ignored debate')
end
scenario "Reviewing links remember the pagination setting and the filter" do
per_page = Kaminari.config.default_per_page
(per_page + 2).times { create(:debate, :flagged_as_inappropiate) }
(per_page + 2).times { create(:debate, :flagged) }
visit moderation_debates_path(filter: 'pending', page: 2)
visit moderation_debates_path(filter: 'pending_flag_review', page: 2)
click_link('Archive', match: :first, exact: true)
click_link('Ignore', match: :first, exact: true)
uri = URI.parse(current_url)
query_params = Rack::Utils.parse_nested_query(uri.query).symbolize_keys
expect(query_params[:filter]).to eq('pending')
expect(query_params[:page]).to eq('2')
expect(current_url).to include('filter=pending_flag_review')
expect(current_url).to include('page=2')
end
feature 'A flagged debate exists' do
background do
@debate = create(:debate, :flagged_as_inappropiate, title: 'spammy spam', description: 'buy buy buy')
@debate = create(:debate, :flagged, title: 'spammy spam', description: 'buy buy buy')
visit moderation_debates_path
end
@@ -114,7 +111,7 @@ feature 'Moderate debates' do
expect(page).to have_content('buy buy buy')
expect(page).to have_content('1')
expect(page).to have_link('Hide')
expect(page).to have_link('Archive')
expect(page).to have_link('Ignore')
end
end
@@ -129,18 +126,18 @@ feature 'Moderate debates' do
expect(@debate.reload).to be_hidden
end
scenario 'Marking the debate as archived' do
scenario 'Marking the debate as ignored' do
within("#debate_#{@debate.id}") do
click_link('Archive')
click_link('Ignore')
end
expect(current_path).to eq(moderation_debates_path)
within("#debate_#{@debate.id}") do
expect(page).to have_content('Archived')
expect(page).to have_content('Ignored')
end
expect(@debate.reload).to be_archived
expect(@debate.reload).to be_ignored_flag
end
end
end

View File

@@ -2,7 +2,7 @@ require 'rails_helper'
describe 'Paranoid methods' do
describe '#hide_all' do
describe '.hide_all' do
it 'hides all instances in the id list' do
debate1 = create(:debate)
debate2 = create(:debate)
@@ -17,7 +17,7 @@ describe 'Paranoid methods' do
end
end
describe '#restore_all' do
describe '.restore_all' do
it 'restores all instances in the id list' do
debate1 = create(:debate)
debate2 = create(:debate)
@@ -34,4 +34,14 @@ describe 'Paranoid methods' do
end
end
describe '#restore' do
it 'resets the confirmed_hide_at attribute' do
debate = create(:debate, :hidden, :with_confirmed_hide)
debate.restore
expect(debate.reload.confirmed_hide?).to_not be
end
end
end

View File

@@ -31,38 +31,38 @@ describe Ability do
it { should_not be_able_to(:comment_as_administrator, debate) }
it { should_not be_able_to(:comment_as_moderator, debate) }
describe 'flagging content as inappropiate' do
it { should be_able_to(:flag_as_inappropiate, debate) }
it { should_not be_able_to(:undo_flag_as_inappropiate, debate) }
it { should be_able_to(:flag_as_inappropiate, comment) }
it { should_not be_able_to(:undo_flag_as_inappropiate, comment) }
describe 'flagging content' do
it { should be_able_to(:flag, debate) }
it { should_not be_able_to(:unflag, debate) }
it { should be_able_to(:flag, comment) }
it { should_not be_able_to(:unflag, comment) }
describe "own comments" do
let(:own_comment) { create(:comment, author: user) }
it { should_not be_able_to(:flag_as_inappropiate, own_comment) }
it { should_not be_able_to(:undo_flag_as_inappropiate, own_comment) }
it { should_not be_able_to(:flag, own_comment) }
it { should_not be_able_to(:unflag, own_comment) }
end
describe "own debates" do
let(:own_debate) { create(:debate, author: user) }
it { should_not be_able_to(:flag_as_inappropiate, own_debate) }
it { should_not be_able_to(:undo_flag_as_inappropiate, own_debate) }
it { should_not be_able_to(:flag, own_debate) }
it { should_not be_able_to(:unflag, own_debate) }
end
describe "already-flagged comments" do
before(:each) { InappropiateFlag.flag!(user, comment) }
before(:each) { Flag.flag!(user, comment) }
it { should_not be_able_to(:flag_as_inappropiate, comment) }
it { should be_able_to(:undo_flag_as_inappropiate, comment) }
it { should_not be_able_to(:flag, comment) }
it { should be_able_to(:unflag, comment) }
end
describe "already-flagged debates" do
before(:each) { InappropiateFlag.flag!(user, debate) }
before(:each) { Flag.flag!(user, debate) }
it { should_not be_able_to(:flag_as_inappropiate, debate) }
it { should be_able_to(:undo_flag_as_inappropiate, debate) }
it { should_not be_able_to(:flag, debate) }
it { should be_able_to(:unflag, debate) }
end
end
@@ -131,8 +131,8 @@ describe Ability do
let(:own_debate) { create(:debate, author: user) }
let(:hidden_comment) { create(:comment, :hidden) }
let(:hidden_debate) { create(:debate, :hidden) }
let(:archived_comment) { create(:comment, :archived) }
let(:archived_debate) { create(:debate, :archived) }
let(:ignored_comment) { create(:comment, :with_ignored_flag) }
let(:ignored_debate) { create(:debate, :with_ignored_flag) }
it { should be_able_to(:hide, comment) }
it { should be_able_to(:hide_in_moderation_screen, comment) }
@@ -144,15 +144,15 @@ describe Ability do
it { should_not be_able_to(:hide, hidden_debate) }
it { should_not be_able_to(:hide, own_debate) }
it { should be_able_to(:archive, comment) }
it { should_not be_able_to(:archive, hidden_comment) }
it { should_not be_able_to(:archive, archived_comment) }
it { should_not be_able_to(:archive, own_comment) }
it { should be_able_to(:ignore_flag, comment) }
it { should_not be_able_to(:ignore_flag, hidden_comment) }
it { should_not be_able_to(:ignore_flag, ignored_comment) }
it { should_not be_able_to(:ignore_flag, own_comment) }
it { should be_able_to(:archive, debate) }
it { should_not be_able_to(:archive, hidden_debate) }
it { should_not be_able_to(:archive, archived_debate) }
it { should_not be_able_to(:archive, own_debate) }
it { should be_able_to(:ignore_flag, debate) }
it { should_not be_able_to(:ignore_flag, hidden_debate) }
it { should_not be_able_to(:ignore_flag, ignored_debate) }
it { should_not be_able_to(:ignore_flag, own_debate) }
it { should_not be_able_to(:hide, user) }
it { should be_able_to(:hide, other_user) }
@@ -169,15 +169,34 @@ describe Ability do
describe "Administrator" do
let(:user) { create(:user) }
before { create(:administrator, user: user) }
let(:other_user) { create(:user) }
let(:other_user) { create(:user) }
let(:hidden_user) { create(:user, :hidden) }
let(:hidden_debate) { create(:debate, :hidden) }
let(:hidden_comment) { create(:comment, :hidden) }
let(:own_debate) { create(:debate, author: user)}
let(:own_comment) { create(:comment, author: user)}
it { should be_able_to(:index, Debate) }
it { should be_able_to(:show, debate) }
it { should be_able_to(:vote, debate) }
it { should be_able_to(:restore, comment) }
it { should be_able_to(:restore, debate) }
it { should be_able_to(:restore, 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) }
it { should be_able_to(:restore, hidden_comment) }
it { should be_able_to(:restore, hidden_debate) }
it { should be_able_to(:restore, hidden_user) }
it { should_not be_able_to(:confirm_hide, comment) }
it { should_not be_able_to(:confirm_hide, debate) }
it { should_not be_able_to(:confirm_hide, other_user) }
it { should be_able_to(:confirm_hide, hidden_comment) }
it { should be_able_to(:confirm_hide, hidden_debate) }
it { should be_able_to(:confirm_hide, hidden_user) }
it { should be_able_to(:comment_as_administrator, debate) }
it { should_not be_able_to(:comment_as_moderator, debate) }

View File

@@ -1,6 +1,6 @@
require 'rails_helper'
describe InappropiateFlag do
describe Flag do
let(:user) { create(:user) }
let(:comment) { create(:comment) }
@@ -8,43 +8,35 @@ describe InappropiateFlag do
describe '.flag!' do
it 'creates a flag when there is none' do
expect { described_class.flag!(user, comment) }.to change{ InappropiateFlag.count }.by(1)
expect(InappropiateFlag.last.user).to eq(user)
expect(InappropiateFlag.last.flaggable).to eq(comment)
expect { described_class.flag!(user, comment) }.to change{ Flag.count }.by(1)
expect(Flag.last.user).to eq(user)
expect(Flag.last.flaggable).to eq(comment)
end
it 'raises an error if the flag has already been created' do
described_class.flag!(user, comment)
expect { described_class.flag!(user, comment) }.to raise_error(InappropiateFlag::AlreadyFlaggedError)
expect { described_class.flag!(user, comment) }.to raise_error(Flag::AlreadyFlaggedError)
end
it 'increases the flag count' do
expect { described_class.flag!(user, comment) }.to change{ comment.reload.inappropiate_flags_count }.by(1)
end
it 'updates the flagged_as date' do
expect { described_class.flag!(user, comment) }.to change{ comment.reload.flagged_as_inappropiate_at }
expect { described_class.flag!(user, comment) }.to change{ comment.reload.flags_count }.by(1)
end
end
describe '.unflag!' do
it 'raises an error if the flag does not exist' do
expect { described_class.unflag!(user, comment) }.to raise_error(InappropiateFlag::NotFlaggedError)
expect { described_class.unflag!(user, comment) }.to raise_error(Flag::NotFlaggedError)
end
describe 'when the flag already exists' do
before(:each) { described_class.flag!(user, comment) }
it 'removes an existing flag' do
expect { described_class.unflag!(user, comment) }.to change{ InappropiateFlag.count }.by(-1)
expect { described_class.unflag!(user, comment) }.to change{ Flag.count }.by(-1)
end
it 'decreases the flag count' do
expect { described_class.unflag!(user, comment) }.to change{ comment.reload.inappropiate_flags_count }.by(-1)
end
it 'does not update the flagged_as date' do
expect { described_class.unflag!(user, comment) }.to_not change{ comment.flagged_as_inappropiate_at }
expect { described_class.unflag!(user, comment) }.to change{ comment.reload.flags_count }.by(-1)
end
end