diff --git a/.gitignore b/.gitignore index e6e78994abd146eaed0cdb0f489cb4fb941156c7..0e8670cdc004fe1b9fb0bf0982f26f1a277c3d74 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,6 @@ *.sqlite3 celerybeat-* core/static/libs/* -deploy # libs static/libs @@ -21,3 +20,6 @@ __pycache__/ # Installer logs pip-log.txt pip-delete-this-directory.txt +.dpl +db.sqlite +log/ diff --git a/.openshift/README.md b/.openshift/README.md new file mode 100644 index 0000000000000000000000000000000000000000..785566bc0d4ed83bbdfa2311e18a4402de9e8bef --- /dev/null +++ b/.openshift/README.md @@ -0,0 +1,5 @@ +The OpenShift `python` cartridge documentation can be found at: +http://openshift.github.io/documentation/oo_cartridge_guide.html#python + +For information about .openshift directory, consult the documentation: +http://openshift.github.io/documentation/oo_user_guide.html#the-openshift-directory diff --git a/.openshift/action_hooks/README.md b/.openshift/action_hooks/README.md new file mode 100644 index 0000000000000000000000000000000000000000..541319581eade0377453213c5abba7411a81ced8 --- /dev/null +++ b/.openshift/action_hooks/README.md @@ -0,0 +1,3 @@ +For information about action hooks, consult the documentation: + +http://openshift.github.io/documentation/oo_user_guide.html#action-hooks diff --git a/.openshift/action_hooks/build b/.openshift/action_hooks/build new file mode 100755 index 0000000000000000000000000000000000000000..ac65222f42fee754d4668461ab403c5051a0d914 --- /dev/null +++ b/.openshift/action_hooks/build @@ -0,0 +1 @@ +export OPENSHIFT_PYTHON_WSGI_APPLICATION=memopol/wsgi.py diff --git a/.openshift/action_hooks/deploy b/.openshift/action_hooks/deploy new file mode 100755 index 0000000000000000000000000000000000000000..35cb182f6897da58853db6f9b93253a1fda85721 --- /dev/null +++ b/.openshift/action_hooks/deploy @@ -0,0 +1,50 @@ +#!/bin/bash +# This deploy hook gets executed after dependencies are resolved and the +# build hook has been run but before the application has been started back +# up again. This script gets executed directly, so it could be python, php, +# ruby, etc. +set -xe + +source ${OPENSHIFT_HOMEDIR}app-root/runtime/dependencies/python/virtenv/bin/activate + +cat ${OPENSHIFT_REPO_DIR}requirements.txt + +pip install -U pip + +pip install -r ${OPENSHIFT_REPO_DIR}requirements.txt + +# We don't have sentry yet +# python ${OPENSHIFT_REPO_DIR}manage.py raven test + +python ${OPENSHIFT_REPO_DIR}manage.py migrate --noinput + +pushd ${OPENSHIFT_DATA_DIR} +if ! [ -d node ]; then + wget https://nodejs.org/dist/v4.2.2/node-v4.2.2-linux-x64.tar.gz + tar xvzf node-v4.2.2-linux-x64.tar.gz + ln -sfn node-v4.2.2-linux-x64 node +fi +popd + +pushd ${OPENSHIFT_REPO_DIR} +if [ -f ${OPENSHIFT_DATA_DIR}sentry ]; then + pip install raven + ./manage.py raven test +else + echo ${OPENSHIFT_DATA_DIR}sentry does not exist, not setting up raven. +fi + +PATH="${OPENSHIFT_DATA_DIR}node/bin:$PATH" +HOME=$OPENSHIFT_DATA_DIR +CI=true +npm install bower +npm install +node_modules/.bin/bower install +node_modules/gulp/bin/gulp.js less +mkdir -p wsgi +./manage.py collectstatic --noinput +popd + +mkdir -p ${OPENSHIFT_DATA_DIR}media +mkdir -p ${OPENSHIFT_REPO_DIR}wsgi/static/media +ln -sf ${OPENSHIFT_DATA_DIR}media ${OPENSHIFT_REPO_DIR}wsgi/static/media diff --git a/.openshift/cron/README.cron b/.openshift/cron/README.cron new file mode 100644 index 0000000000000000000000000000000000000000..ac77f78723e42c4c3a6c4a4763d9edbbc15aa9eb --- /dev/null +++ b/.openshift/cron/README.cron @@ -0,0 +1,27 @@ +Run scripts or jobs on a periodic basis +======================================= +Any scripts or jobs added to the minutely, hourly, daily, weekly or monthly +directories will be run on a scheduled basis (frequency is as indicated by the +name of the directory) using run-parts. + +run-parts ignores any files that are hidden or dotfiles (.*) or backup +files (*~ or *,) or named *.{rpmsave,rpmorig,rpmnew,swp,cfsaved} + +The presence of two specially named files jobs.deny and jobs.allow controls +how run-parts executes your scripts/jobs. + jobs.deny ===> Prevents specific scripts or jobs from being executed. + jobs.allow ===> Only execute the named scripts or jobs (all other/non-named + scripts that exist in this directory are ignored). + +The principles of jobs.deny and jobs.allow are the same as those of cron.deny +and cron.allow and are described in detail at: + http://docs.redhat.com/docs/en-US/Red_Hat_Enterprise_Linux/6/html/Deployment_Guide/ch-Automating_System_Tasks.html#s2-autotasks-cron-access + +See: man crontab or above link for more details and see the the weekly/ + directory for an example. + +PLEASE NOTE: The Cron cartridge must be installed in order to run the configured jobs. + +For more information about cron, consult the documentation: +http://openshift.github.io/documentation/oo_cartridge_guide.html#cron +http://openshift.github.io/documentation/oo_user_guide.html#cron diff --git a/.openshift/cron/daily/.gitignore b/.openshift/cron/daily/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/.openshift/cron/daily/update_database b/.openshift/cron/daily/update_database new file mode 100755 index 0000000000000000000000000000000000000000..aeecfeecdae6c5e6b8a3bdc93a39d5671c95ce79 --- /dev/null +++ b/.openshift/cron/daily/update_database @@ -0,0 +1,8 @@ +#!/bin/bash +set -x + +cmd=$1 + +cd $OPENSHIFT_REPO_DIR +export CLEAN=1 +nohup bin/update_all > $OPENSHIFT_LOG_DIR/update_all.log 2>&1 & diff --git a/.openshift/cron/hourly/.gitignore b/.openshift/cron/hourly/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/.openshift/cron/minutely/.gitignore b/.openshift/cron/minutely/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/.openshift/cron/monthly/.gitignore b/.openshift/cron/monthly/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/.openshift/cron/weekly/README b/.openshift/cron/weekly/README new file mode 100644 index 0000000000000000000000000000000000000000..7c3e659fe2b4dcd863acfe1f61ccbc57dbe93499 --- /dev/null +++ b/.openshift/cron/weekly/README @@ -0,0 +1,16 @@ +Run scripts or jobs on a weekly basis +===================================== +Any scripts or jobs added to this directory will be run on a scheduled basis +(weekly) using run-parts. + +run-parts ignores any files that are hidden or dotfiles (.*) or backup +files (*~ or *,) or named *.{rpmsave,rpmorig,rpmnew,swp,cfsaved} and handles +the files named jobs.deny and jobs.allow specially. + +In this specific example, the chronograph script is the only script or job file +executed on a weekly basis (due to white-listing it in jobs.allow). And the +README and chrono.dat file are ignored either as a result of being black-listed +in jobs.deny or because they are NOT white-listed in the jobs.allow file. + +For more details, please see ../README.cron file. + diff --git a/.openshift/cron/weekly/chrono.dat b/.openshift/cron/weekly/chrono.dat new file mode 100644 index 0000000000000000000000000000000000000000..fc4abb87cba85b2c7bebe25d319a521481693a5d --- /dev/null +++ b/.openshift/cron/weekly/chrono.dat @@ -0,0 +1 @@ +Time And Relative D...n In Execution (Open)Shift! diff --git a/.openshift/cron/weekly/chronograph b/.openshift/cron/weekly/chronograph new file mode 100755 index 0000000000000000000000000000000000000000..61de949f43218d8afe1ec1e70cc41bdb3f335535 --- /dev/null +++ b/.openshift/cron/weekly/chronograph @@ -0,0 +1,3 @@ +#!/bin/bash + +echo "`date`: `cat $(dirname \"$0\")/chrono.dat`" diff --git a/.openshift/cron/weekly/jobs.allow b/.openshift/cron/weekly/jobs.allow new file mode 100644 index 0000000000000000000000000000000000000000..8d32abc703e797106d6cfacfdb1f53975aef7466 --- /dev/null +++ b/.openshift/cron/weekly/jobs.allow @@ -0,0 +1,12 @@ +# +# Script or job files listed in here (one entry per line) will be +# executed on a weekly-basis. +# +# Example: The chronograph script will be executed weekly but the README +# and chrono.dat files in this directory will be ignored. +# +# The README file is actually ignored due to the entry in the +# jobs.deny which is checked before jobs.allow (this file). +# +chronograph + diff --git a/.openshift/cron/weekly/jobs.deny b/.openshift/cron/weekly/jobs.deny new file mode 100644 index 0000000000000000000000000000000000000000..73c945008a7322ec03aecdcba20b92389f7226f1 --- /dev/null +++ b/.openshift/cron/weekly/jobs.deny @@ -0,0 +1,7 @@ +# +# Any script or job files listed in here (one entry per line) will NOT be +# executed (read as ignored by run-parts). +# + +README + diff --git a/.openshift/markers/README.md b/.openshift/markers/README.md new file mode 100644 index 0000000000000000000000000000000000000000..45814da3c7aaea9bed0a8abe5ce0afbcc76c5238 --- /dev/null +++ b/.openshift/markers/README.md @@ -0,0 +1,3 @@ +For information about markers, consult the documentation: + +http://openshift.github.io/documentation/oo_user_guide.html#markers diff --git a/.travis.yml b/.travis.yml index 79b90f61c47cfc3b743eabb02aceb1a07cd3043e..51fcdf389ae930d689b6e92d1bcc1ed3c353b981 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,16 +1,29 @@ sudo: false +env: + matrix: + - DEBUG=True language: python python: - - "2.7" +- '2.7' install: - - pip install django - - pip install -U pip - - pip install -r requirements.txt - - cp memopol/config.json.sample memopol/config.json +- pip install django +- pip install -r requirements.txt before_script: - - npm install -g bower - - bower install - - npm install +- npm install -g bower +- bower install +- npm install script: - - ./manage.py migrate - - node_modules/gulp/bin/gulp.js less +- ./manage.py migrate +- node_modules/gulp/bin/gulp.js less +deploy: +- provider: openshift + user: jamespic@gmail.com + password: + secure: W7hQDKAtmpOfwLjBuss6NEKqPSrRhsbgH8a8eV+/Oo6HZxMi1mbNFSi+6WRNSs3Cil0ZZV+awoqC61jIzV4oTwEYcy5bv9NWNSY1QO34DECMS5sY00wA0zKhkdsdTr9Pc3TLRp1cw6x2KNCF356FKZojFTRbjtfJ79rqBc5k5ww= + app: dev + domain: memopol + skip_cleanup: true + deployment_branch: pr + on: + repo: political-memory/political_memory + branch: pr diff --git a/bin/lib.sh b/bin/lib.sh new file mode 100644 index 0000000000000000000000000000000000000000..a53f054a88bf6f56391becfc633f47f2378ae06f --- /dev/null +++ b/bin/lib.sh @@ -0,0 +1,20 @@ +if [ -n "$OPENSHIFT_HOMEDIR" ]; then + source ${OPENSHIFT_HOMEDIR}app-root/runtime/dependencies/python/virtenv/bin/activate +fi + +function pipe_download_to_command() { + if [ -n "$OPENSHIFT_DATA_DIR" ]; then + cd $OPENSHIFT_DATA_DIR + fi + + [ -n "$CLEAN" ] && rm -rf $1 + [ -f "$1" ] || wget http://parltrack.euwiki.org/dumps/$1 || exit 1 + + if [ -n "$OPENSHIFT_REPO_DIR" ]; then + cd $OPENSHIFT_REPO_DIR + fi + + export DJANGO_SETTINGS_MODULE=memopol.settings + unxz -c ${OPENSHIFT_DATA_DIR}$1 | $2 + [ -n "$CLEAN" ] && rm -rf $1 +} diff --git a/bin/update_all b/bin/update_all new file mode 100755 index 0000000000000000000000000000000000000000..5899c9c1d257bf97c5dd9b233b09a3859535eadb --- /dev/null +++ b/bin/update_all @@ -0,0 +1,16 @@ +#!/bin/bash + +bin/update_representatives + +# grace time for pg +sleep 120 + +bin/update_dossiers + +sleep 120 + +bin/update_votes + +sleep 120 + +bin/update_scores diff --git a/bin/update_dossiers b/bin/update_dossiers new file mode 100755 index 0000000000000000000000000000000000000000..0e6f18b7a176ede7e849041d1404fc6de8ee53f1 --- /dev/null +++ b/bin/update_dossiers @@ -0,0 +1,6 @@ +#!/bin/bash +set -ex + +source ${OPENSHIFT_REPO_DIR}bin/lib.sh + +pipe_download_to_command ep_dossiers.json.xz parltrack_import_dossiers diff --git a/bin/update_representatives b/bin/update_representatives new file mode 100755 index 0000000000000000000000000000000000000000..ef420b9cdf5be71311cefcb5479d064f7ba7d261 --- /dev/null +++ b/bin/update_representatives @@ -0,0 +1,6 @@ +#!/bin/bash +set -ex + +source ${OPENSHIFT_REPO_DIR}bin/lib.sh + +pipe_download_to_command ep_meps_current.json.xz parltrack_import_representatives diff --git a/bin/update_scores b/bin/update_scores new file mode 100755 index 0000000000000000000000000000000000000000..a3234bc6b047aacad51c2ac82df886f70a6b63ed --- /dev/null +++ b/bin/update_scores @@ -0,0 +1,7 @@ +#!/bin/bash +set -ex + +source ${OPENSHIFT_REPO_DIR}bin/lib.sh + +[ -n "$OPENSHIFT_REPO_DIR" ] && cd $OPENSHIFT_REPO_DIR +./manage.py update_score diff --git a/bin/update_votes b/bin/update_votes new file mode 100755 index 0000000000000000000000000000000000000000..f60a96eb74f9ef5c3b6e6d17c6a4a668c4f6af4f --- /dev/null +++ b/bin/update_votes @@ -0,0 +1,6 @@ +#!/bin/bash +set -ex + +source ${OPENSHIFT_REPO_DIR}bin/lib.sh + +pipe_download_to_command ep_votes.json.xz parltrack_import_votes diff --git a/core/templates/admin/index.html b/core/templates/admin/index.html deleted file mode 100644 index a35204e8c11f05b39cfa8e15fb4979d25ae00871..0000000000000000000000000000000000000000 --- a/core/templates/admin/index.html +++ /dev/null @@ -1,16 +0,0 @@ -{% extends "contrib/admin/templates/admin/index.html" %} - -{% block branding %} - <h1 id="site-name">Administration for Memopol</h1> -{% endblock %} - -{% block content %} - - - {{ block.super }} -{% endblock %} - - - - - diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..67106ec55f40621cdcad28eb545631a086e289b8 --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,192 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = _build + +# User-friendly check for sphinx-build +ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) +$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) +endif + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext + +help: + @echo "Please use \`make <target>' where <target> is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " applehelp to make an Apple Help Book" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " xml to make Docutils-native XML files" + @echo " pseudoxml to make pseudoxml-XML files for display purposes" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + @echo " coverage to run coverage check of the documentation (if enabled)" + +clean: + rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Memopol.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Memopol.qhc" + +applehelp: + $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp + @echo + @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." + @echo "N.B. You won't be able to view it unless you put it in" \ + "~/Library/Documentation/Help or install it in your application" \ + "bundle." + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/Memopol" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Memopol" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +latexpdfja: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through platex and dvipdfmx..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +coverage: + $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage + @echo "Testing of coverage in the sources finished, look at the " \ + "results in $(BUILDDIR)/coverage/python.txt." + +xml: + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml + @echo + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." + +pseudoxml: + $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml + @echo + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000000000000000000000000000000000000..39d896982dcb654094252d463a98d5147a71877e --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,354 @@ +# -*- coding: utf-8 -*- +# +# Memopol documentation build configuration file, created by +# sphinx-quickstart on Thu Nov 12 22:42:47 2015. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys +import os +import shlex + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'Memopol' +copyright = u'2015, Laurent Peuch, Mindiell, Arnaud Fabre' +author = u'Laurent Peuch, Mindiell, Arnaud Fabre' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '1.0' +# The full version, including alpha/beta/rc tags. +release = '1.0.0' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +#keep_warnings = False + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = False + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'alabaster' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# "<project> v<release> documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +#html_extra_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a <link> tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Language to be used for generating the HTML full-text search index. +# Sphinx supports the following languages: +# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' +# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr' +#html_search_language = 'en' + +# A dictionary with options for the search language support, empty by default. +# Now only 'ja' uses this config value +#html_search_options = {'type': 'default'} + +# The name of a javascript file (relative to the configuration directory) that +# implements a search results scorer. If empty, the default will be used. +#html_search_scorer = 'scorer.js' + +# Output file base name for HTML help builder. +htmlhelp_basename = 'Memopoldoc' + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', + +# Latex figure (float) alignment +#'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'Memopol.tex', u'Memopol Documentation', + u'Laurent Peuch, Mindiell, Arnaud Fabre', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'memopol', u'Memopol Documentation', + [author], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'Memopol', u'Memopol Documentation', + author, 'Memopol', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +#texinfo_no_detailmenu = False + + +# -- Options for Epub output ---------------------------------------------- + +# Bibliographic Dublin Core info. +epub_title = project +epub_author = author +epub_publisher = author +epub_copyright = copyright + +# The basename for the epub file. It defaults to the project name. +#epub_basename = project + +# The HTML theme for the epub output. Since the default themes are not optimized +# for small screen space, using the same theme for HTML and epub output is +# usually not wise. This defaults to 'epub', a theme designed to save visual +# space. +#epub_theme = 'epub' + +# The language of the text. It defaults to the language option +# or 'en' if the language is not set. +#epub_language = '' + +# The scheme of the identifier. Typical schemes are ISBN or URL. +#epub_scheme = '' + +# The unique identifier of the text. This can be a ISBN number +# or the project homepage. +#epub_identifier = '' + +# A unique identification for the text. +#epub_uid = '' + +# A tuple containing the cover image and cover page html template filenames. +#epub_cover = () + +# A sequence of (type, uri, title) tuples for the guide element of content.opf. +#epub_guide = () + +# HTML files that should be inserted before the pages created by sphinx. +# The format is a list of tuples containing the path and title. +#epub_pre_files = [] + +# HTML files shat should be inserted after the pages created by sphinx. +# The format is a list of tuples containing the path and title. +#epub_post_files = [] + +# A list of files that should not be packed into the epub file. +epub_exclude_files = ['search.html'] + +# The depth of the table of contents in toc.ncx. +#epub_tocdepth = 3 + +# Allow duplicate toc entries. +#epub_tocdup = True + +# Choose between 'default' and 'includehidden'. +#epub_tocscope = 'default' + +# Fix unsupported image types using the Pillow. +#epub_fix_images = False + +# Scale large images. +#epub_max_image_width = 0 + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#epub_show_urls = 'inline' + +# If false, no index is generated. +#epub_use_index = True diff --git a/docs/deployment.rst b/docs/deployment.rst new file mode 100644 index 0000000000000000000000000000000000000000..d9a36fdae19f5d9c8f671206deedb722c9558036 --- /dev/null +++ b/docs/deployment.rst @@ -0,0 +1,93 @@ +Deployment on OpenShift +~~~~~~~~~~~~~~~~~~~~~~~ + +OpenShift is an Open-Source Platform-as-a-Service software by Red Hat. It is +also available in its hosted version known as "OpenShift Online" and the first +three websites ("gears") are free. + +Clone the repository +==================== + +You should fork the project on github and use the fork's clone url. For the +sake of the demo, we'll use the main repository URL:: + + $ git clone https://github.com/political-memory/political_memory.git + Cloning into 'political_memory'... + remote: Counting objects: 2516, done. + remote: Compressing objects: 100% (109/109), done. + remote: Total 2516 (delta 44), reused 0 (delta 0), pack-reused 2402 + Receiving objects: 100% (2516/2516), 4.40 MiB | 79.00 KiB/s, done. + Resolving deltas: 100% (1103/1103), done. + Checking connectivity... done. + + $ cd political_memory/ + +Create your own branch, ie:: + + $ git checkout -b yourbranch origin/pr + Branch yourbranch set up to track remote branch pr from origin. + Switched to a new branch 'yourbranch' + +Create an app on OpenShift +========================== + +To deploy the website, use a command like:: + + $ rhc app-create \ + python-2.7 \ + "http://cartreflect-claytondev.rhcloud.com/reflect?github=smarterclayton/openshift-redis-cart" \ + cron-1.4 \ + postgresql-9.2 \ + -a yourappname \ + -e OPENSHIFT_PYTHON_WSGI_APPLICATION=memopol/wsgi.py \ + --from-code https://github.com/political-memory/political_memory.git + +This should create an app on openshift. Other commands would deploy it at once +but in this tutorial we're going to see how to manage it partly manually for +development. + +Add the git remote created by OpenShift +======================================= + +Add the git remote openshift created for you, you can see it with +``rhc app-show``, ie.:: + + $ rhc app-show -a yourappname + [snip] + Git URL: ssh://569f5cf500045f6a1839a0a4@yourappname-yourdomain.rhcloud.com/~/git/yourappname.git/ + Initial Git URL: https://github.com/political-memory/political_memory.git + SSH: 569f5cf500045f6a1839a0a4@yourappname-yourdomain.rhcloud.com + [snip] + + $ git remote add oo_yourappname ssh://569f5cf500045f6a1839a0a4@yourappname-yourdomain.rhcloud.com/~/git/yourappname.git/ + +Activate OpenShift's git post-recieve hook +========================================== + +Activate OpenShift's post-receive hook on your branch:: + + $ rhc app-configure -a yourappname --deployment-branch yourbranch + +Deploy your branch +================== + +OpenShift will deploy when it receives commits on the deployment branch, to +deploy just do:: + + $ git push oo_yourappname yourbranch + +If something goes wrong and you want to retry, use the ``rhc app-deploy`` +command, ie:: + + $ rhc app-deploy yourbranch -a yourappname + +Data provisionning +================== + +To fill up the representatives database table, either wait for the cron script +to be executed, either do it manually:: + + $ rhc ssh -a yourappname 'cd app-root/repo/ && bin/update_all' + +OpenShift is fun, login with ssh and look around if you're curious, you'll be +able to recreate your app without much effort if you break it anyway. diff --git a/docs/development.rst b/docs/development.rst new file mode 100644 index 0000000000000000000000000000000000000000..ddca78a69672408880eb9613e0f5088c81d7c6e8 --- /dev/null +++ b/docs/development.rst @@ -0,0 +1,180 @@ +Local development tutorial +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. warn:: I reverse-engineered this from the source code I inherited, I might + not be doing the right way nor be able to defend all of technical + decisions. + +This tutorial drives through a local installation of the project for +development on Linux. It requires git, a fairly recent version of nodejs (see +:file:`.openshift/action_hooks/deploy` for a way to install it), python2 and +virtualenv. + +Make a virtual environment +========================== + +For the sake of the tutorial, we'll do this in the temporary directory, but you +could do it anywhere:: + + $ cd /tmp + +Create a python virtual environment and activate it:: + + $ virtualenv memopol_env + Using real prefix '/usr' + New python executable in memopol_env/bin/python2 + Also creating executable in memopol_env/bin/python + Installing setuptools, pip, wheel...done. + + $ source memopol_env/bin/activate + +Clone the repository +==================== + +You should fork the project on github and use the fork's clone url. For the +sake of the demo, we'll use the main repository URL:: + + $ git clone https://github.com/political-memory/political_memory.git + Cloning into 'political_memory'... + remote: Counting objects: 2516, done. + remote: Compressing objects: 100% (109/109), done. + remote: Total 2516 (delta 44), reused 0 (delta 0), pack-reused 2402 + Receiving objects: 100% (2516/2516), 4.40 MiB | 79.00 KiB/s, done. + Resolving deltas: 100% (1103/1103), done. + Checking connectivity... done. + + $ cd political_memory/ + +Create your own branch, ie:: + + $ git checkout -b yourbranch origin/pr + Branch yourbranch set up to track remote branch pr from origin. + Switched to a new branch 'yourbranch' + +Install Python dependencies +=========================== + +Then, install the package for development:: + + $ pip install -e . + Obtaining file:///tmp/political_memory + Collecting django (from political-memory==0.0.1) + Using cached Django-1.9-py2.py3-none-any.whl + + [output snipped for readability] + + Installing collected packages: django, sqlparse, django-debug-toolbar, django-pdb, six, django-extensions, werkzeug, south, pygments, markdown, hamlpy, django-coffeescript, ijson, python-dateutil, pytz, political-memory + Running setup.py develop for political-memory + Successfully installed django-1.9 django-coffeescript-0.7.2 django-debug-toolbar-1.4 django-extensions-1.5.9 django-pdb-0.4.2 hamlpy-0.82.2 ijson-2.2 markdown-2.6.5 political-memory pygments-2.0.2 python-dateutil-2.4.2 pytz-2015.7 six-1.10.0 south-1.0.2 sqlparse-0.1.18 werkzeug-0.11.2 + +And install the requirements:: + + $ pip install -r requirements.txt + Collecting django<1.9,>=1.8 (from -r requirements.txt (line 1)) + + [output snipped for readability] + + Using cached Django-1.8.7-py2.py3-none-any.whl + Running setup.py develop for django-representatives + Running setup.py develop for django-representatives-votes + Successfully installed amqp-1.4.8 anyjson-0.3.3 billiard-3.3.0.22 celery-3.1.19 django-1.8.7 django-adminplus-0.5 django-appconf-1.0.1 django-autocomplete-light-2.2.10 django-bootstrap3-6.2.2 django-celery-3.1.17 django-compressor-1.6 django-constance-1.1.1 django-datetime-widget-0.9.3 django-denorm-0.2.0 django-filter-0.11.0 django-picklefield-0.3.2 django-representatives django-representatives-votes django-taggit-0.17.5 django-uuidfield-0.5.0 djangorestframework-3.3.1 kombu-3.0.30 py-dateutil-2.2 pyprind-2.9.3 requests-2.8.1 slugify-0.0.1 + +Install NodeJS dependencies +=========================== + +We'll also need to install bower for the staticfiles:: + + $ npm install bower + memopol@3.0.0 /tmp/political_memory + └── bower@1.7.0 extraneous + +As well as all the requirements from :file:`package.json`:: + + $ npm install + memopol@3.0.0 /tmp/political_memory + ├── bower@1.7.0 extraneous + ├─┬ gulp@3.9.0 + + [output snipped for readability] + + npm WARN In bower@1.7.0 replacing bundled version of configstore with configstore@0.3.2 + npm WARN In bower@1.7.0 replacing bundled version of latest-version with latest-version@1.0.1 + npm WARN In bower@1.7.0 replacing bundled version of update-notifier with update-notifier@0.3.2 + +Don't worry about the warnings, for they are non-critical (as all warnings). +Then, install the bower packages:: + + $ node_modules/.bin/bower install + bower bootstrap#~3.3.5 cached git://github.com/twbs/bootstrap.git#3.3.6 + bootstrap#3.3.6 static/libs/bootstrap + └── jquery#2.1.4 + + [output snipped for readability] + + jquery#2.1.4 static/libs/jquery + +Build the static files with gulp:: + + $ node_modules/gulp/bin/gulp.js less + [22:26:42] Using gulpfile /tmp/political_memory/gulpfile.js + [22:26:42] Starting 'less'... + [22:26:44] Finished 'less' after 1.54 s + +.. note:: The ``node_modules/gulp/bin/gulp.js watch`` command may be used to + have gulp watching for changes and rebuilding static files + automatically. + +Activate ``DEBUG`` +================== + +``DEBUG`` is disabled by default, the development server won't run properly by +default thnen, to enable it export the ``DEBUG`` variable in the current +shell:: + + $ export DEBUG=True + +Database migrations +=================== + +Run database migrations, it'll use a file-based sqlite database by default:: + + $ ./manage.py migrate + Operations to perform: + Synchronize unmigrated apps: django_filters, staticfiles, datetimewidget, autocomplete_light, messages, adminplus, compressor, humanize, django_extensions, constance, bootstrap3 + Apply all migrations: legislature, votes, database, admin, positions, sessions, representatives, auth, contenttypes, representatives_votes, taggit + Synchronizing apps without migrations: + Creating tables... + Running deferred SQL... + Installing custom SQL... + Running migrations: + Rendering model states... DONE + Applying contenttypes.0001_initial... OK + + [output snipped for readability] + + Applying taggit.0002_auto_20150616_2121... OK + +Run the development server +========================== + +Run the development server:: + + $ ./manage.py runserver + + Performing system checks... + + System check identified no issues (0 silenced). + December 09, 2015 - 21:26:47 + Django version 1.8.7, using settings 'memopol.settings' + Starting development server at http://127.0.0.1:8000/ + Quit the server with CONTROL-C. + [09/Dec/2015 21:26:48] "GET / HTTP/1.1" 200 13294 + +The website is running on ``http://127.0.0.1:8000/``. + +Provision with data +=================== + +To provision it with data (takes a while):: + + $ bin/update_all diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000000000000000000000000000000000000..d31240cb58e58441d397b33355f7c73566745f12 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,23 @@ +.. Memopol documentation master file, created by + sphinx-quickstart on Thu Nov 12 22:42:47 2015. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to Memopol's documentation! +=================================== + +Contents: + +.. toctree:: + :maxdepth: 2 + + development + deployment + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + diff --git a/legislature/models.py b/legislature/models.py index 88f589fb10de93402d6307be548b01f6fb0a1bff..7cf005058225c181e8625193edd05769f6a0e6ed 100644 --- a/legislature/models.py +++ b/legislature/models.py @@ -27,6 +27,8 @@ from django.dispatch import receiver # from django.utils.functional import cached_property from representatives.models import Representative, Mandate, Country +from representatives.management.commands import ( + parltrack_import_representatives,) from votes.models import MemopolVote from core.utils import create_child_instance_from_parent @@ -38,44 +40,14 @@ class MemopolRepresentative(Representative): def update_score(self): score = 0 - for vote in self.votes.all(): + for vote in MemopolVote.objects.filter(representative=self): score += vote.absolute_score self.score = score self.save() - def update_country(self): - # Create a country if it does'nt exist - # The representative's country is the one associated - # with the last 'country' mandate - try: - country_mandate = self.mandates.filter( - group__kind='country' - ).order_by('-begin_date')[0:1].get() - - country, _ = Country.objects.get_or_create( - name=country_mandate.group.name, - code=country_mandate.group.abbreviation - ) - self.country = country - except ObjectDoesNotExist: - self.country = None - self.save() - - def update_main_mandate(self): - try: - self.main_mandate = self.mandates.get( - end_date__gte=datetime.now(), - group__kind='group' - ) - except Mandate.DoesNotExist: - self.main_mandate = None - self.save() - def update_all(self): - self.update_country() self.update_score() - self.update_main_mandate() def active_mandates(self): return self.mandates.filter( @@ -94,7 +66,44 @@ class MemopolRepresentative(Representative): ).filter(representative=self) -@receiver(post_save, sender=Representative) -def create_memopolrepresentative_from_representative(instance, **kwargs): - memopol_representative = create_child_instance_from_parent(MemopolRepresentative, instance) - memopol_representative.save() +def parltrack_representative_post_save(sender, representative, data, **kwargs): + update = False + try: + memopol_representative = MemopolRepresentative.objects.get( + representative_ptr=representative) + except MemopolRepresentative.DoesNotExist: + memopol_representative = MemopolRepresentative( + representative_ptr=representative) + + # Please forgive the horror your are about to witness, but this is + # really necessary. Django wants to update the parent model when we + # save a child model. + memopol_representative.__dict__.update(representative.__dict__) + + try: + country = sorted(data.get('Constituencies', []), + key=lambda c: c.get('end') if c is not None else 1 + )[-1]['country'] + except IndexError: + pass + else: + if sender.cache.get('countries', None) is None: + sender.cache['countries'] = {c.name: c.pk for c in + Country.objects.all()} + country_id = sender.cache['countries'].get(country) + + if memopol_representative.country_id != country_id: + memopol_representative.country_id = country_id + update = True + + if sender.mep_cache['groups']: + main_mandate = sorted(sender.mep_cache['groups'], + key=lambda m: m.end_date)[-1] + + if memopol_representative.main_mandate_id != main_mandate.pk: + memopol_representative.main_mandate_id = main_mandate.pk + update = True + + if update: + memopol_representative.save() +parltrack_import_representatives.ParltrackImporter.representative_post_save.connect(parltrack_representative_post_save) diff --git a/memopol/__init__.py b/memopol/__init__.py index ce38469170d6d5bf342bccb0cdb5691010fe82fa..cd2db24eefeb13b40b8d169bca4ad4a5b4a61010 100644 --- a/memopol/__init__.py +++ b/memopol/__init__.py @@ -22,4 +22,9 @@ from __future__ import absolute_import # This will make sure the app is always imported when # Django starts so that shared_task will use this app. -from .celery import app as celery_app +try: + import celery +except ImportError: + pass +else: + from .celery import app as celery_app diff --git a/memopol/config.json.sample b/memopol/config.json.sample deleted file mode 100644 index c8aad54fa5050df3d533aacf17b0e7e39ea5c377..0000000000000000000000000000000000000000 --- a/memopol/config.json.sample +++ /dev/null @@ -1,14 +0,0 @@ -{ - "debug": true, - "secret_key": "notsecret", - "compotista_server": "http://compotista.dev.laquadrature.net/", - "toutatis_server": "http://toutatis.dev.laquadrature.net/", - "redis_db": 0, - "organization": "local", - "local": true, - "database_name": "db.sqlite", - "database_user": "", - "database_password": "", - "database_host": "", - "database_port": "" -} diff --git a/memopol/settings.py b/memopol/settings.py index ec5779f057454f3f52483d2d7b7e597b89e4a38d..b20df0bd5a71267f87c930e8ba41810a92dcb49d 100644 --- a/memopol/settings.py +++ b/memopol/settings.py @@ -9,51 +9,59 @@ https://docs.djangoproject.com/en/1.7/ref/settings/ """ # Build paths inside the project like this: os.path.join(BASE_DIR, ...) -import json import os -import django -# Normally you should not import ANYTHING from Django directly -# into your settings, but ImproperlyConfigured is an exception. -from django.core.exceptions import ImproperlyConfigured -from django.conf import settings +from django.conf import global_settings -# BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) -config_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'config.json') +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) -with open(config_file) as f: - config = json.loads(f.read()) +DATA_DIR = os.environ.get('OPENSHIFT_DATA_DIR', 'data') +if not os.path.exists(DATA_DIR): + os.makedirs(DATA_DIR) -def get_param(setting, config=config, default=None): - """Get the secret variable or return explicit exception.""" - try: - return config[setting] - except KeyError: - if default: - return default - error_msg = "Set the {0} config variable".format(setting) - raise ImproperlyConfigured(error_msg) - -BASE_DIR = os.path.dirname(os.path.dirname(__file__)) +LOG_DIR = os.environ.get('OPENSHIFT_LOG_DIR', 'log') +if not os.path.exists(LOG_DIR): + os.makedirs(LOG_DIR) +PUBLIC_DIR = os.path.join(os.environ.get('OPENSHIFT_REPO_DIR', ''), 'wsgi/static') # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/1.7/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = get_param('secret_key') +SECRET_FILE = os.path.join(DATA_DIR, 'secret.txt') + +from django.utils.crypto import get_random_string +if not os.path.exists(SECRET_FILE): + chars = 'abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)' + with open(SECRET_FILE, 'w+') as f: + f.write(get_random_string(50, chars)) + +with open(SECRET_FILE, 'r') as f: + SECRET_KEY = f.read() -DEBUG = get_param('debug') + +DEBUG = os.environ.get('DEBUG', False) TEMPLATE_DEBUG = DEBUG +LOG_LEVEL = os.environ.get('DJANGO_LOG_LEVEL', 'INFO') + +if SECRET_KEY == 'notsecret' and not DEBUG: + raise Exception('Please export DJANGO_SECRET_KEY or DEBUG') -ALLOWED_HOSTS = [] +from socket import gethostname +ALLOWED_HOSTS = [ + gethostname(), +] -COMPOTISTA_SERVER = get_param('compotista_server') -TOUTATIS_SERVER = get_param('toutatis_server') -REDIS_DB = get_param('redis_db') -ORGANIZATION_NAME = get_param('organization') +DNS = os.environ.get('OPENSHIFT_APP_DNS', None), +if DNS: + ALLOWED_HOSTS += DNS -# Application definition +if 'DJANGO_ALLOWED_HOSTS' in os.environ: + ALLOWED_HOSTS += os.environ.get('DJANGO_ALLOWED_HOSTS').split(',') + +REDIS_DB = os.environ.get('REDIS_DB', 1) +ORGANIZATION_NAME = os.environ.get('ORGANIZATION', 'Memopol Demo') INSTALLED_APPS = ( # 'django.contrib.admin', @@ -79,20 +87,15 @@ INSTALLED_APPS = ( 'representatives_votes', 'legislature', 'votes', - 'positions' + 'positions', + 'django_extensions', ) if DEBUG: - INSTALLED_APPS += ( - 'django_extensions', - ) - -if get_param('local'): INSTALLED_APPS += ( 'debug_toolbar', ) - MIDDLEWARE_CLASSES = ( 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', @@ -113,25 +116,32 @@ WSGI_APPLICATION = 'memopol.wsgi.application' DATABASES = { 'default': { - 'NAME': get_param('database_name'), - 'USER': get_param('database_user'), - 'PASSWORD': get_param('database_password'), - 'HOST': get_param('database_host'), - 'PORT': get_param('database_port'), + 'NAME': os.environ.get('DJANGO_DATABASE_DEFAULT_NAME', 'db.sqlite'), + 'USER': os.environ.get('DJANGO_DATABASE_DEFAULT_USER', ''), + 'PASSWORD': os.environ.get('DJANGO_DATABASE_DEFAULT_PASSWORD', ''), + 'HOST': os.environ.get('DJANGO_DATABASE_DEFAULT_HOST', ''), + 'PORT': os.environ.get('DJANGO_DATABASE_DEFAULT_PORT', ''), + 'ENGINE': os.environ.get('DJANGO_DATABASE_DEFAULT_ENGINE', + 'django.db.backends.sqlite3'), + } } -if get_param('local'): - DATABASES['default']['ENGINE'] = 'django.db.backends.sqlite3' -elif get_param('database_server') == 'mysql': - DATABASES['default']['ENGINE'] = 'django.db.backends.mysql' -elif get_param('database_server') == 'postgresql': +if 'OPENSHIFT_DATA_DIR' in os.environ: + DATABASES['default']['NAME'] = os.path.join(DATA_DIR, 'db.sqlite') + +if 'OPENSHIFT_POSTGRESQL_DB_HOST' in os.environ: + DATABASES['default']['NAME'] = os.environ['OPENSHIFT_APP_NAME'] + DATABASES['default']['USER'] = os.environ['OPENSHIFT_POSTGRESQL_DB_USERNAME'] + DATABASES['default']['PASSWORD'] = os.environ['OPENSHIFT_POSTGRESQL_DB_PASSWORD'] + DATABASES['default']['HOST'] = os.environ['OPENSHIFT_POSTGRESQL_DB_HOST'] + DATABASES['default']['PORT'] = os.environ['OPENSHIFT_POSTGRESQL_DB_PORT'] DATABASES['default']['ENGINE'] = 'django.db.backends.postgresql_psycopg2' # Internationalization # https://docs.djangoproject.com/en/1.7/topics/i18n/ -LANGUAGE_CODE = get_param('language_code', default='en-us') +LANGUAGE_CODE = os.environ.get('DJANGO_LANGUAGE_CODE', 'en-us') TIME_ZONE = 'UTC' @@ -145,14 +155,24 @@ USE_TZ = True # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/1.7/howto/static-files/ +STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')] + STATIC_URL = '/static/' +COMPRESS_ROOT = 'static/' + +if DATA_DIR: + MEDIA_URL = '/static/media/' + MEDIA_ROOT = os.path.join(DATA_DIR, 'media') + +if PUBLIC_DIR: + STATIC_URL = '/static/collected/' + STATIC_ROOT = os.path.join(PUBLIC_DIR, 'collected') # HAML Templates # https://github.com/jessemiller/hamlpy TEMPLATE_DIRS = ( 'core/templates', - os.path.dirname(django.__file__) ) TEMPLATE_LOADERS = ( @@ -162,10 +182,6 @@ TEMPLATE_LOADERS = ( 'hamlpy.template.loaders.HamlPyAppDirectoriesLoader', ) -TEMPLATE_CONTEXT_PROCESSORS = settings.TEMPLATE_CONTEXT_PROCESSORS + ( - 'constance.context_processors.config', -) - """ TEMPLATE_LOADERS = ( ('django.template.loaders.cached.Loader', ( @@ -175,10 +191,12 @@ TEMPLATE_LOADERS = ( ) """ +TEMPLATE_CONTEXT_PROCESSORS = global_settings.TEMPLATE_CONTEXT_PROCESSORS + ( + 'constance.context_processors.config', +) + # Static files finders -STATIC_URL = '/static/' -COMPRESS_ROOT = 'static/' STATICFILES_FINDERS = ( 'django.contrib.staticfiles.finders.FileSystemFinder', @@ -212,13 +230,8 @@ LOGGING = { }, }, 'handlers': { - 'file': { - 'level': 'DEBUG', - 'class': 'logging.FileHandler', - 'filename': '/tmp/compotista-debug.log', - }, 'console': { - 'level': 'DEBUG', + 'level': LOG_LEVEL, 'class': 'logging.StreamHandler', 'formatter': 'simple' }, @@ -226,25 +239,61 @@ LOGGING = { 'loggers': { 'memopol': { 'handlers': ['console'], - 'level': 'DEBUG' + 'level': LOG_LEVEL, }, 'representatives': { 'handlers': ['console'], - 'level': 'DEBUG' + 'level': LOG_LEVEL, }, 'representatives_votes': { 'handlers': ['console'], - 'level': 'DEBUG' + 'level': LOG_LEVEL, } }, } +if DEBUG: + LOGGING['handlers']['debug'] = { + 'level': 'DEBUG', + 'class': 'logging.FileHandler', + 'filename': os.path.join(LOG_DIR, 'debug.log'), + } + for logger in LOGGING['loggers'].values(): + logger['handlers'].append('debug') + +RAVEN_FILE = os.path.join(DATA_DIR, 'sentry') +if os.path.exists(RAVEN_FILE): + INSTALLED_APPS += ('raven.contrib.django.raven_compat',) + + LOGGING['handlers']['sentry'] = { + 'level': 'INFO', + 'class': 'raven.contrib.django.raven_compat.handlers.SentryHandler', + } + LOGGING['loggers']['sentry.errors'] = LOGGING['loggers']['raven'] = { + 'level': 'INFO', + 'handlers': ['console'], + 'propagate': False, + } + + with open(RAVEN_FILE, 'r') as f: + RAVEN_CONFIG = { + 'dsn': f.read().strip() + } + CONSTANCE_BACKEND = 'constance.backends.redisd.RedisBackend' CONSTANCE_REDIS_CONNECTION = { - 'host': 'localhost', - 'port': 6379, - 'db': 0, + + 'host': os.environ.get('OPENSHIFT_REDIS_HOST', 'localhost'), + 'port': os.environ.get('OPENSHIFT_REDIS_PORT', 6379), + 'password': os.environ.get('REDIS_PASSWORD', ''), + 'db': 1, } +CONSTANCE_REDIS_CONNECTION = 'redis://:%s@%s:%s/%s' % ( + os.environ.get('REDIS_PASSWORD', ''), + os.environ.get('OPENSHIFT_REDIS_HOST', 'localhost'), + os.environ.get('OPENSHIFT_REDIS_PORT', 6379), + 0, +) CONSTANCE_CONFIG = { 'USE_COUNTRY': (True, 'Use country for representative'), diff --git a/memopol/settings.py.example b/memopol/settings.py.example deleted file mode 100644 index 46558a7a63bf4478aaf042d86f4521452c042569..0000000000000000000000000000000000000000 --- a/memopol/settings.py.example +++ /dev/null @@ -1,146 +0,0 @@ -""" -Django settings for memopol project. - -For more information on this file, see -https://docs.djangoproject.com/en/1.7/topics/settings/ - -For the full list of settings and their values, see -https://docs.djangoproject.com/en/1.7/ref/settings/ -""" - -# Build paths inside the project like this: os.path.join(BASE_DIR, ...) -import os -BASE_DIR = os.path.dirname(os.path.dirname(__file__)) - - -# Quick-start development settings - unsuitable for production -# See https://docs.djangoproject.com/en/1.7/howto/deployment/checklist/ - -# SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = 'zbzzs+8wkdnbo-l9x6+r38)$%h)!&22c^di$^6ap_+9oza#irr' - -# SECURITY WARNING: don't run with debug turned on in production! -DEBUG = True - -TEMPLATE_DEBUG = True - -ALLOWED_HOSTS = [] - - -# Application definition - -INSTALLED_APPS = ( - 'django.contrib.admin', - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.staticfiles', - # --- - 'compressor', - 'chronograph', - # --- - 'core', - 'representatives', - 'memopol_representatives', -) - -# App settings - -REPRESENTATIVES_COMPOTISTA_SERVER = 'http://pi2.octopuce.fr:8081' - -MIDDLEWARE_CLASSES = ( - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.auth.middleware.SessionAuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware', -) - -ROOT_URLCONF = 'memopol.urls' - -WSGI_APPLICATION = 'memopol.wsgi.application' - - -# Database -# https://docs.djangoproject.com/en/1.7/ref/settings/#databases - -DATABASES = { - 'sqlite': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), - }, - 'default': { - 'ENGINE': 'django.db.backends.postgresql_psycopg2', - 'NAME': 'memopol_dev', - 'USER': 'dj', - 'PASSWORD': "test", - 'HOST': 'localhost', - 'PORT': '', - } -} - -# Internationalization -# https://docs.djangoproject.com/en/1.7/topics/i18n/ - -LANGUAGE_CODE = 'en-us' - -TIME_ZONE = 'UTC' - -USE_I18N = True - -USE_L10N = True - -USE_TZ = True - - -# Static files (CSS, JavaScript, Images) -# https://docs.djangoproject.com/en/1.7/howto/static-files/ - -STATIC_URL = '/static/' - -# HAML Templates -# https://github.com/jessemiller/hamlpy - -TEMPLATE_DIRS = ( - 'core/templates', -) - -TEMPLATE_LOADERS = ( - 'django.template.loaders.filesystem.Loader', - 'django.template.loaders.app_directories.Loader', - 'hamlpy.template.loaders.HamlPyFilesystemLoader', - 'hamlpy.template.loaders.HamlPyAppDirectoriesLoader', -) - -""" -TEMPLATE_LOADERS = ( - ('django.template.loaders.cached.Loader', ( - 'hamlpy.template.loaders.HamlPyFilesystemLoader', - 'hamlpy.template.loaders.HamlPyAppDirectoriesLoader', - )), -) -""" - -# Static files finders - -STATIC_URL = '/static/' -COMPRESS_ROOT = 'static/' - -STATICFILES_FINDERS = ( - 'django.contrib.staticfiles.finders.FileSystemFinder', - 'django.contrib.staticfiles.finders.AppDirectoriesFinder', - # other finders.. - 'compressor.finders.CompressorFinder', -) - -COMPRESS_PRECOMPILERS = ( - # ('text/coffeescript', 'coffee --compile --stdio'), - ('text/less', 'lessc {infile} {outfile}'), - ('text/x-sass', 'sass {infile} {outfile}'), - ('text/x-scss', 'sass --scss {infile} {outfile}'), - # ('text/stylus', 'stylus < {infile} > {outfile}'), - # ('text/foobar', 'path.to.MyPrecompilerFilter'), -) diff --git a/requirements.txt b/requirements.txt index 61f9dbea48864003f510fc9120b60cfd4df7d04a..d9c25d35dac32407de2259c85e5c4e1f9313c9d0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -16,8 +16,8 @@ django-bootstrap3 django-filter django-taggit django-datetime-widget --e git+https://github.com/political-memory/django-representatives.git#egg=django-representatives --e git+https://github.com/political-memory/django-representatives-votes.git#egg=rdjango-epresentatives-votes +-e git+https://github.com/political-memory/django-representatives.git@parltrack#egg=django-representatives +-e git+https://github.com/political-memory/django-representatives-votes.git@parltrack#egg=django-representatives-votes django-extensions django-debug-toolbar redis diff --git a/setup.py b/setup.py new file mode 100644 index 0000000000000000000000000000000000000000..012aea0439311e21894d7caf495e89f991eba1a2 --- /dev/null +++ b/setup.py @@ -0,0 +1,24 @@ +from setuptools import setup, find_packages + +setup(name='political-memory', + version='0.0.1', + description='OpenShift App', + packages=['political_memory'], + package_dir={'political_memory': '.'}, + author='Laurent Peuch', + author_email='cortex@worlddomination.be', + url='http://github.com/political-memory/political_memory/', + install_requires=[ + 'django', + 'django-debug-toolbar', + 'django_pdb', + 'django_extensions', + 'werkzeug', + 'south', + 'hamlpy', + 'django-coffeescript', + 'ijson', + 'python-dateutil', + 'pytz', + ], +) diff --git a/votes/management/commands/update_score.py b/votes/management/commands/update_score.py new file mode 100644 index 0000000000000000000000000000000000000000..6cbd68445483a94227bb3a01689ae141c3ac7ab1 --- /dev/null +++ b/votes/management/commands/update_score.py @@ -0,0 +1,9 @@ +from django.core.management.base import BaseCommand + +from legislature.models import MemopolRepresentative + + +class Command(BaseCommand): + def handle(self, *args, **options): + for rep in MemopolRepresentative.objects.all(): + rep.update_score()