Merge head
authorJohn Dong <jdong@mit.edu>
Tue, 28 Aug 2007 15:44:47 +0000 (11:44 -0400)
committerJohn Dong <jdong@mit.edu>
Tue, 28 Aug 2007 15:44:47 +0000 (11:44 -0400)
64 files changed:
app/controllers/account_controller.rb
app/controllers/election_controller.rb
app/controllers/graph_controller.rb
app/controllers/quickvote_controller.rb
app/controllers/site_controller.rb
app/models/candidate.rb
app/models/election.rb
app/models/picture.rb [new file with mode: 0644]
app/models/quick_vote.rb
app/models/selectricity_service.rb
app/views/account/signup.rhtml
app/views/account/summary.rhtml [new file with mode: 0644]
app/views/election/_progress.rhtml [new file with mode: 0644]
app/views/election/edit_candidates.rhtml
app/views/election/general_information.rhtml [moved from app/views/election/new.rhtml with 80% similarity]
app/views/election/new_voters.rhtml
app/views/election/show.rhtml
app/views/layouts/_footer.rhtml [new file with mode: 0644]
app/views/layouts/frontpage.rhtml [new file with mode: 0644]
app/views/layouts/main.rhtml
app/views/quickvote/_advanced.rhtml [new file with mode: 0644]
app/views/quickvote/_candidate_list.rhtml
app/views/quickvote/_pref_tables.rhtml
app/views/quickvote/_result_approval.rhtml
app/views/quickvote/_result_borda.rhtml
app/views/quickvote/_result_condorcet.rhtml
app/views/quickvote/_result_plurality.rhtml
app/views/quickvote/_result_ssd.rhtml
app/views/quickvote/create.rhtml
app/views/quickvote/my_quickvotes.rhtml [new file with mode: 0644]
app/views/quickvote/not_viewable.rhtml [new file with mode: 0644]
app/views/quickvote/results.rhtml
app/views/site/_basic_login.rhtml
app/views/site/_user_summary.rhtml
app/views/site/index.rhtml
app/views/voter_notify/votestart.rhtml
config/environment.rb
config/environments/test.rb
config/routes.rb
db/create.sql
db/schema.rb
public/images/bg_controlroom.png [new file with mode: 0644]
public/images/bg_index.png [new file with mode: 0644]
public/images/bg_quickvotes.png [new file with mode: 0644]
public/images/bg_resultblock.png [new file with mode: 0644]
public/images/bg_results.png [new file with mode: 0644]
public/images/bg_voters.png [new file with mode: 0644]
public/images/rails.png [deleted file]
public/images/title.png [new file with mode: 0644]
public/images/title_main.png [new file with mode: 0644]
public/images/top_bar_1.png [new file with mode: 0644]
public/images/top_bar_2.png [new file with mode: 0644]
public/stylesheets/common.css [new file with mode: 0644]
public/stylesheets/front.css [new file with mode: 0644]
public/stylesheets/main.css
test/fixtures/candidates.yml
test/fixtures/elections.yml
test/functional/quickvote_controller_test.rb
test/unit/candidate_test.rb
test/unit/election_test.rb
test/unit/quickvote_test.rb [new file with mode: 0644]
test/unit/selectricityservice_test.rb
vendor/plugins/dynamic_sessions/init.rb [new file with mode: 0644]
vendor/plugins/dynamic_sessions/lib/dynamic_session_expiry.rb [new file with mode: 0644]

index bb614dec3cc0d93f0aef84d82f0bc4c37c4d0f06..e8adcf0fe809b8a466f38eb7161e5af765060104 100644 (file)
@@ -10,7 +10,9 @@ class AccountController < ApplicationController
   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])
@@ -42,4 +44,14 @@ class AccountController < ApplicationController
     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
+
+
index d3332948b4398a197ca8280d69ec8db351ea7be2..4ad8bacb354b5cac24a320b994f74427d2809a23 100644 (file)
@@ -12,7 +12,12 @@ class ElectionController < ApplicationController
   ####################################################################
 
   def new
+    redirect_to :action => 'general_information'
+  end
+  
+  def general_information
     @election = Election.new
+    render :action => 'general_information'
   end
   
   def create_election
