Merge pull request #229 from AyuntamientoMadrid/flag-as-inappropiate-171
Flag as inappropiate
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
class Admin::OrganizationsController < Admin::BaseController
|
class Admin::OrganizationsController < Admin::BaseController
|
||||||
before_filter :set_valid_filters
|
before_filter :set_valid_filters, only: :index
|
||||||
before_filter :parse_filter
|
before_filter :parse_filter, only: :index
|
||||||
|
|
||||||
load_and_authorize_resource
|
load_and_authorize_resource
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,16 @@ class CommentsController < ApplicationController
|
|||||||
respond_with @comment
|
respond_with @comment
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def flag_as_inappropiate
|
||||||
|
InappropiateFlag.flag!(current_user, @comment)
|
||||||
|
respond_with @comment, template: 'comments/_refresh_flag_as_inappropiate_actions'
|
||||||
|
end
|
||||||
|
|
||||||
|
def undo_flag_as_inappropiate
|
||||||
|
InappropiateFlag.unflag!(current_user, @comment)
|
||||||
|
respond_with @comment, template: 'comments/_refresh_flag_as_inappropiate_actions'
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def comment_params
|
def comment_params
|
||||||
|
|||||||
@@ -5,13 +5,13 @@ class DebatesController < ApplicationController
|
|||||||
respond_to :html, :js
|
respond_to :html, :js
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@debates = Debate.includes(:tags).search(params).page(params[:page])
|
@debates = Debate.includes(:tags).includes(:inappropiate_flags).search(params).page(params[:page])
|
||||||
set_debate_votes(@debates)
|
set_debate_votes(@debates)
|
||||||
end
|
end
|
||||||
|
|
||||||
def show
|
def show
|
||||||
set_debate_votes(@debate)
|
set_debate_votes(@debate)
|
||||||
@comments = @debate.root_comments.with_hidden.recent.page(params[:page])
|
@comments = @debate.root_comments.with_hidden.includes(:inappropiate_flags).recent.page(params[:page])
|
||||||
end
|
end
|
||||||
|
|
||||||
def new
|
def new
|
||||||
@@ -51,6 +51,16 @@ class DebatesController < ApplicationController
|
|||||||
set_debate_votes(@debate)
|
set_debate_votes(@debate)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def flag_as_inappropiate
|
||||||
|
InappropiateFlag.flag!(current_user, @debate)
|
||||||
|
respond_with @debate, template: 'debates/_refresh_flag_as_inappropiate_actions'
|
||||||
|
end
|
||||||
|
|
||||||
|
def undo_flag_as_inappropiate
|
||||||
|
InappropiateFlag.unflag!(current_user, @debate)
|
||||||
|
respond_with @debate, template: 'debates/_refresh_flag_as_inappropiate_actions'
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def debate_params
|
def debate_params
|
||||||
|
|||||||
@@ -1,8 +1,42 @@
|
|||||||
class Moderation::CommentsController < Moderation::BaseController
|
class Moderation::CommentsController < Moderation::BaseController
|
||||||
|
before_filter :set_valid_filters, only: :index
|
||||||
|
before_filter :parse_filter, only: :index
|
||||||
|
before_filter :load_comments, only: :index
|
||||||
|
|
||||||
|
load_and_authorize_resource
|
||||||
|
|
||||||
|
def index
|
||||||
|
@comments = @comments.send(@filter)
|
||||||
|
@comments = @comments.page(params[:page])
|
||||||
|
end
|
||||||
|
|
||||||
def hide
|
def hide
|
||||||
@comment = Comment.find(params[:id])
|
|
||||||
@comment.hide
|
@comment.hide
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def hide_in_moderation_screen
|
||||||
|
@comment.hide
|
||||||
|
redirect_to request.query_parameters.merge(action: :index)
|
||||||
|
end
|
||||||
|
|
||||||
|
def mark_as_reviewed
|
||||||
|
@comment.mark_as_reviewed
|
||||||
|
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)
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_valid_filters
|
||||||
|
@valid_filters = %w{all pending_review reviewed}
|
||||||
|
end
|
||||||
|
|
||||||
|
def parse_filter
|
||||||
|
@filter = params[:filter]
|
||||||
|
@filter = 'all' unless @valid_filters.include?(@filter)
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -1,8 +1,42 @@
|
|||||||
class Moderation::DebatesController < Moderation::BaseController
|
class Moderation::DebatesController < Moderation::BaseController
|
||||||
|
before_filter :set_valid_filters, only: :index
|
||||||
|
before_filter :parse_filter, only: :index
|
||||||
|
before_filter :load_debates, only: :index
|
||||||
|
|
||||||
|
load_and_authorize_resource
|
||||||
|
|
||||||
|
def index
|
||||||
|
@debates = @debates.send(@filter)
|
||||||
|
@debates = @debates.page(params[:page])
|
||||||
|
end
|
||||||
|
|
||||||
def hide
|
def hide
|
||||||
@debate = Debate.find(params[:id])
|
|
||||||
@debate.hide
|
@debate.hide
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def hide_in_moderation_screen
|
||||||
|
@debate.hide
|
||||||
|
redirect_to request.query_parameters.merge(action: :index)
|
||||||
|
end
|
||||||
|
|
||||||
|
def mark_as_reviewed
|
||||||
|
@debate.mark_as_reviewed
|
||||||
|
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
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_valid_filters
|
||||||
|
@valid_filters = %w{all pending_review reviewed}
|
||||||
|
end
|
||||||
|
|
||||||
|
def parse_filter
|
||||||
|
@filter = params[:filter]
|
||||||
|
@filter = 'all' unless @valid_filters.include?(@filter)
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -2,9 +2,15 @@ class Ability
|
|||||||
include CanCan::Ability
|
include CanCan::Ability
|
||||||
|
|
||||||
def initialize(user)
|
def initialize(user)
|
||||||
|
|
||||||
|
# If someone can hide something, he can also hide it
|
||||||
|
# from the moderation screen
|
||||||
|
alias_action :hide_in_moderation_screen, to: :hide
|
||||||
|
|
||||||
# Not logged in users
|
# Not logged in users
|
||||||
can :read, Debate
|
can :read, Debate
|
||||||
|
|
||||||
|
|
||||||
if user # logged-in users
|
if user # logged-in users
|
||||||
can [:read, :update], User, id: user.id
|
can [:read, :update], User, id: user.id
|
||||||
|
|
||||||
@@ -16,6 +22,22 @@ class Ability
|
|||||||
can :create, Comment
|
can :create, Comment
|
||||||
can :create, Debate
|
can :create, Debate
|
||||||
|
|
||||||
|
can :flag_as_inappropiate, Comment do |comment|
|
||||||
|
comment.author_id != user.id && !InappropiateFlag.flagged?(user, comment)
|
||||||
|
end
|
||||||
|
|
||||||
|
can :undo_flag_as_inappropiate, Comment do |comment|
|
||||||
|
comment.author_id != user.id && InappropiateFlag.flagged?(user, comment)
|
||||||
|
end
|
||||||
|
|
||||||
|
can :flag_as_inappropiate, Debate do |debate|
|
||||||
|
debate.author_id != user.id && !InappropiateFlag.flagged?(user, debate)
|
||||||
|
end
|
||||||
|
|
||||||
|
can :undo_flag_as_inappropiate, Debate do |debate|
|
||||||
|
debate.author_id != user.id && InappropiateFlag.flagged?(user, debate)
|
||||||
|
end
|
||||||
|
|
||||||
unless user.organization?
|
unless user.organization?
|
||||||
can :vote, Debate
|
can :vote, Debate
|
||||||
can :vote, Comment
|
can :vote, Comment
|
||||||
@@ -26,9 +48,22 @@ class Ability
|
|||||||
can(:verify, Organization){ |o| !o.verified? }
|
can(:verify, Organization){ |o| !o.verified? }
|
||||||
can(:reject, Organization){ |o| !o.rejected? }
|
can(:reject, Organization){ |o| !o.rejected? }
|
||||||
|
|
||||||
can :hide, Comment
|
can :read, Comment
|
||||||
can :hide, Debate
|
|
||||||
|
can :hide, Comment, hidden_at: nil
|
||||||
|
cannot :hide, Comment, user_id: user.id
|
||||||
|
|
||||||
|
can :mark_as_reviewed, Comment, reviewed_at: nil, hidden_at: nil
|
||||||
|
cannot :mark_as_reviewed, Comment, user_id: user.id
|
||||||
|
|
||||||
|
can :hide, Debate, hidden_at: nil
|
||||||
|
cannot :hide, Debate, author_id: user.id
|
||||||
|
|
||||||
|
can :mark_as_reviewed, Debate, reviewed_at: nil, hidden_at: nil
|
||||||
|
cannot :mark_as_reviewed, Debate, author_id: user.id
|
||||||
|
|
||||||
can :hide, User
|
can :hide, User
|
||||||
|
cannot :hide, User, id: user.id
|
||||||
end
|
end
|
||||||
|
|
||||||
if user.administrator?
|
if user.administrator?
|
||||||
|
|||||||
@@ -11,9 +11,16 @@ class Comment < ActiveRecord::Base
|
|||||||
belongs_to :commentable, polymorphic: true
|
belongs_to :commentable, polymorphic: true
|
||||||
belongs_to :user, -> { with_hidden }
|
belongs_to :user, -> { with_hidden }
|
||||||
|
|
||||||
|
has_many :inappropiate_flags, :as => :flaggable
|
||||||
|
|
||||||
default_scope { includes(:user) }
|
default_scope { includes(:user) }
|
||||||
scope :recent, -> { order(id: :desc) }
|
scope :recent, -> { order(id: :desc) }
|
||||||
|
|
||||||
|
scope :sorted_for_moderation, -> { order(inappropiate_flags_count: :desc, updated_at: :desc) }
|
||||||
|
scope :pending_review, -> { where(reviewed_at: nil, hidden_at: nil) }
|
||||||
|
scope :reviewed, -> { where("reviewed_at IS NOT NULL AND hidden_at IS NULL") }
|
||||||
|
scope :flagged_as_inappropiate, -> { where("inappropiate_flags_count > 0") }
|
||||||
|
|
||||||
def self.build(commentable, user, body)
|
def self.build(commentable, user, body)
|
||||||
new commentable: commentable,
|
new commentable: commentable,
|
||||||
user_id: user.id,
|
user_id: user.id,
|
||||||
@@ -28,10 +35,18 @@ class Comment < ActiveRecord::Base
|
|||||||
commentable if commentable.class == Debate
|
commentable if commentable.class == Debate
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def author_id
|
||||||
|
user_id
|
||||||
|
end
|
||||||
|
|
||||||
def author
|
def author
|
||||||
user
|
user
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def author=(author)
|
||||||
|
self.user= author
|
||||||
|
end
|
||||||
|
|
||||||
def total_votes
|
def total_votes
|
||||||
votes_for.size
|
votes_for.size
|
||||||
end
|
end
|
||||||
@@ -40,6 +55,14 @@ class Comment < ActiveRecord::Base
|
|||||||
hidden? || user.hidden?
|
hidden? || user.hidden?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def reviewed?
|
||||||
|
reviewed_at.present?
|
||||||
|
end
|
||||||
|
|
||||||
|
def mark_as_reviewed
|
||||||
|
update(reviewed_at: Time.now)
|
||||||
|
end
|
||||||
|
|
||||||
# TODO: faking counter cache since there is a bug with acts_as_nested_set :counter_cache
|
# 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
|
# Remove when https://github.com/collectiveidea/awesome_nested_set/issues/294 is fixed
|
||||||
# and reset counters using
|
# and reset counters using
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ class Debate < ActiveRecord::Base
|
|||||||
acts_as_paranoid column: :hidden_at
|
acts_as_paranoid column: :hidden_at
|
||||||
|
|
||||||
belongs_to :author, -> { with_hidden }, class_name: 'User', foreign_key: 'author_id'
|
belongs_to :author, -> { with_hidden }, class_name: 'User', foreign_key: 'author_id'
|
||||||
|
has_many :inappropiate_flags, :as => :flaggable
|
||||||
|
|
||||||
validates :title, presence: true
|
validates :title, presence: true
|
||||||
validates :description, presence: true
|
validates :description, presence: true
|
||||||
@@ -22,6 +23,11 @@ class Debate < ActiveRecord::Base
|
|||||||
before_validation :sanitize_description
|
before_validation :sanitize_description
|
||||||
before_validation :sanitize_tag_list
|
before_validation :sanitize_tag_list
|
||||||
|
|
||||||
|
scope :sorted_for_moderation, -> { order(inappropiate_flags_count: :desc, updated_at: :desc) }
|
||||||
|
scope :pending_review, -> { where(reviewed_at: nil, hidden_at: nil) }
|
||||||
|
scope :reviewed, -> { where("reviewed_at IS NOT NULL AND hidden_at IS NULL") }
|
||||||
|
scope :flagged_as_inappropiate, -> { where("inappropiate_flags_count > 0") }
|
||||||
|
|
||||||
# Ahoy setup
|
# Ahoy setup
|
||||||
visitable # Ahoy will automatically assign visit_id on create
|
visitable # Ahoy will automatically assign visit_id on create
|
||||||
|
|
||||||
@@ -68,6 +74,14 @@ class Debate < ActiveRecord::Base
|
|||||||
count < 0 ? 0 : count
|
count < 0 ? 0 : count
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def reviewed?
|
||||||
|
reviewed_at.present?
|
||||||
|
end
|
||||||
|
|
||||||
|
def mark_as_reviewed
|
||||||
|
update(reviewed_at: Time.now)
|
||||||
|
end
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
def sanitize_description
|
def sanitize_description
|
||||||
|
|||||||
41
app/models/inappropiate_flag.rb
Normal file
41
app/models/inappropiate_flag.rb
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
class InappropiateFlag < ActiveRecord::Base
|
||||||
|
|
||||||
|
belongs_to :user
|
||||||
|
belongs_to :flaggable, polymorphic: true, counter_cache: true, touch: :flagged_as_inappropiate_at
|
||||||
|
|
||||||
|
scope(:by_user_and_flaggable, lambda do |user, flaggable|
|
||||||
|
where(user_id: user.id,
|
||||||
|
flaggable_type: flaggable.class.to_s,
|
||||||
|
flaggable_id: flaggable.id)
|
||||||
|
end)
|
||||||
|
|
||||||
|
|
||||||
|
class AlreadyFlaggedError < StandardError
|
||||||
|
def initialize
|
||||||
|
super "The flaggable was already flagged as inappropiate by this user"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class NotFlaggedError < StandardError
|
||||||
|
def initialize
|
||||||
|
super "The flaggable was not flagged as inappropiate by this user"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
def self.flag!(user, flaggable)
|
||||||
|
raise AlreadyFlaggedError if flagged?(user, flaggable)
|
||||||
|
create(user: user, flaggable: flaggable)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.unflag!(user, flaggable)
|
||||||
|
flags = by_user_and_flaggable(user, flaggable)
|
||||||
|
raise NotFlaggedError if flags.empty?
|
||||||
|
flags.destroy_all
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.flagged?(user, flaggable)
|
||||||
|
!! by_user_and_flaggable(user, flaggable).try(:first)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -10,6 +10,7 @@ class User < ActiveRecord::Base
|
|||||||
has_one :administrator
|
has_one :administrator
|
||||||
has_one :moderator
|
has_one :moderator
|
||||||
has_one :organization
|
has_one :organization
|
||||||
|
has_many :inappropiate_flags
|
||||||
|
|
||||||
validates :username, presence: true, unless: :organization?
|
validates :username, presence: true, unless: :organization?
|
||||||
validates :official_level, inclusion: {in: 0..5}
|
validates :official_level, inclusion: {in: 0..5}
|
||||||
|
|||||||
@@ -41,6 +41,11 @@
|
|||||||
</span>
|
</span>
|
||||||
<% end %>
|
<% end %>
|
||||||
• <%= time_ago_in_words(comment.created_at) %>
|
• <%= time_ago_in_words(comment.created_at) %>
|
||||||
|
|
||||||
|
<span class="right js-flag-as-inappropiate-actions">
|
||||||
|
<%= render 'comments/flag_as_inappropiate_actions', comment: comment %>
|
||||||
|
</span>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<% if comment.user.official? && comment.user_id == @debate.author_id %>
|
<% if comment.user.official? && comment.user_id == @debate.author_id %>
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<% if can? :flag_as_inappropiate, comment %>
|
||||||
|
<%= link_to t('shared.flag_as_inappropiate'), flag_as_inappropiate_comment_path(comment), method: :put, remote: true %>
|
||||||
|
<% end %>
|
||||||
|
<% if can? :undo_flag_as_inappropiate, comment %>
|
||||||
|
<%= link_to t('shared.undo_flag_as_inappropiate'), undo_flag_as_inappropiate_comment_path(comment), method: :put, remote: true %>
|
||||||
|
<% end %>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
$("#<%= dom_id(@comment) %> .js-flag-as-inappropiate-actions").html('<%= j render("comments/flag_as_inappropiate_actions", comment: @comment) %>');
|
||||||
6
app/views/debates/_flag_as_inappropiate_actions.html.erb
Normal file
6
app/views/debates/_flag_as_inappropiate_actions.html.erb
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<% if can? :flag_as_inappropiate, debate %>
|
||||||
|
<%= link_to t('shared.flag_as_inappropiate'), flag_as_inappropiate_debate_path(debate), method: :put, remote: true %>
|
||||||
|
<% end %>
|
||||||
|
<% if can? :undo_flag_as_inappropiate, debate %>
|
||||||
|
<%= link_to t('shared.undo_flag_as_inappropiate'), undo_flag_as_inappropiate_debate_path(debate), method: :put, remote: true %>
|
||||||
|
<% end %>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
$("#<%= dom_id(@debate) %> .js-flag-as-inappropiate-actions").html('<%= j render("debates/flag_as_inappropiate_actions", debate: @debate) %>');
|
||||||
@@ -41,6 +41,10 @@
|
|||||||
<span class="bullet"> • </span>
|
<span class="bullet"> • </span>
|
||||||
<i class="icon-comments"></i>
|
<i class="icon-comments"></i>
|
||||||
<%= link_to t("debates.show.comments", count: @debate.comment_threads.count), "#comments" %>
|
<%= link_to t("debates.show.comments", count: @debate.comment_threads.count), "#comments" %>
|
||||||
|
|
||||||
|
<span class='right js-flag-as-inappropiate-actions'>
|
||||||
|
<%= render 'debates/flag_as_inappropiate_actions', debate: @debate %>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<%= @debate.description %>
|
<%= @debate.description %>
|
||||||
|
|||||||
@@ -1,3 +1,21 @@
|
|||||||
<div id="moderation_menu">
|
<nav class="admin-sidebar">
|
||||||
Moderation links
|
<ul id="moderation_menu">
|
||||||
</div>
|
<li>
|
||||||
|
<%= t("moderation.dashboard.index.title") %>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li <%= 'class=active' if controller_name == 'debates' %>>
|
||||||
|
<%= link_to moderation_debates_path do %>
|
||||||
|
<i class="icon-eye"></i>
|
||||||
|
<%= t('moderation.menu.flagged_debates') %>
|
||||||
|
<% end %>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li <%= 'class=active' if controller_name == 'comments' %>>
|
||||||
|
<%= link_to moderation_comments_path do %>
|
||||||
|
<i class="icon-comment-quotes"></i>
|
||||||
|
<%= t('moderation.menu.flagged_comments') %>
|
||||||
|
<% end %>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
|||||||
50
app/views/moderation/comments/index.html.erb
Normal file
50
app/views/moderation/comments/index.html.erb
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
<h2><%= t('moderation.comments.index.title') %></h2>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<%= t('moderation.comments.index.filter') %>:
|
||||||
|
<% @valid_filters.each do |filter| %>
|
||||||
|
<% if @filter == filter %>
|
||||||
|
<%= t("moderation.comments.index.filters.#{filter}") %>
|
||||||
|
<% else %>
|
||||||
|
<%= link_to t("moderation.comments.index.filters.#{filter}"),
|
||||||
|
moderation_comments_path(filter: filter) %>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h3><%= page_entries_info @comments %></h3>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th><%= t('moderation.comments.index.headers.flags') %></th>
|
||||||
|
<th><%= t('moderation.comments.index.headers.updated_at') %></th>
|
||||||
|
<th><%= t('moderation.comments.index.headers.commentable_type') %></th>
|
||||||
|
<th><%= t('moderation.comments.index.headers.commentable') %></th>
|
||||||
|
<th><%= t('moderation.comments.index.headers.comment') %></th>
|
||||||
|
</tr>
|
||||||
|
<% @comments.each do |comment| %>
|
||||||
|
<tr id="comment_<%= comment.id %>">
|
||||||
|
<td><%= comment.inappropiate_flags_count %></td>
|
||||||
|
<td><%= l comment.updated_at.to_date %></td>
|
||||||
|
<td><%= comment.commentable_type.constantize.model_name.human %></td>
|
||||||
|
<td><%= link_to comment.commentable.title, comment.commentable %></td>
|
||||||
|
<td><%= comment.body %></td>
|
||||||
|
<td>
|
||||||
|
<%= link_to t('moderation.comments.index.hide'), hide_in_moderation_screen_moderation_comment_path(comment, request.query_parameters), method: :put %>
|
||||||
|
</td>
|
||||||
|
<% if can? :mark_as_reviewed, comment %>
|
||||||
|
<td>
|
||||||
|
<%= link_to t('moderation.comments.index.mark_as_reviewed'), mark_as_reviewed_moderation_comment_path(comment, request.query_parameters), method: :put %>
|
||||||
|
</td>
|
||||||
|
<% end %>
|
||||||
|
<% if comment.reviewed? %>
|
||||||
|
<td>
|
||||||
|
<%= t('moderation.comments.index.reviewed') %>
|
||||||
|
</td>
|
||||||
|
<% end %>
|
||||||
|
</tr>
|
||||||
|
<% end %>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<%= paginate @comments %>
|
||||||
|
|
||||||
48
app/views/moderation/debates/index.html.erb
Normal file
48
app/views/moderation/debates/index.html.erb
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
<h2><%= t('moderation.debates.index.title') %></h2>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<%= t('moderation.debates.index.filter') %>:
|
||||||
|
<% @valid_filters.each do |filter| %>
|
||||||
|
<% if @filter == filter %>
|
||||||
|
<%= t("moderation.debates.index.filters.#{filter}") %>
|
||||||
|
<% else %>
|
||||||
|
<%= link_to t("moderation.debates.index.filters.#{filter}"),
|
||||||
|
moderation_debates_path(filter: filter) %>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h3><%= page_entries_info @debates %></h3>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th><%= t('moderation.debates.index.headers.flags') %></th>
|
||||||
|
<th><%= t('moderation.debates.index.headers.updated_at') %></th>
|
||||||
|
<th><%= t('moderation.debates.index.headers.title') %></th>
|
||||||
|
<th><%= t('moderation.debates.index.headers.description') %></th>
|
||||||
|
</tr>
|
||||||
|
<% @debates.each do |debate| %>
|
||||||
|
<tr id="debate_<%= debate.id %>">
|
||||||
|
<td><%= debate.inappropiate_flags_count %></td>
|
||||||
|
<td><%= l debate.updated_at.to_date %></td>
|
||||||
|
<td><%= link_to debate.title, debate %></td>
|
||||||
|
<td><%= debate.description %></td>
|
||||||
|
<td>
|
||||||
|
<%= link_to t('moderation.debates.index.hide'), hide_in_moderation_screen_moderation_debate_path(debate, request.query_parameters), method: :put %>
|
||||||
|
</td>
|
||||||
|
<% if can? :mark_as_reviewed, debate %>
|
||||||
|
<td>
|
||||||
|
<%= link_to t('moderation.debates.index.mark_as_reviewed'), mark_as_reviewed_moderation_debate_path(debate, request.query_parameters), method: :put %>
|
||||||
|
</td>
|
||||||
|
<% end %>
|
||||||
|
<% if debate.reviewed? %>
|
||||||
|
<td>
|
||||||
|
<%= t('moderation.debates.index.reviewed') %>
|
||||||
|
</td>
|
||||||
|
<% end %>
|
||||||
|
</tr>
|
||||||
|
<% end %>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<%= paginate @debates %>
|
||||||
|
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
</li>
|
</li>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<% if current_user.moderator? %>
|
<% if current_user.moderator? || current_user.administrator? %>
|
||||||
<li>
|
<li>
|
||||||
<%= link_to t("layouts.header.moderation"), moderation_root_path %>
|
<%= link_to t("layouts.header.moderation"), moderation_root_path %>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -130,6 +130,8 @@ en:
|
|||||||
shared:
|
shared:
|
||||||
tags_cloud:
|
tags_cloud:
|
||||||
tags: Topics
|
tags: Topics
|
||||||
|
flag_as_inappropiate: Flag as inappropiate
|
||||||
|
undo_flag_as_inappropiate: Undo flag as inappropiate
|
||||||
collective: Collective
|
collective: Collective
|
||||||
mailer:
|
mailer:
|
||||||
comment:
|
comment:
|
||||||
|
|||||||
@@ -130,6 +130,8 @@ es:
|
|||||||
shared:
|
shared:
|
||||||
tags_cloud:
|
tags_cloud:
|
||||||
tags: Temas
|
tags: Temas
|
||||||
|
flag_as_inappropiate: Denunciar como inapropiado
|
||||||
|
undo_flag_as_inappropiate: Deshacer denunciar como inapropiado
|
||||||
collective: Colectivo
|
collective: Colectivo
|
||||||
mailer:
|
mailer:
|
||||||
comment:
|
comment:
|
||||||
|
|||||||
@@ -1,6 +1,42 @@
|
|||||||
en:
|
en:
|
||||||
moderation:
|
moderation:
|
||||||
|
menu:
|
||||||
|
flagged_debates: Debates
|
||||||
|
flagged_comments: Comments
|
||||||
dashboard:
|
dashboard:
|
||||||
index:
|
index:
|
||||||
title: Moderation
|
title: Moderation
|
||||||
|
comments:
|
||||||
|
index:
|
||||||
|
title: Comments flagged as inappropiate
|
||||||
|
headers:
|
||||||
|
flags: Flags
|
||||||
|
updated_at: Date
|
||||||
|
commentable_type: Type
|
||||||
|
commentable: Root
|
||||||
|
comment: Comment
|
||||||
|
hide: Hide
|
||||||
|
mark_as_reviewed: Mark as reviewed
|
||||||
|
reviewed: Reviewed
|
||||||
|
filter: Filter
|
||||||
|
filters:
|
||||||
|
all: All
|
||||||
|
pending_review: Pending
|
||||||
|
reviewed: Reviewed
|
||||||
|
debates:
|
||||||
|
index:
|
||||||
|
title: Debates flagged as inappropiate
|
||||||
|
headers:
|
||||||
|
flags: Flags
|
||||||
|
updated_at: Date
|
||||||
|
title: Title
|
||||||
|
description: Description
|
||||||
|
hide: Hide
|
||||||
|
mark_as_reviewed: Mark as reviewed
|
||||||
|
reviewed: Reviewed
|
||||||
|
filter: Filter
|
||||||
|
filters:
|
||||||
|
all: All
|
||||||
|
pending_review: Pending
|
||||||
|
reviewed: Reviewed
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,43 @@
|
|||||||
es:
|
es:
|
||||||
moderation:
|
moderation:
|
||||||
|
menu:
|
||||||
|
flagged_debates: Debates
|
||||||
|
flagged_comments: Comentarios
|
||||||
dashboard:
|
dashboard:
|
||||||
index:
|
index:
|
||||||
title: Moderación
|
title: Moderación
|
||||||
|
comments:
|
||||||
|
index:
|
||||||
|
title: Comentarios Denunciados como Inapropiados
|
||||||
|
headers:
|
||||||
|
flags: Denuncias
|
||||||
|
updated_at: Fecha
|
||||||
|
commentable_type: Tipo
|
||||||
|
commentable: Raíz
|
||||||
|
comment: Comentario
|
||||||
|
hide: Ocultar
|
||||||
|
mark_as_reviewed: Marcar como revisado
|
||||||
|
reviewed: Revisado
|
||||||
|
filter: Filtrar
|
||||||
|
filters:
|
||||||
|
all: Todos
|
||||||
|
pending_review: Pendientes
|
||||||
|
reviewed: Revisados
|
||||||
|
debates:
|
||||||
|
index:
|
||||||
|
title: Debates Denunciados como Inapropiados
|
||||||
|
headers:
|
||||||
|
flags: Denuncias
|
||||||
|
updated_at: Fecha
|
||||||
|
title: Título
|
||||||
|
description: Descripción
|
||||||
|
hide: Ocultar
|
||||||
|
mark_as_reviewed: Marcar como revisado
|
||||||
|
reviewed: Revisado
|
||||||
|
filter: Filtrar
|
||||||
|
filters:
|
||||||
|
all: Todos
|
||||||
|
pending_review: Pendientes
|
||||||
|
reviewed: Revisados
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -13,10 +13,18 @@ Rails.application.routes.draw do
|
|||||||
root 'welcome#index'
|
root 'welcome#index'
|
||||||
|
|
||||||
resources :debates do
|
resources :debates do
|
||||||
member { post :vote }
|
member do
|
||||||
|
post :vote
|
||||||
|
put :flag_as_inappropiate
|
||||||
|
put :undo_flag_as_inappropiate
|
||||||
|
end
|
||||||
|
|
||||||
resources :comments, only: :create, shallow: true do
|
resources :comments, only: :create, shallow: true do
|
||||||
member { post :vote }
|
member do
|
||||||
|
post :vote
|
||||||
|
put :flag_as_inappropiate
|
||||||
|
put :undo_flag_as_inappropiate
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -63,12 +71,20 @@ Rails.application.routes.draw do
|
|||||||
member { put :hide }
|
member { put :hide }
|
||||||
end
|
end
|
||||||
|
|
||||||
resources :debates, only: [] do
|
resources :debates, only: :index do
|
||||||
member { put :hide }
|
member do
|
||||||
|
put :hide
|
||||||
|
put :hide_in_moderation_screen
|
||||||
|
put :mark_as_reviewed
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
resources :comments, only: [] do
|
resources :comments, only: :index do
|
||||||
member { put :hide }
|
member do
|
||||||
|
put :hide
|
||||||
|
put :hide_in_moderation_screen
|
||||||
|
put :mark_as_reviewed
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
15
db/migrate/20150820103351_create_inappropiate_flags.rb
Normal file
15
db/migrate/20150820103351_create_inappropiate_flags.rb
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
class CreateInappropiateFlags < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
create_table :inappropiate_flags do |t|
|
||||||
|
t.belongs_to :user, index: true, foreign_key: true
|
||||||
|
|
||||||
|
t.string :flaggable_type
|
||||||
|
t.integer :flaggable_id
|
||||||
|
|
||||||
|
t.timestamps
|
||||||
|
end
|
||||||
|
|
||||||
|
add_index :inappropiate_flags, [:flaggable_type, :flaggable_id]
|
||||||
|
add_index :inappropiate_flags, [:user_id, :flaggable_type, :flaggable_id], :name => "access_inappropiate_flags"
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
class AddInappropiateFlagFieldsToComments < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
add_column :comments, :flagged_as_inappropiate_at, :datetime
|
||||||
|
add_column :comments, :inappropiate_flags_count, :integer, default: 0
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
class AddInappropiateFlagFieldsToDebates < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
add_column :debates, :flagged_as_inappropiate_at, :datetime
|
||||||
|
add_column :debates, :inappropiate_flags_count, :integer, default: 0
|
||||||
|
end
|
||||||
|
end
|
||||||
5
db/migrate/20150821180131_add_reviewed_at_to_comments.rb
Normal file
5
db/migrate/20150821180131_add_reviewed_at_to_comments.rb
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
class AddReviewedAtToComments < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
add_column :comments, :reviewed_at, :datetime
|
||||||
|
end
|
||||||
|
end
|
||||||
5
db/migrate/20150821180155_add_reviewed_at_to_debates.rb
Normal file
5
db/migrate/20150821180155_add_reviewed_at_to_debates.rb
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
class AddReviewedAtToDebates < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
add_column :debates, :reviewed_at, :datetime
|
||||||
|
end
|
||||||
|
end
|
||||||
31
db/schema.rb
31
db/schema.rb
@@ -11,7 +11,7 @@
|
|||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(version: 20150821130019) do
|
ActiveRecord::Schema.define(version: 20150821180155) do
|
||||||
|
|
||||||
# These are extensions that must be enabled in order to support this database
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "plpgsql"
|
enable_extension "plpgsql"
|
||||||
@@ -41,14 +41,17 @@ ActiveRecord::Schema.define(version: 20150821130019) do
|
|||||||
t.string "title"
|
t.string "title"
|
||||||
t.text "body"
|
t.text "body"
|
||||||
t.string "subject"
|
t.string "subject"
|
||||||
t.integer "user_id", null: false
|
t.integer "user_id", null: false
|
||||||
t.integer "parent_id"
|
t.integer "parent_id"
|
||||||
t.integer "lft"
|
t.integer "lft"
|
||||||
t.integer "rgt"
|
t.integer "rgt"
|
||||||
t.datetime "created_at"
|
t.datetime "created_at"
|
||||||
t.datetime "updated_at"
|
t.datetime "updated_at"
|
||||||
t.integer "children_count", default: 0
|
t.integer "children_count", default: 0
|
||||||
t.datetime "hidden_at"
|
t.datetime "hidden_at"
|
||||||
|
t.datetime "flagged_as_inappropiate_at"
|
||||||
|
t.integer "inappropiate_flags_count", default: 0
|
||||||
|
t.datetime "reviewed_at"
|
||||||
end
|
end
|
||||||
|
|
||||||
add_index "comments", ["commentable_id", "commentable_type"], name: "index_comments_on_commentable_id_and_commentable_type", using: :btree
|
add_index "comments", ["commentable_id", "commentable_type"], name: "index_comments_on_commentable_id_and_commentable_type", using: :btree
|
||||||
@@ -56,17 +59,32 @@ ActiveRecord::Schema.define(version: 20150821130019) do
|
|||||||
add_index "comments", ["user_id"], name: "index_comments_on_user_id", using: :btree
|
add_index "comments", ["user_id"], name: "index_comments_on_user_id", using: :btree
|
||||||
|
|
||||||
create_table "debates", force: :cascade do |t|
|
create_table "debates", force: :cascade do |t|
|
||||||
t.string "title", limit: 80
|
t.string "title", limit: 80
|
||||||
t.text "description"
|
t.text "description"
|
||||||
t.integer "author_id"
|
t.integer "author_id"
|
||||||
t.datetime "created_at", null: false
|
t.datetime "created_at", null: false
|
||||||
t.datetime "updated_at", null: false
|
t.datetime "updated_at", null: false
|
||||||
t.datetime "hidden_at"
|
t.datetime "hidden_at"
|
||||||
t.string "visit_id"
|
t.string "visit_id"
|
||||||
|
t.datetime "flagged_as_inappropiate_at"
|
||||||
|
t.integer "inappropiate_flags_count", default: 0
|
||||||
|
t.datetime "reviewed_at"
|
||||||
end
|
end
|
||||||
|
|
||||||
add_index "debates", ["hidden_at"], name: "index_debates_on_hidden_at", using: :btree
|
add_index "debates", ["hidden_at"], name: "index_debates_on_hidden_at", 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|
|
create_table "moderators", force: :cascade do |t|
|
||||||
t.integer "user_id"
|
t.integer "user_id"
|
||||||
end
|
end
|
||||||
@@ -194,6 +212,7 @@ ActiveRecord::Schema.define(version: 20150821130019) 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_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 "administrators", "users"
|
||||||
|
add_foreign_key "inappropiate_flags", "users"
|
||||||
add_foreign_key "moderators", "users"
|
add_foreign_key "moderators", "users"
|
||||||
add_foreign_key "organizations", "users"
|
add_foreign_key "organizations", "users"
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -16,6 +16,16 @@ FactoryGirl.define do
|
|||||||
trait :hidden do
|
trait :hidden do
|
||||||
hidden_at Time.now
|
hidden_at Time.now
|
||||||
end
|
end
|
||||||
|
|
||||||
|
trait :reviewed do
|
||||||
|
reviewed_at Time.now
|
||||||
|
end
|
||||||
|
|
||||||
|
trait :flagged_as_inappropiate do
|
||||||
|
after :create do |debate|
|
||||||
|
InappropiateFlag.flag!(FactoryGirl.create(:user), debate)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
factory :vote do
|
factory :vote do
|
||||||
@@ -32,6 +42,16 @@ FactoryGirl.define do
|
|||||||
trait :hidden do
|
trait :hidden do
|
||||||
hidden_at Time.now
|
hidden_at Time.now
|
||||||
end
|
end
|
||||||
|
|
||||||
|
trait :reviewed do
|
||||||
|
reviewed_at Time.now
|
||||||
|
end
|
||||||
|
|
||||||
|
trait :flagged_as_inappropiate do
|
||||||
|
after :create do |debate|
|
||||||
|
InappropiateFlag.flag!(FactoryGirl.create(:user), debate)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
factory :administrator do
|
factory :administrator do
|
||||||
@@ -45,14 +65,14 @@ FactoryGirl.define do
|
|||||||
factory :organization do
|
factory :organization do
|
||||||
user
|
user
|
||||||
sequence(:name) { |n| "org#{n}" }
|
sequence(:name) { |n| "org#{n}" }
|
||||||
end
|
|
||||||
|
|
||||||
factory :verified_organization, parent: :organization do
|
trait :verified do
|
||||||
verified_at { Time.now}
|
verified_at Time.now
|
||||||
end
|
end
|
||||||
|
|
||||||
factory :rejected_organization, parent: :organization do
|
trait :rejected do
|
||||||
rejected_at { Time.now}
|
rejected_at Time.now
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
factory :tag, class: 'ActsAsTaggableOn::Tag' do
|
factory :tag, class: 'ActsAsTaggableOn::Tag' do
|
||||||
@@ -82,4 +102,5 @@ FactoryGirl.define do
|
|||||||
id { SecureRandom.uuid }
|
id { SecureRandom.uuid }
|
||||||
started_at DateTime.now
|
started_at DateTime.now
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ feature 'Admin::Organizations' do
|
|||||||
end
|
end
|
||||||
|
|
||||||
scenario "verified organizations have link to reject" do
|
scenario "verified organizations have link to reject" do
|
||||||
organization = create(:verified_organization)
|
organization = create(:organization, :verified)
|
||||||
|
|
||||||
visit admin_organizations_path
|
visit admin_organizations_path
|
||||||
expect(page).to have_content ('Verified')
|
expect(page).to have_content ('Verified')
|
||||||
@@ -40,7 +40,7 @@ feature 'Admin::Organizations' do
|
|||||||
end
|
end
|
||||||
|
|
||||||
scenario "rejected organizations have link to verify" do
|
scenario "rejected organizations have link to verify" do
|
||||||
organization = create(:rejected_organization)
|
organization = create(:organization, :rejected)
|
||||||
|
|
||||||
visit admin_organizations_path
|
visit admin_organizations_path
|
||||||
expect(page).to have_link('Verify')
|
expect(page).to have_link('Verify')
|
||||||
@@ -87,8 +87,8 @@ feature 'Admin::Organizations' do
|
|||||||
|
|
||||||
scenario "Filtering organizations" do
|
scenario "Filtering organizations" do
|
||||||
create(:organization, name: "Pending Organization")
|
create(:organization, name: "Pending Organization")
|
||||||
create(:rejected_organization, name: "Rejected Organization")
|
create(:organization, :rejected, name: "Rejected Organization")
|
||||||
create(:verified_organization, name: "Verified Organization")
|
create(:organization, :verified, name: "Verified Organization")
|
||||||
|
|
||||||
visit admin_organizations_path(filter: 'all')
|
visit admin_organizations_path(filter: 'all')
|
||||||
expect(page).to have_content('Pending Organization')
|
expect(page).to have_content('Pending Organization')
|
||||||
@@ -112,7 +112,8 @@ feature 'Admin::Organizations' do
|
|||||||
end
|
end
|
||||||
|
|
||||||
scenario "Verifying organization links remember the pagination setting and the filter" do
|
scenario "Verifying organization links remember the pagination setting and the filter" do
|
||||||
30.times { create(:organization) }
|
per_page = Kaminari.config.default_per_page
|
||||||
|
(per_page + 2).times { create(:organization) }
|
||||||
|
|
||||||
visit admin_organizations_path(filter: 'pending', page: 2)
|
visit admin_organizations_path(filter: 'pending', page: 2)
|
||||||
|
|
||||||
|
|||||||
@@ -133,4 +133,39 @@ feature 'Comments' do
|
|||||||
expect(page).to have_css(".comment.comment.comment.comment.comment.comment.comment.comment")
|
expect(page).to have_css(".comment.comment.comment.comment.comment.comment.comment.comment")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
scenario "Flagging as inappropiate", :js do
|
||||||
|
user = create(:user)
|
||||||
|
debate = create(:debate)
|
||||||
|
comment = create(:comment, commentable: debate)
|
||||||
|
|
||||||
|
login_as(user)
|
||||||
|
visit debate_path(debate)
|
||||||
|
|
||||||
|
within "#comment_#{comment.id}" do
|
||||||
|
expect(page).to_not have_link "Undo flag as inappropiate"
|
||||||
|
click_on 'Flag as inappropiate'
|
||||||
|
expect(page).to have_link "Undo flag as inappropiate"
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(InappropiateFlag.flagged?(user, comment)).to be
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario "Undoing flagging as inappropiate", :js do
|
||||||
|
user = create(:user)
|
||||||
|
debate = create(:debate)
|
||||||
|
comment = create(:comment, commentable: debate)
|
||||||
|
InappropiateFlag.flag!(user, comment)
|
||||||
|
|
||||||
|
login_as(user)
|
||||||
|
visit debate_path(debate)
|
||||||
|
|
||||||
|
within "#comment_#{comment.id}" do
|
||||||
|
expect(page).to_not have_link("Flag as inappropiate", exact: true)
|
||||||
|
click_on 'Undo flag as inappropiate'
|
||||||
|
expect(page).to have_link("Flag as inappropiate", exact: true)
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(InappropiateFlag.flagged?(user, comment)).to_not be
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -315,4 +315,37 @@ feature 'Debates' do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
scenario "Flagging as inappropiate", :js do
|
||||||
|
user = create(:user)
|
||||||
|
debate = create(:debate)
|
||||||
|
|
||||||
|
login_as(user)
|
||||||
|
visit debate_path(debate)
|
||||||
|
|
||||||
|
within "#debate_#{debate.id}" do
|
||||||
|
expect(page).to_not have_link "Undo flag as inappropiate"
|
||||||
|
click_on 'Flag as inappropiate'
|
||||||
|
expect(page).to have_link "Undo flag as inappropiate"
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(InappropiateFlag.flagged?(user, debate)).to be
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario "Undoing flagging as inappropiate", :js do
|
||||||
|
user = create(:user)
|
||||||
|
debate = create(:debate)
|
||||||
|
InappropiateFlag.flag!(user, debate)
|
||||||
|
|
||||||
|
login_as(user)
|
||||||
|
visit debate_path(debate)
|
||||||
|
|
||||||
|
within "#debate_#{debate.id}" do
|
||||||
|
expect(page).to_not have_link("Flag as inappropiate", exact: true)
|
||||||
|
click_on 'Undo flag as inappropiate'
|
||||||
|
expect(page).to have_link("Flag as inappropiate", exact: true)
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(InappropiateFlag.flagged?(user, debate)).to_not be
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -2,61 +2,64 @@ require 'rails_helper'
|
|||||||
|
|
||||||
feature 'Moderate Comments' do
|
feature 'Moderate Comments' do
|
||||||
|
|
||||||
scenario 'Hide', :js do
|
feature 'Hiding Comments' do
|
||||||
citizen = create(:user)
|
|
||||||
moderator = create(:moderator)
|
|
||||||
|
|
||||||
debate = create(:debate)
|
scenario 'Hide', :js do
|
||||||
comment = create(:comment, commentable: debate, body: 'SPAM')
|
citizen = create(:user)
|
||||||
|
moderator = create(:moderator)
|
||||||
|
|
||||||
login_as(moderator.user)
|
debate = create(:debate)
|
||||||
visit debate_path(debate)
|
comment = create(:comment, commentable: debate, body: 'SPAM')
|
||||||
|
|
||||||
within("#comment_#{comment.id}") do
|
login_as(moderator.user)
|
||||||
click_link 'Hide'
|
visit debate_path(debate)
|
||||||
expect(page).to have_css('.comment .faded')
|
|
||||||
|
within("#comment_#{comment.id}") do
|
||||||
|
click_link 'Hide'
|
||||||
|
expect(page).to have_css('.comment .faded')
|
||||||
|
end
|
||||||
|
|
||||||
|
login_as(citizen)
|
||||||
|
visit debate_path(debate)
|
||||||
|
|
||||||
|
expect(page).to have_css('.comment', count: 1)
|
||||||
|
expect(page).to have_content('This comment has been deleted')
|
||||||
|
expect(page).to_not have_content('SPAM')
|
||||||
end
|
end
|
||||||
|
|
||||||
login_as(citizen)
|
scenario 'Children visible', :js do
|
||||||
visit debate_path(debate)
|
citizen = create(:user)
|
||||||
|
moderator = create(:moderator)
|
||||||
|
|
||||||
expect(page).to have_css('.comment', count: 1)
|
debate = create(:debate)
|
||||||
expect(page).to have_content('This comment has been deleted')
|
comment = create(:comment, commentable: debate, body: 'SPAM')
|
||||||
expect(page).to_not have_content('SPAM')
|
create(:comment, commentable: debate, body: 'Acceptable reply', parent_id: comment.id)
|
||||||
end
|
|
||||||
|
|
||||||
scenario 'Children visible', :js do
|
login_as(moderator.user)
|
||||||
citizen = create(:user)
|
visit debate_path(debate)
|
||||||
moderator = create(:moderator)
|
|
||||||
|
|
||||||
debate = create(:debate)
|
within("#comment_#{comment.id}") do
|
||||||
comment = create(:comment, commentable: debate, body: 'SPAM')
|
first(:link, "Hide").click
|
||||||
reply = create(:comment, commentable: debate, body: 'Acceptable reply', parent_id: comment.id)
|
expect(page).to have_css('.comment .faded')
|
||||||
|
end
|
||||||
|
|
||||||
login_as(moderator.user)
|
login_as(citizen)
|
||||||
visit debate_path(debate)
|
visit debate_path(debate)
|
||||||
|
|
||||||
within("#comment_#{comment.id}") do
|
expect(page).to have_css('.comment', count: 2)
|
||||||
first(:link, "Hide").click
|
expect(page).to have_content('This comment has been deleted')
|
||||||
expect(page).to have_css('.comment .faded')
|
expect(page).to_not have_content('SPAM')
|
||||||
|
|
||||||
|
expect(page).to have_content('Acceptable reply')
|
||||||
end
|
end
|
||||||
|
|
||||||
login_as(citizen)
|
|
||||||
visit debate_path(debate)
|
|
||||||
|
|
||||||
expect(page).to have_css('.comment', count: 2)
|
|
||||||
expect(page).to have_content('This comment has been deleted')
|
|
||||||
expect(page).to_not have_content('SPAM')
|
|
||||||
|
|
||||||
expect(page).to have_content('Acceptable reply')
|
|
||||||
end
|
end
|
||||||
|
|
||||||
scenario 'Moderator actions' do
|
scenario 'Moderator actions in the comment' do
|
||||||
citizen = create(:user)
|
citizen = create(:user)
|
||||||
moderator = create(:moderator)
|
moderator = create(:moderator)
|
||||||
|
|
||||||
debate = create(:debate)
|
debate = create(:debate)
|
||||||
comment = create(:comment, commentable: debate)
|
create(:comment, commentable: debate)
|
||||||
|
|
||||||
login_as(moderator.user)
|
login_as(moderator.user)
|
||||||
visit debate_path(debate)
|
visit debate_path(debate)
|
||||||
@@ -69,4 +72,113 @@ feature 'Moderate Comments' do
|
|||||||
expect(page).to_not have_css("#moderator-comment-actions")
|
expect(page).to_not have_css("#moderator-comment-actions")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
feature '/moderation/ menu' do
|
||||||
|
|
||||||
|
background do
|
||||||
|
moderator = create(:moderator)
|
||||||
|
login_as(moderator.user)
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario "Current filter is properly highlighted" do
|
||||||
|
visit moderation_comments_path
|
||||||
|
expect(page).to_not have_link('All')
|
||||||
|
expect(page).to have_link('Pending')
|
||||||
|
expect(page).to have_link('Reviewed')
|
||||||
|
|
||||||
|
visit moderation_comments_path(filter: 'all')
|
||||||
|
expect(page).to_not have_link('All')
|
||||||
|
expect(page).to have_link('Pending')
|
||||||
|
expect(page).to have_link('Reviewed')
|
||||||
|
|
||||||
|
visit moderation_comments_path(filter: 'pending_review')
|
||||||
|
expect(page).to have_link('All')
|
||||||
|
expect(page).to_not have_link('Pending')
|
||||||
|
expect(page).to have_link('Reviewed')
|
||||||
|
|
||||||
|
visit moderation_comments_path(filter: 'reviewed')
|
||||||
|
expect(page).to have_link('All')
|
||||||
|
expect(page).to have_link('Pending')
|
||||||
|
expect(page).to_not have_link('Reviewed')
|
||||||
|
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, :reviewed, body: "Reviewed 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('Reviewed comment')
|
||||||
|
|
||||||
|
visit moderation_comments_path(filter: 'pending_review')
|
||||||
|
expect(page).to have_content('Pending comment')
|
||||||
|
expect(page).to_not have_content('Hidden comment')
|
||||||
|
expect(page).to_not have_content('Reviewed comment')
|
||||||
|
|
||||||
|
visit moderation_comments_path(filter: 'reviewed')
|
||||||
|
expect(page).to_not have_content('Pending comment')
|
||||||
|
expect(page).to_not have_content('Hidden comment')
|
||||||
|
expect(page).to have_content('Reviewed 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) }
|
||||||
|
|
||||||
|
visit moderation_comments_path(filter: 'pending_review', page: 2)
|
||||||
|
|
||||||
|
click_link('Mark as reviewed', 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_review')
|
||||||
|
expect(query_params[:page]).to eq('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')
|
||||||
|
visit moderation_comments_path
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario 'It is displayed with the correct attributes' do
|
||||||
|
within("#comment_#{@comment.id}") do
|
||||||
|
expect(page).to have_link('Democracy')
|
||||||
|
expect(page).to have_content('spammy spam')
|
||||||
|
expect(page).to have_content('1')
|
||||||
|
expect(page).to have_link('Hide')
|
||||||
|
expect(page).to have_link('Mark as reviewed')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario 'Hiding the comment' do
|
||||||
|
within("#comment_#{@comment.id}") do
|
||||||
|
click_link('Hide')
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(current_path).to eq(moderation_comments_path)
|
||||||
|
expect(page).to_not have_selector("#comment_#{@comment.id}")
|
||||||
|
|
||||||
|
expect(@comment.reload).to be_hidden
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario 'Marking the comment as reviewed' do
|
||||||
|
within("#comment_#{@comment.id}") do
|
||||||
|
click_link('Mark as reviewed')
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(current_path).to eq(moderation_comments_path)
|
||||||
|
|
||||||
|
within("#comment_#{@comment.id}") do
|
||||||
|
expect(page).to have_content('Reviewed')
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(@comment.reload).to be_reviewed
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
@@ -23,4 +23,113 @@ feature 'Moderate debates' do
|
|||||||
expect(page).to have_css('.debate', count: 0)
|
expect(page).to have_css('.debate', count: 0)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
feature '/moderation/ menu' do
|
||||||
|
|
||||||
|
background do
|
||||||
|
moderator = create(:moderator)
|
||||||
|
login_as(moderator.user)
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario "Current filter is properly highlighted" do
|
||||||
|
visit moderation_debates_path
|
||||||
|
expect(page).to_not have_link('All')
|
||||||
|
expect(page).to have_link('Pending')
|
||||||
|
expect(page).to have_link('Reviewed')
|
||||||
|
|
||||||
|
visit moderation_debates_path(filter: 'all')
|
||||||
|
expect(page).to_not have_link('All')
|
||||||
|
expect(page).to have_link('Pending')
|
||||||
|
expect(page).to have_link('Reviewed')
|
||||||
|
|
||||||
|
visit moderation_debates_path(filter: 'pending_review')
|
||||||
|
expect(page).to have_link('All')
|
||||||
|
expect(page).to_not have_link('Pending')
|
||||||
|
expect(page).to have_link('Reviewed')
|
||||||
|
|
||||||
|
visit moderation_debates_path(filter: 'reviewed')
|
||||||
|
expect(page).to have_link('All')
|
||||||
|
expect(page).to have_link('Pending')
|
||||||
|
expect(page).to_not have_link('Reviewed')
|
||||||
|
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, :reviewed, title: "Reviewed 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('Reviewed debate')
|
||||||
|
|
||||||
|
visit moderation_debates_path(filter: 'pending_review')
|
||||||
|
expect(page).to have_content('Pending debate')
|
||||||
|
expect(page).to_not have_content('Hidden debate')
|
||||||
|
expect(page).to_not have_content('Reviewed debate')
|
||||||
|
|
||||||
|
visit moderation_debates_path(filter: 'reviewed')
|
||||||
|
expect(page).to_not have_content('Pending debate')
|
||||||
|
expect(page).to_not have_content('Hidden debate')
|
||||||
|
expect(page).to have_content('Reviewed 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) }
|
||||||
|
|
||||||
|
visit moderation_debates_path(filter: 'pending_review', page: 2)
|
||||||
|
|
||||||
|
click_link('Mark as reviewed', 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_review')
|
||||||
|
expect(query_params[:page]).to eq('2')
|
||||||
|
end
|
||||||
|
|
||||||
|
feature 'A flagged debate exists' do
|
||||||
|
|
||||||
|
background do
|
||||||
|
@debate = create(:debate, :flagged_as_inappropiate, title: 'spammy spam', description: 'buy buy buy')
|
||||||
|
visit moderation_debates_path
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario 'It is displayed with the correct attributes' do
|
||||||
|
within("#debate_#{@debate.id}") do
|
||||||
|
expect(page).to have_link('spammy spam')
|
||||||
|
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('Mark as reviewed')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario 'Hiding the debate' do
|
||||||
|
within("#debate_#{@debate.id}") do
|
||||||
|
click_link('Hide')
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(current_path).to eq(moderation_debates_path)
|
||||||
|
expect(page).to_not have_selector("#debate_#{@debate.id}")
|
||||||
|
|
||||||
|
expect(@debate.reload).to be_hidden
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario 'Marking the debate as reviewed' do
|
||||||
|
within("#debate_#{@debate.id}") do
|
||||||
|
click_link('Mark as reviewed')
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(current_path).to eq(moderation_debates_path)
|
||||||
|
|
||||||
|
within("#debate_#{@debate.id}") do
|
||||||
|
expect(page).to have_content('Reviewed')
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(@debate.reload).to be_reviewed
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -5,6 +5,9 @@ feature 'Admin' do
|
|||||||
|
|
||||||
scenario 'Access as regular user is not authorized' do
|
scenario 'Access as regular user is not authorized' do
|
||||||
login_as(user)
|
login_as(user)
|
||||||
|
visit root_path
|
||||||
|
|
||||||
|
expect(page).to_not have_link("Moderation")
|
||||||
visit moderation_root_path
|
visit moderation_root_path
|
||||||
|
|
||||||
expect(current_path).to eq(root_path)
|
expect(current_path).to eq(root_path)
|
||||||
@@ -15,7 +18,10 @@ feature 'Admin' do
|
|||||||
create(:moderator, user: user)
|
create(:moderator, user: user)
|
||||||
|
|
||||||
login_as(user)
|
login_as(user)
|
||||||
visit moderation_root_path
|
visit root_path
|
||||||
|
|
||||||
|
expect(page).to have_link("Moderation")
|
||||||
|
click_on "Moderation"
|
||||||
|
|
||||||
expect(current_path).to eq(moderation_root_path)
|
expect(current_path).to eq(moderation_root_path)
|
||||||
expect(page).to_not have_content "not authorized"
|
expect(page).to_not have_content "not authorized"
|
||||||
@@ -25,7 +31,10 @@ feature 'Admin' do
|
|||||||
create(:administrator, user: user)
|
create(:administrator, user: user)
|
||||||
|
|
||||||
login_as(user)
|
login_as(user)
|
||||||
visit moderation_root_path
|
visit root_path
|
||||||
|
|
||||||
|
expect(page).to have_link("Moderation")
|
||||||
|
click_on "Moderation"
|
||||||
|
|
||||||
expect(current_path).to eq(moderation_root_path)
|
expect(current_path).to eq(moderation_root_path)
|
||||||
expect(page).to_not have_content "not authorized"
|
expect(page).to_not have_content "not authorized"
|
||||||
|
|||||||
@@ -22,12 +22,48 @@ describe Ability do
|
|||||||
it { should be_able_to(:show, debate) }
|
it { should be_able_to(:show, debate) }
|
||||||
it { should be_able_to(:vote, debate) }
|
it { should be_able_to(:vote, debate) }
|
||||||
|
|
||||||
|
|
||||||
it { should be_able_to(:show, user) }
|
it { should be_able_to(:show, user) }
|
||||||
it { should be_able_to(:edit, user) }
|
it { should be_able_to(:edit, user) }
|
||||||
|
|
||||||
it { should be_able_to(:create, Comment) }
|
it { should be_able_to(:create, Comment) }
|
||||||
it { should be_able_to(:vote, Comment) }
|
it { should be_able_to(:vote, Comment) }
|
||||||
|
|
||||||
|
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 "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) }
|
||||||
|
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) }
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "already-flagged comments" do
|
||||||
|
before(:each) { InappropiateFlag.flag!(user, comment) }
|
||||||
|
|
||||||
|
it { should_not be_able_to(:flag_as_inappropiate, comment) }
|
||||||
|
it { should be_able_to(:undo_flag_as_inappropiate, comment) }
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "already-flagged debates" do
|
||||||
|
before(:each) { InappropiateFlag.flag!(user, debate) }
|
||||||
|
|
||||||
|
it { should_not be_able_to(:flag_as_inappropiate, debate) }
|
||||||
|
it { should be_able_to(:undo_flag_as_inappropiate, debate) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "other users" do
|
describe "other users" do
|
||||||
let(:other_user) { create(:user) }
|
let(:other_user) { create(:user) }
|
||||||
it { should_not be_able_to(:show, other_user) }
|
it { should_not be_able_to(:show, other_user) }
|
||||||
@@ -66,6 +102,7 @@ describe Ability do
|
|||||||
before { create(:moderator, user: user) }
|
before { create(:moderator, user: user) }
|
||||||
let(:other_user) { create(:user) }
|
let(:other_user) { create(:user) }
|
||||||
|
|
||||||
|
|
||||||
it { should be_able_to(:index, Debate) }
|
it { should be_able_to(:index, Debate) }
|
||||||
it { should be_able_to(:show, debate) }
|
it { should be_able_to(:show, debate) }
|
||||||
it { should be_able_to(:vote, debate) }
|
it { should be_able_to(:vote, debate) }
|
||||||
@@ -74,8 +111,8 @@ describe Ability do
|
|||||||
|
|
||||||
describe "organizations" do
|
describe "organizations" do
|
||||||
let(:pending_organization) { create(:organization) }
|
let(:pending_organization) { create(:organization) }
|
||||||
let(:rejected_organization) { create(:rejected_organization) }
|
let(:rejected_organization) { create(:organization, :rejected) }
|
||||||
let(:verified_organization) { create(:verified_organization) }
|
let(:verified_organization) { create(:organization, :verified) }
|
||||||
|
|
||||||
it { should be_able_to( :verify, pending_organization) }
|
it { should be_able_to( :verify, pending_organization) }
|
||||||
it { should be_able_to( :reject, pending_organization) }
|
it { should be_able_to( :reject, pending_organization) }
|
||||||
@@ -87,13 +124,41 @@ describe Ability do
|
|||||||
it { should be_able_to( :verify, rejected_organization) }
|
it { should be_able_to( :verify, rejected_organization) }
|
||||||
end
|
end
|
||||||
|
|
||||||
it { should be_able_to(:hide, comment) }
|
describe "hiding, reviewing and restoring" do
|
||||||
it { should be_able_to(:hide, debate) }
|
let(:own_comment) { create(:comment, author: user) }
|
||||||
it { should be_able_to(:hide, other_user) }
|
let(:own_debate) { create(:debate, author: user) }
|
||||||
|
let(:hidden_comment) { create(:comment, :hidden) }
|
||||||
|
let(:hidden_debate) { create(:debate, :hidden) }
|
||||||
|
let(:reviewed_comment) { create(:comment, :reviewed) }
|
||||||
|
let(:reviewed_debate) { create(:debate, :reviewed) }
|
||||||
|
|
||||||
it { should_not be_able_to(:restore, comment) }
|
it { should be_able_to(:hide, comment) }
|
||||||
it { should_not be_able_to(:restore, debate) }
|
it { should be_able_to(:hide_in_moderation_screen, comment) }
|
||||||
it { should_not be_able_to(:restore, other_user) }
|
it { should_not be_able_to(:hide, hidden_comment) }
|
||||||
|
it { should_not be_able_to(:hide, own_comment) }
|
||||||
|
|
||||||
|
it { should be_able_to(:hide, debate) }
|
||||||
|
it { should be_able_to(:hide_in_moderation_screen, debate) }
|
||||||
|
it { should_not be_able_to(:hide, hidden_debate) }
|
||||||
|
it { should_not be_able_to(:hide, own_debate) }
|
||||||
|
|
||||||
|
it { should be_able_to(:mark_as_reviewed, comment) }
|
||||||
|
it { should_not be_able_to(:mark_as_reviewed, hidden_comment) }
|
||||||
|
it { should_not be_able_to(:mark_as_reviewed, reviewed_comment) }
|
||||||
|
it { should_not be_able_to(:mark_as_reviewed, own_comment) }
|
||||||
|
|
||||||
|
it { should be_able_to(:mark_as_reviewed, debate) }
|
||||||
|
it { should_not be_able_to(:mark_as_reviewed, hidden_debate) }
|
||||||
|
it { should_not be_able_to(:mark_as_reviewed, reviewed_debate) }
|
||||||
|
it { should_not be_able_to(:mark_as_reviewed, own_debate) }
|
||||||
|
|
||||||
|
it { should_not be_able_to(:hide, user) }
|
||||||
|
it { should be_able_to(:hide, other_user) }
|
||||||
|
|
||||||
|
it { should_not be_able_to(:restore, comment) }
|
||||||
|
it { should_not be_able_to(:restore, debate) }
|
||||||
|
it { should_not be_able_to(:restore, other_user) }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "Administrator" do
|
describe "Administrator" do
|
||||||
|
|||||||
64
spec/models/inappropiate_flag_spec.rb
Normal file
64
spec/models/inappropiate_flag_spec.rb
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
describe InappropiateFlag do
|
||||||
|
|
||||||
|
let(:user) { create(:user) }
|
||||||
|
let(:comment) { create(:comment) }
|
||||||
|
|
||||||
|
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)
|
||||||
|
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)
|
||||||
|
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 }
|
||||||
|
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)
|
||||||
|
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)
|
||||||
|
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 }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '.flagged?' do
|
||||||
|
it 'returns false when the user has not flagged the comment' do
|
||||||
|
expect(described_class.flagged?(user, comment)).to_not be
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns true when the user has flagged the comment' do
|
||||||
|
described_class.flag!(user, comment)
|
||||||
|
expect(described_class.flagged?(user, comment)).to be
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
Reference in New Issue
Block a user