212 lines
8.8 KiB
Text
212 lines
8.8 KiB
Text
# What's Conservancy Voting Software Repository For?
|
|
|
|
When I was setting up Conservancy's ability to run elections for its member
|
|
projects, I surveyed various Open Source and Free Software systems systems to
|
|
handle online voting and elections. I was mostly looking for something that
|
|
implemented STV algorithm and ballot collection for the same.
|
|
|
|
## What Open Source and Free Software Election / Voting / Vote Collection Systems Exist
|
|
|
|
As it turns out, there are precious few Free Software voting systems.
|
|
|
|
* [Selectricity](http://selectricity.org/) is a good option, but upon
|
|
discussions with the primary author, Benjamin "Mako" Hill, he confirmed
|
|
that it does not currently implement any of the algorithms designed for
|
|
multiple winner elections. So, if you want a preferential voting system
|
|
with just one winner, Selectricity is probably the best choice.
|
|
|
|
* [Fedora's election system](https://github.com/fedora-infra/elections)'s
|
|
supports only [range voting](http://en.wikipedia.org/wiki/Range_voting).
|
|
|
|
* Meanwhile, for various STV algorithms,
|
|
[OpenSTV](https://github.com/Conservatory/openstv) is the best
|
|
choice for counting votes using various STV methods. OpenSTV is a
|
|
command-line based system that implements all sorts of voting algorithms,
|
|
but it has no vote-collection system. (It's also worth noting that
|
|
openstv has since been taken proprietary, but older versions that were
|
|
released as Free Software are still available.)
|
|
|
|
* [E-Vote](https://github.com/mdipierro/evote) is a system focusing on the
|
|
collection of ballots, and seems promising in its design, but it is
|
|
relatively poorly documented and it was unclear upon initial evaluation
|
|
if STV-style ballots were available.
|
|
|
|
* The Apache Software Foundation released
|
|
[Apache Steve](http://steve.apache.org/), which handles STV vote and
|
|
First-past-the-post ballot collection and appears to be email-centric in
|
|
its vote collection.
|
|
|
|
* GNOME Foundation hacked together a system in the
|
|
[GNOME Foundation website repository](https://git.gnome.org/browse/foundation-web/)
|
|
implemented their own little system to collect votes for
|
|
their annual Directorship elections, using OpenSTV on the backend to
|
|
count the votes.
|
|
|
|
## Why This Fork of GNOME Foundation's Voting System?
|
|
|
|
Since I needed STV specifically, this seemed like the best option (mainly
|
|
because I didn't know about E-Vote when I started, I'd probably have used
|
|
E-Vote if I'd known about it before I started modifying the GNOME
|
|
Foundation's code). Thus, this project is a fork of GNOME's work, with
|
|
*just* the voting stuff included. Most of the GNOME-isms have been removed,
|
|
although a few remain.
|
|
|
|
I've also offered patches back to the GNOME Foundation repository by
|
|
cherry-picking changes that are of use to both projects.
|
|
|
|
Having spent 10-20 hours poking around this PHP code, I must frankly say that
|
|
this isn't a well-designed system, and I don't really recommend it. However,
|
|
if you need to run a few STV elections, using this system, by following the
|
|
instructions below, might be your quickest way to get an election up and
|
|
running. (Note: the instructions herein are loosely based on
|
|
[instructions available on the GNOME Foundation's wiki](https://wiki.gnome.org/MembershipCommittee/ElectionsHowTo),
|
|
although those instructions are somewhat GNOME specific. I believe these
|
|
instructions below are fully self-contained now, such that you don't have to
|
|
read the GNOME Foundation's instructions as secondary information).
|
|
|
|
# Setting up an election
|
|
|
|
0. vote/include/election-sql.php expects a secret config file that exists
|
|
only on the server and is included as PHP code. It's hard coded currently
|
|
to: /home/admin/secret/anonvoting currently.
|
|
|
|
The file should look something like this:
|
|
|
|
<?php
|
|
$mysql_host = "localhost";
|
|
$mysql_user = "someuser";
|
|
$mysql_password = "somepassword";
|
|
$mysql_db = "somedb";
|
|
$committee_name = "The Vote Masters";
|
|
$committee_email = "elections@example.org";
|
|
?>
|
|
|
|
1. When I deploy, I create an account for the election, as the mysql root user:
|
|
|
|
mysql -u root -p
|
|
Password: <MYSQLROOTPW>
|
|
|
|
Then Run these commands at the mysql> prompt:
|
|
|
|
CREATE USER 'someusername' identified by 'somepassword';
|
|
CREATE DATABASE somedbname;
|
|
|
|
Then, exit, and at the main command line run:
|
|
|
|
msyql -u root -p -D somedbname < ..../vote/include/schema.sql
|
|
|
|
Then run this again:
|
|
|
|
mysql -u root -p
|
|
Password: <MYSQLROOTPW>
|
|
|
|
and at the mysql command line, run these grant commands:
|
|
|
|
GRANT SELECT on somedb.elections TO someuser@localhost;
|
|
GRANT SELECT on somedb.election_choices TO someuser@localhost;
|
|
GRANT SELECT,DELETE on somedb.election_tmp_tokens TO someuser@localhost;
|
|
GRANT SELECT on somedb.election_voters TO someuser@localhost;
|
|
GRANT SELECT,INSERT on somedb.election_anon_tokens TO someuser@localhost;
|
|
GRANT SELECT,INSERT on somedb.election_votes TO someuser@localhost;
|
|
GRANT SELECT on somedb.election_results TO someuser@localhost;
|
|
|
|
2. Create an election, with something like this:
|
|
|
|
mysql -u root -D somedb -p
|
|
|
|
SET NAMES 'utf8';
|
|
INSERT INTO elections (type, name, voting_start, voting_end, choices_nb, question) VALUES ("elections", "2011 Spring Election", "2011-05-29 00:00:00", "2011-06-12 23:59:59", "7", "Which candidates would you like to see Elected?");
|
|
set @el_id = @@IDENTITY;
|
|
INSERT INTO election_choices (election_id, choice) VALUES
|
|
(@el_id, 'Candidate 1'),
|
|
(@el_id, 'Candidate 2'),
|
|
(@el_id, 'Candidate 3'),
|
|
(@el_id, 'Candidate 4');
|
|
INSERT INTO election_voters (election_id, email_address) VALUES
|
|
(@el_id, 'voter1@example.org'),
|
|
(@el_id, 'voter2@example.org'),
|
|
(@el_id, 'voter3@example.com'),
|
|
(@el_id, 'voter4@example.net');
|
|
|
|
INSERT INTO election_tmp_tokens (election_id, election_voter_id, tmp_token)
|
|
SELECT @el_id, id, SUBSTRING(MD5(RAND()) FROM 1 FOR 24) AS tmp_token
|
|
FROM election_voters where election_id = @el_id;
|
|
|
|
select @el_id;
|
|
|
|
That number you see at the end is this election's id. The URL you'll
|
|
give out is thus something like:
|
|
http://example.org/vote.php?election_id=THAT_NUMBER
|
|
|
|
3. Create an email template, email-template.txt, in this format:
|
|
|
|
"Person" <person@example.org>
|
|
A subject line describing the vote
|
|
|
|
Dear <member>,
|
|
|
|
Please visit: http://example.org/vote.php?election_id=THAT_NUMBER
|
|
|
|
And use this information to complete the voting:
|
|
|
|
E-mail:
|
|
Vote token:
|
|
|
|
Once you've voted, you'll be given a confirmation token. You can
|
|
verify your own vote at:
|
|
https://example.org/verify.php
|
|
|
|
After the election, you can see the results at:
|
|
https://example.org/results.php?election_id=THAT_NUMBER
|
|
|
|
4. Prepare a list of the temp tokens sent to everyone, perhaps with this command:
|
|
|
|
SELECT a.email_address,b.tmp_token
|
|
FROM election_voters a, election_tmp_tokens b
|
|
WHERE a.election_id = @el_id
|
|
AND a.election_id = b.election_id
|
|
AND b.election_voter_id = a.id;
|
|
|
|
You'll need to then convert that output into a file called "voters.txt",
|
|
with each line in a format of:
|
|
|
|
Full Name;email_address;token
|
|
|
|
5. Then, run this script:
|
|
|
|
$ ./mail-instructions.py voters.txt email-template.txt
|
|
|
|
on some server that can use SMTP from localhost.
|
|
|
|
Note that the script will replace <member>, E-mail, and Vote token:
|
|
strings from (3) above with the appropriate values from the voters.txt
|
|
file.
|
|
|
|
6. When the voting is over, download the election.blt file via this URL:
|
|
|
|
https://example.org/blt.php?election_id=THAT_NUMBER
|
|
|
|
then run this command:
|
|
|
|
$ openstv-run-election -r HtmlReport ScottishSTV election.blt > results.html
|
|
|
|
7. The results HTML has to be in the database, as the PHP code expects it.
|
|
Here's some SQL commands that will get it into the right table:
|
|
|
|
set @result_text = load_file('/path/to/results.html');
|
|
REPLACE INTO election_results (election_id, result) VALUES (@el_id, @result_text);
|
|
|
|
Note that I discovered that /path/to/results.html has to be world-readable
|
|
for this to work, even if you mysql process has read permission. I didn't
|
|
have time to figure out why or if that analysis is correct.
|
|
Dealing With Problems
|
|
=====================
|
|
|
|
## Missing Ballots
|
|
|
|
Voters might complain that they haven't received their token. Likely, it
|
|
either went missing or the email address was wrongly noted in the
|
|
database. In any case, you need to find the ID of the voter With the ID do
|
|
something like:
|
|
SELECT * FROM election_tmp_tokens WHERE election_id = 17 AND election_voter_id = $ID;
|
|
|