Add support for surveys

This commit is contained in:
Magnus Hagander
2009-12-28 16:12:44 +01:00
parent 3aa6730487
commit 2f671fe3d6
9 changed files with 227 additions and 11 deletions

View File

@ -13,6 +13,9 @@ from events.models import Event
from quotes.models import Quote from quotes.models import Quote
from models import Version from models import Version
# models needed for the pieces on the community page
from survey.models import Survey
# models and forms needed for core objects # models and forms needed for core objects
from models import Organisation from models import Organisation
from forms import OrganisationForm from forms import OrganisationForm
@ -32,6 +35,16 @@ def home(request):
'versions': versions, 'versions': versions,
}) })
# Community main page (contains surveys and potentially more)
def community(request):
s = Survey.objects.filter(current=True)
try:
s = s[0]
except:
s = None
return render_to_response('core/community.html', {
'survey': s,
}, NavContext(request, 'community'))
# Generic fallback view for static pages # Generic fallback view for static pages
def fallback(request, url): def fallback(request, url):

View File

@ -102,6 +102,7 @@ INSTALLED_APPS = [
'pgweb.profserv', 'pgweb.profserv',
'pgweb.lists', 'pgweb.lists',
'pgweb.sponsors', 'pgweb.sponsors',
'pgweb.survey',
] ]

0
pgweb/survey/__init__.py Normal file
View File

15
pgweb/survey/admin.py Normal file
View File

@ -0,0 +1,15 @@
from django.contrib import admin
from models import *
class SurveyAdmin(admin.ModelAdmin):
list_display = ('question','posted','current',)
ordering = ('-posted',)
class SurveyAnswerAdmin(admin.ModelAdmin):
list_display = ('survey','tot1','tot2','tot3','tot4','tot5','tot6','tot7','tot8')
ordering = ('-survey__posted',)
admin.site.register(Survey, SurveyAdmin)
admin.site.register(SurveyLock)
admin.site.register(SurveyAnswer, SurveyAnswerAdmin)

95
pgweb/survey/models.py Normal file
View File

@ -0,0 +1,95 @@
from django.db import models
from django.contrib.auth.models import User
from datetime import datetime
# internal text/value object
class SurveyQuestion(object):
def __init__(self, value, text):
self.value = value
self.text = text
class SurveyAnswerValues(object):
def __init__(self, option, votes, votespercent):
self.option = option
self.votes = votes
self.votespercent = votespercent
class Survey(models.Model):
question = models.CharField(max_length=100, null=False, blank=False)
opt1 = models.CharField(max_length=100, null=False, blank=False)
opt2 = models.CharField(max_length=100, null=False, blank=False)
opt3 = models.CharField(max_length=100, null=False, blank=True)
opt4 = models.CharField(max_length=100, null=False, blank=True)
opt5 = models.CharField(max_length=100, null=False, blank=True)
opt6 = models.CharField(max_length=100, null=False, blank=True)
opt7 = models.CharField(max_length=100, null=False, blank=True)
opt8 = models.CharField(max_length=100, null=False, blank=True)
posted = models.DateTimeField(null=False, default=datetime.now)
current = models.BooleanField(null=False, default=False)
def __unicode__(self):
return self.question
@property
def questions(self):
for i in range (1,9):
v = getattr(self, "opt%s" % i)
if not v: break
yield SurveyQuestion(i, v)
@property
def answers(self):
if not hasattr(self, "_answers"):
self._answers = SurveyAnswer.objects.get_or_create(survey=self)[0]
return self._answers
@property
def completeanswers(self):
for a in self._get_complete_answers():
yield SurveyAnswerValues(a[0], a[1], self.totalvotes>0 and (100*a[1]/self.totalvotes) or 0)
@property
def totalvotes(self):
if not hasattr(self,"_totalvotes"):
self._totalvotes = 0
for a in self._get_complete_answers():
self._totalvotes = self._totalvotes + a[1]
return self._totalvotes
def _get_complete_answers(self):
for i in range(1,9):
q = getattr(self, "opt%s" % i)
if not q: break
n = getattr(self.answers, "tot%s" % i)
yield (q,n)
def save(self):
# Make sure only one survey at a time can be the current one
# (there may be some small race conditions here, but the likelyhood
# that two admins are editing the surveys at the same time...)
if self.current:
previous = Survey.objects.filter(current=True)
for p in previous:
if not p == self:
p.current = False
p.save() # primary key check avoids recursion
# Now that we've made any previously current ones non-current, we are
# free to save this one.
super(Survey, self).save()
class SurveyAnswer(models.Model):
survey = models.ForeignKey(Survey, null=False, blank=False, primary_key=True)
tot1 = models.IntegerField(null=False, default=0)
tot2 = models.IntegerField(null=False, default=0)
tot3 = models.IntegerField(null=False, default=0)
tot4 = models.IntegerField(null=False, default=0)
tot5 = models.IntegerField(null=False, default=0)
tot6 = models.IntegerField(null=False, default=0)
tot7 = models.IntegerField(null=False, default=0)
tot8 = models.IntegerField(null=False, default=0)
class SurveyLock(models.Model):
ipaddr = models.IPAddressField(null=False, blank=False)
time = models.DateTimeField(null=False, default=datetime.now)

