Merge pull request #932 from consul/valuators
Valuators and dossier info in spending proposals for Admin
This commit is contained in:
@@ -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(){
|
||||
|
||||
12
app/assets/javascripts/forms.js.coffee
Normal file
12
app/assets/javascripts/forms.js.coffee
Normal 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
|
||||
)
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
4
app/models/valuation_assignment.rb
Normal file
4
app/models/valuation_assignment.rb
Normal file
@@ -0,0 +1,4 @@
|
||||
class ValuationAssignment < ActiveRecord::Base
|
||||
belongs_to :valuator
|
||||
belongs_to :spending_proposal
|
||||
end
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
@@ -0,0 +1 @@
|
||||
$('#assigned_valuators').html("<%= j(render 'assigned_valuators') %>")
|
||||
@@ -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>
|
||||
|
||||
@@ -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 %>
|
||||
|
||||
@@ -23,11 +23,6 @@
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% if @spending_proposal.resolution.present? %>
|
||||
<div class="spending-proposal-resolution">
|
||||
<%= @spending_proposal.resolution %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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...')
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
33
db/schema.rb
33
db/schema.rb
@@ -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
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
FactoryGirl.define do
|
||||
|
||||
sequence(:document_number) { |n| "#{n.to_s.rjust(8, '0')}X" }
|
||||
|
||||
factory :user do
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user