@@ -27,7 +32,7 @@ class ElectionController < ApplicationController
       flash[:notice] = 'Election was successfully created.'
       redirect_to :action => 'edit_candidates', :id => @election.id
     else
-      render :action => 'new'
+      render :action => 'general_information'
     end
   end
   
@@ -62,6 +67,15 @@ class ElectionController < ApplicationController
     @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
@@ -73,9 +87,9 @@ class ElectionController < ApplicationController
   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
@@ -118,9 +132,9 @@ class ElectionController < ApplicationController
 
   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
 
@@ -128,12 +142,7 @@ class ElectionController < ApplicationController
   ## 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
@@ -207,8 +216,8 @@ class ElectionController < ApplicationController
           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
  
index 69577c6df84e1cf80566748993209eb145965027..814eb363c437a0074abea9113fdc7e30e4a1a455 100644 (file)
@@ -3,11 +3,13 @@ class GraphController < ApplicationController
   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)
       
@@ -72,6 +74,7 @@ class GraphController < ApplicationController
                             :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)
index 54784ef46e735749238ea4fc8617bd261cb72d80..cd63c2e52f61245f2d6b0b537cfb56b624e4d0b2 100644 (file)
@@ -4,44 +4,52 @@ class QuickvoteController < ApplicationController
   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
  
@@ -56,8 +64,9 @@ class QuickvoteController < ApplicationController
     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?
@@ -89,8 +98,9 @@ class QuickvoteController < ApplicationController
     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
@@ -119,7 +129,8 @@ class QuickvoteController < ApplicationController
   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
@@ -137,19 +148,27 @@ class QuickvoteController < ApplicationController
   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
@@ -161,8 +180,18 @@ class QuickvoteController < ApplicationController
       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
+
index 80fdfc406c3247b16651ae5c6b0bada8c2d35625..522bbb2cf4dbe3b5e26145a9040b233ac3732187 100644 (file)
@@ -1,5 +1,5 @@
 class SiteController < ApplicationController
-  layout 'main'
+  layout 'frontpage'
   require_dependency "user"
   require_dependency "election"
   require_dependency "account"
index 430b6ab22762223a728eaf6cc27bb3d51f7b8d2e..eeba4d228032499b8d15474123b03e9aa8129208 100644 (file)
@@ -2,6 +2,10 @@ class Candidate < ActiveRecord::Base
   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)
@@ -12,24 +16,21 @@ class Candidate < ActiveRecord::Base
     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
index 59a10bfbe601387eac1b72de2c9fcec03c99560c..a77f4457bb581fba8588e1cf7ee479932851f409 100644 (file)
@@ -15,6 +15,12 @@ class Election < ActiveRecord::Base
   
   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}
@@ -27,11 +33,6 @@ class Election < ActiveRecord::Base
   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
@@ -56,7 +57,6 @@ class Election < ActiveRecord::Base
 
   def start_blockers
     reasons = []
-    
     if self.candidates.length <= 1
       reasons << "You must have at least two candidates."
     end
diff --git a/app/models/picture.rb b/app/models/picture.rb
new file mode 100644 (file)
index 0000000..e7df084
--- /dev/null
@@ -0,0 +1,20 @@
+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
+
index c0367d6b002ebc8f3058bc480c64edb61bbf3aa5..bd390519331e5e2d62c82d69223e9f5397daf664 100644 (file)
@@ -1,16 +1,27 @@
 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
@@ -20,9 +31,11 @@ class QuickVote < Election
         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.")
@@ -34,18 +47,10 @@ class QuickVote < Election
     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
@@ -56,9 +61,21 @@ class QuickVote < Election
     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
index 196161a467ea2bcfb25f5be2f5cb3d22c6123e21..544b618d7c78fddce9fb5d91f8a3a65cf263264c 100644 (file)
@@ -69,31 +69,47 @@ class SelectricityService < ActionWebService::Base
     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
index c0012a73d3cfbaec7fd555693fc949eb96ae55dc..f5228d8b390ff4c06ae79779bbb34ad0ce924c5c 100644 (file)
@@ -1,10 +1,13 @@
 <%= 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>
