Merge pull request #1212 from consul/budget-votes

Budget votes
This commit is contained in:
Raimond Garcia
2016-09-12 16:00:23 +02:00
committed by GitHub
45 changed files with 1200 additions and 221 deletions

View File

@@ -0,0 +1,77 @@
module Budgets
module Ballot
class LinesController < ApplicationController
before_action :authenticate_user!
#before_action :ensure_final_voting_allowed
before_action :load_budget
before_action :load_ballot
before_action :load_investments
load_and_authorize_resource :budget
load_and_authorize_resource :ballot, class: "Budget::Ballot"
load_and_authorize_resource :line, through: :ballot, find_by: :investment_id, class: "Budget::Ballot::Line"
def create
load_investment
load_heading
if @ballot.add_investment(@investment)
#@ballot.set_geozone(@geozone)
#@current_user.update(representative_id: nil)
if request.get?
redirect_to @spending_proposal, notice: t('spending_proposals.notice.voted')
end
else
if request.get?
redirect_to @spending_proposal, notice: t('spending_proposals.notice.could_not_vote')
else
render :new
end
end
end
def destroy
@investment = @line.investment
load_heading
@line.destroy
load_investments
#@ballot.reset_geozone
end
private
def ensure_final_voting_allowed
return head(:forbidden) unless @budget.balloting?
end
def line_params
params.permit(:investment_id)
end
def load_budget
@budget = Budget.find(params[:budget_id])
end
def load_ballot
@ballot = Budget::Ballot.where(user: current_user, budget: @budget).first_or_create
end
def load_investment
@investment = Budget::Investment.find(params[:investment_id])
end
def load_investments
if params[:investments_ids].present?
@investments = Budget::Investment.where(id: params[:investments_ids])
end
end
def load_heading
@heading = @investment.heading
end
end
end
end

View File

@@ -0,0 +1,18 @@
module Budgets
class BallotsController < ApplicationController
before_action :authenticate_user!
load_and_authorize_resource :budget
before_action :load_ballot
def show
render template: "budgets/ballot/show"
end
private
def load_ballot
@ballot = Budget::Ballot.where(user: current_user, budget: @budget).first_or_create
end
end
end

View File

@@ -0,0 +1,10 @@
module Budgets
class GroupsController < ApplicationController
load_and_authorize_resource :budget
load_and_authorize_resource :group, class: "Budget::Group"
def show
end
end
end

View File

@@ -99,7 +99,7 @@ module Budgets
end
def load_heading
@heading = @budget.headings.find(params[:heading_id]) if params[:geozone_id].present?
@heading = @budget.headings.find(params[:heading_id]) if params[:heading_id].present?
end
end

View File

@@ -0,0 +1,7 @@
module BallotsHelper
def progress_bar_width(amount_available, amount_spent)
(amount_spent/amount_available.to_f * 100).to_s + "%"
end
end

View File

@@ -20,4 +20,17 @@ module BudgetHelper
budget_investment_path(investment, options)
end
end
def display_budget_countdown?(budget)
budget.balloting?
end
def css_for_ballot_heading(heading)
return '' unless current_ballot.present?
current_ballot.has_lines_in_heading?(heading) ? 'active' : ''
end
def current_ballot
Budget::Ballot.where(user: current_user, budget: @budget).first
end
end

View File

@@ -45,9 +45,10 @@ module Abilities
can :vote, SpendingProposal
can :create, SpendingProposal
can :create, Budget::Investment, budget: { phase: "accepting" }
can :vote, Budget::Investment, budget: { phase: "selecting" }
can :create, Budget::Ballot, budget: { phase: "balloting" }
can :create, Budget::Investment, budget: { phase: "accepting" }
can :vote, Budget::Investment, budget: { phase: "selecting" }
can [:show, :create], Budget::Ballot, budget: { phase: "balloting" }
can [:create, :destroy], Budget::Ballot::Line#, budget: { phase: "balloting" }
can :create, DirectMessage
can :show, DirectMessage, sender_id: user.id

View File

@@ -6,13 +6,14 @@ module Abilities
can [:read, :map], Debate
can [:read, :map, :summary], Proposal
can :read, Comment
can :read, Budget
can [:read, :welcome], Budget
can :read, Budget::Investment
can :read, SpendingProposal
can :read, Legislation
can :read, User
can [:search, :read], Annotation
can [:read], Budget
can [:read], Budget::Group
can [:read], Budget::Investment
can :new, DirectMessage
end

View File

@@ -5,6 +5,8 @@ class Budget
has_many :lines, dependent: :destroy
has_many :investments, through: :lines
has_many :groups, -> { uniq }, through: :lines
has_many :headings, -> { uniq }, through: :groups
def add_investment(investment)
lines.create!(budget: budget, investment: investment, heading: investment.heading, group_id: investment.heading.group_id)
@@ -22,6 +24,10 @@ class Budget
budget.heading_price(heading) - amount_spent(heading.id)
end
def has_lines_in_group?(group)
self.groups.include?(group)
end
def valid_heading?(heading)
group = heading.group
return false if group.budget_id != budget_id
@@ -40,8 +46,17 @@ class Budget
self.heading_id.present?
end
def has_lines_in_heading?(heading)
investments.by_heading(heading.id).any?
end
def has_investment?(investment)
self.investment_ids.include?(investment.id)
end
def heading_for_group(group)
self.headings.where(group: group).first
end
end
end

View File

@@ -13,15 +13,15 @@ class Budget
#needed? validates :ballot_id, :budget_id, :group_id, :heading_id, :investment_id, presence: true
def insufficient_funds
errors.add(:money, "") if ballot.amount_available(investment.heading) < investment.price.to_i
errors.add(:money, "insufficient funds") if ballot.amount_available(investment.heading) < investment.price.to_i
end
def different_geozone
errors.add(:heading, "") if (ballot.heading.present? && investment.heading != ballot.heading)
errors.add(:heading, "different heading assigned") if (ballot.heading.present? && investment.heading != ballot.heading)
end
def unfeasible
errors.add(:unfeasible, "") unless investment.feasible?
errors.add(:unfeasible, "unfeasible investment") unless investment.feasible?
end
def heading_proposal?

View File

@@ -45,6 +45,7 @@ class Budget
scope :undecided, -> { where(feasibility: "undecided") }
scope :with_supports, -> { where('cached_votes_up > 0') }
scope :by_group, -> (group_id) { where(group_id: group_id) }
scope :by_heading, -> (heading_id) { where(heading_id: heading_id) }
scope :by_admin, -> (admin_id) { where(administrator_id: admin_id) }
scope :by_tag, -> (tag_name) { tagged_with(tag_name) }

View File

@@ -0,0 +1,55 @@
<div class="row ballot">
<%= render 'shared/back_link' %>
<h1 class="text-center"><%= t("budgets.ballots.show.title") %></h1>
<div class="small-12 medium-8 column small-centered text-center">
<h2>
<%= t("budgets.ballots.show.voted_html",
count: @ballot.investments.count) %>
</h2>
<p>
<small>
<%= t("budgets.ballots.show.voted_info_html") %>
</small>
</p>
</div>
<hr>
<div class="margin-top">
<% @ballot.groups.each do |group| %>
<div id="<%= dom_id(group) %>"
class="small-12 medium-6 column">
<h3 class="subtitle">
<%= group.name %> - <%= group.headings.first.name %>
</h3>
<% if @ballot.has_lines_in_group?(group) %>
<h4 class="amount-spent text-right">
<%= t("budgets.ballots.show.amount_spent") %>
<span>
<%= format_price(@budget, @ballot.amount_spent(@ballot.heading_for_group(group).id)) %>
</span>
</h4>
<% else %>
<p>
<%= t("budgets.ballots.show.zero") %><br>
<%= link_to t("budgets.ballots.show.heading_link"),
budget_investments_path(budget, heading_id: heading.id),
data: { no_turbolink: true } %>
</p>
<% end %>
<ul class="ballot-list">
<%= render partial: 'budgets/ballot/investment',
collection: @ballot.investments.by_group(group.id) %>
</ul>
<h4>
<%= t("budgets.ballots.show.remaining",
amount_city: format_price(@budget, @ballot.amount_available(@ballot.heading_for_group(group)))).html_safe %>
</h4>
</div>
<% end %>
</div>
</div>

