From 8e9679101b638f65af8be2e034263efed09bf22e Mon Sep 17 00:00:00 2001 From: "Robin H. Johnson" Date: Thu, 17 Jun 2021 23:56:42 -0700 Subject: Votify: improvements from re-using the codebase for another project Signed-off-by: Robin H. Johnson --- Votify.pm | 49 +++++++++++++++++++++++++++++++++++-------------- countify | 19 +++++++++++++------ 2 files changed, 48 insertions(+), 20 deletions(-) diff --git a/Votify.pm b/Votify.pm index 87fba2f..35a717f 100644 --- a/Votify.pm +++ b/Votify.pm @@ -8,13 +8,13 @@ package Votify; -use POSIX; +use Carp::Always; use Cwd qw(abs_path); +use Data::Dumper; use File::Basename; use File::Spec::Functions; use List::Util; -use Data::Dumper; -use Carp::Always; +use POSIX; use strict; use warnings; @@ -218,8 +218,8 @@ sub new { close(F); # assign confirmation numbers randomly - for my $v (@voterlist) { - do { $r = int rand 0xffff } while exists $self->{'voters'}{$r}; + for my $v (List::Util::shuffle(@voterlist)) { + do { $r = int rand 0xffffffff } while exists $self->{'voters'}{$r}; $self->{'voters'}{$r} = $v; $self->{'confs'}{$v} = $r; } @@ -239,7 +239,7 @@ sub confs { sub voters { my ($self) = @_; - sort keys %{$self->{'confs'}}; + return sort keys %{$self->{'confs'}}; } sub getvoter { @@ -252,7 +252,7 @@ sub getconf { return $self->{'confs'}{$voter}; } -sub write { +sub write_confs { my ($self, $filename) = @_; $filename ||= $self->{'default_filename'}; @@ -263,8 +263,8 @@ sub write { } open(F, ">$filename") or die("can't write to $filename"); - for my $c ($self->confs) { - printf F "%04x %s\n", $c, $self->getvoter($c); + for my $c (sort { $a <=> $b } map { int $_ } $self->confs) { + printf F "%08x %s\n", $c, $self->getvoter($c); } close F; } @@ -287,6 +287,7 @@ sub new { default_filename => catfile($datadir, "master-$election_name"), filename => '', voterlist => $vl, + casting_voters => {}, # indexed by voter ballots => {}, # indexed by conf num candidates => undef, # indexed by long name table => undef, # indexed by row+column @@ -326,6 +327,7 @@ sub collect { next; } $self->{'ballots'}{$c} = $b; + $self->{'casting_voters'}{$v} = 1; } elsif (-f "$home/.ballot-$self->{election}") { print STDERR "Warning: $v did not submit their ballot\n"; @@ -333,7 +335,7 @@ sub collect { } } -sub write { +sub write_master { my ($self, $filename) = @_; $filename ||= $self->{'default_filename'}; @@ -344,14 +346,15 @@ sub write { } open(F, ">$filename") or die("can't write to $filename"); - for my $c (sort keys %{$self->{'ballots'}}) { - printf F "--------- confirmation %04x ---------\n", $c; + for my $c (sort { $a <=> $b } map { int $_ } keys %{$self->{'ballots'}}) { + my $confid = sprintf("%08x",$c); + printf F "--------- confirmation %s ---------\n", $confid; print F $self->{'ballots'}{$c}->to_s } close F; } -sub read { +sub read_master { my ($self, $filename) = @_; my ($election, $entries) = $self->{'election'}; @@ -362,7 +365,7 @@ sub read { { local $/ = undef; $entries = ; } for my $e (split /^--------- confirmation /m, $entries) { next unless $e; # skip the first zero-length record - unless ($e =~ /^([[:xdigit:]]{4}) ---------\n(.*)$/s) { + unless ($e =~ /^([[:xdigit:]]{4,12}) ---------\n(.*)$/s) { die "error parsing entry:\n$e"; } my ($c, $s, $b) = ($1, $2, Ballot->new($election)); @@ -371,6 +374,24 @@ sub read { } } +sub write_casting_voters { + my ($self, $filename) = @_; + + $filename ||= $self->{'default_filename'}; + $self->{'filename'} = $filename; + + if (-f $filename) { + die "$filename already exists; please remove it first"; + } + + open(F, ">$filename") or die("can't write to $filename"); + for my $v (sort keys %{$self->{'casting_voters'}}) { + printf F "%s\n", $v; + } + close F; +} + + sub generate_candidates { my ($self) = @_; my ($B, @C, $s); diff --git a/countify b/countify index 13618a4..cf31d69 100755 --- a/countify +++ b/countify @@ -19,9 +19,13 @@ BEGIN { push @INC, $dirname; } -use POSIX; +use Cwd qw(abs_path); +use File::Basename; +use File::Spec::Functions; use Getopt::Long; use List::Util; +use POSIX; + use Votify 'official'; use strict; @@ -94,12 +98,15 @@ if ($opt{'collect'}) { $master->collect($vl->voters); for my $o ($ol->officials) { my ($uid, $home) = (getpwnam $o)[2,7]; - mkdir "$home/results-$election"; - $master->write("$home/results-$election/master-$election"); - $vl->write("$home/results-$election/confs-$election"); + $home = "/home/$o" unless defined $home; + mkdir catfile("$home", "results-$election"); + $master->write_master("$home/results-$election/master-$election"); + $master->write_casting_voters("$home/results-$election/casting-voters-$election"); + $vl->write_confs("$home/results-$election/confs-$election"); chown $uid, -1, "$home/results-$election", "$home/results-$election/master-$election", - "$home/results-$election/confs-$election"; + "$home/results-$election/confs-$election", + "$home/results-$election/casting-voters-$election"; } exit 0; } @@ -107,7 +114,7 @@ if ($opt{'collect'}) { if ($opt{'rank'}) { my ($master) = MasterBallot->new($election, $vl); my (@candidates, @winner, @ranked, @ranks); - $master->read("$ENV{HOME}/results-$election/master-$election"); + $master->read_master("$ENV{HOME}/results-$election/master-$election"); $master->generate_candidates(); @candidates = sort keys %{$master->{'candidates'}}; -- cgit v1.2.3-65-gdbad