1 # -*- coding: utf-8 -*-
3 # Copyright (c) 2010-2012 Cidadania S. Coop. Galega
5 # This file is part of e-cidadania.
7 # e-cidadania is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation, either version 3 of the License, or
10 # (at your option) any later version.
12 # e-cidadania is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with e-cidadania. If not, see <http://www.gnu.org/licenses/>.
20 from django.http import HttpResponse, HttpResponseRedirect, Http404
21 from django.shortcuts import render_to_response, get_object_or_404, redirect
22 from django.utils.decorators import method_decorator
23 from django.contrib.auth.decorators import login_required, permission_required
24 from django.views.generic.base import TemplateView, RedirectView
25 from django.views.generic.list import ListView
26 from django.views.generic.edit import CreateView, UpdateView, DeleteView
27 from django.views.generic.detail import DetailView
28 from django.views.generic import FormView
29 from django.template import RequestContext
30 from django.views.generic.create_update import create_object
31 from django.views.generic.create_update import update_object
32 from django.contrib.auth.models import User
33 from django.forms.formsets import formset_factory, BaseFormSet
34 from django.forms.models import modelformset_factory, inlineformset_factory
35 from django.core.exceptions import ObjectDoesNotExist
36 from helpers.cache import get_or_insert_object_in_cache
37 from django.core.urlresolvers import NoReverseMatch, reverse
38 from django.template.response import TemplateResponse
40 from core.spaces.models import Space
41 from core.permissions import has_all_permissions, has_space_permission, has_operation_permission
42 from apps.ecidadania.voting.models import *
43 from apps.ecidadania.voting.forms import *
44 from apps.ecidadania.proposals.models import *
46 @permission_required('voting.add_poll')
47 def AddPoll(request, space_url):
50 Create a new poll. Only registered users belonging to a concrete group
51 are allowed to create polls.
53 :parameters: space_url
56 place = get_object_or_404(Space, url=space_url)
57 poll_form = PollForm(request.POST or None)
58 choice_form = ChoiceFormSet(request.POST or None, prefix="choiceform")
61 last_poll_id = Poll.objects.latest('id')
62 current_poll_id = last_poll_id.pk + 1
63 except ObjectDoesNotExist:
66 if (has_operation_permission(request.user, place, 'voting.add_poll', allow=['admins', 'mods'])):
67 if request.method == 'POST':
68 if poll_form.is_valid() and choice_form.is_valid():
69 poll_form_uncommited = poll_form.save(commit=False)
70 poll_form_uncommited.space = place
71 poll_form_uncommited.author = request.user
73 saved_poll = poll_form_uncommited.save()
74 poll_instance = get_object_or_404(Poll, pk=current_poll_id)
76 for form in choice_form.forms:
77 choice = form.save(commit=False)
78 choice.poll = poll_instance
81 return redirect('/spaces/' + space_url)
83 return render_to_response('voting/poll_form.html',
84 {'form': poll_form, 'choiceform': choice_form,
85 'get_place': place, 'pollid': current_poll_id,},
86 context_instance=RequestContext(request))
88 return render_to_response('not_allowed.html',context_instance=RequestContext(request))
90 def EditPoll(request, space_url, poll_id):
95 :parameters: space_url, poll_id
96 :context: form, get_place, choiceform, pollid
98 place = get_object_or_404(Space, url=space_url)
99 if has_operation_permission(request.user, place, 'voting.change_poll', allow=['admins', 'mods']):
101 ChoiceFormSet = inlineformset_factory(Poll, Choice)
102 instance = Poll.objects.get(pk=poll_id)
103 poll_form = PollForm(request.POST or None, instance=instance)
104 choice_form = ChoiceFormSet(request.POST or None, instance=instance, prefix="choiceform")
106 if request.method == 'POST':
107 if poll_form.is_valid() and choice_form.is_valid():
108 poll_form_uncommited = poll_form.save(commit=False)
109 poll_form_uncommited.space = place
110 poll_form_uncommited.author = request.user
112 saved_poll = poll_form_uncommited.save()
114 for form in choice_form.forms:
115 choice = form.save(commit=False)
116 choice.poll = instance
118 return redirect('/spaces/' + space_url)
120 return render_to_response('voting/poll_edit.html',
122 'choiceform': choice_form,
125 context_instance=RequestContext(request))
127 return render_to_response('not_allowed.html', context_instance=RequestContext(request))
130 class DeletePoll(DeleteView):
133 Delete an existent poll. Poll deletion is only reserved to spaces
134 administrators or site admins.
136 context_object_name = "get_place"
138 def get_success_url(self):
139 space = self.kwargs['space_url']
140 return '/spaces/%s' % (space)
142 def get_object(self):
143 space = get_object_or_404(Space, url=self.kwargs['space_url'])
144 if has_operation_permission(self.request.user, space, 'voting.delete_poll', allow=['admins']):
145 return get_object_or_404(Poll, pk=self.kwargs['poll_id'])
147 self.template_name = 'not_allowed.html'
149 def get_context_data(self, **kwargs):
150 context = super(DeletePoll, self).get_context_data(**kwargs)
151 context['get_place'] = get_object_or_404(Space, url=self.kwargs['space_url'])
155 class ListPolls(ListView):
157 Return a list of polls for the current space.
162 def get_queryset(self):
163 key = self.kwargs['space_url']
164 current_space = get_or_insert_object_in_cache(Space, key, url=key)
165 polls = Poll.objects.filter(space=current_space)
167 # Here must go a validation so a user registered to the space
168 # can always see the poll list. While an anonymous or not
169 # registered user can't see anything unless the space is public
173 def get_context_data(self, **kwargs):
174 context = super(ListPolls, self).get_context_data(**kwargs)
175 key = self.kwargs['space_url']
176 space = get_or_insert_object_in_cache(Space, key, url=key)
177 context['get_place'] = space
181 def vote(request, poll_id, space_url):
182 place = get_object_or_404(Space, url=space_url)
183 p = get_object_or_404(Poll, pk=poll_id)
185 selected_choice = p.choice_set.get(pk=request.POST['choice'])
186 except (KeyError, Choice.DoesNotExist):
187 return render_to_response('voting/poll_detail.html', {
189 'error_message': "You didn't select a choice.",
190 }, context_instance=RequestContext(request))
192 selected_choice.votes += 1
193 selected_choice.save()
194 return TemplateResponse(request, 'voting/poll_results.html', {'poll':p, 'get_place': place})
197 class AddVoting(FormView):
200 Create a new voting process. Only registered users belonging to a concrete group
201 are allowed to create voting processes.
205 :parameters: space_url
208 form_class = VotingForm
209 template_name = 'voting/voting_form.html'
211 def get_success_url(self):
212 self.space = get_object_or_404(Space, url=self.kwargs['space_url'])
213 return '/spaces/' + self.space.url + '/'
215 def form_valid(self, form):
216 self.space = get_object_or_404(Space, url=self.kwargs['space_url'])
217 if has_operation_permission(self.request.user, self.space, 'voting.add_voting', allow=['admins', 'mods']):
218 form_uncommited = form.save(commit=False)
219 form_uncommited.author = self.request.user
220 form_uncommited.space = self.space
221 form_uncommited.save()
223 return super(AddVoting, self).form_valid(form)
225 template_name = 'not_allowed.html'
228 def get_context_data(self, **kwargs):
229 context = super(AddVoting, self).get_context_data(**kwargs)
230 self.space = get_object_or_404(Space, url=self.kwargs['space_url'])
231 context['get_place'] = self.space
234 class ViewVoting(DetailView):
237 View a specific voting process.
239 context_object_name = 'voting'
240 template_name = 'voting/voting_detail.html'
242 def get_object(self):
243 return Voting.objects.get(pk=self.kwargs['voting_id'])
245 def get_context_data(self, **kwargs):
248 Get extra context data for the ViewVoting view.
250 context = super(ViewVoting, self).get_context_data(**kwargs)
251 context['get_place'] = get_object_or_404(Space, url=self.kwargs['space_url'])
252 voting = Voting.objects.get(pk=self.kwargs['voting_id'])
253 all_proposals = Proposal.objects.all()
254 proposalsets = voting.proposalsets.all()
255 proposals = voting.proposals.all()
256 context['proposalsets'] = proposalsets
257 context['proposals'] = proposals
258 context['all_proposals'] = all_proposals
262 class EditVoting(UpdateView):
265 Edit an existent voting process.
267 :parameters: space_url, voting_id
271 template_name = 'voting/voting_form.html'
273 def get_success_url(self):
274 return '/spaces/' + self.space.url
276 def get_object(self):
277 self.space = get_object_or_404(Space, url=self.kwargs['space_url'])
278 if has_operation_permission(self.request.user, self.space, 'voting.change_voting', allow=['admins', 'mods']):
279 return get_object_or_404(Voting, pk=self.kwargs['voting_id'])
281 self.template_name = 'not_allowed.html'
283 def get_context_data(self, **kwargs):
284 context = super(EditVoting, self).get_context_data(**kwargs)
285 context['get_place'] = self.space
289 class DeleteVoting(DeleteView):
292 Delete an existent voting process. Voting process deletion is only reserved to spaces
293 administrators or site admins.
295 context_object_name = "get_place"
297 def get_success_url(self):
298 space = self.kwargs['space_url']
299 return '/spaces/%s' % (space)
301 def get_object(self):
302 self.space = get_object_or_404(Space, url=self.kwargs['space_url'])
303 if has_operation_permission(self.request.user, self.space, 'voting.delete_voting', allow=['admins', 'mods']):
304 return get_object_or_404(Voting, pk=self.kwargs['voting_id'])
306 self.template_name = 'not_allowed.html'
308 def get_context_data(self, **kwargs):
311 Get extra context data for the ViewVoting view.
313 context = super(DeleteVoting, self).get_context_data(**kwargs)
314 context['get_place'] = self.space