View File

@@ -1,9 +1,9 @@
<li id="<%= dom_id(investment) %>">
<%= link_to investment.title, investment %>
<span><%= format_price(investment.price) %></span>
<%= link_to investment.title, budget_investment_path(@budget, investment) %>
<span><%= format_price(@budget, investment.price) %></span>
<% if @budget.balloting? %>
<%= link_to ballot_line_path(id: investment.id),
<%= link_to budget_ballot_line_path(@budget, id: investment.id),
title: t('budgets.ballots.show.remove'),
class: "remove-investment-project",
method: :delete,

View File

@@ -1,10 +1,10 @@
<li id="<%= dom_id(investment) %>_sidebar">
<%= investment.title %>
<span><%= format_price(investment.price) %></span>
<span><%= format_price(@budget, investment.price) %></span>
<% if @budget.balloting? %>
<%= link_to ballot_line_path(id: investment.id,
investments_ids: investment_ids),
<%= link_to budget_ballot_line_url(id: investment.id,
investments_ids: investment_ids),
title: t('budgets.ballots.show.remove'),
class: "remove-investment-project",
method: :delete,

View File

@@ -0,0 +1,28 @@
<span class="total-amount">
<%= format_price(@budget, @budget.heading_price(@heading)) %>
</span>
<div class="progress" role="progressbar" tabindex="0"
aria-valuenow="0" aria-valuemin="0" aria-valuemax="100">
<div class="progress-meter"
style="width:
<%= progress_bar_width(@budget.heading_price(@heading),
@ballot.amount_spent(@heading.id)) %>">
</div>
</div>
<div class="progress spent-amount-progress" role="progressbar" tabindex="0"
aria-valuenow="20" aria-valuemin="0" aria-valuetext="25 percent" aria-valuemax="100">
<span class="progress-meter spent-amount-meter"
style="width:
<%= progress_bar_width(@budget.heading_price(@heading),
@ballot.amount_spent(@heading.id)) %>">
<p id="amount-spent" class="progress-meter-text spent-amount-text">
<%= format_price(@budget, @ballot.amount_spent(@heading.id)) %>
<span id="amount-available" class="amount-available">
<%= t("spending_proposals.index.available") %>
<span><%= format_price(@budget, @ballot.amount_available(@heading)) %></span>
</span>
</p>
</span>
</div>

View File

@@ -4,12 +4,12 @@
</span>
<p class="investment-project-amount">
<%= format_price(investment.price) %>
<%= format_price(@budget, investment.price) %>
</p>
<% if @budget.balloting? %>
<%= link_to t('budgets.ballots.show.remove'),
ballot_line_path(id: investment.id,
budget_ballot_line_path(id: investment.id,
investments_ids: investment_ids),
class: "delete small expanded",
method: :delete,

View File

@@ -0,0 +1,5 @@
<% if @investments.present? %>
<% @investments.each do |investment| %>
$("#<%= dom_id(investment) %>_ballot").html('<%= j render("budgets/investments/ballot", investment: investment) %>');
<% end %>
<% end %>

View File

@@ -0,0 +1,5 @@
$("#progress_bar").html('<%= j render("budgets/ballot/progress_bar", ballot: @ballot) %>');
$("#sidebar").html('<%= j render("budgets/investments/sidebar") %>');
$("#<%= dom_id(@investment) %>_ballot").html('<%= j render("budgets/investments/ballot", investment: @investment) %>');
<%= render 'refresh_ballots' %>

View File

@@ -0,0 +1,6 @@
$("#progress_bar").html('<%= j render("budgets/ballot/progress_bar", ballot: @ballot) %>');
$("#sidebar").html('<%= j render("budgets/investments/sidebar") %>');
$("#ballot").html('<%= j render("budgets/ballot/ballot") %>')
$("#<%= dom_id(@investment) %>_ballot").html('<%= j render("budgets/investments/ballot", investment: @investment) %>');
<%= render 'refresh_ballots' %>

View File

@@ -0,0 +1,2 @@
$("#<%= dom_id(@spending_proposal) %>_ballot").html('<%= j render("spending_proposals/ballot", spending_proposal: @spending_proposal) %>');
$(".no-supports-allowed").show();

View File

@@ -0,0 +1,3 @@
<div id="ballot">
<%= render "budgets/ballot/ballot" %>
</div>

View File

@@ -1,94 +0,0 @@
<div class="row ballot">
<%= render 'shared/back_link' %>
<h1 class="text-center"><%= t("budgets.ballots.show.title") %></h1>
<div class="small-12 medium-8 column small-centered text-center">
<h2>
<%= t("budgets.ballots.show.voted_html",
count: @ballot.investments.count) %>
</h2>
<% if @ballot.geozone.present? && district_wide_amount_spent(@ballot) > 0 %>
<%= social_share_button_tag("#{t('budgets.ballots.show.social_share',
amount: format_price(district_wide_amount_spent(@ballot)),
geozone: @ballot.geozone.name)} #{setting['twitter_hashtag']}",
url: participatory_budget_url) %>
<% end %>
<h3>
<%= t("budgets.ballots.show.remaining_city_html",
amount_city: format_price(@ballot.amount_available(nil))) %>
</h3>
<% if @ballot.geozone.present? %>
<h3>
<%= t("budgets.ballots.show.remaining_district_html",
amount_district: format_price(@ballot.amount_available(@ballot.geozone)),
geozone: @ballot.geozone.name) %>
</h3>
<% end %>
<p>
<small>
<%= t("budgets.ballots.show.voted_info_html") %>
</small>
</p>
</div>
<hr>
<div class="margin-top">
<div id="city_wide" class="small-12 medium-6 column">
<h3 class="subtitle">
<%= t("budgets.ballots.show.city_wide") %>
</h3>
<% if @ballot.investments.by_geozone(nil).count > 0 %>
<h4 class="amount-spent text-right">
<%= t("budgets.ballots.show.amount_spent") %>
<span><%= format_price(city_wide_amount_spent(@ballot)) %></span>
</h4>
<% else %>
<p>
<%= t("budgets.ballots.show.zero") %><br>
<%= link_to t("budgets.ballots.show.city_link"),
investments_path(geozone: 'all'),
data: { no_turbolink: true } %>
</p>
<% end %>
<ul class="ballot-list">
<%= render partial: 'budgets/ballots/investment',
collection: @ballot.investments.no_heading %>
</ul>
</div>
<div id="district_wide" class="small-12 medium-6 column">
<h3 class="subtitle">
<%= t("budgets.ballots.show.district_wide") %>
<span>
<% if @ballot.geozone.present? %>
(<%= @ballot.geozone.name %>)
<% end %>
</span>
</h3>
<% if @ballot.geozone.present? %>
<h4 class="amount-spent text-right">
<%= t("budgets.ballots.show.amount_spent") %>
<span><%= format_price(district_wide_amount_spent(@ballot)) %></span>
</h4>
<% else %>
<p>
<%= t("budgets.ballots.show.zero") %><br>
<%= link_to t("budgets.ballots.show.districts_link"), select_district_path %>
</p>
<% end %>
<ul class="ballot-list">
<%= render partial: 'budgets/ballots/investment',
collection: @ballot.investments.with_heading %>
</ul>
</div>
</div>
</div>

