views.py 10.8 KB
Newer Older
Sli's avatar
Sli committed
1
from django.shortcuts import redirect, get_object_or_404
Sli's avatar
Sli committed
2 3 4 5
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 _
6
from django.forms.models import modelform_factory
7
from django.core.exceptions import PermissionDenied, ObjectDoesNotExist, ImproperlyConfigured
8
from django.forms import CheckboxSelectMultiple
Sli's avatar
Sli committed
9
from django.utils import timezone
Sli's avatar
Sli committed
10
from django.conf import settings
11
from django import forms
Sli's avatar
Sli committed
12 13

from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin, CanCreateMixin
Sli's avatar
Sli committed
14
from django.db.models.query import QuerySet
15
from django.views.generic.edit import FormMixin
16
from core.views.forms import SelectDateTime
Sli's avatar
Sli committed
17
from election.models import Election, Role, Candidature, ElectionList, Vote
Sli's avatar
Sli committed
18

19 20
from ajax_select.fields import AutoCompleteSelectField

21

Sli's avatar
Sli committed
22 23 24 25 26 27 28 29 30 31
# 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
Sli's avatar
Sli committed
32
        widget = forms.CheckboxSelectMultiple()
Sli's avatar
Sli committed
33 34 35 36 37 38
        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)
Sli's avatar
Sli committed
39
        return qs
Sli's avatar
Sli committed
40 41 42

    def validate(self, qs):
        if qs.count() > self.max_choice:
43
            raise forms.ValidationError(_("You have selected too much candidates."), code='invalid')
Sli's avatar
Sli committed
44 45


46 47 48 49
# Forms


class CandidateForm(forms.Form):
50 51 52 53 54 55 56 57
    """ 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))
58

59 60

class VoteForm(forms.Form):
Sli's avatar
Sli committed
61
    def __init__(self, election, user, *args, **kwargs):
62
        super(VoteForm, self).__init__(*args, **kwargs)
Sli's avatar
Sli committed
63
        for role in election.role.all():
Sli's avatar
Sli committed
64
            if not role.user_has_voted(user):
Sli's avatar
Sli committed
65 66 67 68 69
                cand = role.candidature
                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,
Sli's avatar
Sli committed
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
                                                                     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')
Sli's avatar
Sli committed
85

86

Sli's avatar
Sli committed
87 88 89 90 91 92 93 94 95
# Display elections


class ElectionsListView(CanViewMixin, ListView):
    """
    A list with all responsabilities and their candidates
    """
    model = Election
    template_name = 'election/election_list.jinja'
Sli's avatar
Sli committed
96

Sli's avatar
Sli committed
97 98 99 100 101 102
    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

Sli's avatar
Sli committed
103 104 105 106 107 108 109 110 111

class ElectionDetailView(CanViewMixin, DetailView):
    """
    Details an election responsability by responsability
    """
    model = Election
    template_name = 'election/election_detail.jinja'
    pk_url_kwarg = "election_id"

112 113 114 115
    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)
Sli's avatar
Sli committed
116
        kwargs['election_form'] = VoteForm(self.get_object(), self.request.user)
117
        kwargs['election_results'] = self.get_object().results
118 119
        return kwargs

Sli's avatar
Sli committed
120 121 122 123 124 125 126 127

# Form view

class CandidatureCreateView(CanCreateMixin, FormView):
    """
    View dedicated to a cundidature creation
    """
    form_class = CandidateForm
Sli's avatar
Sli committed
128
    template_name = 'election/election_detail.jinja'
Sli's avatar
Sli committed
129 130 131

    def dispatch(self, request, *arg, **kwargs):
        self.election_id = kwargs['election_id']
Sli's avatar
Sli committed
132
        self.election = get_object_or_404(Election, pk=self.election_id)
Sli's avatar
Sli committed
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
        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)
156 157 158
        if(data['election'].can_candidate(data['user'])):
            self.create_candidature(data)
            return res
Sli's avatar
Sli committed
159 160
        return res

Sli's avatar
Sli committed
161 162 163 164 165 166 167 168 169
    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

Sli's avatar
Sli committed
170 171 172 173
    def get_success_url(self, **kwargs):
        return reverse_lazy('election:detail', kwargs={'election_id': self.election_id})


174 175 176 177 178
class VoteFormView(CanCreateMixin, FormView):
    """
    Alows users to vote
    """
    form_class = VoteForm
Sli's avatar
Sli committed
179
    template_name = 'election/election_detail.jinja'
180 181

    def dispatch(self, request, *arg, **kwargs):
Sli's avatar
Sli committed
182
        self.election = get_object_or_404(Election, pk=kwargs['election_id'])
183 184 185
        return super(VoteFormView, self).dispatch(request, *arg, **kwargs)

    def vote(self, data):
Sli's avatar
Sli committed
186 187 188 189 190 191 192 193 194 195 196 197
        for key in data.keys():
            if isinstance(data[key], QuerySet):
                if data[key].count() > 0:
                    vote = Vote(role=data[key].first().role)
                    vote.save()
                for el in data[key]:
                    vote.candidature.add(el)
            elif data[key] is not None:
                vote = Vote(role=data[key].role)
                vote.save()
                vote.candidature.add(data[key])
            self.election.role.get(title=key).has_voted.add(self.request.user)
198 199 200

    def get_form_kwargs(self):
        kwargs = super(VoteFormView, self).get_form_kwargs()
Sli's avatar
Sli committed
201 202
        kwargs['election'] = self.election
        kwargs['user'] = self.request.user
203 204 205 206 207 208 209 210
        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)
Sli's avatar
Sli committed
211
        for grp in self.election.vote_groups.all():
212 213 214 215 216 217
            if self.request.user.is_in_group(grp):
                self.vote(data)
                return res
        return res

    def get_success_url(self, **kwargs):
Sli's avatar
Sli committed
218 219 220 221 222 223 224 225 226 227 228
        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

229

230
# Create views
231

Sli's avatar
Sli committed
232

233
class ElectionCreateView(CanCreateMixin, CreateView):
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252
    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})
253 254


Sli's avatar
Sli committed
255 256
class RoleCreateView(CanCreateMixin, CreateView):
    model = Role
Sli's avatar
Sli committed
257
    form_class = RoleForm
Sli's avatar
Sli committed
258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275
    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})


276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298
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})