views.py 11.9 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
# Custom form field

Sli's avatar
Sli committed
24
class LimitedCheckboxField(forms.ModelMultipleChoiceField):
Sli's avatar
Sli committed
25
26
27
28
29
30
31
    """
        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
        super(LimitedCheckboxField, self).__init__(queryset, None, required, widget, label,
Sli's avatar
Sli committed
34
                                                   initial, help_text, *args, **kwargs)
Sli's avatar
Sli committed
35
36

    def clean(self, value):
Sli's avatar
Sli committed
37
        qs = super(LimitedCheckboxField, self).clean(value)
Sli's avatar
Sli committed
38
        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
# Forms


Sli's avatar
Sli committed
49
class CandidateForm(forms.ModelForm):
50
    """ Form to candidate """
Sli's avatar
Sli committed
51
52
53
54
55
56
57
    class Meta:
        model = Candidature
        fields = ['user', 'role', 'program', 'election_list']
        widgets = {
            'program': forms.Textarea
        }

58
59
    user = AutoCompleteSelectField('users', label=_('User to candidate'), help_text=None, required=True)

Sli's avatar
Sli committed
60
61
62
    def __init__(self, *args, **kwargs):
        election_id = kwargs.pop('election_id', None)
        can_edit = kwargs.pop('can_edit', False)
63
        super(CandidateForm, self).__init__(*args, **kwargs)
Sli's avatar
Sli committed
64
65
66
67
68
        if election_id:
            self.fields['role'].queryset = Role.objects.filter(election__id=election_id).all()
            self.fields['election_list'].queryset = ElectionList.objects.filter(election__id=election_id).all()
        if not can_edit:
            self.fields['user'].widget = forms.HiddenInput()
69

70
71

class VoteForm(forms.Form):
Sli's avatar
Sli committed
72
    def __init__(self, election, user, *args, **kwargs):
73
        super(VoteForm, self).__init__(*args, **kwargs)
Sli's avatar
Sli committed
74
75
        if not election.has_voted(user):
            for role in election.roles.all():
Sli's avatar
Sli committed
76
                cand = role.candidatures
Sli's avatar
Sli committed
77
                if role.max_choice > 1:
Sli's avatar
Sli committed
78
                    self.fields[role.title] = LimitedCheckboxField(cand, role.max_choice, required=False)
Sli's avatar
Sli committed
79
80
                else:
                    self.fields[role.title] = forms.ModelChoiceField(cand, required=False,
Sli's avatar
Sli committed
81
82
83
84
85
86
87
88
89
                                                                     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']

Sli's avatar
Sli committed
90
91
92
93
94
95
    def __init__(self, *args, **kwargs):
        election_id = kwargs.pop('election_id', None)
        super(RoleForm, self).__init__(*args, **kwargs)
        if election_id:
            self.fields['election'].queryset = Election.objects.filter(id=election_id).all()

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

103

Sli's avatar
Sli committed
104
105
106
107
108
109
110
111
112
# 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
113

Sli's avatar
Sli committed
114
115
116
117
118
119
    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
120
121
122
123
124
125
126
127
128

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

129
130
131
    def get_context_data(self, **kwargs):
        """ Add additionnal data to the template """
        kwargs = super(ElectionDetailView, self).get_context_data(**kwargs)
Sli's avatar
Sli committed
132
133
        kwargs['election_form'] = VoteForm(self.object, self.request.user)
        kwargs['election_results'] = self.object.results
134
135
        return kwargs

Sli's avatar
Sli committed
136
137
138

# Form view

139
140
141
142
143
class VoteFormView(CanCreateMixin, FormView):
    """
    Alows users to vote
    """
    form_class = VoteForm
Sli's avatar
Sli committed
144
    template_name = 'election/election_detail.jinja'
145
146

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

150
151
152
153
154
155
    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)
Sli's avatar
Sli committed
156
                    vote.save()
157
                for el in election_data[role_title]:
Sli's avatar
Sli committed
158
                    vote.candidature.add(el)
159
160
161
            # If we have a single choice
            elif election_data[role_title] is not None:
                vote = Vote(role=election_data[role_title].role)
Sli's avatar
Sli committed
162
                vote.save()
163
                vote.candidature.add(election_data[role_title])
Sli's avatar
Sli committed
164
        self.election.voters.add(self.request.user)
165
166
167

    def get_form_kwargs(self):
        kwargs = super(VoteFormView, self).get_form_kwargs()
Sli's avatar
Sli committed
168
169
        kwargs['election'] = self.election
        kwargs['user'] = self.request.user
170
171
172
173
174
175
176
177
        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
178
        for grp in self.election.vote_groups.all():
179
180
181
182
183
184
            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
185
186
187
188
189
190
191
192
193
194
        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['object'] = self.election
        kwargs['election'] = self.election
        kwargs['election_form'] = self.get_form()
        return kwargs

195

196
# Create views
197

Sli's avatar
Sli committed
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
class CandidatureCreateView(CanCreateMixin, CreateView):
    """
    View dedicated to a cundidature creation
    """
    form_class = CandidateForm
    model = Candidature
    template_name = 'election/candidate_form.jinja'

    def dispatch(self, request, *arg, **kwargs):
        self.election = get_object_or_404(Election, pk=kwargs['election_id'])
        return super(CandidatureCreateView, self).dispatch(request, *arg, **kwargs)

    def get_initial(self):
        init = {}
        self.can_edit = self.request.user.can_edit(self.election)
        init['user'] = self.request.user.id
        return init

    def get_form_kwargs(self):
        kwargs = super(CandidatureCreateView, self).get_form_kwargs()
        kwargs['election_id'] = self.election.id
        kwargs['can_edit'] = self.can_edit
        return kwargs

    def form_valid(self, form):
        """
            Verify that the selected user is in candidate group
        """
        obj = form.instance
        obj.election = Election.objects.get(id=self.election.id)
        if(obj.election.can_candidate(obj.user)) and (obj.user == self.request.user or self.can_edit):
            return super(CreateView, self).form_valid(form)
        raise PermissionDenied

    def get_context_data(self, **kwargs):
        kwargs = super(CandidatureCreateView, self).get_context_data(**kwargs)
        kwargs['election'] = self.election
        return kwargs

    def get_success_url(self, **kwargs):
        return reverse_lazy('election:detail', kwargs={'election_id': self.election.id})

Sli's avatar
Sli committed
240

241
class ElectionCreateView(CanCreateMixin, CreateView):
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
    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'

Sli's avatar
Sli committed
259
260
261
262
263
264
265
266
    def form_valid(self, form):
        """
            Verify that the user is suscribed
        """
        res = super(CreateView, self).form_valid(form)
        if self.request.user.is_subscribed():
            return res

267
268
    def get_success_url(self, **kwargs):
        return reverse_lazy('election:detail', kwargs={'election_id': self.object.id})
269
270


Sli's avatar
Sli committed
271
272
class RoleCreateView(CanCreateMixin, CreateView):
    model = Role
Sli's avatar
Sli committed
273
    form_class = RoleForm
Sli's avatar
Sli committed
274
275
    template_name = 'core/page_prop.jinja'

Sli's avatar
Sli committed
276
277
278
279
280
281
282
283
284
    def dispatch(self, request, *arg, **kwargs):
        self.election = get_object_or_404(Election, pk=kwargs['election_id'])
        return super(RoleCreateView, self).dispatch(request, *arg, **kwargs)

    def get_initial(self):
        init = {}
        init['election'] = self.election
        return init

Sli's avatar
Sli committed
285
286
287
288
289
290
291
292
    def form_valid(self, form):
        """
            Verify that the user can edit proprely
        """
        obj = form.instance
        if obj.election:
            for grp in obj.election.edit_groups.all():
                if self.request.user.is_in_group(grp):
Sli's avatar
Sli committed
293
                    return super(CreateView, self).form_valid(form)
Sli's avatar
Sli committed
294
295
        raise PermissionDenied

Sli's avatar
Sli committed
296
297
298
299
300
    def get_form_kwargs(self):
        kwargs = super(RoleCreateView, self).get_form_kwargs()
        kwargs['election_id'] = self.election.id
        return kwargs

Sli's avatar
Sli committed
301
302
303
304
    def get_success_url(self, **kwargs):
        return reverse_lazy('election:detail', kwargs={'election_id': self.object.election.id})


305
306
307
308
309
310
311
312
313
314
315
316
317
318
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
        if obj.election:
            for grp in obj.election.candidature_groups.all():
                if self.request.user.is_in_group(grp):
Sli's avatar
Sli committed
319
                    return super(CreateView, self).form_valid(form)
320
321
            for grp in obj.election.edit_groups.all():
                if self.request.user.is_in_group(grp):
Sli's avatar
Sli committed
322
                    return super(CreateView, self).form_valid(form)
323
324
325
326
        raise PermissionDenied

    def get_success_url(self, **kwargs):
        return reverse_lazy('election:detail', kwargs={'election_id': self.object.election.id})