input license information so that the work can be under the AGPLv3
[selectricity-live] / app / models / vote.rb
1 # Selectricity: Voting Machinery for the Masses
2 # Copyright (C) 2007, 2008 Benjamin Mako Hill <mako@atdot.cc>
3 # Copyright (C) 2007 Massachusetts Institute of Technology
4 #
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License as
7 # published by the Free Software Foundation, either version 3 of the
8 # License, or (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 # Affero General Public License for more details.
14 #
15 # You should have received a copy of the GNU Affero General Public
16 # License along with this program.  If not, see
17 # <http://www.gnu.org/licenses/>.
18
19 class Vote < ActiveRecord::Base
20   # relationships to other classes
21   belongs_to :voter
22   has_many :rankings
23   has_one :token
24   
25   # callbacks
26   after_update :save_rankings
27   before_destroy :destroy_rankings
28   
29   def to_s
30     votes.join("")
31   end
32
33   def each
34     self.votes.each {|vote| yield vote}
35   end
36
37   def votes
38     unless @votes
39       if rankings.empty?
40         @votes = Array.new
41       else
42         @votes = rankings.sort.collect { |ranking| ranking.candidate.id }
43       end
44     end
45
46     @votes
47   end
48
49   def votes=(array)
50     @votes = array
51   end
52
53   def save_rankings
54     destroy_rankings
55     self.votes.each_with_index do |candidate_id, index| 
56       ranking = Ranking.new
57       ranking.rank = index
58       ranking.candidate =  Candidate.find(candidate_id)
59       self.rankings << ranking
60     end
61   end
62   
63   def destroy
64     self.destroy_rankings
65     super
66   end
67
68   def destroy_rankings 
69     rankings.each { |ranking| ranking.destroy }
70   end
71
72   def settime
73     self.time = Time.now
74     self.save
75   end
76
77   def confirm!
78     self.confirmed = 1
79     self.save
80     
81     unless self.voter.election.quickvote?
82       token.destroy and token.reload if token
83       self.token = Token.new
84       self.save
85     end
86   end
87
88   def confirm?
89     confirmed == 1
90   end
91   
92   def votestring
93     # create a mapping of candidates ids and the relative order of the
94     # candidates as they appear when sorted alphabetically
95     cand_relnums = {}
96     self.voter.election.candidates.sort.each_with_index do |c, i|
97       cand_relnums[c.id] = i + 1
98     end
99
100     # assemble the votestring
101     self.votes.collect {|v| (cand_relnums[v] + 64).chr}.join("")
102   end
103
104   # the following subroutine is used for quickvotes, but need for elections now
105   # too. It creates a vote with the candidates listed in order of preference 
106   # based on alphabetical order. Meant to be manipulated and then confirmed
107   def set_defaults!  
108     self.votes = voter.election.candidates.sort.collect {|c| c.id }
109     self.save
110   end
111          
112 end

Benjamin Mako Hill || Want to submit a patch?