added changing of polls

This commit is contained in:
lars 2010-04-15 10:32:45 +00:00
parent f2ef35b429
commit 81df603ba2
6 changed files with 217 additions and 18 deletions

Binary file not shown.

View file

@ -0,0 +1,36 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:py="http://genshi.edgewall.org/">
<xi:include href="layout.html" />
<head>
<title>Poll settings</title>
</head>
<body>
<h1>Poll properties</h1>
<form action="" method="post">
<p>
<label for="author">Your name:</label>
<input type="text" id="author" name="author" />
<span py:if="'author' in errors" class="error">${errors.author}</span>
</p>
<p>
<label for="title">Poll name:</label>
<input type="text" id="title" name="title" />
<span py:if="'title' in errors" class="error">${errors.title}</span>
</p>
<p>
<label for="description">Description:</label>
<input type="text" id="description" name="description" />
<span py:if="'description' in errors" class="error">${errors.description}</span>
</p>
<p>
<input type="submit" name="submit" value="Save poll" />
<input type="submit" name="cancel" value="Cancel" />
</p>
</form>
</body>
</html>

View file

@ -0,0 +1,25 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:py="http://genshi.edgewall.org/">
<xi:include href="layout.html" />
<head>
<title>Poll details</title>
</head>
<body>
<h1>Poll: ${poll.title}</h1>
<ul>
<li>Author: ${poll.author}</li>
<li>Created: ${poll.get_creation_time_string()}</li>
<li>Description: ${poll.description}</li>
<li>User URL: <a href="${poll.get_url()}" title="link of this poll">${poll.get_url()}</a></li>
<li>Administrative URL: <a href="${poll.get_admin_url()}" title="link for managing this poll">${poll.get_admin_url()}</a></li>
<li py:if="poll.get_settings()">Settings:<ul>
<li py:for="key, value in poll.get_settings().items()">${key}: ${value}</li>
</ul></li>
<li><a href="${poll.get_edit_url()}" title="edit this poll">Edit this poll</a></li>
</ul>
</body>
</html>

View file

@ -26,7 +26,7 @@
<span py:if="'description' in errors" class="error">${errors.description}</span>
</p>
<p>
<input type="submit" value="Create poll" />
<input type="submit" name="submit" value="Create poll" />
<input type="submit" name="cancel" value="Cancel" />
</p>
</form>

View file

@ -17,7 +17,7 @@
<p><a href="${base_url}polls/new" title="Create a new poll">Create a new poll</a></p>
<ul py:if="polls">
<li py:for="poll in polls">
<a href="${poll.get_url()}" title="Details of poll ${poll.title}">
<a href="${poll.get_admin_url()}" title="Details of poll ${poll.title}">
Poll: ${poll.title} (${poll.get_num_of_submissions()}/${poll.get_num_of_submitters()})
</a>
</li>

View file

