diff --git a/.gitignore b/.gitignore index c22aa5a8e..b69d82f67 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,5 @@ report test.html .test_report deploy/config.yaml +env +.pytest_cache diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..c07c2d41b --- /dev/null +++ b/.travis.yml @@ -0,0 +1,12 @@ +language: python +python: + - "2.7" +install: + # postgresql should be installed by default + - sudo apt-get install libpq-dev + - sudo -u postgres createuser -s `whoami` || true + - createdb zeus_test + - ./setup-python + +script: + - py.test -v diff --git a/README.md b/README.md index 7dda8ffd5..2e382cca2 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ -The Zeus election server -======================== +# The Zeus election server + +[![Build Status](https://travis-ci.org/pwmarcz/zeus.svg?branch=master)](https://travis-ci.org/pwmarcz/zeus) LICENCE: This code is released under the GPL v3 or later @@ -8,10 +9,59 @@ This is a fork of Ben Adida's Helios server. The differences from Helios are as * Whereas Helios produces election results, Zeus produces a tally of the ballots cast. * This allows Zeus to be used in voting systems other than approval voting (which is supported - by Helios), since the vote tally can be fed to any other system that actually produces the + by Helios), since the vote tally can be fed to any other system that actually produces the election results. * In terms of overall architecture and implementation it is closer to the [original Helios implementation](http://static.usenix.org/events/sec08/tech/full_papers/adida/adida.pdf) than Helios v. 3. +## Install + +Install Postgres (`postgres-server`, `libpq-dev`). + +If necessary, create a Postgres user: + + sudo -u postgres createuser -s $(whoami) + +Create a database: + + createdb helios + +Ensure you have Python 2.7 and virtualenv. Setup virtualenv: + + ./setup-virtualenv + +Activate virtualenv: + + . env/bin/activate + +Run migrations: + + python manage.py migrate + +## Run + + python manage.py runserver 0.0.0.0:8000 + +## Test + + py.test -v + +## Python packages + +We use [pip-tools](https://github.com/jazzband/pip-tools) to manage +dependencies: + +- `requirements.in` - contains list of direct dependencies, not necessarily + pinned +- `requirements.txt` - auto-generated from `requirements.in`, all packages, all + versions pinned + +In order to install a new package: + +- activate virtualenv (`. env/bin/activate`) +- edit `requirements.in` +- run `pip-compile` to generate a new `requirements.txt` file +- run `pip-sync` to install the new packages +- test the change and commit all files diff --git a/__init__.py b/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/data/.gitignore b/data/.gitignore new file mode 100644 index 000000000..d6b7ef32c --- /dev/null +++ b/data/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/manage.py b/manage.py index c632a8a38..30d99ac6b 100755 --- a/manage.py +++ b/manage.py @@ -1,6 +1,11 @@ #!/usr/bin/env python import os, sys +# HACK until we upgrade Kombu. +# See https://stackoverflow.com/questions/34198538/cannot-import-name-uuid-generate-random-in-heroku-django +import uuid +uuid._uuid_generate_random = None + if __name__ == "__main__": os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings") diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 000000000..16afb3dac --- /dev/null +++ b/pytest.ini @@ -0,0 +1,3 @@ +[pytest] +DJANGO_SETTINGS_MODULE = test_settings +norecursedirs = env diff --git a/requirements.in b/requirements.in new file mode 100644 index 000000000..ea4b26cc9 --- /dev/null +++ b/requirements.in @@ -0,0 +1,31 @@ +Django==1.8 +#South==0.7.6 +ansicolors==1.0.2 +anyjson==0.3.3 +celerymon==1.0.3 +celery +django-celery +django-eml-email-backend==0.1 +django-extensions==0.9 +django-kombu +django-picklefield==0.3.2 +pycrypto==2.6 +python-dateutil==1.5 +python-openid==2.2.5 +psycopg2==2.7.4 +PyICU==1.7 +django-pagination==1.0.7 +gmpy==1.17 +simplejson==3.4.0 +reportlab==3.0 +pyyaml + +# devtools +selenium==2.25.0 +trunserver==0.0.2 +django-debug-toolbar==0.9.4 +ipython==0.13 +pytest==2.6.4 +pytest-cov==1.8.1 +pytest-xdist==1.11 +pytest-django==2.9.1 diff --git a/requirements.txt b/requirements.txt index a0f13e1df..c773cc744 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,31 +1,56 @@ -Django==1.4 -South==0.7.6 +# +# This file is autogenerated by pip-compile +# To update, run: +# +# pip-compile --output-file requirements.txt requirements.in +# +amqp==1.4.9 # via kombu ansicolors==1.0.2 anyjson==0.3.3 -billiard==2.7.3.17 +apipkg==1.4 # via execnet +attrs==17.4.0 # via automat +automat==0.6.0 # via twisted +backports-abc==0.5 # via tornado +billiard==3.3.0.23 # via celery +celery==3.1.25 celerymon==1.0.3 -celery==2.5.3 -django-celery==2.5.5 +certifi==2018.1.18 # via tornado +constantly==15.1.0 # via twisted +cov-core==1.15.0 # via pytest-cov +coverage==3.7.1 # via cov-core, pytest-cov +django-celery==3.2.2 +django-debug-toolbar==0.9.4 django-eml-email-backend==0.1 django-extensions==0.9 django-kombu==0.9.4 -kombu==2.4.7 +django-pagination==1.0.7 +django-picklefield==0.3.2 +django==1.8 +execnet==1.5.0 # via pytest-xdist +gmpy==1.17 +hyperlink==18.0.0 # via twisted +idna==2.6 # via hyperlink +incremental==17.5.0 # via twisted +ipython==0.13 +kombu==3.0.37 # via celery +psycopg2==2.7.4 +py==1.5.2 # via pytest, pytest-cov, pytest-xdist pycrypto==2.6 +pyicu==2.0.3 +pytest-cov==1.8.1 +pytest-django==2.9.1 +pytest-xdist==1.11 +pytest==2.6.4 python-dateutil==1.5 python-openid==2.2.5 -psycopg2==2.5.2 -PyICU==1.7 -django-pagination==1.0.7 -gmpy==1.17 -simplejson==3.4.0 +pytz==2018.3 # via celery +pyyaml==3.12 reportlab==3.0 - -# devtools -#selenium==2.25.0 -#trunserver==0.0.2 -#django-debug-toolbar==0.9.4 -#ipython==0.13 -#pytest==2.6.4 -#pytest-cov==1.8.1 -#pytest-xdist==1.11 -#pytest-django==2.9.1 +selenium==2.25.0 +simplejson==3.4.0 +singledispatch==3.4.0.3 # via tornado +six==1.11.0 # via automat, singledispatch +tornado==4.5.3 # via celerymon +trunserver==0.0.2 +twisted==17.9.0 # via trunserver +zope.interface==4.4.3 # via twisted diff --git a/settings.py b/settings.py index 2c47b365a..5ae8dcb93 100644 --- a/settings.py +++ b/settings.py @@ -37,8 +37,8 @@ def get_from_env(var, default): # Language code for this installation. All choices can be found here: # http://www.i18nguy.com/unicode/language-identifiers.html -LANGUAGE_CODE = 'el-gr' -LANGUAGES = (('el', 'Greek'),) +LANGUAGE_CODE = 'en' +LANGUAGES = (('en', 'English'),) SITE_ID = 1 @@ -236,9 +236,11 @@ def get_from_env(var, default): ZEUS_VOTER_EMAIL_RATE = '30/m' -ZEUS_ELECTION_LOG_DIR = os.path.join('/', 'usr', 'share', 'zeus', 'election_logs') -ZEUS_RESULTS_PATH = os.path.join('/', 'usr', 'share', 'zeus') -ZEUS_PROOFS_PATH = os.path.join('/', 'usr', 'share', 'zeus_proofs') +DATA_PATH = os.path.join(ROOT_PATH, 'data') + +ZEUS_ELECTION_LOG_DIR = os.path.join(DATA_PATH, 'election_logs') +ZEUS_RESULTS_PATH = os.path.join(DATA_PATH, 'zeus') +ZEUS_PROOFS_PATH = os.path.join(DATA_PATH, 'zeus_proofs') ZEUS_ALLOW_EARLY_ELECTION_CLOSE = True ZEUS_CELERY_TEMPDIR = os.path.join('/', 'var', 'run', 'zeus-celery') ZEUS_HEADER_BG_URL = '/static/zeus/images/logo_bg_nobrand' @@ -265,7 +267,7 @@ def get_from_env(var, default): 'handlers': { 'file': { 'class': 'logging.FileHandler', - 'filename': '/usr/share/zeus/zeus.log' + 'filename': os.path.join(DATA_PATH, 'zeus.log') } } } @@ -312,3 +314,8 @@ def get_from_env(var, default): from local_settings import * except ImportError: pass + +HELIOS_CRYPTOSYSTEM_PARAMS = {} +HELIOS_CRYPTOSYSTEM_PARAMS['p'] = 19936216778566278769000253703181821530777724513886984297472278095277636456087690955868900309738872419217596317525891498128424073395840060513894962337598264322558055230566786268714502738012916669517912719860309819086261817093999047426105645828097562635912023767088410684153615689914052935698627462693772783508681806906452733153116119222181911280990397752728529137894709311659730447623090500459340155653968608895572426146788021409657502780399150625362771073012861137005134355305397837208305921803153308069591184864176876279550962831273252563865904505239163777934648725590326075580394712644972925907314817076990800469107L +HELIOS_CRYPTOSYSTEM_PARAMS['q'] = 9968108389283139384500126851590910765388862256943492148736139047638818228043845477934450154869436209608798158762945749064212036697920030256947481168799132161279027615283393134357251369006458334758956359930154909543130908546999523713052822914048781317956011883544205342076807844957026467849313731346886391754340903453226366576558059611090955640495198876364264568947354655829865223811545250229670077826984304447786213073394010704828751390199575312681385536506430568502567177652698918604152960901576654034795592432088438139775481415636626281932952252619581888967324362795163037790197356322486462953657408538495400234553L +HELIOS_CRYPTOSYSTEM_PARAMS['g'] = 19167066187022047436478413372880824313438678797887170030948364708695623454002582820938932961803261022277829853214287063757589819807116677650566996585535208649540448432196806454948132946013329765141883558367653598679571199251774119976449205171262636938096065535299103638890429717713646407483320109071252653916730386204380996827449178389044942428078669947938163252615751345293014449317883432900504074626873215717661648356281447274508124643639202368368971023489627632546277201661921395442643626191532112873763159722062406562807440086883536046720111922074921528340803081581395273135050422967787911879683841394288935013751L diff --git a/setup-python b/setup-python new file mode 100755 index 000000000..b10343c9d --- /dev/null +++ b/setup-python @@ -0,0 +1,20 @@ +#!/bin/sh -e + +PYTHON=/usr/bin/python2.7 + +if ! test -f "$PYTHON"; then + echo "$PYTHON not found." + exit 1 +fi + +if test -f env/bin/python && ! diff -q "$PYTHON" env/bin/python; then + echo "env/bin/python is different than $PYTHON, recreating virtualenv." + rm -rf env +fi + +if ! test -f env/bin/python; then + virtualenv --python="$PYTHON" env +fi + +. env/bin/activate && pip install pip-tools==1.11.0 +. env/bin/activate && pip-sync diff --git a/zeus/results_report.py b/zeus/results_report.py index a8a97fa38..eede14c5d 100644 --- a/zeus/results_report.py +++ b/zeus/results_report.py @@ -34,6 +34,7 @@ def _(x): PAGE_WIDTH, PAGE_HEIGHT = A4 +''' default_path = '/usr/share/fonts/truetype/linux-libertine/LinLibertine_Re.ttf' linlibertine = TTFont('LinLibertine', # '/Users/Panos/Library/Fonts/LinLibertine_Rah.ttf') @@ -45,7 +46,7 @@ def _(x): # '/Users/Panos/Library/Fonts/LinLibertine_RBah.ttf') getattr(settings, 'ZEUS_RESULTS_FONT_BOLD_PATH', default_path)) pdfmetrics.registerFont(linlibertineb) - +''' ZEUS_LOGO = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'logo-positive.jpg') diff --git a/zeus/views/poll.py b/zeus/views/poll.py index 9d052717e..7acc219af 100644 --- a/zeus/views/poll.py +++ b/zeus/views/poll.py @@ -20,7 +20,7 @@ from django.utils.html import mark_safe, escape from django.shortcuts import redirect from django import forms -from django.template.loader import Template, Context +from django.template import Template, Context from zeus.forms import ElectionForm from zeus import auth