diff --git a/core/management/commands/populate.py b/core/management/commands/populate.py index e69205c0..38ecfe10 100644 --- a/core/management/commands/populate.py +++ b/core/management/commands/populate.py @@ -370,8 +370,8 @@ Cette page vise à documenter la syntaxe *Markdown* utilisée sur le site. el.save() el.view_groups.add(public_group) el.edit_groups.add(ae_board_gorup) - el.candidature_group.add(subscriber_group) - el.vote_group.add(subscriber_group) + el.candidature_groups.add(subscriber_group) + el.vote_groups.add(subscriber_group) el.save() liste = ElectionList(title="Candidature Libre", election=el) liste.save() diff --git a/core/widgets.py b/core/widgets.py new file mode 100644 index 00000000..e1d6cd47 --- /dev/null +++ b/core/widgets.py @@ -0,0 +1,94 @@ +from django import forms +from django.utils.safestring import mark_safe + +class ChoiceWithOtherRenderer(forms.RadioSelect.renderer): + """RadioFieldRenderer that renders its last choice with a placeholder.""" + def __init__(self, *args, **kwargs): + super(ChoiceWithOtherRenderer, self).__init__(*args, **kwargs) + self.choices, self.other = self.choices[:-1], self.choices[-1] + + def __iter__(self): + for input in super(ChoiceWithOtherRenderer, self).__iter__(): + yield input + id = '%s_%s' % (self.attrs['id'], self.other[0]) if 'id' in self.attrs else '' + label_for = ' for="%s"' % id if id else '' + checked = '' if not self.other[0] == self.value else 'checked="true" ' + yield ' %s %%s' % ( + label_for, id, self.other[0], self.name, checked, self.other[1]) + +class ChoiceWithOtherWidget(forms.MultiWidget): + """MultiWidget for use with ChoiceWithOtherField.""" + def __init__(self, choices): + widgets = [ + forms.RadioSelect(choices=choices, renderer=ChoiceWithOtherRenderer), + forms.TextInput + ] + super(ChoiceWithOtherWidget, self).__init__(widgets) + + def decompress(self, value): + if not value: + return [None, None] + return value + + def format_output(self, rendered_widgets): + """Format the output by substituting the "other" choice into the first widget.""" + return rendered_widgets[0] % rendered_widgets[1] + +class ChoiceWithOtherField(forms.MultiValueField): + """ + ChoiceField with an option for a user-submitted "other" value. + + The last item in the choices array passed to __init__ is expected to be a choice for "other". This field's + cleaned data is a tuple consisting of the choice the user made, and the "other" field typed in if the choice + made was the last one. + + >>> class AgeForm(forms.Form): + ... age = ChoiceWithOtherField(choices=[ + ... (0, '15-29'), + ... (1, '30-44'), + ... (2, '45-60'), + ... (3, 'Other, please specify:') + ... ]) + ... + >>> # rendered as a RadioSelect choice field whose last choice has a text input + ... print AgeForm()['age'] + + >>> form = AgeForm({'age_0': 2}) + >>> form.is_valid() + True + >>> form.cleaned_data + {'age': (u'2', u'')} + >>> form = AgeForm({'age_0': 3, 'age_1': 'I am 10 years old'}) + >>> form.is_valid() + True + >>> form.cleaned_data + {'age': (u'3', u'I am 10 years old')} + >>> form = AgeForm({'age_0': 1, 'age_1': 'This is bogus text which is ignored since I didn\\'t pick "other"'}) + >>> form.is_valid() + True + >>> form.cleaned_data + {'age': (u'1', u'')} + """ + def __init__(self, *args, **kwargs): + fields = [ + forms.ChoiceField(widget=forms.RadioSelect(renderer=ChoiceWithOtherRenderer), *args, **kwargs), + forms.CharField(required=False) + ] + widget = ChoiceWithOtherWidget(choices=kwargs['choices']) + kwargs.pop('choices') + self._was_required = kwargs.pop('required', True) + kwargs['required'] = False + super(ChoiceWithOtherField, self).__init__(widget=widget, fields=fields, *args, **kwargs) + + def compress(self, value): + if self._was_required and not value or value[0] in (None, ''): + raise forms.ValidationError(self.error_messages['required']) + if not value: + return [None, u''] + return (value[0], value[1] if value[0] == self.fields[0].choices[-1][0] else u'') \ No newline at end of file diff --git a/election/migrations/0004_auto_20161219_2302.py b/election/migrations/0004_auto_20161219_2302.py new file mode 100644 index 00000000..fabe3212 --- /dev/null +++ b/election/migrations/0004_auto_20161219_2302.py @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0016_auto_20161212_1922'), + ('election', '0003_auto_20161219_1832'), + ] + + operations = [ + migrations.RemoveField( + model_name='election', + name='candidature_group', + ), + migrations.RemoveField( + model_name='election', + name='vote_group', + ), + migrations.AddField( + model_name='election', + name='candidature_groups', + field=models.ManyToManyField(to='core.Group', verbose_name='candidature group', related_name='candidate_elections', blank=True), + ), + migrations.AddField( + model_name='election', + name='vote_groups', + field=models.ManyToManyField(to='core.Group', verbose_name='vote group', related_name='votable_elections', blank=True), + ), + migrations.AlterField( + model_name='election', + name='edit_groups', + field=models.ManyToManyField(to='core.Group', verbose_name='edit group', related_name='editable_elections', blank=True), + ), + migrations.AlterField( + model_name='election', + name='view_groups', + field=models.ManyToManyField(to='core.Group', verbose_name='view group', related_name='viewable_elections', blank=True), + ), + ] diff --git a/election/models.py b/election/models.py index 7598e2a1..f4b63b39 100644 --- a/election/models.py +++ b/election/models.py @@ -18,10 +18,10 @@ class Election(models.Model): start_date = models.DateTimeField(_('start date'), blank=False) end_date = models.DateTimeField(_('end date'), blank=False) - edit_groups = models.ManyToManyField(Group, related_name="editable_election", verbose_name=_("edit group"), blank=True) - view_groups = models.ManyToManyField(Group, related_name="viewable_election", verbose_name=_("view group"), blank=True) - vote_group = models.ManyToManyField(Group, related_name="votable_election", verbose_name=_("vote group"), blank=True) - candidature_group = models.ManyToManyField(Group, related_name="candidate_election", verbose_name=_("candidature group"), blank=True) + edit_groups = models.ManyToManyField(Group, related_name="editable_elections", verbose_name=_("edit group"), blank=True) + view_groups = models.ManyToManyField(Group, related_name="viewable_elections", verbose_name=_("view group"), blank=True) + vote_groups = models.ManyToManyField(Group, related_name="votable_elections", verbose_name=_("vote group"), blank=True) + candidature_groups = models.ManyToManyField(Group, related_name="candidate_elections", verbose_name=_("candidature group"), blank=True) def __str__(self): return self.title diff --git a/election/templates/election/election_detail.jinja b/election/templates/election/election_detail.jinja index d48866eb..89ab2042 100644 --- a/election/templates/election/election_detail.jinja +++ b/election/templates/election/election_detail.jinja @@ -11,14 +11,21 @@

