BetterPoll is a work-in-progress website to allow users to quickly and easily create and vote in ranked-choice polls.
Please note: this project is very new. There are many TODOs littered around the code, and it is not even ready to be publicly deployed in a testing phase.
BetterPoll's backend (whose source code is located in the backend/
directory) exposes a REST-ish API:
POST /poll/<pollid>/vote
with candidate choices to vote- Provided data should be JSON of the form
{"choices":[]}
, where thechoices
key is an array of candidate strings - Response will be
{"success": true}
or equivalent JSON if the vote succeeds, and{"success": false, "error": <errorstring>}
or equivalent if it fails (where<errorstring>
is a string explaining the error that occured)
- Provided data should be JSON of the form
GET /poll/<pollid>
to get info about a poll- In the event of an error, the response will be JSON of the form
{"success": false, "error": <errorstring>}
, where<errorstring>
is a human-readable string describing the error that occurred. - On success, the response will be JSON with the following properties:
success
(boolean):true
.name
(string): the name of the poll.description
(string): the poll's description.candidates
(array of strings): choices for which users can vote.creationTime
(integer): UNIX timestamp at which the poll began (in seconds).endingTime
(integer): UNIX timestamp at which the poll ends (in seconds).numWinners
(integer): number of winners the poll has.protection
(string or null):"ip"
if votes by the same IP address are forbidden, andnull
otherwise.numVotes
(integer): the number of votes cast so far.ended
(boolean):true
if the poll has ended, otherwisefalse
.
- If the poll has ended, the following additional properties will be specified in the response JSON:
winners
(array of strings): the winner(s) of the poll. May be more/less thannumWinners
if multiple winners have the same rank in the overall tally.
- In the event of an error, the response will be JSON of the form
POST /create
to create a poll- Provided data should be JSON, with the following mandatory properties:
name
(string): the name for the poll.description
(string): a description of the poll.candidates
(array of strings): choices for which users can vote. Should be between 2 and 1024 in length.duration
(integer): the amount of time after which the poll will expire, in seconds. Must be positive.numWinners
(integer): the number of winners that the poll can have. Must be greater than 0 and less than the number of candidates provided.
- The following properties are optional:
id
(string): a custom URL for the poll. Must be a string composed of letters A-Z (upper or lowercase), numbers 0-9,_
,.
and-
, with at least 1 and at most 32 characters.protection
(string): the protection method to use to prevent double voting. Currently, the only acceptable values areip
(prevents multiple votes from the same IP address) andnone
(allows all incoming votes). In the future, more protection methods may be implemented.
- Response on success is JSON of the form
{"success": true, "id": <id>}
, where<id>
is the poll's ID. On error, the response will be JSON of the form{"success": false, "error": <errorstring>}
, where<errorstring>
is a human-readable string describing the error that occurred.
- Provided data should be JSON, with the following mandatory properties:
GET /status
to get status information- Returns JSON with the following properties:
success
:true
total
: the total number of polls in the database, ornull
if the database is inaccessibleactive
: the number of polls currently accepting votes, ornull
if the database is inaccessible
- Returns JSON with the following properties:
BetterPoll currently uses PostgreSQL for its database, although it's possible that alternative databases will be added in the future.
Database tests can be disabled with the no-db-test
feature.
There is a database schema at backend/schema.sql
; you'll need to run this to set up the requisite tables before starting the backend server.
BetterPoll's frontend is written in Vue and located in the frontend/
directory.
I plan to generate a static site from this that can be served through something like GitHub Pages.
Configure the databases in Rocket.toml
; an example is provided.
You'll also need to specify ALLOWED_ORIGINS
as an environment variable (or in a .env
file); it is a regular expression specifying allowed origins for CORS.
You may optionally specify the API_URL
environment variable (to use an alternate backend) or the DOMAIN
environment variable (which specifies the domain used in the UI display for custom URLs). However, this is optional; sane defaults are provided.
Most of the libraries used can be found in the Cargo.toml
and package.json
files, but there is one I want to mention specifically:
- @phayes's
tallystick
library is used to provide implementations of the voting algorithms. Currently, only the Schulze method is supported, but it's definitely possible to add more in the future.