View File

@@ -1,3 +0,0 @@
<div id="ballot">
<%= render partial: "ballots/ballot" %>
</div>

View File

@@ -0,0 +1,29 @@
<div class="row investment-projects-scope margin-bottom no-margin-top">
<div id="select-district" class="small-12 medium-7 column select-district">
<%= link_to budget_path(@budget), class: "back" do %>
<span class="icon-angle-left"></span>
<%= t('shared.back') %>
<% end %>
<h2><%# t("spending_proposals.welcome.districts") %></h2>
<div class="row">
<% @group.headings.each_slice(7) do |slice| %>
<div class="small-6 medium-4 column end">
<% slice.each do |heading| %>
<span id="<%= dom_id(heading) %>"
class="<%= css_for_ballot_heading(heading) %>">
<%= link_to heading.name,
budget_investments_path(heading_id: heading.id),
data: { no_turbolink: true } %><br>
</span>
<% end %>
</div>
<% end %>
</div>
</div>
<div class="medium-5 column show-for-medium text-center margin-top">
<%= image_tag "map.jpg" %>
</div>
</div>

View File

@@ -1,9 +1,13 @@
<% reason = investment.reason_for_not_being_ballotable_by(current_user, @ballot) %>
<div class="supports ballot">
<% if @ballot.has_investment?(investment) %>
<%= render 'budgets/ballots/remove', investment: investment %>
<%= render 'budgets/ballot/remove',
investment: investment,
investment_ids: @investments %>
<% else %>
<%= render 'budgets/ballots/add', investment: investment %>
<%= render 'budgets/ballot/add',
investment: investment,
investment_ids: @investments %>
<% end %>
<% if reason.present? && !@ballot.has_investment?(investment) %>
@@ -14,7 +18,7 @@
verify_account: link_to(t("votes.verify_account"), verification_path),
signin: link_to(t("votes.signin"), new_user_session_path),
signup: link_to(t("votes.signup"), new_user_registration_path),
my_heading: link_to(@ballot.heading.try(:name), budget_investments_path(budget_id: @budget.id, heading_id: @ballot.heading_id))
my_heading: link_to(@ballot.try(:heading).try(:name), budget_investments_path(budget_id: @budget.id, heading_id: @ballot.try(:heading_id)))
).html_safe %>
</p>
</div>

View File

@@ -4,13 +4,15 @@
<div class="row">
<div class="small-12 column">
<%= link_to @budget, class: "back" do %>
<%= link_to budget_group_path(@budget, @heading.group), class: "back" do %>
<i class="icon-angle-left"></i>
<%= t("shared.back") %>
<% end %>
<% if can? :show, @ballot %>
<%= link_to t("budget.investments.header.check_ballot"), budget_ballot_path(@budget, @ballot), class: "button float-right" %>
<%= link_to t("budget.investments.header.check_ballot"),
budget_ballot_path(@budget, @ballot),
class: "button float-right" %>
<% end %>
</div>
</div>
@@ -21,10 +23,15 @@
<h1 class="inline-block"><%= @filter_geozone_name %></h1>
<div id="check-ballot" style="display: none;">
<% if can? :show, @ballot %>
<%= link_to t("budget.investments.header.check_ballot"), ballot_path %>
<%= link_to t("budget.investments.header.check_ballot"),
budget_ballot_path(@budget) %>
<% end %>
</div>
<% if @heading.present? && @ballot.heading.present? && @ballot.heading != @heading %>
<% if false
#@heading.present? &&
#@ballot.heading.present? &&
#@ballot.heading != @heading
%>
<br>
<p class="callout warning inline-block">
<%= t("budget.investments.header.different_heading_active") %>
@@ -32,7 +39,7 @@
</p>
<% else %>
<div id="progress_bar" class="no-margin-top">
<%= render 'progress_bar' %>
<%= render 'budgets/ballot/progress_bar' %>
</div>
<% end %>
</div>

View File

@@ -43,18 +43,23 @@
</div>
<% unless investment.unfeasible? %>
<% if feature?("investment_features.phase2") %>
<% if @budget.selecting? || @budget.on_hold? %>
<div id="<%= dom_id(investment) %>_votes"
class="small-12 medium-3 column text-center">
<%= render 'votes',
{ investment: investment, vote_url: vote_investment_path(investment, value: 'yes') } %>
{ investment: investment,
vote_url: vote_budget_investment_path(@budget, investment, value: 'yes') } %>
</div>
<% elsif feature?("investment_features.phase3") %>
<% elsif @budget.balloting? %>
<div id="<%= dom_id(investment) %>_ballot"
class="small-12 medium-3 column text-center">
<%= render 'ballot', investment: investment %>
</div>
<% end %>
<% end %>
</div>
</div>

View File

@@ -13,7 +13,7 @@
<em>
<%= t("budget.investments.index.sidebar.voted_html",
count: @ballot.investments.by_heading(@heading.id).count,
amount_spent: format_price(@ballot.amount_spent(@heading))) %>
amount_spent: format_price(@budget, @ballot.amount_spent(@heading))) %>
</em>
</p>
<% else %>
@@ -22,7 +22,9 @@
<ul class="ballot-list">
<% @ballot.investments.by_heading(@heading).each do |investment| %>
<%= render 'ballots/investment_for_sidebar', investment: investment %>
<%= render 'budgets/ballot/investment_for_sidebar',
investment: investment,
investment_ids: @investments %>
<% end %>
</ul>

View File

@@ -13,7 +13,7 @@
<div class="supported">
<%= t("budget.investments.investment.already_supported") %>
</div>
<% elsif voting_allowed %>
<% elsif @budget.selecting? %>
<%= link_to vote_url,
class: "button button-support small expanded",

View File

@@ -7,7 +7,9 @@
<main id="budget-investments-main">
<%= render 'header' %>
<% unless params[:search].present? %>
<%= render 'header' %>
<% end %>
<div class="wrap row">
<div id="budget-investments" class="budget-investments-list small-12 medium-9 column">

View File

@@ -45,15 +45,19 @@
</div>
<% if (@budget.selecting? && !@investment.unfeasible?) ||
(@budget.balloting? && @investment.feasible?) %>
(@budget.balloting? && @investment.feasible? ||
(@budget.on_hold?)) %>
<aside class="small-12 medium-3 column">
<div class="sidebar-divider"></div>
<h3><%= t("votes.supports") %></h3>
<div class="text-center">
<% if @budget.selecting? %>
<% if @budget.selecting? || @budget.on_hold? %>
<div id="<%= dom_id(@investment) %>_votes">
<%= render 'votes',
{ investment: @investment, vote_url: vote_budget_investment_path(budget_id: @budget.id, id: @investment.id) } %>
{ investment: @investment,
vote_url: vote_budget_investment_path(@budget, @investment, value: 'yes') }
%>
</div>
<% else %>
<div id="<%= dom_id(@investment) %>_ballot">

View File

