diff options
-rw-r--r-- | Votify.pm | 127 | ||||
-rwxr-xr-x | countify | 38 | ||||
-rwxr-xr-x | listify | 58 | ||||
-rwxr-xr-x | votify | 55 |
4 files changed, 157 insertions, 121 deletions
@@ -9,10 +9,14 @@ package Votify; use POSIX; +use Cwd qw(abs_path); +use File::Spec::Functions; use List::Util; use strict; -our ($datadir) = '/etc/elections/current'; +our $datefmt = '%Y-%m-%d %H:%M:%S UTC'; + +our ($basedir) = List::Util::first { -d $_ } ('/etc/elections', '.'); (our $zero = $0) =~ s,.*/,,; our $version = '1.6'; @@ -21,6 +25,98 @@ sub import { $Votify::mode = $mode; } +my @REQUIRED_FILES = qw(ballot officials start stop voters); + +sub get_datadir { + my $election_name = shift; + my $election_dir = abs_path(catfile($Votify::basedir, $election_name)); + if(!validate_election_dir()) { + die "$election_name is not a valid election!" + } + return $election_dir; +} + +sub validate_election_dir { + return 0 unless $_; + my $election_dir = $_; + my $election_name = $election_dir; + $election_name =~ /.*\//; + return 0 unless -d $election_dir; + return 0 if substr($election_name,0,1) eq "."; + my $valid = List::Util::reduce { + $a or $b ? 1 : 0; + } map { + my $file_valid = 0; + # Legacy naming: + $file_valid = 1 if -f sprintf("%s/%s-%s", $election_name, $_, $election_name); + # New naming: + $file_valid = 1 if -f sprintf("%s/%s", $election_name, $_); + #printf "File %s valid=%d\n", $_, $file_valid; + $file_valid; + } @REQUIRED_FILES; + return $valid; +} + +sub get_elections_list { + my @elections; + opendir(D, $Votify::basedir) or die; + @elections = sort grep { + my $valid = validate_election_dir(catfile($Votify::basedir, $_)); + $valid; + } readdir D; + closedir D; + return @elections; +} + +sub grabfile_int { + my $f = shift; + #print "Checking $f\n"; + my $i = 0; + open my $fh, '<', $f or return -1; + local $/ = undef; + $i = <$fh> if defined($fh); + close $fh; + #print "Raw file: $i\n"; + chomp $i if $i; + return $i; +} + + +sub get_single_election_hashref { + my $election_name = shift; + my $election_dir = catfile($Votify::basedir, $election_name); + my %election; + foreach my $fn (@REQUIRED_FILES){ + #print "Scan $fn\n"; + my @filenames = (sprintf("%s/%s", $election_name, $fn), sprintf("%s/%s-%s", $election_name, $fn, $election_name)); + #print Dumper(@filenames); + my $filename = abs_path(List::Util::first { -f $_ } @filenames); + $election{"${fn}file"} = $filename; + }; + #print Dumper(%election); + $election{starttime} = grabfile_int($election{'startfile'}); + $election{stoptime} = grabfile_int($election{'stopfile'}); + return \%election; +} + +sub get_elections_hash { + my %elections; + %elections = map { $_ => get_single_election_hashref($_) } get_elections_list(); + return %elections; +} + +sub get_open_elections_hash { + my %elections = get_elections_hash(); + my @open_elections = grep { + my $starttime = $elections{$_}{'starttime'}; + my $stoptime = $elections{$_}{'stoptime'}; + my $valid = ((not defined $starttime or $starttime < time) and + (not defined $stoptime or $stoptime > time)); + $valid; + } keys %elections; + return map { $_ => $elections{$_} } @open_elections; +} + ###################################################################### # OfficialList ###################################################################### @@ -28,14 +124,15 @@ sub import { package OfficialList; sub new { - my ($class, $election) = @_; + my ($class, $election_name) = @_; my ($self) = { - election => $election, + election => $election_name, officials => [], }; + my $election = Votify::get_single_election_hashref($self->{'election'}); # no point in waiting to load - open(F, "<$Votify::datadir/officials-$election") + open(F, '<', $election->{'officialsfile'}) or die("failed to open officials file"); chomp(@{$self->{'officials'}} = <F>); close(F); @@ -56,18 +153,20 @@ sub officials { package VoterList; sub new { - my ($class, $election) = @_; + my ($class, $election_name) = @_; my (@voterlist, $r); + my $datadir = Votify::get_datadir($election_name); my ($self) = { - election => $election, - default_filename => "$Votify::datadir/confs-$election", + election => $election_name, + default_filename => catfile($datadir, "confs-$election_name"), filename => '', voters => {}, # confnum => voter confs => {}, # voter => confnum }; # no point in waiting to load - open(F, "<$Votify::datadir/voters-$election") + my $election = Votify::get_single_election_hashref($self->{'election'}); + open(F, '<', $election->{'votersfile'}) or die("failed to open voters file"); chomp(@voterlist = <F>); close(F); @@ -133,10 +232,11 @@ package MasterBallot; use Data::Dumper; sub new { - my ($class, $election, $vl) = @_; + my ($class, $election_name, $vl) = @_; + my $datadir = Votify::get_datadir($election_name); my ($self) = { - election => $election, - default_filename => "$Votify::datadir/master-$election", + election => $election_name, + default_filename => catfile($datadir, "master-$election_name"), filename => '', voterlist => $vl, ballots => {}, # indexed by conf num @@ -296,7 +396,7 @@ sub display_table { @shortnames = sort values %{$self->{'candidates'}}; $minlen = length scalar keys %{$self->{'ballots'}}; $minlen = 5 if $minlen < 5; - + # build the format string for my $s (@shortnames) { if (length($s) > $minlen) { @@ -491,7 +591,8 @@ sub read { sub populate { my ($self) = @_; - $self->read("$Votify::datadir/ballot-$self->{election}"); + my $election = Votify::get_single_election_hashref($self->{'election'}); + $self->read($election->{'ballotfile'}); @{$self->{'choices'}} = List::Util::shuffle(@{$self->{'choices'}}); } @@ -8,7 +8,13 @@ # #BEGIN { push @INC, (getpwnam 'fox2mike')[7].'/elections' } -BEGIN { push @INC, '/etc/elections/current' } +BEGIN { + if(-f '/etc/elections/Votify.pm') { + push @INC, '/etc/elections'; + } else { + push @INC, '.' if -f 'Votify.pm'; + } +} use POSIX; use Getopt::Long; @@ -24,33 +30,11 @@ use strict; (my $version = $Votify::version) =~ s/.*?(\d.*\d).*/$zero version $1\n/; my %opt; -sub grabfile_int { - my $f = shift; - open FILE, "<", $f; - my $i = <FILE>; - close FILE; - chomp $i; - return $i + 0; -} - # Collect the open elections -my (@open_elections, $usage_elections); -opendir(D, "$Votify::datadir/") or die; -@open_elections = sort grep { - s/^start-// and do { - my ($startfile) = sprintf "%s/start-%s", $Votify::datadir, $_; - my ($stopfile) = sprintf "%s/stop-%s", $Votify::datadir, $_; - my ($starttime) = grabfile_int($startfile); - my ($stoptime) = grabfile_int($stopfile); - $starttime = (stat _)[9] if stat($startfile) and (!defined($starttime) or ($starttime <= 0)); - $stoptime = (stat _)[9] if stat($stopfile) and (!defined($stoptime) or ($stoptime <= 0)); - ((not defined $starttime or $starttime < time) and - (not defined $stoptime or $stoptime > time)) - } -} readdir D; -closedir D; -if (@open_elections) { - $usage_elections = join("\n ", @open_elections); +my (%open_elections, $usage_elections); +%open_elections = Votify::get_open_elections_hash(); +if (scalar keys %open_elections) { + $usage_elections = join("\n ", keys %open_elections); } else { $usage_elections = "(no elections currently open)"; } @@ -7,8 +7,13 @@ # votify: generate, verify and submit voting ballots for trustee elections # -#BEGIN { push @INC, (getpwnam 'fox2mike')[7].'/elections' } -BEGIN { push @INC, '/etc/elections/current' } +BEGIN { + if(-f '/etc/elections/Votify.pm') { + push @INC, '/etc/elections'; + } else { + push @INC, '.' if -f 'Votify.pm'; + } +} use POSIX; use Getopt::Long; @@ -24,46 +29,17 @@ use strict; (my $version = $Votify::version) =~ s/.*?(\d.*\d).*/$zero version $1\n/; my (%opt, %elections); -sub grabfile_int { - my $f = shift; - my $i = 0; - open FILE, "<", $f; - $i = <FILE> if defined(<FILE>); - close FILE; - chomp $i if $i; - return $i; -} - # Collect the open elections -my (@open_elections, $usage_elections); -opendir(D, "$Votify::datadir/") or die; -@open_elections = sort grep { - s/^start-// and do { - my ($name) = $_; - my ($startfile) = sprintf "%s/start-%s", $Votify::datadir, $_; - my ($stopfile) = sprintf "%s/stop-%s", $Votify::datadir, $_; - my ($starttime) = grabfile_int($startfile); - my ($stoptime) = grabfile_int($stopfile); - $starttime = (stat _)[9] if stat($startfile) and (!defined($starttime) or ($starttime <= 0)); - $stoptime = (stat _)[9] if stat($stopfile) and (!defined($stoptime) or ($stoptime <= 0)); - my $valid = ((not defined $starttime or $starttime < time) and - (not defined $stoptime or $stoptime > time)); - if($valid) { - $elections{$name} = {}; - $elections{$name}{starttime} = $starttime; - $elections{$name}{stoptime} = $stoptime; - } - $valid; - } -} readdir D; -closedir D; -my $datefmt = '%Y-%m-%d %H:%M UTC'; -if (@open_elections) { - $usage_elections = "Presently available elections:\n" . join('', map { - my ($name) = $_; - my ($start) = strftime($datefmt, localtime($elections{$name}{starttime})); - my ($stop) = strftime($datefmt, localtime($elections{$name}{stoptime})); - sprintf("\t%s: %s to %s\n", $name, $start, $stop) } @open_elections); +my ($usage_elections); + +%elections = Votify::get_open_elections_hash(); + +if (scalar(keys %elections) > 0) { + $usage_elections = "Presently available elections:\n" . join('', map { + my ($name) = $_; + my ($start) = strftime($Votify::datefmt, gmtime($elections{$name}{starttime})); + my ($stop) = strftime($Votify::datefmt, gmtime($elections{$name}{stoptime})); + sprintf("\t%s: %s to %s\n", $name, $start, $stop) } keys %elections); $usage_elections .= <<EOF \nA handy tool called "votify" can be used to vote in the election. You can use "votify --help" to get instructions on how to vote, verify, and submit your @@ -8,7 +8,13 @@ # #BEGIN { push @INC, (getpwnam 'fox2mike')[7].'/elections' } -BEGIN { push @INC, '/etc/elections/current' } +BEGIN { + if(-f '/etc/elections/Votify.pm') { + push @INC, '/etc/elections'; + } else { + push @INC, '.' if -f 'Votify.pm'; + } +} use POSIX; use Getopt::Long; @@ -24,34 +30,11 @@ use strict; (my $version = $Votify::version) =~ s/.*?(\d.*\d).*/$zero version $1\n/; my (%opt); -sub grabfile_int { - my $f = shift; - my $i = 0; - open FILE, "<", $f; - $i = <FILE> if defined(<FILE>); - close FILE; - chomp $i if $i; - return $i; -} - # Collect the open elections -my (@open_elections, $usage_elections); -opendir(D, "$Votify::datadir/") or die; -@open_elections = sort grep { - s/^start-// and do { - my ($startfile) = sprintf "%s/start-%s", $Votify::datadir, $_; - my ($stopfile) = sprintf "%s/stop-%s", $Votify::datadir, $_; - my ($starttime) = grabfile_int($startfile); - my ($stoptime) = grabfile_int($stopfile); - $starttime = (stat _)[9] if stat($startfile) and (!defined($starttime) or ($starttime <= 0)); - $stoptime = (stat _)[9] if stat($stopfile) and (!defined($stoptime) or ($stoptime <= 0)); - ((not defined $starttime or $starttime < time) and - (not defined $stoptime or $stoptime > time)) - } -} readdir D; -closedir D; -if (@open_elections) { - $usage_elections = join("\n ", @open_elections); +my (%open_elections, $usage_elections); +%open_elections = Votify::get_open_elections_hash(); +if (scalar keys %open_elections) { + $usage_elections = join("\n ", keys %open_elections); } else { $usage_elections = "(no elections currently open)"; } @@ -104,7 +87,7 @@ Instructions: (4) Submit your ballot. This renames your ballot to ~/.ballot-<election>-submitted so that it will be tallied when the votes are collected. - + \$ $zero --submit <election> EOT @@ -141,16 +124,8 @@ my ($b) = Ballot->new($election); # Check if the election is open. This should really happen in an # Election class in Votify.pm eventually my ($starttime, $stoptime); -my ($startfile) = sprintf "%s/start-%s", $Votify::datadir, $election; -my ($stopfile) = sprintf "%s/stop-%s", $Votify::datadir, $election; -if ( -f $startfile ) { - $starttime = grabfile_int($startfile); - $starttime = (stat _)[9] if stat($startfile) and (!defined($starttime) or ($starttime <= 0)); -} -if ( -f $stopfile ) { - ($stoptime) = grabfile_int($stopfile); - $stoptime = (stat _)[9] if stat($stopfile) and (!defined($stoptime) or ($stoptime <= 0)); -} +$starttime = $open_elections{$election}{'starttime'}; +$stoptime = $open_elections{$election}{'stoptime'}; if ($starttime && $starttime > time) { print "\n", "*" x 75, "\n"; print "WARNING: Specified election doesn't start until ", @@ -166,7 +141,7 @@ if ($stoptime && $stoptime < time) { if ($opt{'new'}) { # Make sure the user is eligible - open(F, "<$Votify::datadir/voters-$election") or die "Failed to open voters file"; + open(F, '<', $open_elections{$election}{'votersfile'}) or die "Failed to open voters file"; my (@voters) = <F>; chomp(@voters); close(F); |