diff --git a/app/views/account/summary.rhtml b/app/views/account/summary.rhtml
new file mode 100644 (file)
index 0000000..2f24e28
--- /dev/null
@@ -0,0 +1,84 @@
+<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>
diff --git a/app/views/election/_progress.rhtml b/app/views/election/_progress.rhtml
new file mode 100644 (file)
index 0000000..520894c
--- /dev/null
@@ -0,0 +1,16 @@
+<% 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>
index 99f2f129abd0607b2308d256d52572dc775d6c96..837f75560760d0ea03d0b6a652eaf25106682bbc 100644 (file)
@@ -1,9 +1,11 @@
+<%= 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 %>
@@ -22,4 +24,4 @@
 <%= submit_tag "Add Candidate" %>
 <% end %>
 
-<%= button_to "Done!", :action => 'show', :id => @election %>
+<%= button_to "Done!", :action => 'new_voters', :id => @election %>
similarity index 80%
rename from app/views/election/new.rhtml
rename to app/views/election/general_information.rhtml
index 7b717486c0042739b2fe91d53b0f492e52677901..0a1a51394c5dff7dc1a8fabdec0cf45bc50e30ca 100644 (file)
@@ -1,3 +1,5 @@
+<%= render_partial 'progress', 'overview' %>
+
 <h1>Create A New Vote</h1>
 
 <h2>Vote Overview</h2>
index 9c3bad3a6f9c99cb36b07a35f19806ef8503ed7f..fc49e13638167dd8fa026ac7e373625e1885ee82 100644 (file)
@@ -1,3 +1,4 @@
+<%= render_partial 'progress', 'voters' %>
 <% @edit = true %>
 <h1><strong><%= @election.name %>:</strong> Enter List of Voter Email Addresses</h1>
 
@@ -6,3 +7,4 @@
 <% form_tag(:action => 'new_voters', :id => @election.id) do %>
 <%= render :partial => 'voters_form' %>
 <% end %>
+<%= button_to "Done", :action => 'show', :id => @election.id %>
index 0051861e3475c418d9480a08cf7f0cc5208f9461..5d22f44352bb6c65e60125447d3a23b53adead5f 100644 (file)
@@ -1,4 +1,4 @@
-<% %>
+<%= render_partial 'progress', 'review' %>
 <h1>Vote Information</h1>
 
 <% if @election.active? %>
@@ -34,7 +34,7 @@
 <% end %>
 
 <h2>Candidates</h2> 
-
+<% %>
 <% unless @election.candidates.empty? %>
   <%= render :partial => 'candidate_list' %>
   <% unless @election.active %>
@@ -54,7 +54,7 @@
   <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 %>
@@ -65,7 +65,7 @@
     <% 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>
diff --git a/app/views/layouts/_footer.rhtml b/app/views/layouts/_footer.rhtml
new file mode 100644 (file)
index 0000000..b23900f
--- /dev/null
@@ -0,0 +1,4 @@
+  <div id="footer">
+       <a href="http://code.selectricity.org/">Copyleft</a> 2006, 2007 &nbsp;&nbsp; || &nbsp;&nbsp; 
+       <a href="http://www.media.mit.edu">MIT Media Lab</a>
+  </div>
diff --git a/app/views/layouts/frontpage.rhtml b/app/views/layouts/frontpage.rhtml
new file mode 100644 (file)
index 0000000..8f14c3a
--- /dev/null
@@ -0,0 +1,25 @@
+<!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>
index 0b9d5cb9d5f2a18494ff4392da386561273525e2..c6a14a31a1eebdb22fcce5263a1e09337a0a2718 100644 (file)
@@ -1,52 +1,44 @@
-<% %>
 <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>
diff --git a/app/views/quickvote/_advanced.rhtml b/app/views/quickvote/_advanced.rhtml
new file mode 100644 (file)
index 0000000..0255fbd
--- /dev/null
@@ -0,0 +1,21 @@
+
+<% 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 %>
index ddb47e53fa7f6a49b707bcecdb530e5ef0dd1a54..76de0ac59e25c40512a466deb13a0af620ddbdd6 100644 (file)
@@ -1,14 +1,14 @@
 <% %>
 <!-- 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>
index 66e0cbf2df1fbf7870581ca6ed849b66db2c7f21..0d2b020f654c6de57a5f145d009da14c28e8d5d8 100644 (file)
@@ -4,7 +4,6 @@
 <% 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">
