Commit a5c24a90 authored by Arnaud Fabre's avatar Arnaud Fabre

update memopol for link between representatives and vote

parent bfb601aa
......@@ -116,10 +116,10 @@ p {
li {
text-decoration: none;
list-style: outside none none;
list-style: inside;
}
.panel.callout {
.panel. {
background: none repeat scroll 0% 0% #5B8EDC;
color: #FFF;
border-color: #2284A1;
......
%ul.nav-bar
%li
%a{href: "{% url 'legislature:representatives_index' %}"}
%a{href: "{% url 'legislature:representative_index' %}"}
Representatives
%li
%em By :
%li
%a{href: "{% url 'legislature:groups_by_kind' 'country' %}"}
%a{href: "{% url 'legislature:group_index' kind='country' %}"}
Countries
%li
%a{href: "{% url 'legislature:groups_by_kind' 'group' %}"}
%a{href: "{% url 'legislature:group_index' kind='group' %}"}
Parties
%li
%a{href: "{% url 'legislature:groups_by_kind' 'delegation' %}"}
%a{href: "{% url 'legislature:group_index' kind='delegation' %}"}
Delegations
%li
%a{href: "{% url 'legislature:groups_by_kind' 'committee' %}"}
%a{href: "{% url 'legislature:group_index' kind='committee' %}"}
Committees
%ul.nav-bar
%li
%a{href: "{% url 'votes:votes_index' %}"}
%a{href: "{% url 'votes:dossier_index' %}"}
Votes
%li
%em By :
-# Pagination block display pagination for the `object_list`
`object_list` could be generated with core.view_utils.render_paginate_list
.pagination
%span.step-links
- if object_list.has_previous
%a{'href': '?={queries.urlencode}&page=={object_list.previous_page_number}'} previous
%span.current
Page ={object_list.number} of ={object_list.paginator.num_pages}
- if object_list.has_next
%a{'href': '?={queries.urlencode}&page=={object_list.next_page_number}'} next
......@@ -3,7 +3,8 @@
.row
.large-8.columns
%p
Actually Memopol is actually reachable only in <b>reduced functionality mode</b>. By the way, you could access to <a href="/representatives">the actual list of MEPs</a>.
Actually Memopol is reachable only in <b>reduced functionality mode</b>.
By the way, you could access to <a href="{% url 'legislature:representative_index' %}">the actual 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>.
%p
......
# 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 Paginator, EmptyPage, PageNotAnInteger
from django.shortcuts import render
def render_paginate_list(request, object_list, template_name, num_by_page=30):
"""
Render a paginated list of representatives
"""
paginator = Paginator(object_list, num_by_page)
page = request.GET.get('page')
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['object_count'] = paginator.count
return render(
request,
template_name,
context
)
......@@ -7,7 +7,7 @@ from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('representatives', '0003_auto_20150625_1151'),
('representatives', '0003_auto_20150702_1827'),
]
operations = [
......
......@@ -32,10 +32,6 @@ from core.utils import create_child_instance_from_parent
class MemopolRepresentative(Representative):
# parent_identifier = 'fingerprint'
# representative_finger = models.CharField(max_length=255, unique=True)
country = models.ForeignKey(Country, null=True)
score = models.IntegerField(default=0)
......@@ -81,13 +77,6 @@ class MemopolRepresentative(Representative):
self.country = None
self.save()
@cached_property
def votes(self):
return Vote.objects.filter(
representative_remote_id = self.remote_id
)
def active_mandates(self):
return self.mandates.filter(
end_date__gte=datetime.now()
......@@ -108,7 +97,7 @@ class MemopolRepresentative(Representative):
def create_memopolrepresentative_from_representative(instance, **kwargs):
memopol_representative = create_child_instance_from_parent(MemopolRepresentative, instance)
memopol_representative.update_country()
memopol_representative.save()
@receiver(post_save, sender=Mandate)
def update_memopolrepresentative_country(instance, created, **kwargs):
......
# 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 datetime import datetime
from django.http import Http404
from django.shortcuts import render, get_object_or_404
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.db.models import Q
......@@ -7,22 +27,19 @@ from django.db.models import Q
from representatives.models import Group
from legislature.models import MemopolRepresentative
def representatives_index(request):
representative_list = _filter_by_search(
request,
MemopolRepresentative.objects.filter(
active=True
def retrieve(request, pk=None, name=None):
if pk:
representative = get_object_or_404(
MemopolRepresentative,
id=pk
)
)
return _render_list(request, representative_list)
def representative_by_name(request, name):
representative = get_object_or_404(
MemopolRepresentative,
full_name=name
)
elif name:
representative = get_object_or_404(
MemopolRepresentative,
full_name=name
)
else:
return Http404()
return render(
request,
......@@ -30,16 +47,6 @@ def representative_by_name(request, name):
{'representative': representative}
)
def representative_view(request, id):
representative = get_object_or_404(MemopolRepresentative, pk=id)
return render(
request,
'legislature/representative_view.html',
{'representative': representative}
)
def representatives_by_group(request, group_kind, group_abbr=None,
group_name=None, search=None, group_id=None):
if group_id:
......
......@@ -10,8 +10,7 @@
%h1= representative.full_name
%h2
SCORE : {{ representative.extra.score }}
SCORE : {{ representative.score }}
%p
%strong
%a{:href => "{{ representative.current_group_mandate|by_group_url }}"}
......@@ -25,8 +24,19 @@
%p= representative.country.name
-# Mandates
%div{:style => "clear: both"}
%h2 Votes
%ul
- for vote in representative.votes.all
%li
={vote.proposal.recommendation.title} -
={vote.position}
(recommendation: ={vote.proposal.recommendation.recommendation})
%h2{:style => "clear: both"} Mandates
%h2 Mandates
- for mandate in representative.active_mandates
.mandate
......
- extends 'base.html'
- load by_group_url
- block content
- include 'legislature/search.html'
%p
Number of representatives: {{ object_count }}
%table
- for representative in object_list
%tr
%td
%a{'href': "{% url 'legislature:representative_detail' name=representative.slug %}"}
%img{'src': '={representative.photo}', 'width': '80'}/
%td
%a{'href': "{% url 'legislature:representative_detail' name=representative.slug %}"}
={representative.full_name}
%td
%a{'href': "{% url 'legislature:representative_index' group_kind='country' group=representative.country.code %}"}
={representative.country.name}
%td
%a{'href': "{{ representative.current_group_mandate|by_group_url }}"}
={representative.current_group_mandate.group.abbreviation}
%td
={representative.score}
- include "core/blocks/pagination.html"
- extends 'base.html'
- block content
- include 'legislature/search.html'
%p
Number of representatives: {{ representative_num }}
%table
- for representative in representatives
%tr
- include 'legislature/representative_block.html'
.pagination
%span.step-links
- if representatives.has_previous
%a{'href': '?={queries.urlencode}&page=={representatives.previous_page_number}'} previous
%span.current
Page ={representatives.number} of ={representatives.paginator.num_pages}
- if representatives.has_next
%a{'href': '?={queries.urlencode}&page=={representatives.next_page_number}'} next
......@@ -17,13 +17,13 @@ def by_group_url(group):
kwargs = {'group_kind': group.kind}
if group.abbreviation:
kwargs['search'] = group.abbreviation
kwargs['group'] = group.abbreviation
else:
kwargs['search'] = group.name
kwargs['group'] = group.name
kwargs['group_id'] = group.id
# kwargs['group_id'] = group.id
return reverse(
'legislature:representatives_by_group',
'legislature:representative_index',
kwargs=kwargs
)
from django.conf.urls import patterns, url
from django.conf.urls import url
from . import views
from views import representative
from views import group
urlpatterns = patterns(
'',
urlpatterns = [
# List of groups by group kind
url(
r'^representatives/?$',
views.representatives_index,
name='representatives_index'
r'^groups/(?P<kind>\w+)?$',
group.index,
name='group_index'
),
# Representative detail by representative name
url(
r'^representatives/view/(?P<num>\d+)$',
views.representative_view,
name='representative_view'
r'^(?P<name>[-\w]+)$',
representative.detail,
name='representative_detail'
),
# Representative detail by representative pk
url(
r'^representatives/(?P<group_kind>\w+)/(?P<search>.+)/(?P<group_id>\d+)?$',
views.representatives_by_group,
name='representatives_by_group'
r'^(?P<pk>\d+)$',
representative.detail,
name='representative_detail'
),
# List of representatives by group kind and group name or pk
url(
r'^representatives/(?P<name>.+)$',
views.representative_by_name,
name='representative_view_by_name'
r'^(?P<group_kind>\w+)/(?P<group>.+)$',
representative.index,
name='representative_index'
),
# List all representatives by default
url(
r'^groups/(?P<kind>\w+)$',
views.groups_by_kind,
name='groups_by_kind'
)
)
r'',
representative.index,
name='representative_index'
),
]
# 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.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.shortcuts import render
def render_paginate_list(request, object_list, template_name, num_by_page=30):
"""
Render a paginated list of representatives
"""
paginator = Paginator(object_list, num_by_page)
page = request.GET.get('page')
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['object_count'] = paginator.count
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 datetime import datetime
from django.shortcuts import render
from representatives.models import Group
def index(request, kind=None):
groups = Group.objects.filter(
mandates__end_date__gte=datetime.now()
)
if kind:
groups = groups.filter(
kind=kind
)
print(groups)
groups = groups.distinct().order_by('name')
return render(
request,
'legislature/groups_list.html',
{'groups': groups}
)
# 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 datetime import datetime
from django.db.models import Q
from django.shortcuts import render, get_object_or_404
from django.http import Http404
from ..models import MemopolRepresentative
from core.views_utils import render_paginate_list
def index(request, group_kind=None, group=None):
# Fetch active representatives
representative_list = MemopolRepresentative.objects.filter(
active=True
)
# Filter the list by group if group information is provided
if group_kind:
if group.isnumeric():
representative_list = representative_list.filter(
mandates__group_id=int(group),
mandates__end_date__gte=datetime.now()
)
else:
# Search group based on abbreviation or name
representative_list = representative_list.filter(
Q(mandates__group__abbreviation=group) |
Q(mandates__group__name=group),
mandates__group__kind=group_kind,
mandates__end_date__gte=datetime.now()
)
# Filter the list by search
representative_list = _filter_by_search(
request,
representative_list
).order_by('-score', 'last_name')
# Render the paginated template
return render_paginate_list(
request,
representative_list,
'legislature/representative_index.html'
)
def detail(request, pk=None, name=None):
if pk:
representative = get_object_or_404(
MemopolRepresentative,
id=pk
)
elif name:
representative = get_object_or_404(
MemopolRepresentative,
slug=name
)
else:
return Http404()
return render(
request,
'legislature/representative_detail.html',
{'representative': representative}
)
def _filter_by_search(request, representative_list):
"""
Return a representative_list filtered by
the representative name provided in search form
"""
search = request.GET.get('search')
if search:
return representative_list.filter(
Q(full_name__icontains=search)
)
else:
return representative_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 django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.shortcuts import render
def render_paginate_list(request, object_list, template_name, num_by_page=30):
"""
Render a paginated list of representatives
"""
paginator = Paginator(object_list, num_by_page)
page = request.GET.get('page')
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['object_count'] = paginator.count
return render(
request,
template_name,
context
)
......@@ -75,6 +75,10 @@ INSTALLED_APPS = (
)
if DEBUG:
INSTALLED_APPS += tuple(get_param('dev_modules'))
MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
......
......@@ -31,7 +31,7 @@ urlpatterns = patterns('',
# Examples:
# url(r'^$', 'memopol.views.home', name='home'),
url(r'^$', core.views.HomeView.as_view(), name='index'),
url('', include('legislature.urls', namespace='legislature')),
url('', include('votes.urls', namespace='votes')),
url(r'^legislature/', include('legislature.urls', namespace='legislature')),
url(r'^votes/', include('votes.urls', namespace='votes')),
url(r'^admin/', include(admin.site.urls)),
)
......@@ -22,12 +22,13 @@ from __future__ import absolute_import
from django.contrib import admin
from django.core.urlresolvers import reverse
from .admin_views import import_vote_with_recommendation, import_vote
from .admin_views import import_vote_with_recommendation, import_vote, update_representatives_score
from .models import Recommendation, MemopolDossier
admin.site.register_view('import_vote', view=import_vote)
admin.site.register_view('import_vote_with_recommendation', view=import_vote_with_recommendation)
admin.site.register_view('update_representatives_score', view=update_representatives_score)
def link_to_edit(obj, field):
try:
......@@ -47,8 +48,11 @@ def link_to_edit(obj, field):
class MemopolDossierAdmin(admin.ModelAdmin):
list_display = ('name', 'dossier')
list_display = ('name', 'dossier_ptr')
search_fields = ('name',)
fields = ('dossier_ptr', 'name')
readonly_fields = ('dossier_ptr',)
class RecommendationsAdmin(admin.ModelAdmin):
......
......@@ -22,18 +22,22 @@ from __future__ import absolute_import
from django.conf import settings
from django.shortcuts import render, redirect
from django import forms
from django.core.management import call_command
import requests
from representatives_votes.models import Proposal
from representatives_votes.tasks import import_a_proposal_from_toutatis
from .forms import RecommendationForm
from .tasks import update_representatives_score as task_urs
class SearchForm(forms.Form):
query = forms.CharField(label='Search', max_length=100)