diff --git a/wortschlucker/src/wortschlucker.py b/wortschlucker/src/wortschlucker.py
index f46b2a2..b7feb9b 100755
--- a/wortschlucker/src/wortschlucker.py
+++ b/wortschlucker/src/wortschlucker.py
@@ -18,6 +18,7 @@ import genshi.template
import genshi
import formencode
import webob
+import csv
import ConfigParser
import datetime
import mimetypes
@@ -49,6 +50,10 @@ BASE_DICT = {
# used as the default setting for expose/close dates
DEFAULT_DAYS_AHEAD = 7
DATE_FORMAT = "%d.%m.%Y"
+EXPORT_DATE_FORMAT = "%d.%m.%Y %H:%M:%S"
+EXPORT_ENCODING = "utf-8"
+EXPORT_CHARSET = "utf8"
+EXPORT_FILENAME_TEMPLATE = "wortschlucker_%%s_%s.csv" % datetime.datetime.now().strftime("%Y-%m-%d")
DEFAULT_DATE = datetime.datetime.now() + datetime.timedelta(days=DEFAULT_DAYS_AHEAD)
POLL_SETTINGS = {
@@ -163,15 +168,19 @@ class Poll(sqlobject.SQLObject):
def announce_via_twitter(self):
complete_url = self.get_url(absolute=True)
- title = "%s %s %s" % (config.get('misc', 'twitter_alert_prefix'),
- self.title[:79], complete_url)
- # the following line is quick and dirty fix for the unicode bug twitter exception.
- # of course it would be better to preserve the umlauts somehow...
- title = title.encode('ascii','ignore')
- twitter_key = config.get('misc', 'twitter_consumer_key')
- twitter_secret = config.get('misc', 'twitter_consumer_secret')
- twitter_access_key = config.get('misc', 'twitter_access_token_key')
- twitter_access_secret = config.get('misc', 'twitter_access_token_secret')
+ try:
+ title = "%s %s %s" % (config.get('misc', 'twitter_alert_prefix'),
+ self.title[:79], complete_url)
+ # the following line is quick and dirty fix for the unicode bug twitter exception.
+ # of course it would be better to preserve the umlauts somehow...
+ title = title.encode('ascii','ignore')
+ twitter_key = config.get('misc', 'twitter_consumer_key')
+ twitter_secret = config.get('misc', 'twitter_consumer_secret')
+ twitter_access_key = config.get('misc', 'twitter_access_token_key')
+ twitter_access_secret = config.get('misc', 'twitter_access_token_secret')
+ except ConfigParser.Error:
+ # a config setting seems to be missing (e.g. in a dev environment)
+ return
publish_twitter_alert(title, twitter_key, twitter_secret, twitter_access_key, twitter_access_secret)
def get_num_of_submitters(self):
@@ -186,7 +195,7 @@ class Poll(sqlobject.SQLObject):
return ContentSubmission.selectBy(poll_id=self.id).count()
def get_submissions(self):
- return ContentSubmission.selectBy(poll_id=self.id)
+ return ContentSubmission.selectBy(poll_id=self.id).orderBy("timestamp_creation")
def delete_poll(self):
submissions = ContentSubmission.selectBy(poll_id=self.id)
@@ -249,11 +258,14 @@ def get_markup_with_links(text):
short_name = url.split("/")[2]
return """%s%s%s""" % (prefix, url, short_name, suffix)
# surround all urls with html markup
- text = re.sub(r"(\A|\s|\()(https?://[\w/\?\.\#=;,_\-\~&]*)(\)|\s|\Z)",
+ text = re.sub(r"(\A|\s|\()(https?://[\w/\?\.\#=;,_\-\~&]*)(\)|\s|\Z)",
get_link_markup, text)
- text = text.replace("\r\n","\n")
- text = text.replace("\r","\n")
- text = text.replace("\n","
")
+ return get_markup_with_formatted_linebreaks(text, "
")
+
+def get_markup_with_formatted_linebreaks(text, break_char):
+ text = text.replace("\r\n", "\n")
+ text = text.replace("\r", "\n")
+ text = text.replace("\n", break_char)
return text
def get_poll_setting_string(key, value):
@@ -514,6 +526,33 @@ def delete_submission(admin_hash_key=None, submission_id_digest=None):
break
return bobo.redirect(poll.get_admin_url())
+@bobo.query('/:admin_hash_key/export')
+def export_poll(admin_hash_key=None):
+ """ Return a download file in csv format (date, author, text).
+ """
+ value_dict = get_default_values()
+ 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)
+ response = webob.Response(content_type="text/csv", charset=EXPORT_CHARSET)
+ # common (excel-based) CSV format with semicolons instead of commas
+ writer = csv.writer(response.body_file, delimiter=";")
+ submissions = list(poll.get_submissions())
+ for submission in submissions:
+ timestamp = submission.timestamp_creation.strftime(EXPORT_DATE_FORMAT)
+ author = submission.submitter.encode(EXPORT_ENCODING, "ignore")
+ content = get_markup_with_formatted_linebreaks(submission.content, os.linesep)
+ items = [timestamp, author, content]
+ for index in range(len(items)):
+ items[index] = items[index].encode(EXPORT_ENCODING, "ignore")
+ writer.writerow(items)
+ filename = EXPORT_FILENAME_TEMPLATE % poll.title
+ filename = filename.replace(" ", "_")
+ filename = re.sub(r"[^a-zA-Z0-9_\-\.]", "", filename)
+ response.content_disposition = 'attachment; filename=%s' % filename
+ return response
+
@bobo.query('/:admin_hash_key/admin')
def admin_poll(cancel=False, submit=None, admin_hash_key=None, author=None,
title=None, description=None, settings=None,