aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Votify.pm127
-rwxr-xr-xcountify38
-rwxr-xr-xlistify58
-rwxr-xr-xvotify55
4 files changed, 157 insertions, 121 deletions
diff --git a/Votify.pm b/Votify.pm
index 1be8de7..289be2c 100644
--- a/Votify.pm
+++ b/Votify.pm
@@ -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'}});
}
diff --git a/countify b/countify
index 975a7ec..1465da4 100755
--- a/countify
+++ b/countify
@@ -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)";
}
diff --git a/listify b/listify
index 10b4b82..c8c24eb 100755
--- a/listify
+++ b/listify
@@ -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
diff --git a/votify b/votify
index 40607b7..e52881d 100755
--- a/votify
+++ b/votify
@@ -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);