Skip to content

Commit

Permalink
Merge pull request consuldemocracy#1776 from AyuntamientoMadrid/spend…
Browse files Browse the repository at this point in the history
…ing_proposals

Migrate spending proposal
  • Loading branch information
voodoorai2000 authored Mar 13, 2019
2 parents fb6d68b + 25e2458 commit e498612
Show file tree
Hide file tree
Showing 38 changed files with 1,771 additions and 107 deletions.
8 changes: 6 additions & 2 deletions app/controllers/budgets/results_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ class ResultsController < ApplicationController
def show
authorize! :read_results, @budget
@investments = Budget::Result.new(@budget, @heading).investments
@headings = @budget.headings.sort_by_name
end

private
Expand All @@ -18,10 +19,13 @@ def load_budget

def load_heading
if @budget.present?
headings = @budget.headings
@heading = headings.find_by_slug_or_id(params[:heading_id]) || headings.first
@heading = @budget.headings.find_by_slug_or_id(params[:heading_id]) || default_heading
end
end

def default_heading
@budget.city_heading || @budget.headings.first
end

end
end
1 change: 1 addition & 0 deletions app/controllers/budgets/stats_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ class StatsController < ApplicationController
def show
authorize! :read_stats, @budget
@stats = load_stats
@headings = @budget.headings.sort_by_name
end

private
Expand Down
56 changes: 35 additions & 21 deletions app/controllers/spending_proposals_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,9 @@ def stats
def results
@geozone = daily_cache("geozone_geozone_#{params[:geozone_id]}") { params[:geozone_id].blank? || params[:geozone_id] == 'all' ? nil : Geozone.find(params[:geozone_id]) }
@delegated_ballots = daily_cache("delegated_geozone_#{params[:geozone_id]}") { Forum.delegated_ballots }
@spending_proposals = daily_cache("sps_geozone_#{params[:geozone_id]}") { SpendingProposal.feasible.compatible.valuation_finished.by_geozone(params[:geozone_id]) }
@spending_proposals = daily_cache("sorted_sps_geozone_#{params[:geozone_id]}") { SpendingProposal.sort_by_delegated_ballots_and_price(@spending_proposals, @delegated_ballots) }

@initial_budget = daily_cache("initial_budget_geozone_#{params[:geozone_id]}") { Ballot.initial_budget(@geozone) }
@incompatibles = daily_cache("incompatibles_geozone_#{params[:geozone_id]}") { SpendingProposal.incompatible.by_geozone(params[:geozone_id]) }
@spending_proposals = daily_cache("sorted_sps_geozone_#{params[:geozone_id]}") { Budget::Result.new(budget_2016, heading_for_geozone(params[:geozone_id])).investments }
@initial_budget = daily_cache("initial_budget_geozone_#{params[:geozone_id]}") { heading_for_geozone(params[:geozone_id]).price }
@incompatibles = daily_cache("incompatibles_geozone_#{params[:geozone_id]}") { budget_2016.investments.incompatible.by_heading(heading_for_geozone(params[:geozone_id])) }
end

private
Expand Down Expand Up @@ -178,7 +176,7 @@ def total_participants_with_gender

def participants
stats_cache('participants') do
users = (authors + voters + balloters + delegators).uniq
users = (authors + voters + balloters).uniq
User.where(id: users)
end
end
Expand All @@ -197,60 +195,59 @@ def total_participants_vote_phase

def total_supports
stats_cache('total_supports') do
ActsAsVotable::Vote.where(votable_type: 'SpendingProposal').count
budget_investment_supports.count
end
end

def total_votes
stats_cache('total_votes') do
BallotLine.count
budget_2016.lines.count
end
end

def authors
stats_cache('authors') { SpendingProposal.pluck(:author_id) }
stats_cache('authors') { budget_2016.investments.pluck(:author_id) }
end

def voters
stats_cache('voters') { ActsAsVotable::Vote.where(votable_type: 'SpendingProposal').pluck(:voter_id) }
stats_cache("voters") { budget_investment_supports.pluck(:voter_id) }
end

def voters_by_geozone(geozone_id)
stats_cache("voters_geozone_#{geozone_id}") do
ActsAsVotable::Vote.where(votable_type: 'SpendingProposal', votable_id: SpendingProposal.by_geozone(geozone_id)).pluck(:voter_id)
heading = heading_for_geozone(geozone_id)
ActsAsVotable::Vote.where(votable_type: "Budget::Investment",
votable_id: budget_2016.investments.by_heading(heading.id))
.pluck(:voter_id)
end
end

def balloters
stats_cache('balloters') do
Ballot.where('ballot_lines_count > ?', 0).pluck(:user_id)
budget_2016.ballots.where("ballot_lines_count > ?", 0).pluck(:user_id)
end
end

