Skip to content
Extraits de code Groupes Projets

Comparer les révisions

Les modifications sont affichées comme si la révision source était fusionnée avec la révision cible. En savoir plus sur la comparaison des révisions.

Source

Sélectionner le projet cible
No results found

Cible

Sélectionner le projet cible
  • la-quadrature-du-net/memopol/memopol
  • lnclt/political_memory
  • arthur/political_memory
  • agrausem/political_memory
  • periode/memopol
  • Anthony/memopol
  • Porkepix/memopol
  • jaster/memopol
  • luxcem/memopol
  • TAlone/memopol
10 résultats
Afficher les modifications
Affichage de
avec 1143 ajouts et 526 suppressions
/ -load memopol_tags cache
- load i18n
- load cache
- load staticfiles
#header.container-fluid
%a{href: "/", id: 'logo'}
%img{src: '{% static "images/logo.png" %}'}
%h1
%a#header_banner{href: "/"}
-trans "Political Memory"
%p.organization
=config.ORGANIZATION_NAME
#nav.container-fluid
-include "core/blocks/navigation.html"
%ul.nav
%li
%a{href: "{% url 'legislature:representative-index' %}"}
Representatives
%li
%a{href: "{% url 'legislature:group-index' kind='country' %}"}
Countries
%li
%a{href: "{% url 'legislature:group-index' kind='group' %}"}
Parties
%li
%a{href: "{% url 'legislature:group-index' kind='delegation' %}"}
Delegations
%li
%a{href: "{% url 'legislature:group-index' kind='committee' %}"}
Committees
%ul.nav
%li
%a{href: "{% url 'votes:dossier-index' %}"}
Votes
-# Pagination block display pagination for the `object_list`
`object_list` could be generated with core.view_utils.render_paginate_list
.pagination-block
%nav
%ul.pagination.pagination-sm
- if object_list.has_previous
%li
%a{'href': '?={queries.urlencode}&page=={object_list.previous_page_number}',
'aria-label': 'Previous'}
<i aria-hidden="true" class="fa fa-chevron-left"></i>
- for page_num in object_list.page_range
- if not page_num
%li.disabled
%a{'href': ''}
- elif page_num == object_list.number
%li.active
%a{'href': ''}
{{ page_num }}
- else
%li
%a{'href': '?={queries.urlencode}&page=={page_num}'}
{{ page_num }}
- if object_list.has_next
%li
%a{'href': '?={queries.urlencode}&page=={object_list.next_page_number}',
'aria-label': 'Next'}
<i aria-hidden="true" class="fa fa-chevron-right"></i>
%div.count
Number of results : {{ paginator.count }}
%br
Number of displayed results :
{{ paginator.per_page }}
(
- for limit in pagination_limits
%a{'href': '?limit={{ limit }}'}
{{ limit }}
- if not forloop.last
\/
)
- extends "base.html"
- block content
.row
.col-md-8
%p
Memopol is reachable only in <b>reduced functionality mode</b>.
By the way, you could access to
<a href="{% url 'legislature:representative-index' %}">the list of MEPs</a>.
%p
You can help on building the new Memopol by <a href="https://wiki.laquadrature.net/Projects/Memopol/Roadmap">coding, translating, de signing, funding, etc...</a>.
.col-md-4
.panel.panel-default
.panel-body
%p
<a href="http://memopol.org">Memopol Blog</a> is available as well as the new
<a href="http://git.laquadrature.net/memopol/memopol/issues">
bugtracking system</a>
%h3
What is memopol?
%p
Political Memory is a tool designed by La Quadrature du Net to help
European citizens to reach members of European Parliament (MEPs) and
track their voting records on issues related to fundamental
freedoms online. <em><a href="">More...</a></em>
# coding: utf-8
# This file is part of memopol.
#
# memopol is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of
# the License, or any later version.
#
# memopol is distributed in the hope that it will
# be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU General Affero Public
# License along with django-representatives.
# If not, see <http://www.gnu.org/licenses/>.
#
# Copyright (C) 2015 Arnaud Fabre <af@laquadrature.net>
from create_child_instance_from_parent import create_child_instance_from_parent
from render_paginate_list import render_paginate_list
# coding: utf-8
# This file is part of memopol.
#
# memopol is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of
# the License, or any later version.
#
# memopol is distributed in the hope that it will
# be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU General Affero Public
# License along with django-representatives.
# If not, see <http://www.gnu.org/licenses/>.
#
# Copyright (C) 2015 Arnaud Fabre <af@laquadrature.net>
from __future__ import absolute_import
def create_child_instance_from_parent(child_cls, parent_instance):
"""
Create a child model instance from a parent instance
"""
parent_cls = parent_instance.__class__
field = child_cls._meta.get_ancestor_link(parent_cls).column
child_instance = child_cls(**{
field: parent_instance.pk
})
child_instance.__dict__.update(parent_instance.__dict__)
child_instance.save()
return child_instance
import math
from django.core.paginator import \
Paginator, QuerySetPaginator, Page, InvalidPage
__all__ = (
'InvalidPage',
'ExPaginator',
'DiggPaginator',
'QuerySetDiggPaginator',
)
class ExPaginator(Paginator):
"""Adds a ``softlimit`` option to ``page()``. If True, querying a
page number larger than max. will not fail, but instead return the
last available page.
This is useful when the data source can not provide an exact count
at all times (like some search engines), meaning the user could
possibly see links to invalid pages at some point which we wouldn't
want to fail as 404s.
>>> items = range(1, 1000)
>>> paginator = ExPaginator(items, 10)
>>> paginator.page(1000)
Traceback (most recent call last):
InvalidPage: That page contains no results
>>> paginator.page(1000, softlimit=True)
<Page 100 of 100>
# [bug] graceful handling of non-int args
>>> paginator.page("str")
Traceback (most recent call last):
InvalidPage: That page number is not an integer
"""
def _ensure_int(self, num, e):
# see Django #7307
try:
return int(num)
except ValueError:
raise e
def page(self, number, softlimit=False):
try:
return super(ExPaginator, self).page(number)
except InvalidPage, e:
number = self._ensure_int(number, e)
if number > self.num_pages and softlimit:
return self.page(self.num_pages, softlimit=False)
else:
raise e
class DiggPaginator(ExPaginator):
"""
Based on Django's default paginator, it adds "Digg-style" page ranges
with a leading block of pages, an optional middle block, and another
block at the end of the page range. They are available as attributes
on the page:
{# with: page = digg_paginator.page(1) #}
{% for num in page.leading_range %} ...
{% for num in page.main_range %} ...
{% for num in page.trailing_range %} ...
Additionally, ``page_range`` contains a nun-numeric ``False`` element
for every transition between two ranges.
{% for num in page.page_range %}
{% if not num %} ... {# literally output dots #}
{% else %}{{ num }}
{% endif %}
{% endfor %}
Additional arguments passed to the constructor allow customization of
how those bocks are constructed:
body=5, tail=2
[1] 2 3 4 5 ... 91 92
|_________| |___|
body tail
|_____|
margin
body=5, tail=2, padding=2
1 2 ... 6 7 [8] 9 10 ... 91 92
|_| |__|
^padding^
|_| |__________| |___|
tail body tail
``margin`` is the minimum number of pages required between two ranges; if
there are less, they are combined into one.
When ``align_left`` is set to ``True``, the paginator operates in a
special mode that always skips the right tail, e.g. does not display the
end block unless necessary. This is useful for situations in which the
exact number of items/pages is not actually known.
# odd body length
>>> print DiggPaginator(range(1,1000), 10, body=5).page(1)
1 2 3 4 5 ... 99 100
>>> print DiggPaginator(range(1,1000), 10, body=5).page(100)
1 2 ... 96 97 98 99 100
# even body length
>>> print DiggPaginator(range(1,1000), 10, body=6).page(1)
1 2 3 4 5 6 ... 99 100
>>> print DiggPaginator(range(1,1000), 10, body=6).page(100)
1 2 ... 95 96 97 98 99 100
# leading range and main range are combined when close; note how
# we have varying body and padding values, and their effect.
>>> print DiggPaginator(range(1,1000), 10, body=5, padding=2, margin=2).page(3)
1 2 3 4 5 ... 99 100
>>> print DiggPaginator(range(1,1000), 10, body=6, padding=2, margin=2).page(4)
1 2 3 4 5 6 ... 99 100
>>> print DiggPaginator(range(1,1000), 10, body=5, padding=1, margin=2).page(6)
1 2 3 4 5 6 7 ... 99 100
>>> print DiggPaginator(range(1,1000), 10, body=5, padding=2, margin=2).page(7)
1 2 ... 5 6 7 8 9 ... 99 100
>>> print DiggPaginator(range(1,1000), 10, body=5, padding=1, margin=2).page(7)
1 2 ... 5 6 7 8 9 ... 99 100
# the trailing range works the same
>>> print DiggPaginator(range(1,1000), 10, body=5, padding=2, margin=2, ).page(98)
1 2 ... 96 97 98 99 100
>>> print DiggPaginator(range(1,1000), 10, body=6, padding=2, margin=2, ).page(97)
1 2 ... 95 96 97 98 99 100
>>> print DiggPaginator(range(1,1000), 10, body=5, padding=1, margin=2, ).page(95)
1 2 ... 94 95 96 97 98 99 100
>>> print DiggPaginator(range(1,1000), 10, body=5, padding=2, margin=2, ).page(94)
1 2 ... 92 93 94 95 96 ... 99 100
>>> print DiggPaginator(range(1,1000), 10, body=5, padding=1, margin=2, ).page(94)
1 2 ... 92 93 94 95 96 ... 99 100
# all three ranges may be combined as well
>>> print DiggPaginator(range(1,151), 10, body=6, padding=2).page(7)
1 2 3 4 5 6 7 8 9 ... 14 15
>>> print DiggPaginator(range(1,151), 10, body=6, padding=2).page(8)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
>>> print DiggPaginator(range(1,151), 10, body=6, padding=1).page(8)
1 2 3 4 5 6 7 8 9 ... 14 15
# no leading or trailing ranges might be required if there are only
# a very small number of pages
>>> print DiggPaginator(range(1,80), 10, body=10).page(1)
1 2 3 4 5 6 7 8
>>> print DiggPaginator(range(1,80), 10, body=10).page(8)
1 2 3 4 5 6 7 8
>>> print DiggPaginator(range(1,12), 10, body=5).page(1)
1 2
# test left align mode
>>> print DiggPaginator(range(1,1000), 10, body=5, align_left=True).page(1)
1 2 3 4 5
>>> print DiggPaginator(range(1,1000), 10, body=5, align_left=True).page(50)
1 2 ... 48 49 50 51 52
>>> print DiggPaginator(range(1,1000), 10, body=5, align_left=True).page(97)
1 2 ... 95 96 97 98 99
>>> print DiggPaginator(range(1,1000), 10, body=5, align_left=True).page(100)
1 2 ... 96 97 98 99 100
# padding: default value
>>> DiggPaginator(range(1,1000), 10, body=10).padding
4
# padding: automatic reduction
>>> DiggPaginator(range(1,1000), 10, body=5).padding
2
>>> DiggPaginator(range(1,1000), 10, body=6).padding
2
# padding: sanity check
>>> DiggPaginator(range(1,1000), 10, body=5, padding=3)
Traceback (most recent call last):
ValueError: padding too large for body (max 2)
"""
def __init__(self, *args, **kwargs):
self.body = kwargs.pop('body', 10)
self.tail = kwargs.pop('tail', 2)
self.align_left = kwargs.pop('align_left', False)
self.margin = kwargs.pop('margin', 4) # TODO: make the default relative to body?
# validate padding value
max_padding = int(math.ceil(self.body/2.0)-1)
self.padding = kwargs.pop('padding', min(4, max_padding))
if self.padding > max_padding:
raise ValueError('padding too large for body (max %d)'%max_padding)
super(DiggPaginator, self).__init__(*args, **kwargs)
def page(self, number, *args, **kwargs):
"""Return a standard ``Page`` instance with custom, digg-specific
page ranges attached.
"""
page = super(DiggPaginator, self).page(number, *args, **kwargs)
number = int(number) # we know this will work
# easier access
num_pages, body, tail, padding, margin = \
self.num_pages, self.body, self.tail, self.padding, self.margin
# put active page in middle of main range
main_range = map(int, [
math.floor(number-body/2.0)+1, # +1 = shift odd body to right
math.floor(number+body/2.0)])
# adjust bounds
if main_range[0] < 1:
main_range = map(abs(main_range[0]-1).__add__, main_range)
if main_range[1] > num_pages:
main_range = map((num_pages-main_range[1]).__add__, main_range)
# Determine leading and trailing ranges; if possible and appropriate,
# combine them with the main range, in which case the resulting main
# block might end up considerable larger than requested. While we
# can't guarantee the exact size in those cases, we can at least try
# to come as close as possible: we can reduce the other boundary to
# max padding, instead of using half the body size, which would
# otherwise be the case. If the padding is large enough, this will
# of course have no effect.
# Example:
# total pages=100, page=4, body=5, (default padding=2)
# 1 2 3 [4] 5 6 ... 99 100
# total pages=100, page=4, body=5, padding=1
# 1 2 3 [4] 5 ... 99 100
# If it were not for this adjustment, both cases would result in the
# first output, regardless of the padding value.
if main_range[0] <= tail+margin:
leading = []
main_range = [1, max(body, min(number+padding, main_range[1]))]
main_range[0] = 1
else:
leading = range(1, tail+1)
# basically same for trailing range, but not in ``left_align`` mode
if self.align_left:
trailing = []
else:
if main_range[1] >= num_pages-(tail+margin)+1:
trailing = []
if not leading:
# ... but handle the special case of neither leading nor
# trailing ranges; otherwise, we would now modify the
# main range low bound, which we just set in the previous
# section, again.
main_range = [1, num_pages]
else:
main_range = [min(num_pages-body+1, max(number-padding, main_range[0])), num_pages]
else:
trailing = range(num_pages-tail+1, num_pages+1)
# finally, normalize values that are out of bound; this basically
# fixes all the things the above code screwed up in the simple case
# of few enough pages where one range would suffice.
main_range = [max(main_range[0], 1), min(main_range[1], num_pages)]
# make the result of our calculations available as custom ranges
# on the ``Page`` instance.
page.main_range = range(main_range[0], main_range[1]+1)
page.leading_range = leading
page.trailing_range = trailing
page.page_range = reduce(lambda x, y: x+((x and y) and [False])+y,
[page.leading_range, page.main_range, page.trailing_range])
page.__class__ = DiggPage
return page
class DiggPage(Page):
def __str__(self):
return " ... ".join(filter(None, [
" ".join(map(str, self.leading_range)),
" ".join(map(str, self.main_range)),
" ".join(map(str, self.trailing_range))]))
class QuerySetDiggPaginator(DiggPaginator, QuerySetPaginator):
pass
if __name__ == "__main__":
import doctest
doctest.testmod()
# coding: utf-8
# This file is part of memopol.
#
# memopol is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of
# the License, or any later version.
#
# memopol is distributed in the hope that it will
# be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU General Affero Public
# License along with django-representatives.
# If not, see <http://www.gnu.org/licenses/>.
#
# Copyright (C) 2015 Arnaud Fabre <af@laquadrature.net>
from __future__ import absolute_import
from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator
from .digg_paginator import DiggPaginator
from django.shortcuts import render
def render_paginate_list(request, object_list, template_name):
"""
Render a paginated list of representatives
"""
pagination_limits = (10, 20, 50, 100)
num_by_page = request.GET.get('limit', 30)
paginator = DiggPaginator(object_list, num_by_page, body=5)
# paginator = Paginator(object_list, num_by_page)
page = request.GET.get('page', 1)
try:
objects = paginator.page(page)
except PageNotAnInteger:
objects = paginator.page(1)
except EmptyPage:
objects = paginator.page(paginator.num_pages)
context = {}
queries_without_page = request.GET.copy()
if 'page' in queries_without_page:
del queries_without_page['page']
context['queries'] = queries_without_page
context['object_list'] = objects
context['paginator'] = paginator
context['pagination_limits'] = pagination_limits
return render(
request,
template_name,
context
)
# coding: utf-8
# This file is part of memopol.
#
# memopol is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of
# the License, or any later version.
#
# memopol is distributed in the hope that it will
# be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU General Affero Public
# License along with django-representatives.
# If not, see <http://www.gnu.org/licenses/>.
#
# Copyright (C) 2015 Arnaud Fabre <af@laquadrature.net>
from django.views.generic.base import TemplateView
class HomeView(TemplateView):
template_name = "core/home.html"
# 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."
Administrator guide
~~~~~~~~~~~~~~~~~~~
This guide targets the administrator who has deployed
the website in production.
Authentication in the admin backend
===================================
If you haven't already, create a super-administrator
account with command::
memopol createsuperuser
Then use this account to authenticate in the
administration backend located in ``/admin``.
User groups
===========
You should create a user group with all permissions
on:
- vote | recommendation
- positions | position
Creating a user
===============
To create a content administrator, create a user with:
- "Staff status": checked, otherwise the user won't be
able to authenticate in the administration backend,
- groups: at least the group created above.
Then, send the credentials to the user along with a link to :doc:`usage`.
API Documentation
~~~~~~~~~~~~~~~~~
Memopol publishes its data with a read-only REST API using `Django REST
Framework <http://www.django-rest-framework.org/>`_. The API is browseable and
partially self-documented, from the ``/api`` URL.
The goal of this documentation is to plug the holes in the
automatically-generated documentation.
Overview
========
The API homepage resides at the ``/api/`` URL. Each model is accessible from two
URLs:
* ``/api/<model>/`` for a (filterable) list of objects
* ``/api/<model>/<pk>/`` to get a detailed view of a specific object
When accessing the API from a web browser, data should be displayed in a
user-friendly paginated interface, and relation fields are links to the
corresponding API URLs (if that's not the case, you can force it by appending
``format=api`` to the querystring). To get raw JSON data instead, either pass
an ``Accept: application/json`` request header or append ``format=json`` to the
querystring.
Object lists may be filtered using ``field=value`` in the querystring ; related
fields may be used in filters with double underscores (for example
``representative__name=John``). Alternative operators may be available for
some fields (for example ``score__gte=100``), amongst which:
* ``lte``: matches values that are lower than or equal to the specified value
* ``gte``: matches values greater than equal to or the specified value
* ``icontains``: matches values that contain the specified value, ignoring case
Note that fields that are made available for filtering depend on each model;
the same goes for alternative operators (by default only exact match is
available).
Finally, note that this documentation does not show the data schema. Feel free
to browse the API yourself to find out how data is published.
Representatives API
===================
This API provides views on representatives and mandates.
Representatives
---------------
The ``/api/representatives/[<pk>/]`` endpoints give access to representatives.
The following fields are available for filtering:
* ``active``: True or False
* ``slug`` (alt.: icontains)
* ``id``
* ``remote_id``
* ``first_name``
* ``last_name`` (alt.: icontains)
* ``gender``: M or F
* ``birth_place``
* ``birth_date`` (alt.: gte, lte)
* ``search``: searches in the ``first_name``, ``last_name`` and ``slug`` fields
Mandates
--------
The ``/api/mandates/[<pk>/]`` endpoints give access to mandates. The following
fields are available for filtering:
* ``id``
* ``group__name`` (alt.: icontains)
* ``group__abbreviation``
* ``search``: searches in the ``group__name`` and ``group_abbreviation`` fields
Constituency
------------
The ``/api/constituencies/[<pk>/]`` endpoints give access to constituencies.
Groups
------
The ``/api/groups/[<pk>/]`` endpoints give access to groups.
Representatives-votes API
=========================
This API provides views on dossiers, proposals and votes.
Dossiers
--------
The ``/api/dossiers/[<pk>/]`` endpoints give access to dossiers. The following
fields are available for filtering:
* ``fingerprint``
* ``title`` (alt.: icontains)
* ``reference`` (alt.: icontains)
* ``search``: searches in the ``fingerprint``, ``title``, ``reference``,
``text`` and ``proposals__title`` fields
Proposals
---------
The ``/api/proposals/[<pk>/]`` endpoints give access to proposals. The following
fields are available for filtering:
* ``fingerprint``
* ``dossier__fingerprint``
* ``title`` (alt.: icontains)
* ``description`` (alt.: icontains)
* ``reference`` (alt.: icontains)
* ``datetime`` (alt.: gte, lte)
* ``kind``
* ``search``: searches in the ``fingerprint``, ``title``,
``dossier__fingerprint``, ``dossier__title`` and ``dossier__reference`` fields
Votes
-----
The ``/api/votes/[<pk>/]`` endpoints give access to votes. The following fields
are available for filtering:
* ``proposal__fingerprint``
* ``position``
* ``representative_name`` (alt.: icontains)
* ``representative``
Memopol API
===========
This API provides views on recommendations and representative scores.
Recommendations
---------------
The ``/api/recommendations/[<pk>/]`` endpoints give access to recommendations.
The following fields are available for filtering:
* ``id``
* ``recommendation``
* ``title`` (alt.: icontains)
* ``description`` (alt.: icontains)
* ``weight`` (alt.: gte, lte)
* ``search``: searches in the ``title`` and ``description`` fields
Vote Scores
-----------
The ``/api/vote_scores/[<pk>/]`` endpoints give access to scored votes; that is,
representative votes with their contribution to the representative score. Only
votes that match a recommendation are visible using this endpoint. The
following fields are available for filtering:
* ``representative``
* ``proposal``
* ``proposal__dossier``
Dossier Scores
--------------
The ``/api/dossier_scores/[<pk>/]`` endpoints give access to dossier scores;
that is, the contribution of each dossier on a representative score. Only
dossiers with recommendations are visible using this endpoint. The following
fields are available for filtering:
* ``dossier``
* ``representative``
* ``score`` (alt.: gte, lte)
Representative scores
---------------------
The ``/api/scores/[<pk>/]`` endpoints give access to total scores for each
representative. The following fields are available for filtering:
* ``representative``
* ``score`` (alt.: gte, lte)
# -*- 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.
# 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 = ['../memopol_env/local/lib/python2.7/site-packages']
# 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
Deployment on a custom machine
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Prerequisites
=============
You will need the following:
* A clone of the git repository at ``https://git.laquadrature.net/memopol/memopol.git``
* A dedicated python virtualenv
* a PostgreSQL>=9.2 database (not necessarily on the same machine)
* a WSGI-capable web server
Setup environment
=================
Set the following environment variables::
DJANGO_SETTINGS_MODULE=memopol.settings
Customize settings
==================
Create a copy of the example local settings file::
$ cp src/memopol/local_settings.py.example src/memopol/local_settings.py
Edit ``src/memopol/local_settings.py`` to set directories, database settings and
allowed hosts. Setup your WSGI server to serve:
* Static files from the directory specified in the ``PUBLIC_DIR`` setting to the
``/static`` URL
* The ``src/memopol/wsgi.py`` WSGI application
Initial memopol setup
=====================
From the repository root, install python dependencies (you may want to do that
in a virtualenv)::
$ pip install -U pip setuptools
$ pip install -Ue .
Install client libraries::
$ src/memopol/bin/install_client_deps.sh
Setup the database schema::
$ memopol migrate --noinput
Collect static files::
$ memopol collectstatic --noinput
Memopol should be ready to go.
Updating
========
To update simply pull the repository and run setup commands again::
$ git pull
$ pip install -Ue .
$ src/memopol/bin/install_client_deps.sh
$ memopol migrate --noinput
$ memopol collectstatic --noinput
Data provisionning
==================
Set up two cron jobs:
* One to update data from parliaments, that runs ``bin/update_all``. This
script takes quite some time to run, so you should schedule it once every
night for example
* One to refresh scores, that runs ``memopol refresh_scores``. This one
runs quite quickly (a few seconds), you may want to run it after the update
job has completed (but you can run it more often).
Ensure that cron jobs get the same environment as the application.
Continue to :doc:`administration`.
Local development tutorial
~~~~~~~~~~~~~~~~~~~~~~~~~~
This tutorial drives through a local installation of the project for
development on Linux. It requires git, a fairly recent version of python2,
virtualenv and PostgreSQL.
Setup the database
==================
Memopol requires PostgreSQL 9.1 or higher. It used to run with SQLite, too, but
that is no longer the case. It is better to install and configure you're local
PostgreSQL server before starting to install Memopol.
On Debian
---------
To setup you're PostgreSQL database on a debian stable distribution, you can use
the package manager apt::
$ apt install postgresql postgresql-server-dev-9.X
Then you need to create the 'memopol' user and the 'memopol' database::
# To have a root access on Postgres, you need to connect as user 'postgres'
$ su - postgres
$ psql -c "create user memopol with password 'memopol';"
$ psql -c "alter role memopol with createdb;"
$ psql -c "create database memopol with owner memopol;"
$ exit
You're database is now setup for Memopol. You can now launch the 'quickstart.sh'
script to automatically install all the components or do it manually.
In General
----------
Make sure the corresponding user and database exist on your system; the user
will need the 'createdb' permission in order to be able to run tests. To create
them, you may use the following commands::
$ psql -c "create user memopol with password 'memopol';" -U postgres
$ psql -c "alter role memopol with createdb;" -U postgres
$ psql -c "create database memopol with owner memopol;" -U postgres
Automatic Install
=================
There is a quickstart script used and tested manually by some of the
developers. Feel free to try it, but don't worry if it doesn't work for you
then you can do each install step manually, which is recommended because well
that's how you will learn most.
Here's how to try it::
$ git clone gitlab@git.laquadrature.net:memopol/memopol.git
$ cd memopol
$ source bin/quickstart.sh
At this point, you should now run the development server and access to Memopol::
$ memopol runserver
If you want more control or if it doesn't work for you, then follow the steps
below or have a look at what the quickstart script does.
Development helper
===================
You can run the script 'bin/dev.sh' to automaticaly setup some aliases. It works
only with Bash and Zsh.
The script build a custom file named '.memopol.alias' at the root of the project
containing all the aliases for memopol. All the path to the project are build
automatically. A single line is added to your '$HOME/.bashrc' or '$HOME/.zshrc'
to source the aliases.
After execute 'bin/dev.sh' you should close the current terminal and open
another one to have access to the aliases.
There is a quick list of available aliases::
memopol-code : Go into the repository and activate virtualenv and
set Django in debug mode
memopol-launch : Run the development server echo
memopol-update-all : Get all the production data
memopol-refresh-scores : Refresh all scores
.. warning:: If you are using multiple setup of Memopol, it is not recommended to
use this script.
If you need to change the location of the project, you should remove this line
from your .bashrc or .zshrc::
source $PATH_TO_THE_PROJECT/.memopol.alias
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
Alternatively, use the tox command::
$ tox -e py27
$ source .tox/py27/bin/activate
Clone the repository
====================
The project is hosted on https://git.laquadrature.net/memopol/memopol
You can get the code with git ::
$ git clone https://git.laquadrature.net/memopol/memopol
Clonage dans 'memopol'...
remote: Counting objects: 7972, done.
remote: Compressing objects: 100% (2668/2668), done.
remote: Total 7972 (delta 5203), reused 7830 (delta 5099)
Réception d'objets: 100% (7972/7972), 4.88 MiB | 4.73 MiB/s, fait.
Résolution des deltas: 100% (5203/5203), fait.
Vérification de la connectivité... fait.
$ cd memopol/
Create your own branch, ie::
$ git checkout -b yourbranch
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/memopol
Collecting django (from memopol==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, memopol
Running setup.py develop for memopol
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 memopol 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
Install client dependencies
===========================
We'll also need to download client libraries::
$ src/memopol/bin/install_client_deps.sh
* Downloading jquery/jquery (2.1.4) from Github...
* Downloading FortAwesome/Font-Awesome (v4.3.0) from Github...
* Downloading lipis/flag-icon-css (0.7.1) from Github...
* Downloading twbs/bootstrap (v3.3.5) from Github...
* Done
Activate ``DJANGO_DEBUG``
=========================
``DEBUG`` is disabled by default, the development server
won't run properly by default then, to enable it export
the ``DJANGO_DEBUG`` variable in the current shell::
$ export DJANGO_DEBUG=True
Database migrations
===================
Database migrations ensure the database schema is up to date with the project.
If you're not sure, you can run them anyway, they won't do any harm. Use the
following command::
$ memopol 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
Provision with data
===================
You can load a small data sample for quick setup:
$ memopol loaddata small_sample.json
If you launch memopol for the first time, you need to launch this command :
$ memopol refresh_scores
Or actual data (takes a while)::
$ bin/update_all
Run the development server
==========================
Run the development server::
$ memopol 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/``.
Continue to :doc:`administration`.
Hacker guide
~~~~~~~~~~~~
See a `hacking demo on the Memopol project in some epic
slides
<https://slides.com/jamespic/cd-devops/fullscreen#/>`_.
Read about it in `Continuous Delivery and DevOps
quickstart
<https://www.packtpub.com/application-development/continuous-delivery-and-devops-%E2%80%93-quickstart-guide-second-edition)>`_,
and I bet you'll order a paperback edition for reference !
Testing
=======
Use the ``tox -l`` command to list tests::
$ pip install tox
$ cd memopol/
$ tox -l
Use the ``tox -e`` command to execute a particular test suite::
$ tox -e py27
And use the ``tox`` command without argument to execute all test suites,
exactly like in CI.
Adding random recommendations
=============================
::
$ memopol shell
In [1]: from representatives_votes.models import Proposal
In [2]: from votes.models import Recommendation
In [3]: import random
In [4]: for p in Proposal.objects.all(): Recommendation.objects.create(proposal=p, recommendation='for', weight=random.randint(1,10))
Creating test fixtures
======================
The largest test fixtures are, the longer it takes to load them, the longer the
test run is.
To create test fixtures for representatives_positions, insert some Position
objects, and reduce the database with::
memopol remove_representatives_without_position
memopol remove_groups_without_mandate
memopol remove_countries_without_group
For representatives_recommendations::
memopol remove_proposals_without_recommendation
memopol remove_dossiers_without_proposal
memopol remove_representatives_without_vote
memopol remove_groups_without_mandate
memopol remove_countries_without_group
docs/img/score_10years.png

3,79 ko

docs/img/score_1year.png

5,5 ko

docs/img/score_exp1k.png

3,1 ko

docs/img/score_exp6.png

4,61 ko