]> projects.mako.cc - selectricity-live/blob - app/controllers/election_controller.rb
571b93628e7e916f2dd4e2228e91c02729c5344d
[selectricity-live] / 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     
190   end
191   
192   def detailed_results
193    
194     self.results
195
196     @voter_list = []
197     @vote_list = []
198     
199     @election.voters.each do |voter|
200       if voter.vote and voter.vote.confirmed?
201         @voter_list << voter.email
202               @vote_list << voter.vote
203       end
204     end
205
206     @vote_list.sort!
207     @vote_list.sort! { |a,b| a.token <=> b.token }
208   end
209
210   ## private methods
211   ####################################################################
212   private
213
214     def process_incoming_voters(raw_voter_list)
215       incoming_voters = RawVoterList.new( raw_voter_list )
216
217       unless incoming_voters.entries.empty?
218         incoming_voters.each do |new_voter|
219           new_voter.email.strip! # There's a trailing \r on all but the last in
220                                  # the list!
221           if new_voter.valid?
222             # the new voter should be in good shape. save add to the election
223             @election.voters << new_voter
224                   new_voter.save
225           end
226           # TODO: Can we do some kind of AJAX error message for the voter being invalid?
227         end
228         @election.save
229       end
230  
231       # reset the next time to have a the same default value for emailing
232       @raw_voter_list = RawVoterList.new
233       @raw_voter_list.email = incoming_voters.email
234     end
235
236     def email_voter(voter=nil)
237       if voter
238         VoterNotify.deliver_votestart(voter)
239         voter.contacted=1
240         voter.save
241       end
242     end
243
244 end

Benjamin Mako Hill || Want to submit a patch?