@@ -46,9 +45,8 @@
                <% else -%>
                  (<%= margin%>)
                <% end -%>
-                 </td>
+       </td>
        <% end -%>
   </tr>
   <% end -%>
 </table>
-
index 12c7958741f67e47407483d683941eab63d00878..c93ce1d5a34f4952ea0e718260595c00308989a3 100644 (file)
@@ -1,7 +1,8 @@
-<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>
 
@@ -12,6 +13,4 @@ chooses.  Approval voting is a limited form of range voting, where the
 range that voters are allowed to express is extremely constrained:
 accept or not.</p>
 
-</div>
-
 </div>
\ No newline at end of file
index 97d82e5eaa24902dccac39b5fe7625c3913a001d..f81cbdba2814bb7dc31209597d2dfa53e928b848 100644 (file)
@@ -1,6 +1,7 @@
-<div class="resultbox">
 <h3>Borda Count Results</h3>
 
+<%= render :partial => 'result', :object => @election.borda_result %>
+
 <div class="rbmoreinfo">
 <h4>About Borda Count</h4>
 
@@ -13,4 +14,4 @@ corresponding to the position in which he or she is ranked by each
 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 ) ) %>
index 4279bbd1b2dfa0e004656e7cb772ba4344d72101..77ce6585f8bc88b7133d0d7ce150f263f836178f 100644 (file)
@@ -1,6 +1,7 @@
-<div class="resultbox">
 <h3>Simple Condorcet Results</h3>
 
+<%= render :partial => 'result', :object => @election.condorcet_result %>
+
 <div class="rbmoreinfo">
 <h4>About Simple Cordorcet Voting</h4>
 
@@ -15,4 +16,3 @@ will be the winner.</p>
 another Condorcet system.</p>
 
 </div>
-</div>
\ No newline at end of file
index 121c1dc9acac23f1d06ce4ab03c34f322ef4dcde..86a94691170027c538c96ec7755c1aab8adb843d 100644 (file)
@@ -1,6 +1,7 @@
-<div class="resultbox">
 <h3>Plurality Results</h3>
 
+<%= render :partial => 'result', :object => @election.plurality_result %>
+
 <div class="rbmoreinfo">
 <h4>About Plurality Voting</h4>
 
@@ -14,4 +15,4 @@ post," "winner-take-all," "majoritarian" or "simple majority"
 voting.</p>
 
 </div>
-</div>
\ No newline at end of file
+<%= image_tag(graph_url( :action => 'plurality_pie', :id => @election ) )%>
index 436dd6701f3163229d53c070ef09128c731b1be4..e1811840828a9c52e19a629b45b92bc872ca5717 100644 (file)
@@ -1,6 +1,7 @@
-<div class="mainresultbox">
 <h3>Schulze Method Results</h3>
 
+<%= render :partial => 'result', :object => @election.ssd_result %>
+
 <div class="rbmoreinfo">
 <h4>About the Schulze Method</h4>
 
@@ -14,4 +15,5 @@ methods for resolving "circular" defeats.</p>
 Beatpath Winner, Path Voting, and Path Winner.</p>
 </div>
 
-</div>
+<%= render :partial => 'pref_tables' %>
+
index cf91e198a4e15183020a680bea65c51ed49f9241..7ccb6443120e8d7f50a1a506176b8b828b9c0b1c 100644 (file)
@@ -3,10 +3,10 @@
 
 <%= 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 %>
 
+
+
+
+
diff --git a/app/views/quickvote/my_quickvotes.rhtml b/app/views/quickvote/my_quickvotes.rhtml
new file mode 100644 (file)
index 0000000..bb38836
--- /dev/null
@@ -0,0 +1,24 @@
+<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>       
diff --git a/app/views/quickvote/not_viewable.rhtml b/app/views/quickvote/not_viewable.rhtml
new file mode 100644 (file)
index 0000000..3c5532e
--- /dev/null
@@ -0,0 +1,3 @@
+<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
index 9727d81289e6690597f298f4d5a0d8bb4a545e5e..0383b5e4434c0acfba9b9e391b16e463687b91b5 100644 (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 ) )%>
+
index f02d362819f23e478b82705f434d99ab89ea0ded..9c689fcb55f084236dedd595a2c7f95065a11fe5 100644 (file)
@@ -1,26 +1,13 @@
-<% -%>
- <% 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>
index 310d98cb6fe37a3f5701e85e3595d35902e2b3c1..e37cafb60a0b9f1792313749b5c5465ef0623c02 100644 (file)
@@ -1,7 +1,3 @@
-<% %>
-
-<h2>Activity Summary</h2>
-
 <% if @current_elections.length < 1 %>
   <em>You have not created any elections.</em>
 <% else %>
