From fa37629d2cb56cc56e5093a9f3d895f65181ecfc Mon Sep 17 00:00:00 2001 From: lars Date: Fri, 22 Feb 2013 01:19:32 +0000 Subject: [PATCH] added admin functions (remove spam content) use efficient sql SELECT for frontpage poll list added link counter for spam detection improve efficiency of post deletion by using sqlobject's "cascade" attribute --- wortschlucker/src/wortschlucker.py | 106 ++++++++++++++++++----------- 1 file changed, 68 insertions(+), 38 deletions(-) diff --git a/wortschlucker/src/wortschlucker.py b/wortschlucker/src/wortschlucker.py index 4cf6648..9389da1 100755 --- a/wortschlucker/src/wortschlucker.py +++ b/wortschlucker/src/wortschlucker.py @@ -43,7 +43,6 @@ loader = genshi.template.TemplateLoader(os.path.join(BASE_DIR, 'templates'), aut BLOG_DIR = os.path.join(BASE_DIR, "blog") - BASE_DICT = { "base_url": "/", # the trailing slash is necessary "show_navbar": True, @@ -51,6 +50,7 @@ BASE_DICT = { "authlevel": "public", #authentiction level of template: one of "public" (e.g. frontpage), "poll_public" (e.g. poll_details),"poll_admin" (poll_admin_details","admin" (admin interface) } + # used as the default setting for expose/close dates DEFAULT_DAYS_AHEAD = 7 DATE_FORMAT = "%d.%m.%Y" @@ -85,7 +85,7 @@ POLL_SETTING_TEMPLATES = { class ContentSubmission(sqlobject.SQLObject): submitter = sqlobject.UnicodeCol() content = sqlobject.UnicodeCol() - poll_id = sqlobject.ForeignKey("Poll") + poll_id = sqlobject.ForeignKey("Poll", cascade=True) timestamp_creation = sqlobject.DateTimeCol() def get_creation_time_string(self): @@ -133,20 +133,20 @@ class Profile(sqlobject.SQLObject): class ProfilePolls(sqlobject.SQLObject): - user = sqlobject.ForeignKey("Profile") - poll = sqlobject.ForeignKey("Poll") + user = sqlobject.ForeignKey("Profile", cascade=True) + poll = sqlobject.ForeignKey("Poll", cascade=True) is_admin = sqlobject.BoolCol() class PollSetting(sqlobject.SQLObject): - poll_id = sqlobject.ForeignKey("Poll") + poll_id = sqlobject.ForeignKey("Poll", cascade=True) key = sqlobject.UnicodeCol() value = sqlobject.UnicodeCol() class PollRelation(sqlobject.SQLObject): - first = sqlobject.ForeignKey("Poll") - second = sqlobject.ForeignKey("Poll") + first = sqlobject.ForeignKey("Poll", cascade=True) + second = sqlobject.ForeignKey("Poll", cascade=True) class Poll(sqlobject.SQLObject): @@ -252,15 +252,6 @@ class Poll(sqlobject.SQLObject): def get_submissions(self): return ContentSubmission.selectBy(poll_id=self.id).orderBy("timestamp_creation") - def delete_poll(self): - submissions = ContentSubmission.selectBy(poll_id=self.id) - settings = PollSetting.selectBy(poll_id=self.id) - for submission in submissions: - submission.destroySelf() - for setting in settings: - setting.destroySelf() - self.destroySelf() - def get_url(self, absolute=False): return get_url_string("%s%s" % (BASE_DICT["base_url"], self.hash_key), absolute) @@ -589,13 +580,16 @@ def is_spam_submitter_name(name, errors_dict): else: return False -def is_spam_content(text, errors_dict): +def count_urls(text, errors_dict): + hits = re.findall(r"(\swww\.|http://|https://)", text) + return len(hits) + +def check_spam_content(text): if re.search(r"()", text.lower()): - errors_dict["content"] = \ - "Spam-Verdacht: Inhalt darf keine HTML-Tags enthalten" return True - else: - return False + if count_urls(text) > 2: + return True + return False @bobo.query('/profile/logout') def user_logout(bobo_request): @@ -866,7 +860,11 @@ def submit_content(bobo_request, hash_key=None, submitter=None, content=None): value_dict["errors"] = {} value_dict["authlevel"] = "poll_public" data = {} - if content and (not is_spam_content(content, value_dict["errors"])): + if content and check_spam_content(content): + value_dict["errors"]["content"] = \ + "Spam-Verdacht: Inhalt darf keine HTML-Tags und nicht " + \ + "zuviele Links enthalten" + else: data["content"] = content if submitter and (not is_spam_submitter_name(submitter, value_dict["errors"])): data["submitter"] = submitter @@ -899,7 +897,7 @@ def delete_poll(bobo_request, admin_hash_key=None): admin_poll_id = get_poll_admin_id(admin_hash_key) if not admin_poll_id is None: poll = Poll.get(admin_poll_id) - poll.delete_poll() + poll.destroySelf() return bobo.redirect(BASE_DICT["base_url"]) @bobo.query('/:admin_hash_key/vote_enable') @@ -1111,15 +1109,21 @@ def serve_blog(bobo_request, blog_id=None): value_dict["blog_list"] = blog_list return render("blog_list.html", **value_dict) -def show_poll_list(bobo_request, render_file, page_size, page=None, filter_private=True): - value_dict = get_default_values(bobo_request) - polls = Poll.select().orderBy("-timestamp_creation") - # TODO: speed the filtering up by using SQL statements (see sqlobject "filter") +def show_poll_list(bobo_request, render_file, page_size, page=None, + filter_private=True, value_dict=None): + if value_dict is None: + value_dict = {} + value_dict.update(get_default_values(bobo_request)) + true_string = get_poll_setting_string("public", True) if filter_private: - polls = [poll for poll in polls if poll.get_settings()["public"]] + polls = Poll.select(sqlobject.sqlbuilder.AND( + PollSetting.q.key == "public", + PollSetting.q.value == true_string, + PollSetting.q.poll_id == Poll.q.id)) else: - # convert the sql query into a list (probably an expensive operation) - polls = [poll for poll in polls] + polls = Poll.select() + polls = polls.orderBy("-timestamp_creation") + poll_count = polls.count() if page is None: page = 1 else: @@ -1130,15 +1134,16 @@ def show_poll_list(bobo_request, render_file, page_size, page=None, filter_priva # "page" should at least be 1 - zero shows an empty list page = max(1, page) start = (page - 1) * page_size - if start >= len(polls): - start = len(polls) - page_size - page = (len(polls) + page_size - 1) / page_size + if start >= poll_count: + start = poll_count - page_size + page = (poll_count + page_size - 1) / page_size end = start + page_size - 1 value_dict["polls"] = polls[start : end + 1] # show a link for the next page, if more polls are available - value_dict["show_next_link"] = (end + 1 < len(polls)) + value_dict["show_next_link"] = (end + 1 < poll_count) value_dict["show_previous_link"] = (start > 0) value_dict["page"] = page + value_dict["page_size"] = page_size return render(render_file, **value_dict) def render_poll_admin(bobo_request, poll, add_related, del_related, count, page, show_delete): @@ -1176,22 +1181,47 @@ def render_poll_admin(bobo_request, poll, add_related, del_related, count, page, value_dict["authlevel"] = "poll_admin" return render("poll_admin_details.html", **value_dict) +@bobo.query('/admin/maintenance') +def admin_maintenance(age_days=60, keyword="viagra", keyword_submission="viagra", method=None): + if method == "Remove old": + age_days = int(age_days) + now = datetime.datetime.now() + oldest = now - datetime.timedelta(days=age_days) + for poll in Poll.select(Poll.q.timestamp_creation < oldest): + if poll.get_num_of_submissions() == 0: + poll.destroySelf() + elif method == "Remove poll by keyword" and keyword: + keyword = keyword.lower() + for poll in Poll.select(): + if (keyword in poll.title.lower()) or (keyword in poll.description.lower()): + poll.destroySelf() + elif method == "Remove submission by keyword" and keyword: + keyword = keyword_submission.lower() + for submission in ContentSubmission.select(): + if keyword in submission.content.lower(): + submission.destroySelf() + return bobo.redirect("../admin") + @bobo.query('/admin') @bobo.query('/admin/') @bobo.query('/admin/page/:page') -def show_admin_page(bobo_request, page=None, page_size=20): +def show_admin_page(bobo_request, page=None, page_size=50): try: page_size = int(page_size) except ValueError: - page_size = 30 - return show_poll_list(bobo_request, "admin.html", page_size, page, filter_private=False) + page_size = 50 + value_dict = {} + value_dict["poll_table"] = Poll + value_dict["submission_table"] = ContentSubmission + return show_poll_list(bobo_request, "admin.html", page_size, page=page, + filter_private=False, value_dict=value_dict) @bobo.query('/') @bobo.query('/public') @bobo.query('/public/') @bobo.query('/public/page/:page') def show_frontpage(bobo_request, page=None): - return show_poll_list(bobo_request, "frontpage.html", 20, page) + return show_poll_list(bobo_request, "frontpage.html", 20, page=page) @bobo.query('') def base():