@@ -0,0 +1 @@
$("#<%= dom_id(@investment) %>_votes").html('<%= j render("budgets/investments/votes", investment: @investment, vote_url: vote_budget_investment_path(@budget, @investment, value: "yes")) %>');

View File

@@ -16,29 +16,24 @@
<div class="small-12 medium-6 column">
<table class="table-fixed">
<thead>
<th><%= t('budget.show.heading') %></th>
<th><%= t('budget.show.price') %></th>
<th><%= t('budget.show.group') %></th>
</thead>
<tbody>
<tr>
<td>
<%= link_to t('budget.show.no_heading'), budget_investments_path(budget_id: @budget.id, heading_id: nil) %>
</td>
<td>
<%# format_price(@budget, @budget.price) %>
</td>
</tr>
<% @budget.headings.each do |heading| %>
<% @budget.groups.each do |group| %>
<tr>
<td>
<%= link_to heading.name, budget_investments_path(budget_id: @budget.id, heading_id: heading.id) %>
</td>
<td>
<%= format_price(@budget, heading.price) %>
<% if group.headings.count == 1 %>
<%= link_to group.name,
budget_investments_path(@budget, heading_id: group.headings.first.id),
data: { no_turbolink: true } %>
<% else %>
<%= link_to group.name, budget_group_path(@budget, group) %>
<% end %>
<br>
</td>
</tr>
<% end %>
</tbody>
</table>
</div>
</div>
</div>

View File

@@ -2,15 +2,15 @@ en:
budgets:
ballots:
show:
amount_spent: "pending translation"
city_wide: "pending translation"
districts_link: "pending translation"
remaining_district_html: "pending translation"
social_share: "pending translation"
title: "pending translation"
voted_html: "pending translation"
voted_info_html: "pending translation"
zero: "pending translation"
title: Your ballot
amount_spent: Amount spent
remaining: "You still have <span>%{amount_city}</span> to invest."
remove: Remove vote
voted_html:
one: "You have voted <span>one</span> proposal."
other: "You have voted <span>%{count}</span> proposals."
voted_info_html: "You can change your vote at any time until the close of this phase.<br> No need to invest all the money available."
zero: You have not voted any investment project.
budget:
phase:
on_hold: On hold
@@ -18,6 +18,9 @@ en:
selecting: Selecting
balloting: Balloting
finished: Finished
groups:
index:
group_title: "Groups"
headings:
none: Whole City
all: All scopes
@@ -101,6 +104,7 @@ en:
check_ballot: Check my ballot
different_heading_active: You have active votes in another district.
show:
group: Group
heading: Heading
price: Price
no_heading: No Heading

View File

@@ -2,15 +2,15 @@ es:
budgets:
ballots:
show:
amount_spent: "pending translation"
city_wide: "pending translation"
districts_link: "pending translation"
remaining_district_html: "pending translation"
social_share: "pending translation"
title: "pending translation"
voted_html: "pending translation"
voted_info_html: "pending translation"
zero: "pending translation"
title: Mis votos
amount_spent: Coste total
remaining: "Te quedan <span>%{amount_city}</span> para invertir"
remove: Quitar voto
voted_html:
one: "Has votado <span>una</span> propuesta."
other: "Has votado <span>%{count}</span> propuestas."
voted_info_html: "Puedes cambiar tus votos en cualquier momento hasta el cierre de esta fase.<br> No hace falta que inviertas todo el dinero disponible."
zero: "Todavía no has votado ninguna propuesta de inversión."
budget:
phase:
on_hold: En pausa
@@ -18,6 +18,9 @@ es:
selecting: Fase de selección
balloting: Fase de Votación
finished: Terminado
groups:
index:
group_title: "Grupos"
headings:
none: Toda la ciudad
all: Todos los ámbitos
@@ -101,6 +104,7 @@ es:
check_ballot: Revisar mis votos
different_heading_active: Ya apoyaste propuestas de otro distrito.
show:
group: Grupo
heading: Partida
price: Cantidad
no_heading: Sin línea

View File

@@ -70,10 +70,11 @@ Rails.application.routes.draw do
end
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 }
end
resource :ballot, only: :show do
resource :ballot, only: :show, controller: "budgets/ballots" do
resources :lines, controller: "budgets/ballot/lines", only: [:create, :destroy]
end
end

View File

@@ -298,11 +298,12 @@ end
puts "Creating Budgets"
(1..10).each do |i|
phases = %w{on_hold accepting selecting balloting finished}
phases.each_with_index do |phase, i|
budget = Budget.create!(name: (Date.today.year - 10 + i).to_s,
description: "<p>#{Faker::Lorem.paragraphs.join('</p><p>')}</p>",
currency_symbol: "",
phase: %w{on_hold accepting selecting balloting finished}.sample,
phase: phase,
valuating: [false, true].sample)
puts budget.name
@@ -313,7 +314,7 @@ puts "Creating Budgets"
geozones.each do |geozone|
group.headings << group.headings.create!(name: geozone.name,
geozone: geozone,
price: rand(1 .. 100) * 10000)
price: rand(1 .. 100) * 100000)
end
print "#{group.name} "
@@ -324,7 +325,7 @@ end
puts "Creating Investments"
tags = Faker::Lorem.words(10)
(1..60).each do |i|
(1..100).each do |i|
heading = Budget::Heading.reorder("RANDOM()").first
investment = Budget::Investment.create!(
@@ -340,7 +341,7 @@ tags = Faker::Lorem.words(10)
unfeasibility_explanation: "<p>#{Faker::Lorem.paragraphs.join('</p><p>')}</p>",
valuation_finished: [false, true].sample,
tag_list: tags.sample(3).join(','),
price: rand(1 .. 100) * 1000000,
price: rand(1 .. 100) * 100000,
terms_of_service: "1")
puts " #{investment.title}"
end

View File

