summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--polls/models.py2
-rw-r--r--polls/views.py312
-rw-r--r--static/bg.jpgbin4449 -> 3473 bytes
-rw-r--r--static/styles.css70
-rw-r--r--templates/createOrEdit.html6
-rw-r--r--templates/vote.html8
6 files changed, 253 insertions, 145 deletions
diff --git a/polls/models.py b/polls/models.py
index 38f1981..08395b8 100644
--- a/polls/models.py
+++ b/polls/models.py
@@ -46,5 +46,5 @@ class Vote(models.Model):
VOTE = ((-1, 'No'),
(0, 'Maybe'),
(1, 'Yes'),)
- vote = models.IntegerField(choices=VOTE)
+ value = models.IntegerField(choices=VOTE)
diff --git a/polls/views.py b/polls/views.py
index 040a9b9..8bb8157 100644
--- a/polls/views.py
+++ b/polls/views.py
@@ -14,11 +14,13 @@ from django.http import HttpResponseRedirect
from papillon.polls.models import Poll, PollUser, Choice, Vote
def getBaseResponse(request):
+ "Get the root url in order to redirect to the main page"
url = "/".join([request.META['HTTP_HOST'],
request.path.split('/')[1], ''])
return {'root_url':url}
def index(request):
+ "Main page"
response_dct = getBaseResponse(request)
error = ''
if 'bad_poll' in request.GET:
@@ -26,27 +28,35 @@ def index(request):
return render_to_response('main.html', response_dct)
def createOrEdit(request, admin_url):
-
+ '''Creation or edition of a poll.
+ admin_url is given to identify a particular poll
+ admin_url is equal to 0 for a new poll
+ response_dct is given to the template with some particular keys:
+ - error is an error message
+ - new is set to true if it is a new poll
+ - admin_url is the url of the current page
+ '''
def genRandomURL():
+ "Generation of a random url"
chars = string.letters + string.digits
url = ''
- for i in range(6):
+ for i in xrange(6):
url += random_choice(chars)
url += str(int(time.time()))
return url
- response_dct = getBaseResponse(request)
- response_dct['TYPES'] = Poll.TYPE
- error = None
- poll = None
- if 'new' in request.POST:
+ def submitNewPoll(request, response_dct):
+ "A new poll is submited"
+ # verify if all the mandatory_fields are set
mandatory_fields = (('author_name', "Author name"),
('poll_name', "Poll name"),
('poll_desc', "Poll description"),
('poll_type', "Poll type"),
)
+ error = ""
for key, label in mandatory_fields:
if key not in request.POST or not request.POST[key]:
+ # only the first error is reported
if not error:
error = "%s is a mandatory field" % label
else:
@@ -54,47 +64,47 @@ def createOrEdit(request, admin_url):
if error:
response_dct['new'] = True
response_dct['error'] = error
- response_dct['admin_url'] = \
- "/".join(request.path.split('/')[:-2]) + '/0/'
- else:
- author = PollUser(name=request.POST['author_name'])
- author.save()
- base_url = 'b' + genRandomURL()
- admin_url = 'a' + genRandomURL()
- poll = Poll(name=request.POST['poll_name'],
+ response_dct['admin_url'] += '/0/'
+ return response_dct, None
+ author = PollUser(name=request.POST['author_name'])
+ author.save()
+ base_url = 'b' + genRandomURL()
+ admin_url = 'a' + genRandomURL()
+ poll = Poll(name=request.POST['poll_name'],
description=request.POST['poll_desc'], author=author, base_url=base_url,
admin_url=admin_url, status = 'D', type=request.POST['poll_type'])
- poll.save()
- url = "/".join(request.path.split('/')[:-2]) \
- + '/%s/' % poll.admin_url
- return HttpResponseRedirect(url)
- elif admin_url == '0':
- response_dct['new'] = True
- response_dct['admin_url'] = \
- "/".join(request.path.split('/')[:-2]) + '/0/'
- else:
+ poll.save()
+ url = response_dct['admin_url'] + '/%s/' % poll.admin_url
+ return response_dct, HttpResponseRedirect(url)
+
+ def getExistingPoll(request, response_dct, admin_url):
+ "Get an existing poll"
try:
poll = Poll.objects.filter(admin_url=admin_url)[0]
except IndexError:
- url = "/".join(request.path.split('/')[:-2]) + '/0/'
- return HttpResponseRedirect(url)
- response_dct['choices'] = Choice.objects.filter(poll=poll).order_by('order')
- response_dct['author_name'] = poll.author.name
- response_dct['poll_name'] = poll.name
- response_dct['poll_desc'] = poll.description
- idx = [type[0] for type in poll.TYPE].index(poll.type)
- response_dct['type_name'] = Poll.TYPE[idx][1]
- response_dct['poll_status'] = poll.status
- response_dct['admin_url'] = \
- "/".join(request.path.split('/')[:-2]) + '/%s/' % poll.admin_url
+ # if the poll don't exist redirect to the creation page
+ url = response_dct['admin_url'] + '/0/'
+ return response_dct, HttpResponseRedirect(url)
+ # base feed of the template
+ new_dct = {'author_name':poll.author.name,
+ 'poll_name':poll.name,
+ 'poll_desc':poll.description,
+ 'choices':Choice.objects.filter(poll=poll).order_by('order'),
+ 'poll_status':poll.status,
+ 'type_name':poll.getTypeLabel()}
+ response_dct.update(new_dct)
+
+ # urls
base_path = request.META['HTTP_HOST'] + \
"/".join(request.path.split('/')[:-3])
- response_dct['full_admin_url'] = base_path + "/edit/" \
- + admin_url + "/"
response_dct['base_url'] = poll.base_url
response_dct['full_base_url'] = base_path + "/poll/" \
+ poll.base_url + "/"
- response_dct['choiceform'] = "<input type='text' name='new_choice'/>"
+ response_dct['admin_url'] += '/%s/' % poll.admin_url
+ response_dct['full_admin_url'] = base_path + "/edit/" \
+ + admin_url + "/"
+
+ # if a new choice is submitted
if 'new_choice' in request.POST and request.POST['new_choice']:
try:
order = Choice.objects.order_by('-order')[0].order
@@ -104,110 +114,194 @@ admin_url=admin_url, status = 'D', type=request.POST['poll_type'])
choice = Choice(poll=poll, name=request.POST['new_choice'],
order=order)
choice.save()
+ # check if a choice has been choosen for deletion
for key in request.POST:
if key.startswith('delete_') and request.POST[key]:
choice = Choice.objects.get(id=int(key[len('delete_'):]))
Vote.objects.filter(choice=choice).delete()
choice.delete()
+ return response_dct, None
+
+ response_dct = getBaseResponse(request)
+ response_dct['TYPES'] = Poll.TYPE
+ response_dct['admin_url'] = \
+ "/".join(request.path.split('/')[:-2])
+ redirection = None
+ if 'new' in request.POST:
+ # new poll is submited
+ response_dct, redirection = submitNewPoll(request, response_dct)
+ elif admin_url == '0':
+ # new empty poll
+ response_dct['new'] = True
+ response_dct['admin_url'] += '/0/'
+ else:
+ # existing poll
+ response_dct, redirection = getExistingPoll(request,
+ response_dct, admin_url)
+ if redirection:
+ return redirection
return render_to_response('createOrEdit.html', response_dct)
def poll(request, poll_url):
+ "Display a poll"
+
+ def modifyVote(request, choices):
+ "Modify user's votes"
+ try:
+ author = PollUser.objects.filter(
+ id=int(request.POST['voter']))[0]
+ except (ValueError, IndexError):
+ return
+ # if no author_name is given deletion of associated votes and
+ # author
+ if not request.POST['author_name']:
+ for choice in choices:
+ v = Vote.objects.filter(voter=author, choice=choice)
+ v.delete()
+ author.delete()
+ return
+ # update the name
+ author.name = request.POST['author_name']
+ author.save()
+ selected_choices = []
+ # set the selected choices
+ for key in request.POST:
+ if key.startswith('vote_') and request.POST[key]:
+ try:
+ id = int(key.split('_')[1])
+ vote = Vote.objects.filter(id=id)[0]
+ if vote.choice not in choices:
+ # bad vote id : the associated choice has
+ # probably been deleted
+ vote.delete()
+ else:
+ vote.vote = 1
+ vote.save()
+ selected_choices.append(vote.choice)
+ except (ValueError, IndexError):
+ # the vote don't exist with this choice
+ v = Vote(voter=author, choice=choice, value=1)
+ v.save()
+ if key.startswith('choice_') and request.POST[key]:
+ try:
+ id = int(key.split('_')[1])
+ choice = Choice.objects.filter(id=id)[0]
+ if choice not in choices:
+ raise ValueError
+ v = Vote(voter=author, choice=choice, value=1)
+ v.save()
+ selected_choices.append(choice)
+ except (ValueError, IndexError):
+ # bad choice id : the choice has probably been deleted
+ pass
+ # update non selected choices
+ for choice in choices:
+ if choice not in selected_choices:
+ try:
+ v = Vote.objects.filter(voter=author, choice=choice)[0]
+ v.vote = 0
+ except IndexError:
+ # the vote don't exist with this choice : probably
+ # a new choice
+ v = Vote(voter=author, choice=choice, value=0)
+ v.save()
+
+ def newVote(request, choices):
+ "Create new votes"
+ if not request.POST['author_name']:
+ return
+ author = PollUser(name=request.POST['author_name'])
+ author.save()
+ selected_choices = []
+
+ # set the selected choices
+ for key in request.POST:
+ if key.startswith('choice_') and request.POST[key]:
+ try:
+ id = int(key.split('_')[1])
+ choice = Choice.objects.filter(id=id)[0]
+ if choice not in choices:
+ raise ValueError
+ v = Vote(voter=author, choice=choice, value=1)
+ v.save()
+ selected_choices.append(choice)
+ except (ValueError, IndexError):
+ # bad choice id : the choice has probably been deleted
+ pass
+ # set non selected choices
+ for choice in choices:
+ if choice not in selected_choices:
+ v = Vote(voter=author, choice=choice, value=0)
+ v.save()
+
response_dct = getBaseResponse(request)
- error = None
try:
poll = Poll.objects.filter(base_url=poll_url)[0]
except IndexError:
poll = None
choices = Choice.objects.filter(poll=poll).order_by('order')
+ # if the poll don't exist or if it has no choices the user is
+ # redirected to the main page
if not choices or not poll:
url = "/".join(request.path.split('/')[:-3])
- url += "?bad_poll=1"
+ url += "/?bad_poll=1"
return HttpResponseRedirect(url)
- response_dct['base_url'] = \
- "/".join(request.path.split('/')[:-2]) + '/%s/' % poll.base_url
-
- response_dct['choices'] = choices
+
+ # a vote is submitted
if 'author_name' in request.POST:
if 'voter' in request.POST:
- try:
- author = PollUser.objects.filter(id=int(request.POST['voter']))[0]
- except (ValueError, IndexError):
- author = None
- if author:
- author.name = request.POST['author_name']
- author.save()
- selected_choices = []
- for key in request.POST:
- if key.startswith('vote_') and request.POST[key]:
- try:
- id = int(key.split('_')[1])
- vote = Vote.objects.filter(id=id)[0]
- if vote.choice not in choices:
- raise ValueError
- vote.vote = 1
- vote.save()
- except (ValueError, IndexError):
- url = "/".join(request.path.split('/')[:-3])
- url += "?bad_poll=1"
- return HttpResponseRedirect(url)
- selected_choices.append(vote.choice)
- for choice in choices:
- if choice not in selected_choices:
- try:
- v = Vote.objects.filter(voter=author, choice=choice)[0]
- v.vote = 0
- except IndexError:
- v = Vote(voter=author, choice=choice, vote=0)
- v.save()
-
+ # modification of an old vote
+ modifyVote(request, choices)
else:
- author = PollUser(name=request.POST['author_name'])
- author.save()
- selected_choices = []
- for key in request.POST:
- if key.startswith('choice_') and request.POST[key]:
- try:
- id = int(key.split('_')[1])
- choice = Choice.objects.filter(id=id)[0]
- if choice not in choices:
- raise ValueError
- except (ValueError, IndexError):
- url = "/".join(request.path.split('/')[:-3])
- url += "?bad_poll=1"
- return HttpResponseRedirect(url)
- v = Vote(voter=author, choice=choice, vote=1)
- selected_choices.append(choice)
- v.save()
- for choice in choices:
- if choice not in selected_choices:
- v = Vote(voter=author, choice=choice, vote=0)
- v.save()
- votes = []
+ newVote(request, choices)
+
+ # 'voter' is in request.GET when the edit button is pushed
+ if 'voter' in request.GET:
+ try:
+ response_dct['current_voter_id'] = int(request.GET['voter'])
+ except ValueError:
+ pass
+
+ response_dct.update({'choices':choices,
+ 'poll_type_name':poll.getTypeLabel(),
+ 'poll_name':poll.name,
+ 'poll_desc':poll.description})
+ response_dct['base_url'] = "/".join(request.path.split('/')[:-2]) \
+ + '/%s/' % poll.base_url
+
+ # get voters and sum for each choice for this poll
+
+ votes = [] # all votes for this poll
votes = Vote.objects.extra(where=['choice_id IN (%s)' \
% ",".join([str(choice.id) for choice in choices])])
+
voters = []
choices_sum = [0 for choice in choices]
choices_ids = [choice.id for choice in choices]
for vote in votes:
if vote.voter not in voters:
+ # initialize a votes list for the current voter
vote.voter.votes = [None for choice in choices]
voters.append(vote.voter)
voter = vote.voter
else:
+ # get the appropriate voter
voter = voters[voters.index(vote.voter)]
idx = choices_ids.index(vote.choice.id)
+ # associate vote in the votes list of the voter
voter.votes[idx] = vote
- choices_sum[idx] += vote.vote
- response_dct['voters'] = voters
- if 'voter' in request.GET:
- try:
- response_dct['current_voter_id'] = int(request.GET['voter'])
- except ValueError:
- pass
- response_dct['voter'] = voters
- response_dct['choices_sum'] = [str(sum) for sum in choices_sum]
- response_dct['poll_type_name'] = poll.getTypeLabel()
- response_dct['poll_name'] = poll.name
- response_dct['poll_desc'] = poll.description
+ choices_sum[idx] += vote.value
+ # for undefined vote get the choice id
+ # on the template the distinction between the choice and the voter
+ # is made by the type of the "vote"
+ for voter in voters:
+ for vote in voter.votes:
+ if not vote:
+ idx = voter.votes.index(vote)
+ voter.votes[idx] = choices[idx].id
+ response_dct.update({'voters':voters,
+ 'voter':voters,
+ 'choices_sum':[str(sum) for sum in choices_sum]
+ })
return render_to_response('vote.html', response_dct)
diff --git a/static/bg.jpg b/static/bg.jpg
index e603ff8..7653c63 100644
--- a/static/bg.jpg
+++ b/static/bg.jpg
Binary files differ
diff --git a/static/styles.css b/static/styles.css
index 2b88e3c..a5bd11e 100644
--- a/static/styles.css
+++ b/static/styles.css
@@ -10,22 +10,13 @@ font-size:12px;
background-color:#ced3e1;
}
-#main{
-background-color:white;
-border:1px solid;
-margin:20px;
-background-image: url(bg.jpg);
-background-repeat:no-repeat;
-background-position:top right;
-}
-
h1, h1 a{
border:1px solid black;
border-right:None;
border-left:None;
background-color:#6f819d;
color:white;
-padding-left:15px;
+padding-left:10px;
font-size:32px;
text-decoration:None;
}
@@ -41,7 +32,7 @@ font-size:24px;
p{
padding:6px;
margin:6px;
-width:600px;
+max-width:600px;
}
td{
@@ -58,10 +49,33 @@ label{
font-weight:bold;
}
+#main{
+background-color:white;
+border:1px solid;
+margin:20px;
+background-image: url(bg.jpg);
+background-repeat:no-repeat;
+background-position:top right;
+}
+
+.error{
+color:red;
+}
+
+#new_poll input{
+width:130px;
+}
+
+#new_poll textarea{
+width:130px;
+height:100px;
+}
+
.form_description{
background-color:#6f819d;
color:white;
font-size:11px;
+width:200px;
}
#content{
@@ -72,52 +86,52 @@ margin:5px;
overflow:auto;
}
-.error{
-color:red;
-}
-
-table.poll{
+#poll{
text-align:center;
}
-.poll a{
+#poll a{
color:black;
}
-.poll td{
+#poll td{
border:1px solid black;
padding:0;
}
-.poll th{
+#poll td.simple{
+border:None;
+}
+
+#poll th{
background-color:#ced3e1;
border:1px solid black;
padding:5px;
}
-.poll .OK{
+#poll input{
+width:100px;
+}
+
+#poll .OK{
background-color:#9ec5d5;
}
-.poll .OKO{
+#poll .OKO{
background-color:#b689d5;
}
-.poll .KO{
+#poll .KO{
background-color:#b9b3bd;
}
-td.simple{
-border:None;
-}
-
-.sum th{
+#sum th{
background-color:white;
border:None;
text-align:center;
}
-.sum td{
+#sum td{
border:None;
font-weight:bold;
}
diff --git a/templates/createOrEdit.html b/templates/createOrEdit.html
index cee7616..073dcfd 100644
--- a/templates/createOrEdit.html
+++ b/templates/createOrEdit.html
@@ -2,12 +2,12 @@
{% block content %}
{% if not new and not choices %}
- <p class='error'>As long as no option was added to the poll, it will not be made available.</p>
+ <p class='error'>As long as no options were added to the poll, it will not be made available.</p>
{% endif %}
<h2>{% if new %}New{% else %}Edit{% endif %} poll</h2>
{% if error %}<p class='error'>{{ error }}</p>{% endif %}
<form action="{{admin_url}}" method="post">
- <table class='new_poll'>
+ <table id='new_poll'>
{% if not new %}<tr>
<td><label>Poll url</label></td>
<td><a href='http://{{full_base_url}}'>http://{{full_base_url}}</a></td>
@@ -54,7 +54,7 @@
{% for choice in choices %}<tr>
<td>&nbsp;</td><td>{{choice.name}}</td><td><input type='checkbox' name='delete_{{choice.id}}'/></td>
</tr>
- {% endfor %}{% endif %}<tr><td><label>New choice</label></td><td>{{choiceform}}</td></tr>
+ {% endfor %}{% endif %}<tr><td><label>New choice</label></td><td><input type='text' name='new_choice'/></td></tr>
{% endif %}</table>
{% if new %}<input type='hidden' name='new' value='1'/>
<input type='submit' value='Create' />
diff --git a/templates/vote.html b/templates/vote.html
index 19150d2..1b862c4 100644
--- a/templates/vote.html
+++ b/templates/vote.html
@@ -6,7 +6,7 @@
<p>{{poll_desc}}</p>
<form method='post' action='{{base_url}}'>
<div id='poll_table'>
- <table class='poll'>
+ <table id='poll'>
<tr>
<td class='simple'></td>
<td class='simple'></td>
@@ -16,10 +16,10 @@
<input type='hidden' name='voter' value='{{voter.id}}'/>
<td class='simple'></td>
<td><input type='text' name='author_name' value='{{voter.name}}'/></td>
- {% for vote in voter.votes %}<td><input type='checkbox' name='vote_{{vote.id}}'{%ifequal vote.vote 1%} checked='checked'{%endifequal%}/></td>{%endfor%}
+ {% for vote in voter.votes %}<td><input type='checkbox' name='{%if vote.id%}vote_{{vote.id}}{%else%}choice_{{vote}}{%endif%}'{%ifequal vote.value 1%} checked='checked'{%endifequal%}/></td>{%endfor%}
{%else%}<td class='simple'><a href='?voter={{voter.id}}'>Edit</a></td>
<td>{{voter.name}}</td>
- {% for vote in voter.votes %}<td class='{%ifequal vote.vote 1%}OK{%else%}KO{%endifequal%}'>{% ifequal vote.vote 1%}Yes{%else%}No{%endifequal%}</td>
+ {% for vote in voter.votes %}<td class='{%ifequal vote.value 1%}OK{%else%}KO{%endifequal%}'>{% ifequal vote.value 1%}Yes{%else%}No{%endifequal%}</td>
{%endfor%}
{%endifequal%}
</tr>{%endfor%}
@@ -30,7 +30,7 @@
{%for choice in choices%}<td><input type='checkbox' name='choice_{{choice.id}}'/></td>{%endfor%}
</tr>
{%endif%}
- <tr class='sum'>
+ <tr id='sum'>
<td class='simple'></td><th>Sum</th>
{% for sum in choices_sum %}<td>{{sum}}</td>
{% endfor %}