views.py 14 KB
Newer Older
chris's avatar
chris committed
1
# Here are the views for sondage
christophe siraut's avatar
christophe siraut committed
2 3 4 5 6 7 8 9

import datetime
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import  get_object_or_404, render_to_response
from django.core.urlresolvers import reverse
from django.template import RequestContext
from django.forms.formsets import formset_factory
from django.forms.models import inlineformset_factory, BaseInlineFormSet
chris's avatar
chris committed
10 11
from sondage.models import Poll, Choice, Vote, Bulletin
from sondage.forms import PollForm, ChoiceForm, VoteForm, BulletinForm
christophe siraut's avatar
christophe siraut committed
12 13
from django.views.generic.create_update import update_object
from django.contrib.auth.decorators import login_required
14
from django.utils.translation import ugettext_lazy as _
15
from django.conf import settings
Christophe Siraut's avatar
Christophe Siraut committed
16
from accounts.views import email_notify
Christophe Siraut's avatar
Christophe Siraut committed
17
from accounts.forms import UserProfileForm
christophe siraut's avatar
christophe siraut committed
18 19 20

def new(request):
    if request.method == 'POST': # If the form has been submitted...
Christophe Siraut's avatar
Christophe Siraut committed
21 22 23 24
        if request.user.is_authenticated():
            instance = Poll(author=str(request.user), user=request.user)
        else:
            instance = Poll(author=str(request.user))
christophe siraut's avatar
christophe siraut committed
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
        form = PollForm(request.POST, instance=instance) # A form bound to the POST data
        if form.is_valid(): # All validation rules pass
            poll_id = form.cleaned_data.get('title') # Process the data in form.cleaned_data
            new_poll = form.save()

            key = 'is_' + new_poll.id + '_author'
            request.session[key] = True # This writes cookie

            redir = '/' + str(new_poll.id) + '/edit/choices/'
            return HttpResponseRedirect(redir)

    else:
        form = PollForm() # An unbound form

    return render_to_response('sondage/poll_form.html', {'form': form}, context_instance=RequestContext(request))


@login_required
def secure_update_object(*args, **kwargs):
    """
    Souldn't we provide a better object to the generic view: object_id=poll
    and then simple the template
    # joe = str(request.user)
    # if Poll.objects.get(id=object_id, author=joe):
    """
    return update_object(*args, **kwargs)

52 53 54
def translation(request, lang_id):
    request.session['django_language'] = lang_id
    return HttpResponseRedirect('/nuages')
christophe siraut's avatar
christophe siraut committed
55 56 57 58 59 60 61

def get_ordereditem_formset(form, formset=BaseInlineFormSet, **kwargs):
    return inlineformset_factory(Poll, Choice, form, formset, **kwargs)

def editchoices(request, poll_id):

    poll = get_object_or_404(Poll.objects.all(),id=poll_id)
62
    language_code = request.LANGUAGE_CODE
63
    error_message = ''
christophe siraut's avatar
christophe siraut committed
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
    if poll.author == 'AnonymousUser': # Anonymous wants to edit his new poll
        key = 'is_' + poll_id + '_author'
        if not request.session.get(key, False):
            return HttpResponse('')
    else:
        if request.user.is_anonymous():
            return HttpResponse('')
        if request.user.username != poll.author:
            return HttpResponse('')

    OrderedItemFormset = get_ordereditem_formset(ChoiceForm, extra=0, can_delete=True)

    if request.method == "POST":
        """
        Should we set a maximum of choices here?
        #instances = request.POST.values()
        if len(instances) < 20:
            for selection in instances:
        """
        instances = OrderedItemFormset(request.POST, instance=poll)
        if instances.is_valid():
            for instance in instances.cleaned_data:
                try:
                    this_choice = instance['choice']
                    if not instance.get('DELETE'):
                        try:
                            choice = Choice.objects.get(poll=poll,choice=instance['choice'])
                            choice.details = instance['details']
                            choice.save()

                        except (KeyError, Choice.DoesNotExist):
                            choice = Choice(poll=poll, choice=instance['choice'], details=instance['details'])
                            choice.save()
97 98 99 100 101 102
                            # If bulletins for this poll existed before edition
                            # add an 'false' vote child to them for newly created choice.
                            # This makes template computation easier
                            for bulletin in Bulletin.objects.filter(poll=poll):
                                nvote = Vote(choice=choice, bulletin=bulletin, voice=False)
                                nvote.save()
christophe siraut's avatar
christophe siraut committed
103 104 105 106 107 108 109 110 111 112 113 114 115
                    else:
                        try:
                            choice = Choice.objects.get(poll=poll,choice=this_choice)
                            """
                            Removing a Choice will remove all childeren Vote objects.
                            When Django deletes an object, it emulates the behavior of
                            the SQL constraint ON DELETE CASCADE -- in other words, any
                            objects which had foreign keys pointing at the object to be
                            deleted will be deleted along with it."""
                            choice.delete()
                        except:
                            pass
                except:
