implemented UI part of Condorcet voting
This commit is contained in:
parent
1a48b80734
commit
20fcc6c9a2
2 changed files with 96 additions and 17 deletions
|
@ -17,6 +17,10 @@ class SubmitForm(formencode.Schema):
|
|||
submitter = formencode.validators.UnicodeString(strip=True, not_empty=True)
|
||||
content = formencode.validators.UnicodeString(strip=True, not_empty=True)
|
||||
|
||||
class VoteSubmissionOrderForm(formencode.Schema):
|
||||
submitter = formencode.validators.UnicodeString(strip=True, not_empty=True)
|
||||
vote_order = formencode.validators.UnicodeString(strip=True)
|
||||
|
||||
class ProfileForm(formencode.Schema):
|
||||
email = formencode.validators.Email(resolve_domain=True, strip=True, not_empty=True)
|
||||
|
||||
|
|
|
@ -104,6 +104,12 @@ class ContentSubmission(sqlobject.SQLObject):
|
|||
return hashlib.md5(str(self.id)).hexdigest()
|
||||
|
||||
|
||||
class VoteOrder(sqlobject.SQLObject):
|
||||
submitter = sqlobject.UnicodeCol()
|
||||
content_submission_id = sqlobject.ForeignKey("ContentSubmission")
|
||||
priority = sqlobject.IntCol()
|
||||
|
||||
|
||||
class Profile(sqlobject.SQLObject):
|
||||
email = sqlobject.UnicodeCol(unique=True)
|
||||
hash_key = sqlobject.StringCol(unique=True)
|
||||
|
@ -198,6 +204,14 @@ class Poll(sqlobject.SQLObject):
|
|||
if (key == 'public') and (value > 0):
|
||||
self.announce_via_twitter()
|
||||
|
||||
def get_ordered_submissions(self, submitter):
|
||||
votes = []
|
||||
for submission in ContentSubmission.selectBy(poll_id=self.id):
|
||||
votes.extend(list(VoteOrder.selectBy(content_submission_id=submission,
|
||||
submitter=submitter)))
|
||||
votes.sort(key=lambda item: item.priority)
|
||||
return [order.content_submission_id for order in votes]
|
||||
|
||||
def announce_via_twitter(self):
|
||||
complete_url = self.get_url(absolute=True)
|
||||
try:
|
||||
|
@ -215,6 +229,14 @@ class Poll(sqlobject.SQLObject):
|
|||
return
|
||||
publish_twitter_alert(title, twitter_key, twitter_secret, twitter_access_key, twitter_access_secret)
|
||||
|
||||
def get_num_of_votes(self):
|
||||
submitters = []
|
||||
for submission in ContentSubmission.selectBy(poll_id=self.id):
|
||||
for vote in VoteOrder.selectBy(content_submission_id=submission):
|
||||
if not vote.submitter in submitters:
|
||||
submitters.append(vote.submitter)
|
||||
return len(submitters)
|
||||
|
||||
def get_num_of_submitters(self):
|
||||
all_submitters = [submission.submitter for submission in ContentSubmission.selectBy(poll_id=self.id)]
|
||||
unique_submitters = []
|
||||
|
@ -245,8 +267,7 @@ class Poll(sqlobject.SQLObject):
|
|||
return get_url_string("%s%s/submit" % (BASE_DICT["base_url"], self.hash_key), absolute)
|
||||
|
||||
def get_vote_url(self, absolute=False):
|
||||
#TODO vote: Diese Funktion ist noch falsch, aber erstmal als Platzhalter noetig
|
||||
return ""
|
||||
return get_url_string("%s%s/vote" % (BASE_DICT["base_url"], self.hash_key), absolute)
|
||||
|
||||
def get_admin_url(self, absolute=False, suffix=""):
|
||||
return get_url_string("%s%s%s" % (BASE_DICT["base_url"], self.admin_hash_key, suffix), absolute)
|
||||
|
@ -266,6 +287,9 @@ class Poll(sqlobject.SQLObject):
|
|||
def is_vote_enabled(self):
|
||||
return self.get_settings()["vote_enabled"]
|
||||
|
||||
def is_vote_finished(self, submitter):
|
||||
return len(self.get_ordered_submissions(submitter)) > 0
|
||||
|
||||
def get_submissions_visibility(self):
|
||||
settings = self.get_settings()
|
||||
return bool(settings["show_all_submissions"] or (settings["expose_date"] and \
|
||||
|
@ -553,15 +577,24 @@ def publish_twitter_alert(text, key, secret,access_key,access_secret):
|
|||
except urllib2.URLError, e:
|
||||
print e.reason
|
||||
|
||||
def check_spam_submitter_name(name):
|
||||
def is_spam_submitter_name(name, errors_dict):
|
||||
lower_text = re.sub("[^a-z]", "", name)
|
||||
upper_text = re.sub("[^A-Z]", "", name)
|
||||
return (len(lower_text) + len(upper_text) == len(name)) and \
|
||||
if (len(lower_text) + len(upper_text) == len(name)) and \
|
||||
(len(lower_text) > 3) and (len(upper_text) > 3) and \
|
||||
(len(name) >= 8) and (not name.startswith(upper_text))
|
||||
(len(name) >= 8) and (not name.startswith(upper_text)):
|
||||
errors_dict["submitter"] = "Spam-Verdacht: bitte den Namen korrigieren"
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
def check_spam_content(text):
|
||||
return bool(re.search(r"(<a\s|\shref=|</a>)", text.lower()))
|
||||
def is_spam_content(text, errors_dict):
|
||||
if re.search(r"(<a\s|\shref=|</a>)", text.lower()):
|
||||
errors_dict["content"] = \
|
||||
"Spam-Verdacht: Inhalt darf keine HTML-Tags enthalten"
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
@bobo.query('/profile/logout')
|
||||
def user_logout(bobo_request):
|
||||
|
@ -738,20 +771,61 @@ def new_poll(bobo_request, submit=None, cancel=None, author=None, title=None,
|
|||
new_poll.change_setting(key, value)
|
||||
return bobo.redirect(new_poll.get_admin_url())
|
||||
|
||||
@bobo.query('/:hash_key/vote')
|
||||
def vote_submission_order(bobo_request, hash_key=None, submitter=None,
|
||||
vote_order=None):
|
||||
value_dict = get_default_values(bobo_request)
|
||||
value_dict["errors"] = {}
|
||||
data = {}
|
||||
if submitter and is_spam_submitter_name(submitter, value_dict["errors"]):
|
||||
data["submitter"] = submitter.strip()
|
||||
if vote_order:
|
||||
data["vote_order"] = vote_order
|
||||
else:
|
||||
data["vote_order"] = ""
|
||||
poll_id = get_poll_id(hash_key)
|
||||
if not poll_id is None:
|
||||
poll = Poll.get(poll_id)
|
||||
value_dict["poll"] = poll
|
||||
try:
|
||||
data = forms.VoteSubmissionOrderForm.to_python(data)
|
||||
except formencode.Invalid, errors_packed:
|
||||
# merge errors with previous ones - but never overwrite existing ones
|
||||
errors = errors_packed.unpack_errors()
|
||||
errors.update(value_dict["errors"])
|
||||
value_dict["errors"] = errors
|
||||
if value_dict["errors"] or poll.is_closed() or \
|
||||
not poll.is_vote_enabled():
|
||||
# ignore silently
|
||||
pass
|
||||
elif poll.is_vote_finished(submitter):
|
||||
# there is already a vote stored for that submitter name
|
||||
value_dict["errors"]["submit"] = \
|
||||
"Fehler: deine Wahl wurde bereits gespeichert."
|
||||
else:
|
||||
# store this order of items
|
||||
digest_dict = {}
|
||||
for submission in ContentSubmission.selectBy(poll_id=poll.id):
|
||||
digest_dict[submission.get_obfuscated_digest()] = submission
|
||||
vote_order = vote_order.split()
|
||||
for index, digest in enumerate(vote_order):
|
||||
if digest in digest_dict:
|
||||
VoteOrder(submitter=submitter, priority=index,
|
||||
content_submission_id=digest_dict[digest])
|
||||
#value_dict["errors"]["submit"] = str(poll.get_ordered_submissions(submitter))
|
||||
value_dict["submitter"] = submitter
|
||||
return render("poll_details.html", input_data=data, **value_dict)
|
||||
else:
|
||||
return bobo.redirect(BASE_DICT["base_url"])
|
||||
|
||||
@bobo.query('/:hash_key/submit')
|
||||
def submit_content(bobo_request, hash_key=None, submitter=None, content=None):
|
||||
value_dict = get_default_values(bobo_request)
|
||||
value_dict["errors"] = {}
|
||||
data = {}
|
||||
if content and check_spam_content(content):
|
||||
value_dict["errors"]["content"] = \
|
||||
"Spam-Verdacht: Inhalt darf keine HTML-Tags enthalten"
|
||||
else:
|
||||
if content and is_spam_content(content, value_dict["errors"]):
|
||||
data["content"] = content
|
||||
if submitter and check_spam_submitter_name(submitter):
|
||||
value_dict["errors"]["submitter"] = \
|
||||
"Spam-Verdacht: bitte den Namen korrigieren"
|
||||
else:
|
||||
if submitter and is_spam_submitter_name(submitter, value_dict["errors"]):
|
||||
data["submitter"] = submitter
|
||||
poll_id = get_poll_id(hash_key)
|
||||
if not poll_id is None:
|
||||
|
@ -774,6 +848,7 @@ def submit_content(bobo_request, hash_key=None, submitter=None, content=None):
|
|||
# remove "content" for the next input
|
||||
del data["content"]
|
||||
return render("poll_details.html", input_data=data, **value_dict)
|
||||
else:
|
||||
return bobo.redirect(BASE_DICT["base_url"])
|
||||
|
||||
@bobo.query('/:admin_hash_key/delete')
|
||||
|
@ -1149,7 +1224,7 @@ def static_files(p1=None, p2=None, p3=None):
|
|||
return get_static_file(pathname)
|
||||
|
||||
|
||||
for table in (Poll, ContentSubmission, PollSetting, PollRelation, Profile, ProfilePolls):
|
||||
for table in (Poll, ContentSubmission, VoteOrder, PollSetting, PollRelation, Profile, ProfilePolls):
|
||||
#table.dropTable()
|
||||
if not table.tableExists():
|
||||
table.createTable()
|
||||
|
|
Loading…
Reference in a new issue