Multiple fixes
[e_cidadania.git] / src / apps / ecidadania / voting / views / voting.py
blob2a65bab9c920d3230eba3c163416cc86f81a42f1
1 # -*- coding: utf-8 -*-
3 # Copyright (c) 2013 Clione Software
4 # Copyright (c) 2010-2013 Cidadania S. Coop. Galega
6 # Licensed under the Apache License, Version 2.0 (the "License");
7 # you may not use this file except in compliance with the License.
8 # You may obtain a copy of the License at
10 # http://www.apache.org/licenses/LICENSE-2.0
12 # Unless required by applicable law or agreed to in writing, software
13 # distributed under the License is distributed on an "AS IS" BASIS,
14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 # See the License for the specific language governing permissions and
16 # limitations under the License.
18 import hashlib
20 from django.core.mail import send_mail
21 from django.http import HttpResponse, HttpResponseRedirect, Http404, HttpResponseServerError
22 from django.shortcuts import render_to_response, get_object_or_404, redirect
23 from django.utils.decorators import method_decorator
24 from django.contrib.auth.decorators import login_required, permission_required
25 from django.views.generic.base import TemplateView, RedirectView
26 from django.views.generic.list import ListView
27 from django.views.generic.edit import CreateView, UpdateView, DeleteView
28 from django.views.generic.detail import DetailView
29 from django.views.generic import FormView
30 from django.template import RequestContext
31 from django.contrib.auth.models import User
32 from django.forms.formsets import formset_factory, BaseFormSet
33 from django.forms.models import modelformset_factory, inlineformset_factory
34 from django.core.exceptions import ObjectDoesNotExist
35 from helpers.cache import get_or_insert_object_in_cache
36 from django.core.urlresolvers import NoReverseMatch, reverse
37 from django.template.response import TemplateResponse
38 from django.utils.translation import ugettext_lazy as _
39 from django.contrib.sites.models import get_current_site
40 from django.core.exceptions import PermissionDenied
42 from e_cidadania import settings
43 from core.spaces.models import Space
44 from apps.ecidadania.voting.models import *
45 from apps.ecidadania.voting.forms import *
46 from apps.ecidadania.proposals.models import Proposal, ProposalSet
49 class AddVoting(FormView):
51 """
52 Create a new voting process. Only registered users belonging to a concrete
53 group are allowed to create voting processes.
55 versionadded: 0.1
57 :parameters: space_url
58 :context: get_place
59 """
60 form_class = VotingForm
61 template_name = 'voting/voting_form.html'
63 def dispatch(self, request, *Args, **kwargs):
64 space = get_object_or_404(Space, url=kwargs['space_url'])
66 if (request.user.has_perm('admin_space', space) or
67 request.user.has_perm('mod_space', space)):
68 return super(AddVoting, self).dispatch(request, *args, **kwargs)
69 else:
70 raise PermissionDenied
72 def get_form_kwargs(self):
73 """
74 This send the current space to the form so we can change the
75 foreignkeys querysets there.
76 """
77 space = get_object_or_404(Space, url=self.kwargs['space_url'])
78 kwargs = super(AddVoting, self).get_form_kwargs()
79 kwargs['current_space'] = space
80 return kwargs
82 def get_success_url(self):
83 self.space = get_object_or_404(Space, url=self.kwargs['space_url'])
84 return '/spaces/' + self.space.url + '/'
86 def form_valid(self, form):
87 self.space = get_object_or_404(Space, url=self.kwargs['space_url'])
88 form_uncommited = form.save(commit=False)
89 form_uncommited.author = self.request.user
90 form_uncommited.space = self.space
91 form_uncommited.save()
92 form.save_m2m()
93 return super(AddVoting, self).form_valid(form)
95 def get_context_data(self, **kwargs):
96 context = super(AddVoting, self).get_context_data(**kwargs)
97 self.space = get_object_or_404(Space, url=self.kwargs['space_url'])
98 context['get_place'] = self.space
99 return context
102 class ViewVoting(DetailView):
105 View a specific voting process.
107 Proposals: Return unlinked proposals (not linked to sets)
108 All_proposals
110 context_object_name = 'voting'
111 template_name = 'voting/voting_detail.html'
113 def dispatch(self, request, *Args, **kwargs):
114 space = get_object_or_404(Space, url=kwargs['space_url'])
116 if request.user.has_perm('view_space', space):
117 return super(ViewVoting, self).dispatch(request, *args, **kwargs)
118 else:
119 raise PermissionDenied
121 def get_object(self):
122 return Voting.objects.get(pk=self.kwargs['voting_id'])
124 def get_context_data(self, **kwargs):
127 Get extra context data for the ViewVoting view.
129 context = super(ViewVoting, self).get_context_data(**kwargs)
130 context['get_place'] = get_object_or_404(Space, url=self.kwargs['space_url'])
131 voting = Voting.objects.get(pk=self.kwargs['voting_id'])
132 all_proposals = Proposal.objects.all()
133 proposalsets = voting.proposalsets.all()
134 proposals = voting.proposals.all()
135 context['proposalsets'] = proposalsets
136 context['proposals'] = proposals
137 context['all_proposals'] = all_proposals
139 return context
142 class EditVoting(UpdateView):
145 Edit an existent voting process.
147 :parameters: space_url, voting_id
148 :context: get_place
150 model = Voting
151 template_name = 'voting/voting_form.html'
153 def dispatch(self, request, *Args, **kwargs):
154 space = get_object_or_404(Space, url=kwargs['space_url'])
156 if (request.user.has_perm('admin_space', space) or
157 request.user.has_perm('mod_space', space)):
158 return super(EditVoting, self).dispatch(request, *args, **kwargs)
159 else:
160 raise PermissionDenied
162 def get_success_url(self):
163 return '/spaces/' + self.space.url
165 def get_object(self):
166 self.space = get_object_or_404(Space, url=self.kwargs['space_url'])
167 return get_object_or_404(Voting, pk=self.kwargs['voting_id'])
169 def get_context_data(self, **kwargs):
170 context = super(EditVoting, self).get_context_data(**kwargs)
171 context['get_place'] = self.space
172 return context
175 class DeleteVoting(DeleteView):
178 Delete an existent voting process. Voting process deletion is only reserved to spaces
179 administrators or site admins.
181 context_object_name = "get_place"
183 def dispatch(self, request, *Args, **kwargs):
184 space = get_object_or_404(Space, url=kwargs['space_url'])
186 if (request.user.has_perm('admin_space', space) or
187 request.user.has_perm('mod_space', space)):
188 return super(DeleteVoting, self).dispatch(request, *args, **kwargs)
189 else:
190 raise PermissionDenied
192 def get_success_url(self):
193 space = self.kwargs['space_url']
194 return '/spaces/%s' % (space)
196 def get_object(self):
197 self.space = get_object_or_404(Space, url=self.kwargs['space_url'])
198 return get_object_or_404(Voting, pk=self.kwargs['voting_id'])
200 def get_context_data(self, **kwargs):
203 Get extra context data for the ViewVoting view.
205 context = super(DeleteVoting, self).get_context_data(**kwargs)
206 context['get_place'] = self.space
207 return context
210 class ListVotings(ListView):
213 List all the existing votings inside the space. This is meant to be a
214 tabbed view, just like the spaces list. The user can see the open and
215 closed votings.
217 .. versionadded:: 0.1.7 beta
219 paginate_by = 10
221 def dispatch(self, request, *Args, **kwargs):
222 space = get_object_or_404(Space, url=kwargs['space_url'])
224 if request.user.has_perm('view_space', space):
225 return super(ListVotings, self).dispatch(request, *args, **kwargs)
226 else:
227 raise PermissionDenied
229 def get_queryset(self):
230 key = self.kwargs['space_url']
231 current_space = get_or_insert_object_in_cache(Space, key, url=key)
232 votings = Voting.objects.filter(space=current_space)
233 return votings
235 def get_context_data(self, **kwargs):
236 context = super(ListVotings, self).get_context_data(**kwargs)
237 key = self.kwargs['space_url']
238 space = get_or_insert_object_in_cache(Space, key, url=key)
239 context['get_place'] = space
240 return context
243 def vote_voting(request, space_url):
246 View to control the votes during a votation process. Do not confuse with
247 proposals support_votes. This function creates a new ConfirmVote object
248 trough VoteForm with the user and a token. After that an email is sent
249 to the user with the token for validation. This function does not add the
250 votes.
252 .. versionadded:: 0.1.7
254 proposal = get_object_or_404(Proposal, pk=request.POST['propid'])
255 space = get_object_or_404(Space, url=space_url)
256 voteform = VoteForm(request.POST)
258 if request.user_has_perm('view_space', space):
259 if request.method == 'POST' and voteform.is_valid():
260 # Generate the objetct
261 token = hashlib.md5("%s%s%s" % (request.user, space,
262 datetime.datetime.now())).hexdigest()
263 voteform_uncommitted = voteform.save(commit=False)
264 voteform_uncommitted.user = request.user
265 voteform_uncommitted.token = token
266 voteform_uncommitted.proposal = proposal
267 voteform_uncommitted.save()
269 # Send the email to the user. Get URL, get user mail, send mail.
270 space_absolute_url = space.get_absolute_url()
271 full_url = ''.join(['http://', get_current_site(request).domain,
272 space_absolute_url, 'voting/vote/validate/', token])
273 user_email = request.user.email
274 subject = _("Validate your vote")
275 body = _("You voted recently on a process in our platform, please validate your vote following this link: %s") % full_url
276 try:
277 send_mail(subject, body, settings.DEFAULT_FROM_EMAIL, [user_email])
278 except:
279 return HttpResponseServerError(_("Couldn't send the email."))
280 else:
281 return HttpResponseBadRequest(_("Request is not POST."))
282 else:
283 raise PermissionDenied
286 def validate_voting(request, space_url, token):
289 Validate the votes done in a votation process. This function checks if the
290 token provided by the user is the same located in the database. If the
291 token is the same, a vote is added, if not, we redirect the user to an
292 error page.
294 space = get_object_or_404(Space, url=space_url)
295 tk = get_object_or_404(ConfirmVote, token=token)
297 if (request.user.has_perm('admin_space', space) or
298 request.user.has_perm('mod_space', space) or
299 request.user == tk.user):
300 try:
301 prop = get_object_or_404(Proposal, pk=tk.proposal.id)
302 prop.votes.add(request.user)
303 return HttpResponse("Your vote has been validated.")
304 except:
305 return HttpResponse("Error V01: Couldn't find the token for validation or the token has already been used.")
306 tk.delete()
308 else:
309 raise PermissionDenied