Merge from jdong, XMLRPC changes and testcases
[selectricity-live] / app / models / election.rb
1 class Election < ActiveRecord::Base
2   has_many :candidates
3   has_many :voters
4   has_many :votes
5   belongs_to :user
6   validates_presence_of :name, :description
7   
8   attr_reader :plurality_result
9   attr_reader :approval_result
10   attr_reader :condorcet_result
11   attr_reader :ssd_result
12   attr_reader :borda_result
13
14   require 'date'
15
16   def startdate
17     read_attribute( :startdate ) || Time.now
18   end
19   
20   def enddate
21     date = read_attribute( :enddate ) || Time.now + 14
22     date - 1.second
23   end
24
25   def enddate=(date)
26     date += 1.day
27     date = Time.gm(*date)
28     super(date)
29   end
30
31   def votes
32     votes = Array.new
33     self.voters.each do |voter|
34       votes << voter.vote
35     end
36     return votes
37   end
38
39   def destroy
40     self.candidates.each do |candidate|
41       candidate.destroy
42     end
43     super
44   end
45
46   def start_blockers
47     reasons = []
48     
49     if self.candidates.length <= 1
50       reasons << "You must have at least two candidates."
51     end
52     
53     if self.voters.length <= 1
54       reasons << "You must have at least two voters."
55     end
56
57     reasons
58   end
59
60   def activate!
61     self.active = 1
62     self.save!
63   end
64   
65   def quickvote?
66     self.class == 'QuickVote'
67   end
68
69   def active?
70     active == 1
71   end 
72
73   def done?
74     active == 2
75   end
76
77   def shortdesc
78     shortdesc = description.split(/\n/)[0]
79   end
80
81   def longdesc
82     longdesc = description.split(/\n/)[1..-1].join("")
83     longdesc.length > 0 ? longdesc : nil 
84   end
85   
86   #Calculate Election Results
87   def results
88     # initalize the tallies to empty arrays
89     preference_tally = Array.new
90     plurality_tally = Array.new
91     approval_tally = Array.new
92
93     self.voters.each do |voter|
94       # skip if the voter has not voted or has an unconfirmed vote
95       next unless voter.voted?
96
97       plurality_tally << voter.vote.rankings.sort[0].candidate.id
98       approval_tally << voter.vote.rankings.sort[0..1].collect \
99         { |ranking| ranking.candidate.id }
100       preference_tally << voter.vote.rankings.sort.collect \
101         { |ranking| ranking.candidate.id }
102     end
103     @plurality_result = PluralityVote.new(plurality_tally).result
104     @approval_result = ApprovalVote.new(approval_tally).result
105     @condorcet_result = PureCondorcetVote.new(preference_tally).result
106     @ssd_result = CloneproofSSDVote.new(preference_tally).result
107     @borda_result = BordaVote.new(preference_tally).result
108     #@runoff_result = InstantRunoffVote.new(preference_tally).result
109     
110     nil # to stay consistent
111   end
112   
113   def names_by_id
114     names = Hash.new
115     
116     competitors = self.candidates.sort.collect {|candidate| candidate.id}
117     competitors.each do |candidate|
118       names[candidate] = Candidate.find(candidate).name
119     end
120     
121     names
122   end
123   
124 end
125
126

Benjamin Mako Hill || Want to submit a patch?