def balloters_by_geozone(geozone_id)
stats_cache("balloters_geozone_#{geozone_id}") do
Ballot.where('ballot_lines_count > ? AND geozone_id = ?', 0, geozone_id).pluck(:user_id)
budget_2016.lines.where(heading_id: heading_for_geozone(geozone_id).id).pluck(:user_id).uniq
end
end

def delegators
stats_cache('delegators') { User.where.not(representative_id: nil).pluck(:id) }
end

def total_spending_proposals
stats_cache('total_spending_proposals') { SpendingProposal.count }
stats_cache('total_spending_proposals') { budget_2016.investments.count }
end

def paper_spending_proposals
112
end

def total_feasible_spending_proposals
stats_cache('total_feasible_spending_proposals') { SpendingProposal.feasible.count }
stats_cache('total_feasible_spending_proposals') { budget_2016.investments.feasible.count }
end

def total_unfeasible_spending_proposals
stats_cache('total_unfeasible_spending_proposals') { SpendingProposal.unfeasible.count }
stats_cache('total_unfeasible_spending_proposals') { budget_2016.investments.unfeasible.count }
end

def total_male_participants
Expand Down Expand Up @@ -356,8 +353,25 @@ def total_unknown_gender_or_age
end
end

def budget_2016
Budget.where(slug: "2016").first
end

def budget_investment_supports
ActsAsVotable::Vote.where(votable: budget_2016.investments)
end

def heading_for_geozone(geozone_id)
if geozone_id == nil
budget_2016.headings.where(name: "Toda la ciudad").first
else
geozone = Geozone.find(geozone_id)
budget_2016.headings.where(name: geozone.name).first
end
end

def stats_cache(key, &block)
Rails.cache.fetch("spending_proposals_stats/201607131316/#{key}", &block)
Rails.cache.fetch("spending_proposals_stats/20190206172211/#{key}", &block)
end

end
14 changes: 7 additions & 7 deletions app/models/budget/ballot/line.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class Line < ActiveRecord::Base
scope :by_investment, ->(investment_id) { where(investment_id: investment_id) }

before_validation :set_denormalized_ids
after_save :store_user_heading
#after_save :store_user_heading

def check_sufficient_funds
errors.add(:money, "insufficient funds") if ballot.amount_available(investment.heading) < investment.price.to_i
Expand All @@ -31,13 +31,13 @@ def check_selected
errors.add(:investment, "unselected investment") unless investment.selected?
end

private
def set_denormalized_ids
self.heading_id ||= investment.try(:heading_id)
self.group_id ||= investment.try(:group_id)
self.budget_id ||= investment.try(:budget_id)
end

def set_denormalized_ids
self.heading_id ||= investment.try(:heading_id)
self.group_id ||= investment.try(:group_id)
self.budget_id ||= investment.try(:budget_id)
end
private

def store_user_heading
return if heading.city_heading?
Expand Down
2 changes: 1 addition & 1 deletion app/models/budget/stats.rb
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,6 @@ def supports(supportable)
stats_cache :voters, :participants, :authors, :balloters, :poll_ballot_voters

def stats_cache(key, &block)
Rails.cache.fetch("budgets_stats/#{budget.id}/#{key}/v10", &block)
Rails.cache.fetch("budgets_stats/#{budget.id}/#{key}/v13", &block)
end
end
2 changes: 1 addition & 1 deletion app/models/comment.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class Comment < ActiveRecord::Base

validates :commentable_type, inclusion: { in: COMMENTABLE_TYPES }

validate :validate_body_length
validate :validate_body_length, unless: -> { valuation }
validate :comment_valuation, if: -> { valuation }

belongs_to :commentable, -> { with_hidden }, polymorphic: true, counter_cache: true
Expand Down
18 changes: 1 addition & 17 deletions app/models/spending_proposal.rb
Original file line number Diff line number Diff line change
Expand Up @@ -151,23 +151,7 @@ def feasible_explanation_required?
end

def total_votes
cached_votes_up + physical_votes + delegated_votes - forum_votes
end

def delegated_votes
count = 0
representative_voters.each do |voter|
count += voter.forum.represented_users.select { |u| !u.voted_for?(self) }.count
end
return count
end

def representative_voters
Vote.representative_votes.for_spending_proposals(self).collect(&:voter)
end

def forum_votes
Vote.representative_votes.for_spending_proposals(self).count
cached_votes_up + physical_votes
end

