Add stubbed model for post status transitions.

This commit is contained in:
Ray Schamp 2014-02-26 17:54:17 -05:00
parent 0b0595942b
commit 0db7fbe715
3 changed files with 355 additions and 1 deletions

View file

@ -13,6 +13,8 @@ from django.shortcuts import get_object_or_404
from django.utils.translation import ugettext_lazy as _
from django.utils import timezone
from django_fsm.db.fields import FSMField, transition
from djangobb_forum.fields import AutoOneToOneField, ExtendedImageField, JSONField
from djangobb_forum.util import smiles, convert_text_to_html
from djangobb_forum import settings as forum_settings
@ -60,6 +62,21 @@ if os.path.exists(path):
else:
THEME_CHOICES = []
import logging
logger = logging.getLogger(__name__)
akismet_api = None
try:
from akismet import Akismet
akismet_api = Akismet(key=forum_settings.AKISMET_API_KEY, blog_url=forum_settings.AKISMET_BLOG_URL, agent=forum_settings.AKISMET_AGENT)
if not akismet_api.verify_key():
logger.error("Invalid Aksimet API key.", extra={'key': akismet_api.key, 'blog': akismet_api.blog_url, 'user_agent': akismet_api.user_agent})
akismet_api = None
except Exception as e:
logger.error("Error while initializing Akismet", extra={'exception': e})
class Category(models.Model):
name = models.CharField(_('Name'), max_length=80)
groups = models.ManyToManyField(Group, blank=True, null=True, verbose_name=_('Groups'), help_text=_('Only users from these groups can see this category'))
@ -492,6 +509,127 @@ class PollChoice(models.Model):
#------------------------------------------------------------------------------
class PostStatus(models.Model):
"""
Keeps track of the status of posts for moderation purposes.
"""
UNREVIEWED = 'unreviewed'
FILTERED_SPAM = 'filtered_spam'
FILTERED_HAM = 'filtered_ham'
MARKED_SPAM = 'marked_spam'
MARKED_HAM = 'marked_ham'
post = models.ForeignKey(Post)
state = FSMField(default=UNREVIEWED)
topic = models.ForeignKey(Topic)
user_agent = models.CharField(max_length=200, blank=True, null=True)
referrer = models.CharField(max_length=200, blank=True, null=True)
permalink = models.CharField(max_length=200, blank=True, null=True)
def to_akismet_data(self):
post = self.post
topic = self.topic
user = post.user
user_ip = post.user_ip
comment_author = user.username
user_agent = self.user_agent
referrer = self.referrer
permalink = self.permalink
comment_date_gmt = post.created.isoformat(' ')
comment_post_modified_gmt = topic.created.isoformat(' ')
return {
'user_ip': user_ip,
'user_agent': user_agent,
'comment_author': comment_author,
'referrer': referrer,
'permalink': permalink,
'comment_type': 'comment',
'comment_date_gmt': comment_date_gmt,
'comment_post_modified_gmt': comment_post_modified_gmt
}
def comment_check(self):
"""
Pass the associated post through Akismet if it's available. If it's not
available return None. Otherwise return True or False.
"""
if akismet_api is None:
logger.warning("Skipping akismet check. No api.")
return None
data = self.to_akismet_data()
content = self.post.body
is_spam = None
try:
is_spam = akismet_api.comment_check(body, data)
except Exception as e:
logger.error("Error while checking Akismet", extra={"exception": e})
is_spam = None
return is_spam
def is_spam(self):
"""
Condition used by the FSM. Return True if the Akismet API is available
and returns a positive. Otherwise return False or None.
"""
is_spam = self.comment_check()
if is_spam is None:
return False
else:
return is_spam
def is_ham(self):
"""
Inverse of is_spam.
"""
is_spam = self.comment_check()
if is_spam is None:
return False
else:
return not is_spam
@transition(
field=state, source=UNREVIEWED, target=FILTERED_SPAM,
save=True, conditions=[is_spam])
def filter_spam(self):
"""
Akismet detects this post is spam, move it to the dustbin and report it.
"""
pass
@transition(
field=state, source=UNREVIEWED, target=FILTERED_HAM,
save=True, conditions=[is_ham])
def filter_ham(self):
"""
Akismet detected this post as ham. Don't do anything.
"""
pass
@transition(
field=state, source=[FILTERED_SPAM, MARKED_SPAM], target=MARKED_HAM,
save=True)
def mark_ham(self):
"""
Either Akismet returned a false positive, or a moderator accidentally
marked this as spam. Tell Akismet that this is ham.
"""
pass
@transition(
field=state, source=[FILTERED_HAM, MARKED_HAM], target=MARKED_SPAM,
save=True)
def mark_spam(self):
"""
Akismet missed this, or a moderator accidentally marked it as ham. Tell
Akismet that this is spam.
"""
pass
from .signals import post_saved, topic_saved
post_save.connect(post_saved, sender=Post, dispatch_uid='djangobb_post_save')