116 117
                    # probably an empty datefield?
                    pass 
christophe siraut's avatar
christophe siraut committed
118 119 120
            redir = '/' + str(poll.id) + '/'
            return HttpResponseRedirect(redir)
        else:
121
            #vforms=OrderedItemFormset(request.POST, instance=poll)
122
            error_message = _("There are some errors in the form you posted.")
123 124
            vforms=instances

christophe siraut's avatar
christophe siraut committed
125
    else:
126 127
        if Choice.objects.filter(poll=poll_id).count() == 0:
            # Sall we replace next line with something like OrderedItemFormset(extra=2)
128
            OrderedItemFormset = get_ordereditem_formset(ChoiceForm, extra=1, can_delete=True)
129
            vforms = OrderedItemFormset(instance=poll)
130 131 132 133 134
        else:
            vforms = OrderedItemFormset(instance=poll)

    return render_to_response('sondage/choice_form.html', {'object': poll, 'vforms': vforms, 'error_message' : error_message, 'language_code': language_code,}, context_instance=RequestContext(request))

christophe siraut's avatar
christophe siraut committed
135

136 137 138 139 140 141 142 143 144 145 146
@login_required
def delete(request, poll_id):

    poll = get_object_or_404(Poll.objects.all(),id=poll_id)

    if poll.author == str(request.user):
        poll.delete()

    return HttpResponseRedirect('/')


christophe siraut's avatar
christophe siraut committed
147 148 149 150 151 152 153 154
def make_buletin_form(poll, **kwargs):
    return [ [VoteForm(prefix=choice) ] for choice in Choice.objects.filter(poll=poll.id) ]


def vote(request, poll_id):

    error_message = None
    poll = get_object_or_404(Poll.objects.all(),id=poll_id)
155
    has_voted = False
christophe siraut's avatar
christophe siraut committed
156 157 158 159

    if request.method == 'POST':

        form = BulletinForm(request.POST,initial={'poll': poll.id,})
160
        vforms = [ [VoteForm(request.POST, prefix=choice, instance=choice) ] for choice in Choice.objects.filter(poll=poll.id) ]
christophe siraut's avatar
christophe siraut committed
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191

        if form.is_valid():           
            if request.user.is_authenticated():
                voter = str(request.user)
            else:
                voter = form.cleaned_data['voter']
                if request.session.get('name'):
                    voter = request.session.get('name')

            if voter != 'your name':
                """
                try:
                    Bulletin.objects.get(poll=poll.id,voter=voter)
                    error_message = 'A user with the same name has already voted.'
                    return render_to_response('sondage/poll_detail.html', {'object': poll, 'form': form, 'vforms':vforms, 'error_message':error_message}, context_instance=RequestContext(request))
                except:
                    pass
                """

                if not Bulletin.objects.filter(poll=poll.id,voter=voter):
                    bulletin = Bulletin(poll=poll,voter=voter)
                    bulletin.save()
                else:
                    bulletin = Bulletin.objects.get(poll=poll.id,voter=voter)

                for forms in vforms:
                    for vorm in forms:
                        if vorm.is_valid():
                            try:
                                choice = Choice.objects.get(choice=vorm.cleaned_data['choice'],poll=poll)
                            except:
192
                                return HttpResponse(vorm.cleaned_data['choice'])
christophe siraut's avatar
christophe siraut committed
193 194

                            if not Vote.objects.filter(choice=choice,bulletin=bulletin):
195 196 197
                                new = Vote(choice=choice,bulletin=bulletin,comment=vorm.cleaned_data['comment'])
                                if vorm.cleaned_data['voice']:
                                    new.voice = vorm.cleaned_data['voice']
christophe siraut's avatar
christophe siraut committed
198 199 200 201 202 203 204 205 206
                                new.save()
                                if new.voice:
                                    choice.votecount += 1
                                    choice.save()
                                error_message = "Your vote has been counted, thank you."
                                if request.user.is_anonymous(): # Anonymous has voted...
                                    key = 'has_voted-' + poll.id
                                    request.session[key] = True # This writes cookie
                                    request.session['name'] = voter # This writes cookie
207
                                    has_voted = True  # Used to show "Forget me"
christophe siraut's avatar
christophe siraut committed
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
                            else:
                                old = Vote.objects.get(choice=choice,bulletin=bulletin)

                                if old.voice:
                                    if not vorm.cleaned_data['voice']:
                                        choice.votecount -= 1
                                        choice.save()
                                else:
                                    if vorm.cleaned_data['voice']:
                                        choice.votecount += 1
                                        choice.save()

                                old.voice = vorm.cleaned_data['voice']
                                old.comment = vorm.cleaned_data['comment']
                                old.save()
223 224 225 226 227 228 229
                                error_message = _("Your vote has been updated, thank you.")
                if has_voted and poll.user:
                    try:
                        if poll.user.userprofile.email_notifications:
                            email_notify(poll, voter)
                    except:
                        pass
