Merge pull request #2778 from wairbut-m2c/backport/investments-moderation

Allow budget investments to be moderated
This commit is contained in:
Alberto
2018-07-27 12:34:17 +02:00
committed by GitHub
36 changed files with 1016 additions and 173 deletions

View File

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

View File

@@ -0,0 +1,8 @@
App.ModeratorBudgetInvestments =
add_class_faded: (id) ->
$("##{id}").addClass("faded")
$("#comments").addClass("faded")
hide_moderator_actions: (id) ->
$("##{id} .js-moderator-investment-actions:first").hide()

View File

@@ -0,0 +1,34 @@
class Admin::HiddenBudgetInvestmentsController < Admin::BaseController
include FeatureFlags
has_filters %w{all with_confirmed_hide without_confirmed_hide}, only: :index
feature_flag :budgets
before_action :load_investment, only: [:confirm_hide, :restore]
def index
@investments = Budget::Investment.only_hidden.send(@current_filter)
.order(hidden_at: :desc)
.page(params[:page])
end
def confirm_hide
@investment.confirm_hide
redirect_to request.query_parameters.merge(action: :index)
end
def restore
@investment.restore
@investment.ignore_flag
Activity.log(current_user, :restore, @investment)
redirect_to request.query_parameters.merge(action: :index)
end
private
def load_investment
@investment = Budget::Investment.with_hidden.find(params[:id])
end
end

View File

@@ -3,18 +3,32 @@ module FlagActions
def flag
Flag.flag(current_user, flaggable)
if controller_name == 'investments'
respond_with flaggable, template: "budgets/#{controller_name}/_refresh_flag_actions"
else
respond_with flaggable, template: "#{controller_name}/_refresh_flag_actions"
end
end
def unflag
Flag.unflag(current_user, flaggable)
if controller_name == 'investments'
respond_with flaggable, template: "budgets/#{controller_name}/_refresh_flag_actions"
else
respond_with flaggable, template: "#{controller_name}/_refresh_flag_actions"
end
end
private
def flaggable
if resource_model.to_s == 'Budget::Investment'
instance_variable_get("@investment")
else
instance_variable_get("@#{resource_model.to_s.downcase}")
end
end
end

View File

@@ -3,8 +3,12 @@ module Polymorphic
private
def resource
if resource_model.to_s == 'Budget::Investment'
@resource ||= instance_variable_get("@investment")
else
@resource ||= instance_variable_get("@#{resource_name}")
end
end
def resource_name
@resource_name ||= resource_model.to_s.downcase

View File

@@ -0,0 +1,24 @@
class Moderation::Budgets::InvestmentsController < Moderation::BaseController
include FeatureFlags
include ModerateActions
has_filters %w{pending_flag_review all with_ignored_flag}, only: :index
has_orders %w{flags created_at}, only: :index
feature_flag :budgets
before_action :load_resources, only: [:index, :moderate]
load_and_authorize_resource class: 'Budget::Investment'
private
def resource_name
'budget_investment'
end
def resource_model
Budget::Investment
end
end

View File

@@ -14,6 +14,7 @@ class StatsController < ApplicationController
@debate_votes = daily_cache('debate_votes') { Vote.where(votable_type: 'Debate').count }
@proposal_votes = daily_cache('proposal_votes') { Vote.where(votable_type: 'Proposal').count }
@comment_votes = daily_cache('comment_votes') { Vote.where(votable_type: 'Comment').count }
@investment_votes = daily_cache('budget_investment_votes') { Vote.where(votable_type: 'Budget::Investment').count }
@votes = daily_cache('votes') { Vote.count }
@verified_users = daily_cache('verified_users') { User.with_hidden.level_two_or_three_verified.count }

View File

@@ -1,19 +1,31 @@
module AdminHelper
def side_menu
if namespace == 'moderation/budgets'
render "/moderation/menu"
else
render "/#{namespace}/menu"
end
end
def namespaced_root_path
if namespace == 'moderation/budgets'
"/moderation"
else
"/#{namespace}"
end
end
def namespaced_header_title
if namespace == 'moderation/budgets'
t("moderation.header.title")
else
t("#{namespace}.header.title")
end
end
def menu_moderated_content?
["proposals", "debates", "comments", "hidden_users", "activity"].include?(controller_name) && controller.class.parent != Admin::Legislation
["proposals", "debates", "comments", "hidden_users", "activity", "hidden_budget_investments"].include?(controller_name) && controller.class.parent != Admin::Legislation
end
def menu_budget?

