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> <span py:if="'description' in errors" class="error">${errors.description}</span>
</p> </p>
<p> <p>
<input type="submit" value="Create poll" /> <input type="submit" name="submit" value="Create poll" />
<input type="submit" name="cancel" value="Cancel" /> <input type="submit" name="cancel" value="Cancel" />
</p> </p>
</form> </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> <p><a href="${base_url}polls/new" title="Create a new poll">Create a new poll</a></p>
<ul py:if="polls"> <ul py:if="polls">
<li py:for="poll in 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()}) Poll: ${poll.title} (${poll.get_num_of_submissions()}/${poll.get_num_of_submitters()})
</a> </a>
</li> </li>

View file

@ -8,6 +8,7 @@ import forms
import sqlobject import sqlobject
import bobo import bobo
from genshi.template import TemplateLoader from genshi.template import TemplateLoader
import genshi.filters
import genshi import genshi
import formencode import formencode
import uuid import uuid
@ -25,19 +26,46 @@ BASE_DICT = {
"errors": {}, "errors": {},
} }
POLL_SETTINGS = {
"show_all_submissions": (bool, False),
"show_statistics": (bool, True),
}
class WordSubmission(sqlobject.SQLObject): class WordSubmission(sqlobject.SQLObject):
submitter = sqlobject.StringCol() submitter = sqlobject.StringCol()
content = sqlobject.StringCol() content = sqlobject.StringCol()
poll_id = sqlobject.ForeignKey("Poll") poll_id = sqlobject.ForeignKey("Poll")
class PollSetting(sqlobject.SQLObject):
poll_id = sqlobject.ForeignKey("Poll")
key = sqlobject.StringCol()
value = sqlobject.StringCol()
class Poll(sqlobject.SQLObject): class Poll(sqlobject.SQLObject):
author = sqlobject.StringCol() author = sqlobject.StringCol()
hash_key = sqlobject.StringCol() hash_key = sqlobject.StringCol()
admin_hash_key = sqlobject.StringCol()
title = sqlobject.StringCol() title = sqlobject.StringCol()
description = sqlobject.StringCol() description = sqlobject.StringCol()
timestamp_creation = sqlobject.DateTimeCol() 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): def get_num_of_submitters(self):
all_submitters = [submission.submitter for submission in WordSubmission.selectBy(poll_id=self.id)] all_submitters = [submission.submitter for submission in WordSubmission.selectBy(poll_id=self.id)]
unique_submitters = [] unique_submitters = []
@ -52,17 +80,48 @@ class Poll(sqlobject.SQLObject):
def get_url(self): def get_url(self):
return "%spolls/%s" % (BASE_DICT["base_url"], self.hash_key) 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): def get_creation_time_string(self):
return str(self.timestamp_creation) 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): def get_default_values(**kwargs):
value_dict = dict(BASE_DICT) value_dict = dict(BASE_DICT)
for key, value in kwargs.items(): for key, value in kwargs.items():
value_dict[key] = value value_dict[key] = value
return value_dict return value_dict
def render(filename, **values): def render(filename, input_data=None, **values):
return loader.load(filename).generate(**values).render("html", doctype="html") 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): def get_poll_id(hash_key):
polls = Poll.selectBy(hash_key=hash_key) polls = Poll.selectBy(hash_key=hash_key)
@ -71,22 +130,31 @@ def get_poll_id(hash_key):
else: else:
return None 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(): def get_new_hash_key():
hash_key = uuid.uuid4().get_hex() 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() hash_key = uuid.uuid4().get_hex()
return hash_key return hash_key
@bobo.query('/polls/new') @bobo.query('/polls/new')
@bobo.query('/polls/new/:author/:title/:description') @bobo.query('/polls/new/:author/:title/:description')
def create_poll(cancel=False, author=None, title=None, description=None): def new_poll(submit=None, cancel=None, author=None, title=None, description=None):
data = {"author": author, "title": title, "description": description}
value_dict = get_default_values() value_dict = get_default_values()
data = {"author": author, "title": title, "description": description}
if cancel: if cancel:
return bobo.redirect(BASE_DICT["base_url"]) return bobo.redirect(BASE_DICT["base_url"])
elif (author is None) and (title is None) and (description is None): elif not submit:
return render("poll_new.html", **value_dict) # show the "new poll" form
return render("poll_new.html", input_data=data, **value_dict)
else: else:
# create the new poll (if it is valid)
errors = {} errors = {}
try: try:
data = forms.PollForm.to_python(data) data = forms.PollForm.to_python(data)
@ -98,13 +166,75 @@ def create_poll(cancel=False, author=None, title=None, description=None):
else: else:
# create the new poll # create the new poll
hash_key = get_new_hash_key() hash_key = get_new_hash_key()
admin_hash_key = get_new_hash_key()
now = datetime.datetime.now() now = datetime.datetime.now()
new_poll = Poll(hash_key=hash_key, timestamp_creation=now, **data) new_poll = Poll(hash_key=hash_key, admin_hash_key=admin_hash_key, timestamp_creation=now, **data)
return bobo.redirect(new_poll.get_url()) 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('')
@bobo.query('/') def base():
return bobo.redirect(BASE_DICT["base_url"])
@bobo.query('/polls') @bobo.query('/polls')
def base_polls():
return bobo.redirect(BASE_DICT["base_url"] + "polls/")
@bobo.query('/')
@bobo.query('/polls/') @bobo.query('/polls/')
def show_polls(): def show_polls():
value_dict = get_default_values() value_dict = get_default_values()
@ -113,20 +243,28 @@ def show_polls():
@bobo.query('/polls/:poll_hash') @bobo.query('/polls/:poll_hash')
def show_one_poll(poll_hash=None): def show_one_poll(poll_hash=None):
value_dict = get_default_values()
poll_id = get_poll_id(poll_hash) poll_id = get_poll_id(poll_hash)
if not poll_id is None: if not poll_id is None:
value_dict = get_default_values()
value_dict["poll"] = Poll.get(poll_id) value_dict["poll"] = Poll.get(poll_id)
return render("poll_details.html", **value_dict) return render("poll_details.html", **value_dict)
else: else:
return bobo.redirect(BASE_DICT["base_url"]) 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.dropTable()
Poll.createTable() if not table.tableExists():
if not WordSubmission.tableExists(): table.createTable()
WordSubmission.createTable()
for poll in Poll.select(): for poll in Poll.select():
print poll 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__)