@ -8,6 +8,7 @@ import forms
import sqlobject
import bobo
from genshi.template import TemplateLoader
import genshi.filters
import genshi
import formencode
import uuid
@ -25,19 +26,46 @@ BASE_DICT = {
"errors": {},
}
POLL_SETTINGS = {
"show_all_submissions": (bool, False),
"show_statistics": (bool, True),
}
class WordSubmission(sqlobject.SQLObject):
submitter = sqlobject.StringCol()
content = sqlobject.StringCol()
poll_id = sqlobject.ForeignKey("Poll")
class PollSetting(sqlobject.SQLObject):
poll_id = sqlobject.ForeignKey("Poll")
key = sqlobject.StringCol()
value = sqlobject.StringCol()
class Poll(sqlobject.SQLObject):
author = sqlobject.StringCol()
hash_key = sqlobject.StringCol()
admin_hash_key = sqlobject.StringCol()
title = sqlobject.StringCol()
description = sqlobject.StringCol()
timestamp_creation = sqlobject.DateTimeCol()
def get_settings(self):
current_dict = {}
for setting in PollSetting.selectBy(poll_id=self.id):
if setting.key in POLL_SETTINGS.keys():
current_dict[setting.key] = self.validate_poll_setting(setting.key, setting.value)
for key, meta_info in POLL_SETTINGS.items():
if not key in current_dict.keys():
current_dict[key] = meta_info[1]
return current_dict
def change_setting(self, key, value):
validated_value = self.validate_poll_setting(key, value)
if not validated_value is None:
poll_setting = PollSetting.selectBy(poll_id=self.id, key=key)
if poll_setting.count() == 1:
poll_setting.value = str(validated_value)
def get_num_of_submitters(self):
all_submitters = [submission.submitter for submission in WordSubmission.selectBy(poll_id=self.id)]
unique_submitters = []
@ -52,17 +80,48 @@ class Poll(sqlobject.SQLObject):
def get_url(self):
return "%spolls/%s" % (BASE_DICT["base_url"], self.hash_key)
def get_admin_url(self):
return "%spolls/%s" % (BASE_DICT["base_url"], self.admin_hash_key)
def get_edit_url(self):
return "%spolls/%s/admin" % (BASE_DICT["base_url"], self.admin_hash_key)
def get_creation_time_string(self):
return str(self.timestamp_creation)
def validate_poll_setting(key, value):
if not key in POLL_SETTINGS.keys():
return None
setting_type = POLL_SETTINGS[key][0]
if setting_type in (basestring, unicode, str):
return value
elif setting_type == bool:
text = value.tolower()
if text in ("0", "false", "no", "off", "disabled"):
return False
elif text in ("1", "true", "yes", "on", "enabled"):
return True
else:
return None
else:
# all other types (e.g. int, float, ...)
try:
return setting_type(value)
except ValueError:
return None
def get_default_values(**kwargs):
value_dict = dict(BASE_DICT)
for key, value in kwargs.items():
value_dict[key] = value
return value_dict
def render(filename, **values):
return loader.load(filename).generate(**values).render("html", doctype="html")
def render(filename, input_data=None, **values):
stream = loader.load(filename).generate(**values)
if not input_data is None:
stream |= genshi.filters.HTMLFormFiller(data=input_data)
return stream.render("html", doctype="html")
def get_poll_id(hash_key):
polls = Poll.selectBy(hash_key=hash_key)
@ -71,22 +130,31 @@ def get_poll_id(hash_key):
else:
return None
def get_poll_admin_id(hash_key):
polls = Poll.selectBy(admin_hash_key=hash_key)
if polls.count() == 1:
return polls[0].id
else:
return None
def get_new_hash_key():
hash_key = uuid.uuid4().get_hex()
while not get_poll_id(hash_key) is None:
while (not get_poll_id(hash_key) is None) or (not get_poll_admin_id(hash_key) is None):
hash_key = uuid.uuid4().get_hex()
return hash_key
@bobo.query('/polls/new')
@bobo.query('/polls/new/:author/:title/:description')
def create_poll(cancel=False, author=None, title=None, description=None):
data = {"author": author, "title": title, "description": description}
def new_poll(submit=None, cancel=None, author=None, title=None, description=None):
value_dict = get_default_values()
data = {"author": author, "title": title, "description": description}
if cancel:
return bobo.redirect(BASE_DICT["base_url"])
elif (author is None) and (title is None) and (description is None):
return render("poll_new.html", **value_dict)
elif not submit:
# show the "new poll" form
return render("poll_new.html", input_data=data, **value_dict)
else:
# create the new poll (if it is valid)
errors = {}
try:
data = forms.PollForm.to_python(data)
@ -98,13 +166,75 @@ def create_poll(cancel=False, author=None, title=None, description=None):
else:
# create the new poll
hash_key = get_new_hash_key()
admin_hash_key = get_new_hash_key()
now = datetime.datetime.now()
new_poll = Poll(hash_key=hash_key, timestamp_creation=now, **data)
return bobo.redirect(new_poll.get_url())
new_poll = Poll(hash_key=hash_key, admin_hash_key=admin_hash_key, timestamp_creation=now, **data)
return bobo.redirect(new_poll.get_admin_url())
@bobo.query('/polls/:admin_hash_key/admin')
def admin_poll(cancel=False, submit=None, admin_hash_key=None, author=None, title=None, description=None, **kwargs):
value_dict = get_default_values()
data = {"author": author, "title": title, "description": description}
poll_id = get_poll_admin_id(admin_hash_key)
if poll_id is None:
return bobo.redirect(BASE_DICT["base_url"])
poll = Poll.get(poll_id)
# cancel: return to (non-edit) admin page
if cancel:
return bobo.redirect(poll.get_admin_url())
if author is None:
data["author"] = poll.author
if title is None:
data["title"] = poll.title
if description is None:
data["description"] = poll.description
settings = poll.get_settings()
# override with the given settings (taken from the form input with the prefix "setting_")
for setting_key, setting_value in kwargs.items():
if setting_key.startswith("setting_"):
real_key = setting_key[len("setting_"):]
if real_key in POLL_SETTINGS.keys():
valid_value = validate_poll_setting(real_key, setting_value)
if not valid_value is None:
settings[real_key] = valid_value
# store the new settings or create the new poll
errors = {}
if submit:
# check for errors only if the content is submitted (not just rendered)
try:
data = forms.PollForm.to_python(data)
except formencode.Invalid, errors_packed:
errors = errors_packed.unpack_errors()
# add "settings" after forms validation - since there is no destination type
data["settings"] = settings
# the admin hash should also not be validated - thus we may not add it before
if errors:
value_dict["errors"] = errors
return render("poll_admin.html", input_data=data, **value_dict)
else:
if submit:
# update core attributes of the existing poll
poll.author = data["author"]
poll.title = data["title"]
poll.description = data["description"]
current_settings = poll.get_settings()
# update settings
for key, value in settings.items():
if current_settings[key] != value:
poll.change_setting(key, value)
return bobo.redirect(poll.get_admin_url())
else:
return render("poll_admin.html", input_data=data, **value_dict)
@bobo.query('')
@bobo.query('/')
def base():
return bobo.redirect(BASE_DICT["base_url"])
@bobo.query('/polls')
def base_polls():
return bobo.redirect(BASE_DICT["base_url"] + "polls/")
@bobo.query('/')
@bobo.query('/polls/')
def show_polls():
value_dict = get_default_values()
@ -113,20 +243,28 @@ def show_polls():
@bobo.query('/polls/:poll_hash')
def show_one_poll(poll_hash=None):
value_dict = get_default_values()
poll_id = get_poll_id(poll_hash)
if not poll_id is None:
value_dict = get_default_values()
value_dict["poll"] = Poll.get(poll_id)
return render("poll_details.html", **value_dict)
else:
admin_poll_id = get_poll_admin_id(poll_hash)
if not admin_poll_id is None:
value_dict["poll"] = Poll.get(admin_poll_id)
return render("poll_admin_details.html", **value_dict)
else:
return bobo.redirect(BASE_DICT["base_url"])
if not Poll.tableExists():
for table in (Poll, WordSubmission, PollSetting):
#Poll.dropTable()
Poll.createTable()
if not WordSubmission.tableExists():
WordSubmission.createTable()
if not table.tableExists():
table.createTable()
for poll in Poll.select():
print poll
# this line allows to use wortschlucker with mod_wsgi
# see: http://groups.google.com/group/bobo-web/msg/2ba55fc381658cd1
#application = bobo.Application(bobo_resources=__name__)