View File

@@ -17,6 +17,9 @@ module Abilities
can :restore, Legislation::Proposal
cannot :restore, Legislation::Proposal, hidden_at: nil
can :restore, Budget::Investment
cannot :restore, Budget::Investment, hidden_at: nil
can :restore, User
cannot :restore, User, hidden_at: nil
@@ -32,6 +35,9 @@ module Abilities
can :confirm_hide, Legislation::Proposal
cannot :confirm_hide, Legislation::Proposal, hidden_at: nil
can :confirm_hide, Budget::Investment
cannot :confirm_hide, Budget::Investment, hidden_at: nil
can :confirm_hide, User
cannot :confirm_hide, User, hidden_at: nil

View File

@@ -46,6 +46,9 @@ module Abilities
can [:flag, :unflag], Legislation::Proposal
cannot [:flag, :unflag], Legislation::Proposal, author_id: user.id
can [:flag, :unflag], Budget::Investment
cannot [:flag, :unflag], Budget::Investment, author_id: user.id
can [:create, :destroy], Follow
can [:destroy], Document, documentable: { author_id: user.id }

View File

@@ -63,6 +63,15 @@ module Abilities
cannot :moderate, ProposalNotification, author_id: user.id
can :index, ProposalNotification
can :hide, Budget::Investment, hidden_at: nil
cannot :hide, Budget::Investment, author_id: user.id
can :ignore_flag, Budget::Investment, ignored_flag_at: nil, hidden_at: nil
cannot :ignore_flag, Budget::Investment, author_id: user.id
can :moderate, Budget::Investment
cannot :moderate, Budget::Investment, author_id: user.id
end
end
end

View File

@@ -23,6 +23,7 @@ class Budget
include Relationable
include Notifiable
include Filterable
include Flaggable
belongs_to :author, -> { with_hidden }, class_name: 'User', foreign_key: 'author_id'
belongs_to :heading
@@ -81,6 +82,8 @@ class Budget
scope :winners, -> { selected.compatible.where(winner: true) }
scope :unselected, -> { not_unfeasible.where(selected: false) }
scope :last_week, -> { where("created_at >= ?", 7.days.ago)}
scope :sort_by_flags, -> { order(flags_count: :desc, updated_at: :desc) }
scope :sort_by_created_at, -> { reorder(created_at: :desc) }
scope :by_budget, ->(budget) { where(budget: budget) }
scope :by_group, ->(group_id) { where(group_id: group_id) }

View File

@@ -182,6 +182,7 @@ class User < ActiveRecord::Base
debates_ids = Debate.where(author_id: id).pluck(:id)
comments_ids = Comment.where(user_id: id).pluck(:id)
proposal_ids = Proposal.where(author_id: id).pluck(:id)
investment_ids = Budget::Investment.where(author_id: id).pluck(:id)
proposal_notification_ids = ProposalNotification.where(author_id: id).pluck(:id)
hide
@@ -189,6 +190,7 @@ class User < ActiveRecord::Base
Debate.hide_all debates_ids
Comment.hide_all comments_ids
Proposal.hide_all proposal_ids
Budget::Investment.hide_all investment_ids
ProposalNotification.hide_all proposal_notification_ids
end

View File

@@ -151,6 +151,12 @@
</li>
<% end %>
<% if feature?(:budgets) %>
<li <%= "class=is-active" if controller_name == "hidden_budget_investments" %>>
<%= link_to t("admin.menu.hidden_budget_investments"), admin_hidden_budget_investments_path %>
</li>
<% end %>
<li <%= "class=is-active" if controller_name == "comments" %>>
<%= link_to t("admin.menu.hidden_comments"), admin_comments_path %>
</li>

View File

