Merge pull request #2717 from consul/allow-author-notifications-to-be-moderated

Allow author notifications to be moderated
This commit is contained in:
Alberto
2018-07-03 11:21:26 +02:00
committed by GitHub
32 changed files with 661 additions and 10 deletions

View File

@@ -33,6 +33,7 @@
//= require moderator_comment //= require moderator_comment
//= require moderator_debates //= require moderator_debates
//= require moderator_proposals //= require moderator_proposals
//= require moderator_proposal_notifications
//= require prevent_double_submission //= require prevent_double_submission
//= require gettext //= require gettext
//= require annotator //= require annotator

View File

@@ -0,0 +1,7 @@
App.ModeratorProposalNotifications =
add_class_faded: (id) ->
$("##{id}").addClass("faded")
hide_moderator_actions: (id) ->
$("##{id} .js-moderator-proposal-notifications-actions:first").hide()

View File

@@ -1963,7 +1963,8 @@ table {
} }
} }
.comment-body { .comment-body,
.notification-body {
img { img {
margin-right: $line-height / 2; margin-right: $line-height / 2;

View File

@@ -0,0 +1,30 @@
class Admin::ProposalNotificationsController < Admin::BaseController
has_filters %w{without_confirmed_hide all with_confirmed_hide}, only: :index
before_action :load_proposal, only: [:confirm_hide, :restore]
def index
@proposal_notifications = ProposalNotification.only_hidden.send(@current_filter).order(hidden_at: :desc)
.page(params[:page])
end
def confirm_hide
@proposal_notification.confirm_hide
redirect_to request.query_parameters.merge(action: :index)
end
def restore
@proposal_notification.restore
@proposal_notification.ignore_flag
Activity.log(current_user, :restore, @proposal_notification)
redirect_to request.query_parameters.merge(action: :index)
end
private
def load_proposal
@proposal_notification = ProposalNotification.with_hidden.find(params[:id])
end
end

View File

@@ -57,4 +57,4 @@ module ModerateActions
:author_id :author_id
end end
end end

View File

@@ -26,4 +26,4 @@ module Polymorphic
send("#{resource_name}_params") send("#{resource_name}_params")
end end
end end

View File

@@ -0,0 +1,24 @@
class Moderation::ProposalNotificationsController < Moderation::BaseController
include ModerateActions
has_filters %w{pending_review all ignored}, only: :index
has_orders %w{created_at moderated}, only: :index
before_action :load_resources, only: [:index, :moderate]
load_and_authorize_resource
def hide
ProposalNotification.find(params[:id]).update(moderated: true)
end
private
def resource_name
'proposal_notification'
end
def resource_model
ProposalNotification
end
end

View File

@@ -24,6 +24,7 @@ class ProposalsController < ApplicationController
def show def show
super super
@notifications = @proposal.notifications @notifications = @proposal.notifications
@notifications = @proposal.notifications.not_moderated
@related_contents = Kaminari.paginate_array(@proposal.relationed_contents).page(params[:page]).per(5) @related_contents = Kaminari.paginate_array(@proposal.relationed_contents).page(params[:page]).per(5)
redirect_to proposal_path(@proposal), status: :moved_permanently if request.path != proposal_path(@proposal) redirect_to proposal_path(@proposal), status: :moved_permanently if request.path != proposal_path(@proposal)

View File

@@ -52,6 +52,17 @@ module Abilities
can :block, User can :block, User
cannot :block, User, id: user.id cannot :block, User, id: user.id
can :hide, ProposalNotification, hidden_at: nil
cannot :hide, ProposalNotification, author_id: user.id
can :ignore_flag, ProposalNotification, ignored_at: nil, hidden_at: nil
cannot :ignore_flag, ProposalNotification, author_id: user.id
can :moderate, ProposalNotification
cannot :moderate, ProposalNotification, author_id: user.id
can :index, ProposalNotification
end end
end end
end end

View File

@@ -10,7 +10,19 @@ class ProposalNotification < ActiveRecord::Base
validates :proposal, presence: true validates :proposal, presence: true
validate :minimum_interval validate :minimum_interval
scope :public_for_api, -> { where(proposal_id: Proposal.public_for_api.pluck(:id)) } scope :public_for_api, -> { where(proposal_id: Proposal.public_for_api.pluck(:id)) }
scope :sort_by_created_at, -> { reorder(created_at: :desc) }
scope :sort_by_moderated, -> { reorder(moderated: :desc) }
scope :moderated, -> { where(moderated: true) }
scope :not_moderated, -> { where(moderated: false) }
scope :pending_review, -> { moderated.where(ignored_at: nil) }
scope :ignored, -> { moderated.where.not(ignored_at: nil) }
acts_as_paranoid column: :hidden_at
include ActsAsParanoidAliases
after_create :set_author
def minimum_interval def minimum_interval
return true if proposal.try(:notifications).blank? return true if proposal.try(:notifications).blank?
@@ -25,4 +37,22 @@ class ProposalNotification < ActiveRecord::Base
proposal proposal
end end
def ignore_flag
update(ignored_at: Time.current)
end
def ignored?
ignored_at.present?
end
def after_restore
update(moderated: false)
end
private
def set_author
self.update(author_id: self.proposal.author_id) if self.proposal
end
end end

View File

@@ -182,12 +182,14 @@ class User < ActiveRecord::Base
debates_ids = Debate.where(author_id: id).pluck(:id) debates_ids = Debate.where(author_id: id).pluck(:id)
comments_ids = Comment.where(user_id: id).pluck(:id) comments_ids = Comment.where(user_id: id).pluck(:id)
proposal_ids = Proposal.where(author_id: id).pluck(:id) proposal_ids = Proposal.where(author_id: id).pluck(:id)
proposal_notification_ids = ProposalNotification.where(author_id: id).pluck(:id)
hide hide
Debate.hide_all debates_ids Debate.hide_all debates_ids
Comment.hide_all comments_ids Comment.hide_all comments_ids
Proposal.hide_all proposal_ids Proposal.hide_all proposal_ids
ProposalNotification.hide_all proposal_notification_ids
end end
def erase(erase_reason = nil) def erase(erase_reason = nil)

View File

@@ -149,6 +149,10 @@
<%= link_to t("admin.menu.hidden_comments"), admin_comments_path %> <%= link_to t("admin.menu.hidden_comments"), admin_comments_path %>
</li> </li>
<li <%= "class=is-active" if controller_name == "proposal_notifications" %>>
<%= link_to t("admin.menu.hidden_proposal_notifications"), admin_proposal_notifications_path %>
</li>
<li <%= "class=is-active" if controller_name == "hidden_users" %>> <li <%= "class=is-active" if controller_name == "hidden_users" %>>
<%= link_to t("admin.menu.hidden_users"), admin_hidden_users_path %> <%= link_to t("admin.menu.hidden_users"), admin_hidden_users_path %>
</li> </li>

View File

@@ -0,0 +1,49 @@
<h2><%= t("admin.proposal_notifications.index.title") %></h2>
<p><%= t("admin.shared.moderated_content") %></p>
<%= render 'shared/filter_subnav', i18n_namespace: "admin.proposal_notifications.index" %>
<% if @proposal_notifications.any? %>
<h3 class="margin"><%= page_entries_info @proposal_notifications %></h3>
<table>
<thead>
<th scope="col"><%= t("admin.shared.title") %></th>
<th scope="col" class="small-6"><%= t("admin.shared.description") %></th>
<th scope="col" class="small-4"><%= t("admin.shared.actions") %></th>
</thead>
<tbody>
<% @proposal_notifications.each do |proposal_notification| %>
<tr id="<%= dom_id(proposal_notification) %>">
<td class="align-top">
<strong><%= proposal_notification.title %></strong>
</td>
<td>
<div class="moderation-description">
<%= proposal_notification.body %>
</div>
</td>
<td class="align-top">
<%= link_to t("admin.actions.restore"),
restore_admin_proposal_notification_path(proposal_notification, request.query_parameters),
method: :put,
data: { confirm: t("admin.actions.confirm") },
class: "button hollow warning" %>
<% unless proposal_notification.confirmed_hide? %>
<%= link_to t("admin.actions.confirm_hide"),
confirm_hide_admin_proposal_notification_path(proposal_notification, request.query_parameters),
method: :put,
class: "button" %>
<% end %>
</td>
</tr>
<% end %>
</tbody>
</table>
<%= paginate @proposal_notifications %>
<% else %>
<div class="callout primary margin">
<%= t("admin.proposal_notifications.index.no_hidden_proposals") %>
</div>
<% end %>

View File

@@ -11,6 +11,13 @@
<%= t("moderation.menu.proposals") %> <%= t("moderation.menu.proposals") %>
<% end %> <% end %>
</li> </li>
<li <%= "class=is-active" if controller_name == "proposal_notifications" %>>
<%= link_to moderation_proposal_notifications_path do %>
<span class="icon-proposals"></span>
<%= t("moderation.menu.proposal_notifications") %>
<% end %>
</li>
<% end %> <% end %>
<% if feature?(:debates) %> <% if feature?(:debates) %>

View File

@@ -0,0 +1,3 @@
var proposal_notification_id = '<%= dom_id(@proposal_notification) %>';
App.ModeratorProposalNotifications.add_class_faded(proposal_notification_id);
App.ModeratorProposalNotifications.hide_moderator_actions(proposal_notification_id);

View File

@@ -0,0 +1,67 @@
<h2><%= t("moderation.proposal_notifications.index.title") %></h2>
<%= render 'shared/filter_subnav', i18n_namespace: "moderation.proposal_notifications.index" %>
<h3 class="inline-block"><%= page_entries_info @proposal_notifications %></h3>
<div class="float-right">
<%= t("moderation.proposal_notifications.index.order") %>
<%= render 'shared/order_selector', i18n_namespace: "moderation.proposal_notifications.index" %>
</div>
<%= form_tag moderate_moderation_proposal_notifications_path(request.query_parameters), method: :put do %>
<p class="js-check">
<%= t('shared.check') %>:
<%= link_to t('shared.check_all'), '#', data: {check_all: "proposal_notification_ids[]"} %>
|
<%= link_to t('shared.check_none'), '#', data: {check_none: "proposal_notification_ids[]"} %>
</p>
<table class="clear">
<tr>
<th>
<%= t("moderation.proposal_notifications.index.headers.proposal_notification") %>
</th>
<th>
<%= t("moderation.proposal_notifications.index.headers.moderate") %>
</th>
</tr>
<% @proposal_notifications.each do |proposal_notification| %>
<tr id="proposal_notification_<%= proposal_notification.id %>">
<td>
<%= link_to proposal_notification.title, proposal_notification, target: "_blank" %>
<br>
<span class="date"><%= l proposal_notification.updated_at.to_date %></span>
<br>
<div class="moderation-description">
<%= proposal_notification.body %>
</div>
</td>
<td class="text-center">
<%= check_box_tag "proposal_notification_ids[]", proposal_notification.id, nil, id: "#{dom_id(proposal_notification)}_check" %>
</td>
</tr>
<% end %>
</table>
<%= submit_tag t('moderation.proposal_notifications.index.block_authors'),
name: "block_authors",
class: "button hollow alert",
data: {confirm: t('moderation.proposal_notifications.index.confirm')}
%>
<div class="float-right">
<%= submit_tag t('moderation.proposal_notifications.index.hide_proposal_notifications'),
name: "hide_proposal_notifications",
class: "button hollow alert",
data: {confirm: t('moderation.proposal_notifications.index.confirm')}
%>
<%= submit_tag t('moderation.proposal_notifications.index.ignore_flags'),
name: "ignore_flags",
class: "button hollow",
data: {confirm: t('moderation.proposal_notifications.index.confirm')}
%>
</div>
<%= paginate @proposal_notifications %>
<% end %>

View File

@@ -0,0 +1,14 @@
<div class="reply">
<span class='js-moderation-actions'>
<% if can? :hide, notification %>
<%= link_to t("admin.actions.hide").capitalize, hide_moderation_proposal_notification_path(notification),
method: :put, remote: true, data: { confirm: t('admin.actions.confirm') } %>
<% end %>
<% if can? :hide, notification.author %>
<span class="divider">&nbsp;&bull;&nbsp;</span>
<%= link_to t("admin.actions.hide_author").capitalize, hide_moderation_user_path(notification.author_id),
method: :put, data: { confirm: t('admin.actions.confirm') } %>
<% end %>
</span>
</div>

View File

@@ -1,6 +1,6 @@
<div class="tabs-panel" id="tab-notifications" role="tab"> <div class="tabs-panel" id="tab-notifications" role="tab">
<div class="row"> <div class="row">
<div class="small-12 column"> <div id="proposal_notifications" class="small-12 column notification-body">
<% if @notifications.blank? %> <% if @notifications.blank? %>
<div class="callout primary text-center"> <div class="callout primary text-center">
<%= t('proposals.show.no_notifications') %> <%= t('proposals.show.no_notifications') %>
@@ -8,9 +8,15 @@
<% end %> <% end %>
<% @notifications.each do |notification| %> <% @notifications.each do |notification| %>
<h3><%= notification.title %></h3> <div id="<%= dom_id(notification) %>">
<p class="more-info"><%= notification.created_at.to_date %></p> <h3><%= notification.title %></h3>
<p><%= notification.body %></p> <p class="more-info"><%= notification.created_at.to_date %></p>
<%= simple_format text_with_links(notification.body), {}, sanitize: false %>
<span class="js-flag-actions">
<%= render 'proposal_notifications/actions', notification: notification %>
</span>
</div>
<% end %> <% end %>
</div> </div>
</div> </div>

View File

@@ -129,6 +129,7 @@ ignore_unused:
- 'admin.banners.index.filters.*' - 'admin.banners.index.filters.*'
- 'admin.debates.index.filter*' - 'admin.debates.index.filter*'
- 'admin.proposals.index.filter*' - 'admin.proposals.index.filter*'
- 'admin.proposal_notifications.index.filter*'
- 'admin.budgets.index.filter*' - 'admin.budgets.index.filter*'
- 'admin.budget_investments.index.filter*' - 'admin.budget_investments.index.filter*'
- 'admin.spending_proposals.index.filter*' - 'admin.spending_proposals.index.filter*'
@@ -151,6 +152,8 @@ ignore_unused:
- 'moderation.proposals.index.order*' - 'moderation.proposals.index.order*'
- 'moderation.debates.index.filter*' - 'moderation.debates.index.filter*'
- 'moderation.debates.index.order*' - 'moderation.debates.index.order*'
- 'moderation.proposal_notifications.index.filter*'
- 'moderation.proposal_notifications.index.order*'
- 'valuation.spending_proposals.index.filter*' - 'valuation.spending_proposals.index.filter*'
- 'valuation.budgets.index.filter*' - 'valuation.budgets.index.filter*'
- 'valuation.budget_investments.index.filter*' - 'valuation.budget_investments.index.filter*'

View File

@@ -103,6 +103,9 @@ en:
poll: poll:
one: "Poll" one: "Poll"
other: "Polls" other: "Polls"
proposal_notification:
one: "Proposal notification"
other: "Proposal notifications"
attributes: attributes:
budget: budget:
name: "Name" name: "Name"

View File

@@ -504,6 +504,7 @@ en:
hidden_comments: Hidden comments hidden_comments: Hidden comments
hidden_debates: Hidden debates hidden_debates: Hidden debates
hidden_proposals: Hidden proposals hidden_proposals: Hidden proposals
hidden_proposal_notifications: Hidden proposal notifications
hidden_users: Hidden users hidden_users: Hidden users
administrators: Administrators administrators: Administrators
managers: Managers managers: Managers
@@ -940,6 +941,15 @@ en:
without_confirmed_hide: Pending without_confirmed_hide: Pending
title: Hidden proposals title: Hidden proposals
no_hidden_proposals: There is no hidden proposals. no_hidden_proposals: There is no hidden proposals.
proposal_notifications:
index:
filter: Filter
filters:
all: All
with_confirmed_hide: Confirmed
without_confirmed_hide: Pending
title: Hidden notifications
no_hidden_proposals: There is no hidden notifications.
settings: settings:
flash: flash:
updated: Value updated updated: Value updated

View File

@@ -47,6 +47,7 @@ en:
flagged_comments: Comments flagged_comments: Comments
flagged_debates: Debates flagged_debates: Debates
proposals: Proposals proposals: Proposals
proposal_notifications: Proposals notifications
users: Block users users: Block users
proposals: proposals:
index: index:
@@ -67,6 +68,25 @@ en:
created_at: Most recent created_at: Most recent
flags: Most flagged flags: Most flagged
title: Proposals title: Proposals
proposal_notifications:
index:
block_authors: Block authors
confirm: Are you sure?
filter: Filter
filters:
all: All
pending_review: Pending review
ignored: Mark as viewed
headers:
moderate: Moderate
proposal_notification: Proposal notification
hide_proposal_notifications: Hide proposals
ignore_flags: Mark as viewed
order: Order by
orders:
created_at: Most recent
moderated: Moderated
title: Proposal notifications
users: users:
index: index:
hidden: Blocked hidden: Blocked

View File

@@ -103,6 +103,9 @@ es:
poll: poll:
one: "Votación" one: "Votación"
other: "Votaciones" other: "Votaciones"
proposal_notification:
one: "Notificación de propuesta"
other: "Notificaciones de propuestas"
attributes: attributes:
budget: budget:
name: "Nombre" name: "Nombre"

View File

@@ -504,6 +504,7 @@ es:
hidden_comments: Comentarios ocultos hidden_comments: Comentarios ocultos
hidden_debates: Debates ocultos hidden_debates: Debates ocultos
hidden_proposals: Propuestas ocultas hidden_proposals: Propuestas ocultas
hidden_proposal_notifications: Notificationes de propuesta ocultas
hidden_users: Usuarios bloqueados hidden_users: Usuarios bloqueados
administrators: Administradores administrators: Administradores
managers: Gestores managers: Gestores
@@ -940,6 +941,15 @@ es:
without_confirmed_hide: Pendientes without_confirmed_hide: Pendientes
title: Propuestas ocultas title: Propuestas ocultas
no_hidden_proposals: No hay propuestas ocultas. no_hidden_proposals: No hay propuestas ocultas.
proposal_notifications:
index:
filter: Filtro
filters:
all: Todas
with_confirmed_hide: Confirmadas
without_confirmed_hide: Pendientes
title: Notificaciones ocultas
no_hidden_proposals: No hay notificaciones ocultas.
settings: settings:
flash: flash:
updated: Valor actualizado updated: Valor actualizado

View File

@@ -47,6 +47,7 @@ es:
flagged_comments: Comentarios flagged_comments: Comentarios
flagged_debates: Debates flagged_debates: Debates
proposals: Propuestas proposals: Propuestas
proposal_notifications: Notificaciones de propuestas
users: Bloquear usuarios users: Bloquear usuarios
proposals: proposals:
index: index:
@@ -67,6 +68,25 @@ es:
created_at: Más recientes created_at: Más recientes
flags: Más denunciadas flags: Más denunciadas
title: Propuestas title: Propuestas
proposal_notifications:
index:
block_authors: Bloquear autores
confirm: '¿Estás seguro?'
filter: Filtro
filters:
all: Todas
pending_review: Pendientes de revisión
ignored: Marcadas como revisadas
headers:
moderate: Moderar
proposal_notification: Notificación de propuesta
hide_proposal_notifications: Ocultar notificaciones
ignore_flags: Marcar como revisadas
order: Ordenar por
orders:
created_at: Más recientes
moderated: Moderadas
title: Notificaciones de propuestas
users: users:
index: index:
hidden: Bloqueado hidden: Bloqueado

View File

@@ -38,6 +38,13 @@ namespace :admin do
get :summary, on: :collection get :summary, on: :collection
end end
resources :proposal_notifications, only: :index do
member do
put :restore
put :confirm_hide
end
end
resources :budgets do resources :budgets do
member do member do
put :calculate_winners put :calculate_winners

View File

@@ -22,4 +22,9 @@ namespace :moderation do
put :hide, on: :member put :hide, on: :member
put :moderate, on: :collection put :moderate, on: :collection
end end
resources :proposal_notifications, only: :index do
put :hide, on: :member
put :moderate, on: :collection
end
end end

View File

@@ -0,0 +1,8 @@
class AddModerationFlagsToProposalNotifications < ActiveRecord::Migration
def change
add_column :proposal_notifications, :moderated, :boolean, default: false
add_column :proposal_notifications, :hidden_at, :datetime
add_column :proposal_notifications, :ignored_at, :datetime
add_column :proposal_notifications, :confirmed_hide_at, :datetime
end
end

View File

@@ -874,8 +874,12 @@ ActiveRecord::Schema.define(version: 20180519132610) do
t.text "body" t.text "body"
t.integer "author_id" t.integer "author_id"
t.integer "proposal_id" t.integer "proposal_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.boolean "moderated", default: false
t.datetime "hidden_at"
t.datetime "ignored_at"
t.datetime "confirmed_hide_at"
end end
create_table "proposals", force: :cascade do |t| create_table "proposals", force: :cascade do |t|

View File

@@ -749,6 +749,23 @@ FactoryBot.define do
sequence(:title) { |n| "Thank you for supporting my proposal #{n}" } sequence(:title) { |n| "Thank you for supporting my proposal #{n}" }
sequence(:body) { |n| "Please let others know so we can make it happen #{n}" } sequence(:body) { |n| "Please let others know so we can make it happen #{n}" }
proposal proposal
association :author, factory: :user
trait :moderated do
moderated true
end
trait :ignored do
ignored_at Date.current
end
trait :hidden do
hidden_at Date.current
end
trait :with_confirmed_hide do
confirmed_hide_at Time.current
end
end end
factory :direct_message do factory :direct_message do

View File

@@ -0,0 +1,95 @@
require 'rails_helper'
feature 'Admin proposal notifications' do
background do
admin = create(:administrator)
login_as(admin.user)
end
scenario 'List shows all relevant info' do
proposal_notification = create(:proposal_notification, :hidden)
visit admin_proposal_notifications_path
expect(page).to have_content(proposal_notification.title)
expect(page).to have_content(proposal_notification.body)
end
scenario 'Restore' do
proposal_notification = create(:proposal_notification, :hidden, created_at: Date.current - 5.days)
visit admin_proposal_notifications_path
click_link 'Restore'
expect(page).not_to have_content(proposal_notification.title)
expect(proposal_notification.reload).not_to be_hidden
expect(proposal_notification).to be_ignored
expect(proposal_notification).not_to be_moderated
end
scenario 'Confirm hide' do
proposal_notification = create(:proposal_notification, :hidden, created_at: Date.current - 5.days)
visit admin_proposal_notifications_path
click_link 'Confirm moderation'
expect(page).not_to have_content(proposal_notification.title)
click_link('Confirmed')
expect(page).to have_content(proposal_notification.title)
expect(proposal_notification.reload).to be_confirmed_hide
end
scenario "Current filter is properly highlighted" do
visit admin_proposal_notifications_path
expect(page).not_to have_link('Pending')
expect(page).to have_link('All')
expect(page).to have_link('Confirmed')
visit admin_proposal_notifications_path(filter: 'Pending')
expect(page).not_to have_link('Pending')
expect(page).to have_link('All')
expect(page).to have_link('Confirmed')
visit admin_proposal_notifications_path(filter: 'all')
expect(page).to have_link('Pending')
expect(page).not_to have_link('All')
expect(page).to have_link('Confirmed')
visit admin_proposal_notifications_path(filter: 'with_confirmed_hide')
expect(page).to have_link('All')
expect(page).to have_link('Pending')
expect(page).not_to have_link('Confirmed')
end
scenario "Filtering proposals" do
create(:proposal_notification, :hidden, title: "Unconfirmed notification")
create(:proposal_notification, :hidden, :with_confirmed_hide, title: "Confirmed notification")
visit admin_proposal_notifications_path(filter: 'pending')
expect(page).to have_content('Unconfirmed notification')
expect(page).not_to have_content('Confirmed notification')
visit admin_proposal_notifications_path(filter: 'all')
expect(page).to have_content('Unconfirmed notification')
expect(page).to have_content('Confirmed notification')
visit admin_proposal_notifications_path(filter: 'with_confirmed_hide')
expect(page).not_to have_content('Unconfirmed notification')
expect(page).to have_content('Confirmed notification')
end
scenario "Action links remember the pagination setting and the filter" do
per_page = Kaminari.config.default_per_page
(per_page + 2).times { create(:proposal_notification, :hidden, :with_confirmed_hide) }
visit admin_proposal_notifications_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

@@ -0,0 +1,189 @@
require 'rails_helper'
feature 'Moderate proposal notifications' do
scenario 'Hide', :js do
citizen = create(:user)
proposal = create(:proposal)
proposal_notification = create(:proposal_notification, proposal: proposal, created_at: Date.current - 4.days)
moderator = create(:moderator)
login_as(moderator.user)
visit proposal_path(proposal)
click_link "Notifications (1)"
within("#proposal_notification_#{proposal_notification.id}") do
accept_confirm { click_link 'Hide' }
end
expect(page).to have_css("#proposal_notification_#{proposal.id}.faded")
logout
login_as(citizen)
visit proposal_path(proposal)
expect(page).to have_content "Notifications (0)"
end
scenario 'Can not hide own proposal notification' do
moderator = create(:moderator)
proposal = create(:proposal, author: moderator.user)
proposal_notification = create(:proposal_notification, proposal: proposal, created_at: Date.current - 4.days)
login_as(moderator.user)
visit proposal_path(proposal)
within("#proposal_notification_#{proposal_notification.id}") do
expect(page).not_to have_link('Hide')
expect(page).not_to have_link('Block author')
end
end
feature '/moderation/ screen' do
background do
moderator = create(:moderator)
login_as(moderator.user)
end
feature 'moderate in bulk' do
feature "When a proposal has been selected for moderation" do
background do
proposal = create(:proposal)
@proposal_notification = create(:proposal_notification, proposal: proposal, created_at: Date.current - 4.days)
visit moderation_proposal_notifications_path
within('.menu.simple') do
click_link "All"
end
within("#proposal_notification_#{@proposal_notification.id}") do
check "proposal_notification_#{@proposal_notification.id}_check"
end
end
scenario 'Hide the proposal' do
click_on "Hide proposals"
expect(page).not_to have_css("#proposal_notification_#{@proposal_notification.id}")
expect(@proposal_notification.reload).to be_hidden
expect(@proposal_notification.author).not_to be_hidden
end
scenario 'Block the author' do
author = create(:user)
@proposal_notification.update(author: author)
click_on "Block authors"
expect(page).not_to have_css("#proposal_notification_#{@proposal_notification.id}")
expect(@proposal_notification.reload).to be_hidden
expect(author.reload).to be_hidden
end
scenario 'Ignore the proposal' do
click_button "Mark as viewed"
expect(@proposal_notification.reload).to be_ignored
expect(@proposal_notification.reload).not_to be_hidden
expect(@proposal_notification.author).not_to be_hidden
end
end
scenario "select all/none", :js do
create_list(:proposal_notification, 2)
visit moderation_proposal_notifications_path
within('.js-check') { click_on 'All' }
expect(all('input[type=checkbox]')).to all(be_checked)
within('.js-check') { click_on 'None' }
all('input[type=checkbox]').each do |checkbox|
expect(checkbox).not_to be_checked
end
end
scenario "remembering page, filter and order" do
create_list(:proposal, 52)
visit moderation_proposal_notifications_path(filter: 'all', page: '2', order: 'created_at')
click_button "Mark as viewed"
expect(page).to have_selector('.js-order-selector[data-order="created_at"]')
expect(current_url).to include('filter=all')
expect(current_url).to include('page=2')
expect(current_url).to include('order=created_at')
end
end
scenario "Current filter is properly highlighted" do
visit moderation_proposal_notifications_path
expect(page).not_to have_link('Pending review')
expect(page).to have_link('All')
expect(page).to have_link('Mark as viewed')
visit moderation_proposal_notifications_path(filter: 'all')
within('.menu.simple') do
expect(page).not_to have_link('All')
expect(page).to have_link('Pending review')
expect(page).to have_link('Mark as viewed')
end
visit moderation_proposal_notifications_path(filter: 'pending_review')
within('.menu.simple') do
expect(page).to have_link('All')
expect(page).not_to have_link('Pending review')
expect(page).to have_link('Mark as viewed')
end
visit moderation_proposal_notifications_path(filter: 'ignored')
within('.menu.simple') do
expect(page).to have_link('All')
expect(page).to have_link('Pending review')
expect(page).not_to have_link('Marked as viewed')
end
end
scenario "Filtering proposals" do
proposal = create(:proposal)
create(:proposal_notification, title: "Regular proposal", proposal: proposal)
create(:proposal_notification, :moderated, title: "Pending proposal", proposal: proposal)
create(:proposal_notification, :hidden, title: "Hidden proposal", proposal: proposal)
create(:proposal_notification, :moderated, :ignored, title: "Ignored proposal", proposal: proposal)
visit moderation_proposal_notifications_path(filter: 'all')
expect(page).to have_content('Regular proposal')
expect(page).to have_content('Pending proposal')
expect(page).not_to have_content('Hidden proposal')
expect(page).to have_content('Ignored proposal')
visit moderation_proposal_notifications_path(filter: 'pending_review')
expect(page).not_to have_content('Regular proposal')
expect(page).to have_content('Pending proposal')
expect(page).not_to have_content('Hidden proposal')
expect(page).not_to have_content('Ignored proposal')
visit moderation_proposal_notifications_path(filter: 'ignored')
expect(page).not_to have_content('Regular proposal')
expect(page).not_to have_content('Pending proposal')
expect(page).not_to have_content('Hidden proposal')
expect(page).to have_content('Ignored proposal')
end
scenario "sorting proposal notifications" do
moderated_notification = create(:proposal_notification, :moderated, title: "Moderated notification", created_at: Time.current - 1.day)
moderated_new_notification = create(:proposal_notification, :moderated, title: "Moderated new notification", created_at: Time.current - 12.hours)
newer_notification = create(:proposal_notification, title: "Newer notification", created_at: Time.current)
old_moderated_notification = create(:proposal_notification, :moderated, title: "Older notification", created_at: Time.current - 2.days)
visit moderation_proposal_notifications_path(filter: 'all', order: 'created_at')
expect(moderated_new_notification.title).to appear_before(moderated_notification.title)
visit moderation_proposal_notifications_path(filter: 'all', order: 'moderated')
expect(old_moderated_notification.title).to appear_before(newer_notification.title)
end
end
end