@@ -0,0 +1,661 @@
require 'rails_helper'
feature 'Ballots' do
let(:budget) { create(:budget, phase: "balloting") }
let(:group) { create(:budget_group, budget: budget, name: "Group 1") }
let(:heading) { create(:budget_heading, group: group, name: "Heading 1", price: 1000000) }
context "Voting" do
let!(:user) { create(:user, :level_two) }
background do
login_as(user)
visit budget_path(budget)
end
context "Group and Heading Navigation" do
scenario "Groups" do
city = create(:budget_group, budget: budget, name: "City")
districts = create(:budget_group, budget: budget, name: "Districts")
visit budget_path(budget)
expect(page).to have_link "City"
expect(page).to have_link "Districts"
end
scenario "Headings" do
city = create(:budget_group, budget: budget, name: "City")
districts = create(:budget_group, budget: budget, name: "Districts")
city_heading1 = create(:budget_heading, group: city, name: "Investments Type1")
city_heading2 = create(:budget_heading, group: city, name: "Investments Type2")
district_heading1 = create(:budget_heading, group: districts, name: "District 1")
district_heading2 = create(:budget_heading, group: districts, name: "District 2")
visit budget_path(budget)
click_link "City"
expect(page).to have_link "Investments Type1"
expect(page).to have_link "Investments Type2"
click_link "Go back"
click_link "Districts"
expect(page).to have_link "District 1"
expect(page).to have_link "District 2"
end
scenario "Investments" do
city = create(:budget_group, budget: budget, name: "City")
districts = create(:budget_group, budget: budget, name: "Districts")
city_heading1 = create(:budget_heading, group: city, name: "Investments Type1")
city_heading2 = create(:budget_heading, group: city, name: "Investments Type2")
district_heading1 = create(:budget_heading, group: districts, name: "District 1")
district_heading2 = create(:budget_heading, group: districts, name: "District 2")
city_investment1 = create(:budget_investment, :feasible, :finished, heading: city_heading1)
city_investment2 = create(:budget_investment, :feasible, :finished, heading: city_heading1)
district1_investment1 = create(:budget_investment, :feasible, :finished, heading: district_heading1)
district1_investment2 = create(:budget_investment, :feasible, :finished, heading: district_heading1)
district2_investment1 = create(:budget_investment, :feasible, :finished, heading: district_heading2)
visit budget_path(budget)
click_link "City"
click_link "Investments Type1"
expect(page).to have_css(".budget-investment", count: 2)
expect(page).to have_content city_investment1.title
expect(page).to have_content city_investment2.title
click_link "Go back"
click_link "Go back"
click_link "Districts"
click_link "District 1"
expect(page).to have_css(".budget-investment", count: 2)
expect(page).to have_content district1_investment1.title
expect(page).to have_content district1_investment2.title
click_link "Go back"
click_link "District 2"
expect(page).to have_css(".budget-investment", count: 1)
expect(page).to have_content district2_investment1.title
end
scenario "Redirect to first heading if there is only one" do
city = create(:budget_group, budget: budget, name: "City")
districts = create(:budget_group, budget: budget, name: "Districts")
city_heading = create(:budget_heading, group: city, name: "City")
district_heading1 = create(:budget_heading, group: districts, name: "District 1")
district_heading2 = create(:budget_heading, group: districts, name: "District 2")
city_investment = create(:budget_investment, :feasible, :finished, heading: city_heading)
visit budget_path(budget)
click_link "City"
expect(page).to have_content city_investment.title
end
end
context "Adding and Removing Investments" do
scenario "Add a proposal", :js do
investment1 = create(:budget_investment, :feasible, :finished, budget: budget, heading: heading, group: group, price: 10000)
investment2 = create(:budget_investment, :feasible, :finished, budget: budget, heading: heading, group: group, price: 20000)
visit budget_path(budget)
click_link "Group 1"
within("#budget_investment_#{investment1.id}") do
find('.add a').trigger('click')
end
expect(page).to have_css("#amount-spent", text: "€10,000")
expect(page).to have_css("#amount-available", text: "€990,000")
within("#sidebar") do
expect(page).to have_content investment1.title
expect(page).to have_content "€10,000"
end
within("#budget_investment_#{investment2.id}") do
find('.add a').trigger('click')
end
expect(page).to have_css("#amount-spent", text: "€30,000")
expect(page).to have_css("#amount-available", text: "€970,000")
within("#sidebar") do
expect(page).to have_content investment2.title
expect(page).to have_content "€20,000"
end
end
scenario "Remove a proposal", :js do
investment1 = create(:budget_investment, :feasible, :finished, budget: budget, heading: heading, group: group, price: 10000)
ballot = create(:budget_ballot, user: user, budget: budget, investments: [investment1])
visit budget_path(budget)
click_link "Group 1"
expect(page).to have_content investment1.title
expect(page).to have_css("#amount-spent", text: "€10,000")
expect(page).to have_css("#amount-available", text: "€990,000")
within("#sidebar") do
expect(page).to have_content investment1.title
expect(page).to have_content "€10,000"
end
within("#budget_investment_#{investment1.id}") do
find('.remove a').trigger('click')
end
expect(page).to have_css("#amount-spent", text: "€0")
expect(page).to have_css("#amount-available", text: "€1,000,000")
within("#sidebar") do
expect(page).to_not have_content investment1.title
expect(page).to_not have_content "€10,000"
end
end
end
#Break up or simplify with helpers
context "Balloting in multiple headings" do
scenario "Independent progress bar for headings", :js do
city = create(:budget_group, budget: budget, name: "City")
districts = create(:budget_group, budget: budget, name: "Districts")
city_heading = create(:budget_heading, group: city, name: "All city", price: 10000000)
district_heading1 = create(:budget_heading, group: districts, name: "District 1", price: 1000000)
district_heading2 = create(:budget_heading, group: districts, name: "District 2", price: 2000000)
investment1 = create(:budget_investment, :feasible, :finished, heading: city_heading, price: 10000)
investment2 = create(:budget_investment, :feasible, :finished, heading: district_heading1, price: 20000)
investment3 = create(:budget_investment, :feasible, :finished, heading: district_heading2, price: 30000)
visit budget_path(budget)
click_link "City"
within("#budget_investment_#{investment1.id}") do
find('.add a').trigger('click')
expect(page).to have_content "Remove"
end
expect(page).to have_css("#amount-spent", text: "€10,000")
expect(page).to have_css("#amount-available", text: "€9,990,000")
within("#sidebar") do
expect(page).to have_content investment1.title
expect(page).to have_content "€10,000"
end
visit budget_path(budget)
click_link "Districts"
click_link "District 1"
expect(page).to have_css("#amount-spent", text: "€0")
expect(page).to have_css("#amount-spent", text: "€1,000,000")
within("#budget_investment_#{investment2.id}") do
find('.add a').trigger('click')
expect(page).to have_content "Remove"
end
visit budget_path(budget)
click_link "Districts"
click_link "District 1"
expect(page).to have_css("#amount-spent", text: "€20,000")
expect(page).to have_css("#amount-available", text: "€980,000")
within("#sidebar") do
expect(page).to have_content investment2.title
expect(page).to have_content "€20,000"
expect(page).to_not have_content investment1.title
expect(page).to_not have_content "€10,000"
end
visit budget_path(budget)
click_link "City"
expect(page).to have_css("#amount-spent", text: "€10,000")
expect(page).to have_css("#amount-available", text: "€9,990,000")
within("#sidebar") do
expect(page).to have_content investment1.title
expect(page).to have_content "€10,000"
expect(page).to_not have_content investment2.title
expect(page).to_not have_content "€20,000"
end
visit budget_path(budget)
click_link "Districts"
click_link "District 2"
expect(page).to have_css("#amount-spent", text: "€0")
expect(page).to have_css("#amount-spent", text: "€2,000,000")
end
end
scenario "Display progress bar after first vote", :js do
investment = create(:budget_investment, :feasible, :finished, heading: heading, price: 10000)
visit budget_investments_path(budget, heading_id: heading.id)
expect(page).to have_content investment.title
within("#budget_investment_#{investment.id}") do
find('.add a').trigger('click')
expect(page).to have_content "Remove"
end
within("#progress_bar") do
expect(page).to have_css("#amount-spent", text: "€10,000")
end
end
end
context "Groups" do
let!(:user) { create(:user, :level_two) }
let!(:districts_group) { create(:budget_group, budget: budget, name: "Districts") }
let!(:california_heading) { create(:budget_heading, group: districts_group, name: "California") }
let!(:new_york_heading) { create(:budget_heading, group: districts_group, name: "New York") }
let!(:investment) { create(:budget_investment, :feasible, :finished, heading: california_heading) }
background do
login_as(user)
end
scenario 'Select my heading', :js do
visit budget_path(budget)
click_link "Districts"
click_link "California"
within("#budget_investment_#{investment.id}") do
find('.add a').trigger('click')
expect(page).to have_content "Remove"
end
visit budget_path(budget)
click_link "Districts"
expect(page).to have_content "California"
expect(page).to have_css("#budget_heading_#{california_heading.id}.active")
end
scenario 'Change my heading', :js do
investment1 = create(:budget_investment, :feasible, :finished, heading: california_heading)
investment2 = create(:budget_investment, :feasible, :finished, heading: new_york_heading)
create(:budget_ballot, user: user, budget: budget, investments: [investment1])
visit budget_investments_path(budget, heading_id: california_heading.id)
within("#budget_investment_#{investment1.id}") do
find('.remove a').trigger('click')
end
visit budget_investments_path(budget, heading_id: new_york_heading.id)
within("#budget_investment_#{investment2.id}") do
find('.add a').trigger('click')
end
visit budget_path(budget)
click_link "Districts"
expect(page).to have_css("#budget_heading_#{new_york_heading.id}.active")
expect(page).to_not have_css("#budget_heading_#{california_heading.id}.active")
end
scenario 'View another heading' do
investment = create(:budget_investment, :feasible, :finished, heading: california_heading)
create(:budget_ballot, user: user, budget: budget, investments: [investment])
visit budget_investments_path(budget, heading_id: new_york_heading.id)
expect(page).to_not have_css "#progressbar"
expect(page).to have_content "You have active votes in another district:"
expect(page).to have_link california_heading.name, href: budget_investments_path(budget, heading: california_heading)
end
end
context 'Showing the ballot' do
pending "Do not display heading name if there is only one heading in the group (example: group city)"
scenario 'Displaying the correct count & amount' do
user = create(:user, :level_two)
group1 = create(:budget_group, budget: budget)
group2 = create(:budget_group, budget: budget)
heading1 = create(:budget_heading, name: "District 1", group: group1, price: 100)
heading2 = create(:budget_heading, name: "District 2", group: group2, price: 50)
ballot = create(:budget_ballot, user: user, budget: budget)
investment1 = create(:budget_investment, :feasible, price: 10, heading: heading1, group: group1)
investment2 = create(:budget_investment, :feasible, price: 10, heading: heading1, group: group1)
investment3 = create(:budget_investment, :feasible, price: 5, heading: heading2, group: group2)
investment4 = create(:budget_investment, :feasible, price: 5, heading: heading2, group: group2)
investment5 = create(:budget_investment, :feasible, price: 5, heading: heading2, group: group2)
create(:budget_ballot_line, ballot: ballot, investment: investment1, group: group1)
create(:budget_ballot_line, ballot: ballot, investment: investment2, group: group1)
create(:budget_ballot_line, ballot: ballot, investment: investment3, group: group2)
create(:budget_ballot_line, ballot: ballot, investment: investment4, group: group2)
create(:budget_ballot_line, ballot: ballot, investment: investment5, group: group2)
login_as(user)
visit budget_ballot_path(budget)
expect(page).to have_content("You have voted 5 proposals")
within("#budget_group_#{group1.id}") do
expect(page).to have_content "#{group1.name} - #{heading1.name}"
expect(page).to have_content "Amount spent €20"
expect(page).to have_content "You still have €80 to invest"
end
within("#budget_group_#{group2.id}") do
expect(page).to have_content "#{group2.name} - #{heading2.name}"
expect(page).to have_content "Amount spent €15"
expect(page).to have_content "You still have €35 to invest"
end
end
end
scenario 'Removing spending proposals from ballot', :js do
user = create(:user, :level_two)
ballot = create(:budget_ballot, user: user, budget: budget)
investment = create(:budget_investment, :feasible, :finished, price: 10, heading: heading, group: group)
create(:budget_ballot_line, ballot: ballot, investment: investment, heading: heading, group: group)
login_as(user)
visit budget_ballot_path(budget)
expect(page).to have_content("You have voted one proposal")
within("#budget_investment_#{investment.id}") do
find(".remove-investment-project").trigger('click')
end
expect(current_path).to eq(budget_ballot_path(budget))
expect(page).to have_content("You have voted 0 proposals")
end
scenario 'Removing spending proposals from ballot (sidebar)', :js do
user = create(:user, :level_two)
investment1 = create(:budget_investment, :feasible, :finished, price: 10000, heading: heading)
investment2 = create(:budget_investment, :feasible, :finished, price: 20000, heading: heading)
ballot = create(:budget_ballot, budget: budget, user: user, investments: [investment1, investment2])
login_as(user)
visit budget_investments_path(budget, heading_id: heading.id)
expect(page).to have_css("#amount-spent", text: "€30,000")
expect(page).to have_css("#amount-available", text: "€970,000")
within("#sidebar") do
expect(page).to have_content investment1.title
expect(page).to have_content "€10,000"
expect(page).to have_content investment2.title
expect(page).to have_content "€20,000"
end
within("#sidebar #budget_investment_#{investment1.id}_sidebar") do
find(".remove-investment-project").trigger('click')
end
expect(page).to have_css("#amount-spent", text: "€20,000")
expect(page).to have_css("#amount-available", text: "€980,000")
within("#sidebar") do
expect(page).to_not have_content investment1.title
expect(page).to_not have_content "€10,000"
expect(page).to have_content investment2.title
expect(page).to have_content "€20,000"
end
end
context 'Permissions' do
scenario 'User not logged in', :js do
investment = create(:budget_investment, :feasible, :finished, heading: heading)
visit budget_investments_path(budget, heading_id: heading.id)
within("#budget_investment_#{investment.id}") do
find("div.ballot").hover
expect_message_you_need_to_sign_in_to_ballot
end
end
scenario 'User not verified', :js do
user = create(:user)
investment = create(:budget_investment, :feasible, :finished, heading: heading)
login_as(user)
visit budget_investments_path(budget, heading_id: heading.id)
within("#budget_investment_#{investment.id}") do
find("div.ballot").hover
expect_message_only_verified_can_vote_investments
end
end
scenario 'User is organization', :js do
org = create(:organization)
investment = create(:budget_investment, :feasible, :finished, heading: heading)
login_as(org.user)
visit budget_investments_path(budget, heading_id: heading.id)
within("#budget_investment_#{investment.id}") do
find("div.ballot").hover
expect_message_organizations_cannot_vote
end
end
scenario 'Unfeasible investments' do
user = create(:user, :level_two)
investment = create(:budget_investment, :finished, :unfeasible, heading: heading)
login_as(user)
visit budget_investments_path(budget, heading_id: heading.id, unfeasible: 1)
within("#budget_investment_#{investment.id}") do
expect(page).to_not have_css("div.ballot")
end
end
scenario 'Investments with feasibility undecided are not shown' do
user = create(:user, :level_two)
investment = create(:budget_investment, :finished, feasibility: "undecided", heading: heading)
login_as(user)
visit budget_investments_path(budget, heading_id: heading.id)
within("#budget-investments") do
expect(page).to_not have_css("div.ballot")
expect(page).to_not have_css("#budget_investment_#{investment.id}")
end
end
scenario 'Different district', :js do
user = create(:user, :level_two)
california = create(:geozone)
new_york = create(:geozone)
sp1 = create(:spending_proposal, :feasible, :finished, geozone: california)
sp2 = create(:spending_proposal, :feasible, :finished, geozone: new_york)
create(:ballot, user: user, geozone: california, spending_proposals: [sp1])
login_as(user)
visit spending_proposals_path(geozone: new_york)
within("#spending_proposal_#{sp2.id}") do
find("div.ballot").hover
expect_message_already_voted_in_another_geozone(california)
end
end
scenario 'Insufficient funds', :js do
user = create(:user, :level_two)
california = create(:geozone)
sp1 = create(:spending_proposal, :feasible, :finished, price: 25000000)
login_as(user)
visit spending_proposals_path(geozone: 'all')
within("#spending_proposal_#{sp1.id}") do
find('.add a').trigger('click')
expect_message_insufficient_funds
end
end
scenario 'Displays error message for all proposals (on create)', :js do
user = create(:user, :level_two)
california = create(:geozone)
sp1 = create(:spending_proposal, :feasible, :finished, price: 20000000)
sp2 = create(:spending_proposal, :feasible, :finished, price: 5000000)
login_as(user)
visit spending_proposals_path(geozone: 'all')
within("#spending_proposal_#{sp1.id}") do
find('.add a').trigger('click')
expect(page).to have_content "Remove vote"
end
within("#spending_proposal_#{sp2.id}") do
find("div.ballot").hover
expect_message_insufficient_funds
end
end
scenario 'Displays error message for all proposals (on destroy)', :js do
user = create(:user, :level_two)
sp1 = create(:spending_proposal, :feasible, :finished, price: 24000000)
sp2 = create(:spending_proposal, :feasible, :finished, price: 5000000)
create(:ballot, user: user, spending_proposals: [sp1])
login_as(user)
visit spending_proposals_path(geozone: 'all')
within("#spending_proposal_#{sp2.id}") do
find("div.ballot").hover
expect(page).to have_content "This proposal's price is more than the available amount left"
expect(page).to have_selector('.in-favor a', visible: false)
end
within("#spending_proposal_#{sp1.id}") do
find('.remove a').trigger('click')
end
within("#spending_proposal_#{sp2.id}") do
find("div.ballot").hover
expect(page).to_not have_content "This proposal's price is more than the available amount left"
expect(page).to have_selector('.in-favor a', visible: true)
end
end
scenario 'Displays error message for all proposals (on destroy from sidebar)', :js do
user = create(:user, :level_two)
sp1 = create(:spending_proposal, :feasible, :finished, price: 24000000)
sp2 = create(:spending_proposal, :feasible, :finished, price: 5000000)
create(:ballot, user: user, spending_proposals: [sp1])
login_as(user)
visit spending_proposals_path(geozone: 'all')
within("#spending_proposal_#{sp2.id}") do
find("div.ballot").hover
expect(page).to have_content "This proposal's price is more than the available amount left"
expect(page).to have_selector('.in-favor a', visible: false)
end
within("#spending_proposal_#{sp1.id}_sidebar") do
find('.remove-investment-project').trigger('click')
end
expect(page).to_not have_css "#spending_proposal_#{sp1.id}_sidebar"
within("#spending_proposal_#{sp2.id}") do
find("div.ballot").hover
expect(page).to_not have_content "This proposal's price is more than the available amount left"
expect(page).to have_selector('.in-favor a', visible: true)
end
end
scenario "Display hover for ajax generated content", :js do
user = create(:user, :level_two)
california = create(:geozone)
sp1 = create(:spending_proposal, :feasible, :finished, price: 20000000)
sp2 = create(:spending_proposal, :feasible, :finished, price: 5000000)
login_as(user)
visit spending_proposals_path(geozone: 'all')
within("#spending_proposal_#{sp1.id}") do
find('.add a').trigger('click')
expect(page).to have_content "Remove vote"
end
within("#spending_proposal_#{sp2.id}") do
find("div.ballot").trigger(:mouseover)
expect_message_insufficient_funds
end
end
end
end
feature "Ballots in the wrong phase" do
background { login_as(create(:user, :level_two)) }
let(:sp) { create(:spending_proposal, :feasible, :finished, price: 10000) }
scenario "When not on phase 3" do
Setting['feature.spending_proposal_features.phase3'] = nil
visit create_ballot_line_path(spending_proposal_id: sp.id)
expect(page.status_code).to eq(403)
end
scenario "When in phase 3 but voting disabled" do
Setting['feature.spending_proposal_features.phase3'] = true
Setting['feature.spending_proposal_features.final_voting_allowed'] = nil
expect{visit create_ballot_line_path(spending_proposal_id: sp.id)}.to raise_error(ActionController::RoutingError)
end
end

