fix security issue
[selectricity] / 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. Please see the COPYING file for
6 # details.
7
8 class Vote < ActiveRecord::Base
9   # relationships to other classes
10   belongs_to :voter
11   has_many :rankings
12   has_one :token
13   
14   # callbacks
15   after_update :save_rankings
16   before_destroy :destroy_rankings
17   
18   def to_s
19     votes.join("")
20   end
21
22   def each
23     self.votes.each {|vote| yield vote}
24   end
25
26   def votes
27     unless @votes
28       if rankings.empty?
29         @votes = Array.new
30       else
31         @votes = self.rankings.sort.collect { |ranking| ranking.candidate.id }
32       end
33     end
34
35     @votes
36   end
37
38   def votes=(array)
39     @votes = array
40   end
41
42   def save_rankings
43     self.votes # i need to initalize this before destroying rankings
44                # or else the ranks themselves show up as nil
45
46     destroy_rankings
47     self.votes.each_with_index do |candidate_id, index| 
48       ranking = Ranking.new
49       ranking.rank = index
50       ranking.candidate =  Candidate.find(candidate_id)
51       self.rankings << ranking
52     end
53   end
54   
55   def destroy
56     self.destroy_rankings
57     super
58   end
59
60   def destroy_rankings 
61     rankings.each { |ranking| ranking.destroy }
62   end
63
64   def confirm!
65     if self.voter.election.candidates.length == self.rankings.length
66       self.confirmed = 1
67       self.time = Time.now
68       self.save
69     
70       unless self.voter.election.quickvote?
71         token.destroy and token.reload if token
72         self.token = Token.new
73         self.save
74       end
75       return false
76     else
77       return true
78     end
79   end
80
81   def confirm?
82     confirmed == 1
83   end
84   
85   def votestring
86     # create a mapping of candidates ids and the relative order of the
87     # candidates as they appear when sorted alphabetically
88     cand_relnums = {}
89     self.voter.election.candidates.sort.each_with_index do |c, i|
90       cand_relnums[c.id] = i + 1
91     end
92
93     # assemble the votestring
94     self.votes.collect {|v| (cand_relnums[v] + 64).chr}.join("")
95   end
96
97   # the following subroutine is used for quickvotes, but need for elections now
98   # too. It creates a vote with the candidates listed in order of preference 
99   # based on alphabetical order. Meant to be manipulated and then confirmed
100   def set_defaults!  
101     self.votes = self.voter.election.candidates.sort_by { rand }.collect {|c| c.id }
102     self.save
103   end
104          
105 end

Benjamin Mako Hill || Want to submit a patch?