diff options
Diffstat (limited to 'parts/django/django/contrib/comments/moderation.py')
-rw-r--r-- | parts/django/django/contrib/comments/moderation.py | 353 |
1 files changed, 0 insertions, 353 deletions
diff --git a/parts/django/django/contrib/comments/moderation.py b/parts/django/django/contrib/comments/moderation.py deleted file mode 100644 index 7f429c5..0000000 --- a/parts/django/django/contrib/comments/moderation.py +++ /dev/null @@ -1,353 +0,0 @@ -""" -A generic comment-moderation system which allows configuration of -moderation options on a per-model basis. - -To use, do two things: - -1. Create or import a subclass of ``CommentModerator`` defining the - options you want. - -2. Import ``moderator`` from this module and register one or more - models, passing the models and the ``CommentModerator`` options - class you want to use. - - -Example -------- - -First, we define a simple model class which might represent entries in -a Weblog:: - - from django.db import models - - class Entry(models.Model): - title = models.CharField(maxlength=250) - body = models.TextField() - pub_date = models.DateField() - enable_comments = models.BooleanField() - -Then we create a ``CommentModerator`` subclass specifying some -moderation options:: - - from django.contrib.comments.moderation import CommentModerator, moderator - - class EntryModerator(CommentModerator): - email_notification = True - enable_field = 'enable_comments' - -And finally register it for moderation:: - - moderator.register(Entry, EntryModerator) - -This sample class would apply two moderation steps to each new -comment submitted on an Entry: - -* If the entry's ``enable_comments`` field is set to ``False``, the - comment will be rejected (immediately deleted). - -* If the comment is successfully posted, an email notification of the - comment will be sent to site staff. - -For a full list of built-in moderation options and other -configurability, see the documentation for the ``CommentModerator`` -class. - -""" - -import datetime - -from django.conf import settings -from django.core.mail import send_mail -from django.contrib.comments import signals -from django.db.models.base import ModelBase -from django.template import Context, loader -from django.contrib import comments -from django.contrib.sites.models import Site - -class AlreadyModerated(Exception): - """ - Raised when a model which is already registered for moderation is - attempting to be registered again. - - """ - pass - -class NotModerated(Exception): - """ - Raised when a model which is not registered for moderation is - attempting to be unregistered. - - """ - pass - -class CommentModerator(object): - """ - Encapsulates comment-moderation options for a given model. - - This class is not designed to be used directly, since it doesn't - enable any of the available moderation options. Instead, subclass - it and override attributes to enable different options:: - - ``auto_close_field`` - If this is set to the name of a ``DateField`` or - ``DateTimeField`` on the model for which comments are - being moderated, new comments for objects of that model - will be disallowed (immediately deleted) when a certain - number of days have passed after the date specified in - that field. Must be used in conjunction with - ``close_after``, which specifies the number of days past - which comments should be disallowed. Default value is - ``None``. - - ``auto_moderate_field`` - Like ``auto_close_field``, but instead of outright - deleting new comments when the requisite number of days - have elapsed, it will simply set the ``is_public`` field - of new comments to ``False`` before saving them. Must be - used in conjunction with ``moderate_after``, which - specifies the number of days past which comments should be - moderated. Default value is ``None``. - - ``close_after`` - If ``auto_close_field`` is used, this must specify the - number of days past the value of the field specified by - ``auto_close_field`` after which new comments for an - object should be disallowed. Default value is ``None``. - - ``email_notification`` - If ``True``, any new comment on an object of this model - which survives moderation will generate an email to site - staff. Default value is ``False``. - - ``enable_field`` - If this is set to the name of a ``BooleanField`` on the - model for which comments are being moderated, new comments - on objects of that model will be disallowed (immediately - deleted) whenever the value of that field is ``False`` on - the object the comment would be attached to. Default value - is ``None``. - - ``moderate_after`` - If ``auto_moderate_field`` is used, this must specify the number - of days past the value of the field specified by - ``auto_moderate_field`` after which new comments for an - object should be marked non-public. Default value is - ``None``. - - Most common moderation needs can be covered by changing these - attributes, but further customization can be obtained by - subclassing and overriding the following methods. Each method will - be called with three arguments: ``comment``, which is the comment - being submitted, ``content_object``, which is the object the - comment will be attached to, and ``request``, which is the - ``HttpRequest`` in which the comment is being submitted:: - - ``allow`` - Should return ``True`` if the comment should be allowed to - post on the content object, and ``False`` otherwise (in - which case the comment will be immediately deleted). - - ``email`` - If email notification of the new comment should be sent to - site staff or moderators, this method is responsible for - sending the email. - - ``moderate`` - Should return ``True`` if the comment should be moderated - (in which case its ``is_public`` field will be set to - ``False`` before saving), and ``False`` otherwise (in - which case the ``is_public`` field will not be changed). - - Subclasses which want to introspect the model for which comments - are being moderated can do so through the attribute ``_model``, - which will be the model class. - - """ - auto_close_field = None - auto_moderate_field = None - close_after = None - email_notification = False - enable_field = None - moderate_after = None - - def __init__(self, model): - self._model = model - - def _get_delta(self, now, then): - """ - Internal helper which will return a ``datetime.timedelta`` - representing the time between ``now`` and ``then``. Assumes - ``now`` is a ``datetime.date`` or ``datetime.datetime`` later - than ``then``. - - If ``now`` and ``then`` are not of the same type due to one of - them being a ``datetime.date`` and the other being a - ``datetime.datetime``, both will be coerced to - ``datetime.date`` before calculating the delta. - - """ - if now.__class__ is not then.__class__: - now = datetime.date(now.year, now.month, now.day) - then = datetime.date(then.year, then.month, then.day) - if now < then: - raise ValueError("Cannot determine moderation rules because date field is set to a value in the future") - return now - then - - def allow(self, comment, content_object, request): - """ - Determine whether a given comment is allowed to be posted on - a given object. - - Return ``True`` if the comment should be allowed, ``False - otherwise. - - """ - if self.enable_field: - if not getattr(content_object, self.enable_field): - return False - if self.auto_close_field and self.close_after: - if self._get_delta(datetime.datetime.now(), getattr(content_object, self.auto_close_field)).days >= self.close_after: - return False - return True - - def moderate(self, comment, content_object, request): - """ - Determine whether a given comment on a given object should be - allowed to show up immediately, or should be marked non-public - and await approval. - - Return ``True`` if the comment should be moderated (marked - non-public), ``False`` otherwise. - - """ - if self.auto_moderate_field and self.moderate_after: - if self._get_delta(datetime.datetime.now(), getattr(content_object, self.auto_moderate_field)).days >= self.moderate_after: - return True - return False - - def email(self, comment, content_object, request): - """ - Send email notification of a new comment to site staff when email - notifications have been requested. - - """ - if not self.email_notification: - return - recipient_list = [manager_tuple[1] for manager_tuple in settings.MANAGERS] - t = loader.get_template('comments/comment_notification_email.txt') - c = Context({ 'comment': comment, - 'content_object': content_object }) - subject = '[%s] New comment posted on "%s"' % (Site.objects.get_current().name, - content_object) - message = t.render(c) - send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, recipient_list, fail_silently=True) - -class Moderator(object): - """ - Handles moderation of a set of models. - - An instance of this class will maintain a list of one or more - models registered for comment moderation, and their associated - moderation classes, and apply moderation to all incoming comments. - - To register a model, obtain an instance of ``Moderator`` (this - module exports one as ``moderator``), and call its ``register`` - method, passing the model class and a moderation class (which - should be a subclass of ``CommentModerator``). Note that both of - these should be the actual classes, not instances of the classes. - - To cease moderation for a model, call the ``unregister`` method, - passing the model class. - - For convenience, both ``register`` and ``unregister`` can also - accept a list of model classes in place of a single model; this - allows easier registration of multiple models with the same - ``CommentModerator`` class. - - The actual moderation is applied in two phases: one prior to - saving a new comment, and the other immediately after saving. The - pre-save moderation may mark a comment as non-public or mark it to - be removed; the post-save moderation may delete a comment which - was disallowed (there is currently no way to prevent the comment - being saved once before removal) and, if the comment is still - around, will send any notification emails the comment generated. - - """ - def __init__(self): - self._registry = {} - self.connect() - - def connect(self): - """ - Hook up the moderation methods to pre- and post-save signals - from the comment models. - - """ - signals.comment_will_be_posted.connect(self.pre_save_moderation, sender=comments.get_model()) - signals.comment_was_posted.connect(self.post_save_moderation, sender=comments.get_model()) - - def register(self, model_or_iterable, moderation_class): - """ - Register a model or a list of models for comment moderation, - using a particular moderation class. - - Raise ``AlreadyModerated`` if any of the models are already - registered. - - """ - if isinstance(model_or_iterable, ModelBase): - model_or_iterable = [model_or_iterable] - for model in model_or_iterable: - if model in self._registry: - raise AlreadyModerated("The model '%s' is already being moderated" % model._meta.module_name) - self._registry[model] = moderation_class(model) - - def unregister(self, model_or_iterable): - """ - Remove a model or a list of models from the list of models - whose comments will be moderated. - - Raise ``NotModerated`` if any of the models are not currently - registered for moderation. - - """ - if isinstance(model_or_iterable, ModelBase): - model_or_iterable = [model_or_iterable] - for model in model_or_iterable: - if model not in self._registry: - raise NotModerated("The model '%s' is not currently being moderated" % model._meta.module_name) - del self._registry[model] - - def pre_save_moderation(self, sender, comment, request, **kwargs): - """ - Apply any necessary pre-save moderation steps to new - comments. - - """ - model = comment.content_type.model_class() - if model not in self._registry: - return - content_object = comment.content_object - moderation_class = self._registry[model] - - # Comment will be disallowed outright (HTTP 403 response) - if not moderation_class.allow(comment, content_object, request): - return False - - if moderation_class.moderate(comment, content_object, request): - comment.is_public = False - - def post_save_moderation(self, sender, comment, request, **kwargs): - """ - Apply any necessary post-save moderation steps to new - comments. - - """ - model = comment.content_type.model_class() - if model not in self._registry: - return - self._registry[model].email(comment, comment.content_object, request) - -# Import this instance in your own code to use in registering -# your models for moderation. -moderator = Moderator() |