@@ -0,0 +1,49 @@
<h2><%= t("admin.hidden_budget_investments.index.title") %></h2>
<p><%= t("admin.shared.moderated_content") %></p>
<%= render 'shared/filter_subnav', i18n_namespace: "admin.hidden_budget_investments.index" %>
<% if @investments.any? %>
<h3 class="margin"><%= page_entries_info @investments %></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>
<% @investments.each do |investment| %>
<tr id="<%= dom_id(investment) %>">
<td class="align-top">
<strong><%= investment.title %></strong>
</td>
<td>
<div class="moderation-description">
<%= investment.description %>
</div>
</td>
<td class="align-top">
<%= link_to t("admin.actions.restore"),
restore_admin_hidden_budget_investment_path(investment, request.query_parameters),
method: :put,
data: { confirm: t("admin.actions.confirm") },
class: "button hollow warning" %>
<% unless investment.confirmed_hide? %>
<%= link_to t("admin.actions.confirm_hide"),
confirm_hide_admin_hidden_budget_investment_path(investment, request.query_parameters),
method: :put,
class: "button" %>
<% end %>
</td>
</tr>
<% end %>
</tbody>
</table>
<%= paginate @investments %>
<% else %>
<div class="callout primary margin">
<%= t("admin.hidden_budget_investments.index.no_hidden_budget_investments") %>
</div>
<% end %>

View File

@@ -0,0 +1,10 @@
<% if can? :hide, investment %>
<%= link_to t("admin.actions.hide").capitalize, hide_moderation_budget_investment_path(investment),
method: :put, remote: true, data: { confirm: t("admin.actions.confirm") } %>
<% end %>
<% if can? :hide, investment.author %>
&nbsp;|&nbsp;
<%= link_to t("admin.actions.hide_author").capitalize, hide_moderation_user_path(investment.author_id),
method: :put, data: { confirm: t("admin.actions.confirm") } %>
<% end %>

View File

@@ -0,0 +1,25 @@
<span class="flag-content">
<% if show_flag_action? investment %>
<a id="flag-expand-investment-<%= investment.id %>" data-toggle="flag-drop-investment-<%= investment.id %>" title="<%= t('shared.flag') %>">
<span class="icon-flag flag-disable"></span>
</a>
<span class="dropdown-pane" id="flag-drop-investment-<%= investment.id %>" data-dropdown data-auto-focus="true">
<%= link_to t('shared.flag'), flag_budget_investment_path(investment.budget, investment.id),
method: :put,
remote: true,
id: "flag-investment-#{ investment.id }" %>
</span>
<% end %>
<% if show_unflag_action? investment %>
<a id="unflag-expand-investment-<%= investment.id %>" data-toggle="unflag-drop-investment-<%= investment.id %>" title="<%= t('shared.unflag') %>">
<span class="icon-flag flag-active"></span>
</a>
<span class="dropdown-pane" id="unflag-drop-investment-<%= investment.id %>" data-dropdown data-auto-focus="true">
<%= link_to t('shared.unflag'), unflag_budget_investment_path(investment.budget, investment.id),
method: :put,
remote: true,
id: "unflag-investment-#{ investment.id }" %>
</span>
<% end %>
</span>

View File

@@ -7,6 +7,11 @@
og_image_url: (investment.image.present? ? investment.image_url(:thumb) : nil) %>
<% end %>
<% cache [locale_and_user_status(investment),
investment,
investment.author,
Flag.flagged?(current_user, investment),
@investment_votes] do %>
<section class="budget-investment-show" id="<%= dom_id(investment) %>">
<div class="row">
@@ -21,6 +26,10 @@
<%= l investment.created_at.to_date %>
<span class="bullet">&nbsp;&bull;&nbsp;</span>
<%= investment.heading.name %>
<span class="bullet">&nbsp;&bull;&nbsp;</span>
<span class="js-flag-actions">
<%= render 'budgets/investments/flag_actions', investment: @investment %>
</span>
</div>
<br>
@@ -76,6 +85,10 @@
<% end %>
<%= render 'relationable/related_content', relationable: @investment %>
<div class="js-moderator-investment-actions margin">
<%= render "budgets/investments/actions", investment: @investment %>
</div>
</div>
<aside class="small-12 medium-3 column">
@@ -130,13 +143,6 @@
</div>
<% end %>
<% else %>
<div class="float-right">
<span class="label-budget-investment float-left">
<%= t("budgets.investments.show.title") %>
</span>
<span class="icon-budget"></span>
</div>
<br>
<% if investment.unfeasible? %>
<div class="callout warning">
<%= t("budgets.investments.show.project_unfeasible_html") %>
@@ -153,6 +159,14 @@
<div class="callout warning">
<%= t("budgets.investments.show.project_not_selected_html") %>
</div>
<% else %>
<br>
<div class="float-right">
<span class="label-budget-investment float-left">
<%= t("budgets.investments.show.title") %>
</span>
<span class="icon-budget"></span>
</div>
<% end %>
<% if investment.should_show_price? %>
<div class="sidebar-divider"></div>
@@ -184,3 +198,4 @@
</aside>
</div>
</section>
<% end %>

