Each election should only have one set of results; use UNIQUE to enforce.
[conservancy:voting.git] / README
1 # Why This Fork of GNOME Foundation's Voting System?
2
3 When I was setting up Conservancy's ability to run elections for its member
4 projects, I surveyed various Open Source and Free Software systems systems to
5 handle online voting and elections.  I was mostly looking for something that
6 implemented STV algorithm and ballot collection for the same.
7
8 As it turns out, there are precious few Free Software voting systems.
9
10   * [Selectricity](http://selectricity.org/) is a good option, but upon
11     discussions with the primary author, Benjamin "Mako" Hill, he confirmed
12     that it does not currently implement any of the algorithms designed for
13     multiple winner elections.  So, if you want a preferential voting system
14     with just one winner, Selectricity is probably the best choice.
15
16   * [Fedora's election system](https://github.com/fedora-infra/elections)'s
17     supports only [range voting](http://en.wikipedia.org/wiki/Range_voting).
18
19   * Meanwhile, for various STV algorithms,
20     [OpenSTV](https://github.com/Conservatory/openstv) is the best
21     choice for counting votes using various STV methods.  OpenSTV is a
22     command-line based system that implements all sorts of voting algorithms,
23     but it has no vote-collection system.  (It's also worth noting that
24     openstv has since been taken proprietary, but older versions that were
25     released as Free Software are still available.)
26
27   * [E-Vote](https://github.com/mdipierro/evote) is a system focusing on the
28     collection of ballots, and seems promising in its design, but it is
29     relatively poorly documented and it was unclear upon initial evaluation
30     if STV-style ballots were available.
31
32   * GNOME Foundation hacked together a system in the
33     [GNOME Foundation website repository](https://git.gnome.org/browse/foundation-web/)
34     implemented their own little system to collect votes for
35     their annual Directorship elections, using OpenSTV on the backend to
36     count the votes.
37
38 Since I needed STV specifically, this seemed like the best option (mainly
39 because I didn't know about E-Vote when I started, I'd probably have used
40 E-Vote if I'd known about it before I started modifying the GNOME
41 Foundation's code).  Thus, this project is a fork of GNOME's work, with
42 *just* the voting stuff included.  Most of the GNOME-isms have been removed,
43 although a few remain.
44
45 I've also offered patches back to the GNOME Foundation repository by
46 cherry-picking changes that are of use to both projects.
47
48 Having spent 10-20 hours poking around this PHP code, I must frankly say that
49 this isn't a well-designed system, and I don't really recommend it.  However,
50 if you need to run a few elections, using this system, by following the
51 instructions below, might be your quickest way to get an election up and
52 running.  (Note: the instructions herein are loosely based on
53 [instructions available on the GNOME Foundation's wiki](https://wiki.gnome.org/MembershipCommittee/ElectionsHowTo),
54 although those instructions are somewhat GNOME specific.  I believe these
55 instructions below are fully self-contained now, such that you don't have to
56 read the GNOME Foundation's instructions as secondary information).
57
58 # Setting up an election
59
60 0. vote/include/election-sql.php expects a secret config file that exists
61    only on the server and is included as PHP code.  It's hard coded currently
62    to: /home/admin/secret/anonvoting currently.
63
64    The file should look something like this:
65
66          <?php
67              $mysql_host = "localhost";
68              $mysql_user = "someuser";
69              $mysql_password = "somepassword";
70              $mysql_db = "somedb";
71              $committee_name = "The Vote Masters";
72              $committee_email = "elections@example.org";
73           ?>
74
75 1. When I deploy, I create an account for the election, as the mysql root user:
76
77         mysql -u root -p
78         Password: <MYSQLROOTPW>
79
80    Then Run these commands at the mysql> prompt:
81
82         CREATE USER 'someusername' identified by 'somepassword';
83         CREATE DATABASE somedbname;
84
85    Then, exit, and at the main command line run:
86
87         msyql -u root -p -D somedbname < ..../vote/include/schema.sql
88
89    Then run this again:
90
91         mysql -u root -p
92         Password: <MYSQLROOTPW>
93
94    and at the mysql command line, run these grant commands:
95
96         GRANT SELECT on somedb.elections TO someuser@localhost;
97         GRANT SELECT on somedb.election_choices TO someuser@localhost;
98         GRANT SELECT,DELETE on somedb.election_tmp_tokens TO someuser@localhost;
99         GRANT SELECT on somedb.election_voters TO someuser@localhost;
100         GRANT SELECT,INSERT on somedb.election_anon_tokens TO someuser@localhost;
101         GRANT SELECT,INSERT on somedb.election_votes TO someuser@localhost;
102
103 2. Create an election, with something like this:
104
105         mysql -u root -D somedb -p
106
107         SET NAMES 'utf8';
108         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?");
109         set @el_id = @@IDENTITY;
110         INSERT INTO election_choices (election_id, choice) VALUES
111                 (@el_id, 'Candidate 1'),
112                 (@el_id, 'Candidate 2'),
113                 (@el_id, 'Candidate 3'),
114                 (@el_id, 'Candidate 4');
115         INSERT INTO election_voters (election_id, email_address) VALUES
116                 (@el_id, 'voter1@example.org'),
117                 (@el_id, 'voter2@example.org'),
118                 (@el_id, 'voter3@example.com'),
119                 (@el_id, 'voter4@example.net');
120
121         INSERT INTO election_tmp_tokens (election_id, election_voter_id, tmp_token)
122            SELECT @el_id, id, SUBSTRING(MD5(RAND()) FROM 1 FOR 24) AS tmp_token
123            FROM election_voters where election_id = @el_id;
124
125         select @el_id;
126
127     That number you see at the end is this election's id.  The URL you'll
128     give out is thus something like:
129       http://example.org/vote.php?election_id=THAT_NUMBER
130
131 3. Create an email template, email-template.txt, in this format:
132
133         "Person" <person@example.org>
134         A subject line describing the vote
135
136         Dear <member>,
137
138         Please visit: http://example.org/vote.php?election_id=THAT_NUMBER
139
140         And use this information to complete the voting:
141
142            E-mail:
143            Vote token:
144
145         Once you've voted, you'll be given a confirmation token.  You can
146         verify your own vote at:
147             https://example.org/verify.php
148
149         After the election, you can see the results at:
150            https://example.org/results.php?election_id=THAT_NUMBER
151
152 4. Prepare a list of the temp tokens sent to everyone, perhaps with this command:
153
154         SELECT a.email_address,b.tmp_token
155          FROM election_voters a, election_tmp_tokens b
156         WHERE a.election_id = @el_id
157           AND a.election_id = b.election_id
158           AND b.election_voter_id = a.id;
159
160    You'll need to then convert that output into a file called "voters.txt",
161    with each line in a format of:
162
163          Full Name;email_address;token
164
165 5. Then, run this script:
166
167          $ ./mail-instructions.py voters.txt email-template.txt
168  
169    on some server that can use SMTP from localhost.
170
171    Note that the script will replace <member>, E-mail, and Vote token:
172    strings from (3) above with the appropriate values from the voters.txt
173    file.
174
175 6. When the voting is over, download the election.blt file via this URL:
176
177         https://example.org/blt.php?election_id=THAT_NUMBER
178
179    then run this command:
180
181         $ openstv-run-election -r HtmlReport ScottishSTV election.blt > output.html
182
183 Dealing With Problems
184 =====================
185
186 ## Missing Ballots
187
188 Voters might complain that they haven't received their token.  Likely, it
189 either went missing or the email address was wrongly noted in the
190 database. In any case, you need to find the ID of the voter With the ID do
191 something like:
192     SELECT * FROM election_tmp_tokens WHERE election_id = 17 AND election_voter_id  = $ID;
193