Commit 33adf51b authored by njoyard's avatar njoyard Committed by GitHub

Merge pull request #104 from political-memory/add-dossier-documents

Add dossier documents
parents 6d21ccd2 9e4aee12
...@@ -11,6 +11,9 @@ memopol/config.json ...@@ -11,6 +11,9 @@ memopol/config.json
# Byte-compiled / optimized / DLL files # Byte-compiled / optimized / DLL files
__pycache__/ __pycache__/
*.py[cod] *.py[cod]
.cache
.coverage
*.egg-info
# Installer logs # Installer logs
pip-log.txt pip-log.txt
...@@ -18,3 +21,5 @@ pip-delete-this-directory.txt ...@@ -18,3 +21,5 @@ pip-delete-this-directory.txt
.dpl .dpl
db.sqlite db.sqlite
log/ log/
/data
from rest_framework import routers from rest_framework import routers
from representatives.api import ( from representatives.api import (
ChamberViewSet,
ConstituencyViewSet, ConstituencyViewSet,
GroupViewSet, GroupViewSet,
MandateViewSet, MandateViewSet,
...@@ -23,6 +24,7 @@ from representatives_recommendations.api import ( ...@@ -23,6 +24,7 @@ from representatives_recommendations.api import (
router = routers.DefaultRouter() router = routers.DefaultRouter()
router.register(r'chambers', ChamberViewSet, 'api-chamber')
router.register(r'constituencies', ConstituencyViewSet, 'api-constituency') router.register(r'constituencies', ConstituencyViewSet, 'api-constituency')
router.register(r'dossiers', DossierViewSet, 'api-dossier') router.register(r'dossiers', DossierViewSet, 'api-dossier')
router.register(r'dossier_scores', DossierScoreViewSet, 'api-dossierscore') router.register(r'dossier_scores', DossierScoreViewSet, 'api-dossierscore')
......
...@@ -13,7 +13,7 @@ from representatives.models import Chamber, Group, Representative ...@@ -13,7 +13,7 @@ from representatives.models import Chamber, Group, Representative
from representatives_votes.models import Dossier from representatives_votes.models import Dossier
def chamber_filter(qs, value): def rep_chamber_filter(qs, value):
today = datetime.date.today() today = datetime.date.today()
return qs.filter( return qs.filter(
Q(mandates__end_date__gte=today) | Q(mandates__end_date__isnull=True), Q(mandates__end_date__gte=today) | Q(mandates__end_date__isnull=True),
...@@ -21,6 +21,10 @@ def chamber_filter(qs, value): ...@@ -21,6 +21,10 @@ def chamber_filter(qs, value):
) )
def dossier_chamber_filter(qs, value):
return qs.filter(documents__chamber=value)
def group_filter(qs, value): def group_filter(qs, value):
today = datetime.date.today() today = datetime.date.today()
return qs.filter( return qs.filter(
...@@ -34,7 +38,7 @@ class RepresentativeFilter(FilterSet): ...@@ -34,7 +38,7 @@ class RepresentativeFilter(FilterSet):
search = MethodFilter(action='search_filter') search = MethodFilter(action='search_filter')
chamber = ModelChoiceFilter(queryset=Chamber.objects.all(), chamber = ModelChoiceFilter(queryset=Chamber.objects.all(),
action=chamber_filter) action=rep_chamber_filter)
country = ModelChoiceFilter(queryset=Group.objects.filter(kind='country'), country = ModelChoiceFilter(queryset=Group.objects.filter(kind='country'),
action=group_filter) action=group_filter)
...@@ -60,9 +64,12 @@ class DossierFilter(FilterSet): ...@@ -60,9 +64,12 @@ class DossierFilter(FilterSet):
search = MethodFilter(action='search_filter') search = MethodFilter(action='search_filter')
chamber = ModelChoiceFilter(queryset=Chamber.objects.all(),
action=dossier_chamber_filter)
class Meta: class Meta:
model = Dossier model = Dossier
fields = ['search'] fields = ['search', 'chamber']
def search_filter(self, qs, value): def search_filter(self, qs, value):
if len(value) == 0: if len(value) == 0:
......
...@@ -942,12 +942,24 @@ ...@@ -942,12 +942,24 @@
"reference": "2010/2935(RSP)", "reference": "2010/2935(RSP)",
"title": "Resolution on the Anti-Counterfeiting Trade Agreement (ACTA)", "title": "Resolution on the Anti-Counterfeiting Trade Agreement (ACTA)",
"text": "", "text": "",
"created": "2015-12-27T17:40:18.700Z", "created": "2015-12-27T17:40:18.700Z"
"link": "http://www.europarl.europa.eu/oeil/popups/ficheprocedure.do?reference=2010/2935(RSP)"
}, },
"model": "representatives_votes.dossier", "model": "representatives_votes.dossier",
"pk": 28147 "pk": 28147
}, },
{
"fields": {
"updated": "2015-12-27T17:40:18.700Z",
"created": "2015-12-27T17:40:18.700Z",
"title": "",
"kind": "procedure-file",
"link": "http://www.europarl.europa.eu/oeil/popups/ficheprocedure.do?reference=2010/2935(RSP)",
"dossier": 28147,
"chamber": 1
},
"model": "representatives_votes.document",
"pk": 1
},
{ {
"fields": { "fields": {
"updated": "2015-12-27T18:03:52.645Z", "updated": "2015-12-27T18:03:52.645Z",
...@@ -1092,13 +1104,13 @@ ...@@ -1092,13 +1104,13 @@
"app_label": "representatives_positions" "app_label": "representatives_positions"
}, },
"model": "contenttypes.contenttype", "model": "contenttypes.contenttype",
"pk": 28 "pk": 29
}, },
{ {
"fields": { "fields": {
"tag": 1, "tag": 1,
"object_id": 1, "object_id": 1,
"content_type": 28 "content_type": 29
}, },
"model": "taggit.taggeditem", "model": "taggit.taggeditem",
"pk": 1 "pk": 1
...@@ -1107,7 +1119,7 @@ ...@@ -1107,7 +1119,7 @@
"fields": { "fields": {
"tag": 2, "tag": 2,
"object_id": 1, "object_id": 1,
"content_type": 28 "content_type": 29
}, },
"model": "taggit.taggeditem", "model": "taggit.taggeditem",
"pk": 2 "pk": 2
...@@ -1116,7 +1128,7 @@ ...@@ -1116,7 +1128,7 @@
"fields": { "fields": {
"tag": 1, "tag": 1,
"object_id": 3, "object_id": 3,
"content_type": 28 "content_type": 29
}, },
"model": "taggit.taggeditem", "model": "taggit.taggeditem",
"pk": 5 "pk": 5
...@@ -1125,7 +1137,7 @@ ...@@ -1125,7 +1137,7 @@
"fields": { "fields": {
"tag": 1, "tag": 1,
"object_id": 2, "object_id": 2,
"content_type": 28 "content_type": 29
}, },
"model": "taggit.taggeditem", "model": "taggit.taggeditem",
"pk": 6 "pk": 6
...@@ -1134,7 +1146,7 @@ ...@@ -1134,7 +1146,7 @@
"fields": { "fields": {
"tag": 3, "tag": 3,
"object_id": 2, "object_id": 2,
"content_type": 28 "content_type": 29
}, },
"model": "taggit.taggeditem", "model": "taggit.taggeditem",
"pk": 7 "pk": 7
......
...@@ -21679,12 +21679,24 @@ ...@@ -21679,12 +21679,24 @@
"reference": "2010/2935(RSP)", "reference": "2010/2935(RSP)",
"title": "Resolution on the Anti-Counterfeiting Trade Agreement (ACTA)", "title": "Resolution on the Anti-Counterfeiting Trade Agreement (ACTA)",
"text": "", "text": "",
"created": "2015-12-27T17:40:18.700Z", "created": "2015-12-27T17:40:18.700Z"
"link": "http://www.europarl.europa.eu/oeil/popups/ficheprocedure.do?reference=2010/2935(RSP)"
}, },
"model": "representatives_votes.dossier", "model": "representatives_votes.dossier",
"pk": 28147 "pk": 28147
}, },
{
"fields": {
"updated": "2015-12-27T17:40:18.700Z",
"created": "2015-12-27T17:40:18.700Z",
"title": "",
"kind": "procedure-file",
"link": "http://www.europarl.europa.eu/oeil/popups/ficheprocedure.do?reference=2010/2935(RSP)",
"dossier": 28147,
"chamber": 1
},
"model": "representatives_votes.document",
"pk": 1
},
{ {
"fields": { "fields": {
"updated": "2015-12-27T18:03:52.645Z", "updated": "2015-12-27T18:03:52.645Z",
......
...@@ -101,6 +101,15 @@ def chamber_icon(chamber): ...@@ -101,6 +101,15 @@ def chamber_icon(chamber):
abbr=cssify(chamber.abbreviation))) abbr=cssify(chamber.abbreviation)))
@register.filter
def chamber_small_icon(chamber):
return mark_safe(
u'<span class="chamber-icon ' +
u'chamber-icon-{abbr}" title="{name}"></span>'.format(
name=chamber.name,
abbr=cssify(chamber.abbreviation)))
@register.filter @register.filter
def mandate_icon(main_mandate): def mandate_icon(main_mandate):
return mark_safe( return mark_safe(
......
...@@ -84,6 +84,44 @@ ...@@ -84,6 +84,44 @@
<strong>2010/2935(RSP)</strong> <strong>2010/2935(RSP)</strong>
</p> </p>
<h2>
Documents
</h2>
<table class='table'>
<tr>
<th>
Chamber
</th>
<th>
Document type
</th>
<th>
Title
</th>
</tr>
<tr>
<td>
<span class="chamber-icon chamber-icon-ep"></span> European Parliament
</td>
<td>
<a class='external' href='http://www.europarl.europa.eu/oeil/popups/ficheprocedure.do?reference=2010/2935(RSP)' target='_blank'>
Procedure file
</a>
</td>
<td>
<a class='external' href='http://www.europarl.europa.eu/oeil/popups/ficheprocedure.do?reference=2010/2935(RSP)' target='_blank'>
</a>
</td>
</tr>
</table>
<h2> <h2>
Recommendations Recommendations
......
...@@ -91,6 +91,11 @@ ...@@ -91,6 +91,11 @@
<form class='filter-form' action='/votes/dossier/' method='get'> <form class='filter-form' action='/votes/dossier/' method='get'>
<div class="form-group has-success"><label class="control-label" for="id_search">Search</label><input class="form-control" id="id_search" name="search" placeholder="Search" title="Filter" type="text" /><span class="help-block">Filter <div class="form-group has-success"><label class="control-label" for="id_search">Search</label><input class="form-control" id="id_search" name="search" placeholder="Search" title="Filter" type="text" /><span class="help-block">Filter
</span></div>
<div class="form-group has-success"><label class="control-label" for="id_chamber">Chamber</label><select class="form-control" id="id_chamber" name="chamber" title="Filter">
<option value="" selected="selected">---------</option>
<option value="1">European Parliament [EP]</option>
</select><span class="help-block">Filter
</span></div> </span></div>
<div class="form-group"> <div class="form-group">
...@@ -164,6 +169,9 @@ ...@@ -164,6 +169,9 @@
</h1> </h1>
<table class='table'> <table class='table'>
<tr> <tr>
<th>
Chambers
</th>
<th> <th>
Title Title
</th> </th>
...@@ -180,6 +188,11 @@ ...@@ -180,6 +188,11 @@
</tr> </tr>
<tr> <tr>
<td>
<span class="chamber-icon chamber-icon-ep" title="European Parliament"></span>
</td>
<td> <td>
<a href='/votes/dossier/28147/'> <a href='/votes/dossier/28147/'>
Resolution on the Anti-Counterfeiting Trade Agreement (ACTA) Resolution on the Anti-Counterfeiting Trade Agreement (ACTA)
......
...@@ -91,6 +91,11 @@ ...@@ -91,6 +91,11 @@
<form class='filter-form' action='/votes/dossier/' method='get'> <form class='filter-form' action='/votes/dossier/' method='get'>
<div class="form-group has-success"><label class="control-label" for="id_search">Search</label><input class="form-control" id="id_search" name="search" placeholder="Search" title="Filter" type="text" value="acta" /><span class="help-block">Filter <div class="form-group has-success"><label class="control-label" for="id_search">Search</label><input class="form-control" id="id_search" name="search" placeholder="Search" title="Filter" type="text" value="acta" /><span class="help-block">Filter
</span></div>
<div class="form-group has-success"><label class="control-label" for="id_chamber">Chamber</label><select class="form-control" id="id_chamber" name="chamber" title="Filter">
<option value="" selected="selected">---------</option>
<option value="1">European Parliament [EP]</option>
</select><span class="help-block">Filter
</span></div> </span></div>
<div class="form-group"> <div class="form-group">
...@@ -164,6 +169,9 @@ ...@@ -164,6 +169,9 @@
</h1> </h1>
<table class='table'> <table class='table'>
<tr> <tr>
<th>
Chambers
</th>
<th> <th>
Title Title
</th> </th>
...@@ -180,6 +188,11 @@ ...@@ -180,6 +188,11 @@
</tr> </tr>
<tr> <tr>
<td>
<span class="chamber-icon chamber-icon-ep" title="European Parliament"></span>
</td>
<td> <td>
<a href='/votes/dossier/28147/'> <a href='/votes/dossier/28147/'>
Resolution on the Anti-Counterfeiting Trade Agreement (ACTA) Resolution on the Anti-Counterfeiting Trade Agreement (ACTA)
......
...@@ -91,6 +91,11 @@ ...@@ -91,6 +91,11 @@
<form class='filter-form' action='/votes/dossier/' method='get'> <form class='filter-form' action='/votes/dossier/' method='get'>
<div class="form-group has-success"><label class="control-label" for="id_search">Search</label><input class="form-control" id="id_search" name="search" placeholder="Search" title="Filter" type="text" value="no-dossier-will-have-that-title-ever" /><span class="help-block">Filter <div class="form-group has-success"><label class="control-label" for="id_search">Search</label><input class="form-control" id="id_search" name="search" placeholder="Search" title="Filter" type="text" value="no-dossier-will-have-that-title-ever" /><span class="help-block">Filter
</span></div>
<div class="form-group has-success"><label class="control-label" for="id_chamber">Chamber</label><select class="form-control" id="id_chamber" name="chamber" title="Filter">
<option value="" selected="selected">---------</option>
<option value="1">European Parliament [EP]</option>
</select><span class="help-block">Filter
</span></div> </span></div>
<div class="form-group"> <div class="form-group">
......
...@@ -14,31 +14,38 @@ class DossiersTest(ResponseDiffMixin, TestCase): ...@@ -14,31 +14,38 @@ class DossiersTest(ResponseDiffMixin, TestCase):
# session setup # session setup
self.client.get('/votes/dossier/') self.client.get('/votes/dossier/')
# 1 query for chamber list (search form)
# 1 query for dossier count # 1 query for dossier count
# 1 query for dossiers # 1 query for dossiers
# 1 query for proposals # 1 query for proposals
# 1 query for recommendations # 1 query for recommendations
self.responsediff_test('/votes/dossier/', 4) # 1 query for documents
# 1 query for document chambers
self.responsediff_test('/votes/dossier/', 7)
def test_dossier_search(self): def test_dossier_search(self):
# session setup # session setup
self.client.get('/votes/dossier/') self.client.get('/votes/dossier/')
# 1 query for chamber list (search form)
# 1 query for dossier count # 1 query for dossier count
# 1 query for dossiers # 1 query for dossiers
# 1 query for proposals # 1 query for proposals
# 1 query for recommendations # 1 query for recommendations
# 1 query for documents
# 1 query for document chambers
q = 'acta' q = 'acta'
self.responsediff_test('/votes/dossier/?search=%s' % q, 4) self.responsediff_test('/votes/dossier/?search=%s' % q, 7)
def test_dossier_search_noresults(self): def test_dossier_search_noresults(self):
# session setup # session setup
self.client.get('/votes/dossier/') self.client.get('/votes/dossier/')
# 1 query for chamber list (search form)
# 1 query for dossier count # 1 query for dossier count
# nothing else since count = 0 # nothing else since count = 0
q = 'no-dossier-will-have-that-title-ever' q = 'no-dossier-will-have-that-title-ever'
self.responsediff_test('/votes/dossier/?search=%s' % q, 1) self.responsediff_test('/votes/dossier/?search=%s' % q, 2)
def test_dossier_detail(self): def test_dossier_detail(self):
# Get 1st dossier in dataset # Get 1st dossier in dataset
...@@ -50,4 +57,6 @@ class DossiersTest(ResponseDiffMixin, TestCase): ...@@ -50,4 +57,6 @@ class DossiersTest(ResponseDiffMixin, TestCase):
# 1 query for the dossier # 1 query for the dossier
# 1 query for proposals # 1 query for proposals
# 1 query for recommendations # 1 query for recommendations
self.responsediff_test('/votes/dossier/%s/' % dossier.pk, 3) # 1 query for documents
# 1 query for document chambers
self.responsediff_test('/votes/dossier/%s/' % dossier.pk, 5)
...@@ -9,5 +9,7 @@ class DossierDetail(generic.DetailView): ...@@ -9,5 +9,7 @@ class DossierDetail(generic.DetailView):
queryset = Dossier.objects.prefetch_related( queryset = Dossier.objects.prefetch_related(
'proposals', 'proposals',
'proposals__recommendation' 'proposals__recommendation',
'documents',
'documents__chamber',
) )
...@@ -15,7 +15,9 @@ class DossierList(PaginationMixin, generic.ListView): ...@@ -15,7 +15,9 @@ class DossierList(PaginationMixin, generic.ListView):
current_filter = None current_filter = None
queryset = Dossier.objects.prefetch_related( queryset = Dossier.objects.prefetch_related(
'proposals', 'proposals',
'proposals__recommendation' 'proposals__recommendation',
'documents',
'documents__chamber'
).annotate( ).annotate(
nb_proposals=Count('proposals'), nb_proposals=Count('proposals'),
nb_recomm=Count('proposals__recommendation') nb_recomm=Count('proposals__recommendation')
......
...@@ -16,8 +16,8 @@ setup(name='political-memory', ...@@ -16,8 +16,8 @@ setup(name='political-memory',
'django-datetime-widget>=0.9,<1.0', 'django-datetime-widget>=0.9,<1.0',
'django-filter>=0.13,<0.14', 'django-filter>=0.13,<0.14',
'django-libsass>=0.7,<0.8', 'django-libsass>=0.7,<0.8',
'django-representatives-votes==0.0.20', 'django-representatives-votes==0.0.22',
'django-representatives==0.0.27', 'django-representatives==0.0.29',
'django-taggit>=0.17,<0.18', 'django-taggit>=0.17,<0.18',
'django>=1.8,<1.9', 'django>=1.8,<1.9',
'djangorestframework>=3,<4', 'djangorestframework>=3,<4',
......
...@@ -9,6 +9,32 @@ ...@@ -9,6 +9,32 @@
%p %p
<strong>{{ dossier.reference }}</strong> <strong>{{ dossier.reference }}</strong>
%h2
- trans "Documents"
%table.table
%tr
%th
- trans "Chamber"
%th
- trans "Document type"
%th
- trans "Title"
- for document in dossier.documents.all
%tr
%td
= document.chamber | chamber_icon
%td
%a.external{'href': '{{ document.link }}', target:'_blank'}
- if document.kind == 'procedure-file'
- trans "Procedure file"
- else
= document.kind
%td
%a.external{'href': '{{ document.link }}', target:'_blank'}
= document.title
%h2 %h2
- trans "Recommendations" - trans "Recommendations"
......
- extends "base.html" - extends "base.html"
- load i18n - load i18n
- load memopol_tags