View File

@@ -0,0 +1 @@
App.Flaggable.update("<%= dom_id(@investment) %>", "<%= j render("budgets/investments/flag_actions", investment: @investment) %>")

View File

@@ -29,6 +29,15 @@
</li>
<% end %>
<% if feature?(:budgets) %>
<li <%= "class=is-active" if controller_name == "investments" %>>
<%= link_to moderation_budget_investments_path do %>
<span class="icon-budget"></span>
<%= t("moderation.menu.flagged_investments") %>
<% end %>
</li>
<% end %>
<li <%= "class=is-active" if controller_name == "comments" %>>
<%= link_to moderation_comments_path do %>
<span class="icon-comments"></span>

View File

@@ -0,0 +1,3 @@
var investment_id = '<%= dom_id(@investment) %>'
App.ModeratorBudgetInvestments.add_class_faded(investment_id)
App.ModeratorBudgetInvestments.hide_moderator_actions(investment_id)

View File

@@ -0,0 +1,73 @@
<h2><%= t("moderation.budget_investments.index.title") %></h2>
<%= render "shared/filter_subnav", i18n_namespace: "moderation.budget_investments.index" %>
<h3 class="inline-block"><%= page_entries_info @budget_investments %></h3>
<div class="float-right">
<%= t("moderation.budget_investments.index.order") %>
<%= render "shared/order_selector", i18n_namespace: "moderation.budget_investments.index" %>
</div>
<%= form_tag moderate_moderation_budget_investments_path(request.query_parameters), method: :put do %>
<p class="float-left js-check">
<%= t("shared.check") %>:
<%= link_to t("shared.check_all"), "#", data: { check_all: "budget_investment_ids[]" } %>
|
<%= link_to t("shared.check_none"), "#", data: { check_none: "budget_investment_ids[]" } %>
</p>
<table class="clear">
<thead>
<tr>
<th><%= t("moderation.budget_investments.index.headers.budget_investment") %></th>
<th><%= t("moderation.budget_investments.index.headers.moderate") %></th>
</tr>
</thead>
<tbody>
<% @budget_investments.each do |investment| %>
<tr id="investment_<%= investment.id %>">
<td>
<%= link_to investment.title, admin_budget_budget_investment_path(
budget_id: investment.budget_id,
id: investment.id
), target: "_blank" %>
<br>
<span class="date"><%= l investment.updated_at.to_date %></span>
<span class="bullet">&nbsp;&bull;&nbsp;</span>
<%= investment.flags_count %><span class="icon-flag flag-disable"></span>
<span class="bullet">&nbsp;&bull;&nbsp;</span>
<%= investment.author.username %>
<br>
<div class="moderation-description">
<%= investment.description %>
</div>
</td>
<td class="text-center">
<%= check_box_tag "budget_investment_ids[]", investment.id, nil, id: "#{dom_id(investment)}_check" %>
</td>
</tr>
<% end %>
</tbody>
</table>
<%= submit_tag t("moderation.budget_investments.index.block_authors"),
name: "block_authors",
class: "button hollow alert",
data: { confirm: t("moderation.budget_investments.index.confirm") } %>
<div class="float-right">
<%= submit_tag t("moderation.budget_investments.index.hide_budget_investments"),
name: "hide_budget_investments",
class: "button hollow alert",
data: { confirm: t("moderation.budget_investments.index.confirm") } %>
<%= submit_tag t("moderation.budget_investments.index.ignore_flags"),
name: "ignore_flags",
class: "button hollow",
data: { confirm: t("moderation.budget_investments.index.confirm") } %>
</div>
<%= paginate @budget_investments %>
<% end %>

View File