index 1b994b0e16ebf84e29e1b7df89c1c9298cb81e44..bb74bba558278331eb15c27b640e9121bd016cf9 100644 (file)
@@ -1,25 +1,65 @@
-<% %>
+<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>
 
@@ -47,7 +87,7 @@ ongoing election, you can log in to vote using your token here.</p>
 
 <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
@@ -58,3 +98,4 @@ ongoing election, you can log in to vote using your token here.</p>
 </td>
 </tr>
 </table>
+-->
index b844ee23477a9b05e16cbf5db8daf460ae95ebbf..b31f1ba44414984e8747cc6c99495f053a43e215 100644 (file)
@@ -13,10 +13,10 @@ need to use the following token to log in to selectricity.media.mit.edu:
 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:
index 571638d14a3fc1a0ccefbce34442f8cbc1fa8fc0..80f19b46ee25983f4511ac36c4142d8daf895857 100644 (file)
@@ -87,6 +87,10 @@ class String
   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"
index f0689b924bf935c9ca8cb91c578f2cba521e250c..7c2f617db2b1810fd86d3c15418b607403b991ca 100644 (file)
@@ -16,4 +16,9 @@ config.action_controller.perform_caching             = false
 # 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
index 96beafd4dde7af51ba160cde5e02fff5794c7dd0..735f5d7c92f2448bf9ba945c624652a0e0b6e67c 100644 (file)
@@ -15,7 +15,7 @@ ActionController::Routing::Routes.draw do |map|
  
   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',
index 7b3fef5600b061a043c5c3972abe066aa75df79f..2033ed18c838d6ff1182f07f96e4ce70d2e64153 100644 (file)
@@ -3,14 +3,17 @@
 
 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),
@@ -26,9 +29,20 @@ create table candidates (
  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)
 );
 
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..4ea61b7973e5dc269191f16b03c1c4cdfbcba66a 100644 (file)
@@ -0,0 +1,77 @@
+# 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
diff --git a/public/images/bg_controlroom.png b/public/images/bg_controlroom.png
new file mode 100644 (file)
index 0000000..5629933
Binary files /dev/null and b/public/images/bg_controlroom.png differ
diff --git a/public/images/bg_index.png b/public/images/bg_index.png
new file mode 100644 (file)
index 0000000..52ac075
Binary files /dev/null and b/public/images/bg_index.png differ
diff --git a/public/images/bg_quickvotes.png b/public/images/bg_quickvotes.png
new file mode 100644 (file)
index 0000000..fd844ec
Binary files /dev/null and b/public/images/bg_quickvotes.png differ
diff --git a/public/images/bg_resultblock.png b/public/images/bg_resultblock.png
new file mode 100644 (file)
index 0000000..21a05bd
Binary files /dev/null and b/public/images/bg_resultblock.png differ
diff --git a/public/images/bg_results.png b/public/images/bg_results.png
new file mode 100644 (file)
index 0000000..a94d556
Binary files /dev/null and b/public/images/bg_results.png differ
diff --git a/public/images/bg_voters.png b/public/images/bg_voters.png
new file mode 100644 (file)
index 0000000..8901917
Binary files /dev/null and b/public/images/bg_voters.png differ
diff --git a/public/images/rails.png b/public/images/rails.png
deleted file mode 100644 (file)
index b8441f1..0000000
Binary files a/public/images/rails.png and /dev/null differ
diff --git a/public/images/title.png b/public/images/title.png
new file mode 100644 (file)
index 0000000..acf328f
Binary files /dev/null and b/public/images/title.png differ
diff --git a/public/images/title_main.png b/public/images/title_main.png
new file mode 100644 (file)
index 0000000..f3dd02d
Binary files /dev/null and b/public/images/title_main.png differ
diff --git a/public/images/top_bar_1.png b/public/images/top_bar_1.png
new file mode 100644 (file)
index 0000000..3be6999
Binary files /dev/null and b/public/images/top_bar_1.png differ
diff --git a/public/images/top_bar_2.png b/public/images/top_bar_2.png
new file mode 100644 (file)
index 0000000..7242913
Binary files /dev/null and b/public/images/top_bar_2.png differ
diff --git a/public/stylesheets/common.css b/public/stylesheets/common.css
new file mode 100644 (file)
index 0000000..9bc6264
--- /dev/null
@@ -0,0 +1,77 @@
+@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;
+}
diff --git a/public/stylesheets/front.css b/public/stylesheets/front.css
new file mode 100644 (file)
index 0000000..1285e7f
--- /dev/null
@@ -0,0 +1,120 @@
+@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;
+}
+
index 86cf84b2ac856f01547ad20befc745c83d3e3fc9..76eff61026e1a05c6a188d0a779280c77ea8c196 100644 (file)
@@ -167,6 +167,7 @@ a:active { color: #FFFFFF; text-decoration: none; background: #0259C4; }
   color: #fff;
   border-bottom: 0px;
 }