View File

@@ -10,12 +10,11 @@ feature 'Budgets' do
scenario 'Show' do
budget = create(:budget)
group = create(:budget_group, budget: budget)
heading = create(:budget_heading, group: group)
group1 = create(:budget_group, budget: budget)
group2 = create(:budget_group, budget: budget)
visit budget_path(budget)
expect(page).to have_content(budget.name)
expect(page).to have_content(heading.name)
budget.groups.each {|group| expect(page).to have_link(group.name)}
end
end

View File

@@ -11,7 +11,7 @@ feature 'Budget Investments' do
investments = [create(:budget_investment, budget: budget, group: group, heading: heading), create(:budget_investment, budget: budget, group: group, heading: heading), create(:budget_investment, :feasible, budget: budget, group: group, heading: heading)]
unfeasible_investment = create(:budget_investment, :unfeasible, budget: budget, group: group, heading: heading)
visit budget_investments_path(budget_id: budget.id)
visit budget_investments_path(budget, heading_id: heading.id)
expect(page).to have_selector('#budget-investments .budget-investment', count: 3)
investments.each do |investment|
@@ -29,7 +29,7 @@ feature 'Budget Investments' do
investment2 = create(:budget_investment, budget: budget, group: group, heading: heading, title: "Schwifty Hello")
investment3 = create(:budget_investment, budget: budget, group: group, heading: heading, title: "Do not show me")
visit budget_investments_path(budget_id: budget.id)
visit budget_investments_path(budget, heading_id: heading.id)
within(".expanded #search_form") do
fill_in "search", with: "Schwifty"
@@ -53,7 +53,7 @@ feature 'Budget Investments' do
investment3 = create(:budget_investment, budget: budget, group: group, heading: heading)
investment4 = create(:budget_investment, :feasible, budget: budget, group: group, heading: heading)
visit budget_investments_path(budget_id: budget.id, unfeasible: 1)
visit budget_investments_path(budget_id: budget.id, heading_id: heading.id, unfeasible: 1)
within("#budget-investments") do
expect(page).to have_css('.budget-investment', count: 1)
@@ -72,10 +72,10 @@ feature 'Budget Investments' do
per_page = Kaminari.config.default_per_page
(per_page + 2).times { create(:budget_investment) }
visit budget_investments_path(budget_id: budget.id)
visit budget_investments_path(budget, heading_id: heading.id)
order = all(".budget-investment h3").collect {|i| i.text }
visit budget_investments_path(budget_id: budget.id)
visit budget_investments_path(budget, heading_id: heading.id)
new_order = eq(all(".budget-investment h3").collect {|i| i.text })
expect(order).to_not eq(new_order)
@@ -85,13 +85,13 @@ feature 'Budget Investments' do
per_page = Kaminari.config.default_per_page
(per_page + 2).times { create(:budget_investment) }
visit budget_investments_path(budget_id: budget.id)
visit budget_investments_path(budget, heading_id: heading.id)
click_link "highest rated"
click_link "random"
order = all(".budget-investment h3").collect {|i| i.text }
visit budget_investments_path(budget_id: budget.id)
visit budget_investments_path(budget, heading_id: heading.id)
new_order = eq(all(".budget-investment h3").collect {|i| i.text })
expect(order).to_not eq(new_order)
@@ -101,7 +101,7 @@ feature 'Budget Investments' do
per_page = Kaminari.config.default_per_page
(per_page + 2).times { create(:budget_investment, budget: budget, group: group, heading: heading) }
visit budget_investments_path(budget_id: budget.id)
visit budget_investments_path(budget, heading_id: heading.id)
order = all(".budget-investment h3").collect {|i| i.text }
@@ -120,7 +120,7 @@ feature 'Budget Investments' do
create(:budget_investment, budget: budget, group: group, heading: heading, title: 'Worst proposal').update_column(:confidence_score, 2)
create(:budget_investment, budget: budget, group: group, heading: heading, title: 'Medium proposal').update_column(:confidence_score, 5)
visit budget_investments_path(budget_id: budget.id)
visit budget_investments_path(budget, heading_id: heading.id)
click_link 'highest rated'
expect(page).to have_selector('a.active', text: 'highest rated')
@@ -274,23 +274,6 @@ feature 'Budget Investments' do
end
context "Badge" do
scenario "Spending proposal created by a User" do
user = create(:user)
user_investment = create(:budget_investment, budget: budget, group: group, heading: heading)
visit budget_investment_path(budget_id: budget.id, id: user_investment.id)
expect(page).to_not have_css "is-forum"
visit budget_investments_path(budget_id: budget.id, id: user_investment.id)
within "#budget_investment_#{user_investment.id}" do
expect(page).to_not have_css "is-forum"
end
end
end
context "Phase 3 - Final Voting" do
background do
@@ -325,7 +308,7 @@ feature 'Budget Investments' do
create(:budget_investment, :feasible, :finished, budget: budget, group: group, heading: heading, title: 'Build an ugly house', price: 1000).update_column(:confidence_score, 5)
create(:budget_investment, :feasible, :finished, budget: budget, group: group, heading: heading, title: 'Build a skyscraper', price: 20000)
visit budget_investments_path(budget_id: budget.id)
visit budget_investments_path(budget, heading_id: heading.id)
click_link 'by price'
expect(page).to have_selector('a.active', text: 'by price')
@@ -344,11 +327,7 @@ feature 'Budget Investments' do
sp1 = create(:budget_investment, :feasible, :finished, budget: budget, group: group, heading: heading, price: 10000)
login_as(user)
visit root_path
first(:link, "Participatory budgeting").click
click_link budget.name
click_link "No Heading"
visit budget_investments_path(budget, heading_id: heading.id)
click_link sp1.title

