Commit 0731c495 authored by Nicolas Joyard's avatar Nicolas Joyard
Browse files

Add working position form

parent f6d6bd9a
......@@ -213,7 +213,7 @@ TEMPLATE_LOADERS = (
TEMPLATE_CONTEXT_PROCESSORS = global_settings.TEMPLATE_CONTEXT_PROCESSORS + (
'django.template.context_processors.request',
'memopol.context_processors.search_form_options'
'memopol.context_processors.search_form_options',
)
# Static files finders
......
......@@ -7,13 +7,17 @@ class BaseTest(ResponseDiffTestMixin, test.TestCase):
"""
Common queries
- 1 for chambers
- 1 for countries
- 1 for parties
- 1 for committees
- 1 for delegations
- 5 for search forms
- 1 for chambers
- 1 for countries
- 1 for parties
- 1 for committees
- 1 for delegations
- 2 for the position form
- 1 for representatives
- 1 for themes
"""
left_pane_queries = 5
left_pane_queries = 7
def request_test(self, url=None):
self.assertResponseDiffEmpty(self.client.get(url or self.url))
......
<form action="" method="post">
<div class="modal-header">
<button aria-label="Close" class="close" data-dismiss="modal" type="button"><span aria-hidden="true">×</span></button>
<h4 class="modal-title">Add a representative public position</h4>
</div>
<div class="modal-body">
<input name="csrfmiddlewaretoken" type="hidden" value="csrftoken"/>
<div class="row">
<div class="col-sm-12">
<div class="well well-sm text-justify">
<p>
Use this form to submit a public position taken by a representative and
related to one of the themes followed on this instance of Political Memory.
Public positions may include blog or social network posts, interviews,
parliament interventions...
</p>
<p>
Be sure to include a relevant excerpt from the public position as well as
a valid link that refers to it. Note that positions will be reviewed by
the staff before publication.
</p>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-6">
<div class="form-group"><label class="col-md-3 control-label" for="id_position-representative">Representative</label><div class="col-md-9"><select class="form-control" id="id_position-representative" name="position-representative" required="required" title="">
<option selected="selected" value="">---------</option>
<option value="4902">François Asensi</option>
<option value="4893">Thierry Benoit</option>
<option value="4898">Marcel Bonnot</option>
<option value="4891">Jean-Claude Bouchet</option>
<option value="22">Paul BRANNEN</option>
<option value="12">Udo BULLMANN</option>
<option value="4914">Jean-Paul Chanteguet</option>
<option value="4912">Jean-Louis Christ</option>
<option value="4900">Jean-Michel Couve</option>
<option value="21">Esther de LANGE</option>
<option value="9">Albert DESS</option>
<option value="4896">Marc Dolez</option>
<option value="4889">Dominique Dord</option>
<option value="4899">Olivier Dussopt</option>
<option value="4890">Daniel Fasquelle</option>
<option value="24">María Teresa GIMÉNEZ BARBAT</option>
<option value="4894">Claude Goasguen</option>
<option value="4885">Pascale Got</option>
<option value="13">Bolesław G. PIECHA</option>
<option value="20">Iveta GRIGULE</option>
<option value="1">Czesław HOC</option>
<option value="4910">Philippe Houillon</option>
<option value="7">Sylvia-Yvonne KAUFMANN</option>
<option value="18">Jan KELLER</option>
<option value="3">Dietmar KÖSTER</option>
<option value="29">Werner LANGEN</option>
<option value="23">Jo LEINEN</option>
<option value="4903">Pierre Lellouche</option>
<option value="4886">Annick Lepetit</option>
<option value="4895">Pierre Lequiller</option>
<option value="8">Arne LIETZ</option>
<option value="19">Verónica LOPE FONTAGNÉ</option>
<option value="4908">Jacqueline Maquet</option>
<option value="4907">Philippe Martin</option>
<option value="25">Gesine MEISSNER</option>
<option value="4904">Hervé Morin</option>
<option value="4913">Alain Moyne-Bressand</option>
<option value="16">Angelika NIEBLER</option>
<option value="14">Paul NUTTALL</option>
<option value="5">Patrick O'FLYNN</option>
<option value="4905">Martine Pinville</option>
<option value="15">Mirosław PIOTROWSKI</option>
<option value="4906">François Pupponi</option>
<option value="4911">Jean-Luc Reitzer</option>
<option value="4909">Franck Reynier</option>
<option value="4888">Marcel Rogemont</option>
<option value="4901">André Santini</option>
<option value="10">Annie SCHREIJER-PIERIK</option>
<option value="28">Joachim SCHUSTER</option>
<option value="26">Helga STEVENS</option>
<option value="17">László TŐKÉS</option>
<option value="4887">Jean-Jacques Urvoas</option>
<option value="4892">Alain Vidalies</option>
<option value="4897">Philippe Vigier</option>
<option value="6">Axel VOSS</option>
<option value="2">Renate WEBER</option>
<option value="11">Kerstin WESTPHAL</option>
<option value="4">Hermann WINKLER</option>
<option value="27">Damiano ZOFFOLI</option>
</select></div></div>
<div class="form-group"><label class="col-md-3 control-label" for="id_position-datetime">Datetime</label><div class="col-md-9">
<div class="input-group date" id="id_position-datetime">
<input class="form-control" id="id_position-datetime" name="position-datetime" placeholder="Datetime" readonly="" required="required" title="" type="text"/>
<span class="input-group-addon"><span class="glyphicon glyphicon-remove"></span></span>
<span class="input-group-addon"><span class="glyphicon glyphicon-calendar"></span></span>
</div>
<script type="text/javascript">
$("#id_position-datetime").datetimepicker({minView: 2,
autoclose: true,
language: 'en',
startView: 2,
format: 'yyyy-mm-dd'}).find('input').addClass("form-control");
</script>
</div></div>
<div class="form-group"><label class="col-md-3 control-label" for="id_position-link">Link</label><div class="col-md-9"><input class="form-control" id="id_position-link" maxlength="500" name="position-link" placeholder="Link" required="required" title="" type="url"/></div></div>
</div>
<div class="col-sm-6">
<div class="form-group"><label class="col-md-3 control-label" for="id_position-themes_0">Themes</label><div class="col-md-9"><div id="id_position-themes"><div class="checkbox"><label for="id_position-themes_0"><input class="" id="id_position-themes_0" name="position-themes" title="" type="checkbox" value="1"/> Etat d'urgence</label></div>
<div class="checkbox"><label for="id_position-themes_1"><input class="" id="id_position-themes_1" name="position-themes" title="" type="checkbox" value="2"/> ACTA</label></div></div></div></div>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<div class="col-sm-12">
<div class="form-group"><label class="control-label" for="id_position-text">Text</label><textarea class="form-control" cols="40" id="id_position-text" name="position-text" placeholder="Text" required="required" rows="10" title=""></textarea></div>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-default" data-dismiss="modal" type="button">Close</button>
<button class="btn btn-primary" type="submit">Submit public position</button>
</div>
</form>
\ No newline at end of file
<option selected="selected" value="4899">Olivier Dussopt</option>
\ No newline at end of file
<input checked="checked" class="" id="id_position-themes_0" name="position-themes" title="" type="checkbox" value="1"/>
\ No newline at end of file
from .base import BaseTest, RepresentativeBaseTest, ThemeBaseTest
class PositionFormTest(BaseTest):
url = '/'
def test_position_form(self):
self.client.cookies['csrftoken'] = 'csrftoken'
self.selector_test('#add-position-form form')
def test_select_representative(self):
self.selector_test(
'#add-position-form #id_position-representative option[selected]',
RepresentativeBaseTest.base_url % 'none'
)
def test_select_theme(self):
self.selector_test(
'#add-position-form #id_position-themes input[checked]',
ThemeBaseTest.base_url % 'none'
)
# coding: utf-8
from django.conf.urls import include, url
from django.contrib import admin
from django.views import generic
from views.home import HomeView
from views.dossier_ac import DossierAutocomplete, ProposalAutocomplete
from views.dossier_detail_base import DossierDetailBase
......@@ -184,8 +185,6 @@ urlpatterns = [
),
url(r'^admin/', include(admin.site.urls)),
url(r'^positions/', include('representatives_positions.urls',
namespace='representatives_positions')),
url(r'^api/', include(api.router.urls)),
url(r'^$', generic.TemplateView.as_view(template_name='home.html')),
url(r'^$', HomeView.as_view()),
]
......@@ -4,8 +4,10 @@ from django.views import generic
from representatives_votes.models import Dossier
from representatives_positions.views import PositionFormMixin
class DossierDetailBase(generic.DetailView):
class DossierDetailBase(PositionFormMixin, generic.DetailView):
template_name = 'representatives_votes/dossier_detail.html'
queryset = Dossier.objects.prefetch_related('themes')
......@@ -9,8 +9,11 @@ from representatives_votes.models import Dossier
from ..filters import DossierFilter
from representatives_positions.views import PositionFormMixin
class DossierList(PaginationMixin, SortMixin, generic.ListView):
class DossierList(PaginationMixin, SortMixin, PositionFormMixin,
generic.ListView):
current_filter = None
queryset = Dossier.objects.prefetch_related(
......
# coding: utf-8
from django.views import generic
from representatives_positions.views import PositionFormMixin
class HomeView(PositionFormMixin, generic.TemplateView):
template_name = 'home.html'
......@@ -8,8 +8,11 @@ from representatives.models import Chamber, Representative, Address, Phone, \
from .representative_mixin import RepresentativeViewMixin
from representatives_positions.views import PositionFormMixin
class RepresentativeDetailBase(RepresentativeViewMixin, generic.DetailView):
class RepresentativeDetailBase(RepresentativeViewMixin, PositionFormMixin,
generic.DetailView):
queryset = Representative.objects.select_related('score')
......@@ -56,5 +59,6 @@ class RepresentativeDetailBase(RepresentativeViewMixin, generic.DetailView):
c = super(RepresentativeDetailBase, self).get_context_data(**kwargs)
self.add_representative_country_and_main_mandate(c['object'])
c['position_form'].fields['representative'].initial = c['object'].pk
return c
......@@ -10,10 +10,12 @@ from representatives.models import Representative
from ..filters import RepresentativeFilter
from .representative_mixin import RepresentativeViewMixin
from representatives_positions.views import PositionFormMixin
class RepresentativeList(CSVDownloadMixin, GridListMixin, PaginationMixin,
RepresentativeViewMixin, ActiveLegislatureMixin,
SortMixin, generic.ListView):
SortMixin, PositionFormMixin, generic.ListView):
csv_name = 'representatives'
queryset = Representative.objects.select_related('score')
......
......@@ -4,8 +4,16 @@ from django.views import generic
from memopol_themes.models import Theme
from representatives_positions.views import PositionFormMixin
class ThemeDetailBase(generic.DetailView):
class ThemeDetailBase(PositionFormMixin, generic.DetailView):
template_name = 'memopol_themes/theme_detail.html'
queryset = Theme.objects.all()
def get_context_data(self, **kwargs):
c = super(ThemeDetailBase, self).get_context_data(**kwargs)
c['position_form'].fields['themes'].initial = [c['object']]
return c
......@@ -9,8 +9,11 @@ from memopol_themes.models import Theme
from ..filters import ThemeFilter
from representatives_positions.views import PositionFormMixin
class ThemeList(PaginationMixin, SortMixin, generic.ListView):
class ThemeList(PaginationMixin, SortMixin, PositionFormMixin,
generic.ListView):
current_filter = None
queryset = Theme.objects.all().annotate(
......
......@@ -2,21 +2,36 @@ from django import forms
from datetimewidget.widgets import DateWidget
from memopol_themes.models import Theme
from .models import Position
class PositionForm(forms.ModelForm):
themes = forms.models.ModelMultipleChoiceField(
queryset=Theme.objects.all(),
required=False,
widget=forms.CheckboxSelectMultiple
)
class Meta:
model = Position
fields = ['datetime', 'text', 'link', 'representative']
fields = ['representative', 'link', 'datetime', 'themes', 'text']
widgets = {
# Use localization and bootstrap 3
'datetime': DateWidget(
attrs={
'id': 'yourdatetimeid'
},
usel10n=True,
bootstrap_version=3,
),
'representative': forms.HiddenInput
bootstrap_version=3
)
}
def save(self, commit=True):
position = super(PositionForm, self).save(commit=False)
if commit:
position.save()
if position.pk:
position.themes = self.cleaned_data.get('themes')
self.save_m2m()
return position
from django.db import models
from django.core.urlresolvers import reverse
from django.template.defaultfilters import truncatewords
from representatives.models import Representative
......@@ -21,7 +20,3 @@ class Position(models.Model):
def unpublish(self):
self.published = False
def get_absolute_url(self):
return reverse('representatives_positions:position-detail',
args=(self.pk,))
from django.conf.urls import url
import views
urlpatterns = [
url(
r'^position/create/$',
views.PositionCreate.as_view(),
name='position-create'
),
url(
r'^position/(?P<pk>\d+)/$',
views.PositionDetail.as_view(),
name='position-detail'
),
]
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment