Added a check to make sure a voter has a valid email address before attempting ot...
[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   end
80
81   def start_election
82     @election = Election.find(params[:id])
83     
84     @election.voters.each do |voter|
85       voter.vote = Vote.new
86       email_voter voter unless voter.email.nil?
87     end
88
89     @election.activate!
90     redirect_to :action => 'show', :id => @election.id
91   end
92
93   # methods fod display, adding, deleting, and manipulating candidate
94   # information for elections
95   ####################################################################
96   def edit_candidates
97     @sidebar_content = render_to_string :partial => 'progress',
98                                         :locals => { :page => 'candidates' }
99     @election = Election.find( params[:id] )
100   end
101
102   def add_candidate
103     @election = Election.find(params[:id])
104     @candidate = Candidate.new(params[:candidate])
105     @election.candidates << @candidate
106
107     if @candidate.save
108       # check to see if they've uploaded a picture
109       if params[:picture][:uploaded_data]
110         picture = Picture.new(params[:picture])
111         @candidate.picture = picture if picture.save
112       end
113
114       @candidate = Candidate.new
115       redirect_to :action => 'edit_candidates', :id => @election.id
116     else
117       render :action => 'edit_candidates', :id => @election.id
118     end
119   end
120   
121   def delete_candidate
122     candidate = Candidate.find( params[:id] )
123     candidate.destroy
124   end
125
126   def candidate_picture
127     candidate = Candidate.find( params[:id] )
128     send_data( candidate.picture.data,
129                :filename => candidate.picture.filename,
130                :type => candidate.picture.filetype,
131                :disposition => 'inline' )
132   end
133
134   ## methods for displaying, adding, deleting, and manipulating voters
135   ## for a particular election
136   ####################################################################
137   def new_voters
138     redirect_to :action => 'edit_voters', :id => params[:id]
139   end
140   
141   def edit_voters
142     @sidebar_content = render_to_string :partial => 'progress',
143                                         :locals => { :page => 'voters' }
144
145     @election = Election.find( params[:id] )
146     if params.has_key?( :raw_voter_list )
147       process_incoming_voters( params[:raw_voter_list] )
148     end
149     @raw_voter_list = RawVoterList.new
150   end
151   
152   def delete_voter
153     voter = Voter.find( params[:id] )
154     voter.destroy
155   end
156
157   def toggle_authenticated
158     @election = Election.find(params[:id])
159     if params[:authenticated] == "1"
160       @election.authenticated = true
161     else
162       @election.authenticated = false
163     end
164     @election.save
165   end
166   
167   ## methods for computing and printing results
168   ####################################################################
169   def results
170     @election = Election.find( params[:id] )
171     votes = []
172
173     @election.voters.each do |voter|
174       if voter.vote and voter.vote.confirmed?
175         votes << voter.vote.rankings.sort.collect {|vote| vote.candidate_id}
176       end
177     end
178     
179     @voteobj = CloneproofSSDVote.new(votes)
180     @resultobj = @voteobj.result
181     @winners = @resultobj.winners
182     
183     @candidates_by_id = {}
184     @election.candidates.each {|cand| @candidates_by_id[cand.id] = cand}
185   end
186   
187   def detailed_results
188    
189     self.results
190
191     @voter_list = []
192     @vote_list = []
193     @election.voters. each do |voter|
194       if voter.vote and voter.vote.confirmed?
195         @voter_list << voter.email
196               @vote_list << voter.vote
197       end
198     end
199
200     @vote_list.sort!
201     @vote_list.sort! { |a,b| a.token <=> b.token }
202   end
203
204   ## private methods
205   ####################################################################
206   private
207
208     def process_incoming_voters(raw_voter_list)
209       incoming_voters = RawVoterList.new( raw_voter_list )
210
211       unless incoming_voters.entries.empty?
212         incoming_voters.each do |new_voter|
213           new_voter.email.strip! # There's a trailing \r on all but the last in
214                                  # the list!
215           if new_voter.valid?
216             # the new voter should be in good shape. save add to the election
217             @election.voters << new_voter
218                   new_voter.save
219           end
220           # TODO: Can we do some kind of AJAX error message for the voter being invalid?
221         end
222         @election.save
223       end
224  
225       # reset the next time to have a the same default value for emailing
226       @raw_voter_list = RawVoterList.new
227       @raw_voter_list.email = incoming_voters.email
228     end
229
230     def email_voter(voter=nil)
231       if voter
232         VoterNotify.deliver_votestart(voter)
233         voter.contacted=1
234         voter.save
235       end
236     end
237
238 end

Benjamin Mako Hill || Want to submit a patch?