View File

@@ -0,0 +1,109 @@
require 'rails_helper'
feature 'Votes' do
background do
@manuela = create(:user, verified_at: Time.now)
end
feature 'Investments' do
let(:budget) { create(:budget, phase: "selecting") }
let(:group) { create(:budget_group, budget: budget) }
let(:heading) { create(:budget_heading, group: group) }
background { login_as(@manuela) }
feature 'Index' do
scenario "Index shows user votes on proposals" do
investment1 = create(:budget_investment, heading: heading)
investment2 = create(:budget_investment, heading: heading)
investment3 = create(:budget_investment, heading: heading)
create(:vote, voter: @manuela, votable: investment1, vote_flag: true)
visit budget_investments_path(budget, heading_id: heading.id)
within("#budget-investments") do
within("#budget_investment_#{investment1.id}_votes") do
expect(page).to have_content "You have already supported this. Share it!"
end
within("#budget_investment_#{investment2.id}_votes") do
expect(page).to_not have_content "You have already supported this. Share it!"
end
within("#budget_investment_#{investment3.id}_votes") do
expect(page).to_not have_content "You have already supported this. Share it!"
end
end
end
scenario 'Create from spending proposal index', :js do
investment = create(:budget_investment, heading: heading, budget: budget)
visit budget_investments_path(budget, heading_id: heading.id)
within('.supports') do
find('.in-favor a').click
expect(page).to have_content "1 support"
expect(page).to have_content "You have already supported this. Share it!"
end
end
end
feature 'Single spending proposal' do
background do
@investment = create(:budget_investment, budget: budget)
end
scenario 'Show no votes' do
visit budget_investment_path(budget, @investment)
expect(page).to have_content "No supports"
end
scenario 'Trying to vote multiple times', :js do
visit budget_investment_path(budget, @investment)
within('.supports') do
find('.in-favor a').click
expect(page).to have_content "1 support"
expect(page).to_not have_selector ".in-favor a"
end
end
scenario 'Create from proposal show', :js do
visit budget_investment_path(budget, @investment)
within('.supports') do
find('.in-favor a').click
expect(page).to have_content "1 support"
expect(page).to have_content "You have already supported this. Share it!"
end
end
end
scenario 'Disable voting on spending proposals', :js do
login_as(@manuela)
budget.update(phase: "on_hold")
investment = create(:budget_investment, budget: budget, heading: heading)
visit budget_investments_path(budget, heading_id: heading.id)
within("#budget_investment_#{investment.id}") do
find("div.supports").hover
expect_message_selecting_not_allowed
end
visit budget_investment_path(budget, investment)
within("#budget_investment_#{investment.id}") do
find("div.supports").hover
expect_message_selecting_not_allowed
end
end
end
end

