diff --git a/docs/ref/contrib/comments/moderation.txt b/docs/ref/contrib/comments/moderation.txt new file mode 100644 index 0000000000..545279b6c4 --- /dev/null +++ b/docs/ref/contrib/comments/moderation.txt @@ -0,0 +1,235 @@ +.. _ref-contrib-comments-moderation: + +========================== +Generic comment moderation +========================== + +.. module:: django.contrib.comments.moderation + :synopsis: Support for automatic comment moderation. + +Django's bundled comments application is extremely useful on its own, +but the amount of comment spam circulating on the Web today +essentially makes it necessary to have some sort of automatic +moderation system in place for any application which makes use of +comments. To make this easier to handle in a consistent fashion, +``django.contrib.comments.moderation`` (based on `comment_utils`_) +provides a generic, extensible comment-moderation system which can +be applied to any model or set of models which want to make use of +Django's comment system. + +.. _`comment_utils`: http://code.google.com/p/django-comment-utils/ + +Overview +======== + +The entire system is contained within ``django.contrib.comments.moderation``, +and uses a two-step process to enable moderation for any given model: + +1. A subclass of :class:`CommentModerator` + is defined which specifies the moderation options the model wants to + enable. + +2. The model is registered with the moderation system, passing in the + model class and the class which specifies its moderation options. + +A simple example is the best illustration of this. Suppose we have the +following model, which would 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.DateTimeField() + enable_comments = models.BooleanField() + +Now, suppose that we want the following steps to be applied whenever a +new comment is posted on an ``Entry``: + +1. If the ``Entry``'s ``enable_comments`` field is ``False``, the + comment will simply be disallowed (i.e., immediately deleted). + +2. If the ``enable_comments`` field is ``True``, the comment will be + allowed to save. + +3. Once the comment is saved, an email should be sent to site staff + notifying them of the new comment. + +Accomplishing this is fairly straightforward and requires very little +code:: + + from django.contrib.comments.moderation import CommentModerator, moderator + + class EntryModerator(CommentModerator): + email_notification = True + enable_field = 'enable_comments' + + moderator.register(Entry, EntryModerator) + +The :class:`CommentModerator` class pre-defines a number of useful moderation +options which subclasses can enable or disable as desired, and ``moderator`` +knows how to work with them to determine whether to allow a comment, whether +to moderate a comment which will be allowed to post, and whether to email +notifications of new comments. + +Built-in moderation options +--------------------------- + +.. class:: CommentModerator + + Most common comment-moderation needs can be handled by subclassing + :class:`CommentModerator` and + changing the values of pre-defined attributes; the full range of built-in + options is as follows. + + .. attribute:: auto_close_field + + If this is set to the name of a + :class:`~django.db.models.fields.DateField` or + :class:`~django.db.models.fields.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 :attr:`close_after`, which specifies the + number of days past which comments should be + disallowed. Default value is ``None``. + + .. attribute:: auto_moderate_field + + Like :attr:`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 + :attr:`moderate_after`, which specifies the number of days past + which comments should be moderated. Default value is ``None``. + + .. attribute:: close_after + + If :attr:`auto_close_field` is used, this must specify the number + of days past the value of the field specified by + :attr:`auto_close_field` after which new comments for an object + should be disallowed. Default value is ``None``. + + .. attribute:: email_notification + + If ``True``, any new comment on an object of this model which + survives moderation (i.e., is not deleted) will generate an + email to site staff. Default value is ``False``. + + .. attribute:: enable_field + + If this is set to the name of a + :class:`~django.db.models.fields.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``. + + .. attribute:: moderate_after + + If :attr:`auto_moderate_field` is used, this must specify the number + of days past the value of the field specified by + :attr:`auto_moderate_field` after which new comments for an object + should be marked non-public. Default value is ``None``. + +Simply subclassing :class:`CommentModerator` and changing the values of these +options will automatically enable the various moderation methods for any +models registered using the subclass. + +Adding custom moderation methods +-------------------------------- + +For situations where the built-in options listed above are not +sufficient, subclasses of +:class:`CommentModerator` can also +override the methods which actually perform the moderation, and apply any +logic they desire. +:class:`CommentModerator` defines three +methods which determine how moderation will take place; each method will be +called by the moderation system and passed two arguments: ``comment``, which +is the new comment being posted, and ``content_object``, which is the +object the comment will be attached to: + +.. method:: CommentModerator.allow(comment, content_object) + + 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). + +.. method:: CommentModerator.email(comment, content_object) + + If email notification of the new comment should be sent to + site staff or moderators, this method is responsible for + sending the email. + +.. method:: CommentModerator.moderate(comment, content_object) + + 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). + + +Registering models for moderation +--------------------------------- + +The moderation system, represented by +``django.contrib.comments.moderation.moderator`` is an instance of the class +:class:`Moderator`, which allows registration and "unregistration" of models +via two methods: + +.. function:: moderator.register(model_or_iterable, moderation_class) + + Takes two arguments: the first should be either a model class + or list of model classes, and the second should be a subclass + of ``CommentModerator``, and register the model or models to + be moderated using the options defined in the + ``CommentModerator`` subclass. If any of the models are + already registered for moderation, the exception + :exc:`AlreadyModerated` will be raised. + +.. function:: moderator.unregister(model_or_iterable) + + Takes one argument: a model class or list of model classes, + and removes the model or models from the set of models which + are being moderated. If any of the models are not currently + being moderated, the exception + :exc:`NotModerated` will be raised. + + +Customizing the moderation system +--------------------------------- + +Most use cases will work easily with simple subclassing of +:class:`CommentModerator` and registration with the provided +:class:`Moderator` instance, but customization of global moderation behavior +can be achieved by subclassing :class:`Moderator` and instead registering +models with an instance of the subclass. + +.. class:: Moderator + + In addition to the :meth:`Moderator.register` and + :meth:`Moderator.unregister` methods detailed above, the following methods + on :class:`Moderator` can be overridden to achieve customized behavior: + + .. method:: connect + + Determines how moderation is set up globally. The base + implementation in + :class:`Moderator` does this by + attaching listeners to the :data:`~django.db.models.signals.pre_save` + and :data:`~django.db.models.signals.post_save` signals from the + comment models. + + .. method:: pre_save_moderation(sender, instance, **kwargs) + + In the base implementation, applies all pre-save moderation + steps (such as determining whether the comment needs to be + deleted, or whether it needs to be marked as non-public or + generate an email). + + .. method:: post_save_moderation(sender, instance, **kwargs) + + In the base implementation, applies all post-save moderation + steps (currently this consists entirely of deleting comments + which were disallowed).