From d86d7d89145230100980ca13bf44083ae1e954cb Mon Sep 17 00:00:00 2001
From: John Dong
Date: Tue, 14 Aug 2007 17:31:59 -0400
Subject: [PATCH 01/16] * Refactor candidate map over to its own API call
---
app/apis/selectricity_api.rb | 4 ++++
app/models/selectricity_service.rb | 11 +++++++++++
2 files changed, 15 insertions(+)
diff --git a/app/apis/selectricity_api.rb b/app/apis/selectricity_api.rb
index 8c0f04f..d478a5a 100644
--- a/app/apis/selectricity_api.rb
+++ b/app/apis/selectricity_api.rb
@@ -4,6 +4,9 @@ class VoteResultStruct < ActionWebService::Struct
member :condorcet_winners, [:int]
member :ssd_winners, [:int]
member :borda_winners, [:int]
+ member :errors, [:string]
+end
+class CandidateMap < ActionWebService::Struct
member :candidate_ids, [:int]
member :candidate_names, [:string]
member :errors, [:string]
@@ -11,6 +14,7 @@ end
class SelectricityAPI < ActionWebService::API::Base
api_method :cast_quickvote, :expects => [:int, :int, [[:int]]], :returns => [:string]
api_method :get_quickvote_results, :expects => [:string], :returns => [VoteResultStruct]
+ api_method :get_quickvote_candidate_map, :expects => [:string], :returns => [CandidateMap]
end
diff --git a/app/models/selectricity_service.rb b/app/models/selectricity_service.rb
index c0adc8a..75d2e3e 100644
--- a/app/models/selectricity_service.rb
+++ b/app/models/selectricity_service.rb
@@ -20,10 +20,21 @@ class SelectricityService < ActionWebService::Base
result.condorcet_winners=qv.condorcet_result.winners
result.ssd_winners=qv.ssd_result.winners
result.borda_winners=qv.borda_result.winners
+ result
+ end
+ def get_quickvote_candidate_map(shortname)
+ qv=QuickVote.ident_to_quickvote(shortname)
+ result=CandidateMap.new
+ result.errors=[]
+ unless qv
+ result.errors << "No quickvote with name #{shortname} found!"
+ return result
+ end
candidates={}
qv.candidates.each {|c| candidates[c.id] = c.name}
result.candidate_ids=candidates.keys
result.candidate_names=candidates.values
result
end
+
end
--
2.39.2
From 8afec3c5b4896fd7665e6527f3acb7c7afac7e47 Mon Sep 17 00:00:00 2001
From: John Dong
Date: Tue, 14 Aug 2007 18:23:06 -0400
Subject: [PATCH 02/16] Fix broken Plurality vote by removing a type check in
RubyVote. TODO: Figure out why it was in there
---
app/models/quick_vote.rb | 2 --
lib/rubyvote/election.rb | 2 +-
2 files changed, 1 insertion(+), 3 deletions(-)
diff --git a/app/models/quick_vote.rb b/app/models/quick_vote.rb
index 5f566c6..c427b98 100644
--- a/app/models/quick_vote.rb
+++ b/app/models/quick_vote.rb
@@ -63,7 +63,6 @@ class QuickVote < Election
preference_tally << voter.vote.rankings.sort.collect \
{ |ranking| ranking.candidate.id }
end
-
@plurality_result = PluralityVote.new(plurality_tally).result
@approval_result = ApprovalVote.new(approval_tally).result
@condorcet_result = PureCondorcetVote.new(preference_tally).result
@@ -72,7 +71,6 @@ class QuickVote < Election
#@runoff_result = InstantRunoffVote.new(preference_tally).result
#@runoff_results = PluralityVote.new(preference_tally).result
-
end
### Convert a shortname or id into a QuickVote
diff --git a/lib/rubyvote/election.rb b/lib/rubyvote/election.rb
index 75614e6..66e4c2a 100644
--- a/lib/rubyvote/election.rb
+++ b/lib/rubyvote/election.rb
@@ -75,7 +75,7 @@ class PluralityVote < ElectionVote
protected
def verify_vote(vote=nil)
- vote.instance_of?( String )
+ not vote.instance_of?( Array )
end
def tally_vote(candidate)
--
2.39.2
From 886da4d0dc54fabee70bf4e7aea4d2988f7cf83d Mon Sep 17 00:00:00 2001
From: John Dong
Date: Wed, 15 Aug 2007 12:00:58 -0400
Subject: [PATCH 03/16] Import latest subversion RubyVote.
---
lib/rubyvote/election.rb | 20 +++++++++++++++-----
1 file changed, 15 insertions(+), 5 deletions(-)
diff --git a/lib/rubyvote/election.rb b/lib/rubyvote/election.rb
index 66e4c2a..b9bb557 100644
--- a/lib/rubyvote/election.rb
+++ b/lib/rubyvote/election.rb
@@ -34,7 +34,7 @@
class ElectionVote
attr_reader :votes
attr_reader :candidates
-
+
def initialize(votes=nil)
@votes = Hash.new unless defined?(@votes)
@candidates = Array.new unless defined?(@candidates)
@@ -42,7 +42,11 @@ class ElectionVote
if votes
if votes.instance_of?( Array )
votes.each do |vote|
- self.tally_vote(vote) if self.verify_vote(vote)
+ if self.verify_vote(vote)
+ self.tally_vote(vote)
+ else
+ raise InvalidVoteError.new ("Invalid vote object", vote)
+ end
end
else
raise ElectionError, "Votes must be in the form of an array.", caller
@@ -75,7 +79,7 @@ class PluralityVote < ElectionVote
protected
def verify_vote(vote=nil)
- not vote.instance_of?( Array )
+ vote ? true : false
end
def tally_vote(candidate)
@@ -114,8 +118,7 @@ end
class ElectionResult
attr_reader :winners
- attr_reader :election
-
+
def initialize(voteobj=nil)
unless voteobj and voteobj.kind_of?( ElectionVote )
raise ArgumentError, "You must pass a ElectionVote array.", caller
@@ -164,3 +167,10 @@ end
class ElectionError < ArgumentError
end
+class InvalidVoteError < ElectionError
+ attr_accessor :voteobj
+ def initialize(msg=nil, voteobj=nil)
+ super(msg)
+ @voteobj=voteobj
+ end
+end
--
2.39.2
From c6cd449132c45625d6453d1ffed08bc9142db8d3 Mon Sep 17 00:00:00 2001
From: John Dong
Date: Wed, 15 Aug 2007 12:30:25 -0400
Subject: [PATCH 04/16] XMLRPC: Add translator from candidate ID to names
---
app/apis/selectricity_api.rb | 1 +
app/models/selectricity_service.rb | 17 +++++++++++++++++
2 files changed, 18 insertions(+)
diff --git a/app/apis/selectricity_api.rb b/app/apis/selectricity_api.rb
index d478a5a..da2f6f7 100644
--- a/app/apis/selectricity_api.rb
+++ b/app/apis/selectricity_api.rb
@@ -15,6 +15,7 @@ class SelectricityAPI < ActionWebService::API::Base
api_method :cast_quickvote, :expects => [:int, :int, [[:int]]], :returns => [:string]
api_method :get_quickvote_results, :expects => [:string], :returns => [VoteResultStruct]
api_method :get_quickvote_candidate_map, :expects => [:string], :returns => [CandidateMap]
+ api_method :quickvote_candidate_ids_to_names, :expects => [:string,[:int]], :returns => [[:string]]
end
diff --git a/app/models/selectricity_service.rb b/app/models/selectricity_service.rb
index 75d2e3e..eb09d8d 100644
--- a/app/models/selectricity_service.rb
+++ b/app/models/selectricity_service.rb
@@ -5,6 +5,23 @@ class SelectricityService < ActionWebService::Base
def cast_quickvote(election_id, vote_id, vote_list)
#Obviously not implemented
end
+ def quickvote_candidate_ids_to_names(shortname, id_list)
+ qv=QuickVote.ident_to_quickvote(shortname)
+ candidates={}
+ return [] unless qv
+ qv.results
+ qv.candidates.each {|c| candidates[c.id] = c}
+ results=[]
+ id_list.each { |id|
+ name=candidates[id]
+ if name
+ results << name
+ else
+ results << ""
+ end
+ }
+ results
+ end
def get_quickvote_results(shortname)
#TODO: Validate shortname
qv=QuickVote.ident_to_quickvote(shortname)
--
2.39.2
From 06bede5ddbcd7f26e50a958c4d64527580cc38c9 Mon Sep 17 00:00:00 2001
From: John Dong
Date: Wed, 15 Aug 2007 15:12:41 -0400
Subject: [PATCH 05/16] Commit partial implementation of casting quickvotes via
xmlrpc. WARNING: Currently I think it creates inconsistent objects in the
database that'll screw up voting.
---
app/apis/selectricity_api.rb | 2 +-
app/models/selectricity_service.rb | 15 +++++++++++++--
2 files changed, 14 insertions(+), 3 deletions(-)
diff --git a/app/apis/selectricity_api.rb b/app/apis/selectricity_api.rb
index da2f6f7..8a8dce4 100644
--- a/app/apis/selectricity_api.rb
+++ b/app/apis/selectricity_api.rb
@@ -12,7 +12,7 @@ class CandidateMap < ActionWebService::Struct
member :errors, [:string]
end
class SelectricityAPI < ActionWebService::API::Base
- api_method :cast_quickvote, :expects => [:int, :int, [[:int]]], :returns => [:string]
+ api_method :cast_quickvote, :expects => [:string, :int, [[:int]]], :returns => [:string]
api_method :get_quickvote_results, :expects => [:string], :returns => [VoteResultStruct]
api_method :get_quickvote_candidate_map, :expects => [:string], :returns => [CandidateMap]
api_method :quickvote_candidate_ids_to_names, :expects => [:string,[:int]], :returns => [[:string]]
diff --git a/app/models/selectricity_service.rb b/app/models/selectricity_service.rb
index eb09d8d..86458e0 100644
--- a/app/models/selectricity_service.rb
+++ b/app/models/selectricity_service.rb
@@ -2,8 +2,19 @@ require 'action_controller/integration'
class SelectricityService < ActionWebService::Base
web_service_api SelectricityAPI
- def cast_quickvote(election_id, vote_id, vote_list)
- #Obviously not implemented
+ def cast_quickvote(election_name, voter_id, vote_list)
+ election = QuickVote.ident_to_quickvote election_name
+ if election
+ voter = QuickVoter.new
+ voter.election = election
+ voter.session_id = "XMLRPC:#{voter_id}"
+ voter.vote=Vote.new
+ voter.vote.votes=vote_list[0]
+ voter.vote.time = Time.now
+ voter.save!
+ voter.vote.confirm!
+ voter.save!
+ end
end
def quickvote_candidate_ids_to_names(shortname, id_list)
qv=QuickVote.ident_to_quickvote(shortname)
--
2.39.2
From 9565924bed8f9afd0682d4d029378711b905c550 Mon Sep 17 00:00:00 2001
From: John Dong
Date: Wed, 15 Aug 2007 15:53:26 -0400
Subject: [PATCH 06/16] Import latest RubyVote svn to fix infinite loop bug
---
lib/rubyvote/condorcet.rb | 5 ++++-
lib/rubyvote/irv.rb | 5 +++++
2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/lib/rubyvote/condorcet.rb b/lib/rubyvote/condorcet.rb
index 65c664d..c0539ab 100644
--- a/lib/rubyvote/condorcet.rb
+++ b/lib/rubyvote/condorcet.rb
@@ -184,7 +184,10 @@ class PureCondorcetResult < CondorcetResult
def condorcet
votes = @election.votes
candidates = @election.candidates
-
+ unless votes.length>0 and candidates.length>0
+ @winners=[nil]
+ return @winners
+ end
victors = Hash.new
candidates.each do |candidate|
victors[candidate] = Array.new
diff --git a/lib/rubyvote/irv.rb b/lib/rubyvote/irv.rb
index 3851738..b26b1d1 100644
--- a/lib/rubyvote/irv.rb
+++ b/lib/rubyvote/irv.rb
@@ -87,6 +87,11 @@ class InstantRunoffResult < ElectionResult
apply_retention(votes, votes_sum * params['percent_retention'])
end
+ unless votes.length > 0
+ @winners=[nil]
+ return
+ end
+
begin
ranked_candidates = votes.sort do |a, b|
b[1][0] <=> a[1][0]
--
2.39.2
From ae1b10889b53eeabc3a1f2281cfc1555781ab7fb Mon Sep 17 00:00:00 2001
From: John Dong
Date: Wed, 15 Aug 2007 16:17:11 -0400
Subject: [PATCH 07/16] Pull in svn Rubyvote again
---
lib/rubyvote/condorcet.rb | 4 ++--
lib/rubyvote/election.rb | 2 +-
lib/rubyvote/irv.rb | 2 +-
3 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/lib/rubyvote/condorcet.rb b/lib/rubyvote/condorcet.rb
index c0539ab..0b7a306 100644
--- a/lib/rubyvote/condorcet.rb
+++ b/lib/rubyvote/condorcet.rb
@@ -185,7 +185,7 @@ class PureCondorcetResult < CondorcetResult
votes = @election.votes
candidates = @election.candidates
unless votes.length>0 and candidates.length>0
- @winners=[nil]
+ @winners=[]
return @winners
end
victors = Hash.new
@@ -224,7 +224,7 @@ class CloneproofSSDResult < CondorcetResult
def cpssd
votes = @election.votes
candidates = *@election.candidates
-
+
def in_schwartz_set?(candidate, candidates, transitive_defeats)
candidates.each do |challenger|
next if candidate == challenger
diff --git a/lib/rubyvote/election.rb b/lib/rubyvote/election.rb
index b9bb557..42f18bb 100644
--- a/lib/rubyvote/election.rb
+++ b/lib/rubyvote/election.rb
@@ -133,7 +133,7 @@ class ElectionResult
end
def winner?
- @winners.length > 0
+ @winners.length > 0 and not @winners[0].nil?
end
end
diff --git a/lib/rubyvote/irv.rb b/lib/rubyvote/irv.rb
index b26b1d1..c3fabe6 100644
--- a/lib/rubyvote/irv.rb
+++ b/lib/rubyvote/irv.rb
@@ -88,7 +88,7 @@ class InstantRunoffResult < ElectionResult
end
unless votes.length > 0
- @winners=[nil]
+ @winners=[]
return
end
--
2.39.2
From 07800d892d8454c16d75ddc35cd36e630498aab0 Mon Sep 17 00:00:00 2001
From: John Dong
Date: Wed, 15 Aug 2007 16:28:05 -0400
Subject: [PATCH 08/16] Merge another cpssd fix
---
lib/rubyvote/condorcet.rb | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/lib/rubyvote/condorcet.rb b/lib/rubyvote/condorcet.rb
index 0b7a306..aaa5044 100644
--- a/lib/rubyvote/condorcet.rb
+++ b/lib/rubyvote/condorcet.rb
@@ -217,6 +217,7 @@ class CloneproofSSDResult < CondorcetResult
def initialize(voteobj=nil)
super(voteobj)
@winners = self.cpssd()
+ @winners.delete nil
end
protected
@@ -224,7 +225,7 @@ class CloneproofSSDResult < CondorcetResult
def cpssd
votes = @election.votes
candidates = *@election.candidates
-
+
def in_schwartz_set?(candidate, candidates, transitive_defeats)
candidates.each do |challenger|
next if candidate == challenger
--
2.39.2
From 9770c8de272b16601b7c5d26ddb73a83993dd16b Mon Sep 17 00:00:00 2001
From: John Dong
Date: Wed, 15 Aug 2007 16:37:03 -0400
Subject: [PATCH 09/16] Add some quick info about XMLRPC API
---
README | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/README b/README
index f8a8928..88fcd97 100644
--- a/README
+++ b/README
@@ -81,6 +81,26 @@ gem installed, you can use the ri command, or the above mentioned gem_server.
If you guys want more helpful stuff here, let me know.
+======================================
+=== XML-RPC INFO ==
+======================================
+
+The XML-RPC API is still under development, but is somewhat functional already:
+
+To instantiate a client in Ruby, try something like:
+client=ActionWebService::Client::XmlRpc.new(SelectricityAPI,"http://localhost:3000/selectricity_service/vote")
+
+
+Getting the results of a quickvote is quite simple:
+?> client.get_quickvote_results("test")
+=> #
+
+Casting a quickvote:
+client.cast_quickvote("test",1,[[1,2]])
+
+To figure out what you're voting for:
+>> client.get_quickvote_candidate_map("test")=> #
+
--
2.39.2
From 7f2bdc00ac867092eebed2b64596efeaacca0d87 Mon Sep 17 00:00:00 2001
From: John Dong
Date: Wed, 15 Aug 2007 16:45:51 -0400
Subject: [PATCH 10/16] Record a junk IP address for XMLRPC'ers
---
app/models/selectricity_service.rb | 1 +
1 file changed, 1 insertion(+)
diff --git a/app/models/selectricity_service.rb b/app/models/selectricity_service.rb
index 86458e0..ac2ef20 100644
--- a/app/models/selectricity_service.rb
+++ b/app/models/selectricity_service.rb
@@ -7,6 +7,7 @@ class SelectricityService < ActionWebService::Base
if election
voter = QuickVoter.new
voter.election = election
+ voter.ipaddress = "0.0.0.0"
voter.session_id = "XMLRPC:#{voter_id}"
voter.vote=Vote.new
voter.vote.votes=vote_list[0]
--
2.39.2
From 597c27db39d8b36e623a9d6573e75edf657142c0 Mon Sep 17 00:00:00 2001
From: John Dong
Date: Wed, 15 Aug 2007 17:03:41 -0400
Subject: [PATCH 11/16] Record "XMLRPC Request" in ipadress field of XML RPC
created votes.
Added IPAddr verification of IP Addresses
---
app/models/selectricity_service.rb | 2 +-
app/views/quickvote/results.rhtml | 10 ++++++++--
2 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/app/models/selectricity_service.rb b/app/models/selectricity_service.rb
index ac2ef20..add5ab9 100644
--- a/app/models/selectricity_service.rb
+++ b/app/models/selectricity_service.rb
@@ -7,7 +7,7 @@ class SelectricityService < ActionWebService::Base
if election
voter = QuickVoter.new
voter.election = election
- voter.ipaddress = "0.0.0.0"
+ voter.ipaddress = "XMLRPC Request"
voter.session_id = "XMLRPC:#{voter_id}"
voter.vote=Vote.new
voter.vote.votes=vote_list[0]
diff --git a/app/views/quickvote/results.rhtml b/app/views/quickvote/results.rhtml
index 1fad7ea..98a71e5 100644
--- a/app/views/quickvote/results.rhtml
+++ b/app/views/quickvote/results.rhtml
@@ -1,4 +1,4 @@
-<% %>
+<%require 'IPAddr' %>
Results
<% if @election.shortdesc %>
@@ -156,7 +156,13 @@ by several other names.
<% next unless voter.voted? %>
<%= voter.ipaddress %> |
- <%= `host #{voter.ipaddress}`.sub(/^.*pointer (.*)\.$/, '\1') %> |
+ <% begin %>
+ <%= `host #{IPAddr.new(voter.ipaddress).to_s}`.sub(/^.*pointer (.*)\.$/, '\1') %>
+
+ <% rescue ArgumentError => err %>
+ <%= " - " %>
+ <% end %>
+ |
<%= voter.vote.votestring %> |
<% end %>
--
2.39.2
From 8f3646d179b4d779c9521b6cc1b227f371830395 Mon Sep 17 00:00:00 2001
From: John Dong
Date: Wed, 15 Aug 2007 17:35:51 -0400
Subject: [PATCH 12/16] Display same in hostname and IP when IP lookup fails
---
app/views/quickvote/results.rhtml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/views/quickvote/results.rhtml b/app/views/quickvote/results.rhtml
index 98a71e5..9677d9a 100644
--- a/app/views/quickvote/results.rhtml
+++ b/app/views/quickvote/results.rhtml
@@ -160,7 +160,7 @@ by several other names.
<%= `host #{IPAddr.new(voter.ipaddress).to_s}`.sub(/^.*pointer (.*)\.$/, '\1') %>
<% rescue ArgumentError => err %>
- <%= " - " %>
+ <%= voter.ipaddress %>
<% end %>
<%= voter.vote.votestring %> |
--
2.39.2
From 924aa1ff433ac4ccd2db5851e91038088be00a09 Mon Sep 17 00:00:00 2001
From:
Date: Wed, 15 Aug 2007 17:46:20 -0400
Subject: [PATCH 13/16] Modified graphs to ahve a 4 color scheme, but it isn't
the full palette of selectricity yet , that will be on next commit. LAso
modified several voting methods within RubyVote to have more useful instance
variables and accessors available in the results class. the quickvote results
view has been updated to include a partial for displaying a condorcet vote
table, w hich is strangely appearing below the footer on the results page, it
seems to be displaying the correct data however.
---
.bzrignore | 1 +
app/controllers/graph_controller.rb | 38 +++++++++++++++++----------
app/views/quickvote/_pref_table.rhtml | 19 ++++++++++++++
app/views/quickvote/results.rhtml | 4 +--
lib/rubyvote/condorcet.rb | 6 +++--
lib/rubyvote/election.rb | 5 +++-
lib/rubyvote/positional.rb | 9 ++++---
7 files changed, 60 insertions(+), 22 deletions(-)
create mode 100644 app/views/quickvote/_pref_table.rhtml
diff --git a/.bzrignore b/.bzrignore
index 50c7c5b..1e24ca1 100644
--- a/.bzrignore
+++ b/.bzrignore
@@ -5,3 +5,4 @@ server.log
test.log
tmp
public/engine_files
+.DS_Store
diff --git a/app/controllers/graph_controller.rb b/app/controllers/graph_controller.rb
index 8256884..bbd5cd7 100644
--- a/app/controllers/graph_controller.rb
+++ b/app/controllers/graph_controller.rb
@@ -7,13 +7,19 @@ class GraphController < ApplicationController
size = "700x400"
@graph = options[:graph_type].new(size)
- @graph.theme = { :background_colors => ['#73BF26', '#ffffff'] }
+ @graph.theme = { :colors => ['#000000', '#00FFFF', '#FFCC00', '#990033'],
+ :background_colors => ['#74ce00', '#ffffff'] }
@graph.font = File.expand_path('/usr/X11R6/lib/X11/fonts/TTF/Vera.ttf',
RAILS_ROOT)
# fill in the data with the optional data name
- #Check to see if multiple datasets, if so, fill them all!
- if options[:data].size > 1 && options[:data].all? {|i| i.is_a?(Array)}
+ #Check to see if multiple datasets, if so, fill them all!
+ if options[:data].is_a?(Hash)
+ options[:data].each_pair do |name, array|
+ @graph.data( name, array)
+ end
+ #if each dataset nameless, will have only multiple arrays
+ elsif options[:data].size > 1 && options[:data].all? {|i| i.is_a?(Array)}
options[:data].each do |array|
@graph.data( options.fetch(:data_name, "Data"), array)
end
@@ -73,10 +79,10 @@ class GraphController < ApplicationController
def borda_bar
@election = Election.find(params[:id])
- pref_tally = make_preference_tally(@election)
+ #pref_tally = make_preference_tally(@election)
- @borda_result = BordaVote.new(pref_tally).result
- data, labels = get_borda_points(@borda_result)
+ #@borda_result = BordaVote.new(pref_tally).result
+ data, labels = get_borda_points(@election.borda_result)
graph = GruffGraff.new( :graph_type => Gruff::Bar,
:data_name => @election.name,
@@ -87,16 +93,22 @@ class GraphController < ApplicationController
:x_axis_label => "Candidate")
send_data(*graph.output)
end
-
- def choices_positions
+ #Acording to Tufte, small, concomparitive, highly labeled data sets usually
+ # belong in tables. The following is a bar graph...but would it be better
+ #as a table?
+ def choices_positions
@election = Election.find(params[:id])
pref_tally = make_preference_tally(@election)
fulldata, labels = get_positions_info(@election)
- labels = @candidates
+ legend = Hash.new
+
+ @election.candidates.each_with_index do |candidate, index|
+ legend[candidate.name] = fulldata[index]
+ end
+
graph = GruffGraff.new( :graph_type => Gruff::Bar,
- :data_name => @election.name,
- :data => fulldata,
+ :data => legend,
:interval_labels => labels,
:title => "Times Voted in Each Position",
:y_axis_label => "Number of Times Ranked",
@@ -133,7 +145,7 @@ class GraphController < ApplicationController
rank_labels[i] = (i+1).to_s
end
end
-
+
return buckets2.values, rank_labels
end
@@ -236,8 +248,6 @@ class GraphController < ApplicationController
end
def get_borda_points(result)
- #points holds how mnay points each candidate has received in array form
- #becasue Gruff::Bar#data takes only an array
points = Array.new
labels = Hash.new
diff --git a/app/views/quickvote/_pref_table.rhtml b/app/views/quickvote/_pref_table.rhtml
new file mode 100644
index 0000000..dfcb6cc
--- /dev/null
+++ b/app/views/quickvote/_pref_table.rhtml
@@ -0,0 +1,19 @@
+<% candidates = @election.candidates.sort.collect {|candidate| candidate.id} -%>
+
+
+ |
+ <% candidates.each do |candidate| -%>
+ <%= candidate -%> |
+ <% end -%>
+<% candidates.each do |winner| -%>
+
+ <%= winner %> |
+ <% candidates.each do |loser| -%>
+ <% if winner == loser -%>
+ -- |
+ <% else %>
+ <%= @election.condorcet_result.matrix[winner][loser] %> |
+ <% end -%>
+ <% end -%>
+
+<%end -%>
\ No newline at end of file
diff --git a/app/views/quickvote/results.rhtml b/app/views/quickvote/results.rhtml
index 98a71e5..5626636 100644
--- a/app/views/quickvote/results.rhtml
+++ b/app/views/quickvote/results.rhtml
@@ -145,7 +145,6 @@ by several other names.
Voters
-
IP Address |
@@ -168,8 +167,9 @@ by several other names.
<% end %>
+<%= render :partial => 'pref_table' %>
+
<%= image_tag( graph_url( :action => 'votes_per_day', :id => @election ) ) %>
<%= image_tag( graph_url( :action => 'votes_per_interval', :id => @election ))%>
<%= image_tag( graph_url( :action => 'borda_bar', :id => @election ) ) %>
<%= image_tag( graph_url( :action => 'choices_positions', :id => @election ) ) %>
-
diff --git a/lib/rubyvote/condorcet.rb b/lib/rubyvote/condorcet.rb
index aaa5044..bf4e548 100644
--- a/lib/rubyvote/condorcet.rb
+++ b/lib/rubyvote/condorcet.rb
@@ -32,7 +32,7 @@
## the CloneproofSSDVote classes but should not be used directly.
class CondorcetVote < ElectionVote
-
+
attr_accessor :results
def initialize(votes=nil)
@@ -144,15 +144,17 @@ end
## directly.
class CondorcetResult < ElectionResult
+ attr_reader :matrix
+
def initialize(voteobj=nil)
unless voteobj and voteobj.kind_of?( CondorcetVote )
raise ArgumentError, "You must pass a CondorcetVote array.", caller
end
super(voteobj)
+ @matrix = voteobj.votes
end
protected
-
def defeats(candidates=nil, votes=nil)
candidates = @election.candidates unless candidates
votes = @election.votes unless votes
diff --git a/lib/rubyvote/election.rb b/lib/rubyvote/election.rb
index 42f18bb..efb8dd8 100644
--- a/lib/rubyvote/election.rb
+++ b/lib/rubyvote/election.rb
@@ -140,7 +140,8 @@ end
class PluralityResult < ElectionResult
attr_reader :ranked_candidates
-
+ attr_reader :points
+
def initialize(voteobj=nil)
super(voteobj)
@@ -151,6 +152,8 @@ class PluralityResult < ElectionResult
b[1] <=> a[1]
end.collect {|a| a[0]}
+ @points = self.election.votes
+
# winners are anyone who has the same number of votes as the
# first person
@winners = @ranked_candidates.find_all do |i|
diff --git a/lib/rubyvote/positional.rb b/lib/rubyvote/positional.rb
index 3de3fb2..dc0b63a 100644
--- a/lib/rubyvote/positional.rb
+++ b/lib/rubyvote/positional.rb
@@ -38,7 +38,7 @@ class BordaVote < ElectionVote
end
super(votes)
end
-
+
def tally_vote(vote)
points = candidates.length - 1
vote.each do |candidate|
@@ -51,7 +51,7 @@ class BordaVote < ElectionVote
points -= 1
end
end
-
+
def verify_vote(vote=nil)
vote.instance_of?( Array ) and
vote == vote.uniq
@@ -64,11 +64,12 @@ end
class BordaResult < ElectionResult
attr_reader :ranked_candidates
+ attr_reader :points
def initialize(voteobj=nil)
super(voteobj)
votes = @election.votes
-
+
@ranked_candidates = votes.sort do |a, b|
b[1] <=> a[1]
end.collect {|i| i[0]}
@@ -76,6 +77,8 @@ class BordaResult < ElectionResult
@winners = @ranked_candidates.find_all do |i|
votes[i] == votes[@ranked_candidates[0]]
end
+
+ @points = self.election.votes
end
end
--
2.39.2
From e682e1ecce33417f8410e71bd58d385c47e37c5b Mon Sep 17 00:00:00 2001
From: John Dong
Date: Thu, 16 Aug 2007 13:09:31 -0400
Subject: [PATCH 14/16] Fix crasher when nil is passed to ident_to_quickvote
---
app/models/quick_vote.rb | 1 +
1 file changed, 1 insertion(+)
diff --git a/app/models/quick_vote.rb b/app/models/quick_vote.rb
index c427b98..ce4a4fb 100644
--- a/app/models/quick_vote.rb
+++ b/app/models/quick_vote.rb
@@ -75,6 +75,7 @@ class QuickVote < Election
### Convert a shortname or id into a QuickVote
def self.ident_to_quickvote(ident)
+ return nil unless ident
if ident.match(/^\d+$/)
quickvote = QuickVote.find(ident)
else
--
2.39.2
From cf4234876994cb4b7e09cdd116e092424d9f4951 Mon Sep 17 00:00:00 2001
From: John Dong
Date: Thu, 16 Aug 2007 13:54:37 -0400
Subject: [PATCH 15/16] * Tighter validation, closed a number of crashes due to
invalid data * Security: Escape HTML to prevent injection of code onto the
form * Prevent empty candidates from passing validation * Clearer, non
Engrishy error messages on quickvote/create * Prevent quickvote ident names
from clashing with reserved controller actions
---
app/models/quick_vote.rb | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/app/models/quick_vote.rb b/app/models/quick_vote.rb
index ce4a4fb..0efb574 100644
--- a/app/models/quick_vote.rb
+++ b/app/models/quick_vote.rb
@@ -10,12 +10,16 @@ class QuickVote < Election
attr_accessor :borda_result
def validate
- if @raw_candidates.length < 2
- errors.add("You must list at least two candidates.")
+ if not @raw_candidates or @raw_candidates.length < 2
+ errors.add(nil, "You must list at least two candidates.")
end
-
+
if name =~ /[^A-Za-z0-9]/
- errors.add("The name must only include numbers and letters.")
+ errors.add(:name, "must only include numbers and letters.")
+ end
+
+ if name =~ /^(create|index|confirm|change|results)$/
+ errors.add(:name, " is a reserved word.")
end
end
@@ -40,6 +44,7 @@ class QuickVote < Election
end
def create_candidates
+ return unless errors.empty?
@raw_candidates.each do |name|
candidate = Candidate.new({:name => name})
self.candidates << candidate
--
2.39.2
From 40891d8740b77b6d6249e8982f15e2f348725282 Mon Sep 17 00:00:00 2001
From: John Dong
Date: Thu, 16 Aug 2007 13:56:41 -0400
Subject: [PATCH 16/16] Also a part of the previous commit
---
app/controllers/quickvote_controller.rb | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/app/controllers/quickvote_controller.rb b/app/controllers/quickvote_controller.rb
index 83a6cc5..2847df9 100644
--- a/app/controllers/quickvote_controller.rb
+++ b/app/controllers/quickvote_controller.rb
@@ -34,11 +34,13 @@ class QuickvoteController < ApplicationController
end
def add_candidate
- candidate_name = params[:ajax][:newcandidate]
- if flash.has_key?(:candlist) and flash[:candlist].instance_of?(Array)
- flash[:candlist] << candidate_name
- else
- flash[:candlist] = [ candidate_name ]
+ candidate_name = CGI.escapeHTML(params[:ajax][:newcandidate])
+ unless candidate_name.strip.empty?
+ if flash.has_key?(:candlist) and flash[:candlist].instance_of?(Array)
+ flash[:candlist] << candidate_name
+ else
+ flash[:candlist] = [ candidate_name ]
+ end
end
flash.keep(:candlist)
render_partial 'candidate_list'
--
2.39.2