def code
Expand Down
4 changes: 2 additions & 2 deletions app/views/budgets/results/show.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@
<h3 class="margin-bottom">
<%= t("budgets.results.heading_selection_title") %>
</h3>
<ul class="menu vertical no-margin-top no-padding-top">
<% @budget.headings.order('id ASC').each do |heading| %>
<ul id="headings" class="menu vertical no-margin-top no-padding-top">
<% @headings.each do |heading| %>
<li>
<%= link_to heading.name,
custom_budget_heading_result_path(@budget, heading_id: heading.to_param),
Expand Down
4 changes: 2 additions & 2 deletions app/views/budgets/stats/show.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -201,8 +201,8 @@
<th scope="col" class="tiny"><%= t("budgets.stats.percent_heading_census_html") %></th>
</tr>
</thead>
<tbody>
<% @budget.headings.order('id ASC').each do |heading| %>
<tbody id="headings">
<% @headings.each do |heading| %>
<tr id="<%= heading.name.parameterize %>">
<td class="border-left">
<strong><%= heading.name %></strong>
Expand Down
13 changes: 4 additions & 9 deletions app/views/custom/budgets/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -162,15 +162,10 @@
</div>
<div class="small-12 medium-6 column table" data-equalizer-watch>
<div id="budget_<%= budget.id %>_results" class="table-cell align-middle">
<% if budget.name == "Presupuestos Participativos 2016" %>
<%= link_to t("budgets.index.see_results"),
participatory_budget_results_path,
class: "button" %>
<% else %>
<%= link_to t("budgets.index.see_results"),
custom_budget_results_path(budget),
class: "button" %>
<% end %>
<%= link_to t("budgets.index.see_results"),
custom_budget_results_path(budget),
class: "button" %>

<% unless budget.name == "Presupuestos Participativos 2018" %>
<%= link_to t("budgets.index.milestones"),
custom_budget_executions_path(budget, status: 1),
Expand Down
5 changes: 5 additions & 0 deletions db/migrate/20190116152624_add_delegated_to_votes.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddDelegatedToVotes < ActiveRecord::Migration
def change
add_column :votes, :delegated, :boolean, default: false
end
end
1 change: 1 addition & 0 deletions db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1785,6 +1785,7 @@
t.datetime "created_at"
t.datetime "updated_at"
t.integer "signature_id"
t.boolean "delegated", default: false
end

add_index "votes", ["signature_id"], name: "index_votes_on_signature_id", using: :btree
Expand Down
7 changes: 7 additions & 0 deletions lib/migrations/log.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module Migrations::Log

def log(message)
print message unless Rails.env.test?
end

end
92 changes: 92 additions & 0 deletions lib/migrations/spending_proposal/ballot.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
require_dependency "budget"
require_dependency "budget/ballot"

class Migrations::SpendingProposal::Ballot
include Migrations::Log

attr_accessor :spending_proposal_ballot, :budget_investment_ballot, :represented_user

def initialize(spending_proposal_ballot, represented_user=nil)
@represented_user = represented_user
@spending_proposal_ballot = spending_proposal_ballot
@budget_investment_ballot = find_or_initialize_budget_investment_ballot
end

def migrate_ballot
return if user_already_voted?

if budget_investment_ballot.save
log(".")
migrate_ballot_lines
else
log("\nError creating budget investment ballot from spending proposal ballot #{spending_proposal_ballot.id}\n")
end
end

def migrate_ballot_lines
spending_proposal_ballot.spending_proposals.each do |spending_proposal|
budget_investment = find_budget_investment(spending_proposal)

if budget_investment.blank?
log("Budget investment not found for spending proposal #{spending_proposal.id}")
next
end

ballot_line = find_or_initialize_ballot_line(budget_investment)
if ballot_line_saved?(ballot_line)
log(".")
else
log("Error adding spending proposal: #{spending_proposal.id} to ballot: #{budget_investment_ballot.id}\n")
log(ballot_line.errors.messages)
end
end
end

private

def budget
Budget.where(slug: "2016").first
end

def find_budget_investment(spending_proposal)
budget.investments.where(original_spending_proposal_id: spending_proposal.id).first
end

def find_or_initialize_budget_investment_ballot
Budget::Ballot.find_or_initialize_by(budget_investment_ballot_attributes)
end

def find_or_initialize_ballot_line(investment)
return nil if investment.blank?

attributes = { ballot: budget_investment_ballot, investment: investment }
budget_investment_ballot.lines.where(attributes).first_or_initialize
end

def user_already_voted?
budget_investment_ballot.ballot_lines_count > 0 && represented_user
end

def ballot_line_saved?(ballot_line)
return true if ballot_line_exists?(ballot_line)

ballot_line.set_denormalized_ids
ballot_line.save(validate: false)
end

def ballot_line_exists?(ballot_line)
budget_investment_ballot.investments.include?(ballot_line.investment)
end

def budget_investment_ballot_attributes
{
budget_id: budget.id,
user_id: user_id
}
end

def user_id
represented_user.try(:id) || spending_proposal_ballot.user_id
end

end
Loading

0 comments on commit e498612

Please sign in to comment.