+
 .resultbox {
   text-align: center;
   width: 400px;
@@ -312,3 +313,26 @@ li.moveable {
   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;
+}
index 8794d28ae419929e241d892341c7429b84e5c74e..4a651bfcf79dbce6a825c34a302228021a2eacda 100644 (file)
@@ -1,5 +1,31 @@
 # 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
index 8794d28ae419929e241d892341c7429b84e5c74e..814540fcd314c7ede325fa4cde8a5c8f3237ccda 100644 (file)
@@ -1,5 +1,22 @@
 # 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
index 02c133e1508c40c28d7fdd1443f1a916d9ccfa80..ee79b3f50444e3902211b3d72fd5b5b379ecf5de 100644 (file)
@@ -28,7 +28,7 @@ class QuickvoteControllerTest < Test::Unit::TestCase
   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
@@ -42,19 +42,19 @@ class QuickvoteControllerTest < Test::Unit::TestCase
   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
 
@@ -119,7 +119,7 @@ class QuickvoteControllerTest < Test::Unit::TestCase
     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
index b640f0c17fe662a7bcb9d19196b4df4cc57252df..86d190ef661c4ab92147d548c6382aa7277629f7 100644 (file)
@@ -1,10 +1,8 @@
 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
index 60663cfc7d477fa4e4fbf5db66138e2e065ef986..90a2d4faa7fcea1870c2457e28ed10dd7b212407 100644 (file)
@@ -1,10 +1,7 @@
 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
diff --git a/test/unit/quickvote_test.rb b/test/unit/quickvote_test.rb
new file mode 100644 (file)
index 0000000..69a7033
--- /dev/null
@@ -0,0 +1,38 @@
+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
index c0f73c02789236df5c23e8728cc0d79aca329144..1c28cf1b5277a4125f99953444bd80dcb1aabdc0 100644 (file)
@@ -9,13 +9,16 @@ class SelectricityServiceTest < Test::Unit::TestCase
   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
 
@@ -29,18 +32,22 @@ class SelectricityServiceTest < Test::Unit::TestCase
   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
@@ -50,132 +57,188 @@ class SelectricityServiceTest < Test::Unit::TestCase
   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)
diff --git a/vendor/plugins/dynamic_sessions/init.rb b/vendor/plugins/dynamic_sessions/init.rb
new file mode 100644 (file)
index 0000000..bc1da90
--- /dev/null
@@ -0,0 +1 @@
+require 'dynamic_session_expiry'
\ No newline at end of file
diff --git a/vendor/plugins/dynamic_sessions/lib/dynamic_session_expiry.rb b/vendor/plugins/dynamic_sessions/lib/dynamic_session_expiry.rb
new file mode 100644 (file)
index 0000000..8752365
--- /dev/null
@@ -0,0 +1,38 @@
+# 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

Benjamin Mako Hill || Want to submit a patch?