diff options
Diffstat (limited to 'parts/django/django/contrib/comments')
27 files changed, 0 insertions, 1887 deletions
diff --git a/parts/django/django/contrib/comments/__init__.py b/parts/django/django/contrib/comments/__init__.py deleted file mode 100644 index 42384e7..0000000 --- a/parts/django/django/contrib/comments/__init__.py +++ /dev/null @@ -1,91 +0,0 @@ -from django.conf import settings -from django.core import urlresolvers -from django.core.exceptions import ImproperlyConfigured -from django.contrib.comments.models import Comment -from django.contrib.comments.forms import CommentForm -from django.utils.importlib import import_module - -DEFAULT_COMMENTS_APP = 'django.contrib.comments' - -def get_comment_app(): - """ - Get the comment app (i.e. "django.contrib.comments") as defined in the settings - """ - # Make sure the app's in INSTALLED_APPS - comments_app = get_comment_app_name() - if comments_app not in settings.INSTALLED_APPS: - raise ImproperlyConfigured("The COMMENTS_APP (%r) "\ - "must be in INSTALLED_APPS" % settings.COMMENTS_APP) - - # Try to import the package - try: - package = import_module(comments_app) - except ImportError: - raise ImproperlyConfigured("The COMMENTS_APP setting refers to "\ - "a non-existing package.") - - return package - -def get_comment_app_name(): - """ - Returns the name of the comment app (either the setting value, if it - exists, or the default). - """ - return getattr(settings, 'COMMENTS_APP', DEFAULT_COMMENTS_APP) - -def get_model(): - """ - Returns the comment model class. - """ - if get_comment_app_name() != DEFAULT_COMMENTS_APP and hasattr(get_comment_app(), "get_model"): - return get_comment_app().get_model() - else: - return Comment - -def get_form(): - """ - Returns the comment ModelForm class. - """ - if get_comment_app_name() != DEFAULT_COMMENTS_APP and hasattr(get_comment_app(), "get_form"): - return get_comment_app().get_form() - else: - return CommentForm - -def get_form_target(): - """ - Returns the target URL for the comment form submission view. - """ - if get_comment_app_name() != DEFAULT_COMMENTS_APP and hasattr(get_comment_app(), "get_form_target"): - return get_comment_app().get_form_target() - else: - return urlresolvers.reverse("django.contrib.comments.views.comments.post_comment") - -def get_flag_url(comment): - """ - Get the URL for the "flag this comment" view. - """ - if get_comment_app_name() != DEFAULT_COMMENTS_APP and hasattr(get_comment_app(), "get_flag_url"): - return get_comment_app().get_flag_url(comment) - else: - return urlresolvers.reverse("django.contrib.comments.views.moderation.flag", - args=(comment.id,)) - -def get_delete_url(comment): - """ - Get the URL for the "delete this comment" view. - """ - if get_comment_app_name() != DEFAULT_COMMENTS_APP and hasattr(get_comment_app(), "get_delete_url"): - return get_comment_app().get_delete_url(comment) - else: - return urlresolvers.reverse("django.contrib.comments.views.moderation.delete", - args=(comment.id,)) - -def get_approve_url(comment): - """ - Get the URL for the "approve this comment from moderation" view. - """ - if get_comment_app_name() != DEFAULT_COMMENTS_APP and hasattr(get_comment_app(), "get_approve_url"): - return get_comment_app().get_approve_url(comment) - else: - return urlresolvers.reverse("django.contrib.comments.views.moderation.approve", - args=(comment.id,)) diff --git a/parts/django/django/contrib/comments/admin.py b/parts/django/django/contrib/comments/admin.py deleted file mode 100644 index 4cb9066..0000000 --- a/parts/django/django/contrib/comments/admin.py +++ /dev/null @@ -1,73 +0,0 @@ -from django.contrib import admin -from django.contrib.comments.models import Comment -from django.utils.translation import ugettext_lazy as _, ungettext -from django.contrib.comments import get_model -from django.contrib.comments.views.moderation import perform_flag, perform_approve, perform_delete - -class CommentsAdmin(admin.ModelAdmin): - fieldsets = ( - (None, - {'fields': ('content_type', 'object_pk', 'site')} - ), - (_('Content'), - {'fields': ('user', 'user_name', 'user_email', 'user_url', 'comment')} - ), - (_('Metadata'), - {'fields': ('submit_date', 'ip_address', 'is_public', 'is_removed')} - ), - ) - - list_display = ('name', 'content_type', 'object_pk', 'ip_address', 'submit_date', 'is_public', 'is_removed') - list_filter = ('submit_date', 'site', 'is_public', 'is_removed') - date_hierarchy = 'submit_date' - ordering = ('-submit_date',) - raw_id_fields = ('user',) - search_fields = ('comment', 'user__username', 'user_name', 'user_email', 'user_url', 'ip_address') - actions = ["flag_comments", "approve_comments", "remove_comments"] - - def get_actions(self, request): - actions = super(CommentsAdmin, self).get_actions(request) - # Only superusers should be able to delete the comments from the DB. - if not request.user.is_superuser and 'delete_selected' in actions: - actions.pop('delete_selected') - if not request.user.has_perm('comments.can_moderate'): - if 'approve_comments' in actions: - actions.pop('approve_comments') - if 'remove_comments' in actions: - actions.pop('remove_comments') - return actions - - def flag_comments(self, request, queryset): - self._bulk_flag(request, queryset, perform_flag, - lambda n: ungettext('flagged', 'flagged', n)) - flag_comments.short_description = _("Flag selected comments") - - def approve_comments(self, request, queryset): - self._bulk_flag(request, queryset, perform_approve, - lambda n: ungettext('approved', 'approved', n)) - approve_comments.short_description = _("Approve selected comments") - - def remove_comments(self, request, queryset): - self._bulk_flag(request, queryset, perform_delete, - lambda n: ungettext('removed', 'removed', n)) - remove_comments.short_description = _("Remove selected comments") - - def _bulk_flag(self, request, queryset, action, done_message): - """ - Flag, approve, or remove some comments from an admin action. Actually - calls the `action` argument to perform the heavy lifting. - """ - n_comments = 0 - for comment in queryset: - action(request, comment) - n_comments += 1 - - msg = ungettext(u'1 comment was successfully %(action)s.', - u'%(count)s comments were successfully %(action)s.', - n_comments) - self.message_user(request, msg % {'count': n_comments, 'action': done_message(n_comments)}) - -# Only register the default admin if the model is the built-in comment model -# (this won't be true if there's a custom comment app). -if get_model() is Comment: - admin.site.register(Comment, CommentsAdmin) diff --git a/parts/django/django/contrib/comments/feeds.py b/parts/django/django/contrib/comments/feeds.py deleted file mode 100644 index e74ca2d..0000000 --- a/parts/django/django/contrib/comments/feeds.py +++ /dev/null @@ -1,38 +0,0 @@ -from django.conf import settings -from django.contrib.syndication.views import Feed -from django.contrib.sites.models import Site -from django.contrib import comments -from django.utils.translation import ugettext as _ - -class LatestCommentFeed(Feed): - """Feed of latest comments on the current site.""" - - def title(self): - if not hasattr(self, '_site'): - self._site = Site.objects.get_current() - return _("%(site_name)s comments") % dict(site_name=self._site.name) - - def link(self): - if not hasattr(self, '_site'): - self._site = Site.objects.get_current() - return "http://%s/" % (self._site.domain) - - def description(self): - if not hasattr(self, '_site'): - self._site = Site.objects.get_current() - return _("Latest comments on %(site_name)s") % dict(site_name=self._site.name) - - def items(self): - qs = comments.get_model().objects.filter( - site__pk = settings.SITE_ID, - is_public = True, - is_removed = False, - ) - if getattr(settings, 'COMMENTS_BANNED_USERS_GROUP', None): - where = ['user_id NOT IN (SELECT user_id FROM auth_user_groups WHERE group_id = %s)'] - params = [settings.COMMENTS_BANNED_USERS_GROUP] - qs = qs.extra(where=where, params=params) - return qs.order_by('-submit_date')[:40] - - def item_pubdate(self, item): - return item.submit_date diff --git a/parts/django/django/contrib/comments/forms.py b/parts/django/django/contrib/comments/forms.py deleted file mode 100644 index 0c4b285..0000000 --- a/parts/django/django/contrib/comments/forms.py +++ /dev/null @@ -1,190 +0,0 @@ -import time -import datetime - -from django import forms -from django.forms.util import ErrorDict -from django.conf import settings -from django.contrib.contenttypes.models import ContentType -from models import Comment -from django.utils.encoding import force_unicode -from django.utils.hashcompat import sha_constructor -from django.utils.text import get_text_list -from django.utils.translation import ungettext, ugettext_lazy as _ - -COMMENT_MAX_LENGTH = getattr(settings,'COMMENT_MAX_LENGTH', 3000) - -class CommentSecurityForm(forms.Form): - """ - Handles the security aspects (anti-spoofing) for comment forms. - """ - content_type = forms.CharField(widget=forms.HiddenInput) - object_pk = forms.CharField(widget=forms.HiddenInput) - timestamp = forms.IntegerField(widget=forms.HiddenInput) - security_hash = forms.CharField(min_length=40, max_length=40, widget=forms.HiddenInput) - - def __init__(self, target_object, data=None, initial=None): - self.target_object = target_object - if initial is None: - initial = {} - initial.update(self.generate_security_data()) - super(CommentSecurityForm, self).__init__(data=data, initial=initial) - - def security_errors(self): - """Return just those errors associated with security""" - errors = ErrorDict() - for f in ["honeypot", "timestamp", "security_hash"]: - if f in self.errors: - errors[f] = self.errors[f] - return errors - - def clean_security_hash(self): - """Check the security hash.""" - security_hash_dict = { - 'content_type' : self.data.get("content_type", ""), - 'object_pk' : self.data.get("object_pk", ""), - 'timestamp' : self.data.get("timestamp", ""), - } - expected_hash = self.generate_security_hash(**security_hash_dict) - actual_hash = self.cleaned_data["security_hash"] - if expected_hash != actual_hash: - raise forms.ValidationError("Security hash check failed.") - return actual_hash - - def clean_timestamp(self): - """Make sure the timestamp isn't too far (> 2 hours) in the past.""" - ts = self.cleaned_data["timestamp"] - if time.time() - ts > (2 * 60 * 60): - raise forms.ValidationError("Timestamp check failed") - return ts - - def generate_security_data(self): - """Generate a dict of security data for "initial" data.""" - timestamp = int(time.time()) - security_dict = { - 'content_type' : str(self.target_object._meta), - 'object_pk' : str(self.target_object._get_pk_val()), - 'timestamp' : str(timestamp), - 'security_hash' : self.initial_security_hash(timestamp), - } - return security_dict - - def initial_security_hash(self, timestamp): - """ - Generate the initial security hash from self.content_object - and a (unix) timestamp. - """ - - initial_security_dict = { - 'content_type' : str(self.target_object._meta), - 'object_pk' : str(self.target_object._get_pk_val()), - 'timestamp' : str(timestamp), - } - return self.generate_security_hash(**initial_security_dict) - - def generate_security_hash(self, content_type, object_pk, timestamp): - """Generate a (SHA1) security hash from the provided info.""" - info = (content_type, object_pk, timestamp, settings.SECRET_KEY) - return sha_constructor("".join(info)).hexdigest() - -class CommentDetailsForm(CommentSecurityForm): - """ - Handles the specific details of the comment (name, comment, etc.). - """ - name = forms.CharField(label=_("Name"), max_length=50) - email = forms.EmailField(label=_("Email address")) - url = forms.URLField(label=_("URL"), required=False) - comment = forms.CharField(label=_('Comment'), widget=forms.Textarea, - max_length=COMMENT_MAX_LENGTH) - - def get_comment_object(self): - """ - Return a new (unsaved) comment object based on the information in this - form. Assumes that the form is already validated and will throw a - ValueError if not. - - Does not set any of the fields that would come from a Request object - (i.e. ``user`` or ``ip_address``). - """ - if not self.is_valid(): - raise ValueError("get_comment_object may only be called on valid forms") - - CommentModel = self.get_comment_model() - new = CommentModel(**self.get_comment_create_data()) - new = self.check_for_duplicate_comment(new) - - return new - - def get_comment_model(self): - """ - Get the comment model to create with this form. Subclasses in custom - comment apps should override this, get_comment_create_data, and perhaps - check_for_duplicate_comment to provide custom comment models. - """ - return Comment - - def get_comment_create_data(self): - """ - Returns the dict of data to be used to create a comment. Subclasses in - custom comment apps that override get_comment_model can override this - method to add extra fields onto a custom comment model. - """ - return dict( - content_type = ContentType.objects.get_for_model(self.target_object), - object_pk = force_unicode(self.target_object._get_pk_val()), - user_name = self.cleaned_data["name"], - user_email = self.cleaned_data["email"], - user_url = self.cleaned_data["url"], - comment = self.cleaned_data["comment"], - submit_date = datetime.datetime.now(), - site_id = settings.SITE_ID, - is_public = True, - is_removed = False, - ) - - def check_for_duplicate_comment(self, new): - """ - Check that a submitted comment isn't a duplicate. This might be caused - by someone posting a comment twice. If it is a dup, silently return the *previous* comment. - """ - possible_duplicates = self.get_comment_model()._default_manager.using( - self.target_object._state.db - ).filter( - content_type = new.content_type, - object_pk = new.object_pk, - user_name = new.user_name, - user_email = new.user_email, - user_url = new.user_url, - ) - for old in possible_duplicates: - if old.submit_date.date() == new.submit_date.date() and old.comment == new.comment: - return old - - return new - - def clean_comment(self): - """ - If COMMENTS_ALLOW_PROFANITIES is False, check that the comment doesn't - contain anything in PROFANITIES_LIST. - """ - comment = self.cleaned_data["comment"] - if settings.COMMENTS_ALLOW_PROFANITIES == False: - bad_words = [w for w in settings.PROFANITIES_LIST if w in comment.lower()] - if bad_words: - plural = len(bad_words) > 1 - raise forms.ValidationError(ungettext( - "Watch your mouth! The word %s is not allowed here.", - "Watch your mouth! The words %s are not allowed here.", plural) % \ - get_text_list(['"%s%s%s"' % (i[0], '-'*(len(i)-2), i[-1]) for i in bad_words], 'and')) - return comment - -class CommentForm(CommentDetailsForm): - honeypot = forms.CharField(required=False, - label=_('If you enter anything in this field '\ - 'your comment will be treated as spam')) - - def clean_honeypot(self): - """Check that nothing's been entered into the honeypot.""" - value = self.cleaned_data["honeypot"] - if value: - raise forms.ValidationError(self.fields["honeypot"].label) - return value diff --git a/parts/django/django/contrib/comments/managers.py b/parts/django/django/contrib/comments/managers.py deleted file mode 100644 index 499feee..0000000 --- a/parts/django/django/contrib/comments/managers.py +++ /dev/null @@ -1,22 +0,0 @@ -from django.db import models -from django.contrib.contenttypes.models import ContentType -from django.utils.encoding import force_unicode - -class CommentManager(models.Manager): - - def in_moderation(self): - """ - QuerySet for all comments currently in the moderation queue. - """ - return self.get_query_set().filter(is_public=False, is_removed=False) - - def for_model(self, model): - """ - QuerySet for all comments for a particular model (either an instance or - a class). - """ - ct = ContentType.objects.get_for_model(model) - qs = self.get_query_set().filter(content_type=ct) - if isinstance(model, models.Model): - qs = qs.filter(object_pk=force_unicode(model._get_pk_val())) - return qs diff --git a/parts/django/django/contrib/comments/models.py b/parts/django/django/contrib/comments/models.py deleted file mode 100644 index 5e128d2..0000000 --- a/parts/django/django/contrib/comments/models.py +++ /dev/null @@ -1,191 +0,0 @@ -import datetime -from django.contrib.auth.models import User -from django.contrib.comments.managers import CommentManager -from django.contrib.contenttypes import generic -from django.contrib.contenttypes.models import ContentType -from django.contrib.sites.models import Site -from django.db import models -from django.core import urlresolvers -from django.utils.translation import ugettext_lazy as _ -from django.conf import settings - -COMMENT_MAX_LENGTH = getattr(settings,'COMMENT_MAX_LENGTH',3000) - -class BaseCommentAbstractModel(models.Model): - """ - An abstract base class that any custom comment models probably should - subclass. - """ - - # Content-object field - content_type = models.ForeignKey(ContentType, - verbose_name=_('content type'), - related_name="content_type_set_for_%(class)s") - object_pk = models.TextField(_('object ID')) - content_object = generic.GenericForeignKey(ct_field="content_type", fk_field="object_pk") - - # Metadata about the comment - site = models.ForeignKey(Site) - - class Meta: - abstract = True - - def get_content_object_url(self): - """ - Get a URL suitable for redirecting to the content object. - """ - return urlresolvers.reverse( - "comments-url-redirect", - args=(self.content_type_id, self.object_pk) - ) - -class Comment(BaseCommentAbstractModel): - """ - A user comment about some object. - """ - - # Who posted this comment? If ``user`` is set then it was an authenticated - # user; otherwise at least user_name should have been set and the comment - # was posted by a non-authenticated user. - user = models.ForeignKey(User, verbose_name=_('user'), - blank=True, null=True, related_name="%(class)s_comments") - user_name = models.CharField(_("user's name"), max_length=50, blank=True) - user_email = models.EmailField(_("user's email address"), blank=True) - user_url = models.URLField(_("user's URL"), blank=True) - - comment = models.TextField(_('comment'), max_length=COMMENT_MAX_LENGTH) - - # Metadata about the comment - submit_date = models.DateTimeField(_('date/time submitted'), default=None) - ip_address = models.IPAddressField(_('IP address'), blank=True, null=True) - is_public = models.BooleanField(_('is public'), default=True, - help_text=_('Uncheck this box to make the comment effectively ' \ - 'disappear from the site.')) - is_removed = models.BooleanField(_('is removed'), default=False, - help_text=_('Check this box if the comment is inappropriate. ' \ - 'A "This comment has been removed" message will ' \ - 'be displayed instead.')) - - # Manager - objects = CommentManager() - - class Meta: - db_table = "django_comments" - ordering = ('submit_date',) - permissions = [("can_moderate", "Can moderate comments")] - verbose_name = _('comment') - verbose_name_plural = _('comments') - - def __unicode__(self): - return "%s: %s..." % (self.name, self.comment[:50]) - - def save(self, *args, **kwargs): - if self.submit_date is None: - self.submit_date = datetime.datetime.now() - super(Comment, self).save(*args, **kwargs) - - def _get_userinfo(self): - """ - Get a dictionary that pulls together information about the poster - safely for both authenticated and non-authenticated comments. - - This dict will have ``name``, ``email``, and ``url`` fields. - """ - if not hasattr(self, "_userinfo"): - self._userinfo = { - "name" : self.user_name, - "email" : self.user_email, - "url" : self.user_url - } - if self.user_id: - u = self.user - if u.email: - self._userinfo["email"] = u.email - - # If the user has a full name, use that for the user name. - # However, a given user_name overrides the raw user.username, - # so only use that if this comment has no associated name. - if u.get_full_name(): - self._userinfo["name"] = self.user.get_full_name() - elif not self.user_name: - self._userinfo["name"] = u.username - return self._userinfo - userinfo = property(_get_userinfo, doc=_get_userinfo.__doc__) - - def _get_name(self): - return self.userinfo["name"] - def _set_name(self, val): - if self.user_id: - raise AttributeError(_("This comment was posted by an authenticated "\ - "user and thus the name is read-only.")) - self.user_name = val - name = property(_get_name, _set_name, doc="The name of the user who posted this comment") - - def _get_email(self): - return self.userinfo["email"] - def _set_email(self, val): - if self.user_id: - raise AttributeError(_("This comment was posted by an authenticated "\ - "user and thus the email is read-only.")) - self.user_email = val - email = property(_get_email, _set_email, doc="The email of the user who posted this comment") - - def _get_url(self): - return self.userinfo["url"] - def _set_url(self, val): - self.user_url = val - url = property(_get_url, _set_url, doc="The URL given by the user who posted this comment") - - def get_absolute_url(self, anchor_pattern="#c%(id)s"): - return self.get_content_object_url() + (anchor_pattern % self.__dict__) - - def get_as_text(self): - """ - Return this comment as plain text. Useful for emails. - """ - d = { - 'user': self.user or self.name, - 'date': self.submit_date, - 'comment': self.comment, - 'domain': self.site.domain, - 'url': self.get_absolute_url() - } - return _('Posted by %(user)s at %(date)s\n\n%(comment)s\n\nhttp://%(domain)s%(url)s') % d - -class CommentFlag(models.Model): - """ - Records a flag on a comment. This is intentionally flexible; right now, a - flag could be: - - * A "removal suggestion" -- where a user suggests a comment for (potential) removal. - - * A "moderator deletion" -- used when a moderator deletes a comment. - - You can (ab)use this model to add other flags, if needed. However, by - design users are only allowed to flag a comment with a given flag once; - if you want rating look elsewhere. - """ - user = models.ForeignKey(User, verbose_name=_('user'), related_name="comment_flags") - comment = models.ForeignKey(Comment, verbose_name=_('comment'), related_name="flags") - flag = models.CharField(_('flag'), max_length=30, db_index=True) - flag_date = models.DateTimeField(_('date'), default=None) - - # Constants for flag types - SUGGEST_REMOVAL = "removal suggestion" - MODERATOR_DELETION = "moderator deletion" - MODERATOR_APPROVAL = "moderator approval" - - class Meta: - db_table = 'django_comment_flags' - unique_together = [('user', 'comment', 'flag')] - verbose_name = _('comment flag') - verbose_name_plural = _('comment flags') - - def __unicode__(self): - return "%s flag of comment ID %s by %s" % \ - (self.flag, self.comment_id, self.user.username) - - def save(self, *args, **kwargs): - if self.flag_date is None: - self.flag_date = datetime.datetime.now() - super(CommentFlag, self).save(*args, **kwargs) 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() diff --git a/parts/django/django/contrib/comments/signals.py b/parts/django/django/contrib/comments/signals.py deleted file mode 100644 index fe1083b..0000000 --- a/parts/django/django/contrib/comments/signals.py +++ /dev/null @@ -1,21 +0,0 @@ -""" -Signals relating to comments. -""" -from django.dispatch import Signal - -# Sent just before a comment will be posted (after it's been approved and -# moderated; this can be used to modify the comment (in place) with posting -# details or other such actions. If any receiver returns False the comment will be -# discarded and a 403 (not allowed) response. This signal is sent at more or less -# the same time (just before, actually) as the Comment object's pre-save signal, -# except that the HTTP request is sent along with this signal. -comment_will_be_posted = Signal(providing_args=["comment", "request"]) - -# Sent just after a comment was posted. See above for how this differs -# from the Comment object's post-save signal. -comment_was_posted = Signal(providing_args=["comment", "request"]) - -# Sent after a comment was "flagged" in some way. Check the flag to see if this -# was a user requesting removal of a comment, a moderator approving/removing a -# comment, or some other custom user flag. -comment_was_flagged = Signal(providing_args=["comment", "flag", "created", "request"]) diff --git a/parts/django/django/contrib/comments/templates/comments/400-debug.html b/parts/django/django/contrib/comments/templates/comments/400-debug.html deleted file mode 100644 index 29593b5..0000000 --- a/parts/django/django/contrib/comments/templates/comments/400-debug.html +++ /dev/null @@ -1,53 +0,0 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" lang="en"> -<head> - <meta http-equiv="content-type" content="text/html; charset=utf-8" /> - <title>Comment post not allowed (400)</title> - <meta name="robots" content="NONE,NOARCHIVE" /> - <style type="text/css"> - html * { padding:0; margin:0; } - body * { padding:10px 20px; } - body * * { padding:0; } - body { font:small sans-serif; background:#eee; } - body>div { border-bottom:1px solid #ddd; } - h1 { font-weight:normal; margin-bottom:.4em; } - h1 span { font-size:60%; color:#666; font-weight:normal; } - table { border:none; border-collapse: collapse; width:100%; } - td, th { vertical-align:top; padding:2px 3px; } - th { width:12em; text-align:right; color:#666; padding-right:.5em; } - #info { background:#f6f6f6; } - #info ol { margin: 0.5em 4em; } - #info ol li { font-family: monospace; } - #summary { background: #ffc; } - #explanation { background:#eee; border-bottom: 0px none; } - </style> -</head> -<body> - <div id="summary"> - <h1>Comment post not allowed <span>(400)</span></h1> - <table class="meta"> - <tr> - <th>Why:</th> - <td>{{ why }}</td> - </tr> - </table> - </div> - <div id="info"> - <p> - The comment you tried to post to this view wasn't saved because something - tampered with the security information in the comment form. The message - above should explain the problem, or you can check the <a - href="http://docs.djangoproject.com/en/dev/ref/contrib/comments/">comment - documentation</a> for more help. - </p> - </div> - - <div id="explanation"> - <p> - You're seeing this error because you have <code>DEBUG = True</code> in - your Django settings file. Change that to <code>False</code>, and Django - will display a standard 400 error page. - </p> - </div> -</body> -</html> diff --git a/parts/django/django/contrib/comments/templates/comments/approve.html b/parts/django/django/contrib/comments/templates/comments/approve.html deleted file mode 100644 index 78d15db..0000000 --- a/parts/django/django/contrib/comments/templates/comments/approve.html +++ /dev/null @@ -1,15 +0,0 @@ -{% extends "comments/base.html" %} -{% load i18n %} - -{% block title %}{% trans "Approve a comment" %}{% endblock %} - -{% block content %} - <h1>{% trans "Really make this comment public?" %}</h1> - <blockquote>{{ comment|linebreaks }}</blockquote> - <form action="." method="post">{% csrf_token %} - {% if next %}<div><input type="hidden" name="next" value="{{ next }}" id="next" /></div>{% endif %} - <p class="submit"> - <input type="submit" name="submit" value="{% trans "Approve" %}" /> or <a href="{{ comment.get_absolute_url }}">cancel</a> - </p> - </form> -{% endblock %} diff --git a/parts/django/django/contrib/comments/templates/comments/approved.html b/parts/django/django/contrib/comments/templates/comments/approved.html deleted file mode 100644 index d4ba245..0000000 --- a/parts/django/django/contrib/comments/templates/comments/approved.html +++ /dev/null @@ -1,8 +0,0 @@ -{% extends "comments/base.html" %} -{% load i18n %} - -{% block title %}{% trans "Thanks for approving" %}.{% endblock %} - -{% block content %} - <h1>{% trans "Thanks for taking the time to improve the quality of discussion on our site" %}.</h1> -{% endblock %} diff --git a/parts/django/django/contrib/comments/templates/comments/base.html b/parts/django/django/contrib/comments/templates/comments/base.html deleted file mode 100644 index 0f58e3e..0000000 --- a/parts/django/django/contrib/comments/templates/comments/base.html +++ /dev/null @@ -1,10 +0,0 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml"> -<head> - <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> - <title>{% block title %}{% endblock %}</title> -</head> -<body> - {% block content %}{% endblock %} -</body> -</html> diff --git a/parts/django/django/contrib/comments/templates/comments/delete.html b/parts/django/django/contrib/comments/templates/comments/delete.html deleted file mode 100644 index 50c9a4d..0000000 --- a/parts/django/django/contrib/comments/templates/comments/delete.html +++ /dev/null @@ -1,15 +0,0 @@ -{% extends "comments/base.html" %} -{% load i18n %} - -{% block title %}{% trans "Remove a comment" %}{% endblock %} - -{% block content %} -<h1>{% trans "Really remove this comment?" %}</h1> - <blockquote>{{ comment|linebreaks }}</blockquote> - <form action="." method="post">{% csrf_token %} - {% if next %}<div><input type="hidden" name="next" value="{{ next }}" id="next" /></div>{% endif %} - <p class="submit"> - <input type="submit" name="submit" value="{% trans "Remove" %}" /> or <a href="{{ comment.get_absolute_url }}">cancel</a> - </p> - </form> -{% endblock %} diff --git a/parts/django/django/contrib/comments/templates/comments/deleted.html b/parts/django/django/contrib/comments/templates/comments/deleted.html deleted file mode 100644 index e608481..0000000 --- a/parts/django/django/contrib/comments/templates/comments/deleted.html +++ /dev/null @@ -1,8 +0,0 @@ -{% extends "comments/base.html" %} -{% load i18n %} - -{% block title %}{% trans "Thanks for removing" %}.{% endblock %} - -{% block content %} - <h1>{% trans "Thanks for taking the time to improve the quality of discussion on our site" %}.</h1> -{% endblock %} diff --git a/parts/django/django/contrib/comments/templates/comments/flag.html b/parts/django/django/contrib/comments/templates/comments/flag.html deleted file mode 100644 index ca7c77f..0000000 --- a/parts/django/django/contrib/comments/templates/comments/flag.html +++ /dev/null @@ -1,15 +0,0 @@ -{% extends "comments/base.html" %} -{% load i18n %} - -{% block title %}{% trans "Flag this comment" %}{% endblock %} - -{% block content %} -<h1>{% trans "Really flag this comment?" %}</h1> - <blockquote>{{ comment|linebreaks }}</blockquote> - <form action="." method="post">{% csrf_token %} - {% if next %}<div><input type="hidden" name="next" value="{{ next }}" id="next" /></div>{% endif %} - <p class="submit"> - <input type="submit" name="submit" value="{% trans "Flag" %}" /> or <a href="{{ comment.get_absolute_url }}">cancel</a> - </p> - </form> -{% endblock %} diff --git a/parts/django/django/contrib/comments/templates/comments/flagged.html b/parts/django/django/contrib/comments/templates/comments/flagged.html deleted file mode 100644 index e558019..0000000 --- a/parts/django/django/contrib/comments/templates/comments/flagged.html +++ /dev/null @@ -1,8 +0,0 @@ -{% extends "comments/base.html" %} -{% load i18n %} - -{% block title %}{% trans "Thanks for flagging" %}.{% endblock %} - -{% block content %} - <h1>{% trans "Thanks for taking the time to improve the quality of discussion on our site" %}.</h1> -{% endblock %} diff --git a/parts/django/django/contrib/comments/templates/comments/form.html b/parts/django/django/contrib/comments/templates/comments/form.html deleted file mode 100644 index 2a9ad55..0000000 --- a/parts/django/django/contrib/comments/templates/comments/form.html +++ /dev/null @@ -1,20 +0,0 @@ -{% load comments i18n %} -<form action="{% comment_form_target %}" method="post">{% csrf_token %} - {% if next %}<div><input type="hidden" name="next" value="{{ next }}" /></div>{% endif %} - {% for field in form %} - {% if field.is_hidden %} - <div>{{ field }}</div> - {% else %} - {% if field.errors %}{{ field.errors }}{% endif %} - <p - {% if field.errors %} class="error"{% endif %} - {% ifequal field.name "honeypot" %} style="display:none;"{% endifequal %}> - {{ field.label_tag }} {{ field }} - </p> - {% endif %} - {% endfor %} - <p class="submit"> - <input type="submit" name="post" class="submit-post" value="{% trans "Post" %}" /> - <input type="submit" name="preview" class="submit-preview" value="{% trans "Preview" %}" /> - </p> -</form> diff --git a/parts/django/django/contrib/comments/templates/comments/list.html b/parts/django/django/contrib/comments/templates/comments/list.html deleted file mode 100644 index 3d4ec1e..0000000 --- a/parts/django/django/contrib/comments/templates/comments/list.html +++ /dev/null @@ -1,10 +0,0 @@ -<dl id="comments"> - {% for comment in comment_list %} - <dt id="c{{ comment.id }}"> - {{ comment.submit_date }} - {{ comment.name }} - </dt> - <dd> - <p>{{ comment.comment }}</p> - </dd> - {% endfor %} -</dl> diff --git a/parts/django/django/contrib/comments/templates/comments/posted.html b/parts/django/django/contrib/comments/templates/comments/posted.html deleted file mode 100644 index 76f7f6d..0000000 --- a/parts/django/django/contrib/comments/templates/comments/posted.html +++ /dev/null @@ -1,8 +0,0 @@ -{% extends "comments/base.html" %} -{% load i18n %} - -{% block title %}{% trans "Thanks for commenting" %}.{% endblock %} - -{% block content %} - <h1>{% trans "Thank you for your comment" %}.</h1> -{% endblock %} diff --git a/parts/django/django/contrib/comments/templates/comments/preview.html b/parts/django/django/contrib/comments/templates/comments/preview.html deleted file mode 100644 index b1607b9..0000000 --- a/parts/django/django/contrib/comments/templates/comments/preview.html +++ /dev/null @@ -1,36 +0,0 @@ -{% extends "comments/base.html" %} -{% load i18n %} - -{% block title %}{% trans "Preview your comment" %}{% endblock %} - -{% block content %} - {% load comments %} - <form action="{% comment_form_target %}" method="post">{% csrf_token %} - {% if next %}<div><input type="hidden" name="next" value="{{ next }}" /></div>{% endif %} - {% if form.errors %} - <h1>{% blocktrans count form.errors|length as counter %}Please correct the error below{% plural %}Please correct the errors below{% endblocktrans %}</h1> - {% else %} - <h1>{% trans "Preview your comment" %}</h1> - <blockquote>{{ comment|linebreaks }}</blockquote> - <p> - {% trans "and" %} <input type="submit" name="submit" class="submit-post" value="{% trans "Post your comment" %}" id="submit" /> {% trans "or make changes" %}: - </p> - {% endif %} - {% for field in form %} - {% if field.is_hidden %} - <div>{{ field }}</div> - {% else %} - {% if field.errors %}{{ field.errors }}{% endif %} - <p - {% if field.errors %} class="error"{% endif %} - {% ifequal field.name "honeypot" %} style="display:none;"{% endifequal %}> - {{ field.label_tag }} {{ field }} - </p> - {% endif %} - {% endfor %} - <p class="submit"> - <input type="submit" name="submit" class="submit-post" value="{% trans "Post" %}" /> - <input type="submit" name="preview" class="submit-preview" value="{% trans "Preview" %}" /> - </p> - </form> -{% endblock %} diff --git a/parts/django/django/contrib/comments/templatetags/__init__.py b/parts/django/django/contrib/comments/templatetags/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/parts/django/django/contrib/comments/templatetags/__init__.py +++ /dev/null diff --git a/parts/django/django/contrib/comments/templatetags/comments.py b/parts/django/django/contrib/comments/templatetags/comments.py deleted file mode 100644 index 42691c6..0000000 --- a/parts/django/django/contrib/comments/templatetags/comments.py +++ /dev/null @@ -1,333 +0,0 @@ -from django import template -from django.template.loader import render_to_string -from django.conf import settings -from django.contrib.contenttypes.models import ContentType -from django.contrib import comments -from django.utils.encoding import smart_unicode - -register = template.Library() - -class BaseCommentNode(template.Node): - """ - Base helper class (abstract) for handling the get_comment_* template tags. - Looks a bit strange, but the subclasses below should make this a bit more - obvious. - """ - - #@classmethod - def handle_token(cls, parser, token): - """Class method to parse get_comment_list/count/form and return a Node.""" - tokens = token.contents.split() - if tokens[1] != 'for': - raise template.TemplateSyntaxError("Second argument in %r tag must be 'for'" % tokens[0]) - - # {% get_whatever for obj as varname %} - if len(tokens) == 5: - if tokens[3] != 'as': - raise template.TemplateSyntaxError("Third argument in %r must be 'as'" % tokens[0]) - return cls( - object_expr = parser.compile_filter(tokens[2]), - as_varname = tokens[4], - ) - - # {% get_whatever for app.model pk as varname %} - elif len(tokens) == 6: - if tokens[4] != 'as': - raise template.TemplateSyntaxError("Fourth argument in %r must be 'as'" % tokens[0]) - return cls( - ctype = BaseCommentNode.lookup_content_type(tokens[2], tokens[0]), - object_pk_expr = parser.compile_filter(tokens[3]), - as_varname = tokens[5] - ) - - else: - raise template.TemplateSyntaxError("%r tag requires 4 or 5 arguments" % tokens[0]) - - handle_token = classmethod(handle_token) - - #@staticmethod - def lookup_content_type(token, tagname): - try: - app, model = token.split('.') - return ContentType.objects.get(app_label=app, model=model) - except ValueError: - raise template.TemplateSyntaxError("Third argument in %r must be in the format 'app.model'" % tagname) - except ContentType.DoesNotExist: - raise template.TemplateSyntaxError("%r tag has non-existant content-type: '%s.%s'" % (tagname, app, model)) - lookup_content_type = staticmethod(lookup_content_type) - - def __init__(self, ctype=None, object_pk_expr=None, object_expr=None, as_varname=None, comment=None): - if ctype is None and object_expr is None: - raise template.TemplateSyntaxError("Comment nodes must be given either a literal object or a ctype and object pk.") - self.comment_model = comments.get_model() - self.as_varname = as_varname - self.ctype = ctype - self.object_pk_expr = object_pk_expr - self.object_expr = object_expr - self.comment = comment - - def render(self, context): - qs = self.get_query_set(context) - context[self.as_varname] = self.get_context_value_from_queryset(context, qs) - return '' - - def get_query_set(self, context): - ctype, object_pk = self.get_target_ctype_pk(context) - if not object_pk: - return self.comment_model.objects.none() - - qs = self.comment_model.objects.filter( - content_type = ctype, - object_pk = smart_unicode(object_pk), - site__pk = settings.SITE_ID, - ) - - # The is_public and is_removed fields are implementation details of the - # built-in comment model's spam filtering system, so they might not - # be present on a custom comment model subclass. If they exist, we - # should filter on them. - field_names = [f.name for f in self.comment_model._meta.fields] - if 'is_public' in field_names: - qs = qs.filter(is_public=True) - if getattr(settings, 'COMMENTS_HIDE_REMOVED', True) and 'is_removed' in field_names: - qs = qs.filter(is_removed=False) - - return qs - - def get_target_ctype_pk(self, context): - if self.object_expr: - try: - obj = self.object_expr.resolve(context) - except template.VariableDoesNotExist: - return None, None - return ContentType.objects.get_for_model(obj), obj.pk - else: - return self.ctype, self.object_pk_expr.resolve(context, ignore_failures=True) - - def get_context_value_from_queryset(self, context, qs): - """Subclasses should override this.""" - raise NotImplementedError - -class CommentListNode(BaseCommentNode): - """Insert a list of comments into the context.""" - def get_context_value_from_queryset(self, context, qs): - return list(qs) - -class CommentCountNode(BaseCommentNode): - """Insert a count of comments into the context.""" - def get_context_value_from_queryset(self, context, qs): - return qs.count() - -class CommentFormNode(BaseCommentNode): - """Insert a form for the comment model into the context.""" - - def get_form(self, context): - ctype, object_pk = self.get_target_ctype_pk(context) - if object_pk: - return comments.get_form()(ctype.get_object_for_this_type(pk=object_pk)) - else: - return None - - def render(self, context): - context[self.as_varname] = self.get_form(context) - return '' - -class RenderCommentFormNode(CommentFormNode): - """Render the comment form directly""" - - #@classmethod - def handle_token(cls, parser, token): - """Class method to parse render_comment_form and return a Node.""" - tokens = token.contents.split() - if tokens[1] != 'for': - raise template.TemplateSyntaxError("Second argument in %r tag must be 'for'" % tokens[0]) - - # {% render_comment_form for obj %} - if len(tokens) == 3: - return cls(object_expr=parser.compile_filter(tokens[2])) - - # {% render_comment_form for app.models pk %} - elif len(tokens) == 4: - return cls( - ctype = BaseCommentNode.lookup_content_type(tokens[2], tokens[0]), - object_pk_expr = parser.compile_filter(tokens[3]) - ) - handle_token = classmethod(handle_token) - - def render(self, context): - ctype, object_pk = self.get_target_ctype_pk(context) - if object_pk: - template_search_list = [ - "comments/%s/%s/form.html" % (ctype.app_label, ctype.model), - "comments/%s/form.html" % ctype.app_label, - "comments/form.html" - ] - context.push() - formstr = render_to_string(template_search_list, {"form" : self.get_form(context)}, context) - context.pop() - return formstr - else: - return '' - -class RenderCommentListNode(CommentListNode): - """Render the comment list directly""" - - #@classmethod - def handle_token(cls, parser, token): - """Class method to parse render_comment_list and return a Node.""" - tokens = token.contents.split() - if tokens[1] != 'for': - raise template.TemplateSyntaxError("Second argument in %r tag must be 'for'" % tokens[0]) - - # {% render_comment_list for obj %} - if len(tokens) == 3: - return cls(object_expr=parser.compile_filter(tokens[2])) - - # {% render_comment_list for app.models pk %} - elif len(tokens) == 4: - return cls( - ctype = BaseCommentNode.lookup_content_type(tokens[2], tokens[0]), - object_pk_expr = parser.compile_filter(tokens[3]) - ) - handle_token = classmethod(handle_token) - - def render(self, context): - ctype, object_pk = self.get_target_ctype_pk(context) - if object_pk: - template_search_list = [ - "comments/%s/%s/list.html" % (ctype.app_label, ctype.model), - "comments/%s/list.html" % ctype.app_label, - "comments/list.html" - ] - qs = self.get_query_set(context) - context.push() - liststr = render_to_string(template_search_list, { - "comment_list" : self.get_context_value_from_queryset(context, qs) - }, context) - context.pop() - return liststr - else: - return '' - -# We could just register each classmethod directly, but then we'd lose out on -# the automagic docstrings-into-admin-docs tricks. So each node gets a cute -# wrapper function that just exists to hold the docstring. - -#@register.tag -def get_comment_count(parser, token): - """ - Gets the comment count for the given params and populates the template - context with a variable containing that value, whose name is defined by the - 'as' clause. - - Syntax:: - - {% get_comment_count for [object] as [varname] %} - {% get_comment_count for [app].[model] [object_id] as [varname] %} - - Example usage:: - - {% get_comment_count for event as comment_count %} - {% get_comment_count for calendar.event event.id as comment_count %} - {% get_comment_count for calendar.event 17 as comment_count %} - - """ - return CommentCountNode.handle_token(parser, token) - -#@register.tag -def get_comment_list(parser, token): - """ - Gets the list of comments for the given params and populates the template - context with a variable containing that value, whose name is defined by the - 'as' clause. - - Syntax:: - - {% get_comment_list for [object] as [varname] %} - {% get_comment_list for [app].[model] [object_id] as [varname] %} - - Example usage:: - - {% get_comment_list for event as comment_list %} - {% for comment in comment_list %} - ... - {% endfor %} - - """ - return CommentListNode.handle_token(parser, token) - -#@register.tag -def render_comment_list(parser, token): - """ - Render the comment list (as returned by ``{% get_comment_list %}``) - through the ``comments/list.html`` template - - Syntax:: - - {% render_comment_list for [object] %} - {% render_comment_list for [app].[model] [object_id] %} - - Example usage:: - - {% render_comment_list for event %} - - """ - return RenderCommentListNode.handle_token(parser, token) - -#@register.tag -def get_comment_form(parser, token): - """ - Get a (new) form object to post a new comment. - - Syntax:: - - {% get_comment_form for [object] as [varname] %} - {% get_comment_form for [app].[model] [object_id] as [varname] %} - """ - return CommentFormNode.handle_token(parser, token) - -#@register.tag -def render_comment_form(parser, token): - """ - Render the comment form (as returned by ``{% render_comment_form %}``) through - the ``comments/form.html`` template. - - Syntax:: - - {% render_comment_form for [object] %} - {% render_comment_form for [app].[model] [object_id] %} - """ - return RenderCommentFormNode.handle_token(parser, token) - -#@register.simple_tag -def comment_form_target(): - """ - Get the target URL for the comment form. - - Example:: - - <form action="{% comment_form_target %}" method="post"> - """ - return comments.get_form_target() - -#@register.simple_tag -def get_comment_permalink(comment, anchor_pattern=None): - """ - Get the permalink for a comment, optionally specifying the format of the - named anchor to be appended to the end of the URL. - - Example:: - {{ get_comment_permalink comment "#c%(id)s-by-%(user_name)s" }} - """ - - if anchor_pattern: - return comment.get_absolute_url(anchor_pattern) - return comment.get_absolute_url() - -register.tag(get_comment_count) -register.tag(get_comment_list) -register.tag(get_comment_form) -register.tag(render_comment_form) -register.simple_tag(comment_form_target) -register.simple_tag(get_comment_permalink) -register.tag(render_comment_list) diff --git a/parts/django/django/contrib/comments/urls.py b/parts/django/django/contrib/comments/urls.py deleted file mode 100644 index d903779..0000000 --- a/parts/django/django/contrib/comments/urls.py +++ /dev/null @@ -1,16 +0,0 @@ -from django.conf.urls.defaults import * - -urlpatterns = patterns('django.contrib.comments.views', - url(r'^post/$', 'comments.post_comment', name='comments-post-comment'), - url(r'^posted/$', 'comments.comment_done', name='comments-comment-done'), - url(r'^flag/(\d+)/$', 'moderation.flag', name='comments-flag'), - url(r'^flagged/$', 'moderation.flag_done', name='comments-flag-done'), - url(r'^delete/(\d+)/$', 'moderation.delete', name='comments-delete'), - url(r'^deleted/$', 'moderation.delete_done', name='comments-delete-done'), - url(r'^approve/(\d+)/$', 'moderation.approve', name='comments-approve'), - url(r'^approved/$', 'moderation.approve_done', name='comments-approve-done'), -) - -urlpatterns += patterns('', - url(r'^cr/(\d+)/(.+)/$', 'django.contrib.contenttypes.views.shortcut', name='comments-url-redirect'), -) diff --git a/parts/django/django/contrib/comments/views/__init__.py b/parts/django/django/contrib/comments/views/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/parts/django/django/contrib/comments/views/__init__.py +++ /dev/null diff --git a/parts/django/django/contrib/comments/views/comments.py b/parts/django/django/contrib/comments/views/comments.py deleted file mode 100644 index c2b553f..0000000 --- a/parts/django/django/contrib/comments/views/comments.py +++ /dev/null @@ -1,136 +0,0 @@ -from django import http -from django.conf import settings -from utils import next_redirect, confirmation_view -from django.core.exceptions import ObjectDoesNotExist, ValidationError -from django.db import models -from django.shortcuts import render_to_response -from django.template import RequestContext -from django.template.loader import render_to_string -from django.utils.html import escape -from django.views.decorators.http import require_POST -from django.contrib import comments -from django.contrib.comments import signals -from django.views.decorators.csrf import csrf_protect - -class CommentPostBadRequest(http.HttpResponseBadRequest): - """ - Response returned when a comment post is invalid. If ``DEBUG`` is on a - nice-ish error message will be displayed (for debugging purposes), but in - production mode a simple opaque 400 page will be displayed. - """ - def __init__(self, why): - super(CommentPostBadRequest, self).__init__() - if settings.DEBUG: - self.content = render_to_string("comments/400-debug.html", {"why": why}) - -@csrf_protect -@require_POST -def post_comment(request, next=None, using=None): - """ - Post a comment. - - HTTP POST is required. If ``POST['submit'] == "preview"`` or if there are - errors a preview template, ``comments/preview.html``, will be rendered. - """ - # Fill out some initial data fields from an authenticated user, if present - data = request.POST.copy() - if request.user.is_authenticated(): - if not data.get('name', ''): - data["name"] = request.user.get_full_name() or request.user.username - if not data.get('email', ''): - data["email"] = request.user.email - - # Check to see if the POST data overrides the view's next argument. - next = data.get("next", next) - - # Look up the object we're trying to comment about - ctype = data.get("content_type") - object_pk = data.get("object_pk") - if ctype is None or object_pk is None: - return CommentPostBadRequest("Missing content_type or object_pk field.") - try: - model = models.get_model(*ctype.split(".", 1)) - target = model._default_manager.using(using).get(pk=object_pk) - except TypeError: - return CommentPostBadRequest( - "Invalid content_type value: %r" % escape(ctype)) - except AttributeError: - return CommentPostBadRequest( - "The given content-type %r does not resolve to a valid model." % \ - escape(ctype)) - except ObjectDoesNotExist: - return CommentPostBadRequest( - "No object matching content-type %r and object PK %r exists." % \ - (escape(ctype), escape(object_pk))) - except (ValueError, ValidationError), e: - return CommentPostBadRequest( - "Attempting go get content-type %r and object PK %r exists raised %s" % \ - (escape(ctype), escape(object_pk), e.__class__.__name__)) - - # Do we want to preview the comment? - preview = "preview" in data - - # Construct the comment form - form = comments.get_form()(target, data=data) - - # Check security information - if form.security_errors(): - return CommentPostBadRequest( - "The comment form failed security verification: %s" % \ - escape(str(form.security_errors()))) - - # If there are errors or if we requested a preview show the comment - if form.errors or preview: - template_list = [ - # These first two exist for purely historical reasons. - # Django v1.0 and v1.1 allowed the underscore format for - # preview templates, so we have to preserve that format. - "comments/%s_%s_preview.html" % (model._meta.app_label, model._meta.module_name), - "comments/%s_preview.html" % model._meta.app_label, - # Now the usual directory based template heirarchy. - "comments/%s/%s/preview.html" % (model._meta.app_label, model._meta.module_name), - "comments/%s/preview.html" % model._meta.app_label, - "comments/preview.html", - ] - return render_to_response( - template_list, { - "comment" : form.data.get("comment", ""), - "form" : form, - "next": next, - }, - RequestContext(request, {}) - ) - - # Otherwise create the comment - comment = form.get_comment_object() - comment.ip_address = request.META.get("REMOTE_ADDR", None) - if request.user.is_authenticated(): - comment.user = request.user - - # Signal that the comment is about to be saved - responses = signals.comment_will_be_posted.send( - sender = comment.__class__, - comment = comment, - request = request - ) - - for (receiver, response) in responses: - if response == False: - return CommentPostBadRequest( - "comment_will_be_posted receiver %r killed the comment" % receiver.__name__) - - # Save the comment and signal that it was saved - comment.save() - signals.comment_was_posted.send( - sender = comment.__class__, - comment = comment, - request = request - ) - - return next_redirect(data, next, comment_done, c=comment._get_pk_val()) - -comment_done = confirmation_view( - template = "comments/posted.html", - doc = """Display a "comment was posted" success page.""" -) - diff --git a/parts/django/django/contrib/comments/views/moderation.py b/parts/django/django/contrib/comments/views/moderation.py deleted file mode 100644 index 73304ba..0000000 --- a/parts/django/django/contrib/comments/views/moderation.py +++ /dev/null @@ -1,159 +0,0 @@ -from django import template -from django.conf import settings -from django.shortcuts import get_object_or_404, render_to_response -from django.contrib.auth.decorators import login_required, permission_required -from utils import next_redirect, confirmation_view -from django.contrib import comments -from django.contrib.comments import signals -from django.views.decorators.csrf import csrf_protect - -@csrf_protect -@login_required -def flag(request, comment_id, next=None): - """ - Flags a comment. Confirmation on GET, action on POST. - - Templates: `comments/flag.html`, - Context: - comment - the flagged `comments.comment` object - """ - comment = get_object_or_404(comments.get_model(), pk=comment_id, site__pk=settings.SITE_ID) - - # Flag on POST - if request.method == 'POST': - perform_flag(request, comment) - return next_redirect(request.POST.copy(), next, flag_done, c=comment.pk) - - # Render a form on GET - else: - return render_to_response('comments/flag.html', - {'comment': comment, "next": next}, - template.RequestContext(request) - ) - -@csrf_protect -@permission_required("comments.can_moderate") -def delete(request, comment_id, next=None): - """ - Deletes a comment. Confirmation on GET, action on POST. Requires the "can - moderate comments" permission. - - Templates: `comments/delete.html`, - Context: - comment - the flagged `comments.comment` object - """ - comment = get_object_or_404(comments.get_model(), pk=comment_id, site__pk=settings.SITE_ID) - - # Delete on POST - if request.method == 'POST': - # Flag the comment as deleted instead of actually deleting it. - perform_delete(request, comment) - return next_redirect(request.POST.copy(), next, delete_done, c=comment.pk) - - # Render a form on GET - else: - return render_to_response('comments/delete.html', - {'comment': comment, "next": next}, - template.RequestContext(request) - ) - -@csrf_protect -@permission_required("comments.can_moderate") -def approve(request, comment_id, next=None): - """ - Approve a comment (that is, mark it as public and non-removed). Confirmation - on GET, action on POST. Requires the "can moderate comments" permission. - - Templates: `comments/approve.html`, - Context: - comment - the `comments.comment` object for approval - """ - comment = get_object_or_404(comments.get_model(), pk=comment_id, site__pk=settings.SITE_ID) - - # Delete on POST - if request.method == 'POST': - # Flag the comment as approved. - perform_approve(request, comment) - return next_redirect(request.POST.copy(), next, approve_done, c=comment.pk) - - # Render a form on GET - else: - return render_to_response('comments/approve.html', - {'comment': comment, "next": next}, - template.RequestContext(request) - ) - -# The following functions actually perform the various flag/aprove/delete -# actions. They've been broken out into seperate functions to that they -# may be called from admin actions. - -def perform_flag(request, comment): - """ - Actually perform the flagging of a comment from a request. - """ - flag, created = comments.models.CommentFlag.objects.get_or_create( - comment = comment, - user = request.user, - flag = comments.models.CommentFlag.SUGGEST_REMOVAL - ) - signals.comment_was_flagged.send( - sender = comment.__class__, - comment = comment, - flag = flag, - created = created, - request = request, - ) - -def perform_delete(request, comment): - flag, created = comments.models.CommentFlag.objects.get_or_create( - comment = comment, - user = request.user, - flag = comments.models.CommentFlag.MODERATOR_DELETION - ) - comment.is_removed = True - comment.save() - signals.comment_was_flagged.send( - sender = comment.__class__, - comment = comment, - flag = flag, - created = created, - request = request, - ) - - -def perform_approve(request, comment): - flag, created = comments.models.CommentFlag.objects.get_or_create( - comment = comment, - user = request.user, - flag = comments.models.CommentFlag.MODERATOR_APPROVAL, - ) - - comment.is_removed = False - comment.is_public = True - comment.save() - - signals.comment_was_flagged.send( - sender = comment.__class__, - comment = comment, - flag = flag, - created = created, - request = request, - ) - -# Confirmation views. - -flag_done = confirmation_view( - template = "comments/flagged.html", - doc = 'Displays a "comment was flagged" success page.' -) -delete_done = confirmation_view( - template = "comments/deleted.html", - doc = 'Displays a "comment was deleted" success page.' -) -approve_done = confirmation_view( - template = "comments/approved.html", - doc = 'Displays a "comment was approved" success page.' -) diff --git a/parts/django/django/contrib/comments/views/utils.py b/parts/django/django/contrib/comments/views/utils.py deleted file mode 100644 index 8b729d2..0000000 --- a/parts/django/django/contrib/comments/views/utils.py +++ /dev/null @@ -1,58 +0,0 @@ -""" -A few bits of helper functions for comment views. -""" - -import urllib -import textwrap -from django.http import HttpResponseRedirect -from django.core import urlresolvers -from django.shortcuts import render_to_response -from django.template import RequestContext -from django.core.exceptions import ObjectDoesNotExist -from django.contrib import comments - -def next_redirect(data, default, default_view, **get_kwargs): - """ - Handle the "where should I go next?" part of comment views. - - The next value could be a kwarg to the function (``default``), or a - ``?next=...`` GET arg, or the URL of a given view (``default_view``). See - the view modules for examples. - - Returns an ``HttpResponseRedirect``. - """ - next = data.get("next", default) - if next is None: - next = urlresolvers.reverse(default_view) - if get_kwargs: - joiner = ('?' in next) and '&' or '?' - next += joiner + urllib.urlencode(get_kwargs) - return HttpResponseRedirect(next) - -def confirmation_view(template, doc="Display a confirmation view."): - """ - Confirmation view generator for the "comment was - posted/flagged/deleted/approved" views. - """ - def confirmed(request): - comment = None - if 'c' in request.GET: - try: - comment = comments.get_model().objects.get(pk=request.GET['c']) - except (ObjectDoesNotExist, ValueError): - pass - return render_to_response(template, - {'comment': comment}, - context_instance=RequestContext(request) - ) - - confirmed.__doc__ = textwrap.dedent("""\ - %s - - Templates: `%s`` - Context: - comment - The posted comment - """ % (doc, template) - ) - return confirmed |