{{object.title}}

{{object.description}}

{% trans %}End :{% endtrans %} {{object.end_date}}

+ {% if object.election_list.exists() %} {% set nb_list = object.election_list.all().count() + 1 -%} {% for liste in object.election_list.all() %} + {% if object.is_candidature_active -%} + {% set nb_list = nb_list -%} + {% else -%} {% set nb_list = nb_list + 1 -%} + {% endif -%} {% endfor %} + {% if not object.is_candidature_active -%} + {% endif %} {% for role in object.role.all() %} @@ -40,8 +47,14 @@ {% endfor %} + {% if not object.is_candidature_active -%} + {% endif %} {% endfor %}
{{liste.title}}{% trans %}Blank vote{% endtrans %}
{{role.title}}
+ {% endif %} + {% if object.is_candidature_active -%} + candidature + {% endif -%} {% endblock %} \ No newline at end of file diff --git a/election/urls.py b/election/urls.py index 2e39e877..ba36777b 100644 --- a/election/urls.py +++ b/election/urls.py @@ -4,5 +4,6 @@ from election.views import * urlpatterns = [ url(r'^$', ElectionsListView.as_view(), name='list'), + url(r'^create$', PageCreateView.as_view(), name='create'), url(r'^(?P[0-9]+)/detail$', ElectionDetailView.as_view(), name='detail'), ] diff --git a/election/views.py b/election/views.py index 3ab2d51d..4dd06371 100644 --- a/election/views.py +++ b/election/views.py @@ -3,12 +3,25 @@ from django.views.generic import ListView, DetailView, RedirectView from django.views.generic.edit import UpdateView, CreateView, DeleteView, FormView from django.core.urlresolvers import reverse_lazy, reverse from django.utils.translation import ugettext_lazy as _ +from django.forms.models import modelform_factory +from django.forms import CheckboxSelectMultiple from django.utils import timezone from django.conf import settings +from django import forms from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin, CanCreateMixin +from core.views.forms import SelectDateTime +from core.widgets import ChoiceWithOtherField from election.models import Election, Role, Candidature +from ajax_select.fields import AutoCompleteSelectField + +# Forms + + +class CandidateForm(forms.Form): + user = AutoCompleteSelectField('users', label=_('Refound this account'), help_text=None, required=True) + # Display elections @@ -34,4 +47,24 @@ class ElectionDetailView(CanViewMixin, DetailView): template_name = 'election/election_detail.jinja' pk_url_kwarg = "election_id" -# Forms + +class PageCreateView(CanCreateMixin, CreateView): + model = Election + form_class = modelform_factory(Election, + fields=['title', 'description', 'start_candidature', 'end_candidature', 'start_date', 'end_date', + 'edit_groups', 'view_groups', 'vote_groups', 'candidature_groups'], + widgets={ + 'edit_groups': CheckboxSelectMultiple, + 'view_groups': CheckboxSelectMultiple, + 'edit_groups': CheckboxSelectMultiple, + 'vote_groups': CheckboxSelectMultiple, + 'candidature_groups': CheckboxSelectMultiple, + 'start_date': SelectDateTime, + 'end_date': SelectDateTime, + 'start_candidature': SelectDateTime, + 'end_candidature': SelectDateTime, + }) + template_name = 'core/page_prop.jinja' + + def get_success_url(self, **kwargs): + return reverse_lazy('election:detail', kwargs={'election_id': self.object.id})