@@ -135,6 +135,7 @@ ignore_unused:
- 'admin.spending_proposals.index.filter*'
- 'admin.organizations.index.filter*'
- 'admin.hidden_users.index.filter*'
- 'admin.hidden_budget_investments.index.filter*'
- 'admin.activity.show.filter*'
- 'admin.legislation.processes.index.filter*'
- 'admin.legislation.processes.*.submit_button'
@@ -152,6 +153,8 @@ ignore_unused:
- 'moderation.proposals.index.order*'
- 'moderation.debates.index.filter*'
- 'moderation.debates.index.order*'
- 'moderation.budget_investments.index.filter*'
- 'moderation.budget_investments.index.order*'
- 'moderation.proposal_notifications.index.filter*'
- 'moderation.proposal_notifications.index.order*'
- 'valuation.spending_proposals.index.filter*'

View File

@@ -345,6 +345,15 @@ en:
hidden_at: 'Hidden at:'
registered_at: 'Registered at:'
title: Activity of user (%{user})
hidden_budget_investments:
index:
filter: Filter
filters:
all: All
with_confirmed_hide: Confirmed
without_confirmed_hide: Pending
title: Hidden budgets investments
no_hidden_budget_investments: There are no hidden budget investments
legislation:
processes:
create:
@@ -514,6 +523,7 @@ en:
hidden_comments: Hidden comments
hidden_debates: Hidden debates
hidden_proposals: Hidden proposals
hidden_budget_investments: Hidden budget investments
hidden_proposal_notifications: Hidden proposal notifications
hidden_users: Hidden users
administrators: Administrators

View File

@@ -46,6 +46,7 @@ en:
menu:
flagged_comments: Comments
flagged_debates: Debates
flagged_investments: Budget investments
proposals: Proposals
proposal_notifications: Proposals notifications
users: Block users
@@ -68,6 +69,25 @@ en:
created_at: Most recent
flags: Most flagged
title: Proposals
budget_investments:
index:
block_authors: Block authors
confirm: Are you sure?
filter: Filter
filters:
all: All
pending_flag_review: Pending
with_ignored_flag: Marked as viewed
headers:
moderate: Moderate
budget_investment: Budget investment
hide_budget_investments: Hide budget investments
ignore_flags: Mark as viewed
order: Order by
orders:
created_at: Most recent
flags: Most flagged
title: Budget investments
proposal_notifications:
index:
block_authors: Block authors

View File

@@ -346,6 +346,15 @@ es:
hidden_at: 'Bloqueado:'
registered_at: 'Fecha de alta:'
title: Actividad del usuario (%{user})
hidden_budget_investments:
index:
filter: Filtro
filters:
all: Todos
with_confirmed_hide: Confirmados
without_confirmed_hide: Pendientes
title: Proyectos de gasto ocultos
no_hidden_budget_investments: No hay proyectos de gasto ocultos
legislation:
processes:
create:
@@ -515,6 +524,7 @@ es:
hidden_comments: Comentarios ocultos
hidden_debates: Debates ocultos
hidden_proposals: Propuestas ocultas
hidden_budget_investments: Proyectos de gasto ocultos
hidden_proposal_notifications: Notificationes de propuesta ocultas
hidden_users: Usuarios bloqueados
administrators: Administradores

View File

@@ -46,6 +46,7 @@ es:
menu:
flagged_comments: Comentarios
flagged_debates: Debates
flagged_investments: Proyectos de gasto
proposals: Propuestas
proposal_notifications: Notificaciones de propuestas
users: Bloquear usuarios
@@ -68,6 +69,25 @@ es:
created_at: Más recientes
flags: Más denunciadas
title: Propuestas
budget_investments:
index:
block_authors: Bloquear autores
confirm: '¿Estás seguro?'
filter: Filtro
filters:
all: Todos
pending_flag_review: Pendientes de revisión
with_ignored_flag: Marcadas como revisadas
headers:
moderate: Moderar
budget_investment: Proyecto de gasto
hide_budget_investments: Ocultar proyectos de gasto
ignore_flags: Marcar como revisadas
order: Ordenar por
orders:
created_at: Más recientes
flags: Más denunciadas
title: Proyectos de gasto
proposal_notifications:
index:
block_authors: Bloquear autores

View File

@@ -15,6 +15,13 @@ namespace :admin do
end
end
resources :hidden_budget_investments, only: :index do
member do
put :restore
put :confirm_hide
end
end
resources :debates, only: :index do
member do
put :restore
@@ -78,6 +85,7 @@ namespace :admin do
end
resources :tags, only: [:index, :create, :update, :destroy]
resources :officials, only: [:index, :edit, :update, :destroy] do
get :search, on: :collection
end
@@ -93,6 +101,7 @@ namespace :admin do
get :search, on: :collection
get :summary, on: :collection
end
resources :valuator_groups
resources :managers, only: [:index, :create, :destroy] do

