diff --git a/wortschlucker/src/forms.py b/wortschlucker/src/forms.py index 2f0b6c6..45b6563 100644 --- a/wortschlucker/src/forms.py +++ b/wortschlucker/src/forms.py @@ -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) diff --git a/wortschlucker/src/wortschlucker.py b/wortschlucker/src/wortschlucker.py index 40c9c05..8b62e5a 100755 --- a/wortschlucker/src/wortschlucker.py +++ b/wortschlucker/src/wortschlucker.py @@ -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"()", text.lower())) +def is_spam_content(text, errors_dict): + if re.search(r"()", 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,7 +848,8 @@ 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) - return bobo.redirect(BASE_DICT["base_url"]) + else: + return bobo.redirect(BASE_DICT["base_url"]) @bobo.query('/:admin_hash_key/delete') def delete_poll(bobo_request, admin_hash_key=None): @@ -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()