Badword Filter für Kommentare
Veröffentlich am 11.03.2009, 12:56
Mich hat in den letzten Tagen eine heftige Spamwelle erwischt. Da ich die im django.contrib verfügbare Comments App verwende, gibt es neben dem honeypot Feld keinen Spamschutz.
Da mir Rechenaufgaben, Captchas und handische Moderation zu aufwändig sind, werde ich es mit einem Badword Filter versuchen.
Der Filter arbeitet sehr einfach. Über das comment_will_ne_posted Signal wird der Kommentartext auf Badwords überprüft und im Falle eines Treffers auf versteckt gesetzt. Dadurch wird der Kommentar nicht gelöscht und ich kann False-Positives wieder zum Leben erwecken.
models.py
from django.db import models
from django.utils.translation import ugettext as _
import re
class CommentBadword(models.Model):
word = models.CharField(_('Bad word'), max_length=255, blank=False)
is_regex = models.BooleanField(_('Is regex'), default=False)
def __unicode__(self):
return self.word
def validate(self, text):
if self.is_regex:
if re.compile(self.word).search(text):
return False
else:
if self.word in text:
return False
return True
class Meta:
verbose_name = _('Comment Badword')
verbose_name_plural = _('Comment Badwords')
forms.py
from django import forms
from django.utils.translation import ugettext as _
from .models import CommentBadword
import re
class CommentBadwordForm(forms.ModelForm):
def clean(self):
if self.cleaned_data['is_regex'] and not self._errors.get('word', None):
try:
test = re.compile(self.cleaned_data['word'])
except:
self._errors['word'] = forms.util.ErrorList([_('Invalid regex pattern')])
return self.cleaned_data
class Meta:
model = CommentBadword
admin.py
from django.contrib import admin
from .models CommentBadword
from .forms import CommentBadwordForm
class CommentBadwordAdmin(admin.ModelAdmin):
list_display = ('word', 'is_regex')
list_filter = ('is_regex',)
search_fields = ('word',)
form = CommentBadwordForm
admin.site.register(CommentBadword, CommentBadwordAdmin)
init.py oder auch woanders, hauptsache der Connect wird ausgeführt
from django.contrib.comments.models import Comment
from django.contrib.comments.signals import comment_will_be_posted
from .models import CommentBadword
def comment_badword_filter(sender, **kwargs):
instance = kwargs['comment']
for badword in CommentBadword.objects.all():
if not badword.validate(instance.comment):
instance.is_public = False
return True
comment_will_be_posted.connect(comment_badword_filter, sender=Comment, dispatch_uid='comment_badword_filter')
Ich denke, dass sich der Code zu großen Teilen selbst erklärt. Zwei Anmerkungen möchte ich jedoch loswerden.
Das CommenBadword Model kann sowohl mit einzelnen gesperrten Wörtern als auch mit regulären Ausdrücken umgehen. Eine entsprechende Validierung im Django Admin wird durchgeführt.
Theoretisch kann man diesen Badword Filter auch für andere Texte verwenden (Foren, etc.). Zur Validierung muss lediglich die Methode validate des CommentBadword Models mit dem zu prüfenden Text aufgerufen werden.Beispiel:
mybadword.validate(mytext)
.. gibt True zurück, wenn der Text keine Badwords enthält und somit freigegeben werden kann.
Viel Spass damit!
Tags: comments, django, moderation
comments: Mail bei neuem Kommentar
Veröffentlich am 18.02.2009, 21:53
Eines der Dinge, die ich in django.contrib.comments vermisse, ist eine E-Mail Benachrichtigung bei neuen Kommentaren. Nach etwas Suchen habe ich nur eine alte Variante aus dem Jahr 2006 gefunden.
Das nehme ich als Anlass, hier mal meine aktuelle - 1.0 kompatible - Umsetzung zu veröffentlichen.
Ich habe diesen Code einfach in die __init__.py meiner Blog App gespeichert (kann auch woanders gespeichert werden, hauptsache Django verarbeitet die Datei automatisch).
from django.contrib.comments.models import Comment
from django.contrib.sites.models import Site
from django.core.mail import mail_managers
from django.db.models import signals
def comment_notification(sender, instance, **kwargs):
subject = 'New Comment on %s' % instance.content_object
msg = 'http://%s%s\n\nComment:\n%s' % (
Site.objects.get_current().domain,
instance.content_object.get_absolute_url(),
instance.comment
)
mail_managers(subject, msg, fail_silently=True)
signals.post_save.connect(comment_notification, sender=Comment)
Wichtig: MANAGERS in der settings.py korrekt konfigurieren, z.B.:
MANAGERS = (
('Webmaster', 'mail@example.com'),
)