From 81df603ba22eb640cb4fbd9ec036675e0d1b199c Mon Sep 17 00:00:00 2001 From: lars Date: Thu, 15 Apr 2010 10:32:45 +0000 Subject: [PATCH] added changing of polls --- wortschlucker/database.sqlite | Bin 3072 -> 4096 bytes wortschlucker/templates/poll_admin.html | 36 ++++ .../templates/poll_admin_details.html | 25 +++ wortschlucker/templates/poll_new.html | 2 +- wortschlucker/templates/polls.html | 2 +- wortschlucker/wortschlucker.py | 170 ++++++++++++++++-- 6 files changed, 217 insertions(+), 18 deletions(-) create mode 100644 wortschlucker/templates/poll_admin.html create mode 100644 wortschlucker/templates/poll_admin_details.html diff --git a/wortschlucker/database.sqlite b/wortschlucker/database.sqlite index 384bdb4b8d21f2819472fc882767a03214091112..04c9929b4c1fc1ffbcddb3b705250e6c76e5ac6d 100644 GIT binary patch delta 658 zcmaKq%W4!s6o#iSIL#n}$}l2`1u{rv0(HMML7Yf$LS`ega3O@Mu4;2>yJNb?ATB1! z6Bq^rw=Ui04P5&!zJfIqkx|6MS)9XvsPCMgI=goUKHk3*h|ZtUy&P@zq9EynpM&o~ za{2bt_?Okn$--4TQs5;RidK`WY z)z$5IBb?W9(&&7CkF6+AoqPAeimu39$s8HUxggYGtf15y3zS1hm3Kgq|LdOhYHQz>W&QLom`oWy@*lu^ z+rNet&={*RH^M)T9Mi~Jy@M#siG_kN`OkqheR<&0RB)=BbsA0?OfmYB#6Eulh0d;! delta 227 zcmZorXpop7CB(qafC^Y9>ez5FF+OErn#uTdvmi?;BUhs#GrPE`C}WfBr0RRrkHL3sr diff --git a/wortschlucker/templates/poll_admin.html b/wortschlucker/templates/poll_admin.html new file mode 100644 index 0000000..07cf631 --- /dev/null +++ b/wortschlucker/templates/poll_admin.html @@ -0,0 +1,36 @@ + + + + + + Poll settings + + +

Poll properties

+
+

+ + + ${errors.author} +

+

+ + + ${errors.title} +

+

+ + + ${errors.description} +

+

+ + +

+
+ + + + diff --git a/wortschlucker/templates/poll_admin_details.html b/wortschlucker/templates/poll_admin_details.html new file mode 100644 index 0000000..50bc869 --- /dev/null +++ b/wortschlucker/templates/poll_admin_details.html @@ -0,0 +1,25 @@ + + + + + + Poll details + + +

Poll: ${poll.title}

+ + + + diff --git a/wortschlucker/templates/poll_new.html b/wortschlucker/templates/poll_new.html index c096f7f..ca27017 100644 --- a/wortschlucker/templates/poll_new.html +++ b/wortschlucker/templates/poll_new.html @@ -26,7 +26,7 @@ ${errors.description}

- +

diff --git a/wortschlucker/templates/polls.html b/wortschlucker/templates/polls.html index a808421..d2f465d 100644 --- a/wortschlucker/templates/polls.html +++ b/wortschlucker/templates/polls.html @@ -17,7 +17,7 @@

Create a new poll

  • - + Poll: ${poll.title} (${poll.get_num_of_submissions()}/${poll.get_num_of_submitters()})
  • diff --git a/wortschlucker/wortschlucker.py b/wortschlucker/wortschlucker.py index 2fd5ad3..8bca1cf 100755 --- a/wortschlucker/wortschlucker.py +++ b/wortschlucker/wortschlucker.py @@ -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: - 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.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__) +