View File

@@ -1,7 +1,12 @@
resources :budgets, only: [:show, :index] do
resources :groups, controller: "budgets/groups", only: [:show]
resources :investments, controller: "budgets/investments", only: [:index, :new, :create, :show, :destroy] do
member { post :vote }
member do
post :vote
put :flag
put :unflag
end
collection { get :suggest }
end

View File

@@ -27,4 +27,9 @@ namespace :moderation do
put :hide, on: :member
put :moderate, on: :collection
end
resources :budget_investments, only: :index, controller: 'budgets/investments' do
put :hide, on: :member
put :moderate, on: :collection
end
end

View File

@@ -0,0 +1,9 @@
class AddModerationAttrsToInvestments < ActiveRecord::Migration
def change
change_table :budget_investments do |t|
t.datetime :confirmed_hide_at
t.datetime :ignored_flag_at
t.integer :flags_count, default: 0
end
end
end

View File

@@ -207,6 +207,9 @@ ActiveRecord::Schema.define(version: 20180711224810) do
t.integer "community_id"
t.boolean "visible_to_valuators", default: false
t.integer "valuator_group_assignments_count", default: 0
t.datetime "confirmed_hide_at"
t.datetime "ignored_flag_at"
t.integer "flags_count", default: 0
end
add_index "budget_investments", ["administrator_id"], name: "index_budget_investments_on_administrator_id", using: :btree

View File

@@ -362,6 +362,24 @@ FactoryBot.define do
feasibility "feasible"
valuation_finished true
end
trait :hidden do
hidden_at Time.current
end
trait :with_ignored_flag do
ignored_flag_at Time.current
end
trait :flagged do
after :create do |investment|
Flag.flag(create(:user), investment)
end
end
trait :with_confirmed_hide do
confirmed_hide_at Time.current
end
end
factory :budget_phase, class: 'Budget::Phase' do

View File

@@ -0,0 +1,108 @@
require 'rails_helper'
feature 'Admin hidden budget investments' do
let(:budget) { create(:budget) }
let(:group) { create(:budget_group, name: 'Music', budget: budget) }
let(:heading) { create(:budget_heading, name: 'Black metal', price: 666666, group: group) }
background do
admin = create(:administrator)
login_as(admin.user)
end
scenario 'Disabled with a feature flag' do
Setting['feature.budgets'] = nil
expect{ visit admin_hidden_budget_investments_path }.to raise_exception(FeatureFlags::FeatureDisabled)
Setting['feature.budgets'] = true
end
scenario 'List shows all relevant info' do
investment = create(:budget_investment, :hidden, heading: heading)
visit admin_hidden_budget_investments_path
expect(page).to have_content(investment.title)
expect(page).to have_content(investment.description)
end
scenario 'Restore' do
investment = create(:budget_investment, :hidden, heading: heading)
visit admin_hidden_budget_investments_path
click_link 'Restore'
expect(page).not_to have_content(investment.title)
investment.reload
expect(investment).to be_ignored_flag
end
scenario 'Confirm hide' do
investment = create(:budget_investment, :hidden, heading: heading)
visit admin_hidden_budget_investments_path
click_link('Pending')
expect(page).to have_content(investment.title)
click_link 'Confirm moderation'
expect(page).not_to have_content(investment.title)
click_link('Confirmed')
expect(page).to have_content(investment.title)
expect(investment.reload).to be_confirmed_hide
end
scenario "Current filter is properly highlighted" do
visit admin_hidden_budget_investments_path
expect(page).not_to have_link('All')
expect(page).to have_link('Pending')
expect(page).to have_link('Confirmed')
visit admin_hidden_budget_investments_path(filter: 'without_confirmed_hide')
expect(page).to have_link('All')
expect(page).to have_link('Confirmed')
expect(page).not_to have_link('Pending')
visit admin_hidden_budget_investments_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 investments' do
create(:budget_investment, :hidden, heading: heading, title: 'Unconfirmed investment')
create(:budget_investment, :hidden, :with_confirmed_hide, heading: heading, title: 'Confirmed investment')
visit admin_hidden_budget_investments_path(filter: 'without_confirmed_hide')
expect(page).to have_content('Unconfirmed investment')
expect(page).not_to have_content('Confirmed investment')
visit admin_hidden_budget_investments_path(filter: 'all')
expect(page).to have_content('Unconfirmed investment')
expect(page).to have_content('Confirmed investment')
visit admin_hidden_budget_investments_path(filter: 'with_confirmed_hide')
expect(page).not_to have_content('Unconfirmed investment')
expect(page).to have_content('Confirmed investment')
end
scenario "Action links remember the pagination setting and the filter" do
per_page = Kaminari.config.default_per_page
(per_page + 2).times { create(:budget_investment, :hidden, :with_confirmed_hide, heading: heading) }
visit admin_hidden_budget_investments_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

