QuickVotes are now displayed in the control panel list - and you can click on
[selectricity] / app / controllers / election_controller.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 ElectionController < ApplicationController
20   require_dependency "raw_voter_list"
21   require_dependency "voter"
22   require_dependency "vote"
23   require_dependency "candidate"
24   layout 'main'
25
26   ## methods for displaying, creating,
27   ## and manipulating election overview data
28   ####################################################################
29
30   def new
31     redirect_to :action => 'general_information'
32   end
33   
34   def general_information
35     @sidebar_content = render_to_string :partial => 'progress',
36                                         :locals => { :page => 'overview' }
37     @election = Election.new
38     render :action => 'general_information'
39   end
40   
41   def create_election
42     @election = Election.new(params[:election])
43     
44     # default options
45     @election.user = session[:user]
46     @election.anonymous = 1
47     @election.startdate = Time.now
48
49     if @election.save
50       flash[:notice] = 'Election was successfully created.'
51       redirect_to :action => 'edit_candidates', :id => @election.id
52     else
53       render :action => 'general_information'
54     end
55   end
56   
57   # TODO add filter to verify that the person working on or looking at
58   # something is the owner
59   def edit_general_information
60     @election = Election.find(params[:id])
61   end
62   
63   def update_general_information
64     @election = Election.find(params[:id])
65     if @election.update_attributes(params[:election])
66       flash[:notice] = 'Election was successfully updated.'
67       redirect_to :action => 'show', :id => @election
68     else
69       render :action => 'edit'
70     end
71   end
72
73
74   def show
75     @sidebar_content = render_to_string :partial => 'progress',
76                                         :locals => { :page => 'review' }
77
78     @election = Election.find(params[:id])
79     if @election.type == QuickVote
80       redirect_to(:controller => 'quickvote', :action => 'index', :ident => @election.id)
81     end
82       
83   end
84
85   def start_election
86     @election = Election.find(params[:id])
87     
88     @election.voters.each do |voter|
89       voter.vote = Vote.new
90       email_voter voter unless voter.email.nil?
91     end
92
93     @election.activate!
94     redirect_to :action => 'show', :id => @election.id
95   end
96
97   # methods fod display, adding, deleting, and manipulating candidate
98   # information for elections
99   ####################################################################
100   def edit_candidates
101     @sidebar_content = render_to_string :partial => 'progress',
102                                         :locals => { :page => 'candidates' }
103     @election = Election.find( params[:id] )
104   end
105
106   def add_candidate
107     @election = Election.find(params[:id])
108     @candidate = Candidate.new(params[:candidate])
109     @election.candidates << @candidate
110
111     if @candidate.save
112       # check to see if they've uploaded a picture
113       if params[:picture][:uploaded_data]
114         picture = Picture.new(params[:picture])
115         @candidate.picture = picture if picture.save
116       end
117
118       @candidate = Candidate.new
119       redirect_to :action => 'edit_candidates', :id => @election.id
120     else
121       render :action => 'edit_candidates', :id => @election.id
122     end
123   end
124   
125   def delete_candidate
126     candidate = Candidate.find( params[:id] )
127     candidate.destroy
128   end
129
130   def candidate_picture
131     candidate = Candidate.find( params[:id] )
132     send_data( candidate.picture.data,
133                :filename => candidate.picture.filename,
134                :type => candidate.picture.filetype,
135                :disposition => 'inline' )
136   end
137
138   ## methods for displaying, adding, deleting, and manipulating voters
139   ## for a particular election
140   ####################################################################
141   def new_voters
142     redirect_to :action => 'edit_voters', :id => params[:id]
143   end
144   
145   def edit_voters
146     @sidebar_content = render_to_string :partial => 'progress',
147                                         :locals => { :page => 'voters' }
148
149     @election = Election.find( params[:id] )
150     if params.has_key?( :raw_voter_list )
151       process_incoming_voters( params[:raw_voter_list] )
152     end
153     @raw_voter_list = RawVoterList.new
154   end
155   
156   def delete_voter
157     voter = Voter.find( params[:id] )
158     voter.destroy
159   end
160
161   def toggle_authenticated
162     @election = Election.find(params[:id])
163     if params[:authenticated] == "1"
164       @election.authenticated = true
165     else
166       @election.authenticated = false
167     end
168     @election.save
169   end
170   
171   ## methods for computing and printing results
172   ####################################################################
173   def results
174     @election = Election.find( params[:id] )
175     votes = []
176
177     @election.voters.each do |voter|
178       if voter.vote and voter.vote.confirmed?
179         votes << voter.vote.rankings.sort.collect {|vote| vote.candidate_id}
180       end
181     end
182     
183     @voteobj = CloneproofSSDVote.new(votes)
184     @resultobj = @voteobj.result
185     @winners = @resultobj.winners
186     
187     @candidates_by_id = {}
188     @election.candidates.each {|cand| @candidates_by_id[cand.id] = cand}
189   end
190   
191   def detailed_results
192    
193     self.results
194
195     @voter_list = []
196     @vote_list = []
197     @election.voters. each do |voter|
198       if voter.vote and voter.vote.confirmed?
199         @voter_list << voter.email
200               @vote_list << voter.vote
201       end
202     end
203
204     @vote_list.sort!
205     @vote_list.sort! { |a,b| a.token <=> b.token }
206   end
207
208   ## private methods
209   ####################################################################
210   private
211
212     def process_incoming_voters(raw_voter_list)
213       incoming_voters = RawVoterList.new( raw_voter_list )
214
215       unless incoming_voters.entries.empty?
216         incoming_voters.each do |new_voter|
217           new_voter.email.strip! # There's a trailing \r on all but the last in
218                                  # the list!
219           if new_voter.valid?
220             # the new voter should be in good shape. save add to the election
221             @election.voters << new_voter
222                   new_voter.save
223           end
224           # TODO: Can we do some kind of AJAX error message for the voter being invalid?
225         end
226         @election.save
227       end
228  
229       # reset the next time to have a the same default value for emailing
230       @raw_voter_list = RawVoterList.new
231       @raw_voter_list.email = incoming_voters.email
232     end
233
234     def email_voter(voter=nil)
235       if voter
236         VoterNotify.deliver_votestart(voter)
237         voter.contacted=1
238         voter.save
239       end
240     end
241
242 end

Benjamin Mako Hill || Want to submit a patch?