56
pgweb/survey/views.py Normal file
View File

@ -0,0 +1,56 @@
from django.shortcuts import render_to_response, get_object_or_404
from django.http import HttpResponse, Http404, HttpResponseServerError, HttpResponseRedirect
from django.db import connection
from pgweb.util.contexts import NavContext
from models import Survey, SurveyAnswer, SurveyLock
def results(request, surveyid, junk=None):
survey = get_object_or_404(Survey, pk=surveyid)
surveylist = Survey.objects.all()
return render_to_response('survey/results.html', {
'survey': survey,
'surveylist': surveylist,
}, NavContext(request, 'community'))
def vote(request, surveyid):
# Check that we have a valid answer number
try:
ansnum = int(request.POST['answer'])
if ansnum < 1 or ansnum > 8:
return HttpResponseServerError("Invalid answer")
except:
return HttpResponseServerError("Unable to determine answer")
attrname = "tot%s" % ansnum
# Do IP based locking...
try:
addr = request.META.get('REMOTE_ADDR')
if addr == None or addr == "":
raise Exception()
except:
return HttpResponseServerError("Unable to determine client IP address")
# Clean out any old junk
curs = connection.cursor()
curs.execute("DELETE FROM survey_surveylock WHERE (\"time\" + '15 minutes') < now()")
# Check if we are locked
lock = SurveyLock.objects.filter(ipaddr=addr)
if len(lock) > 0:
return HttpResponseServerError("Too many requests from your IP in the past 15 minutes")
# Generate a new lock item, and store it
lock = SurveyLock(ipaddr=addr)
lock.save()
# Only now do we bother actually finding out if the survey exists...
surv = get_object_or_404(Survey, pk=surveyid)
answers = SurveyAnswer.objects.get_or_create(survey=surv)[0]
setattr(answers, attrname, getattr(answers, attrname)+1)
answers.save()
return HttpResponseRedirect("/community/survey/%s/" % ansnum)

View File