@@ -1617,4 +1617,69 @@ feature 'Budget Investments' do
end
end
scenario 'Flagging an investment as innapropriate', :js do
user = create(:user)
investment = create(:budget_investment, heading: heading)
login_as(user)
visit budget_investment_path(budget, investment)
within "#budget_investment_#{investment.id}" do
find("#flag-expand-investment-#{investment.id}").click
find("#flag-investment-#{investment.id}").click
expect(page).to have_css("#unflag-expand-investment-#{investment.id}")
end
expect(Flag.flagged?(user, investment)).to be
end
scenario 'Unflagging an investment', :js do
user = create(:user)
investment = create(:budget_investment, heading: heading)
Flag.flag(user, investment)
login_as(user)
visit budget_investment_path(budget, investment)
within "#budget_investment_#{investment.id}" do
find("#unflag-expand-investment-#{investment.id}").click
find("#unflag-investment-#{investment.id}").click
expect(page).to have_css("#flag-expand-investment-#{investment.id}")
end
expect(Flag.flagged?(user, investment)).not_to be
end
scenario 'Flagging an investment updates the DOM properly', :js do
user = create(:user)
investment = create(:budget_investment, heading: heading)
login_as(user)
visit budget_investment_path(budget, investment)
within "#budget_investment_#{investment.id}" do
find("#flag-expand-investment-#{investment.id}").click
find("#flag-investment-#{investment.id}").click
expect(page).to have_css("#unflag-expand-investment-#{investment.id}")
end
expect(Flag.flagged?(user, investment)).to be
within "#budget_investment_#{investment.id}" do
find("#unflag-expand-investment-#{investment.id}").click
find("#unflag-investment-#{investment.id}").click
expect(page).to have_css("#flag-expand-investment-#{investment.id}")
end
expect(Flag.flagged?(user, investment)).not_to be
end
end

View File

