Merge pull request #932 from consul/valuators

Valuators and dossier info in spending proposals for Admin
This commit is contained in:
Enrique García
2016-02-25 12:54:51 +01:00
22 changed files with 248 additions and 347 deletions

View File

@@ -40,6 +40,7 @@
//= require advanced_search
//= require registration_form
//= require suggest
//= require forms
var initialize_modules = function() {
App.Comments.initialize();
@@ -55,6 +56,7 @@ var initialize_modules = function() {
App.AdvancedSearch.initialize();
App.RegistrationForm.initialize();
App.Suggest.initialize();
App.Forms.initialize();
};
$(function(){

View File

@@ -0,0 +1,12 @@
App.Forms =
initialize: ->
$('.js-submit-on-change').unbind('change').on('change', ->
$(this).closest('form').submit()
false
)
$('.js-toggle-link').unbind('click').on('click', ->
$($(this).data('toggle-selector')).toggle("down")
false
)

View File

@@ -8,7 +8,6 @@ var initialize_stats_modules = function() {
};
$(function(){
$(document).ready(initialize_stats_modules);
$(document).on('page:load', initialize_stats_modules);
$(document).on('ajax:complete', initialize_stats_modules);

View File

@@ -1,27 +1,27 @@
class Admin::SpendingProposalsController < Admin::BaseController
include FeatureFlags
has_filters %w{unresolved accepted rejected}, only: :index
feature_flag :spending_proposals
load_and_authorize_resource
feature_flag :spending_proposals
def index
@spending_proposals = @spending_proposals.includes([:geozone]).send(@current_filter).order(created_at: :desc).page(params[:page])
@spending_proposals = @spending_proposals.includes([:geozone], [administrator: :user]).order(created_at: :desc).page(params[:page])
end
def show
@admins = Administrator.includes(:user).all
@valuators = Valuator.includes(:user).all.order("users.username ASC")
end
def accept
@spending_proposal.accept
redirect_to request.query_parameters.merge(action: :index)
def assign_admin
@spending_proposal.update(params.require(:spending_proposal).permit(:administrator_id))
render nothing: true
end
def reject
@spending_proposal.reject
redirect_to request.query_parameters.merge(action: :index)
def assign_valuators
params[:spending_proposal] ||= {}
params[:spending_proposal][:valuator_ids] ||= []
@spending_proposal.update(params.require(:spending_proposal).permit(valuator_ids: []))
end
end

View File

@@ -4,10 +4,11 @@ class SpendingProposal < ActiveRecord::Base
apply_simple_captcha
RESOLUTIONS = ["accepted", "rejected"]
belongs_to :author, -> { with_hidden }, class_name: 'User', foreign_key: 'author_id'
belongs_to :geozone
belongs_to :administrator
has_many :valuation_assignments, dependent: :destroy
has_many :valuators, through: :valuation_assignments
validates :title, presence: true
validates :author, presence: true
@@ -15,42 +16,10 @@ class SpendingProposal < ActiveRecord::Base
validates :title, length: { in: 4..SpendingProposal.title_max_length }
validates :description, length: { maximum: SpendingProposal.description_max_length }
validates :resolution, inclusion: { in: RESOLUTIONS, allow_nil: true }
validates :terms_of_service, acceptance: { allow_nil: false }, on: :create
scope :accepted, -> { where(resolution: "accepted") }
scope :rejected, -> { where(resolution: "rejected") }
scope :unresolved, -> { where(resolution: nil) }
def accept
update_attribute(:resolution, "accepted")
end
def reject
update_attribute(:resolution, "rejected")
end
def accepted?
resolution == "accepted"
end
def rejected?
resolution == "rejected"
end
def unresolved?
resolution.blank?
end
def legality
case legal
when true
"legal"
when false
"not_legal"
else
"undefined"
end
def description
super.try :html_safe
end
def feasibility
@@ -64,8 +33,4 @@ class SpendingProposal < ActiveRecord::Base
end
end
def description
super.try :html_safe
end
end

View File

@@ -0,0 +1,4 @@
class ValuationAssignment < ActiveRecord::Base
belongs_to :valuator
belongs_to :spending_proposal
end

View File

@@ -2,5 +2,8 @@ class Valuator < ActiveRecord::Base
belongs_to :user, touch: true
delegate :name, :email, to: :user
has_many :valuation_assignments, dependent: :destroy
has_many :spending_proposals, through: :valuation_assignments
validates :user_id, presence: true, uniqueness: true
end

View File

@@ -0,0 +1,9 @@
<ul>
<% @spending_proposal.valuators.each do |valuator| %>
<li><%= valuator.name %> (<%= valuator.email %>)</li>
<% end %>
<% if @spending_proposal.valuators.empty? %>
<li><%= t("admin.spending_proposals.show.undefined") %></li>
<% end %>
</ul>

View File

@@ -0,0 +1 @@
$('#assigned_valuators').html("<%= j(render 'assigned_valuators') %>")

View File

@@ -1,7 +1,5 @@
<h2><%= t("admin.spending_proposals.index.title") %></h2>
<%= render 'shared/filter_subnav', i18n_namespace: "admin.spending_proposals.index" %>
<h3><%= page_entries_info @spending_proposals %></h3>
<table>
@@ -14,22 +12,6 @@
<td>
<%= geozone_name(spending_proposal) %>
</td>
<td>
<% unless spending_proposal.accepted? %>
<%= link_to t("admin.spending_proposals.actions.accept"),
accept_admin_spending_proposal_path(spending_proposal, request.query_parameters),
method: :put,
data: { confirm: t("admin.actions.confirm") },
class: "button radius tiny success no-margin" %>
<% end %>
<% unless spending_proposal.rejected? %>
<%= link_to t("admin.spending_proposals.actions.reject"),
reject_admin_spending_proposal_path(spending_proposal, request.query_parameters),
method: :put,
data: { confirm: t("admin.actions.confirm") },
class: "button radius tiny warning right" %>
<% end %>
</td>
</tr>
<% end %>
</table>

View File

@@ -1,44 +1,78 @@
<h2><%= @spending_proposal.title %></h2>
<h2><%= t("admin.spending_proposals.show.heading") %> <%= @spending_proposal.id %></h2>
<h1><%= @spending_proposal.title %></h1>
<%= safe_html_with_links @spending_proposal.description.html_safe %>
<%= safe_html_with_links @spending_proposal.description %>
<% if @spending_proposal.external_url.present? %>
<p><%= text_with_links @spending_proposal.external_url %></p>
<% end %>
<p><%= t("admin.spending_proposals.show.by") %>:
<h2><%= t("admin.spending_proposals.show.info") %></h2>
<p><strong><%= t("admin.spending_proposals.show.by") %>:</strong>
<%= link_to @spending_proposal.author.name, admin_user_path(@spending_proposal.author) %>
</p>
<p><%= t("admin.spending_proposals.show.association_name") %>:
<%= @spending_proposal.association_name %>
</p>
<p><%= t("admin.spending_proposals.show.geozone") %>:
<% if @spending_proposal.association_name.present? %>
<p><strong><%= t("admin.spending_proposals.show.association_name") %>:</strong>
<%= @spending_proposal.association_name %>
</p>
<% end %>
<p><strong><%= t("admin.spending_proposals.show.geozone") %>:</strong>
<%= geozone_name(@spending_proposal) %>
</p>
<p><%= l @spending_proposal.created_at, format: :datetime %></p>
<p>
<% unless @spending_proposal.accepted? %>
<%= link_to t("admin.spending_proposals.actions.accept"),
accept_admin_spending_proposal_path(@spending_proposal),
method: :put,
data: { confirm: t("admin.actions.confirm") },
class: "button radius tiny success no-margin" %>
<% end %>
<% unless @spending_proposal.rejected? %>
<%= link_to t("admin.spending_proposals.actions.reject"),
reject_admin_spending_proposal_path(@spending_proposal),
method: :put,
data: { confirm: t("admin.actions.confirm") },
class: "button radius tiny warning" %>
<% end %>
<p><strong><%= t("admin.spending_proposals.show.sent") %>:</strong>
<%= l @spending_proposal.created_at, format: :datetime %>
</p>
<h2><%= t("admin.spending_proposals.show.responsibles") %></h2>
<h2><%= t("admin.spending_proposals.show.dossier") %>:</h2>
<p><strong><%= t("admin.spending_proposals.show.assigned_admin") %>:</strong>
<%= form_for(@spending_proposal, url: assign_admin_admin_spending_proposal_path(@spending_proposal), remote: true, html: {id: 'administrator_assignment_form'}) do |f| %>
<%= f.select :administrator_id, @admins.collect { |a| [ "#{a.name} (#{a.email})", a.id ] }, {include_blank: t("admin.spending_proposals.show.undefined"), label: false}, class: "js-submit-on-change" %>
<% end %>
</p>
<p><strong><%= t("admin.spending_proposals.show.price") %>:</strong> <%= @spending_proposal.price %></p>
<p><strong><%= t("admin.spending_proposals.show.legality") %>:</strong> <%= t("admin.spending_proposals.show.#{@spending_proposal.legality}") %></p>
<p><strong><%= t("admin.spending_proposals.show.feasibility") %>:</strong> <%= t("admin.spending_proposals.show.#{@spending_proposal.feasibility}") %></p>
<p><strong><%= t("admin.spending_proposals.show.assigned_valuators") %>:</strong></p>
<div id="assigned_valuators">
<%= render "assigned_valuators" %>
</div>
<%= safe_html_with_links(@spending_proposal.explanation.html_safe) if @spending_proposal.explanation %>
<h3><%= link_to t("admin.spending_proposals.show.assign_valuators"), "", class: "js-toggle-link", data: {"toggle-selector" => "#valuators-assign-list"} %></h3>
<div style="display:none" id="valuators-assign-list">
<%= form_for(@spending_proposal, url: assign_valuators_admin_spending_proposal_path(@spending_proposal), remote: true, html: {id: 'valuators_assignment_form'}) do |f| %>
<% @valuators.each do |valuator| -%>
<div>
<%= check_box_tag "valuator_ids_#{valuator.id}", valuator.id, @spending_proposal.valuators.include?(valuator),
name: 'spending_proposal[valuator_ids][]',
class: "js-submit-on-change" %>
<%= label_tag "valuator_ids_#{valuator.id}", valuator.name %>
</div>
<% end -%>
<% end -%>
</div>
<h2><%= t("admin.spending_proposals.show.dossier") %></h2>
<p><strong><%= t("admin.spending_proposals.show.price") %> (<%= t("admin.spending_proposals.show.currency") %>):</strong>
<%= @spending_proposal.price.present? ? @spending_proposal.price : t("admin.spending_proposals.show.undefined") %>
</p>
<%= simple_format(safe_html_with_links(@spending_proposal.price_explanation.html_safe), {}, sanitize: false) if @spending_proposal.price_explanation.present? %>
<p><strong><%= t("admin.spending_proposals.show.feasibility") %>:</strong>
<%= t("admin.spending_proposals.show.#{@spending_proposal.feasibility}") %>
</p>
<%= simple_format(safe_html_with_links(@spending_proposal.feasible_explanation.html_safe), {}, sanitize: false) if @spending_proposal.feasible_explanation.present? %>
<% if @spending_proposal.valuation_finished %>
<p><strong><%= t("admin.spending_proposals.show.valuation_finished") %></strong>
<% end %>
<% if @spending_proposal.internal_comments.present? %>
<h2><%= t("admin.spending_proposals.show.internal_comments") %></h2>
<%= simple_format(safe_html_with_links(@spending_proposal.internal_comments.html_safe), {}, sanitize: false) %>
<% end %>

View File

@@ -23,11 +23,6 @@
</div>
<% end %>
<% if @spending_proposal.resolution.present? %>
<div class="spending-proposal-resolution">
<%= @spending_proposal.resolution %>
</div>
<% end %>
</div>
</div>

View File

@@ -137,9 +137,6 @@ en:
button: Search
placeholder: Search user by name or email'
spending_proposals:
actions:
accept: Accept
reject: Reject
index:
filter: Filter
filters:
@@ -148,18 +145,26 @@ en:
unresolved: Unresolved
title: Spending proposals for participatory budgeting
show:
heading: Investment project
info: Author info
association_name: Asociación
by: Sent by
sent: Sent at
geozone: Scope
dossier: Dossier
price: Price
legality: Legality
legal: Legal
not_legal: Not legal
currency: "€"
feasibility: Feasibility
feasible: Feasible
not_feasible: Not feasible
undefined: Undefined
valuation_finished: Valuation finished
internal_comments: Internal comments
responsibles: Responsibles
assigned_admin: Assigned admin
assigned_valuators: Assigned valuators
assign_valuators: Assign valuators
assign: Assign
stats:
show:
stats_title: Stats

View File

@@ -57,7 +57,7 @@ es:
officials: Cargos públicos
organizations: Organizaciones
settings: Configuración global
spending_proposals: Propuestas de gasto
spending_proposals: Propuestas de inversión
stats: Estadísticas
moderators:
index:
@@ -137,9 +137,6 @@ es:
button: Buscar
placeholder: Buscar usuario por nombre o email
spending_proposals:
actions:
accept: Aceptar
reject: Rechazar
index:
filter: Filtro
filters:
@@ -148,18 +145,26 @@ es:
unresolved: Sin resolver
title: Propuestas de gasto para presupuestos participativos
show:
heading: Propuesta de inversión
info: Datos de envío
association_name: Asociación
by: Enviada por
sent: Fecha de creación
geozone: Ámbito
dossier: Informe
price: Coste
legality: Legalidad
legal: Legal
not_legal: No legal
currency: "€"
feasibility: Viabilidad
feasible: Viable
not_feasible: No viable
undefined: Sin definir
valuation_finished: Informe finalizado
internal_comments: Commentarios internos
responsibles: Responsables
assigned_admin: Administrador asignado
assigned_valuators: Evaluadores asignados
assign_valuators: Asignar evaluadores
assign: Asignar
stats:
show:
stats_title: Estadísticas

View File

@@ -131,10 +131,10 @@ Rails.application.routes.draw do
end
end
resources :spending_proposals, only: [:index, :show], path: 'investment_projects' do
resources :spending_proposals, only: [:index, :show] do
member do
put :accept
put :reject
patch :assign_admin
patch :assign_valuators
end
end

View File

@@ -41,6 +41,9 @@ admin.create_administrator
moderator = create_user('mod@madrid.es', 'mod')
moderator.create_moderator
valuator = create_user('valuator@madrid.es', 'valuator')
valuator.create_valuator
(1..10).each do |i|
org_name = Faker::Company.name
org_user = create_user("org#{i}@madrid.es", org_name)
@@ -247,8 +250,6 @@ end
puts "Creating Spending Proposals"
resolutions = ["accepted", "rejected", nil]
(1..30).each do |i|
geozone = Geozone.reorder("RANDOM()").first
author = User.reorder("RANDOM()").first
@@ -258,12 +259,17 @@ resolutions = ["accepted", "rejected", nil]
external_url: Faker::Internet.url,
description: description,
created_at: rand((Time.now - 1.week) .. Time.now),
resolution: resolutions.sample,
geozone: [geozone, nil].sample,
terms_of_service: "1")
puts " #{spending_proposal.title}"
end
puts "Creating Valuation Assignments"
(1..17).to_a.sample.times do
SpendingProposal.reorder("RANDOM()").first.valuators << valuator.valuator
end
puts "Creating Legislation"
Legislation.create!(title: 'Participatory Democracy', body: 'In order to achieve...')

View File

@@ -0,0 +1,16 @@
class ChangeSpendingProposalsFields < ActiveRecord::Migration
def change
remove_index :spending_proposals, column: :resolution
remove_column :spending_proposals, :legal, :boolean
remove_column :spending_proposals, :resolution, :string
remove_column :spending_proposals, :explanation, :text
add_column :spending_proposals, :price_explanation, :text
add_column :spending_proposals, :feasible_explanation, :text
add_column :spending_proposals, :internal_comments, :text
add_column :spending_proposals, :valuation_finished, :boolean, default: false
add_column :spending_proposals, :explanations_log, :text
add_column :spending_proposals, :administrator_id, :integer
end
end

View File

@@ -0,0 +1,9 @@
class CreateValuationAssignments < ActiveRecord::Migration
def change
create_table :valuation_assignments do |t|
t.belongs_to :valuator
t.belongs_to :spending_proposal
t.timestamps null: false
end
end
end

View File

@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20160222145100) do
ActiveRecord::Schema.define(version: 20160224123110) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -108,10 +108,10 @@ ActiveRecord::Schema.define(version: 20160222145100) do
t.string "visit_id"
t.datetime "hidden_at"
t.integer "flags_count", default: 0
t.datetime "ignored_flag_at"
t.integer "cached_votes_total", default: 0
t.integer "cached_votes_up", default: 0
t.integer "cached_votes_down", default: 0
t.datetime "ignored_flag_at"
t.integer "comments_count", default: 0
t.datetime "confirmed_hide_at"
t.integer "cached_anonymous_votes_total", default: 0
@@ -129,6 +129,7 @@ ActiveRecord::Schema.define(version: 20160222145100) do
add_index "debates", ["cached_votes_total"], name: "index_debates_on_cached_votes_total", using: :btree
add_index "debates", ["cached_votes_up"], name: "index_debates_on_cached_votes_up", using: :btree
add_index "debates", ["confidence_score"], name: "index_debates_on_confidence_score", using: :btree
add_index "debates", ["description"], name: "index_debates_on_description", using: :btree
add_index "debates", ["geozone_id"], name: "index_debates_on_geozone_id", using: :btree
add_index "debates", ["hidden_at"], name: "index_debates_on_hidden_at", using: :btree
add_index "debates", ["hot_score"], name: "index_debates_on_hot_score", using: :btree
@@ -205,7 +206,7 @@ ActiveRecord::Schema.define(version: 20160222145100) do
create_table "locks", force: :cascade do |t|
t.integer "user_id"
t.integer "tries", default: 0
t.datetime "locked_until", default: '2000-01-01 07:01:01', null: false
t.datetime "locked_until", default: '2000-01-01 00:01:01', null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
@@ -265,6 +266,7 @@ ActiveRecord::Schema.define(version: 20160222145100) do
add_index "proposals", ["author_id"], name: "index_proposals_on_author_id", using: :btree
add_index "proposals", ["cached_votes_up"], name: "index_proposals_on_cached_votes_up", using: :btree
add_index "proposals", ["confidence_score"], name: "index_proposals_on_confidence_score", using: :btree
add_index "proposals", ["description"], name: "index_proposals_on_description", using: :btree
add_index "proposals", ["geozone_id"], name: "index_proposals_on_geozone_id", using: :btree
add_index "proposals", ["hidden_at"], name: "index_proposals_on_hidden_at", using: :btree
add_index "proposals", ["hot_score"], name: "index_proposals_on_hot_score", using: :btree
@@ -294,20 +296,22 @@ ActiveRecord::Schema.define(version: 20160222145100) do
t.text "description"
t.integer "author_id"
t.string "external_url"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "geozone_id"
t.string "resolution"
t.float "price"
t.boolean "legal"
t.boolean "feasible"
t.text "explanation"
t.string "association_name"
t.text "price_explanation"
t.text "feasible_explanation"
t.text "internal_comments"
t.boolean "valuation_finished", default: false
t.text "explanations_log"
t.integer "administrator_id"
end
add_index "spending_proposals", ["author_id"], name: "index_spending_proposals_on_author_id", using: :btree
add_index "spending_proposals", ["geozone_id"], name: "index_spending_proposals_on_geozone_id", using: :btree
add_index "spending_proposals", ["resolution"], name: "index_spending_proposals_on_resolution", using: :btree
create_table "taggings", force: :cascade do |t|
t.integer "tag_id"
@@ -328,8 +332,8 @@ ActiveRecord::Schema.define(version: 20160222145100) do
t.boolean "featured", default: false
t.integer "debates_count", default: 0
t.integer "proposals_count", default: 0
t.string "kind"
t.integer "spending_proposals_count", default: 0
t.string "kind"
end
add_index "tags", ["debates_count"], name: "index_tags_on_debates_count", using: :btree
@@ -405,8 +409,8 @@ ActiveRecord::Schema.define(version: 20160222145100) do
t.boolean "public_activity", default: true
t.boolean "newsletter", default: false
t.integer "notifications_count", default: 0
t.string "locale"
t.boolean "registering_with_oauth", default: false
t.string "locale"
t.string "oauth_email"
t.integer "geozone_id"
t.string "redeemable_code"
@@ -418,6 +422,13 @@ ActiveRecord::Schema.define(version: 20160222145100) do
add_index "users", ["hidden_at"], name: "index_users_on_hidden_at", using: :btree
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree
create_table "valuation_assignments", force: :cascade do |t|
t.integer "valuator_id"
t.integer "spending_proposal_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "valuators", force: :cascade do |t|
t.integer "user_id"
end

View File

@@ -1,4 +1,5 @@
FactoryGirl.define do
sequence(:document_number) { |n| "#{n.to_s.rjust(8, '0')}X" }
factory :user do

View File

@@ -19,97 +19,18 @@ feature 'Admin spending proposals' do
expect(page).to have_content(spending_proposal.title)
end
scenario 'Accept from index' do
spending_proposal = create(:spending_proposal)
visit admin_spending_proposals_path
click_link 'Accept'
expect(page).to_not have_content(spending_proposal.title)
click_link 'Accepted'
expect(page).to have_content(spending_proposal.title)
expect(spending_proposal.reload).to be_accepted
end
scenario 'Reject from index' do
spending_proposal = create(:spending_proposal)
visit admin_spending_proposals_path
click_link 'Reject'
expect(page).to_not have_content(spending_proposal.title)
click_link('Rejected')
expect(page).to have_content(spending_proposal.title)
expect(spending_proposal.reload).to be_rejected
end
scenario "Current filter is properly highlighted" do
visit admin_spending_proposals_path
expect(page).to_not have_link('Unresolved')
expect(page).to have_link('Accepted')
expect(page).to have_link('Rejected')
visit admin_spending_proposals_path(filter: 'unresolved')
expect(page).to_not have_link('Unresolved')
expect(page).to have_link('Accepted')
expect(page).to have_link('Rejected')
visit admin_spending_proposals_path(filter: 'accepted')
expect(page).to have_link('Unresolved')
expect(page).to_not have_link('Accepted')
expect(page).to have_link('Rejected')
visit admin_spending_proposals_path(filter: 'rejected')
expect(page).to have_link('Accepted')
expect(page).to have_link('Unresolved')
expect(page).to_not have_link('Rejected')
end
scenario "Filtering proposals" do
create(:spending_proposal, title: "Recent spending proposal")
create(:spending_proposal, title: "Good spending proposal", resolution: "accepted")
create(:spending_proposal, title: "Bad spending proposal", resolution: "rejected")
visit admin_spending_proposals_path(filter: 'unresolved')
expect(page).to have_content('Recent spending proposal')
expect(page).to_not have_content('Good spending proposal')
expect(page).to_not have_content('Bad spending proposal')
visit admin_spending_proposals_path(filter: 'accepted')
expect(page).to have_content('Good spending proposal')
expect(page).to_not have_content('Recent spending proposal')
expect(page).to_not have_content('Bad spending proposal')
visit admin_spending_proposals_path(filter: 'rejected')
expect(page).to have_content('Bad spending proposal')
expect(page).to_not have_content('Good spending proposal')
expect(page).to_not have_content('Recent spending proposal')
end
scenario "Action links remember the pagination setting and the filter" do
per_page = Kaminari.config.default_per_page
(per_page + 2).times { create(:spending_proposal, resolution: "accepted") }
visit admin_spending_proposals_path(filter: 'accepted', page: 2)
click_on('Reject', match: :first, exact: true)
expect(current_url).to include('filter=accepted')
expect(current_url).to include('page=2')
end
scenario 'Show' do
administrator = create(:administrator, user: create(:user, username: 'Ana', email: 'ana@admins.org'))
valuator = create(:valuator, user: create(:user, username: 'Rachel', email: 'rachel@valuators.org'))
spending_proposal = create(:spending_proposal,
geozone: create(:geozone),
association_name: 'People of the neighbourhood',
price: 1234.56,
legal: true,
feasible: false,
explanation: "It's impossible")
feasible_explanation: 'It is impossible',
administrator: administrator)
spending_proposal.valuators << valuator
visit admin_spending_proposals_path
click_link spending_proposal.title
@@ -119,38 +40,71 @@ feature 'Admin spending proposals' do
expect(page).to have_content(spending_proposal.author.name)
expect(page).to have_content(spending_proposal.association_name)
expect(page).to have_content(spending_proposal.geozone.name)
expect(page).to have_content("1234.56")
expect(page).to have_content("Legal")
expect(page).to have_content("Not feasible")
expect(page).to have_content("It's impossible")
expect(page).to have_content('1234.56')
expect(page).to have_content('Not feasible')
expect(page).to have_content('It is impossible')
expect(page).to have_select('spending_proposal[administrator_id]', selected: 'Ana (ana@admins.org)')
within('#assigned_valuators') do
expect(page).to have_content('Rachel (rachel@valuators.org)')
end
end
scenario 'Accept from show' do
scenario 'Administrator assigment', :js do
spending_proposal = create(:spending_proposal)
administrator = create(:administrator, user: create(:user, username: 'Ana', email: 'ana@admins.org'))
visit admin_spending_proposal_path(spending_proposal)
click_link 'Accept'
expect(page).to have_select('spending_proposal[administrator_id]', selected: 'Undefined')
select 'Ana (ana@admins.org)', from: 'spending_proposal[administrator_id]'
expect(page).to_not have_content(spending_proposal.title)
visit admin_spending_proposal_path(spending_proposal)
click_link 'Accepted'
expect(page).to have_content(spending_proposal.title)
expect(spending_proposal.reload).to be_accepted
expect(page).to have_select('spending_proposal[administrator_id]', selected: 'Ana (ana@admins.org)')
end
scenario 'Reject from show' do
scenario 'Valuators assigments', :js do
spending_proposal = create(:spending_proposal)
valuator1 = create(:valuator, user: create(:user, username: 'Valentina', email: 'v1@valuators.org'))
valuator2 = create(:valuator, user: create(:user, username: 'Valerian', email: 'v2@valuators.org'))
valuator3 = create(:valuator, user: create(:user, username: 'Val', email: 'v3@valuators.org'))
visit admin_spending_proposal_path(spending_proposal)
click_link 'Reject'
within('#assigned_valuators') do
expect(page).to have_content('Undefined')
expect(page).to_not have_content('Valentina (v1@valuators.org)')
expect(page).to_not have_content('Valerian (v2@valuators.org)')
expect(page).to_not have_content('Val (v3@valuators.org)')
end
expect(page).to_not have_content(spending_proposal.title)
visit admin_spending_proposal_path(spending_proposal)
click_link('Rejected')
expect(page).to have_content(spending_proposal.title)
click_link "Assign valuators"
expect(spending_proposal.reload).to be_rejected
within('#valuators-assign-list') do
check "valuator_ids_#{valuator1.id}"
check "valuator_ids_#{valuator3.id}"
end
within('#assigned_valuators') do
expect(page).to have_content('Valentina (v1@valuators.org)')
expect(page).to have_content('Val (v3@valuators.org)')
expect(page).to_not have_content('Undefined')
expect(page).to_not have_content('Valerian (v2@valuators.org)')
end
visit admin_spending_proposal_path(spending_proposal)
within('#assigned_valuators') do
expect(page).to have_content('Valentina (v1@valuators.org)')
expect(page).to have_content('Val (v3@valuators.org)')
expect(page).to_not have_content('Undefined')
expect(page).to_not have_content('Valerian (v2@valuators.org)')
end
end
end

View File

@@ -43,23 +43,6 @@ describe SpendingProposal do
end
describe "dossier info" do
describe "#legality" do
it "can be legal" do
spending_proposal.legal = true
expect(spending_proposal.legality).to eq "legal"
end
it "can be not-legal" do
spending_proposal.legal = false
expect(spending_proposal.legality).to eq "not_legal"
end
it "can be undefined" do
spending_proposal.legal = nil
expect(spending_proposal.legality).to eq "undefined"
end
end
describe "#feasibility" do
it "can be feasible" do
spending_proposal.feasible = true
@@ -78,99 +61,4 @@ describe SpendingProposal do
end
end
describe "resolution status" do
it "should be valid" do
spending_proposal.resolution = "accepted"
expect(spending_proposal).to be_valid
spending_proposal.resolution = "rejected"
expect(spending_proposal).to be_valid
spending_proposal.resolution = "wrong"
expect(spending_proposal).to_not be_valid
end
it "can be accepted" do
spending_proposal.accept
expect(spending_proposal.reload.resolution).to eq("accepted")
end
it "can be rejected" do
spending_proposal.reject
expect(spending_proposal.reload.resolution).to eq("rejected")
end
describe "#accepted?" do
it "should be true if resolution equals 'accepted'" do
spending_proposal.resolution = "accepted"
expect(spending_proposal.accepted?).to eq true
end
it "should be false otherwise" do
spending_proposal.resolution = "rejected"
expect(spending_proposal.accepted?).to eq false
spending_proposal.resolution = nil
expect(spending_proposal.accepted?).to eq false
end
end
describe "#rejected?" do
it "should be true if resolution equals 'rejected'" do
spending_proposal.resolution = "rejected"
expect(spending_proposal.rejected?).to eq true
end
it "should be false otherwise" do
spending_proposal.resolution = "accepted"
expect(spending_proposal.rejected?).to eq false
spending_proposal.resolution = nil
expect(spending_proposal.rejected?).to eq false
end
end
describe "#unresolved?" do
it "should be true if resolution is blank" do
spending_proposal.resolution = nil
expect(spending_proposal.unresolved?).to eq true
end
it "should be false otherwise" do
spending_proposal.resolution = "accepted"
expect(spending_proposal.unresolved?).to eq false
spending_proposal.resolution = "rejected"
expect(spending_proposal.unresolved?).to eq false
end
end
end
describe "scopes" do
before(:each) do
2.times { create(:spending_proposal, resolution: "accepted") }
2.times { create(:spending_proposal, resolution: "rejected") }
2.times { create(:spending_proposal, resolution: nil) }
end
describe "unresolved" do
it "should return all spending proposals without resolution" do
unresolved = SpendingProposal.all.unresolved
expect(unresolved.size).to eq(2)
unresolved.each {|u| expect(u.resolution).to be_nil}
end
end
describe "accepted" do
it "should return all accepted spending proposals" do
accepted = SpendingProposal.all.accepted
expect(accepted.size).to eq(2)
accepted.each {|a| expect(a.resolution).to eq("accepted")}
end
end
describe "rejected" do
it "should return all rejected spending proposals" do
rejected = SpendingProposal.all.rejected
expect(rejected.size).to eq(2)
rejected.each {|r| expect(r.resolution).to eq("rejected")}
end
end
end
end