Merge pull request #936 from consul/admin-valuations
Adds filters for [admin] spending_proposals
This commit is contained in:
@@ -2,10 +2,12 @@ class Admin::SpendingProposalsController < Admin::BaseController
|
|||||||
include FeatureFlags
|
include FeatureFlags
|
||||||
feature_flag :spending_proposals
|
feature_flag :spending_proposals
|
||||||
|
|
||||||
|
has_filters %w{all without_admin without_valuators}, only: :index
|
||||||
|
|
||||||
load_and_authorize_resource
|
load_and_authorize_resource
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@spending_proposals = @spending_proposals.includes(:geozone, administrator: :user, valuators: :user).order(created_at: :desc).page(params[:page])
|
@spending_proposals = geozone_filter(params[:geozone_id].presence).includes(:geozone, administrator: :user, valuators: :user).send(@current_filter).order(created_at: :desc).page(params[:page])
|
||||||
end
|
end
|
||||||
|
|
||||||
def show
|
def show
|
||||||
@@ -24,4 +26,17 @@ class Admin::SpendingProposalsController < Admin::BaseController
|
|||||||
@spending_proposal.update(params.require(:spending_proposal).permit(valuator_ids: []))
|
@spending_proposal.update(params.require(:spending_proposal).permit(valuator_ids: []))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def geozone_filter(geozone)
|
||||||
|
case geozone
|
||||||
|
when nil
|
||||||
|
@spending_proposals
|
||||||
|
when 'all'
|
||||||
|
@spending_proposals.where(geozone_id: nil)
|
||||||
|
else
|
||||||
|
@spending_proposals.where(geozone_id: params[:geozone_id].presence)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ class Proposal < ActiveRecord::Base
|
|||||||
scope :sort_by_created_at, -> { reorder(created_at: :desc) }
|
scope :sort_by_created_at, -> { reorder(created_at: :desc) }
|
||||||
scope :sort_by_most_commented, -> { reorder(comments_count: :desc) }
|
scope :sort_by_most_commented, -> { reorder(comments_count: :desc) }
|
||||||
scope :sort_by_random, -> { reorder("RANDOM()") }
|
scope :sort_by_random, -> { reorder("RANDOM()") }
|
||||||
scope :sort_by_relevance , -> { all }
|
scope :sort_by_relevance, -> { all }
|
||||||
scope :sort_by_flags, -> { order(flags_count: :desc, updated_at: :desc) }
|
scope :sort_by_flags, -> { order(flags_count: :desc, updated_at: :desc) }
|
||||||
scope :last_week, -> { where("proposals.created_at >= ?", 7.days.ago)}
|
scope :last_week, -> { where("proposals.created_at >= ?", 7.days.ago)}
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,9 @@ class SpendingProposal < ActiveRecord::Base
|
|||||||
validates :description, length: { maximum: SpendingProposal.description_max_length }
|
validates :description, length: { maximum: SpendingProposal.description_max_length }
|
||||||
validates :terms_of_service, acceptance: { allow_nil: false }, on: :create
|
validates :terms_of_service, acceptance: { allow_nil: false }, on: :create
|
||||||
|
|
||||||
|
scope :without_admin, -> { where(administrator_id: nil) }
|
||||||
|
scope :without_valuators, -> { where(valuation_assignments_count: 0) }
|
||||||
|
|
||||||
def description
|
def description
|
||||||
super.try :html_safe
|
super.try :html_safe
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
class ValuationAssignment < ActiveRecord::Base
|
class ValuationAssignment < ActiveRecord::Base
|
||||||
belongs_to :valuator
|
belongs_to :valuator
|
||||||
belongs_to :spending_proposal
|
belongs_to :spending_proposal, counter_cache: true
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,16 @@
|
|||||||
<h2><%= t("admin.spending_proposals.index.title") %></h2>
|
<h2><%= t("admin.spending_proposals.index.title") %></h2>
|
||||||
|
|
||||||
|
<div class="small-12 medium-4 column right">
|
||||||
|
<%= form_tag admin_spending_proposals_path, method: :get, enforce_utf8: false do %>
|
||||||
|
<%= select_tag :geozone_id, options_for_select(geozone_select_options.unshift([t("geozones.none"), "all"]), params[:geozone_id]),
|
||||||
|
{ prompt: t("admin.spending_proposals.index.geozone_filter_all"),
|
||||||
|
label: false,
|
||||||
|
class: "js-submit-on-change"} %>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<%= render 'shared/filter_subnav', i18n_namespace: "admin.spending_proposals.index" %>
|
||||||
|
|
||||||
<h3><%= page_entries_info @spending_proposals %></h3>
|
<h3><%= page_entries_info @spending_proposals %></h3>
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
@@ -25,7 +36,7 @@
|
|||||||
<%= spending_proposal.valuators.first.name %>
|
<%= spending_proposal.valuators.first.name %>
|
||||||
</span>
|
</span>
|
||||||
<% else %>
|
<% else %>
|
||||||
<span title="<%= spending_proposal.valuators.map(&:name) * ', ' %>">
|
<span title="<%= spending_proposal.valuators.map(&:name).join(', ') %>">
|
||||||
<%= t('admin.spending_proposals.index.valuators_assigned', count: spending_proposal.valuators.size) %>
|
<%= t('admin.spending_proposals.index.valuators_assigned', count: spending_proposal.valuators.size) %>
|
||||||
</span>
|
</span>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@@ -138,11 +138,11 @@ en:
|
|||||||
placeholder: Search user by name or email'
|
placeholder: Search user by name or email'
|
||||||
spending_proposals:
|
spending_proposals:
|
||||||
index:
|
index:
|
||||||
filter: Filter
|
geozone_filter_all: All zones
|
||||||
filters:
|
filters:
|
||||||
accepted: Accepted
|
all: All
|
||||||
rejected: Rejected
|
without_admin: Without assigned admin
|
||||||
unresolved: Unresolved
|
without_valuators: Without valuator
|
||||||
title: Investment projects for participatory budgeting
|
title: Investment projects for participatory budgeting
|
||||||
admin_assigned: Assigned administrator
|
admin_assigned: Assigned administrator
|
||||||
no_admin_assigned: No admin assigned
|
no_admin_assigned: No admin assigned
|
||||||
|
|||||||
@@ -138,11 +138,11 @@ es:
|
|||||||
placeholder: Buscar usuario por nombre o email
|
placeholder: Buscar usuario por nombre o email
|
||||||
spending_proposals:
|
spending_proposals:
|
||||||
index:
|
index:
|
||||||
filter: Filtro
|
geozone_filter_all: Todos los ámbitos de actuación
|
||||||
filters:
|
filters:
|
||||||
accepted: Aceptadas
|
all: Todas
|
||||||
rejected: Rechazadas
|
without_admin: Sin administrador asignado
|
||||||
unresolved: Sin resolver
|
without_valuators: Sin evaluador
|
||||||
title: Propuestas de inversión para presupuestos participativos
|
title: Propuestas de inversión para presupuestos participativos
|
||||||
admin_assigned: Administrador asignado
|
admin_assigned: Administrador asignado
|
||||||
no_admin_assigned: Sin admin asignado
|
no_admin_assigned: Sin admin asignado
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
class AddAssignmentsCounterCacheToSpendingProposal < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
add_column :spending_proposals, :valuation_assignments_count, :integer, default: 0
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -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: 20160224123110) do
|
ActiveRecord::Schema.define(version: 20160225171916) 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"
|
||||||
@@ -296,8 +296,8 @@ ActiveRecord::Schema.define(version: 20160224123110) do
|
|||||||
t.text "description"
|
t.text "description"
|
||||||
t.integer "author_id"
|
t.integer "author_id"
|
||||||
t.string "external_url"
|
t.string "external_url"
|
||||||
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.integer "geozone_id"
|
t.integer "geozone_id"
|
||||||
t.float "price"
|
t.float "price"
|
||||||
t.boolean "feasible"
|
t.boolean "feasible"
|
||||||
@@ -305,9 +305,10 @@ ActiveRecord::Schema.define(version: 20160224123110) do
|
|||||||
t.text "price_explanation"
|
t.text "price_explanation"
|
||||||
t.text "feasible_explanation"
|
t.text "feasible_explanation"
|
||||||
t.text "internal_comments"
|
t.text "internal_comments"
|
||||||
t.boolean "valuation_finished", default: false
|
t.boolean "valuation_finished", default: false
|
||||||
t.text "explanations_log"
|
t.text "explanations_log"
|
||||||
t.integer "administrator_id"
|
t.integer "administrator_id"
|
||||||
|
t.integer "valuation_assignments_count", default: 0
|
||||||
end
|
end
|
||||||
|
|
||||||
add_index "spending_proposals", ["author_id"], name: "index_spending_proposals_on_author_id", using: :btree
|
add_index "spending_proposals", ["author_id"], name: "index_spending_proposals_on_author_id", using: :btree
|
||||||
|
|||||||
@@ -50,6 +50,74 @@ feature 'Admin spending proposals' do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
scenario "Index filtering by geozone", :js do
|
||||||
|
geozone = create(:geozone, name: "District 9")
|
||||||
|
create(:spending_proposal, title: "Realocate visitors", geozone: geozone)
|
||||||
|
create(:spending_proposal, title: "Destroy the city")
|
||||||
|
|
||||||
|
visit admin_spending_proposals_path
|
||||||
|
expect(page).to have_link("Realocate visitors")
|
||||||
|
expect(page).to have_link("Destroy the city")
|
||||||
|
|
||||||
|
select "District 9", from: "geozone_id"
|
||||||
|
|
||||||
|
expect(page).to have_link("Realocate visitors")
|
||||||
|
expect(page).to_not have_link("Destroy the city")
|
||||||
|
|
||||||
|
select "All city", from: "geozone_id"
|
||||||
|
|
||||||
|
expect(page).to have_link("Destroy the city")
|
||||||
|
expect(page).to_not have_link("Realocate visitors")
|
||||||
|
|
||||||
|
select "All zones", from: "geozone_id"
|
||||||
|
expect(page).to have_link("Realocate visitors")
|
||||||
|
expect(page).to have_link("Destroy the city")
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario "Current filter is properly highlighted" do
|
||||||
|
visit admin_spending_proposals_path
|
||||||
|
|
||||||
|
expect(page).to_not have_link('All')
|
||||||
|
expect(page).to have_link('Without assigned admin')
|
||||||
|
expect(page).to have_link('Without valuator')
|
||||||
|
|
||||||
|
visit admin_spending_proposals_path(filter: 'without_admin')
|
||||||
|
expect(page).to_not have_link('Without assigned admin')
|
||||||
|
expect(page).to have_link('All')
|
||||||
|
expect(page).to have_link('Without valuator')
|
||||||
|
|
||||||
|
visit admin_spending_proposals_path(filter: 'without_valuators')
|
||||||
|
expect(page).to_not have_link('Without valuator')
|
||||||
|
expect(page).to have_link('Without assigned admin')
|
||||||
|
expect(page).to have_link('All')
|
||||||
|
|
||||||
|
visit admin_spending_proposals_path(filter: 'all')
|
||||||
|
expect(page).to_not have_link('All')
|
||||||
|
expect(page).to have_link('Without assigned admin')
|
||||||
|
expect(page).to have_link('Without valuator')
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario "Filtering proposals" do
|
||||||
|
assigned = create(:spending_proposal, title: "Assigned idea", administrator: create(:administrator))
|
||||||
|
valuating = create(:spending_proposal, title: "Evaluating...")
|
||||||
|
valuating.valuators << create(:valuator)
|
||||||
|
|
||||||
|
visit admin_spending_proposals_path(filter: 'all')
|
||||||
|
|
||||||
|
expect(page).to have_content("Assigned idea")
|
||||||
|
expect(page).to have_content("Evaluating...")
|
||||||
|
|
||||||
|
visit admin_spending_proposals_path(filter: 'without_admin')
|
||||||
|
|
||||||
|
expect(page).to have_content("Evaluating...")
|
||||||
|
expect(page).to_not have_content("Assigned idea")
|
||||||
|
|
||||||
|
visit admin_spending_proposals_path(filter: 'without_valuators')
|
||||||
|
|
||||||
|
expect(page).to have_content("Assigned idea")
|
||||||
|
expect(page).to_not have_content("Evaluating...")
|
||||||
|
end
|
||||||
|
|
||||||
scenario 'Show' do
|
scenario 'Show' do
|
||||||
administrator = create(:administrator, user: create(:user, username: 'Ana', email: 'ana@admins.org'))
|
administrator = create(:administrator, user: create(:user, username: 'Ana', email: 'ana@admins.org'))
|
||||||
valuator = create(:valuator, user: create(:user, username: 'Rachel', email: 'rachel@valuators.org'))
|
valuator = create(:valuator, user: create(:user, username: 'Rachel', email: 'rachel@valuators.org'))
|
||||||
@@ -90,9 +158,9 @@ feature 'Admin spending proposals' do
|
|||||||
|
|
||||||
expect(page).to have_select('spending_proposal[administrator_id]', selected: 'Undefined')
|
expect(page).to have_select('spending_proposal[administrator_id]', selected: 'Undefined')
|
||||||
select 'Ana (ana@admins.org)', from: 'spending_proposal[administrator_id]'
|
select 'Ana (ana@admins.org)', from: 'spending_proposal[administrator_id]'
|
||||||
expect(page).to have_select('spending_proposal[administrator_id]', selected: 'Ana (ana@admins.org)')
|
|
||||||
|
|
||||||
visit admin_spending_proposal_path(spending_proposal)
|
visit admin_spending_proposals_path
|
||||||
|
click_link spending_proposal.title
|
||||||
|
|
||||||
expect(page).to have_select('spending_proposal[administrator_id]', selected: 'Ana (ana@admins.org)')
|
expect(page).to have_select('spending_proposal[administrator_id]', selected: 'Ana (ana@admins.org)')
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -61,4 +61,32 @@ describe SpendingProposal do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
describe "scopes" do
|
||||||
|
describe "without_admin" do
|
||||||
|
it "should return all spending proposals without assigned admin" do
|
||||||
|
spending_proposal1 = create(:spending_proposal)
|
||||||
|
spending_proposal2 = create(:spending_proposal, administrator: create(:administrator))
|
||||||
|
|
||||||
|
without_admin = SpendingProposal.without_admin
|
||||||
|
|
||||||
|
expect(without_admin.size).to eq(1)
|
||||||
|
expect(without_admin.first).to eq(spending_proposal1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "without_valuators" do
|
||||||
|
it "should return all spending proposals without assigned valuators" do
|
||||||
|
spending_proposal1 = create(:spending_proposal)
|
||||||
|
spending_proposal2 = create(:spending_proposal)
|
||||||
|
spending_proposal1.valuators << create(:valuator)
|
||||||
|
|
||||||
|
without_admin = SpendingProposal.without_valuators
|
||||||
|
|
||||||
|
expect(without_admin.size).to eq(1)
|
||||||
|
expect(without_admin.first).to eq(spending_proposal2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user