@ -33,9 +33,12 @@ urlpatterns = patterns('',
(r'^download/products/(\d+)(-.*)?/$', 'downloads.views.productlist'), (r'^download/products/(\d+)(-.*)?/$', 'downloads.views.productlist'),
(r'^docs/(current|\d\.\d)/(static|interactive)/(.*).html$', 'docs.views.docpage'), (r'^docs/(current|\d\.\d)/(static|interactive)/(.*).html$', 'docs.views.docpage'),
(r'^community/$', 'core.views.community'),
(r'^community/contributors/$', 'contributors.views.completelist'), (r'^community/contributors/$', 'contributors.views.completelist'),
(r'^community/lists/$', 'lists.views.root'), (r'^community/lists/$', 'lists.views.root'),
(r'^community/survey/vote/(\d+)/$', 'survey.views.vote'),
(r'^community/survey[/\.](\d+)(-.*)?/$', 'survey.views.results'),
(r'^support/professional_(support|hosting)/$', 'profserv.views.root'), (r'^support/professional_(support|hosting)/$', 'profserv.views.root'),
(r'^support/professional_(support|hosting)[/_](.*)/$', 'profserv.views.region'), (r'^support/professional_(support|hosting)[/_](.*)/$', 'profserv.views.region'),

View File

@ -11,30 +11,29 @@
</div> </div>
</div> </div>
<!-- BEGIN survey_block --> {%if survey%}
<div id="pgSurveyWrap"> <div id="pgSurveyWrap">
<div id="pgSurvey"> <div id="pgSurvey">
<dl> <dl>
<dt>User Survey</dt> <dt>User Survey</dt>
<dd>{survey_question}</dd> <dd>{{survey.question}}</dd>
<dd> <dd>
<form method="post" action="{master_server}/vote"> <form method="post" action="/community/survey/vote/{{survey.id}}/">
<p> <p>
<input type="hidden" name="action" value="vote"/> {%for q in survey.questions%}
<input type="hidden" name="surveyid" value="{survey_id}"/> <input type="radio" name="answer" value="{{q.value}}" id="surv_opt_{{q.value}}" /><label for="surv_opt_{{q.value}}">{{q.text}}</label><br />
<!-- BEGIN survey_option_loop --> {%endfor%}
<input type="radio" name="answer" value="{option_num}" id="surv_opt_{option_num}" /><label for="surv_opt_{option_num}">{option_text}</label><br />
<!-- END survey_option_loop -->
</p> </p>
<p><input id="surveySubmit" type="submit" name="submit" value="Vote" /></p> <p><input id="surveySubmit" type="submit" name="submit" value="Vote" /></p>
</form> </form>
</dd> </dd>
<dd><a href="/community/survey.{survey_id}">Results</a></dd> <dd><a href="/community/survey/{{survey.id}}-{{survey|slugify}}/">Results</a></dd>
</dl> </dl>
</div> </div>
</div> </div>
<!-- END survey_block --> {%endif%}
<p>FIXME</p>
<!-- BEGIN planet_block --> <!-- BEGIN planet_block -->
<div id="pgPlanetWrap"> <div id="pgPlanetWrap">
<div id="pgPlanet"> <div id="pgPlanet">

View File

@ -0,0 +1,34 @@
{%extends "base/page.html"%}
{%block title%}Survey Results: {{survey}}{%endblock%}
{%block contents%}
<h1>Survey Results</h1>
<p>The current results of our <b>{{survey}}</b> survey are:</p>
<div class="tblBasic">
<table border="0" cellpadding="0" cellspacing="0" class="tblBasicGrey">
<tr>
<th class="colFirst">Answer</th>
<th class="colMid">Responses</th>
<th class="colLast">Percentage</th>
</tr>
{%for a in survey.completeanswers%}
<tr>
<td class="colFirst">{{a.option}}</td>
<td class="colMid">{{a.votes}}</td>
<td class="colLast">{{a.votespercent}}%</td>
</tr>
{%endfor%}
<tr class="lastrow">
<td class="colFirst"><b>Total</b></td>
<td class="colMid">{{survey.totalvotes}}</td>
<td class="colLast"></td>
</tr>
</table>
<h2>Other Surveys</h2>
<ul>
{%for s in surveylist%}
<li><a href="/community/survey/{{s.id}}-{{s.question|slugify}}/">{{s.question}}</a></li>
{%endfor%}
</ul>
{%endblock%}