christophe siraut's avatar
christophe siraut committed
230
            else:
231
                error_message = _('Did you forget to provide your name?')
christophe siraut's avatar
christophe siraut committed
232 233
        else:
            #error_message = form.errors
234 235
            error_message = _('Did you forget to provide your name?')
            voter = _('your name')
christophe siraut's avatar
christophe siraut committed
236 237 238 239 240 241 242 243 244

    else: # request.method = 'GET'

        key = 'is_' + poll.id + '_author'
        if request.session.get(key, False):
            # Assume author is positive for all choices, when he votes for the first time.
            vforms = [ [ VoteForm(initial={'choice': choice,'voice': True,}, prefix=choice) ] for choice in Choice.objects.filter(poll=poll_id) ]
        else:
            # Default formset for unknown user
245
            vforms = [ [ VoteForm(initial={'choice': choice,}, prefix=choice) ] for choice in Choice.objects.filter(poll=poll_id) ]
christophe siraut's avatar
christophe siraut committed
246 247 248 249
        if request.user.is_authenticated():
            voter = str(request.user)
            try:
                bulletin = Bulletin.objects.get(poll=poll,voter=voter)
250
                error_message = " You have voted."
christophe siraut's avatar
christophe siraut committed
251 252 253 254 255 256 257
                diff = len(vforms) - len(Vote.objects.filter(bulletin=bulletin))
                if diff == 0:
                    """
                    Hum, previously bulletin has not the same amount of vote objects,
                    we should concatenate the existing votes with empty remaing ones...
                    Give an empty bulletin for now.
                    """
258
                    vforms = [ [ VoteForm(initial={'choice': vote.choice,'voice': vote.voice, 'comment': vote.comment,}, prefix=vote.choice) ] for vote in Vote.objects.filter(bulletin=bulletin).order_by('choice__choice') ]
christophe siraut's avatar
christophe siraut committed
259 260 261 262

            except:
                pass
        else:
263
            voter = ''
264
            error_message = _("Login let you modify your vote anytime.")
christophe siraut's avatar
christophe siraut committed
265 266
            key = 'has_voted-' + poll.id
            if request.session.get(key, False):
267
                has_voted = True  # Used to show "Forget me"
christophe siraut's avatar
christophe siraut committed
268 269 270 271
                voter = request.session.get('name')
                #error_message = 'Modify your vote? (clear cookie if you are not ' + voter + ')'
                try:
                    bulletin = Bulletin.objects.get(poll=poll,voter=voter)
272
                    error_message = voter + ' has voted'
christophe siraut's avatar
christophe siraut committed
273 274 275 276 277 278 279
                    diff = len(vforms) - len(Vote.objects.filter(bulletin=bulletin))
                    if diff == 0:
                        """
                        Hum, previously bulletin has not the same amount of vote objects,
                        we should concatenate the existing votes with empty remaing ones...
                        Give an empty bulletin for now.
                        """
280
                        vforms = [ [ VoteForm(initial={'choice': vote.choice,'voice': vote.voice, 'comment': vote.comment,}, prefix=vote.choice) ] for vote in Vote.objects.filter(bulletin=bulletin).order_by('choice__choice') ]
christophe siraut's avatar
christophe siraut committed
281 282 283 284

                except:
                    pass

285 286
    form = BulletinForm(instance=poll,initial={'voter': voter})
    #form = BulletinForm(instance=poll)
287
    current_site = settings.SITE + poll.id
288
    return render_to_response('sondage/poll_detail.html', {'object': poll, 'form': form, 'vforms':vforms, 'error_message':error_message, 'has_voted': has_voted, 'current_site': current_site}, context_instance=RequestContext(request))
christophe siraut's avatar
christophe siraut committed
289

chris's avatar
chris committed
290
def exp_csv(request, poll_id):
Christophe Siraut's avatar
Christophe Siraut committed
291 292 293 294 295 296
    import csv

    # Create the HttpResponse object with the appropriate CSV header.
    response = HttpResponse(mimetype='text/csv')
    response['Content-Disposition'] = 'attachment; filename=nuages.csv'

chris's avatar
chris committed
297 298 299
    poll = get_object_or_404(Poll.objects.all(),id=poll_id)
    choices = Choice.objects.filter(poll=poll)
    bulletins = Bulletin.objects.filter(poll=poll)
Christophe Siraut's avatar
Christophe Siraut committed
300 301 302 303 304 305 306 307 308 309 310
    writer = csv.writer(response, quotechar='"', quoting=csv.QUOTE_ALL)
    fr = ["",]
    for c in choices:
       fr.append(c)
    writer.writerow(fr)
    for b in bulletins:
        r = [b.voter.encode("utf-8"),]
        for v in Vote.objects.filter(bulletin=b):
            r.append(v)
        writer.writerow(r)
    return response