require_dependency "voter"
require_dependency "vote"
require_dependency "candidate"
+
+ helper :sparklines
layout 'main'
+
+ before_filter :verify_owner,
+ :except => [:new, :general_information, :create_election]
+ before_filter :verify_not_active,
+ :except => [:new, :general_information, :create_election,
+ :show, :results, :details, :pref_tables]
+
## methods for displaying, creating,
## and manipulating election overview data
####################################################################
end
end
- def create_theme_hash
- target = Hash.new
- params.each do |k,v|
- target[k] = v if k=="top_bar" or k=="default_image" or k=="bg1" \
- or k=="bg2" or k=="bottom_bar"
- end
- return target
- end
-
- # TODO add filter to verify that the person working on or looking at
- # something is the owner
def edit_general_information
+ @sidebar_content = render_to_string :partial => 'progress',
+ :locals => { :page => 'overview' }
@election = Election.find(params[:id])
end
flash[:notice] = 'Election was successfully updated.'
redirect_to :action => 'show', :id => @election
else
- render :action => 'edit'
+ render :action => 'edit_general_information'
end
end
def edit_candidates
@sidebar_content = render_to_string :partial => 'progress',
:locals => { :page => 'candidates' }
- @election = Election.find( params[:id] )
+ @election = Election.find(params[:id] )
end
def add_candidate
end
def delete_candidate
- candidate = Candidate.find( params[:id] )
+ candidate = Candidate.find(params[:candidate] )
candidate.destroy
end
def candidate_picture
- candidate = Candidate.find( params[:id] )
+ candidate = Candidate.find(params[:candidate])
send_data( candidate.picture.data,
:filename => candidate.picture.filename,
:type => candidate.picture.filetype,
@sidebar_content = render_to_string :partial => 'progress',
:locals => { :page => 'voters' }
- @election = Election.find( params[:id] )
+ @election = Election.find(params[:id])
+
if params.has_key?( :raw_voter_list )
process_incoming_voters( params[:raw_voter_list] )
end
end
def delete_voter
- voter = FullVoter.find( params[:id] )
+ voter = FullVoter.find(params[:voter])
voter.destroy
end
## methods for computing and printing results
####################################################################
def results
- @election = Election.find( params[:id] )
- votes = []
-
- @election.voters.each do |voter|
- if voter.vote and voter.vote.confirmed?
- votes << voter.vote.rankings.sort.collect {|vote| vote.candidate_id}
- end
+ @election = Election.find(params[:id])
+
+ if @election.early_results? \
+ or @election.enddate < Time.now
+
+ # render results
+ @sidebar_content = render_to_string(:partial => 'full_results_sidebar')
+ render :template => 'common/results'
+ else
+ redirect_to :action => 'index'
end
-
- @voteobj = CloneproofSSDVote.new(votes)
- @resultobj = @voteobj.result
- @winners = @resultobj.winners
-
- @candidates_by_id = {}
- @election.candidates.each {|cand| @candidates_by_id[cand.id] = cand}
-
end
- def detailed_results
-
- self.results
-
- @voter_list = []
- @vote_list = []
-
- @election.voters.each do |voter|
- if voter.vote and voter.vote.confirmed?
- @voter_list << voter.email
- @vote_list << voter.vote
- end
- end
+ def pref_tables
+ @election = Election.find(params[:id])
+ render :template => 'common/pref_tables_wrapper', :layout => 'basic'
+ end
- @vote_list.sort!
- @vote_list.sort! { |a,b| a.token <=> b.token }
+ def details
+ @election = Election.find(params[:id])
+ render :template => 'common/details'
end
## private methods
voter.save
end
end
+
+ def create_theme_hash
+ target = Hash.new
+ params.each do |k,v|
+ target[k] = v if k=="top_bar" or k=="default_image" or k=="bg1" \
+ or k=="bg2" or k=="bottom_bar"
+ end
+ return target
+ end
+
+ # verify that the person trying to edit the election is the owner
+ def verify_owner
+ election = Election.find(params[:id])
+ unless election.user == session[:user]
+ redirect_to :controller => 'front', :action => 'index'
+ end
+ end
+
+ # verify that the election is not active
+ def verify_not_active
+ election = Election.find(params[:id])
+ unless election.active == 0
+ redirect_to :controller => 'front', :action => 'index'
+ end
+ end
end
#Give registered users additional QuickVote functionality
@quickvote.user_id = session[:user][:id] if session[:user]
+ @quickvote.create_candidates
# try to save, if it fails, show the page again (the flash should
# still be intact
require_dependency "vote"
require_dependency "election"
+ before_filter :authenticate, :except => [:index, :login, :reminder,
+ :kiosk_ready]
+
def index
if params[:election_id]
@election = Election.find(params[:election_id])
end
end
- def pref_tables
- if authenticate
- @election = @voter.election
- @results = @election.results
- @candidates = {}
- @election.candidates.each {|c| @candidates[c.id] = c}
- @names = @election.names_by_id
- render :template => 'common/pref_tables', :layout => 'basic'
- else
- redirect_to :action => 'index'
- end
- end
-
- def details
- if authenticate
- @election = @voter.election
- @votes = @election.votes.select {|v| v.confirmed? }.shuffle
- @voters = @votes.collect {|v| v.voter}.shuffle
- render :action => 'details'
- else
- redirect_to :action => 'index'
- end
- end
-
def review
- if authenticate
- @voter.vote.time = Time.now
- @voter.vote.save
- @voter.reload
- else
- redirect_to :action => 'index'
- end
+ @voter.vote.time = Time.now
+ @voter.vote.save
+ @voter.reload
end
def confirm
- if authenticate
- @voter.vote.confirm!
-
- if @voter.election.embeddable? and params[:embed] == "true" \
- and @voter.election.early_results?
- redirect_to :action => :results, :id => @password, :embed => 'true'
- elsif @voter.election.kiosk and params[:kiosk] = "true"
- redirect_to :action => "kiosk_ready", :id => @password, :kiosk => true
- else
- render :action => 'thanks'
- end
+ @voter.vote.confirm!
+
+ if @voter.election.embeddable? and params[:embed] == "true" \
+ and @voter.election.early_results?
+ redirect_to :action => :results, :id => @password, :embed => 'true'
+ elsif not(@voter.election.verifiable) \
+ and @voter.election.kiosk and params[:kiosk] == "true"
+ redirect_to :action => "kiosk_ready", :id => @password, :kiosk => true
else
- redirect_to :action => 'index'
+ render :action => 'thanks'
end
end
end
def results
- if authenticate and
- (@voter.election.early_results? \
- or @voter.election.enddate < Time.now)
+ if @voter.election.early_results? \
+ or @voter.election.enddate < Time.now
@election = @voter.election
- # compute and display results
-
- @results = @election.results
- @candidates = {}
- @election.candidates.each {|c| @candidates[c.id] = c}
- @names = @election.names_by_id
-
- @sidebar_content = render_to_string(:partial => 'results_sidebar')
+ @sidebar_content = render_to_string(:partial => 'full_results_sidebar')
+
#look for custom theme, and assign to instance variabels for widget use
if @election.embed_custom_string
@top_bar = SkinPicture.find(:first,
if @election.embeddable? and params[:embed] == "true"
render :template => 'embed/results', :layout => 'embed'
else
- render :action => 'results'
+ render :template => 'common/results'
end
else
redirect_to :action => 'index'
end
end
+ def pref_tables
+ @election = @voter.election
+ render :template => 'common/pref_tables_wrapper', :layout => 'basic'
+ end
+
+ def details
+ @election = @voter.election
+ render :template => 'common/details'
+ end
+
def kiosk_ready
reset_session
if password == "open"
election = Election.find(params[:format])
- # check to see if the person has voted before
- unless election.authenticated?
+ # if it's not actually open, lets redirect
+ if election.authenticated
+ redirect_to :action => 'index'
+
+ # otherwise, lets see if they've before
+ else
@voter = OpenVoter.find(:all,
:conditions => ["session_id = ? and election_id = ?",
session.session_id, election.id])[0]
- @password = "open." + election.id.to_s
- end
- # if it's ready for kiosk_mode, then we create and authenticate
- unless @voter and params[:action] == 'kiosk_ready' \
- and election.kiosk
-
- # this is maybe not quite as a dry as it should be
- @voter = OpenVoter.new unless @voter
+ # when (a) there is no voter or (b) when there is a voter but
+ # it's kiosk mode on the right page, rewrite witha blank voter
+ if not(@voter) \
+ or (params[:action] == 'kiosk_ready' and election.kiosk)
+ @voter = OpenVoter.new unless @voter
+ end
+ # now that we have a voter (one way or another), set things
+ # right
@voter.election = election
@voter.session_id = session.session_id
@password = "open." + election.id.to_s
else
@voter = FullVoter.find(:all,
:conditions => [ "password = ?", password ] )[0]
- @password = @voter.password
+
+ if @voter
+ @password = @voter.password
+ else
+ redirect_to :Action => 'index'
+ end
end
- @voter
end
end
has_many :votes
belongs_to :user
validates_presence_of :name, :description
-
+
+ # enforce constraints associated with dependencies (i.e., a kiosk
+ # election can't also be unauthenticated)
+ before_save :enforce_constraints
+
#validate that method is one of the listed election types
-
attr_reader :plurality_result
attr_reader :approval_result
attr_reader :condorcet_result
attr_reader :borda_result
require 'date'
-
+
def initialize(params={})
super
self.enddate = read_attribute( :enddate ) || \
def activate!
self.active = 1
- self.save!
+ self.save
end
def quickvote?
names
end
+
+ def candidate_hash
+ hash = {}
+ self.candidates.each {|c| hash[c.id] = c}
+ return hash
+ end
+
+
+ # TODO now that this code is in here, we should go ahead and remove
+ # date checking from other places in the code
+ def after_find
+ if self.active < 2 and self.enddate < Time.now
+ self.active = 2
+ self.save
+ end
+ end
+
+ private
+ def enforce_constraints
+ # kiosks can't be authenticated
+ self.authenticated = false if kiosk?
+ return true
+ end
+
end
class QuickVote < Election
before_validation :build_candidate_names
- after_validation :create_candidates
validates_uniqueness_of :name
attr_accessor :candidate_names
def build_candidate_names
@candidate_names ||= []
- if @candidate_names.empty? and not candidates.empty?
- @candidate_names = candidates.collect {|c| c.name}
+ if @candidate_names.empty? and not self.candidates.empty?
+ @candidate_names = self.candidates.collect {|c| c.name}
end
end
<% @user.elections.select {|e| e.instance_of?(Election)}.each do |election| %>
<tr>
<td style="text-align: left;">
- <% if election.active == 1 -%>
<%= link_to "#{election.name}", :controller => 'election',
:action => 'show', :id => election %>
- <% else -%>
- <%=h election.name %>
- <% end -%>
</td>
<td style="text-align: left;"><%=h election.description %></td>
<td style="text-align: left;">
+<!-- first, process the results -->
+<% @election.results! %>
+
+<!-- create the necessary variables -->
<% candidates = @election.ssd_result.ranked_candidates.flatten -%>
<% voters = @election.voters.size %>
<% matrix = @election.ssd_result.matrix %>
<% victories = @election.ssd_result.victories_and_ties %>
+<% @names = @election.names_by_id %>
+
<p>Each number in the table below shows how many times the candidate on
the left beat the matching candidate on the top. The winner is on the
top of the left column.</p>
+<% @votes = @election.votes.select {|v| v.confirmed? }.shuffle %>
+<% @voters = @votes.collect {|v| v.voter}.shuffle %>
+
<div id="title-header">
<span class="header">Details</span>
<span class="subheader"><%= @election.name %></span>
<ol>
<%- @voters.each do |voter| -%>
-<li><%= voter.email %></li>
+<li><% if voter.email %>
+ <%= voter.email %>
+ <% elsif @election.kiosk? %>
+ Kiosk Voter
+ <% else %>
+ Unknown voter
+ <% end %></li>
<%- end -%>
</ol>
<p>The following table lists the votes cast in random order.</p>
-<p>The column marked <em>Verification Token</em> lists tokens that were
-given to voters at the time of voting. Voters can check to see that the
-vote that corresponds to their token was recorded correctly. The column
-marked <em>Vote</em> lists the candidates in order of the voter's
-preference. To read these votes, refer to the key below.</p>
+<p><% if @election.verifiable %>The column marked <em>Verification
+Token</em> lists tokens that were given to voters at the time of voting.
+Voters can check to see that the vote that corresponds to their token
+was recorded correctly.<% end %> The column marked <em>Vote</em> lists
+the candidates in order of the voter's preference. To read these votes,
+refer to the key below.</p>
<table class="preftable">
<tr>
<th></th>
-<th>Verification Token</th>
+<% if @election.verifiable %><th>Verification Token</th><% end %>
<th>Vote</th>
<%- @votes.each_with_index do |vote, i| -%>
<tr>
<td><%= i + 1 %></td>
-<td><%= vote.token %></td><td><%= vote.votestring%></td>
+<% if @election.verifiable %><td><%= vote.token %></td><% end %>
+<td><%= vote.votestring%></td>
</tr>
<%- end -%>
</table>
+<!-- create the default variables -->
+<% @results = @election.results %>
+<% @names = @election.names_by_id %>
+<% @candidates = @election.candidate_hash %>
+
<% require 'whois/whois' %>
<div id="title-header">
<%= link_to_remote "Delete",
:complete => "Element.remove('cand#{@current_candidate.id}')",
:url => { :action => :delete_candidate,
- :id => @current_candidate.id } %>
+ :id => @election.id, :candidate => @current_candidate.id } %>
</div>
<div class="clear-div"></div>
<%= render :partial => 'candidate_box_info' %>
--- /dev/null
+<!-- common data to all sidebars -->
+<%= render :partial => 'common/results_sidebar' %>
+
+<h2>Details</h2>
+
+<p><%= link_to "Auditing Information", { :action => 'details', :id => @election.id }, :popup => [] %></p>
<% if @edit %>
<%= link_to_remote "Delete",
:complete => "Element.remove('voter#{voter.id}')",
- :url => { :action => :delete_voter, :id => voter.id } %>
+ :url => { :action => :delete_voter, :id => @election.id,
+ :voter => voter.id } %>
<% end %>
</li>
</div>
+++ /dev/null
-<h2>Result</h2>
-
-<%= render :partial => 'winner' %>
-
-<h2>Result Details</h2>
-
-<%= render :partial => 'winner_details' %>
-
-<h2>Election Rolls for Voter Verification</h2>
-
-<p>The voting rolls -- displayed here in alphabetical order -- for the
-last election are are follows.</p>
-
-<p>Information is displayed here to help voters verifying that their own
-vote was recorded correctly and that the election was not tampered
-with.</p>
-
-<h3>Voters</h3>
-<table border="1">
-<th>Voters (A-Z)</th>
-<% for email in @voter_list %>
-<tr>
-<td><%= email %></td>
-</tr>
-<% end %>
-</table>
-
-<h3>Votes by Token</h3>
-
-<p>The votes, listed in alphabetical order by token.</p>
-
-<table border="1">
-<tr>
- <th rowspan="2">Token (0-9, A-Z)</th>
- <th colspan="<%= @election.candidates.length %>">Rank of Candidates</th>
-</tr>
-<tr>
-
-<% for candidate in @election.candidates.sort.reverse %>
- <th><%= candidate %></th>
-<% end %>
-
-</tr>
-<% for vote in @vote_list %>
- <tr>
- <td><%= vote.token %></td>
- <% for ranking in vote.rankings %>
- <td><%= ranking %></td>
- <% end %>
- </tr>
-<% end %>
-</table>
<div class="clear-div"></div>
+<% if @election.active == 0 %>
+
<div class="normal-header">
<span class="header">Enter New Candidate</span>
<span class="subheader"></span>
to proceed to the next step.</p>
<%= button_to "Proceed to Next Step", :action => 'new_voters', :id => @election %>
+
+<% else %>
+
+<p>You can not edit the list of candidates once the election has begun.
+please return to the <%= link_to "election overview page", :action =>
+'show', :id => @election.id %>.</p>
+
+<% end %>
<% form_tag( {:action => 'update_general_information', :id => @election},
:multipart => true ) do %>
<%= render :partial => 'overview_form' %>
- <%= render :partial => 'theme_upload' %>
+ <!-- <%= render :partial => 'theme_upload' %> -->
<%= submit_tag 'Done' %>
<% end %>
<span class="subheader"></span>
</div>
-<p id="unauth_notice" <%= 'style="display: none;"' if @election.authenticated %>>Anyone will be able to
-vote in this election.</p>
+<% if @election.active == 0 %>
+
+<p id="unauth_notice" <%= 'style="display: none;"' if @election.authenticated %>>
+<% if @election.kiosk? %>
+ <em>Because you have enabled kiosk mode, there will be no registration of voters.</em>
+<% end %>
+Anyone will be able to vote in this election.</p>
<div id="voter_info_box" <%= 'style="display: none;"' unless @election.authenticated %>>
<%= render :partial => 'voter_list' %>
<% end %>
</div>
-<%= check_box :election, :authenticated %> Only allow registered voters
+<% unless @election.kiosk? %>
+ <%= check_box :election, :authenticated %> Only allow registered voters
+<% end %>
<%= observe_field "election_authenticated",
:url => { :action => 'toggle_authenticated', :id => @election.id },
<p>When you are done entering voters, please click the button below
to proceed to the next step.</p>
-<%= button_to 'Proceed to Next Step!', :action => 'show', :id => @election.id %>
+<%= button_to 'Proceed to Next Step', :action => 'show', :id => @election.id %>
+
+<% else %>
+
+<p>You can not edit the list of voters once the election has begun.
+please return to the <%= link_to "election overview page", :action =>
+'show', :id => @election.id %>.</p>
+
+<% end %>
+
:election_id => @election.id %>.</div>
<% elsif (@election.active? && @election.early_results? ) %>
- <div id="status">The creator of this election has decided that the results
+ <div id="status">You have decided that the results
should be viewable while the election is in progress.
- <%if @election.voters.empty? %>
+ <%if @election.voters.select {|v| v.vote.confirmed?}.empty? %>
However, no one has voted yet.
<% else %>
- <%= link_to "View results", :controller => 'voter', :action => 'results',
- :id => "open" %>.
+ <%= link_to "View results", :controller => 'election', :action => 'results',
+ :id => @election.id %>.
<% end %>
</div>
<% elsif @election.active? %>
<h2>Details</h2>
<p><%= link_to "Auditing Information", { :action => 'details', :id => @password }, :popup => [] %></p>
-
<p>Please select from one of the following pages.</p>
<div style="text-align: center;">
- <p><%= button_to 'Confirm This Vote', :action => 'confirm', :id => @password %></p>
-
- <p>If you choose, you will be able to go back<br />and change it up until
- the end of the voting period.</p>
+ <p><% if @voter.election.kiosk? and params[:kiosk] == 'true' %>
+ <%= button_to 'Confirm This Vote', :action => 'confirm', :id => @password,
+ :kiosk => true %>
+ <% else %>
+ <%= button_to 'Confirm This Vote', :action => 'confirm', :id => @password %>
+ <% end %>
+ </p>
+
+ <% unless @voter.election.kiosk? %>
+ <p>If you choose, you will be able to go back<br />and change it up until
+ the end of the voting period.</p>
+ <% end %>
- <p><%= button_to 'Discard This Vote', votepassword_url(
- :action => 'index', :urlpassword => @password) %></p>
-
- <p>You will be returned to the voting page to vote<br /> again, if you choose.</p>
-
+ <p><% if @voter.election.kiosk? and params[:kiosk] == 'true' %>
+ <%= button_to 'Discard This Vote',
+ votepassword_url(:action => 'index', :urlpassword => @password,
+ :kiosk => true) %>
+ <% else %>
+ <%= button_to 'Discard This Vote',
+ votepassword_url(:action => 'index', :urlpassword => @password) %>
+ <% end %>
+ </p>
+
</tr>
</div>
end of the election, you will be able to use this token to verify that
your vote was used in the election and that your vote was recorded
correctly.</p>
+
+<% if @voter.election.kiosk? and params[:kiosk] == 'true' %>
+
+<p>Please click the done button below when finished to reset the system
+for the next voter.</p>
+
+<%= button_to "Done", :action => "kiosk_ready", :id => @password, :kiosk => true %>
+
+<% end %>