Sith/election/views.py
2016-12-25 19:54:10 +01:00

301 lines
11 KiB
Python

from django.shortcuts import redirect, get_object_or_404
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.core.exceptions import PermissionDenied, ObjectDoesNotExist, ImproperlyConfigured
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 django.db.models.query import QuerySet
from django.views.generic.edit import FormMixin
from core.views.forms import SelectDateTime
from election.models import Election, Role, Candidature, ElectionList, Vote
from ajax_select.fields import AutoCompleteSelectField
# Custom form field
class VoteCheckbox(forms.ModelMultipleChoiceField):
"""
Used to replace ModelMultipleChoiceField but with
automatic backend verification
"""
def __init__(self, queryset, max_choice, required=True, widget=None, label=None,
initial=None, help_text='', *args, **kwargs):
self.max_choice = max_choice
widget = forms.CheckboxSelectMultiple()
super(VoteCheckbox, self).__init__(queryset, None, required, widget, label,
initial, help_text, *args, **kwargs)
def clean(self, value):
qs = super(VoteCheckbox, self).clean(value)
self.validate(qs)
return qs
def validate(self, qs):
if qs.count() > self.max_choice:
raise forms.ValidationError(_("You have selected too much candidates."), code='invalid')
# Forms
class CandidateForm(forms.Form):
""" Form to candidate """
user = AutoCompleteSelectField('users', label=_('User to candidate'), help_text=None, required=True)
program = forms.CharField(widget=forms.Textarea)
def __init__(self, election_id, *args, **kwargs):
super(CandidateForm, self).__init__(*args, **kwargs)
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, election, user, *args, **kwargs):
super(VoteForm, self).__init__(*args, **kwargs)
for role in election.roles.all():
if not role.user_has_voted(user):
cand = role.candidatures
if role.max_choice > 1:
self.fields[role.title] = VoteCheckbox(cand, role.max_choice, required=False)
else:
self.fields[role.title] = forms.ModelChoiceField(cand, required=False,
widget=forms.RadioSelect(), empty_label=_("Blank vote"))
class RoleForm(forms.ModelForm):
""" Form for creating a role """
class Meta:
model = Role
fields = ['title', 'election', 'description', 'max_choice']
def clean(self):
cleaned_data = super(RoleForm, self).clean()
title = cleaned_data.get('title')
election = cleaned_data.get('election')
if Role.objects.filter(title=title, election=election).exists():
raise forms.ValidationError(_("This role already exists for this election"), code='invalid')
# Display elections
class ElectionsListView(CanViewMixin, ListView):
"""
A list with all responsabilities and their candidates
"""
model = Election
template_name = 'election/election_list.jinja'
def get_queryset(self):
qs = super(ElectionsListView, self).get_queryset()
today = timezone.now()
qs = qs.filter(end_date__gte=today, start_date__lte=today)
return qs
class ElectionDetailView(CanViewMixin, DetailView):
"""
Details an election responsability by responsability
"""
model = Election
template_name = 'election/election_detail.jinja'
pk_url_kwarg = "election_id"
def get_context_data(self, **kwargs):
""" Add additionnal data to the template """
kwargs = super(ElectionDetailView, self).get_context_data(**kwargs)
kwargs['candidate_form'] = CandidateForm(self.get_object().id)
kwargs['election_form'] = VoteForm(self.get_object(), self.request.user)
kwargs['election_results'] = self.get_object().results
return kwargs
# Form view
class CandidatureCreateView(CanCreateMixin, FormView):
"""
View dedicated to a cundidature creation
"""
form_class = CandidateForm
template_name = 'election/election_detail.jinja'
def dispatch(self, request, *arg, **kwargs):
self.election_id = kwargs['election_id']
self.election = get_object_or_404(Election, pk=self.election_id)
return super(CandidatureCreateView, self).dispatch(request, *arg, **kwargs)
def get_form_kwargs(self):
kwargs = super(CandidatureCreateView, self).get_form_kwargs()
kwargs['election_id'] = self.election_id
return kwargs
def create_candidature(self, data):
cand = Candidature(
role=data['role'],
user=data['user'],
election_list=data['election_list'],
program=data['program']
)
cand.save()
def form_valid(self, form):
"""
Verify that the selected user is in candidate group
"""
data = form.clean()
res = super(FormView, self).form_valid(form)
data['election'] = Election.objects.get(id=self.election_id)
if(data['election'].can_candidate(data['user'])):
self.create_candidature(data)
return res
return res
def get_context_data(self, **kwargs):
""" Add additionnal data to the template """
kwargs = super(CandidatureCreateView, self).get_context_data(**kwargs)
kwargs['candidate_form'] = self.get_form()
kwargs['object'] = self.election
kwargs['election'] = self.election
kwargs['election_form'] = VoteForm(self.election, self.request.user)
return kwargs
def get_success_url(self, **kwargs):
return reverse_lazy('election:detail', kwargs={'election_id': self.election_id})
class VoteFormView(CanCreateMixin, FormView):
"""
Alows users to vote
"""
form_class = VoteForm
template_name = 'election/election_detail.jinja'
def dispatch(self, request, *arg, **kwargs):
self.election = get_object_or_404(Election, pk=kwargs['election_id'])
return super(VoteFormView, self).dispatch(request, *arg, **kwargs)
def vote(self, election_data):
for role_title in election_data.keys():
# If we have a multiple choice field
if isinstance(election_data[role_title], QuerySet):
if election_data[role_title].count() > 0:
vote = Vote(role=election_data[role_title].first().role)
vote.save()
for el in election_data[role_title]:
vote.candidature.add(el)
# If we have a single choice
elif election_data[role_title] is not None:
vote = Vote(role=election_data[role_title].role)
vote.save()
vote.candidature.add(election_data[role_title])
self.election.roles.get(title=role_title).has_voted.add(self.request.user)
def get_form_kwargs(self):
kwargs = super(VoteFormView, self).get_form_kwargs()
kwargs['election'] = self.election
kwargs['user'] = self.request.user
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)
for grp in self.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})
def get_context_data(self, **kwargs):
""" Add additionnal data to the template """
kwargs = super(VoteFormView, self).get_context_data(**kwargs)
kwargs['candidate_form'] = CandidateForm(self.election.id)
kwargs['object'] = self.election
kwargs['election'] = self.election
kwargs['election_form'] = self.get_form()
return kwargs
# Create views
class ElectionCreateView(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})
class RoleCreateView(CanCreateMixin, CreateView):
model = Role
form_class = RoleForm
template_name = 'core/page_prop.jinja'
def form_valid(self, form):
"""
Verify that the user can edit proprely
"""
obj = form.instance
res = super(CreateView, self).form_valid
if obj.election:
for grp in obj.election.edit_groups.all():
if self.request.user.is_in_group(grp):
return res(form)
raise PermissionDenied
def get_success_url(self, **kwargs):
return reverse_lazy('election:detail', kwargs={'election_id': self.object.election.id})
class ElectionListCreateView(CanCreateMixin, CreateView):
model = ElectionList
form_class = modelform_factory(ElectionList,
fields=['title', 'election'])
template_name = 'core/page_prop.jinja'
def form_valid(self, form):
"""
Verify that the user can vote on this election
"""
obj = form.instance
res = super(CreateView, self).form_valid
if obj.election:
for grp in obj.election.candidature_groups.all():
if self.request.user.is_in_group(grp):
return res(form)
for grp in obj.election.edit_groups.all():
if self.request.user.is_in_group(grp):
return res(form)
raise PermissionDenied
def get_success_url(self, **kwargs):
return reverse_lazy('election:detail', kwargs={'election_id': self.object.election.id})