def index
redirect_to(:action => 'signup') unless logged_in? || User.count > 0
end
-
+
+ #these methods provide basic functionality for the user login system
+ #===================================================================
def login
return unless request.post?
self.current_user = User.authenticate(params[:login], params[:password])
flash[:notice] = "You have been logged out."
redirect_back_or_default(:controller => '/site', :action => 'index')
end
+ #======================================================================
+
+ #The following methods are for slectricity specific uses
+ def summary
+ @user = User.find(params[:id])
+ end
+
+
end
+
+
####################################################################
def new
+ redirect_to :action => 'general_information'
+ end
+
+ def general_information
@election = Election.new
+ render :action => 'general_information'
end
def create_election
flash[:notice] = 'Election was successfully created.'
redirect_to :action => 'edit_candidates', :id => @election.id
else
- render :action => 'new'
+ render :action => 'general_information'
end
end
@election.activate!
redirect_to :action => 'show', :id => @election.id
end
+
+ def change_notices
+ election = Election.find(params[:id])
+ if election.notices == 0
+ election.notices = 1
+ else
+ election.notices = 0
+ end
+ end
# methods fod display, adding, deleting, and manipulating candidate
# information for elections
def add_candidate
@election = Election.find(params[:id])
@candidate = Candidate.new(params[:candidate])
-
+ @election.candidates << @candidate
+
if @candidate.save
- @election.candidates << @candidate
@candidate = Candidate.new
redirect_to :action => 'edit_candidates', :id => @election.id
else
def candidate_picture
candidate = Candidate.find( params[:id] )
- send_data( candidate.picture_data,
- :filename => candidate.picture_filename,
- :type => candidate.picture_type,
+ send_data( candidate.picture.data,
+ :filename => candidate.picture.filename,
+ :type => candidate.picture.filetype,
:disposition => 'inline' )
end
## for a particular election
####################################################################
def new_voters
- @election = Election.find( params[:id] )
- if params.has_key?[:raw_voter_list]
- process_incoming_voters( params[:raw_voter_list] )
- end
- @raw_voter_list = RawVoterList.new
-
+ edit_voters
end
def edit_voters
end
# the new voter should be in good shape. save add to the election
- new_voter.save
@election.voters << new_voter
+ new_voter.save
end
end
class GruffGraff
def initialize(options)
- size = "700x400"
+ size = options[:size] ? options[:size] : "400x300" #allow custom sizing
@graph = options[:graph_type].new(size)
-
- @graph.theme = { :colors => ['#000000', '#00FFFF', '#FFCC00', '#990033'],
- :background_colors => ['#74ce00', '#ffffff'] }
+
+ @graph.no_data_message = "No Voters"
+
+ @graph.theme = { :colors => ['#005CD9', '#DC0D13', '#131313', '#990033'],
+ :background_colors => ['#74CE00', '#FFFFFF'] }
@graph.font = File.expand_path('/usr/X11R6/lib/X11/fonts/TTF/Vera.ttf',
RAILS_ROOT)
:data => data,
:interval_labels => labels,
:title => "Voters Over Time",
+ :size => "700x400",
:x_axis_label => scale,
:y_axis_label => "Number of Votes")
send_data(*graph.output)
require_dependency "quick_vote"
require_dependency "vote"
require_dependency "election"
-
+
#############################################################
# the following methods pertain to creating quickvotes
#############################################################
def create
- if params[:quickvote]
+ if params[:quickvote]
@quickvote = QuickVote.new(params[:quickvote])
# store the candidate grabbed through ajax and stored in flash
- @quickvote.candidatelist = flash[:candlist]
+ @quickvote.candidate_names = flash[:candidate_names]
@quickvote.description=@quickvote.description
+ #record who created the quickvote so that person can monitor it easily
+ @quickvote.quickuser = session.session_id
+ #Give registered users additional QuickVote functionality
+ @quickvote.user_id = session[:user][:id] if session[:user]
# try to save, if it fails, show the page again (the flash should
# still be intact
if @quickvote.save
@quickvote = @quickvote.reload
render :action => 'success'
else
- flash.keep(:candlist)
+ flash.keep(:candidate_names)
end
else
# if we don't have a quickvote param, it means that the person
# here has not been hitting this page and we can clear any
- # candlist in the flash
- flash.delete(:candlist) if flash.has_key?(:candlist)
+ # candidate_names list in the flash
+ flash.delete(:candidate_names) if flash.has_key?(:candidate_names)
+ @quickvote = QuickVote.new
end
end
def add_candidate
candidate_name = params[:ajax][:newcandidate]
unless candidate_name.strip.empty?
- if flash.has_key?(:candlist) and flash[:candlist].instance_of?(Array)
- flash[:candlist] << candidate_name unless flash[:candlist].index(candidate_name)
+ if flash.has_key?(:candidate_names) \
+ and flash[:candidate_names].instance_of?(Array)
+ unless flash[:candidate_names].index(candidate_name)
+ flash[:candidate_names] << candidate_name
+ end
else
- flash[:candlist] = [ candidate_name ]
+ flash[:candidate_names] = [ candidate_name ]
end
end
- flash.keep(:candlist)
+ flash.keep(:candidate_names)
render_partial 'candidate_list'
end
if @election
# look to see that the voter has been created and has voted in
# this election, and has confirmed their vote
- @voter = QuickVoter.find(:all, :conditions => ["session_id = ? and election_id = ?",
- session.session_id, @election.id])[0]
+ @voter = QuickVoter.find(:all,
+ :conditions => ["session_id = ? and election_id = ?",
+ session.session_id, @election.id])[0]
# if the voter has not voted we destroy them
if @voter and not @voter.voted?
election = QuickVote.ident_to_quickvote(params[:ident])
# find out who the voter is for this election
- @voter = QuickVoter.find(:all, :conditions => ["session_id = ? and election_id = ?",
- session.session_id, election.id])[0]
+ @voter = QuickVoter.find(:all,
+ :conditions => ["session_id = ? and election_id = ?",
+ session.session_id, election.id])[0]
if not @voter
# we have not seen this voter before. something is wrong, try
end
def change
- voter = QuickVoter.find(:all, :conditions => ["session_id = ?", session.session_id])[0]
+ voter = QuickVoter.find(:all, :conditions => ["session_id = ?",
+ session.session_id])[0]
voter.destroy
redirect_to quickvote_url( :ident => params[:ident] )
end
def mapvoters
@map = GMap.new("map_div_id")
@map.control_init(:large_map => true, :map_type => true)
- center=nil
+ center = nil
+
QuickVote.ident_to_quickvote(params[:id]).voters.each do |voter|
next unless voter.ipaddress
+
location = GeoKit::Geocoders::IpGeocoder.geocode(voter.ipaddress)
next unless location.lng and location.lat
+
unless center
- center=[location.lat,location.lng]
- @map.center_zoom_init(center,4)
+ center = [location.lat, location.lng]
+ @map.center_zoom_init(center, 4)
end
- marker = GMarker.new([location.lat,location.lng], :title => "Voter", :info_window => (voter.ipaddress or "unknown")+" "+voter.vote.votestring)
+
+ marker = GMarker.new([location.lat,location.lng],
+ :title => "Voter",
+ :info_window => (voter.ipaddress or "unknown") \
+ + " " + voter.vote.votestring)
@map.overlay_init(marker)
end
end
+
###############################################################
# the following method pertains to displaying the results of a
# quickvote
redirect_to :controller => 'site'
return
end
+ if @election.viewable == 0 && @election.active == 1
+ render :action => 'not_viewable' and return
+ end
@results = @election.results
@candidates = {}
@election.candidates.each {|c| @candidates[c.id] = c}
end
+
+ def my_quickvotes
+ @myqvs = QuickVote.find(:all, :conditions => ["quickuser = ?",
+ session.session_id])
+ end
+
end
+
class SiteController < ApplicationController
- layout 'main'
+ layout 'frontpage'
require_dependency "user"
require_dependency "election"
require_dependency "account"
belongs_to :election
validates_presence_of :name
+ # i have to call this picture_assoc because picture= does not overload
+ # the normal association method made by has_one
+ has_one :picture_obj, :class_name => "Picture"
+
# validate uniqueness of a name *within a given election*
def <=>(other)
name
end
- def picture=(picture_field)
- if picture_field
- unless picture_field.content_type.match(/^image/)
- return false
- end
- self.picture_filename = base_part_of(picture_field.original_filename)
- self.picture_type = picture_field.content_type.chomp
- self.picture_data = picture_field.read
- end
+ def picture
+ picture_obj
end
- def base_part_of(filename)
- name = File.basename(filename)
- name.gsub(/[^\w._-]/, '')
+ def picture=(field)
+ if field and field.length > 0
+ self.picture_obj = Picture.new.set_from_field(field)
+ return picture_obj.save
+ else
+ return false
+ end
end
def picture?
- !self.picture_filename.nil?
+ !self.picture_obj.nil?
end
end
require 'date'
+ def initialize(params={})
+ super
+ self.enddate = read_attribute( :enddate ) || \
+ Time.now + 14.days - 1.second
+ end
+
def other_methods
if election_method
@other_methods = ELECTION_TYPES.reject {|i| i == election_method}
def startdate
read_attribute( :startdate ) || Time.now
end
-
- def enddate
- date = read_attribute( :enddate ) || Time.now + 14
- date - 1.second
- end
def enddate=(date)
date += 1.day
def start_blockers
reasons = []
-
if self.candidates.length <= 1
reasons << "You must have at least two candidates."
end
--- /dev/null
+class Picture < ActiveRecord::Base
+ belongs_to :candidate
+
+ def set_from_field(field)
+ unless field.content_type.match(/^image/)
+ return false
+ end
+ self.filename = base_part_of(field.original_filename)
+ self.filetype = field.content_type.chomp
+ self.data = field.read
+ self
+ end
+
+ def base_part_of(filename)
+ name = File.basename(filename)
+ name.gsub(/[^\w._-]/, '')
+ end
+
+end
+
class QuickVote < Election
+ before_validation :build_candidate_names
after_validation :create_candidates
validates_uniqueness_of :name
validates_presence_of :name
- attr_accessor :raw_candidates
+
+ attr_accessor :candidate_names
attr_accessor :reviewed
+ def initialize(params={})
+ super
+ self.startdate = Time.now
+ self.active = 1
+ self.anonymous = 1 unless self.anonymous
+ self.enddate = read_attribute( :enddate ) || \
+ Time.now + 30.days - 1.second
+ end
+
def validate
- if not @raw_candidates or @raw_candidates.length < 2
+ if @candidate_names.length < 2
errors.add(nil, "You must list at least two candidates.")
end
-
- @raw_candidates.each do |c|
+
+ @candidate_names.each do |c|
unless c.instance_of? String
errors.add(nil, "Candidates must be strings")
next
errors.add(nil, "Candidate name must not be empty")
next
end
- end if @raw_candidates
-
- errors.add(nil, "Candidates must all be unique") if @raw_candidates and @raw_candidates.uniq!
+ end if @candidate_names
+
+ if @candidate_names and @candidate_names.uniq!
+ errors.add(nil, "Candidates must all be unique")
+ end
if name =~ /[^A-Za-z0-9]/
errors.add(:name, "must only include numbers and letters.")
if name =~ /^(create|index|confirm|change|results)$/
errors.add(:name, " is a reserved word.")
end
- end
-
- def initialize(params={})
- super
- self.startdate = Time.now
- self.enddate = Time.now + 30.days
- self.active = 1
- self.anonymous = 1
- end
- def candidatelist=(candlist)
- @raw_candidates = candlist
+ if enddate < startdate
+ errors.add(nil, "QuickVotes can't end before they start")
+ end
end
def name
reviewed.to_i == 1
end
+ def build_candidate_names
+ @candidate_names ||= []
+ if @candidate_names.empty? and not candidates.empty?
+ @candidate_names = candidates.collect {|c| c.name}
+ end
+ end
+
def create_candidates
return unless errors.empty?
- @raw_candidates.each do |name|
+
+ # delete the candidates
+ candidates.each {|c| c.destroy}
+
+ # create the new list based on the names
+ @candidate_names.each do |name|
candidate = Candidate.new({:name => name})
self.candidates << candidate
end
result.candidate_names=candidates.values
result
end
+
def get_quickvote_votes(shortname)
- qv=QuickVote.ident_to_quickvote(shortname)
- votes=Array.new
+ qv = QuickVote.ident_to_quickvote(shortname)
+
unless qv
raise ArgumentError.new("Cannot find QuickVote #{shortname}")
end
- qv.votes.each do |vote|
- votes << VoteInfo.new(:voter_id => vote.voter.id, :voter_ipaddress => vote.voter.ipaddress, :vote_time => vote.time.to_i, :vote => vote.votes, :voter_session_id => vote.voter.session_id )
+
+ qv.votes.collect do |vote|
+ VoteInfo.new(:voter_id => vote.voter.id,
+ :voter_ipaddress => vote.voter.ipaddress,
+ :vote_time => vote.time.to_i,
+ :vote => vote.votes,
+ :voter_session_id => vote.voter.session_id)
end
- return votes
end
+
def list_quickvotes()
- all=Array.new
- QuickVote.find(:all).each do |election|
- all << get_quickvote(election.name)
+ QuickVote.find(:all).collect do |election|
+ get_quickvote(election.name)
end
- return all
end
+
def get_quickvote(shortname)
- raise ArgumentError.new("Cannot find QuickVote named #{shortname}") unless election=QuickVote.ident_to_quickvote(shortname)
- return ElectionStruct.new(:id => election.id, :name => election.name, :description => election.description, :candidate_ids => election.candidates.collect {|c| c.id }, :candidate_names => election.candidates.collect {|c| c.name } )
+ unless election = QuickVote.ident_to_quickvote(shortname)
+ raise ArgumentError.new("Cannot find QuickVote named #{shortname}")
+ end
+
+ ElectionStruct.new(
+ :id => election.id,
+ :name => election.name,
+ :description => election.description,
+ :candidate_ids => election.candidates.collect {|c| c.id },
+ :candidate_names => election.candidates.collect {|c| c.name } )
end
+
def create_quickvote(election)
- qv=QuickVote.new(:name => election.name, :description => election.description)
- qv.candidatelist=election.candidate_names
+ qv = QuickVote.new(:name => election.name,
+ :description => election.description)
+ qv.candidate_names = election.candidate_names
+
if qv.save
return ""
else
<%= error_messages_for :user %>
<% form_for :user do |f| -%>
+
<p><label for="login">Login</label><br/>
<%= f.text_field :login %></p>
<p><label for="email">Email</label><br/>
-<%= f.text_field :email %></p>
+<%= f.text_field :email %><br />
+People participating in elections you're administrating will contact you
+at this address.</p>
<p><label for="password">Password</label><br/>
<%= f.password_field :password %></p>
--- /dev/null
+<h2>This is your user summary profile, <%=h @user.login.capitalize %></h2>
+
+<p>
+E-mail: <%=h @user.email %><br />
+Member since: <%=h @user.created_at.strftime("%x") %>
+</p>
+
+<p>Your Elections:
+ <table class="voterbox">
+ <tr>
+ <% Election.content_columns.each do |column| -%>
+ <% next if column.name.eql?("viewable") || column.name.eql?("quickuser")\
+ || column.name.eql?("active") %>
+ <th><%= column.human_name %></th>
+ <% end -%>
+ </tr>
+
+ <% @user.elections.select {|e| e.instance_of?(Election)}.each do |election| %>
+ <tr>
+ <td>
+ <% if election.active == 1 -%>
+ <%= link_to "#{election.name}", :controller => 'election',
+ :action => 'show', :id => election %>
+ <% else -%>
+ <%=h election.name %>
+ <% end -%>
+ </td>
+ <td><%=h election.description %></td>
+ <td>
+ <% if election.anonymous == 0 -%>
+ No
+ <% else -%>
+ Yes
+ <% end -%>
+ </td>
+ <td><%=h election.startdate.strftime("%x") %></td>
+ <td><%=h election.enddate.strftime("%x") %></td>
+ <td>
+ <% if election.notices == 0 -%>
+ No
+ <% else -%>
+ Yes
+ <% end -%>
+ </td>
+ <td><%=h election.election_method %></td>
+ </tr>
+ <% end -%>
+ </table>
+</p>
+
+<p>
+Your Quickvotes:
+<table class="voterbox">
+ <tr>
+ <% ["Name", "Description", "Start Date", "End Date", "Notices"].each do |column| %>
+ <th><%= column %></th>
+ <% end -%>
+ </tr>
+
+ <% @user.elections.select {|e| e.instance_of?(QuickVote)}.each do |quickvote|
+ %>
+ <tr>
+ <td>
+ <% if quickvote.active == 1 %>
+ <%= link_to "#{quickvote.name}",
+ quickaction_url( :ident => quickvote.name,
+ :action => 'results' ) %>
+ <% else %>
+ <%=h quickvote.name %>
+ <% end %>
+ </td>
+ <td><%=h quickvote.description %></td>
+ <td><%=h quickvote.startdate.strftime("%x") %></td>
+ <td><%=h quickvote.enddate.strftime("%x") %></td>
+ <td>
+ <% if quickvote.notices == 0 -%>
+ No
+ <% else -%>
+ Yes
+ <% end -%>
+ </td>
+ </tr>
+<% end %>
+</table>
--- /dev/null
+<% progress_steps = [ ['overview', 'General Information'],
+ ['candidates', 'Candidates'],
+ ['voters', 'Voters'],
+ ['review', 'Review'] ] %>
+<div id="election_creation_progress_bar">
+
+<ul>
+<% progress_steps.each_with_index do |kv, i| -%>
+ <% step, description = kv -%>
+ <li class="<%= step == progress ? 'step_selected' : 'step_unselected' -%>
+ <%= " last" if i + 1 == progress_steps.length -%>
+ ">Step <%= i + 1 %>: <%= description %></li>
+<% end -%>
+</ul>
+
+</div>
+<%= render_partial 'progress', 'candidates' %>
<h1>Edit/Add Candidates</h1>
<%= error_messages_for :candidate %>
<% unless @election.candidates.empty? %>
<p>The following are valid options or candidates in this election:</p>
+1;3A
<% @election.candidates.each do |candidate| %>
<% @current_candidate = candidate %>
<%= submit_tag "Add Candidate" %>
<% end %>
-<%= button_to "Done!", :action => 'show', :id => @election %>
+<%= button_to "Done!", :action => 'new_voters', :id => @election %>
+<%= render_partial 'progress', 'overview' %>
+
<h1>Create A New Vote</h1>
<h2>Vote Overview</h2>
+<%= render_partial 'progress', 'voters' %>
<% @edit = true %>
<h1><strong><%= @election.name %>:</strong> Enter List of Voter Email Addresses</h1>
<% form_tag(:action => 'new_voters', :id => @election.id) do %>
<%= render :partial => 'voters_form' %>
<% end %>
+<%= button_to "Done", :action => 'show', :id => @election.id %>
-<% %>
+<%= render_partial 'progress', 'review' %>
<h1>Vote Information</h1>
<% if @election.active? %>
<% end %>
<h2>Candidates</h2>
-
+<% %>
<% unless @election.candidates.empty? %>
<%= render :partial => 'candidate_list' %>
<% unless @election.active %>
<p><em>There are currently no voters registered. <%= link_to "Add some!", :action => 'edit_voters', :id => @election.id unless @election.active %></em></p>
<% end %>
-<% unless @election.active %>
+<% unless @election.active? %>
<h2>Start Election</h2>
<% if @election.start_blockers.length > 0 %>
<% end %>
</ul>
<% else %>
- <p>Please check eveything carefully on this page before starting this
+ <p>Please check everything carefully on this page before starting this
vote. Once you begin the vote, you will <em>not</em> be able to add or
change candidates, modify the voting lists, or change the end
time.</p>
--- /dev/null
+ <div id="footer">
+ <a href="http://code.selectricity.org/">Copyleft</a> 2006, 2007 ||
+ <a href="http://www.media.mit.edu">MIT Media Lab</a>
+ </div>
--- /dev/null
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <title>Selectricity</title>
+ <%= stylesheet_link_tag "common", :media => "all" %>
+ <%= stylesheet_link_tag "front", :media => "all" %>
+ </head>
+
+ <body>
+ <div id="page-wrapper">
+
+ <div id="header">
+ <a href="index.html"><h1>selectricity: voting machinery for the masses</h1></a>
+ </div>
+
+ <div id="body">
+ <%= @content_for_layout %>
+ </div>
+
+ <%= render_partial 'layouts/footer' %>
+</div>
+</body>
+
+</html>
-<% %>
<html>
- <head>
- <title><%= @page_title || "Selectricity" %></title>
- <%= stylesheet_link_tag "main", :media => "all" %>
-
- <%= javascript_include_tag "prototype", "effects", "dragdrop", "controls" %>
- </head>
- <body>
- <div id="top">
- <% if @page_title %>
- <h3><%= @page_title %></h3>
- <% else %>
- <span id="headertext"><%= link_to('<h3>Selectricity<br />
- <font size="-1">Voting Machinery for the Masses</font></h3>', :controller =>
- 'site', :action => 'index')%></span>
- <% end %>
+ <head>
+ <title><%= @page_title || "Selectricity" %></title>
+ <%= stylesheet_link_tag "main", :media => "all" %>
+ <%= javascript_include_tag "prototype", "effects", "dragdrop", "controls" %>
+ </head>
- <div id="links">
- <% if session[:user] %>
- Welcome <strong><%= User.find(session[:user]).login.capitalize %></strong>
- <% else %>
- <%= link_to("Login", :controller => "account", :action => "login")
- %>/<%= link_to("Sign up", :controller => "account", :action => "signup")%>
- <% end %> |
-
- <% if session[:user] %>
- <%= link_to("Logout", :controller => "account", :action => "logout") %> |
- <% end %>
-
- <%= link_to("Help/About", :controller => "site", :action => "about") %>
- </div>
- </div>
-
- <% if flash[:notice]%>
- <div id="notice"><%= flash[:notice] %></div>
- <% end%>
+ <body>
+ <div id="top">
+ <% if @page_title %>
+ <h3><%= @page_title %></h3>
+ <% else %>
+ <span id="headertext"><%= link_to('<h3>Selectricity<br />
+ <font size="-1">Voting Machinery for the Masses</font></h3>', :controller =>
+ 'site', :action => 'index')%></span>
+ <% end %>
- <div id="main">
- <%= @content_for_layout %>
- </div>
+ <div id="links">
+ <% if session[:user] %>
+ Welcome <strong><%= User.find(session[:user]).login.capitalize %></strong>
+ <%= link_to("Profile", :controller => "account",
+ :action => "summary", :id => session[:user][:id] )%>
+ <%= link_to("Logout", :controller => "account",
+ :action => "logout") %> |
+ <% else %>
+ <%= link_to("Login", :controller => "account", :action => "login")
+ %>/<%= link_to("Sign up", :controller => "account", :action => "signup")%>
+ <% end %> |
+
+ <%= link_to("Help/About", :controller => "site", :action => "about") %>
+ </div>
+</div>
+
+ <% if flash[:notice]%>
+ <div id="notice"><%= flash[:notice] %></div>
+ <% end%>
- <div id="footer">
- <hr />
- <%= link_to "Copyleft", "http://code.selectricity.org/"
- %> 2006, 2007 ||
- <%= link_to "MIT Media Lab", "http://www.media.mit.edu" %> and the
- <a href="http://code.selectricity.org/team">Selectricity Team</a>
- </div>
+ <div id="main">
+ <%= @content_for_layout %>
+ </div>
- </body>
+ <%= render_partial 'layouts/footer' %>
+ </body>
</html>
--- /dev/null
+
+<% fields_for 'quickvote', quickvote do |quickform| %>
+
+<span><label for="quickvote_election_method">Election Method</span><br />
+<%= quickform.select('election_method',
+ %w(ssd condorcet plurality approval borda) ) %><br />
+
+<span><label for="quickvote_enddate">End Time</span><br />
+<%= quickform.date_select(:enddate, :start_year => Time.now.year) %><br />
+
+</p>Want the results to be visible while the election is active?
+Yes <%= quickform.radio_button(:viewable, 1)%>
+No <%= quickform.radio_button(:viewable, 0)%></p>
+
+<% if session[:user] %>
+<p>Would you like to be e-mailed when this QuickVote concludes?
+Yes <%= quickform.radio_button(:notices, 1)%>
+No <%= quickform.radio_button(:notices, 0)%></p>
+<% end -%>
+
+<% end %>
<% %>
<!-- the list of candidates -->
-<% if flash[:candlist] %>
+<% if flash[:candidate_names] %>
<ul>
- <% for cand in flash[:candlist] %>
+ <% for cand in flash[:candidate_names] %>
<li><%=h cand.capitalize %></li>
<% end %>
</ul>
<% end %>
-<% form_remote_tag(:update => 'candlist',
+<% form_remote_tag(:update => 'candidate_names',
:url => { :action => 'add_candidate' },
:complete => "Field.focus('ajax_newcandidate')") do %>
<p>
<% victories = @election.condorcet_result.victories_and_ties %>
<% names = @election.names_by_id %>
-
<!-- This table shows how many times each choice was ranked above the other,
with percentages-->
<table class="voterbox">
<% else -%>
(<%= margin%>)
<% end -%>
- </td>
+ </td>
<% end -%>
</tr>
<% end -%>
</table>
-
-<div class="resultbox">
<h3>Approval Result</h3>
<p><font size="-1">(This algorithm assumes that top two choices are "approved.")</font></p>
+<%= render :partial => 'result', :object => @election.approval_result %>
+
<div class="rbmoreinfo">
<h4>About Approval Voting</h4>
range that voters are allowed to express is extremely constrained:
accept or not.</p>
-</div>
-
</div>
\ No newline at end of file
-<div class="resultbox">
<h3>Borda Count Results</h3>
+<%= render :partial => 'result', :object => @election.borda_result %>
+
<div class="rbmoreinfo">
<h4>About Borda Count</h4>
voter. Once all votes have been counted the candidate with the most
points is the winner.</p>
</div>
-</div>
\ No newline at end of file
+<%= image_tag( graph_url( :action => 'borda_bar', :id => @election ) ) %>
-<div class="resultbox">
<h3>Simple Condorcet Results</h3>
+<%= render :partial => 'result', :object => @election.condorcet_result %>
+
<div class="rbmoreinfo">
<h4>About Simple Cordorcet Voting</h4>
another Condorcet system.</p>
</div>
-</div>
\ No newline at end of file
-<div class="resultbox">
<h3>Plurality Results</h3>
+<%= render :partial => 'result', :object => @election.plurality_result %>
+
<div class="rbmoreinfo">
<h4>About Plurality Voting</h4>
voting.</p>
</div>
-</div>
\ No newline at end of file
+<%= image_tag(graph_url( :action => 'plurality_pie', :id => @election ) )%>
-<div class="mainresultbox">
<h3>Schulze Method Results</h3>
+<%= render :partial => 'result', :object => @election.ssd_result %>
+
<div class="rbmoreinfo">
<h4>About the Schulze Method</h4>
Beatpath Winner, Path Voting, and Path Winner.</p>
</div>
-</div>
+<%= render :partial => 'pref_tables' %>
+
<%= error_messages_for 'quickvote' %>
-<p><label for="quickvote_candidatelist">Choices</p>
+<p><label for="quickvote_candidate_names">Choices</p>
<!-- the list of candidates -->
-<div id="candlist">
+<div id="candidate_names">
<%= render :partial => 'candidate_list' %>
</div>
<%= text_area 'quickvote', 'description', :cols => 50, :rows => 4 %></p>
+<%= check_box('options', 'advanced',
+ :onclick => 'Element.toggle($("advanced")); false;' )%>Advanced
+
+<div id="advanced" style="display: none">
+<%= render :partial => 'advanced', :locals => {:quickvote => @quickvote} %>
+</div>
+<br />
+
<%= submit_tag "Create Quickvote" -%>
<% end %>
+
+
+
+
--- /dev/null
+<table class="voterbox">
+ <tr>
+ <% ["Name", "Start Date", "End Date", "Description"].each do |column| %>
+ <th><%= column %></th>
+ <% end -%>
+ </tr>
+
+ <% @myqvs.each do |quickvote| %>
+ <tr>
+ <td>
+ <% if quickvote.active == 1 %>
+ <%= link_to "#{quickvote.name}",
+ quickaction_url( :ident => quickvote.name,
+ :action => 'results' ) %>
+ <% else %>
+ <%=h quickvote.name %>
+ <% end %>
+ </td>
+ <td><%=h quickvote.startdate.strftime("%x") %></td>
+ <td><%=h quickvote.enddate.strftime("%x") %></td>
+ <td><%=h quickvote.description %></td>
+ </tr>
+<% end %>
+</table>
--- /dev/null
+<p>Sorry, the creator of this QuickVote has decided this election shouldn't
+ be visible while the QuickVote is running. </p>
+<%= link_to "Selectricity Home", :controller => 'site' %>
\ No newline at end of file
<h2>Winners</h2>
+<div class="mainresultbox">
<%= render :partial => 'result_' + @election.election_method,
:object => @results[@election.election_method] %>
-
+</div>
<h3> Other Voting Methods </h3>
<% for result_type in @election.other_methods %>
+<div class="resultbox">
<%= render :partial => 'result_' + result_type,
:object => @results[result_type] %>
+</div>
<% end %>
<% end %>
</table>
-<%= render :partial => 'pref_tables' %>
-
<%=image_tag( graph_url( :action => 'votes_per_interval', :id => @election ))%>
<br />
-<%= image_tag( graph_url( :action => 'borda_bar', :id => @election ) ) %><br />
+
<%= image_tag( graph_url( :action => 'choices_positions', :id => @election ) ) %><br />
-<%= image_tag(graph_url( :action => 'plurality_pie', :id => @election ) )%>
+
-<% -%>
- <% form_tag :controller => 'account', :action => 'login' do %>
- <table>
- <label for="login">Login</label>
- <%= text_field "Login", "login", :size => 30 %><br />
- <label for="password">Password</label>
- <%= password_field "Password", "password", :size => 30 %><br />
- </table>
+<% form_tag :controller => 'account', :action => 'login' do %>
- <div class="button-bar">
- <p><%= submit_tag 'Login' %></p>
-<% end %>
- <p><%= link_to 'Register for an account', :controller =>
-'account', :action => 'signup' %></p>
-
- <p><%= link_to 'Lost or forgot your password?', :controller => 'account', :action => 'forgot_password' %></p>
+ <p><label for="login">Login</label></p>
+ <p><%= text_field "Login", "login", :size => 30 %></p>
+ <p><label for="password">Password</label></p>
+ <p><%= password_field "Password", "password", :size => 30 %></p>
- <p>Unfortunately, Selectricity is currently being tested and new
- accounts for full votes (i.e., non-<em>QuickVotes</em>) can not
- be automatically created. If you are interested in using
- Selectricity to
- run an organizational election, contact <a
- href="http://mako.cc/contact.html">Benjamin Mako Hill</a>.</p>
+ <p><%= submit_tag 'Login' %></p>
+<% end %>
- </div>
+<p><%= link_to 'Register for an account', :controller => 'account', :action => 'signup' %></p>
+<p><%= link_to 'Lost or forgot your password?', :controller => 'account', :action => 'forgot_password' %></p>
-<% %>
-
-<h2>Activity Summary</h2>
-
<% if @current_elections.length < 1 %>
<em>You have not created any elections.</em>
<% else %>
-<% %>
+<div id="voters" class="main-section">
+ <div id="voters-content">
+ <h2>Voters</h2>
-<table width="auto" padding="5px">
-<tr>
-<td width="47%" valign="top">
+ <p>If you have received an email with a token inviting you to vote in
+ an ongoing election, you can log in to vote using your token below.</p>
-<h2>QuickVotes</h2>
+ <%= form_tag :controller => 'voter', :action => 'index' %>
+ <p><%= text_field :vote, :password %></p>
+ <p><%= submit_tag "Log In" %></p>
+ <%= end_form_tag %>
-<p><em>QuickVotes</em> are like polls: unstructured, non-anonymous and
-without the complex features of <em>Selectricity</em>. They are the
-quickest way to make a decision or to compare between voting
-methods.</p>
+ <p><%= link_to 'Lost or forgot your token?', :controller => 'voter', :action => 'forgot_password' %></p>
-<p><%= link_to "Create a QuickVote", :controller => 'quickvote', :action => 'create' %></p>
+ <h3>SMS Interface</h3>
+ <p>For information on accessing Selectricity over email or via SMS/text messages from your mobile phone, email <%= link_to "vote\@mako.cc", "mailto:vote@mako.cc" %> with "help" in the body or read the <%= link_to "Selectricity Anywhere documentation", "selectricity-anywhere.html"%>.</p>
-<p>Recent <em>QuickVotes</em> include:</p>
+ </div>
+</div>
-<ul>
-<% for quickvote in @quickvotes %>
-<li><%= link_to (h(quickvote.shortdesc) || "Unnamed"), quickvote_url(:ident => quickvote.name) %></li>
-<% end %>
-</ul>
+<div id="control-room" class="main-section">
+ <div id="control-room-content">
+ <h2>Control Room</h2>
+
+ <% if session[:user] %>
+ <%= render :partial => 'user_summary' %>
+ <% else %>
+
+ <p>You must have an account to start a new vote or to administer an
+ existing vote. You can log in or create a new account below.</p>
+
+ <%= render_partial 'basic_login' %>
+ <% end %>
+
+ </div>
+</div>
+
+<div id="quickvotes" class="main-section">
+ <div id="quickvotes-content">
+
+ <h2>QuickVotes</h2>
+ <p><em>QuickVotes</em> are like polls: unstructured, non-anonymous and
+ without the complex features of <em>Selectricity</em>. They are the
+ quickest way to make a decision or to compare between voting
+ methods.</p>
+
+ <ul>
+ <li><%= link_to( "Create a QuickVote", :controller => 'quickvote', :action => 'create') %></li>
+ <li><%= link_to( "Recent QuickVotes", :controller => 'quickvote', :action => 'my_quickvotes')%></li>
+ </ul>
+
+ <p>Recently created <em>QuickVotes</em> include:</p>
+ <ul>
+ <% for quickvote in @quickvotes %>
+ <li><%= link_to (h(quickvote.shortdesc) || "Unnamed"), quickvote_url(:ident => quickvote.name) %></li>
+ <% end %>
+ </ul>
+
+ </div>
+</div>
+
+<!--
<h2>Selectricity <em>Anywhere</em></h2>
<p><%= link_to 'Lost or forgot your token?', :controller => 'voter', :action => 'forgot_password' %></p>
<% if session[:user] %>
- <%= render_partial 'user_summary' %>
+ <%= render :partial => 'user_summary' %>
<% else %>
<h2>Vote Administrators</h2>
<p>You must have an account to start a new vote or to administer an
</td>
</tr>
</table>
+-->
Alternatively, you can just click this URL:
<%= url_for :controller => 'election', :action => 'show', :id => @voter.election.id %>
-If you have any questions or if you feel you have recieved this message
+If you have any questions or if you feel you have received this message
in error, you should contact:
- <%= @voter.election.user.name %> <<%= @voter.election.user.email %>>
+ <%= @voter.election.user.login %> <<%= @voter.election.user.email %>>
(The initiator of this election)
Alternatively, if you feel there is a technical error, please contact:
end
end
+#Change the session store key, so that it will not conflict with other webapps
+ActionController::Base.session_options[:session_key] = 'selectricity_session_id'
+CGI::Session.expire_after 1.year
+
# action mailer configuration
ActionMailer::Base.delivery_method = :sendmail
ActionMailer::Base.default_charset = "utf-8"
# Tell ActionMailer not to deliver emails to the real world.
# The :test delivery method accumulates sent emails in the
# ActionMailer::Base.deliveries array.
-config.action_mailer.delivery_method = :test
\ No newline at end of file
+config.action_mailer.delivery_method = :test
+
+# start the debugger
+require 'ruby-debug'
+SCRIPT_LINES__ = {}
+Debugger.start
map.connect 'quickvote/:action/:id',
:controller => 'quickvote',
- :requirements => { :action => /(create|add_candidate|sort_candidates)/ }
+ :requirements => { :action => /(create|add_candidate|sort_candidates|my_quickvotes)/ }
map.quickaction 'quickvote/:ident/:action',
:controller => 'quickvote',
drop table if exists elections;
create table elections (
- id int NOT NULL auto_increment,
+ id int NOT NULL auto_increment,
name varchar(100) NOT NULL,
description TEXT NOT NULL,
anonymous tinyint NOT NULL DEFAULT 1,
startdate datetime,
enddate datetime NOT NULL,
active tinyint NOT NULL DEFAULT 0,
+ viewable tinyint NOT NULL DEFAULT 1,
+ notices tinyint NOT NULL DEFAULT 0,
user_id int NULL,
+ quickuser varchar(255) NULL, #stores session_id for quickvote creators
election_method varchar(100) DEFAULT 'ssd',
`type` varchar(100) NOT NULL,
primary key (id),
election_id int NOT NULL,
name varchar(100) NOT NULL,
description text NULL,
- picture_filename varchar(200),
- picture_data blob,
- picture_type varchar(100),
+ primary key (id)
+);
+
+# CREATE pictures TABLE
+#####################################
+
+drop table if exists pictures;
+create table pictures (
+ id int NOT NULL auto_increment,
+ filename varchar(200),
+ data blob,
+ filetype varchar(100),
+ candidate_id int NULL,
+ constraint fk_candidate_picture foreign key (candidate_id) references candidates(id),
primary key (id)
);
+# This file is autogenerated. Instead of editing this file, please use the
+# migrations feature of ActiveRecord to incrementally modify your database, and
+# then regenerate this schema definition.
+
+ActiveRecord::Schema.define() do
+
+ create_table "candidates", :force => true do |t|
+ t.column "election_id", :integer, :null => false
+ t.column "name", :string, :limit => 100, :default => "", :null => false
+ t.column "description", :text
+ t.column "picture_filename", :string, :limit => 200
+ t.column "picture_data", :binary
+ t.column "picture_type", :string, :limit => 100
+ end
+
+ create_table "elections", :force => true do |t|
+ t.column "name", :string, :limit => 100, :default => "", :null => false
+ t.column "description", :text, :default => "", :null => false
+ t.column "anonymous", :integer, :limit => 4, :default => 1, :null => false
+ t.column "startdate", :datetime
+ t.column "enddate", :datetime, :null => false
+ t.column "active", :integer, :limit => 4, :default => 0, :null => false
+ t.column "viewable", :integer, :limit => 4, :default => 1, :null => false
+ t.column "notices", :integer, :limit => 4, :default => 0, :null => false
+ t.column "user_id", :integer
+ t.column "quickuser", :string
+ t.column "election_method", :string, :limit => 100, :default => "ssd"
+ t.column "type", :string, :limit => 100, :default => "", :null => false
+ end
+
+ add_index "elections", ["user_id"], :name => "fk_user_election"
+
+ create_table "rankings", :force => true do |t|
+ t.column "vote_id", :integer
+ t.column "candidate_id", :integer
+ t.column "rank", :integer
+ end
+
+ create_table "tokens", :force => true do |t|
+ t.column "token", :string, :limit => 100, :default => "", :null => false
+ t.column "vote_id", :integer, :null => false
+ end
+
+ add_index "tokens", ["vote_id"], :name => "fk_vote_token"
+
+ create_table "users", :force => true do |t|
+ t.column "login", :text
+ t.column "ip", :text, :default => "", :null => false
+ t.column "email", :text
+ t.column "crypted_password", :string, :limit => 40
+ t.column "salt", :string, :limit => 40
+ t.column "created_at", :datetime
+ t.column "updated_at", :datetime
+ t.column "remember_token", :text
+ t.column "remember_token_expires_at", :datetime
+ end
+
+ create_table "voters", :force => true do |t|
+ t.column "email", :string, :limit => 100
+ t.column "password", :string, :limit => 100
+ t.column "contacted", :integer, :limit => 4, :default => 0, :null => false
+ t.column "election_id", :integer, :null => false
+ t.column "session_id", :string, :limit => 32
+ t.column "ipaddress", :string, :limit => 32
+ end
+
+ add_index "voters", ["election_id"], :name => "fk_election_voter"
+
+ create_table "votes", :force => true do |t|
+ t.column "voter_id", :integer
+ t.column "confirmed", :integer, :limit => 4, :default => 0, :null => false
+ t.column "time", :datetime
+ end
+
+ add_index "votes", ["voter_id"], :name => "fk_vote_voter"
+
+end
--- /dev/null
+@charset "UTF-8";
+/* CSS Document */
+
+/****************************************************************
+ Selectricity || selectricity.org
+ Design by Courtland Allen
+
+ "Reset Reloaded"
+ Thanks to Eric Meyer
+ http://meyerweb.com/eric/thoughts/2007/05/01/reset-reloaded/
+*****************************************************************/
+
+/* common css files */
+
+html, body, div, span, applet, object, iframe,
+h1, h2, h3, h4, h5, h6, p, blockquote, pre,
+a, abbr, acronym, address, big, cite, code,
+del, dfn, em, font, img, ins, kbd, q, s, samp,
+small, strike, strong, sub, sup, tt, var,
+dl, dt, dd,
+fieldset, form, label, legend,
+table, caption, tbody, tfoot, thead, tr, th, td {
+ margin: 0;
+ padding: 0;
+ border: 0;
+ font-size: 100%;
+ font-family: inherit;
+ vertical-align: baseline;
+}
+
+
+#body {
+ font-family: "Trebuchet MS", Verdana, Arial, Helvetica, sans-serif;
+ color: white;
+ font-size: 12px;
+ text-align: left;
+ line-height: 1.5em;
+}
+
+#body a {
+ text-decoration: underline;
+ color: inherit;
+ display: inline;
+ opacity: 0.8;
+}
+
+#body a:hover {
+ opacity: .5;
+}
+
+strong, h2, h3 {
+ font-weight: bold;
+}
+
+h2, h3 {
+ text-transform: uppercase;
+ margin-bottom: 0.5em !important;
+}
+
+
+/* footer */
+
+#footer {
+ font-size: 11px;
+ font-family: "Trebuchet MS", Trebuchet, Verdana, Arial, Helvetica, sans-serif;
+ margin-top: 40px;
+ text-align: center;
+}
+
+#footer a {
+ text-decoration: none;
+ color: #dc0d13;
+}
+
+#footer a:hover {
+ text-decoration: underline;
+}
--- /dev/null
+@charset "UTF-8";
+/* CSS Document */
+
+/****************************************************************
+ Selectricity || selectricity.org
+ Design by Courtland Allen
+*****************************************************************/
+
+html, body, div, span, applet, object, iframe,
+h1, h2, h3, h4, h5, h6, p, blockquote, pre,
+a, abbr, acronym, address, big, cite, code,
+del, dfn, em, font, img, ins, kbd, q, s, samp,
+small, strike, strong, sub, sup, tt, var,
+dl, dt, dd,
+fieldset, form, label, legend,
+table, caption, tbody, tfoot, thead, tr, th, td {
+ margin: 0;
+ padding: 0;
+ border: 0;
+ font-size: 100%;
+ font-family: inherit;
+ vertical-align: baseline;
+}
+
+body {
+ line-height: 1;
+ color: black;
+ background: #ffffff url(/images/bg_index.png) repeat-x top center;
+}
+
+/* tables still need 'cellspacing="0"' in the markup */
+table {
+ border-collapse: separate;
+}
+
+caption, th, td {
+ text-align: left;
+ font-weight: normal;
+}
+
+#page-wrapper {
+ width: 960px;
+ margin: 0 auto 0 auto;
+ text-align: center;
+}
+
+
+/* Header */
+#header h1 {
+ background: url(/images/title.png) center top no-repeat;
+ overflow: hidden;
+ padding-top: 189px;
+ height: 0px;
+ margin-top: 10px;
+}
+
+
+/* Body */
+
+#body {
+ margin-top: 9px;
+ height: 609px;
+}
+
+h2 {
+ margin-top: 0.3em;
+ font-size: 24px;
+}
+
+h3 {
+ margin-top: 1em;
+ font-size: 16px;
+}
+
+.main-section {
+ float: left;
+ padding-left: 120px;
+ padding-right: 15px;
+}
+
+.main-section p {
+ font-size: 12px;
+ overflow: hidden;
+ line-height: 2em;
+ margin-bottom: 1em;
+}
+
+#voters {
+ padding-top: 50px;
+ height: 559px;
+ width: 185px;
+ background: url(/images/bg_voters.png) top left no-repeat;
+}
+
+#voters-content {
+ height: 516px;
+}
+
+#control-room {
+ padding-top: 139px;
+ height: 470px;
+ width: 185px;
+ background: url(/images/bg_controlroom.png) top left no-repeat;
+}
+
+#control-room-content {
+ height: 428px;
+}
+
+#quickvotes {
+ padding-top: 80px;
+ height: 529px;
+ width: 185px;
+ background: url(/images/bg_quickvotes.png) top left no-repeat;
+}
+
+#quickvotes-content {
+ height: 486px;
+}
+
color: #fff;
border-bottom: 0px;
}
+
.resultbox {
text-align: center;
width: 400px;
padding: 5px;
}
+#election_creation_progress_bar ul li {
+ display: inline;
+ list-style: default;
+}
+
+#election_creation_progress_bar ul li:after {
+ font-weight: normal;
+ color: #000;
+ content: " || ";
+}
+
+#election_creation_progress_bar ul li.last:after {
+ content: "";
+}
+
+#election_creation_progress_bar li.step_selected {
+ font-weight: bold;
+}
+
+#election_creation_progress_bar li.step_unselected {
+ color: #CCCCCC;
+ font-weight: bold;
+}
# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
-first:
- id: 1
-another:
- id: 2
+
+mika_normal:
+ id: 1
+ name: mika
+ election_id: 1
+
+mako_normal:
+ id: 2
+ name: mako
+ election_id: 1
+
+bettamax_normal:
+ id: 3
+ name: bettamax
+ election_id: 1
+
+mika_badend:
+ id: 4
+ name: mika
+ election_id: 2
+
+mako_badend:
+ id: 5
+ name: mako
+ election_id: 2
+
+bettamax_badend:
+ id: 6
+ name: bettamax
+ election_id: 2
# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
-first:
- id: 1
-another:
- id: 2
+quickvote_normal:
+ id: 1
+ name: acetarium
+ description: who is the winner?
+ anonymous: 1
+ startdate: 2007-08-22 12:00:00
+ enddate: 2007-09-21 11:59:59
+ active: 1
+ type: QuickVote
+ election_method: ssd
+
+quickvote_invalid_endtime:
+ id: 2
+ name: acetarium2
+ description: who is the winner?
+ anonymous: 1
+ startdate: 2007-08-22 12:00:00
+ enddate: 2003-09-21 11:59:59
+ active: 1
+ type: QuickVote
+ election_method: ssd
end
def test_create_quickvote
- post(:create, {'commit' =>"Create Quickvote", 'quickvote' =>{'name' =>"variable", 'description' =>"Favorite variable."}}, nil, {:candlist=>["foo", "bar", "foobar"]})
+ post(:create, {'commit' =>"Create Quickvote", 'quickvote' =>{'name' =>"variable", 'description' =>"Favorite variable."}}, nil, {:candidate_names=>["foo", "bar", "foobar"]})
assert_template "quickvote/success"
get :index, { 'ident' => "variable"}
assert_response :success
end
def test_create_quickvote_badname
- post(:create, {'commit' => "Create Quickvote", 'quickvote' => {'name' => "has a space", 'description' => "Foobar"}}, nil, {:candlist => ["foo", "bar", "foobar"]})
+ post(:create, {'commit' => "Create Quickvote", 'quickvote' => {'name' => "has a space", 'description' => "Foobar"}}, nil, {:candidate_names => ["foo", "bar", "foobar"]})
assert_template "quickvote/create"
end
def test_create_quickvote_dupe_candidate
- post(:create, {'commit' => "Create Quickvote", 'quickvote' => {'name' => "has a space", 'description' => "Foobar"}}, nil, {:candlist => ["foo", "bar", "bar", "foobar"]})
+ post(:create, {'commit' => "Create Quickvote", 'quickvote' => {'name' => "has a space", 'description' => "Foobar"}}, nil, {:candidate_names => ["foo", "bar", "bar", "foobar"]})
assert_template "quickvote/create"
end
def test_create_quickvote_nil_candidate
- post(:create, {'commit' => "Create Quickvote", 'quickvote' => {'name' => "has a space", 'description' => "Foobar"}}, nil, {:candlist => nil})
+ post(:create, {'commit' => "Create Quickvote", 'quickvote' => {'name' => "has a space", 'description' => "Foobar"}}, nil, {:candidate_names => nil})
assert_template "quickvote/create"
- post(:create, {'commit' => "Create Quickvote", 'quickvote' => {'name' => "has a space", 'description' => "Foobar"}}, nil, {:candlist => []})
+ post(:create, {'commit' => "Create Quickvote", 'quickvote' => {'name' => "has a space", 'description' => "Foobar"}}, nil, {:candidate_names => []})
assert_template "quickvote/create"
end
test_create_quickvote
qv=QuickVote.ident_to_quickvote('variable')
qv.description="<object>foo</object>"
- qv.candidatelist = ["<object>foo", "bar<object>", "<foobar>"]
+ qv.candidate_names = ["<object>foo", "bar<object>", "<foobar>"]
qv.save!
get :index, { 'ident' => 'variable' }
assert_response :success
require File.dirname(__FILE__) + '/../test_helper'
class CandidateTest < Test::Unit::TestCase
- fixtures :candidates
- # Replace this with your real tests.
- def test_truth
- assert_kind_of Candidate, candidates(:first)
+ def test_default
+ assert true
end
end
require File.dirname(__FILE__) + '/../test_helper'
class ElectionTest < Test::Unit::TestCase
- fixtures :elections
-
- # Replace this with your real tests.
- def test_truth
- assert_kind_of Election, elections(:first)
+ def test_default
+ assert true
end
end
--- /dev/null
+require File.dirname(__FILE__) + '/../test_helper'
+
+class QuickVoteTest < Test::Unit::TestCase
+ fixtures :elections, :candidates
+
+ def setup
+ @quickvote_normal = QuickVote.find(1)
+ end
+
+ def test_create_update_delete_quickvote_from_fixture
+ assert_kind_of QuickVote, @quickvote_normal
+ assert_equal 1, @quickvote_normal.id
+ assert_equal 'acetarium', @quickvote_normal.name
+ assert_equal 'who is the winner?', @quickvote_normal.description
+ #assert_equal QuickVote, @quickvote_normal.type
+ assert_equal 'ssd', @quickvote_normal.election_method
+ assert_equal '2007-08-22 12:00:00', @quickvote_normal.startdate_before_type_cast
+ assert_equal '2007-09-21 11:59:59', @quickvote_normal.enddate_before_type_cast
+
+ # make sure that the each of the three andidates
+ (1..3).each do |i|
+ assert @quickvote_normal.candidates.include?(Candidate.find(i))
+ end
+
+ # update and save
+ @quickvote_normal.name = 'foobar'
+ assert @quickvote_normal.save,
+ @quickvote_normal.errors.full_messages.join("; ")
+
+ @quickvote_normal.reload
+ assert_equal 'foobar', @quickvote_normal.name
+ end
+
+ def test_create_invalid_enddate
+ qv = QuickVote.find(2)
+ assert_equal qv.save, false, "created vote with invalid enddate"
+ end
+end
end
def test_list_quickvotes
- result= invoke_delegated :vote, :list_quickvotes
+ result = invoke_delegated :vote, :list_quickvotes
assert_instance_of Array, result
- assert_equal result.length, 0
+ assert result.length > 0
end
def test_create_quickvote
- election = ElectionStruct.new :name => "TestVote", :description => "Test Vote", :candidate_names => ["Apple", "Orange", "Banana", "Pineapple"]
+ election = ElectionStruct.new(
+ { :name => "TestVote",
+ :description => "Test Vote",
+ :candidate_names => ["Apple", "Orange", "Banana", "Pineapple"] })
assert_create_quickvote_succeeds election
end
def test_cast_nil_quickvote
assert_cast_quickvote_fails nil, nil, nil
assert_cast_quickvote_fails "foo", nil, nil
- assert_cast_quickvote_fails "foo",33, []
+ assert_cast_quickvote_fails "foo", 33, []
test_create_quickvote
- assert_cast_quickvote_fails "TestVote",42,nil
- assert_cast_quickvote_fails "TestVote",nil,[]
+ assert_cast_quickvote_fails "TestVote", 42,nil
+ assert_cast_quickvote_fails "TestVote", nil, []
end
def test_cast_malformed_votelist
test_create_quickvote
election = invoke_delegated :vote, :get_quickvote, "TestVote"
assert_cast_quickvote_fails "TestVote", 11, [election.candidate_ids[0]]
- assert_cast_quickvote_fails "TestVote", 11, [1,2]
- assert_cast_quickvote_fails "TestVote", 11, [election.candidate_ids[0],election.candidate_ids[0], election.candidate_ids[1], election.candidate_ids[1], election.candidate_ids[2]]
+ assert_cast_quickvote_fails "TestVote", 11, [1, 2]
+ assert_cast_quickvote_fails "TestVote", 11, [election.candidate_ids[0],
+ election.candidate_ids[0],
+ election.candidate_ids[1],
+ election.candidate_ids[1],
+ election.candidate_ids[2]]
end
def test_get_nonexistent_quickvote
end
def test_get_voters_nonexistent_quickvote
- assert_raises(ArgumentError) {invoke_delegated :vote, :get_quickvote_votes, "asdfasdf"}
+ assert_raises(ArgumentError) { invoke_delegated(:vote,
+ :get_quickvote_votes, "asdfasdf") }
end
def test_get_candidate_map_nonexistent_quickvote
- assert_raises(ArgumentError) { invoke_delegated :vote, :get_quickvote_candidate_map, "asdfasdf"}
+ assert_raises(ArgumentError) { invoke_delegated(:vote,
+ :get_quickvote_candidate_map,
+ "asdfasdf") }
end
def test_cast_mass_quickvote
test_create_quickvote
- election = invoke_delegated :vote, :get_quickvote, "TestVote"
+ election = invoke_delegated(:vote, :get_quickvote, "TestVote")
20.times do |t|
- casted_vote = election.candidate_ids.sort_by {rand}
+ casted_vote = election.candidate_ids.sort_by { rand }
assert_cast_quickvote_succeeds "TestVote", t, [casted_vote]
end
end
def test_cast_quickvote_nonexistent
- assert_cast_quickvote_fails "ASDFJOFASF", "me", [1,2,3]
+ assert_cast_quickvote_fails "ASDFJOFASF", "me", [1, 2, 3]
end
def test_cast_quickvote_nonexistent_candidates
test_create_quickvote
election = invoke_delegated :vote, :get_quickvote, "TestVote"
- assert_cast_quickvote_fails "TestVote", 42, [123,342314,5342,1,1,2]
+ assert_cast_quickvote_fails "TestVote", 42, [123, 342314, 5342, 1, 1, 2]
end
def test_create_mass_quickvote
10.times do |t|
- election = ElectionStruct.new :name => "test#{t}", :description => "Test Vote", :candidate_names => ["Apple", "Orange", "Banana", "Pineapple"]
- assert_create_quickvote_succeeds election
+ assert_create_quickvote_succeeds ElectionStruct.new({
+ :name => "test#{t}",
+ :description => "Test Vote",
+ :candidate_names => ["Apple", "Orange", "Banana", "Pineapple"]})
end
end
def test_create_quickvote_bad_name
- election = ElectionStruct.new :name => "invalid space", :description => "Test Vote", :candidate_names => ["Apple", "Orange", "Banana", "Pineapple"]
- assert_create_quickvote_fails election
+ assert_create_quickvote_fails ElectionStruct.new({
+ :name => "invalid space",
+ :description => "Test Vote",
+ :candidate_names => ["Apple", "Orange", "Banana", "Pineapple"]})
+
end
def test_create_quickvote_nil
- election = ElectionStruct.new
- assert_create_quickvote_fails election
+ assert_create_quickvote_fails ElectionStruct.new()
end
def test_create_quickvote_name_nil
- election = ElectionStruct.new :name => "", :description => "Test Vote", :candidate_names => ["Apple", "Orange", "Banana", "Pineapple"]
- assert_create_quickvote_fails election
+ assert_create_quickvote_fails ElectionStruct.new({
+ :name => "",
+ :description => "Test Vote",
+ :candidate_names => ["Apple", "Orange", "Banana", "Pineapple"]})
end
def test_create_quickvote_description_nil
- election = ElectionStruct.new :name => "foobar", :description => nil, :candidate_names => ["Apple", "Orange", "Banana", "Pineapple"]
- assert_create_quickvote_fails election
-
+ assert_create_quickvote_fails ElectionStruct.new({
+ :name => "foobar",
+ :description => nil,
+ :candidate_names => ["Apple", "Orange", "Banana", "Pineapple"]})
end
def test_create_quickvote_description_whitespace
- election = ElectionStruct.new :name => "foobar", :description => " ", :candidate_names => ["Apple", "Orange", "Banana", "Pineapple"]
- assert_create_quickvote_fails election
- election = ElectionStruct.new :name => "foobar", :description => "\t\t", :candidate_names => ["Apple", "Orange", "Banana", "Pineapple"]
- assert_create_quickvote_fails election
+ assert_create_quickvote_fails ElectionStruct.new({
+ :name => "foobar",
+ :description => " ",
+ :candidate_names => ["Apple", "Orange", "Banana", "Pineapple"]})
+
+ assert_create_quickvote_fails ElectionStruct.new({
+ :name => "foobar",
+ :description => "\t\t",
+ :candidate_names => ["Apple", "Orange", "Banana", "Pineapple"]})
end
def test_create_quickvote_candidates_nil
- election = ElectionStruct.new :name => "foobar", :description => "valid", :candidate_names => nil
- assert_create_quickvote_fails election
+ assert_create_quickvote_fails ElectionStruct.new({
+ :name => "foobar",
+ :description => "valid",
+ :candidate_names => nil })
end
+
def test_create_quickvote_insufficient_candidates
- election = ElectionStruct.new :name => "foobar", :description => "valid", :candidate_names => ["Apple"]
- assert_create_quickvote_fails election
+ assert_create_quickvote_fails ElectionStruct.new({
+ :name => "foobar",
+ :description => "valid",
+ :candidate_names => ["Apple"] })
end
+
def test_create_quickvote_candidates_whitespace
- election = ElectionStruct.new :name => "foobar", :description => "valid", :candidate_names => [" ", " ", " ", " "]
- assert_create_quickvote_fails election
+ assert_create_quickvote_fails ElectionStruct.new({
+ :name => "foobar",
+ :description => "valid",
+ :candidate_names => [" ", " ", " ", " "]})
end
+
def test_create_quickvote_dupe_candidates
- election = ElectionStruct.new :name => "foobar", :description => "valid", :candidate_names => ["Apple", "Apple", "Apple", "Apple"]
- assert_create_quickvote_fails election
+ assert_create_quickvote_fails ElectionStruct.new({
+ :name => "foobar",
+ :description => "valid",
+ :candidate_names => ["Apple", "Apple", "Apple", "Apple"]})
- # Previous may pass coincidentally if a uniq! then a sizecheck reveals too few unique names
- # We don't want this to happen. Dupe canidates should fail regardless of how many are left.
+ # TODO: Previous may pass coincidentally if a uniq! then a sizecheck
+ # reveals too few unique names
+
+ # We don't want this to happen. Dupe canidates should fail
+ # regardless of how many are left.
- election = ElectionStruct.new :name => "foobar", :description => "valid", :candidate_names => ["Apple", "Apple", "Orange", "Orange", "Pineapple" , "Pineapple"]
- assert_create_quickvote_fails election
+ assert_create_quickvote_fails ElectionStruct.new({
+ :name => "foobar",
+ :description => "valid",
+ :candidate_names => ["Apple", "Apple", "Orange",
+ "Orange", "Pineapple" , "Pineapple"]})
end
+
def test_create_quickvote_candidates_nil_mixed
- election = ElectionStruct.new :name => "foobar", :description => "valid", :candidate_names => ["Apple", nil ]
- assert_create_quickvote_fails election
+ assert_create_quickvote_fails ElectionStruct.new({
+ :name => "foobar",
+ :description => "valid",
+ :candidate_names => ["Apple", nil ]})
+
end
+
def test_create_quickvote_description_xmlescape
# Will an embedded XML element bork the table?
- election = ElectionStruct.new :name => "foobar", :description => "test </string>", :candidate_names => ["Apple", "Orange", "Banana", "Pineapple"]
- assert_create_quickvote_succeeds election
+ assert_create_quickvote_succeeds ElectionStruct.new({
+ :name => "foobar",
+ :description => "test </string>",
+ :candidate_names => ["Apple", "Orange", "Banana", "Pineapple"]})
end
+
def test_create_quickvote_unprintable_description
- election = ElectionStruct.new :name => "foobar", :description => "test \x01\x02\x03\x04\x05\x06\x07\x08", :candidate_names => ["Apple", "Orange", "Banana", "Pineapple"]
- assert_create_quickvote_succeeds election
+ assert_create_quickvote_succeeds ElectionStruct.new ({
+ :name => "foobar",
+ :description => "test \x01\x02\x03\x04\x05\x06\x07\x08",
+ :candidate_names => ["Apple", "Orange", "Banana", "Pineapple"]})
end
+
def test_quickvote_proper_results
- election = ElectionStruct.new :name => "favdev", :description => "Who is your favorite developer?", :candidate_names => ["mako", "jdong", "justin"]
- assert_create_quickvote_succeeds election
- reflection = invoke_delegated :vote, :get_quickvote, "favdev"
+ assert_create_quickvote_succeeds ElectionStruct.new({
+ :name => "favdev",
+ :description => "Who is your favorite developer?",
+ :candidate_names => ["mako", "jdong", "justin"]})
+
+ reflection = invoke_delegated(:vote, :get_quickvote, "favdev")
+
+ # build the candidate list
candidates = {}
reflection.candidate_names.each_with_index do |name, index|
- candidates[name] = reflection.candidate_ids[index]
+ candidates[name] = reflection.candidate_ids[index]
end
+
25.times do |t|
vote = [candidates["jdong"], candidates["mako"], candidates["justin"]]
assert_cast_quickvote_succeeds "favdev", "1:#{t}", [vote]
end
+
5.times do |t|
vote = [candidates["mako"], candidates["justin"], candidates["jdong"]]
assert_cast_quickvote_succeeds "favdev", "2:#{t}", [vote]
end
+
10.times do |t|
vote = [candidates["justin"], candidates["mako"], candidates["jdong"]]
assert_cast_quickvote_succeeds "favdev", "3:#{t}", [vote]
end
+
results=nil
- assert_nothing_raised {results=invoke_delegated(:vote, :get_quickvote_results, "favdev")}
+
+ assert_nothing_raised { results = invoke_delegated(:vote,
+ :get_quickvote_results, "favdev") }
assert_equal results.approval_winners, [candidates["mako"]]
assert_equal results.borda_winners, [candidates["jdong"]]
assert_equal results.plurality_winners, [candidates["jdong"]]
assert_equal results.condorcet_winners, [candidates["jdong"]]
assert_equal results.ssd_winners, [candidates["jdong"]]
end
- private
+ ## helper methods and non-tests used throughout this file
+ #########################################################
+ private
def assert_cast_quickvote_succeeds(shortname, id, vote)
assert_nothing_raised do
old_votes = invoke_delegated(:vote, :get_quickvote_votes, shortname)
--- /dev/null
+require 'dynamic_session_expiry'
\ No newline at end of file
--- /dev/null
+# Provides the ability to have session cookies for your Rails app calculated
+# relative to the current time.
+#
+# In your environment.rb file (or in the environments/*.rb file of your choice),
+# do something like the following:
+#
+# CGI::Session.expire_after 1.month
+#
+# Session cookies will then expire one month after the session was created. This
+# differs from the usual session cookie behavior in that the expiration date is
+# not a fixed time, but rather relative to the current time.
+
+class CGI
+ class Session
+ @@session_expiration_offset = 0
+
+ def self.session_expiration_offset
+ @@session_expiration_offset
+ end
+
+ def self.session_expiration_offset=(value)
+ @@session_expiration_offset = value
+ end
+
+ def self.expire_after(value)
+ @@session_expiration_offset = value
+ end
+
+ alias :initialize_without_dynamic_session_expiration :initialize #:nodoc:
+ def initialize(request, option={}) #:nodoc:
+ if @@session_expiration_offset && @@session_expiration_offset > 0
+ option['session_expires'] = Time.now + @@session_expiration_offset
+ end
+ initialize_without_dynamic_session_expiration(request, option)
+ end
+
+ end
+end
\ No newline at end of file