View File

@@ -434,25 +434,26 @@ feature 'Votes' do
end
end
end
end
scenario 'Disable voting on spending proposals', :js do
login_as(@manuela)
Setting["feature.spending_proposal_features.voting_allowed"] = nil
spending_proposal = create(:spending_proposal)
scenario 'Disable voting on spending proposals', :js do
login_as(@manuela)
Setting["feature.spending_proposal_features.voting_allowed"] = nil
spending_proposal = create(:spending_proposal)
visit spending_proposals_path
visit spending_proposals_path
within("#spending_proposal_#{spending_proposal.id}") do
find("div.supports").hover
expect_message_voting_not_allowed
end
within("#spending_proposal_#{spending_proposal.id}") do
find("div.supports").hover
expect_message_voting_not_allowed
end
visit spending_proposal_path(spending_proposal)
visit spending_proposal_path(spending_proposal)
within("#spending_proposal_#{spending_proposal.id}") do
find("div.supports").hover
expect_message_voting_not_allowed
within("#spending_proposal_#{spending_proposal.id}") do
find("div.supports").hover
expect_message_voting_not_allowed
end
end
end
end

View File

@@ -159,6 +159,11 @@ module CommonActions
expect(page).to have_selector('.in-favor a', visible: false)
end
def expect_message_you_need_to_sign_in_to_ballot
expect(page).to have_content 'Not Logged In'
expect(page).to have_selector('.in-favor a', visible: false)
end
def expect_message_you_need_to_sign_in_to_vote_comments
expect(page).to have_content 'You must Sign in or Sign up to vote'
expect(page).to have_selector('.logged', visible: false)
@@ -175,11 +180,27 @@ module CommonActions
expect(page).to have_selector('.in-favor a', visible: false)
end
def expect_message_only_verified_can_vote_investments
expect(page).to have_content 'Not Verified'
expect(page).to have_selector('.in-favor a', visible: false)
end
def expect_message_voting_not_allowed
expect(page).to have_content 'Voting phase is closed'
expect(page).to_not have_selector('.in-favor a')
end
def expect_message_selecting_not_allowed
expect(page).to have_content 'No Selecting Allowed'
expect(page).to_not have_selector('.in-favor a')
end
def expect_message_organizations_cannot_vote
#expect(page).to have_content 'Organisations are not permitted to vote.'
expect(page).to have_content 'Organization'
expect(page).to have_selector('.in-favor a', visible: false)
end
def create_featured_proposals
[create(:proposal, :with_confidence_score, cached_votes_up: 100),
create(:proposal, :with_confidence_score, cached_votes_up: 90),