@@ -0,0 +1,246 @@
require 'rails_helper'
feature 'Moderate budget investments' do
let(:budget) { create(:budget) }
let(:group) { create(:budget_group, name: 'Culture', budget: budget) }
let(:heading) { create(:budget_heading, name: 'More libraries', price: 666666, group: group) }
background do
@mod = create(:moderator)
@investment = create(:budget_investment, heading: heading, author: create(:user))
end
scenario 'Disabled with a feature flag' do
Setting['feature.budgets'] = nil
login_as(@mod.user)
expect{ visit moderation_budget_investments_path }.to raise_exception(FeatureFlags::FeatureDisabled)
Setting['feature.budgets'] = true
end
scenario 'Hiding an investment', :js do
login_as(@mod.user)
visit budget_investment_path(budget, @investment)
accept_confirm { click_link 'Hide' }
expect(page).to have_css('.faded', count: 2)
visit budget_investments_path(budget.id, heading_id: heading.id)
expect(page).not_to have_content(@investment.title)
end
scenario "Hiding an investment's author", :js do
login_as(@mod.user)
visit budget_investment_path(budget, @investment)
accept_confirm { click_link 'Hide author' }
expect(page).to have_current_path(debates_path)
visit budget_investments_path(budget.id, heading_id: heading.id)
expect(page).not_to have_content(@investment.title)
end
scenario 'Can not hide own investment' do
@investment.update(author: @mod.user)
login_as(@mod.user)
visit budget_investment_path(budget, @investment)
within "#budget_investment_#{@investment.id}" do
expect(page).not_to have_link('Hide')
expect(page).not_to have_link('Hide author')
end
end
feature '/moderation/ screen' do
background do
login_as(@mod.user)
end
feature 'moderate in bulk' do
feature 'When an investment has been selected for moderation' do
background do
visit moderation_budget_investments_path
within('.menu.simple') do
click_link 'All'
end
within("#investment_#{@investment.id}") do
check "budget_investment_#{@investment.id}_check"
end
expect(page).not_to have_css("investment#{@investment.id}")
end
scenario 'Hide the investment' do
click_button 'Hide budget investments'
expect(page).not_to have_css("investment_#{@investment.id}")
@investment.reload
expect(@investment.author).not_to be_hidden
end
scenario 'Block the author' do
click_button 'Block authors'
expect(page).not_to have_css("investment_#{@investment.id}")
@investment.reload
expect(@investment.author).to be_hidden
end
scenario 'Ignore the investment' do
click_button 'Mark as viewed'
expect(page).not_to have_css("investment_#{@investment.id}")
@investment.reload
expect(@investment).to be_ignored_flag
expect(@investment).not_to be_hidden
expect(@investment.author).not_to be_hidden
end
end
scenario 'select all/none', :js do
create_list(:budget_investment, 2, heading: heading, author: create(:user))
visit moderation_budget_investments_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(:budget_investment, 52, heading: heading, author: create(:user))
visit moderation_budget_investments_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_budget_investments_path
expect(page).not_to have_link('Pending')
expect(page).to have_link('All')
expect(page).to have_link('Marked as viewed')
visit moderation_budget_investments_path(filter: 'all')
within('.menu.simple') do
expect(page).not_to have_link('All')
expect(page).to have_link('Pending')
expect(page).to have_link('Marked as viewed')
end
visit moderation_budget_investments_path(filter: 'pending_flag_review')
within('.menu.simple') do
expect(page).to have_link('All')
expect(page).not_to have_link('Pending')
expect(page).to have_link('Marked as viewed')
end
visit moderation_budget_investments_path(filter: 'with_ignored_flag')
within('.menu.simple') do
expect(page).to have_link('All')
expect(page).to have_link('Pending')
expect(page).not_to have_link('Marked as viewed')
end
end
scenario 'Filtering investments' do
create(:budget_investment, heading: heading, title: 'Books investment')
create(:budget_investment, :flagged, heading: heading, title: 'Non-selected investment')
create(:budget_investment, :hidden, heading: heading, title: 'Hidden investment')
create(:budget_investment, :flagged, :with_ignored_flag, heading: heading, title: 'Ignored investment')
visit moderation_budget_investments_path(filter: 'all')
expect(page).to have_content('Books investment')
expect(page).to have_content('Non-selected investment')
expect(page).not_to have_content('Hidden investment')
expect(page).to have_content('Ignored investment')
visit moderation_budget_investments_path(filter: 'pending_flag_review')
expect(page).not_to have_content('Books investment')
expect(page).to have_content('Non-selected investment')
expect(page).not_to have_content('Hidden investment')
expect(page).not_to have_content('Ignored investment')
visit moderation_budget_investments_path(filter: 'with_ignored_flag')
expect(page).not_to have_content('Books investment')
expect(page).not_to have_content('Non-selected investment')
expect(page).not_to have_content('Hidden investment')
expect(page).to have_content('Ignored investment')
end
scenario 'sorting investments' do
flagged_investment = create(:budget_investment,
heading: heading,
title: 'Flagged investment',
created_at: Time.current - 1.day,
flags_count: 5
)
flagged_new_investment = create(:budget_investment,
heading: heading,
title: 'Flagged new investment',
created_at: Time.current - 12.hours,
flags_count: 3
)
latest_investment = create(:budget_investment,
heading: heading,
title: 'Latest investment',
created_at: Time.current
)
visit moderation_budget_investments_path(order: 'created_at')
expect(flagged_new_investment.title).to appear_before(flagged_investment.title)
visit moderation_budget_investments_path(order: 'flags')
expect(flagged_investment.title).to appear_before(flagged_new_investment.title)
visit moderation_budget_investments_path(filter: 'all', order: 'created_at')
expect(latest_investment.title).to appear_before(flagged_new_investment.title)
expect(flagged_new_investment.title).to appear_before(flagged_investment.title)
visit moderation_budget_investments_path(filter: 'all', order: 'flags')
expect(flagged_investment.title).to appear_before(flagged_new_investment.title)
expect(flagged_new_investment.title).to appear_before(latest_investment.title)
end
end
end