diff --git a/core/widgets.py b/core/widgets.py deleted file mode 100644 index e1d6cd47..00000000 --- a/core/widgets.py +++ /dev/null @@ -1,94 +0,0 @@ -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/models.py b/election/models.py index 979c3beb..8e3fbc92 100644 --- a/election/models.py +++ b/election/models.py @@ -80,6 +80,9 @@ class Candidature(models.Model): program = models.TextField(_('description'), null=True, blank=True) election_list = models.ForeignKey(ElectionList, related_name='candidature', verbose_name=_('election_list')) + def __str__(self): + return "%s : %s" % (self.role.title, self.user.username) + class Vote(models.Model): """ diff --git a/election/urls.py b/election/urls.py index 380fa1db..59ad8a42 100644 --- a/election/urls.py +++ b/election/urls.py @@ -8,5 +8,6 @@ urlpatterns = [ url(r'^list/create$', ElectionListCreateView.as_view(), name='create_list'), url(r'^role/create$', RoleCreateView.as_view(), name='create_role'), url(r'^(?P[0-9]+)/candidate$', CandidatureCreateView.as_view(), name='candidate'), + url(r'^(?P[0-9]+)/vote$', VoteFormView.as_view(), name='vote'), url(r'^(?P[0-9]+)/detail$', ElectionDetailView.as_view(), name='detail'), ] diff --git a/election/views.py b/election/views.py index d253e58d..e11955a0 100644 --- a/election/views.py +++ b/election/views.py @@ -11,8 +11,8 @@ from django.conf import settings from django import forms from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin, CanCreateMixin +from django.views.generic.edit import FormMixin from core.views.forms import SelectDateTime -from core.widgets import ChoiceWithOtherField from election.models import Election, Role, Candidature, ElectionList from ajax_select.fields import AutoCompleteSelectField @@ -31,6 +31,25 @@ class CandidateForm(forms.Form): self.fields['role'] = forms.ModelChoiceField(Role.objects.filter(election__id=election_id)) self.fields['election_list'] = forms.ModelChoiceField(ElectionList.objects.filter(election__id=election_id)) + +class VoteForm(forms.Form): + def __init__(self, role_id, *args, **kwargs): + super(VoteForm, self).__init__(*args, **kwargs) + self.max_choice = Role.objects.get(id=role_id).max_choice + cand = Candidature.objects.filter(role__id=role_id) + if self.max_choice > 1: + self.fields['candidature'] = forms.ModelMultipleChoiceField(cand, required=False, + widget=forms.CheckboxSelectMultiple()) + else: + self.fields['candidature'] = forms.ModelChoiceField(cand, required=False, + widget=forms.RadioSelect(), empty_label=_("Blank vote")) + + def clean_candidature(self): + data = self.cleaned_data['candidature'] + if self.max_choice > 1 and len(data) > self.max_choice: + raise forms.ValidationError(_("You have selected too much candidate")) + return data + # Display elections @@ -110,6 +129,43 @@ class CandidatureCreateView(CanCreateMixin, FormView): return reverse_lazy('election:detail', kwargs={'election_id': self.election_id}) +class VoteFormView(CanCreateMixin, FormView): + """ + Alows users to vote + """ + form_class = VoteForm + template_name = 'core/page_prop.jinja' + + def dispatch(self, request, *arg, **kwargs): + self.election_id = kwargs['election_id'] + return super(VoteFormView, self).dispatch(request, *arg, **kwargs) + + def vote(self, data): + pass + + def get_form_kwargs(self): + kwargs = super(VoteFormView, self).get_form_kwargs() + kwargs['role_id'] = self.election_id + return kwargs + + def form_valid(self, form): + """ + Verify that the user is part in a vote group + """ + data = form.clean() + res = super(FormView, self).form_valid(form) + if self.request.user.is_root: + self.vote(data) + return res + for grp in data['role'].election.vote_groups.all(): + if self.request.user.is_in_group(grp): + self.vote(data) + return res + return res + + def get_success_url(self, **kwargs): + return reverse_lazy('election:detail', kwargs={'election_id': self.election_id}) + # Create views