Commit 5fade4566c673bb94bb2c7d026d380300fe98cc9

Authored by Łukasz Banasiak
Committed by Claude Paroz
1 parent 52cb6fe3

Reformatted code to be PEP 8 compliant

@@ -10,6 +10,7 @@ except ImportError: @@ -10,6 +10,7 @@ except ImportError:
10 10
11 DEFAULT_COMMENTS_APP = 'django_comments' 11 DEFAULT_COMMENTS_APP = 'django_comments'
12 12
  13 +
13 def get_comment_app(): 14 def get_comment_app():
14 """ 15 """
15 Get the comment app (i.e. "django_comments") as defined in the settings 16 Get the comment app (i.e. "django_comments") as defined in the settings
@@ -17,18 +18,21 @@ def get_comment_app(): @@ -17,18 +18,21 @@ def get_comment_app():
17 # Make sure the app's in INSTALLED_APPS 18 # Make sure the app's in INSTALLED_APPS
18 comments_app = get_comment_app_name() 19 comments_app = get_comment_app_name()
19 if comments_app not in settings.INSTALLED_APPS: 20 if comments_app not in settings.INSTALLED_APPS:
20 - raise ImproperlyConfigured("The COMMENTS_APP (%r) "\  
21 - "must be in INSTALLED_APPS" % settings.COMMENTS_APP) 21 + raise ImproperlyConfigured(
  22 + "The COMMENTS_APP (%r) must be in INSTALLED_APPS" % settings.COMMENTS_APP
  23 + )
22 24
23 # Try to import the package 25 # Try to import the package
24 try: 26 try:
25 package = import_module(comments_app) 27 package = import_module(comments_app)
26 except ImportError as e: 28 except ImportError as e:
27 - raise ImproperlyConfigured("The COMMENTS_APP setting refers to "\  
28 - "a non-existing package. (%s)" % e) 29 + raise ImproperlyConfigured(
  30 + "The COMMENTS_APP setting refers to a non-existing package. (%s)" % e
  31 + )
29 32
30 return package 33 return package
31 34
  35 +
32 def get_comment_app_name(): 36 def get_comment_app_name():
33 """ 37 """
34 Returns the name of the comment app (either the setting value, if it 38 Returns the name of the comment app (either the setting value, if it
@@ -36,6 +40,7 @@ def get_comment_app_name(): @@ -36,6 +40,7 @@ def get_comment_app_name():
36 """ 40 """
37 return getattr(settings, 'COMMENTS_APP', DEFAULT_COMMENTS_APP) 41 return getattr(settings, 'COMMENTS_APP', DEFAULT_COMMENTS_APP)
38 42
  43 +
39 def get_model(): 44 def get_model():
40 from django_comments.models import Comment 45 from django_comments.models import Comment
41 """ 46 """
@@ -46,6 +51,7 @@ def get_model(): @@ -46,6 +51,7 @@ def get_model():
46 else: 51 else:
47 return Comment 52 return Comment
48 53
  54 +
49 def get_form(): 55 def get_form():
50 from django_comments.forms import CommentForm 56 from django_comments.forms import CommentForm
51 """ 57 """
@@ -56,6 +62,7 @@ def get_form(): @@ -56,6 +62,7 @@ def get_form():
56 else: 62 else:
57 return CommentForm 63 return CommentForm
58 64
  65 +
59 def get_form_target(): 66 def get_form_target():
60 """ 67 """
61 Returns the target URL for the comment form submission view. 68 Returns the target URL for the comment form submission view.
@@ -65,6 +72,7 @@ def get_form_target(): @@ -65,6 +72,7 @@ def get_form_target():
65 else: 72 else:
66 return urlresolvers.reverse("django_comments.views.comments.post_comment") 73 return urlresolvers.reverse("django_comments.views.comments.post_comment")
67 74
  75 +
68 def get_flag_url(comment): 76 def get_flag_url(comment):
69 """ 77 """
70 Get the URL for the "flag this comment" view. 78 Get the URL for the "flag this comment" view.
@@ -75,6 +83,7 @@ def get_flag_url(comment): @@ -75,6 +83,7 @@ def get_flag_url(comment):
75 return urlresolvers.reverse("django_comments.views.moderation.flag", 83 return urlresolvers.reverse("django_comments.views.moderation.flag",
76 args=(comment.id,)) 84 args=(comment.id,))
77 85
  86 +
78 def get_delete_url(comment): 87 def get_delete_url(comment):
79 """ 88 """
80 Get the URL for the "delete this comment" view. 89 Get the URL for the "delete this comment" view.
@@ -85,6 +94,7 @@ def get_delete_url(comment): @@ -85,6 +94,7 @@ def get_delete_url(comment):
85 return urlresolvers.reverse("django_comments.views.moderation.delete", 94 return urlresolvers.reverse("django_comments.views.moderation.delete",
86 args=(comment.id,)) 95 args=(comment.id,))
87 96
  97 +
88 def get_approve_url(comment): 98 def get_approve_url(comment):
89 """ 99 """
90 Get the URL for the "approve this comment from moderation" view. 100 Get the URL for the "approve this comment from moderation" view.
@@ -14,22 +14,26 @@ class UsernameSearch(object): @@ -14,22 +14,26 @@ class UsernameSearch(object):
14 a mechanism for issuing the equivalent of a .filter(user__username=...) 14 a mechanism for issuing the equivalent of a .filter(user__username=...)
15 search in CommentAdmin. 15 search in CommentAdmin.
16 """ 16 """
  17 +
17 def __str__(self): 18 def __str__(self):
18 return 'user__%s' % get_user_model().USERNAME_FIELD 19 return 'user__%s' % get_user_model().USERNAME_FIELD
19 20
20 21
21 class CommentsAdmin(admin.ModelAdmin): 22 class CommentsAdmin(admin.ModelAdmin):
22 fieldsets = ( 23 fieldsets = (
23 - (None,  
24 - {'fields': ('content_type', 'object_pk', 'site')} 24 + (
  25 + None,
  26 + {'fields': ('content_type', 'object_pk', 'site')}
25 ), 27 ),
26 - (_('Content'),  
27 - {'fields': ('user', 'user_name', 'user_email', 'user_url', 'comment')} 28 + (
  29 + _('Content'),
  30 + {'fields': ('user', 'user_name', 'user_email', 'user_url', 'comment')}
28 ), 31 ),
29 - (_('Metadata'),  
30 - {'fields': ('submit_date', 'ip_address', 'is_public', 'is_removed')} 32 + (
  33 + _('Metadata'),
  34 + {'fields': ('submit_date', 'ip_address', 'is_public', 'is_removed')}
31 ), 35 ),
32 - ) 36 + )
33 37
34 list_display = ('name', 'content_type', 'object_pk', 'ip_address', 'submit_date', 'is_public', 'is_removed') 38 list_display = ('name', 'content_type', 'object_pk', 'ip_address', 'submit_date', 'is_public', 'is_removed')
35 list_filter = ('submit_date', 'site', 'is_public', 'is_removed') 39 list_filter = ('submit_date', 'site', 'is_public', 'is_removed')
@@ -54,16 +58,19 @@ class CommentsAdmin(admin.ModelAdmin): @@ -54,16 +58,19 @@ class CommentsAdmin(admin.ModelAdmin):
54 def flag_comments(self, request, queryset): 58 def flag_comments(self, request, queryset):
55 self._bulk_flag(request, queryset, perform_flag, 59 self._bulk_flag(request, queryset, perform_flag,
56 lambda n: ungettext('flagged', 'flagged', n)) 60 lambda n: ungettext('flagged', 'flagged', n))
  61 +
57 flag_comments.short_description = _("Flag selected comments") 62 flag_comments.short_description = _("Flag selected comments")
58 63
59 def approve_comments(self, request, queryset): 64 def approve_comments(self, request, queryset):
60 self._bulk_flag(request, queryset, perform_approve, 65 self._bulk_flag(request, queryset, perform_approve,
61 lambda n: ungettext('approved', 'approved', n)) 66 lambda n: ungettext('approved', 'approved', n))
  67 +
62 approve_comments.short_description = _("Approve selected comments") 68 approve_comments.short_description = _("Approve selected comments")
63 69
64 def remove_comments(self, request, queryset): 70 def remove_comments(self, request, queryset):
65 self._bulk_flag(request, queryset, perform_delete, 71 self._bulk_flag(request, queryset, perform_delete,
66 lambda n: ungettext('removed', 'removed', n)) 72 lambda n: ungettext('removed', 'removed', n))
  73 +
67 remove_comments.short_description = _("Remove selected comments") 74 remove_comments.short_description = _("Remove selected comments")
68 75
69 def _bulk_flag(self, request, queryset, action, done_message): 76 def _bulk_flag(self, request, queryset, action, done_message):
@@ -4,6 +4,7 @@ from django.utils.translation import ugettext as _ @@ -4,6 +4,7 @@ from django.utils.translation import ugettext as _
4 4
5 import django_comments 5 import django_comments
6 6
  7 +
7 class LatestCommentFeed(Feed): 8 class LatestCommentFeed(Feed):
8 """Feed of latest comments on the current site.""" 9 """Feed of latest comments on the current site."""
9 10
@@ -22,9 +23,9 @@ class LatestCommentFeed(Feed): @@ -22,9 +23,9 @@ class LatestCommentFeed(Feed):
22 23
23 def items(self): 24 def items(self):
24 qs = django_comments.get_model().objects.filter( 25 qs = django_comments.get_model().objects.filter(
25 - site__pk = self.site.pk,  
26 - is_public = True,  
27 - is_removed = False, 26 + site__pk=self.site.pk,
  27 + is_public=True,
  28 + is_removed=False,
28 ) 29 )
29 return qs.order_by('-submit_date')[:40] 30 return qs.order_by('-submit_date')[:40]
30 31
1 import time 1 import time
  2 +
2 from django import forms 3 from django import forms
3 4
4 try: 5 try:
@@ -13,18 +14,18 @@ from django.utils.encoding import force_text @@ -13,18 +14,18 @@ from django.utils.encoding import force_text
13 from django.utils.text import get_text_list 14 from django.utils.text import get_text_list
14 from django.utils import timezone 15 from django.utils import timezone
15 from django.utils.translation import ungettext, ugettext, ugettext_lazy as _ 16 from django.utils.translation import ungettext, ugettext, ugettext_lazy as _
16 -  
17 from django_comments.models import Comment 17 from django_comments.models import Comment
18 18
19 -COMMENT_MAX_LENGTH = getattr(settings,'COMMENT_MAX_LENGTH', 3000) 19 +COMMENT_MAX_LENGTH = getattr(settings, 'COMMENT_MAX_LENGTH', 3000)
  20 +
20 21
21 class CommentSecurityForm(forms.Form): 22 class CommentSecurityForm(forms.Form):
22 """ 23 """
23 Handles the security aspects (anti-spoofing) for comment forms. 24 Handles the security aspects (anti-spoofing) for comment forms.
24 """ 25 """
25 - content_type = forms.CharField(widget=forms.HiddenInput)  
26 - object_pk = forms.CharField(widget=forms.HiddenInput)  
27 - timestamp = forms.IntegerField(widget=forms.HiddenInput) 26 + content_type = forms.CharField(widget=forms.HiddenInput)
  27 + object_pk = forms.CharField(widget=forms.HiddenInput)
  28 + timestamp = forms.IntegerField(widget=forms.HiddenInput)
28 security_hash = forms.CharField(min_length=40, max_length=40, widget=forms.HiddenInput) 29 security_hash = forms.CharField(min_length=40, max_length=40, widget=forms.HiddenInput)
29 30
30 def __init__(self, target_object, data=None, initial=None): 31 def __init__(self, target_object, data=None, initial=None):
@@ -45,9 +46,9 @@ class CommentSecurityForm(forms.Form): @@ -45,9 +46,9 @@ class CommentSecurityForm(forms.Form):
45 def clean_security_hash(self): 46 def clean_security_hash(self):
46 """Check the security hash.""" 47 """Check the security hash."""
47 security_hash_dict = { 48 security_hash_dict = {
48 - 'content_type' : self.data.get("content_type", ""),  
49 - 'object_pk' : self.data.get("object_pk", ""),  
50 - 'timestamp' : self.data.get("timestamp", ""), 49 + 'content_type': self.data.get("content_type", ""),
  50 + 'object_pk': self.data.get("object_pk", ""),
  51 + 'timestamp': self.data.get("timestamp", ""),
51 } 52 }
52 expected_hash = self.generate_security_hash(**security_hash_dict) 53 expected_hash = self.generate_security_hash(**security_hash_dict)
53 actual_hash = self.cleaned_data["security_hash"] 54 actual_hash = self.cleaned_data["security_hash"]
@@ -65,11 +66,11 @@ class CommentSecurityForm(forms.Form): @@ -65,11 +66,11 @@ class CommentSecurityForm(forms.Form):
65 def generate_security_data(self): 66 def generate_security_data(self):
66 """Generate a dict of security data for "initial" data.""" 67 """Generate a dict of security data for "initial" data."""
67 timestamp = int(time.time()) 68 timestamp = int(time.time())
68 - security_dict = {  
69 - 'content_type' : str(self.target_object._meta),  
70 - 'object_pk' : str(self.target_object._get_pk_val()),  
71 - 'timestamp' : str(timestamp),  
72 - 'security_hash' : self.initial_security_hash(timestamp), 69 + security_dict = {
  70 + 'content_type': str(self.target_object._meta),
  71 + 'object_pk': str(self.target_object._get_pk_val()),
  72 + 'timestamp': str(timestamp),
  73 + 'security_hash': self.initial_security_hash(timestamp),
73 } 74 }
74 return security_dict 75 return security_dict
75 76
@@ -80,10 +81,10 @@ class CommentSecurityForm(forms.Form): @@ -80,10 +81,10 @@ class CommentSecurityForm(forms.Form):
80 """ 81 """
81 82
82 initial_security_dict = { 83 initial_security_dict = {
83 - 'content_type' : str(self.target_object._meta),  
84 - 'object_pk' : str(self.target_object._get_pk_val()),  
85 - 'timestamp' : str(timestamp),  
86 - } 84 + 'content_type': str(self.target_object._meta),
  85 + 'object_pk': str(self.target_object._get_pk_val()),
  86 + 'timestamp': str(timestamp),
  87 + }
87 return self.generate_security_hash(**initial_security_dict) 88 return self.generate_security_hash(**initial_security_dict)
88 89
89 def generate_security_hash(self, content_type, object_pk, timestamp): 90 def generate_security_hash(self, content_type, object_pk, timestamp):
@@ -95,15 +96,16 @@ class CommentSecurityForm(forms.Form): @@ -95,15 +96,16 @@ class CommentSecurityForm(forms.Form):
95 value = "-".join(info) 96 value = "-".join(info)
96 return salted_hmac(key_salt, value).hexdigest() 97 return salted_hmac(key_salt, value).hexdigest()
97 98
  99 +
98 class CommentDetailsForm(CommentSecurityForm): 100 class CommentDetailsForm(CommentSecurityForm):
99 """ 101 """
100 Handles the specific details of the comment (name, comment, etc.). 102 Handles the specific details of the comment (name, comment, etc.).
101 """ 103 """
102 - name = forms.CharField(label=_("Name"), max_length=50)  
103 - email = forms.EmailField(label=_("Email address"))  
104 - url = forms.URLField(label=_("URL"), required=False)  
105 - comment = forms.CharField(label=_('Comment'), widget=forms.Textarea,  
106 - max_length=COMMENT_MAX_LENGTH) 104 + name = forms.CharField(label=_("Name"), max_length=50)
  105 + email = forms.EmailField(label=_("Email address"))
  106 + url = forms.URLField(label=_("URL"), required=False)
  107 + comment = forms.CharField(label=_('Comment'), widget=forms.Textarea,
  108 + max_length=COMMENT_MAX_LENGTH)
107 109
108 def get_comment_object(self): 110 def get_comment_object(self):
109 """ 111 """
@@ -138,16 +140,16 @@ class CommentDetailsForm(CommentSecurityForm): @@ -138,16 +140,16 @@ class CommentDetailsForm(CommentSecurityForm):
138 method to add extra fields onto a custom comment model. 140 method to add extra fields onto a custom comment model.
139 """ 141 """
140 return dict( 142 return dict(
141 - content_type = ContentType.objects.get_for_model(self.target_object),  
142 - object_pk = force_text(self.target_object._get_pk_val()),  
143 - user_name = self.cleaned_data["name"],  
144 - user_email = self.cleaned_data["email"],  
145 - user_url = self.cleaned_data["url"],  
146 - comment = self.cleaned_data["comment"],  
147 - submit_date = timezone.now(),  
148 - site_id = settings.SITE_ID,  
149 - is_public = True,  
150 - is_removed = False, 143 + content_type=ContentType.objects.get_for_model(self.target_object),
  144 + object_pk=force_text(self.target_object._get_pk_val()),
  145 + user_name=self.cleaned_data["name"],
  146 + user_email=self.cleaned_data["email"],
  147 + user_url=self.cleaned_data["url"],
  148 + comment=self.cleaned_data["comment"],
  149 + submit_date=timezone.now(),
  150 + site_id=settings.SITE_ID,
  151 + is_public=True,
  152 + is_removed=False,
151 ) 153 )
152 154
153 def check_for_duplicate_comment(self, new): 155 def check_for_duplicate_comment(self, new):
@@ -158,11 +160,11 @@ class CommentDetailsForm(CommentSecurityForm): @@ -158,11 +160,11 @@ class CommentDetailsForm(CommentSecurityForm):
158 possible_duplicates = self.get_comment_model()._default_manager.using( 160 possible_duplicates = self.get_comment_model()._default_manager.using(
159 self.target_object._state.db 161 self.target_object._state.db
160 ).filter( 162 ).filter(
161 - content_type = new.content_type,  
162 - object_pk = new.object_pk,  
163 - user_name = new.user_name,  
164 - user_email = new.user_email,  
165 - user_url = new.user_url, 163 + content_type=new.content_type,
  164 + object_pk=new.object_pk,
  165 + user_name=new.user_name,
  166 + user_email=new.user_email,
  167 + user_url=new.user_url,
166 ) 168 )
167 for old in possible_duplicates: 169 for old in possible_duplicates:
168 if old.submit_date.date() == new.submit_date.date() and old.comment == new.comment: 170 if old.submit_date.date() == new.submit_date.date() and old.comment == new.comment:
@@ -184,14 +186,15 @@ class CommentDetailsForm(CommentSecurityForm): @@ -184,14 +186,15 @@ class CommentDetailsForm(CommentSecurityForm):
184 "Watch your mouth! The word %s is not allowed here.", 186 "Watch your mouth! The word %s is not allowed here.",
185 "Watch your mouth! The words %s are not allowed here.", 187 "Watch your mouth! The words %s are not allowed here.",
186 len(bad_words)) % get_text_list( 188 len(bad_words)) % get_text_list(
187 - ['"%s%s%s"' % (i[0], '-'*(len(i)-2), i[-1])  
188 - for i in bad_words], ugettext('and'))) 189 + ['"%s%s%s"' % (i[0], '-' * (len(i) - 2), i[-1])
  190 + for i in bad_words], ugettext('and')))
189 return comment 191 return comment
190 192
  193 +
191 class CommentForm(CommentDetailsForm): 194 class CommentForm(CommentDetailsForm):
192 - honeypot = forms.CharField(required=False,  
193 - label=_('If you enter anything in this field '\  
194 - 'your comment will be treated as spam')) 195 + honeypot = forms.CharField(required=False,
  196 + label=_('If you enter anything in this field '
  197 + 'your comment will be treated as spam'))
195 198
196 def clean_honeypot(self): 199 def clean_honeypot(self):
197 """Check that nothing's been entered into the honeypot.""" 200 """Check that nothing's been entered into the honeypot."""
@@ -2,8 +2,8 @@ from django.db import models @@ -2,8 +2,8 @@ from django.db import models
2 from django.contrib.contenttypes.models import ContentType 2 from django.contrib.contenttypes.models import ContentType
3 from django.utils.encoding import force_text 3 from django.utils.encoding import force_text
4 4
5 -class CommentManager(models.Manager):  
6 5
  6 +class CommentManager(models.Manager):
7 def in_moderation(self): 7 def in_moderation(self):
8 """ 8 """
9 QuerySet for all comments currently in the moderation queue. 9 QuerySet for all comments currently in the moderation queue.
@@ -24,12 +24,20 @@ class Migration(migrations.Migration): @@ -24,12 +24,20 @@ class Migration(migrations.Migration):
24 ('user_url', models.URLField(verbose_name="user's URL", blank=True)), 24 ('user_url', models.URLField(verbose_name="user's URL", blank=True)),
25 ('comment', models.TextField(max_length=3000, verbose_name='comment')), 25 ('comment', models.TextField(max_length=3000, verbose_name='comment')),
26 ('submit_date', models.DateTimeField(default=None, verbose_name='date/time submitted')), 26 ('submit_date', models.DateTimeField(default=None, verbose_name='date/time submitted')),
27 - ('ip_address', models.GenericIPAddressField(unpack_ipv4=True, null=True, verbose_name='IP address', blank=True)),  
28 - ('is_public', models.BooleanField(default=True, help_text='Uncheck this box to make the comment effectively disappear from the site.', verbose_name='is public')),  
29 - ('is_removed', models.BooleanField(default=False, help_text='Check this box if the comment is inappropriate. A "This comment has been removed" message will be displayed instead.', verbose_name='is removed')),  
30 - ('content_type', models.ForeignKey(related_name='content_type_set_for_comment', verbose_name='content type', to='contenttypes.ContentType')), 27 + ('ip_address', models.GenericIPAddressField(
  28 + unpack_ipv4=True, null=True, verbose_name='IP address', blank=True)),
  29 + ('is_public', models.BooleanField(default=True,
  30 + help_text='Uncheck this box to make the comment effectively disappear from the site.',
  31 + verbose_name='is public')),
  32 + ('is_removed', models.BooleanField(default=False,
  33 + help_text='Check this box if the comment is inappropriate. A "This comment has been removed"'
  34 + 'message will be displayed instead.',
  35 + verbose_name='is removed')),
  36 + ('content_type', models.ForeignKey(related_name='content_type_set_for_comment',
  37 + verbose_name='content type', to='contenttypes.ContentType')),
31 ('site', models.ForeignKey(to='sites.Site')), 38 ('site', models.ForeignKey(to='sites.Site')),
32 - ('user', models.ForeignKey(related_name='comment_comments', verbose_name='user', blank=True, to=settings.AUTH_USER_MODEL, null=True)), 39 + ('user', models.ForeignKey(related_name='comment_comments', verbose_name='user',
  40 + blank=True, to=settings.AUTH_USER_MODEL, null=True)),
33 ], 41 ],
34 options={ 42 options={
35 'ordering': ('submit_date',), 43 'ordering': ('submit_date',),
@@ -46,8 +54,10 @@ class Migration(migrations.Migration): @@ -46,8 +54,10 @@ class Migration(migrations.Migration):
46 ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), 54 ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
47 ('flag', models.CharField(max_length=30, verbose_name='flag', db_index=True)), 55 ('flag', models.CharField(max_length=30, verbose_name='flag', db_index=True)),
48 ('flag_date', models.DateTimeField(default=None, verbose_name='date')), 56 ('flag_date', models.DateTimeField(default=None, verbose_name='date')),
49 - ('comment', models.ForeignKey(related_name='flags', verbose_name='comment', to='django_comments.Comment')),  
50 - ('user', models.ForeignKey(related_name='comment_flags', verbose_name='user', to=settings.AUTH_USER_MODEL)), 57 + ('comment', models.ForeignKey(related_name='flags', verbose_name='comment',
  58 + to='django_comments.Comment')),
  59 + ('user', models.ForeignKey(related_name='comment_flags', verbose_name='user',
  60 + to=settings.AUTH_USER_MODEL)),
51 ], 61 ],
52 options={ 62 options={
53 'db_table': 'django_comment_flags', 63 'db_table': 'django_comment_flags',
@@ -26,8 +26,8 @@ class BaseCommentAbstractModel(models.Model): @@ -26,8 +26,8 @@ class BaseCommentAbstractModel(models.Model):
26 26
27 # Content-object field 27 # Content-object field
28 content_type = models.ForeignKey(ContentType, 28 content_type = models.ForeignKey(ContentType,
29 - verbose_name=_('content type'),  
30 - related_name="content_type_set_for_%(class)s") 29 + verbose_name=_('content type'),
  30 + related_name="content_type_set_for_%(class)s")
31 object_pk = models.TextField(_('object ID')) 31 object_pk = models.TextField(_('object ID'))
32 content_object = GenericForeignKey(ct_field="content_type", fk_field="object_pk") 32 content_object = GenericForeignKey(ct_field="content_type", fk_field="object_pk")
33 33
@@ -57,7 +57,7 @@ class Comment(BaseCommentAbstractModel): @@ -57,7 +57,7 @@ class Comment(BaseCommentAbstractModel):
57 # user; otherwise at least user_name should have been set and the comment 57 # user; otherwise at least user_name should have been set and the comment
58 # was posted by a non-authenticated user. 58 # was posted by a non-authenticated user.
59 user = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name=_('user'), 59 user = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name=_('user'),
60 - blank=True, null=True, related_name="%(class)s_comments") 60 + blank=True, null=True, related_name="%(class)s_comments")
61 user_name = models.CharField(_("user's name"), max_length=50, blank=True) 61 user_name = models.CharField(_("user's name"), max_length=50, blank=True)
62 user_email = models.EmailField(_("user's email address"), blank=True) 62 user_email = models.EmailField(_("user's email address"), blank=True)
63 user_url = models.URLField(_("user's URL"), blank=True) 63 user_url = models.URLField(_("user's URL"), blank=True)
@@ -68,12 +68,12 @@ class Comment(BaseCommentAbstractModel): @@ -68,12 +68,12 @@ class Comment(BaseCommentAbstractModel):
68 submit_date = models.DateTimeField(_('date/time submitted'), default=None) 68 submit_date = models.DateTimeField(_('date/time submitted'), default=None)
69 ip_address = models.GenericIPAddressField(_('IP address'), unpack_ipv4=True, blank=True, null=True) 69 ip_address = models.GenericIPAddressField(_('IP address'), unpack_ipv4=True, blank=True, null=True)
70 is_public = models.BooleanField(_('is public'), default=True, 70 is_public = models.BooleanField(_('is public'), default=True,
71 - help_text=_('Uncheck this box to make the comment effectively ' \  
72 - 'disappear from the site.')) 71 + help_text=_('Uncheck this box to make the comment effectively '
  72 + 'disappear from the site.'))
73 is_removed = models.BooleanField(_('is removed'), default=False, 73 is_removed = models.BooleanField(_('is removed'), default=False,
74 - help_text=_('Check this box if the comment is inappropriate. ' \  
75 - 'A "This comment has been removed" message will ' \  
76 - 'be displayed instead.')) 74 + help_text=_('Check this box if the comment is inappropriate. '
  75 + 'A "This comment has been removed" message will '
  76 + 'be displayed instead.'))
77 77
78 # Manager 78 # Manager
79 objects = CommentManager() 79 objects = CommentManager()
@@ -120,6 +120,7 @@ class Comment(BaseCommentAbstractModel): @@ -120,6 +120,7 @@ class Comment(BaseCommentAbstractModel):
120 userinfo["name"] = u.get_username() 120 userinfo["name"] = u.get_username()
121 self._userinfo = userinfo 121 self._userinfo = userinfo
122 return self._userinfo 122 return self._userinfo
  123 +
123 userinfo = property(_get_userinfo, doc=_get_userinfo.__doc__) 124 userinfo = property(_get_userinfo, doc=_get_userinfo.__doc__)
124 125
125 def _get_name(self): 126 def _get_name(self):
@@ -127,9 +128,10 @@ class Comment(BaseCommentAbstractModel): @@ -127,9 +128,10 @@ class Comment(BaseCommentAbstractModel):
127 128
128 def _set_name(self, val): 129 def _set_name(self, val):
129 if self.user_id: 130 if self.user_id:
130 - raise AttributeError(_("This comment was posted by an authenticated "\ 131 + raise AttributeError(_("This comment was posted by an authenticated "
131 "user and thus the name is read-only.")) 132 "user and thus the name is read-only."))
132 self.user_name = val 133 self.user_name = val
  134 +
133 name = property(_get_name, _set_name, doc="The name of the user who posted this comment") 135 name = property(_get_name, _set_name, doc="The name of the user who posted this comment")
134 136
135 def _get_email(self): 137 def _get_email(self):
@@ -137,9 +139,10 @@ class Comment(BaseCommentAbstractModel): @@ -137,9 +139,10 @@ class Comment(BaseCommentAbstractModel):
137 139
138 def _set_email(self, val): 140 def _set_email(self, val):
139 if self.user_id: 141 if self.user_id:
140 - raise AttributeError(_("This comment was posted by an authenticated "\ 142 + raise AttributeError(_("This comment was posted by an authenticated "
141 "user and thus the email is read-only.")) 143 "user and thus the email is read-only."))
142 self.user_email = val 144 self.user_email = val
  145 +
143 email = property(_get_email, _set_email, doc="The email of the user who posted this comment") 146 email = property(_get_email, _set_email, doc="The email of the user who posted this comment")
144 147
145 def _get_url(self): 148 def _get_url(self):
@@ -147,6 +150,7 @@ class Comment(BaseCommentAbstractModel): @@ -147,6 +150,7 @@ class Comment(BaseCommentAbstractModel):
147 150
148 def _set_url(self, val): 151 def _set_url(self, val):
149 self.user_url = val 152 self.user_url = val
  153 +
150 url = property(_get_url, _set_url, doc="The URL given by the user who posted this comment") 154 url = property(_get_url, _set_url, doc="The URL given by the user who posted this comment")
151 155
152 def get_absolute_url(self, anchor_pattern="#c%(id)s"): 156 def get_absolute_url(self, anchor_pattern="#c%(id)s"):
@@ -197,8 +201,9 @@ class CommentFlag(models.Model): @@ -197,8 +201,9 @@ class CommentFlag(models.Model):
197 verbose_name_plural = _('comment flags') 201 verbose_name_plural = _('comment flags')
198 202
199 def __str__(self): 203 def __str__(self):
200 - return "%s flag of comment ID %s by %s" % \  
201 - (self.flag, self.comment_id, self.user.get_username()) 204 + return "%s flag of comment ID %s by %s" % (
  205 + self.flag, self.comment_id, self.user.get_username()
  206 + )
202 207
203 def save(self, *args, **kwargs): 208 def save(self, *args, **kwargs):
204 if self.flag_date is None: 209 if self.flag_date is None:
@@ -66,6 +66,7 @@ from django.utils import timezone @@ -66,6 +66,7 @@ from django.utils import timezone
66 import django_comments 66 import django_comments
67 from django_comments import signals 67 from django_comments import signals
68 68
  69 +
69 class AlreadyModerated(Exception): 70 class AlreadyModerated(Exception):
70 """ 71 """
71 Raised when a model which is already registered for moderation is 72 Raised when a model which is already registered for moderation is
@@ -74,6 +75,7 @@ class AlreadyModerated(Exception): @@ -74,6 +75,7 @@ class AlreadyModerated(Exception):
74 """ 75 """
75 pass 76 pass
76 77
  78 +
77 class NotModerated(Exception): 79 class NotModerated(Exception):
78 """ 80 """
79 Raised when a model which is not registered for moderation is 81 Raised when a model which is not registered for moderation is
@@ -82,6 +84,7 @@ class NotModerated(Exception): @@ -82,6 +84,7 @@ class NotModerated(Exception):
82 """ 84 """
83 pass 85 pass
84 86
  87 +
85 class CommentModerator(object): 88 class CommentModerator(object):
86 """ 89 """
87 Encapsulates comment-moderation options for a given model. 90 Encapsulates comment-moderation options for a given model.
@@ -209,7 +212,8 @@ class CommentModerator(object): @@ -209,7 +212,8 @@ class CommentModerator(object):
209 return False 212 return False
210 if self.auto_close_field and self.close_after is not None: 213 if self.auto_close_field and self.close_after is not None:
211 close_after_date = getattr(content_object, self.auto_close_field) 214 close_after_date = getattr(content_object, self.auto_close_field)
212 - if close_after_date is not None and self._get_delta(timezone.now(), close_after_date).days >= self.close_after: 215 + if close_after_date is not None and self._get_delta(timezone.now(),
  216 + close_after_date).days >= self.close_after:
213 return False 217 return False
214 return True 218 return True
215 219
@@ -225,7 +229,8 @@ class CommentModerator(object): @@ -225,7 +229,8 @@ class CommentModerator(object):
225 """ 229 """
226 if self.auto_moderate_field and self.moderate_after is not None: 230 if self.auto_moderate_field and self.moderate_after is not None:
227 moderate_after_date = getattr(content_object, self.auto_moderate_field) 231 moderate_after_date = getattr(content_object, self.auto_moderate_field)
228 - if moderate_after_date is not None and self._get_delta(timezone.now(), moderate_after_date).days >= self.moderate_after: 232 + if moderate_after_date is not None and self._get_delta(timezone.now(),
  233 + moderate_after_date).days >= self.moderate_after:
229 return True 234 return True
230 return False 235 return False
231 236
@@ -239,13 +244,14 @@ class CommentModerator(object): @@ -239,13 +244,14 @@ class CommentModerator(object):
239 return 244 return
240 recipient_list = [manager_tuple[1] for manager_tuple in settings.MANAGERS] 245 recipient_list = [manager_tuple[1] for manager_tuple in settings.MANAGERS]
241 t = loader.get_template('comments/comment_notification_email.txt') 246 t = loader.get_template('comments/comment_notification_email.txt')
242 - c = Context({ 'comment': comment,  
243 - 'content_object': content_object }) 247 + c = Context({'comment': comment,
  248 + 'content_object': content_object})
244 subject = '[%s] New comment posted on "%s"' % (get_current_site(request).name, 249 subject = '[%s] New comment posted on "%s"' % (get_current_site(request).name,
245 - content_object) 250 + content_object)
246 message = t.render(c) 251 message = t.render(c)
247 send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, recipient_list, fail_silently=True) 252 send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, recipient_list, fail_silently=True)
248 253
  254 +
249 class Moderator(object): 255 class Moderator(object):
250 """ 256 """
251 Handles moderation of a set of models. 257 Handles moderation of a set of models.
@@ -277,6 +283,7 @@ class Moderator(object): @@ -277,6 +283,7 @@ class Moderator(object):
277 around, will send any notification emails the comment generated. 283 around, will send any notification emails the comment generated.
278 284
279 """ 285 """
  286 +
280 def __init__(self): 287 def __init__(self):
281 self._registry = {} 288 self._registry = {}
282 self.connect() 289 self.connect()
1 <!DOCTYPE html> 1 <!DOCTYPE html>
2 <html lang="en"> 2 <html lang="en">
3 <head> 3 <head>
4 - <meta http-equiv="content-type" content="text/html; charset=utf-8" /> 4 + <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
5 <title>Comment post not allowed (400)</title> 5 <title>Comment post not allowed (400)</title>
6 - <meta name="robots" content="NONE,NOARCHIVE" /> 6 + <meta name="robots" content="NONE,NOARCHIVE"/>
7 <style type="text/css"> 7 <style type="text/css">
8 - <![CDATA[  
9 - html * { padding:0; margin:0; }  
10 - body * { padding:10px 20px; }  
11 - body * * { padding:0; }  
12 - body { font:small sans-serif; background:#eee; }  
13 - body>div { border-bottom:1px solid #ddd; }  
14 - h1 { font-weight:normal; margin-bottom:.4em; }  
15 - h1 span { font-size:60%; color:#666; font-weight:normal; }  
16 - table { border:none; border-collapse: collapse; width:100%; }  
17 - td, th { vertical-align:top; padding:2px 3px; }  
18 - th { width:12em; text-align:right; color:#666; padding-right:.5em; }  
19 - #info { background:#f6f6f6; }  
20 - #info ol { margin: 0.5em 4em; }  
21 - #info ol li { font-family: monospace; }  
22 - #summary { background: #ffc; }  
23 - #explanation { background:#eee; border-bottom: 0px none; }  
24 - ]]> 8 + <
  9 + !
  10 + [CDATA[
  11 + html * {
  12 + padding: 0;
  13 + margin: 0;
  14 + }
  15 +
  16 + body * {
  17 + padding: 10px 20px;
  18 + }
  19 +
  20 + body * * {
  21 + padding: 0;
  22 + }
  23 +
  24 + body {
  25 + font: small sans-serif;
  26 + background: #eee;
  27 + }
  28 +
  29 + body > div {
  30 + border-bottom: 1px solid #ddd;
  31 + }
  32 +
  33 + h1 {
  34 + font-weight: normal;
  35 + margin-bottom: .4em;
  36 + }
  37 +
  38 + h1 span {
  39 + font-size: 60%;
  40 + color: #666;
  41 + font-weight: normal;
  42 + }
  43 +
  44 + table {
  45 + border: none;
  46 + border-collapse: collapse;
  47 + width: 100%;
  48 + }
  49 +
  50 + td, th {
  51 + vertical-align: top;
  52 + padding: 2px 3px;
  53 + }
  54 +
  55 + th {
  56 + width: 12em;
  57 + text-align: right;
  58 + color: #666;
  59 + padding-right: .5em;
  60 + }
  61 +
  62 + #info {
  63 + background: #f6f6f6;
  64 + }
  65 +
  66 + #info ol {
  67 + margin: 0.5em 4em;
  68 + }
  69 +
  70 + #info ol li {
  71 + font-family: monospace;
  72 + }
  73 +
  74 + #summary {
  75 + background: #ffc;
  76 + }
  77 +
  78 + #explanation {
  79 + background: #eee;
  80 + border-bottom: 0px none;
  81 + }
  82 +
  83 + ]
  84 + ]
  85 + >
25 </style> 86 </style>
26 </head> 87 </head>
27 <body> 88 <body>
28 - <div id="summary">  
29 - <h1>Comment post not allowed <span>(400)</span></h1>  
30 - <table class="meta">  
31 - <tr>  
32 - <th>Why:</th>  
33 - <td>{{ why }}</td>  
34 - </tr>  
35 - </table>  
36 - </div>  
37 - <div id="info">  
38 - <p> 89 +<div id="summary">
  90 + <h1>Comment post not allowed <span>(400)</span></h1>
  91 + <table class="meta">
  92 + <tr>
  93 + <th>Why:</th>
  94 + <td>{{ why }}</td>
  95 + </tr>
  96 + </table>
  97 +</div>
  98 +<div id="info">
  99 + <p>
39 The comment you tried to post to this view wasn't saved because something 100 The comment you tried to post to this view wasn't saved because something
40 tampered with the security information in the comment form. The message 101 tampered with the security information in the comment form. The message
41 above should explain the problem, or you can check the <a 102 above should explain the problem, or you can check the <a
42 - href="http://docs.djangoproject.com/en/dev/ref/contrib/comments/">comment 103 + href="http://docs.djangoproject.com/en/dev/ref/contrib/comments/">comment
43 documentation</a> for more help. 104 documentation</a> for more help.
44 - </p>  
45 - </div>  
46 -  
47 - <div id="explanation">  
48 - <p>  
49 - You're seeing this error because you have <code>DEBUG = True</code> in  
50 - your Django settings file. Change that to <code>False</code>, and Django  
51 - will display a standard 400 error page.  
52 - </p>  
53 - </div> 105 + </p>
  106 +</div>
  107 +
  108 +<div id="explanation">
  109 + <p>
  110 + You're seeing this error because you have <code>DEBUG = True</code> in
  111 + your Django settings file. Change that to <code>False</code>, and Django
  112 + will display a standard 400 error page.
  113 + </p>
  114 +</div>
54 </body> 115 </body>
55 </html> 116 </html>
@@ -7,9 +7,10 @@ @@ -7,9 +7,10 @@
7 <h1>{% trans "Really make this comment public?" %}</h1> 7 <h1>{% trans "Really make this comment public?" %}</h1>
8 <blockquote>{{ comment|linebreaks }}</blockquote> 8 <blockquote>{{ comment|linebreaks }}</blockquote>
9 <form action="." method="post">{% csrf_token %} 9 <form action="." method="post">{% csrf_token %}
10 - {% if next %}<div><input type="hidden" name="next" value="{{ next }}" id="next" /></div>{% endif %} 10 + {% if next %}
  11 + <div><input type="hidden" name="next" value="{{ next }}" id="next"/></div>{% endif %}
11 <p class="submit"> 12 <p class="submit">
12 - <input type="submit" name="submit" value="{% trans "Approve" %}" /> or <a href="{{ comment.get_absolute_url }}">cancel</a> 13 + <input type="submit" name="submit" value="{% trans "Approve" %}"/> or <a href="{{ comment.get_absolute_url }}">cancel</a>
13 </p> 14 </p>
14 </form> 15 </form>
15 {% endblock %} 16 {% endblock %}
1 <!DOCTYPE html> 1 <!DOCTYPE html>
2 <html> 2 <html>
3 <head> 3 <head>
4 - <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 4 + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
5 <title>{% block title %}{% endblock %}</title> 5 <title>{% block title %}{% endblock %}</title>
6 </head> 6 </head>
7 <body> 7 <body>
8 - {% block content %}{% endblock %} 8 +{% block content %}{% endblock %}
9 </body> 9 </body>
10 </html> 10 </html>
@@ -4,12 +4,13 @@ @@ -4,12 +4,13 @@
4 {% block title %}{% trans "Remove a comment" %}{% endblock %} 4 {% block title %}{% trans "Remove a comment" %}{% endblock %}
5 5
6 {% block content %} 6 {% block content %}
7 -<h1>{% trans "Really remove this comment?" %}</h1> 7 + <h1>{% trans "Really remove this comment?" %}</h1>
8 <blockquote>{{ comment|linebreaks }}</blockquote> 8 <blockquote>{{ comment|linebreaks }}</blockquote>
9 <form action="." method="post">{% csrf_token %} 9 <form action="." method="post">{% csrf_token %}
10 - {% if next %}<div><input type="hidden" name="next" value="{{ next }}" id="next" /></div>{% endif %} 10 + {% if next %}
  11 + <div><input type="hidden" name="next" value="{{ next }}" id="next"/></div>{% endif %}
11 <p class="submit"> 12 <p class="submit">
12 - <input type="submit" name="submit" value="{% trans "Remove" %}" /> or <a href="{{ comment.get_absolute_url }}">cancel</a> 13 + <input type="submit" name="submit" value="{% trans "Remove" %}"/> or <a href="{{ comment.get_absolute_url }}">cancel</a>
13 </p> 14 </p>
14 </form> 15 </form>
15 {% endblock %} 16 {% endblock %}
@@ -4,12 +4,14 @@ @@ -4,12 +4,14 @@
4 {% block title %}{% trans "Flag this comment" %}{% endblock %} 4 {% block title %}{% trans "Flag this comment" %}{% endblock %}
5 5
6 {% block content %} 6 {% block content %}
7 -<h1>{% trans "Really flag this comment?" %}</h1> 7 + <h1>{% trans "Really flag this comment?" %}</h1>
8 <blockquote>{{ comment|linebreaks }}</blockquote> 8 <blockquote>{{ comment|linebreaks }}</blockquote>
9 <form action="." method="post">{% csrf_token %} 9 <form action="." method="post">{% csrf_token %}
10 - {% if next %}<div><input type="hidden" name="next" value="{{ next }}" id="next" /></div>{% endif %} 10 + {% if next %}
  11 + <div><input type="hidden" name="next" value="{{ next }}" id="next"/></div>{% endif %}
11 <p class="submit"> 12 <p class="submit">
12 - <input type="submit" name="submit" value="{% trans "Flag" %}" /> or <a href="{{ comment.get_absolute_url }}">cancel</a> 13 + <input type="submit" name="submit" value="{% trans "Flag" %}"/> or <a
  14 + href="{{ comment.get_absolute_url }}">cancel</a>
13 </p> 15 </p>
14 </form> 16 </form>
15 {% endblock %} 17 {% endblock %}
1 {% load comments i18n %} 1 {% load comments i18n %}
2 <form action="{% comment_form_target %}" method="post">{% csrf_token %} 2 <form action="{% comment_form_target %}" method="post">{% csrf_token %}
3 - {% if next %}<div><input type="hidden" name="next" value="{{ next }}" /></div>{% endif %} 3 + {% if next %}
  4 + <div><input type="hidden" name="next" value="{{ next }}"/></div>{% endif %}
4 {% for field in form %} 5 {% for field in form %}
5 {% if field.is_hidden %} 6 {% if field.is_hidden %}
6 <div>{{ field }}</div> 7 <div>{{ field }}</div>
7 {% else %} 8 {% else %}
8 {% if field.errors %}{{ field.errors }}{% endif %} 9 {% if field.errors %}{{ field.errors }}{% endif %}
9 <p 10 <p
10 - {% if field.errors %} class="error"{% endif %}  
11 - {% ifequal field.name "honeypot" %} style="display:none;"{% endifequal %}> 11 + {% if field.errors %} class="error"{% endif %}
  12 + {% ifequal field.name "honeypot" %} style="display:none;"{% endifequal %}>
12 {{ field.label_tag }} {{ field }} 13 {{ field.label_tag }} {{ field }}
13 </p> 14 </p>
14 {% endif %} 15 {% endif %}
15 {% endfor %} 16 {% endfor %}
16 <p class="submit"> 17 <p class="submit">
17 - <input type="submit" name="post" class="submit-post" value="{% trans "Post" %}" />  
18 - <input type="submit" name="preview" class="submit-preview" value="{% trans "Preview" %}" /> 18 + <input type="submit" name="post" class="submit-post" value="{% trans "Post" %}"/>
  19 + <input type="submit" name="preview" class="submit-preview" value="{% trans "Preview" %}"/>
19 </p> 20 </p>
20 </form> 21 </form>
1 <dl id="comments"> 1 <dl id="comments">
2 {% for comment in comment_list %} 2 {% for comment in comment_list %}
3 <dt id="c{{ comment.id }}"> 3 <dt id="c{{ comment.id }}">
4 - {{ comment.submit_date }} - {{ comment.name }} 4 + {{ comment.submit_date }} - {{ comment.name }}
5 </dt> 5 </dt>
6 <dd> 6 <dd>
7 - <p>{{ comment.comment }}</p> 7 + <p>{{ comment.comment }}</p>
8 </dd> 8 </dd>
9 {% endfor %} 9 {% endfor %}
10 </dl> 10 </dl>
@@ -6,14 +6,17 @@ @@ -6,14 +6,17 @@
6 {% block content %} 6 {% block content %}
7 {% load comments %} 7 {% load comments %}
8 <form action="{% comment_form_target %}" method="post">{% csrf_token %} 8 <form action="{% comment_form_target %}" method="post">{% csrf_token %}
9 - {% if next %}<div><input type="hidden" name="next" value="{{ next }}" /></div>{% endif %} 9 + {% if next %}
  10 + <div><input type="hidden" name="next" value="{{ next }}"/></div>{% endif %}
10 {% if form.errors %} 11 {% if form.errors %}
11 - <h1>{% blocktrans count counter=form.errors|length %}Please correct the error below{% plural %}Please correct the errors below{% endblocktrans %}</h1> 12 + <h1>{% blocktrans count counter=form.errors|length %}Please correct the error below{% plural %}Please correct the
  13 + errors below{% endblocktrans %}</h1>
12 {% else %} 14 {% else %}
13 - <h1>{% trans "Preview your comment" %}</h1> 15 + <h1>{% trans "Preview your comment" %}</h1>
14 <blockquote>{{ comment|linebreaks }}</blockquote> 16 <blockquote>{{ comment|linebreaks }}</blockquote>
15 <p> 17 <p>
16 - {% trans "and" %} <input type="submit" name="submit" class="submit-post" value="{% trans "Post your comment" %}" id="submit" /> {% trans "or make changes" %}: 18 + {% trans "and" %} <input type="submit" name="submit" class="submit-post" value="{% trans "Post your comment" %}"
  19 + id="submit"/> {% trans "or make changes" %}:
17 </p> 20 </p>
18 {% endif %} 21 {% endif %}
19 {% for field in form %} 22 {% for field in form %}
@@ -22,15 +25,15 @@ @@ -22,15 +25,15 @@
22 {% else %} 25 {% else %}
23 {% if field.errors %}{{ field.errors }}{% endif %} 26 {% if field.errors %}{{ field.errors }}{% endif %}
24 <p 27 <p
25 - {% if field.errors %} class="error"{% endif %}  
26 - {% ifequal field.name "honeypot" %} style="display:none;"{% endifequal %}> 28 + {% if field.errors %} class="error"{% endif %}
  29 + {% ifequal field.name "honeypot" %} style="display:none;"{% endifequal %}>
27 {{ field.label_tag }} {{ field }} 30 {{ field.label_tag }} {{ field }}
28 </p> 31 </p>
29 {% endif %} 32 {% endif %}
30 {% endfor %} 33 {% endfor %}
31 <p class="submit"> 34 <p class="submit">
32 - <input type="submit" name="submit" class="submit-post" value="{% trans "Post" %}" />  
33 - <input type="submit" name="preview" class="submit-preview" value="{% trans "Preview" %}" /> 35 + <input type="submit" name="submit" class="submit-post" value="{% trans "Post" %}"/>
  36 + <input type="submit" name="preview" class="submit-preview" value="{% trans "Preview" %}"/>
34 </p> 37 </p>
35 </form> 38 </form>
36 {% endblock %} 39 {% endblock %}
@@ -28,8 +28,8 @@ class BaseCommentNode(template.Node): @@ -28,8 +28,8 @@ class BaseCommentNode(template.Node):
28 if tokens[3] != 'as': 28 if tokens[3] != 'as':
29 raise template.TemplateSyntaxError("Third argument in %r must be 'as'" % tokens[0]) 29 raise template.TemplateSyntaxError("Third argument in %r must be 'as'" % tokens[0])
30 return cls( 30 return cls(
31 - object_expr = parser.compile_filter(tokens[2]),  
32 - as_varname = tokens[4], 31 + object_expr=parser.compile_filter(tokens[2]),
  32 + as_varname=tokens[4],
33 ) 33 )
34 34
35 # {% get_whatever for app.model pk as varname %} 35 # {% get_whatever for app.model pk as varname %}
@@ -37,9 +37,9 @@ class BaseCommentNode(template.Node): @@ -37,9 +37,9 @@ class BaseCommentNode(template.Node):
37 if tokens[4] != 'as': 37 if tokens[4] != 'as':
38 raise template.TemplateSyntaxError("Fourth argument in %r must be 'as'" % tokens[0]) 38 raise template.TemplateSyntaxError("Fourth argument in %r must be 'as'" % tokens[0])
39 return cls( 39 return cls(
40 - ctype = BaseCommentNode.lookup_content_type(tokens[2], tokens[0]),  
41 - object_pk_expr = parser.compile_filter(tokens[3]),  
42 - as_varname = tokens[5] 40 + ctype=BaseCommentNode.lookup_content_type(tokens[2], tokens[0]),
  41 + object_pk_expr=parser.compile_filter(tokens[3]),
  42 + as_varname=tokens[5]
43 ) 43 )
44 44
45 else: 45 else:
@@ -57,7 +57,8 @@ class BaseCommentNode(template.Node): @@ -57,7 +57,8 @@ class BaseCommentNode(template.Node):
57 57
58 def __init__(self, ctype=None, object_pk_expr=None, object_expr=None, as_varname=None, comment=None): 58 def __init__(self, ctype=None, object_pk_expr=None, object_expr=None, as_varname=None, comment=None):
59 if ctype is None and object_expr is None: 59 if ctype is None and object_expr is None:
60 - raise template.TemplateSyntaxError("Comment nodes must be given either a literal object or a ctype and object pk.") 60 + raise template.TemplateSyntaxError(
  61 + "Comment nodes must be given either a literal object or a ctype and object pk.")
61 self.comment_model = django_comments.get_model() 62 self.comment_model = django_comments.get_model()
62 self.as_varname = as_varname 63 self.as_varname = as_varname
63 self.ctype = ctype 64 self.ctype = ctype
@@ -76,9 +77,9 @@ class BaseCommentNode(template.Node): @@ -76,9 +77,9 @@ class BaseCommentNode(template.Node):
76 return self.comment_model.objects.none() 77 return self.comment_model.objects.none()
77 78
78 qs = self.comment_model.objects.filter( 79 qs = self.comment_model.objects.filter(
79 - content_type = ctype,  
80 - object_pk = smart_text(object_pk),  
81 - site__pk = settings.SITE_ID, 80 + content_type=ctype,
  81 + object_pk=smart_text(object_pk),
  82 + site__pk=settings.SITE_ID,
82 ) 83 )
83 84
84 # The is_public and is_removed fields are implementation details of the 85 # The is_public and is_removed fields are implementation details of the
@@ -107,16 +108,21 @@ class BaseCommentNode(template.Node): @@ -107,16 +108,21 @@ class BaseCommentNode(template.Node):
107 """Subclasses should override this.""" 108 """Subclasses should override this."""
108 raise NotImplementedError 109 raise NotImplementedError
109 110
  111 +
110 class CommentListNode(BaseCommentNode): 112 class CommentListNode(BaseCommentNode):
111 """Insert a list of comments into the context.""" 113 """Insert a list of comments into the context."""
  114 +
112 def get_context_value_from_queryset(self, context, qs): 115 def get_context_value_from_queryset(self, context, qs):
113 return list(qs) 116 return list(qs)
114 117
  118 +
115 class CommentCountNode(BaseCommentNode): 119 class CommentCountNode(BaseCommentNode):
116 """Insert a count of comments into the context.""" 120 """Insert a count of comments into the context."""
  121 +
117 def get_context_value_from_queryset(self, context, qs): 122 def get_context_value_from_queryset(self, context, qs):
118 return qs.count() 123 return qs.count()
119 124
  125 +
120 class CommentFormNode(BaseCommentNode): 126 class CommentFormNode(BaseCommentNode):
121 """Insert a form for the comment model into the context.""" 127 """Insert a form for the comment model into the context."""
122 128
@@ -135,13 +141,14 @@ class CommentFormNode(BaseCommentNode): @@ -135,13 +141,14 @@ class CommentFormNode(BaseCommentNode):
135 return None 141 return None
136 else: 142 else:
137 object_pk = self.object_pk_expr.resolve(context, 143 object_pk = self.object_pk_expr.resolve(context,
138 - ignore_failures=True) 144 + ignore_failures=True)
139 return self.ctype.get_object_for_this_type(pk=object_pk) 145 return self.ctype.get_object_for_this_type(pk=object_pk)
140 146
141 def render(self, context): 147 def render(self, context):
142 context[self.as_varname] = self.get_form(context) 148 context[self.as_varname] = self.get_form(context)
143 return '' 149 return ''
144 150
  151 +
145 class RenderCommentFormNode(CommentFormNode): 152 class RenderCommentFormNode(CommentFormNode):
146 """Render the comment form directly""" 153 """Render the comment form directly"""
147 154
@@ -159,8 +166,8 @@ class RenderCommentFormNode(CommentFormNode): @@ -159,8 +166,8 @@ class RenderCommentFormNode(CommentFormNode):
159 # {% render_comment_form for app.models pk %} 166 # {% render_comment_form for app.models pk %}
160 elif len(tokens) == 4: 167 elif len(tokens) == 4:
161 return cls( 168 return cls(
162 - ctype = BaseCommentNode.lookup_content_type(tokens[2], tokens[0]),  
163 - object_pk_expr = parser.compile_filter(tokens[3]) 169 + ctype=BaseCommentNode.lookup_content_type(tokens[2], tokens[0]),
  170 + object_pk_expr=parser.compile_filter(tokens[3])
164 ) 171 )
165 172
166 def render(self, context): 173 def render(self, context):
@@ -172,12 +179,13 @@ class RenderCommentFormNode(CommentFormNode): @@ -172,12 +179,13 @@ class RenderCommentFormNode(CommentFormNode):
172 "comments/form.html" 179 "comments/form.html"
173 ] 180 ]
174 context.push() 181 context.push()
175 - formstr = render_to_string(template_search_list, {"form" : self.get_form(context)}, context) 182 + formstr = render_to_string(template_search_list, {"form": self.get_form(context)}, context)
176 context.pop() 183 context.pop()
177 return formstr 184 return formstr
178 else: 185 else:
179 return '' 186 return ''
180 187
  188 +
181 class RenderCommentListNode(CommentListNode): 189 class RenderCommentListNode(CommentListNode):
182 """Render the comment list directly""" 190 """Render the comment list directly"""
183 191
@@ -195,8 +203,8 @@ class RenderCommentListNode(CommentListNode): @@ -195,8 +203,8 @@ class RenderCommentListNode(CommentListNode):
195 # {% render_comment_list for app.models pk %} 203 # {% render_comment_list for app.models pk %}
196 elif len(tokens) == 4: 204 elif len(tokens) == 4:
197 return cls( 205 return cls(
198 - ctype = BaseCommentNode.lookup_content_type(tokens[2], tokens[0]),  
199 - object_pk_expr = parser.compile_filter(tokens[3]) 206 + ctype=BaseCommentNode.lookup_content_type(tokens[2], tokens[0]),
  207 + object_pk_expr=parser.compile_filter(tokens[3])
200 ) 208 )
201 209
202 def render(self, context): 210 def render(self, context):
@@ -210,13 +218,14 @@ class RenderCommentListNode(CommentListNode): @@ -210,13 +218,14 @@ class RenderCommentListNode(CommentListNode):
210 qs = self.get_queryset(context) 218 qs = self.get_queryset(context)
211 context.push() 219 context.push()
212 liststr = render_to_string(template_search_list, { 220 liststr = render_to_string(template_search_list, {
213 - "comment_list" : self.get_context_value_from_queryset(context, qs) 221 + "comment_list": self.get_context_value_from_queryset(context, qs)
214 }, context) 222 }, context)
215 context.pop() 223 context.pop()
216 return liststr 224 return liststr
217 else: 225 else:
218 return '' 226 return ''
219 227
  228 +
220 # We could just register each classmethod directly, but then we'd lose out on 229 # We could just register each classmethod directly, but then we'd lose out on
221 # the automagic docstrings-into-admin-docs tricks. So each node gets a cute 230 # the automagic docstrings-into-admin-docs tricks. So each node gets a cute
222 # wrapper function that just exists to hold the docstring. 231 # wrapper function that just exists to hold the docstring.
@@ -242,6 +251,7 @@ def get_comment_count(parser, token): @@ -242,6 +251,7 @@ def get_comment_count(parser, token):
242 """ 251 """
243 return CommentCountNode.handle_token(parser, token) 252 return CommentCountNode.handle_token(parser, token)
244 253
  254 +
245 @register.tag 255 @register.tag
246 def get_comment_list(parser, token): 256 def get_comment_list(parser, token):
247 """ 257 """
@@ -264,6 +274,7 @@ def get_comment_list(parser, token): @@ -264,6 +274,7 @@ def get_comment_list(parser, token):
264 """ 274 """
265 return CommentListNode.handle_token(parser, token) 275 return CommentListNode.handle_token(parser, token)
266 276
  277 +
267 @register.tag 278 @register.tag
268 def render_comment_list(parser, token): 279 def render_comment_list(parser, token):
269 """ 280 """
@@ -282,6 +293,7 @@ def render_comment_list(parser, token): @@ -282,6 +293,7 @@ def render_comment_list(parser, token):
282 """ 293 """
283 return RenderCommentListNode.handle_token(parser, token) 294 return RenderCommentListNode.handle_token(parser, token)
284 295
  296 +
285 @register.tag 297 @register.tag
286 def get_comment_form(parser, token): 298 def get_comment_form(parser, token):
287 """ 299 """
@@ -294,6 +306,7 @@ def get_comment_form(parser, token): @@ -294,6 +306,7 @@ def get_comment_form(parser, token):
294 """ 306 """
295 return CommentFormNode.handle_token(parser, token) 307 return CommentFormNode.handle_token(parser, token)
296 308
  309 +
297 @register.tag 310 @register.tag
298 def render_comment_form(parser, token): 311 def render_comment_form(parser, token):
299 """ 312 """
@@ -307,6 +320,7 @@ def render_comment_form(parser, token): @@ -307,6 +320,7 @@ def render_comment_form(parser, token):
307 """ 320 """
308 return RenderCommentFormNode.handle_token(parser, token) 321 return RenderCommentFormNode.handle_token(parser, token)
309 322
  323 +
310 @register.simple_tag 324 @register.simple_tag
311 def comment_form_target(): 325 def comment_form_target():
312 """ 326 """
@@ -318,6 +332,7 @@ def comment_form_target(): @@ -318,6 +332,7 @@ def comment_form_target():
318 """ 332 """
319 return django_comments.get_form_target() 333 return django_comments.get_form_target()
320 334
  335 +
321 @register.simple_tag 336 @register.simple_tag
322 def get_comment_permalink(comment, anchor_pattern=None): 337 def get_comment_permalink(comment, anchor_pattern=None):
323 """ 338 """
@@ -331,4 +346,3 @@ def get_comment_permalink(comment, anchor_pattern=None): @@ -331,4 +346,3 @@ def get_comment_permalink(comment, anchor_pattern=None):
331 if anchor_pattern: 346 if anchor_pattern:
332 return comment.get_absolute_url(anchor_pattern) 347 return comment.get_absolute_url(anchor_pattern)
333 return comment.get_absolute_url() 348 return comment.get_absolute_url()
334 -  
1 from django.conf.urls import patterns, url 1 from django.conf.urls import patterns, url
2 2
3 urlpatterns = patterns('django_comments.views', 3 urlpatterns = patterns('django_comments.views',
4 - url(r'^post/$', 'comments.post_comment', name='comments-post-comment'),  
5 - url(r'^posted/$', 'comments.comment_done', name='comments-comment-done'),  
6 - url(r'^flag/(\d+)/$', 'moderation.flag', name='comments-flag'),  
7 - url(r'^flagged/$', 'moderation.flag_done', name='comments-flag-done'),  
8 - url(r'^delete/(\d+)/$', 'moderation.delete', name='comments-delete'),  
9 - url(r'^deleted/$', 'moderation.delete_done', name='comments-delete-done'),  
10 - url(r'^approve/(\d+)/$', 'moderation.approve', name='comments-approve'),  
11 - url(r'^approved/$', 'moderation.approve_done', name='comments-approve-done'), 4 + url(r'^post/$', 'comments.post_comment', name='comments-post-comment'),
  5 + url(r'^posted/$', 'comments.comment_done', name='comments-comment-done'),
  6 + url(r'^flag/(\d+)/$', 'moderation.flag', name='comments-flag'),
  7 + url(r'^flagged/$', 'moderation.flag_done', name='comments-flag-done'),
  8 + url(r'^delete/(\d+)/$', 'moderation.delete', name='comments-delete'),
  9 + url(r'^deleted/$', 'moderation.delete_done', name='comments-delete-done'),
  10 + url(r'^approve/(\d+)/$', 'moderation.approve', name='comments-approve'),
  11 + url(r'^approved/$', 'moderation.approve_done', name='comments-approve-done'),
12 ) 12 )
13 13
14 urlpatterns += patterns('', 14 urlpatterns += patterns('',
15 - url(r'^cr/(\d+)/(.+)/$', 'django.contrib.contenttypes.views.shortcut', name='comments-url-redirect'), 15 + url(r'^cr/(\d+)/(.+)/$', 'django.contrib.contenttypes.views.shortcut',
  16 + name='comments-url-redirect'),
16 ) 17 )
@@ -15,12 +15,14 @@ import django_comments @@ -15,12 +15,14 @@ import django_comments
15 from django_comments import signals 15 from django_comments import signals
16 from django_comments.views.utils import next_redirect, confirmation_view 16 from django_comments.views.utils import next_redirect, confirmation_view
17 17
  18 +
18 class CommentPostBadRequest(http.HttpResponseBadRequest): 19 class CommentPostBadRequest(http.HttpResponseBadRequest):
19 """ 20 """
20 Response returned when a comment post is invalid. If ``DEBUG`` is on a 21 Response returned when a comment post is invalid. If ``DEBUG`` is on a
21 nice-ish error message will be displayed (for debugging purposes), but in 22 nice-ish error message will be displayed (for debugging purposes), but in
22 production mode a simple opaque 400 page will be displayed. 23 production mode a simple opaque 400 page will be displayed.
23 """ 24 """
  25 +
24 def __init__(self, why): 26 def __init__(self, why):
25 super(CommentPostBadRequest, self).__init__() 27 super(CommentPostBadRequest, self).__init__()
26 if settings.DEBUG: 28 if settings.DEBUG:
@@ -57,16 +59,15 @@ def post_comment(request, next=None, using=None): @@ -57,16 +59,15 @@ def post_comment(request, next=None, using=None):
57 "Invalid content_type value: %r" % escape(ctype)) 59 "Invalid content_type value: %r" % escape(ctype))
58 except AttributeError: 60 except AttributeError:
59 return CommentPostBadRequest( 61 return CommentPostBadRequest(
60 - "The given content-type %r does not resolve to a valid model." % \  
61 - escape(ctype)) 62 + "The given content-type %r does not resolve to a valid model." % escape(ctype))
62 except ObjectDoesNotExist: 63 except ObjectDoesNotExist:
63 return CommentPostBadRequest( 64 return CommentPostBadRequest(
64 - "No object matching content-type %r and object PK %r exists." % \  
65 - (escape(ctype), escape(object_pk))) 65 + "No object matching content-type %r and object PK %r exists." % (
  66 + escape(ctype), escape(object_pk)))
66 except (ValueError, ValidationError) as e: 67 except (ValueError, ValidationError) as e:
67 return CommentPostBadRequest( 68 return CommentPostBadRequest(
68 - "Attempting go get content-type %r and object PK %r exists raised %s" % \  
69 - (escape(ctype), escape(object_pk), e.__class__.__name__)) 69 + "Attempting go get content-type %r and object PK %r exists raised %s" % (
  70 + escape(ctype), escape(object_pk), e.__class__.__name__))
70 71
71 # Do we want to preview the comment? 72 # Do we want to preview the comment?
72 preview = "preview" in data 73 preview = "preview" in data
@@ -77,8 +78,7 @@ def post_comment(request, next=None, using=None): @@ -77,8 +78,7 @@ def post_comment(request, next=None, using=None):
77 # Check security information 78 # Check security information
78 if form.security_errors(): 79 if form.security_errors():
79 return CommentPostBadRequest( 80 return CommentPostBadRequest(
80 - "The comment form failed security verification: %s" % \  
81 - escape(str(form.security_errors()))) 81 + "The comment form failed security verification: %s" % escape(str(form.security_errors())))
82 82
83 # If there are errors or if we requested a preview show the comment 83 # If there are errors or if we requested a preview show the comment
84 if form.errors or preview: 84 if form.errors or preview:
@@ -116,7 +116,7 @@ def post_comment(request, next=None, using=None): @@ -116,7 +116,7 @@ def post_comment(request, next=None, using=None):
116 ) 116 )
117 117
118 for (receiver, response) in responses: 118 for (receiver, response) in responses:
119 - if response == False: 119 + if response is False:
120 return CommentPostBadRequest( 120 return CommentPostBadRequest(
121 "comment_will_be_posted receiver %r killed the comment" % receiver.__name__) 121 "comment_will_be_posted receiver %r killed the comment" % receiver.__name__)
122 122
@@ -129,7 +129,8 @@ def post_comment(request, next=None, using=None): @@ -129,7 +129,8 @@ def post_comment(request, next=None, using=None):
129 ) 129 )
130 130
131 return next_redirect(request, fallback=next or 'comments-comment-done', 131 return next_redirect(request, fallback=next or 'comments-comment-done',
132 - c=comment._get_pk_val()) 132 + c=comment._get_pk_val())
  133 +
133 134
134 comment_done = confirmation_view( 135 comment_done = confirmation_view(
135 template="comments/posted.html", 136 template="comments/posted.html",
@@ -10,6 +10,7 @@ import django_comments @@ -10,6 +10,7 @@ import django_comments
10 from django_comments import signals 10 from django_comments import signals
11 from django_comments.views.utils import next_redirect, confirmation_view 11 from django_comments.views.utils import next_redirect, confirmation_view
12 12
  13 +
13 @csrf_protect 14 @csrf_protect
14 @login_required 15 @login_required
15 def flag(request, comment_id, next=None): 16 def flag(request, comment_id, next=None):
@@ -27,15 +28,17 @@ def flag(request, comment_id, next=None): @@ -27,15 +28,17 @@ def flag(request, comment_id, next=None):
27 if request.method == 'POST': 28 if request.method == 'POST':
28 perform_flag(request, comment) 29 perform_flag(request, comment)
29 return next_redirect(request, fallback=next or 'comments-flag-done', 30 return next_redirect(request, fallback=next or 'comments-flag-done',
30 - c=comment.pk) 31 + c=comment.pk)
31 32
32 # Render a form on GET 33 # Render a form on GET
33 else: 34 else:
34 - return render_to_response('comments/flag.html', 35 + return render_to_response(
  36 + 'comments/flag.html',
35 {'comment': comment, "next": next}, 37 {'comment': comment, "next": next},
36 template.RequestContext(request) 38 template.RequestContext(request)
37 ) 39 )
38 40
  41 +
39 @csrf_protect 42 @csrf_protect
40 @permission_required("django_comments.can_moderate") 43 @permission_required("django_comments.can_moderate")
41 def delete(request, comment_id, next=None): 44 def delete(request, comment_id, next=None):
@@ -55,15 +58,17 @@ def delete(request, comment_id, next=None): @@ -55,15 +58,17 @@ def delete(request, comment_id, next=None):
55 # Flag the comment as deleted instead of actually deleting it. 58 # Flag the comment as deleted instead of actually deleting it.
56 perform_delete(request, comment) 59 perform_delete(request, comment)
57 return next_redirect(request, fallback=next or 'comments-delete-done', 60 return next_redirect(request, fallback=next or 'comments-delete-done',
58 - c=comment.pk) 61 + c=comment.pk)
59 62
60 # Render a form on GET 63 # Render a form on GET
61 else: 64 else:
62 - return render_to_response('comments/delete.html', 65 + return render_to_response(
  66 + 'comments/delete.html',
63 {'comment': comment, "next": next}, 67 {'comment': comment, "next": next},
64 template.RequestContext(request) 68 template.RequestContext(request)
65 ) 69 )
66 70
  71 +
67 @csrf_protect 72 @csrf_protect
68 @permission_required("django_comments.can_moderate") 73 @permission_required("django_comments.can_moderate")
69 def approve(request, comment_id, next=None): 74 def approve(request, comment_id, next=None):
@@ -83,15 +88,17 @@ def approve(request, comment_id, next=None): @@ -83,15 +88,17 @@ def approve(request, comment_id, next=None):
83 # Flag the comment as approved. 88 # Flag the comment as approved.
84 perform_approve(request, comment) 89 perform_approve(request, comment)
85 return next_redirect(request, fallback=next or 'comments-approve-done', 90 return next_redirect(request, fallback=next or 'comments-approve-done',
86 - c=comment.pk) 91 + c=comment.pk)
87 92
88 # Render a form on GET 93 # Render a form on GET
89 else: 94 else:
90 - return render_to_response('comments/approve.html', 95 + return render_to_response(
  96 + 'comments/approve.html',
91 {'comment': comment, "next": next}, 97 {'comment': comment, "next": next},
92 template.RequestContext(request) 98 template.RequestContext(request)
93 ) 99 )
94 100
  101 +
95 # The following functions actually perform the various flag/aprove/delete 102 # The following functions actually perform the various flag/aprove/delete
96 # actions. They've been broken out into separate functions to that they 103 # actions. They've been broken out into separate functions to that they
97 # may be called from admin actions. 104 # may be called from admin actions.
@@ -101,40 +108,41 @@ def perform_flag(request, comment): @@ -101,40 +108,41 @@ def perform_flag(request, comment):
101 Actually perform the flagging of a comment from a request. 108 Actually perform the flagging of a comment from a request.
102 """ 109 """
103 flag, created = django_comments.models.CommentFlag.objects.get_or_create( 110 flag, created = django_comments.models.CommentFlag.objects.get_or_create(
104 - comment = comment,  
105 - user = request.user,  
106 - flag = django_comments.models.CommentFlag.SUGGEST_REMOVAL 111 + comment=comment,
  112 + user=request.user,
  113 + flag=django_comments.models.CommentFlag.SUGGEST_REMOVAL
107 ) 114 )
108 signals.comment_was_flagged.send( 115 signals.comment_was_flagged.send(
109 - sender = comment.__class__,  
110 - comment = comment,  
111 - flag = flag,  
112 - created = created,  
113 - request = request, 116 + sender=comment.__class__,
  117 + comment=comment,
  118 + flag=flag,
  119 + created=created,
  120 + request=request,
114 ) 121 )
115 122
  123 +
116 def perform_delete(request, comment): 124 def perform_delete(request, comment):
117 flag, created = django_comments.models.CommentFlag.objects.get_or_create( 125 flag, created = django_comments.models.CommentFlag.objects.get_or_create(
118 - comment = comment,  
119 - user = request.user,  
120 - flag = django_comments.models.CommentFlag.MODERATOR_DELETION 126 + comment=comment,
  127 + user=request.user,
  128 + flag=django_comments.models.CommentFlag.MODERATOR_DELETION
121 ) 129 )
122 comment.is_removed = True 130 comment.is_removed = True
123 comment.save() 131 comment.save()
124 signals.comment_was_flagged.send( 132 signals.comment_was_flagged.send(
125 - sender = comment.__class__,  
126 - comment = comment,  
127 - flag = flag,  
128 - created = created,  
129 - request = request, 133 + sender=comment.__class__,
  134 + comment=comment,
  135 + flag=flag,
  136 + created=created,
  137 + request=request,
130 ) 138 )
131 139
132 140
133 def perform_approve(request, comment): 141 def perform_approve(request, comment):
134 flag, created = django_comments.models.CommentFlag.objects.get_or_create( 142 flag, created = django_comments.models.CommentFlag.objects.get_or_create(
135 - comment = comment,  
136 - user = request.user,  
137 - flag = django_comments.models.CommentFlag.MODERATOR_APPROVAL, 143 + comment=comment,
  144 + user=request.user,
  145 + flag=django_comments.models.CommentFlag.MODERATOR_APPROVAL,
138 ) 146 )
139 147
140 comment.is_removed = False 148 comment.is_removed = False
@@ -142,24 +150,24 @@ def perform_approve(request, comment): @@ -142,24 +150,24 @@ def perform_approve(request, comment):
142 comment.save() 150 comment.save()
143 151
144 signals.comment_was_flagged.send( 152 signals.comment_was_flagged.send(
145 - sender = comment.__class__,  
146 - comment = comment,  
147 - flag = flag,  
148 - created = created,  
149 - request = request, 153 + sender=comment.__class__,
  154 + comment=comment,
  155 + flag=flag,
  156 + created=created,
  157 + request=request,
150 ) 158 )
151 159
152 # Confirmation views. 160 # Confirmation views.
153 161
154 flag_done = confirmation_view( 162 flag_done = confirmation_view(
155 - template = "comments/flagged.html",  
156 - doc = 'Displays a "comment was flagged" success page.' 163 + template="comments/flagged.html",
  164 + doc='Displays a "comment was flagged" success page.'
157 ) 165 )
158 delete_done = confirmation_view( 166 delete_done = confirmation_view(
159 - template = "comments/deleted.html",  
160 - doc = 'Displays a "comment was deleted" success page.' 167 + template="comments/deleted.html",
  168 + doc='Displays a "comment was deleted" success page.'
161 ) 169 )
162 approve_done = confirmation_view( 170 approve_done = confirmation_view(
163 - template = "comments/approved.html",  
164 - doc = 'Displays a "comment was approved" success page.' 171 + template="comments/approved.html",
  172 + doc='Displays a "comment was approved" success page.'
165 ) 173 )
@@ -3,9 +3,10 @@ A few bits of helper functions for comment views. @@ -3,9 +3,10 @@ A few bits of helper functions for comment views.
3 """ 3 """
4 4
5 import textwrap 5 import textwrap
  6 +
6 try: 7 try:
7 from urllib.parse import urlencode 8 from urllib.parse import urlencode
8 -except ImportError: # Python 2 9 +except ImportError: # Python 2
9 from urllib import urlencode 10 from urllib import urlencode
10 11
11 from django.http import HttpResponseRedirect 12 from django.http import HttpResponseRedirect
@@ -16,6 +17,7 @@ from django.utils.http import is_safe_url @@ -16,6 +17,7 @@ from django.utils.http import is_safe_url
16 17
17 import django_comments 18 import django_comments
18 19
  20 +
19 def next_redirect(request, fallback, **get_kwargs): 21 def next_redirect(request, fallback, **get_kwargs):
20 """ 22 """
21 Handle the "where should I go next?" part of comment views. 23 Handle the "where should I go next?" part of comment views.
@@ -42,11 +44,13 @@ def next_redirect(request, fallback, **get_kwargs): @@ -42,11 +44,13 @@ def next_redirect(request, fallback, **get_kwargs):
42 next += joiner + urlencode(get_kwargs) + anchor 44 next += joiner + urlencode(get_kwargs) + anchor
43 return HttpResponseRedirect(next) 45 return HttpResponseRedirect(next)
44 46
  47 +
45 def confirmation_view(template, doc="Display a confirmation view."): 48 def confirmation_view(template, doc="Display a confirmation view."):
46 """ 49 """
47 Confirmation view generator for the "comment was 50 Confirmation view generator for the "comment was
48 posted/flagged/deleted/approved" views. 51 posted/flagged/deleted/approved" views.
49 """ 52 """
  53 +
50 def confirmed(request): 54 def confirmed(request):
51 comment = None 55 comment = None
52 if 'c' in request.GET: 56 if 'c' in request.GET:
@@ -54,7 +58,8 @@ def confirmation_view(template, doc="Display a confirmation view."): @@ -54,7 +58,8 @@ def confirmation_view(template, doc="Display a confirmation view."):
54 comment = django_comments.get_model().objects.get(pk=request.GET['c']) 58 comment = django_comments.get_model().objects.get(pk=request.GET['c'])
55 except (ObjectDoesNotExist, ValueError): 59 except (ObjectDoesNotExist, ValueError):
56 pass 60 pass
57 - return render_to_response(template, 61 + return render_to_response(
  62 + template,
58 {'comment': comment}, 63 {'comment': comment},
59 context_instance=RequestContext(request) 64 context_instance=RequestContext(request)
60 ) 65 )
@@ -11,7 +11,8 @@ @@ -11,7 +11,8 @@
11 # All configuration values have a default; values that are commented out 11 # All configuration values have a default; values that are commented out
12 # serve to show the default. 12 # serve to show the default.
13 13
14 -import sys, os 14 +import os
  15 +import sys
15 16
16 # If extensions (or modules to document with autodoc) are in another directory, 17 # If extensions (or modules to document with autodoc) are in another directory,
17 # add these directories to sys.path here. If the directory is relative to the 18 # add these directories to sys.path here. If the directory is relative to the
  1 +[flake8]
  2 +exclude = docs/*
  3 +ignore = E128
  4 +max-line-length = 119
  5 +
  6 +[wheel]
  7 +universal = 1
@@ -2,29 +2,35 @@ from django.core import urlresolvers @@ -2,29 +2,35 @@ from django.core import urlresolvers
2 from .models import CustomComment 2 from .models import CustomComment
3 from .forms import CustomCommentForm 3 from .forms import CustomCommentForm
4 4
  5 +
5 def get_model(): 6 def get_model():
6 return CustomComment 7 return CustomComment
7 8
  9 +
8 def get_form(): 10 def get_form():
9 return CustomCommentForm 11 return CustomCommentForm
10 12
  13 +
11 def get_form_target(): 14 def get_form_target():
12 return urlresolvers.reverse( 15 return urlresolvers.reverse(
13 "custom_comments.views.custom_submit_comment" 16 "custom_comments.views.custom_submit_comment"
14 ) 17 )
15 18
  19 +
16 def get_flag_url(c): 20 def get_flag_url(c):
17 return urlresolvers.reverse( 21 return urlresolvers.reverse(
18 "custom_comments.views.custom_flag_comment", 22 "custom_comments.views.custom_flag_comment",
19 args=(c.id,) 23 args=(c.id,)
20 ) 24 )
21 25
  26 +
22 def get_delete_url(c): 27 def get_delete_url(c):
23 return urlresolvers.reverse( 28 return urlresolvers.reverse(
24 "custom_comments.views.custom_delete_comment", 29 "custom_comments.views.custom_delete_comment",
25 args=(c.id,) 30 args=(c.id,)
26 ) 31 )
27 32
  33 +
28 def get_approve_url(c): 34 def get_approve_url(c):
29 return urlresolvers.reverse( 35 return urlresolvers.reverse(
30 "custom_comments.views.custom_approve_comment", 36 "custom_comments.views.custom_approve_comment",
@@ -4,11 +4,14 @@ from django.http import HttpResponse @@ -4,11 +4,14 @@ from django.http import HttpResponse
4 def custom_submit_comment(request): 4 def custom_submit_comment(request):
5 return HttpResponse("Hello from the custom submit comment view.") 5 return HttpResponse("Hello from the custom submit comment view.")
6 6
  7 +
7 def custom_flag_comment(request, comment_id): 8 def custom_flag_comment(request, comment_id):
8 return HttpResponse("Hello from the custom flag view.") 9 return HttpResponse("Hello from the custom flag view.")
9 10
  11 +
10 def custom_delete_comment(request, comment_id): 12 def custom_delete_comment(request, comment_id):
11 return HttpResponse("Hello from the custom delete view.") 13 return HttpResponse("Hello from the custom delete view.")
12 14
  15 +
13 def custom_approve_comment(request, comment_id): 16 def custom_approve_comment(request, comment_id):
14 return HttpResponse("Hello from the custom approve view.") 17 return HttpResponse("Hello from the custom approve view.")
@@ -14,8 +14,8 @@ sys.path[0:0] = [here, parent] @@ -14,8 +14,8 @@ sys.path[0:0] = [here, parent]
14 14
15 from django.conf import settings 15 from django.conf import settings
16 settings.configure( 16 settings.configure(
17 - DATABASES = {'default': {'ENGINE': 'django.db.backends.sqlite3'}},  
18 - INSTALLED_APPS = [ 17 + DATABASES={'default': {'ENGINE': 'django.db.backends.sqlite3'}},
  18 + INSTALLED_APPS=[
19 "django.contrib.auth", 19 "django.contrib.auth",
20 "django.contrib.contenttypes", 20 "django.contrib.contenttypes",
21 "django.contrib.sessions", 21 "django.contrib.sessions",
@@ -30,13 +30,14 @@ settings.configure( @@ -30,13 +30,14 @@ settings.configure(
30 'django.contrib.auth.middleware.AuthenticationMiddleware', 30 'django.contrib.auth.middleware.AuthenticationMiddleware',
31 'django.contrib.messages.middleware.MessageMiddleware', 31 'django.contrib.messages.middleware.MessageMiddleware',
32 ), 32 ),
33 - ROOT_URLCONF = 'testapp.urls',  
34 - SECRET_KEY = "it's a secret to everyone",  
35 - SITE_ID = 1, 33 + ROOT_URLCONF='testapp.urls',
  34 + SECRET_KEY="it's a secret to everyone",
  35 + SITE_ID=1,
36 ) 36 )
37 37
38 from django.test.runner import DiscoverRunner 38 from django.test.runner import DiscoverRunner
39 39
  40 +
40 def main(): 41 def main():
41 if django.VERSION >= (1, 7): 42 if django.VERSION >= (1, 7):
42 django.setup() 43 django.setup()
@@ -17,6 +17,7 @@ class Author(models.Model): @@ -17,6 +17,7 @@ class Author(models.Model):
17 def __str__(self): 17 def __str__(self):
18 return '%s %s' % (self.first_name, self.last_name) 18 return '%s %s' % (self.first_name, self.last_name)
19 19
  20 +
20 @python_2_unicode_compatible 21 @python_2_unicode_compatible
21 class Article(models.Model): 22 class Article(models.Model):
22 author = models.ForeignKey(Author) 23 author = models.ForeignKey(Author)
@@ -25,6 +26,7 @@ class Article(models.Model): @@ -25,6 +26,7 @@ class Article(models.Model):
25 def __str__(self): 26 def __str__(self):
26 return self.headline 27 return self.headline
27 28
  29 +
28 @python_2_unicode_compatible 30 @python_2_unicode_compatible
29 class Entry(models.Model): 31 class Entry(models.Model):
30 title = models.CharField(max_length=250) 32 title = models.CharField(max_length=250)
@@ -35,5 +37,6 @@ class Entry(models.Model): @@ -35,5 +37,6 @@ class Entry(models.Model):
35 def __str__(self): 37 def __str__(self):
36 return self.title 38 return self.title
37 39
  40 +
38 class Book(models.Model): 41 class Book(models.Model):
39 dewey_decimal = models.DecimalField(primary_key=True, decimal_places=2, max_digits=5) 42 dewey_decimal = models.DecimalField(primary_key=True, decimal_places=2, max_digits=5)
@@ -14,70 +14,73 @@ from ..models import Article, Author @@ -14,70 +14,73 @@ from ..models import Article, Author
14 # Shortcut 14 # Shortcut
15 CT = ContentType.objects.get_for_model 15 CT = ContentType.objects.get_for_model
16 16
17 -# Helper base class for comment tests that need data. 17 +
18 @override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.UnsaltedMD5PasswordHasher',)) 18 @override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.UnsaltedMD5PasswordHasher',))
19 class CommentTestCase(TestCase): 19 class CommentTestCase(TestCase):
  20 + """
  21 + Helper base class for comment tests that need data.
  22 + """
20 fixtures = ["comment_tests"] 23 fixtures = ["comment_tests"]
21 urls = 'testapp.urls_default' 24 urls = 'testapp.urls_default'
22 25
23 def createSomeComments(self): 26 def createSomeComments(self):
24 # Two anonymous comments on two different objects 27 # Two anonymous comments on two different objects
25 c1 = Comment.objects.create( 28 c1 = Comment.objects.create(
26 - content_type = CT(Article),  
27 - object_pk = "1",  
28 - user_name = "Joe Somebody",  
29 - user_email = "jsomebody@example.com",  
30 - user_url = "http://example.com/~joe/",  
31 - comment = "First!",  
32 - site = Site.objects.get_current(), 29 + content_type=CT(Article),
  30 + object_pk="1",
  31 + user_name="Joe Somebody",
  32 + user_email="jsomebody@example.com",
  33 + user_url="http://example.com/~joe/",
  34 + comment="First!",
  35 + site=Site.objects.get_current(),
33 ) 36 )
34 c2 = Comment.objects.create( 37 c2 = Comment.objects.create(
35 - content_type = CT(Author),  
36 - object_pk = "1",  
37 - user_name = "Joe Somebody",  
38 - user_email = "jsomebody@example.com",  
39 - user_url = "http://example.com/~joe/",  
40 - comment = "First here, too!",  
41 - site = Site.objects.get_current(), 38 + content_type=CT(Author),
  39 + object_pk="1",
  40 + user_name="Joe Somebody",
  41 + user_email="jsomebody@example.com",
  42 + user_url="http://example.com/~joe/",
  43 + comment="First here, too!",
  44 + site=Site.objects.get_current(),
42 ) 45 )
43 46
44 # Two authenticated comments: one on the same Article, and 47 # Two authenticated comments: one on the same Article, and
45 # one on a different Author 48 # one on a different Author
46 user = User.objects.create( 49 user = User.objects.create(
47 - username = "frank_nobody",  
48 - first_name = "Frank",  
49 - last_name = "Nobody",  
50 - email = "fnobody@example.com",  
51 - password = "",  
52 - is_staff = False,  
53 - is_active = True,  
54 - is_superuser = False, 50 + username="frank_nobody",
  51 + first_name="Frank",
  52 + last_name="Nobody",
  53 + email="fnobody@example.com",
  54 + password="",
  55 + is_staff=False,
  56 + is_active=True,
  57 + is_superuser=False,
55 ) 58 )
56 c3 = Comment.objects.create( 59 c3 = Comment.objects.create(
57 - content_type = CT(Article),  
58 - object_pk = "1",  
59 - user = user,  
60 - user_url = "http://example.com/~frank/",  
61 - comment = "Damn, I wanted to be first.",  
62 - site = Site.objects.get_current(), 60 + content_type=CT(Article),
  61 + object_pk="1",
  62 + user=user,
  63 + user_url="http://example.com/~frank/",
  64 + comment="Damn, I wanted to be first.",
  65 + site=Site.objects.get_current(),
63 ) 66 )
64 c4 = Comment.objects.create( 67 c4 = Comment.objects.create(
65 - content_type = CT(Author),  
66 - object_pk = "2",  
67 - user = user,  
68 - user_url = "http://example.com/~frank/",  
69 - comment = "You get here first, too?",  
70 - site = Site.objects.get_current(), 68 + content_type=CT(Author),
  69 + object_pk="2",
  70 + user=user,
  71 + user_url="http://example.com/~frank/",
  72 + comment="You get here first, too?",
  73 + site=Site.objects.get_current(),
71 ) 74 )
72 75
73 return c1, c2, c3, c4 76 return c1, c2, c3, c4
74 77
75 def getData(self): 78 def getData(self):
76 return { 79 return {
77 - 'name' : 'Jim Bob',  
78 - 'email' : 'jim.bob@example.com',  
79 - 'url' : '',  
80 - 'comment' : 'This is my comment', 80 + 'name': 'Jim Bob',
  81 + 'email': 'jim.bob@example.com',
  82 + 'url': '',
  83 + 'comment': 'This is my comment',
81 } 84 }
82 85
83 def getValidData(self, obj): 86 def getValidData(self, obj):
@@ -32,7 +32,7 @@ class CommentAppAPITests(CommentTestCase): @@ -32,7 +32,7 @@ class CommentAppAPITests(CommentTestCase):
32 ) 32 )
33 def testGetMissingCommentApp(self): 33 def testGetMissingCommentApp(self):
34 with six.assertRaisesRegex(self, ImproperlyConfigured, 'missing_app'): 34 with six.assertRaisesRegex(self, ImproperlyConfigured, 'missing_app'):
35 - _ = django_comments.get_comment_app() 35 + django_comments.get_comment_app()
36 36
37 def testGetForm(self): 37 def testGetForm(self):
38 self.assertEqual(django_comments.get_form(), CommentForm) 38 self.assertEqual(django_comments.get_form(), CommentForm)
@@ -14,25 +14,31 @@ from ..models import Entry @@ -14,25 +14,31 @@ from ..models import Entry
14 class EntryModerator1(CommentModerator): 14 class EntryModerator1(CommentModerator):
15 email_notification = True 15 email_notification = True
16 16
  17 +
17 class EntryModerator2(CommentModerator): 18 class EntryModerator2(CommentModerator):
18 enable_field = 'enable_comments' 19 enable_field = 'enable_comments'
19 20
  21 +
20 class EntryModerator3(CommentModerator): 22 class EntryModerator3(CommentModerator):
21 auto_close_field = 'pub_date' 23 auto_close_field = 'pub_date'
22 close_after = 7 24 close_after = 7
23 25
  26 +
24 class EntryModerator4(CommentModerator): 27 class EntryModerator4(CommentModerator):
25 auto_moderate_field = 'pub_date' 28 auto_moderate_field = 'pub_date'
26 moderate_after = 7 29 moderate_after = 7
27 30
  31 +
28 class EntryModerator5(CommentModerator): 32 class EntryModerator5(CommentModerator):
29 auto_moderate_field = 'pub_date' 33 auto_moderate_field = 'pub_date'
30 moderate_after = 0 34 moderate_after = 0
31 35
  36 +
32 class EntryModerator6(CommentModerator): 37 class EntryModerator6(CommentModerator):
33 auto_close_field = 'pub_date' 38 auto_close_field = 'pub_date'
34 close_after = 0 39 close_after = 0
35 40
  41 +
36 class CommentUtilsModeratorTests(CommentTestCase): 42 class CommentUtilsModeratorTests(CommentTestCase):
37 fixtures = ["comment_utils.xml"] 43 fixtures = ["comment_utils.xml"]
38 44
@@ -14,6 +14,7 @@ from ..models import Article, Book @@ -14,6 +14,7 @@ from ..models import Article, Book
14 14
15 post_redirect_re = re.compile(r'^http://testserver/posted/\?c=(?P<pk>\d+$)') 15 post_redirect_re = re.compile(r'^http://testserver/posted/\?c=(?P<pk>\d+$)')
16 16
  17 +
17 class CommentViewTests(CommentTestCase): 18 class CommentViewTests(CommentTestCase):
18 19
19 def testPostCommentHTTPMethods(self): 20 def testPostCommentHTTPMethods(self):
@@ -214,7 +215,8 @@ class CommentViewTests(CommentTestCase): @@ -214,7 +215,8 @@ class CommentViewTests(CommentTestCase):
214 Test that the comment_will_be_posted signal can prevent the comment from 215 Test that the comment_will_be_posted signal can prevent the comment from
215 actually getting saved 216 actually getting saved
216 """ 217 """
217 - def receive(sender, **kwargs): return False 218 + def receive(sender, **kwargs):
  219 + return False
218 signals.comment_will_be_posted.connect(receive, dispatch_uid="comment-test") 220 signals.comment_will_be_posted.connect(receive, dispatch_uid="comment-test")
219 a = Article.objects.get(pk=1) 221 a = Article.objects.get(pk=1)
220 data = self.getValidData(a) 222 data = self.getValidData(a)
@@ -229,7 +231,7 @@ class CommentViewTests(CommentTestCase): @@ -229,7 +231,7 @@ class CommentViewTests(CommentTestCase):
229 it gets posted 231 it gets posted
230 """ 232 """
231 def receive(sender, **kwargs): 233 def receive(sender, **kwargs):
232 - # a bad but effective spam filter :)... 234 + # a bad but effective spam filter :)...
233 kwargs['comment'].is_public = False 235 kwargs['comment'].is_public = False
234 236
235 signals.comment_will_be_posted.connect(receive) 237 signals.comment_will_be_posted.connect(receive)
@@ -244,21 +246,21 @@ class CommentViewTests(CommentTestCase): @@ -244,21 +246,21 @@ class CommentViewTests(CommentTestCase):
244 response = self.client.post("/post/", data) 246 response = self.client.post("/post/", data)
245 location = response["Location"] 247 location = response["Location"]
246 match = post_redirect_re.match(location) 248 match = post_redirect_re.match(location)
247 - self.assertTrue(match != None, "Unexpected redirect location: %s" % location) 249 + self.assertisNotNone(match, "Unexpected redirect location: %s" % location)
248 250
249 data["next"] = "/somewhere/else/" 251 data["next"] = "/somewhere/else/"
250 data["comment"] = "This is another comment" 252 data["comment"] = "This is another comment"
251 response = self.client.post("/post/", data) 253 response = self.client.post("/post/", data)
252 location = response["Location"] 254 location = response["Location"]
253 match = re.search(r"^http://testserver/somewhere/else/\?c=\d+$", location) 255 match = re.search(r"^http://testserver/somewhere/else/\?c=\d+$", location)
254 - self.assertTrue(match != None, "Unexpected redirect location: %s" % location) 256 + self.assertIsNotNone(match, "Unexpected redirect location: %s" % location)
255 257
256 data["next"] = "http://badserver/somewhere/else/" 258 data["next"] = "http://badserver/somewhere/else/"
257 data["comment"] = "This is another comment with an unsafe next url" 259 data["comment"] = "This is another comment with an unsafe next url"
258 response = self.client.post("/post/", data) 260 response = self.client.post("/post/", data)
259 location = response["Location"] 261 location = response["Location"]
260 match = post_redirect_re.match(location) 262 match = post_redirect_re.match(location)
261 - self.assertTrue(match != None, "Unsafe redirection to: %s" % location) 263 + self.assertIsNotNone(match, "Unsafe redirection to: %s" % location)
262 264
263 def testCommentDoneView(self): 265 def testCommentDoneView(self):
264 a = Article.objects.get(pk=1) 266 a = Article.objects.get(pk=1)
@@ -266,7 +268,7 @@ class CommentViewTests(CommentTestCase): @@ -266,7 +268,7 @@ class CommentViewTests(CommentTestCase):
266 response = self.client.post("/post/", data) 268 response = self.client.post("/post/", data)
267 location = response["Location"] 269 location = response["Location"]
268 match = post_redirect_re.match(location) 270 match = post_redirect_re.match(location)
269 - self.assertTrue(match != None, "Unexpected redirect location: %s" % location) 271 + self.assertIsNotNone(match, "Unexpected redirect location: %s" % location)
270 pk = int(match.group('pk')) 272 pk = int(match.group('pk'))
271 response = self.client.get(location) 273 response = self.client.get(location)
272 self.assertTemplateUsed(response, "comments/posted.html") 274 self.assertTemplateUsed(response, "comments/posted.html")
@@ -283,7 +285,7 @@ class CommentViewTests(CommentTestCase): @@ -283,7 +285,7 @@ class CommentViewTests(CommentTestCase):
283 response = self.client.post("/post/", data) 285 response = self.client.post("/post/", data)
284 location = response["Location"] 286 location = response["Location"]
285 match = re.search(r"^http://testserver/somewhere/else/\?foo=bar&c=\d+$", location) 287 match = re.search(r"^http://testserver/somewhere/else/\?foo=bar&c=\d+$", location)
286 - self.assertTrue(match != None, "Unexpected redirect location: %s" % location) 288 + self.assertIsNotNone(match, "Unexpected redirect location: %s" % location)
287 289
288 def testCommentPostRedirectWithInvalidIntegerPK(self): 290 def testCommentPostRedirectWithInvalidIntegerPK(self):
289 """ 291 """
@@ -312,7 +314,7 @@ class CommentViewTests(CommentTestCase): @@ -312,7 +314,7 @@ class CommentViewTests(CommentTestCase):
312 response = self.client.post("/post/", data) 314 response = self.client.post("/post/", data)
313 location = response["Location"] 315 location = response["Location"]
314 match = re.search(r"^http://testserver/somewhere/else/\?foo=bar&c=\d+#baz$", location) 316 match = re.search(r"^http://testserver/somewhere/else/\?foo=bar&c=\d+#baz$", location)
315 - self.assertTrue(match != None, "Unexpected redirect location: %s" % location) 317 + self.assertIsNotNone(match, "Unexpected redirect location: %s" % location)
316 318
317 # Without a query string 319 # Without a query string
318 a = Article.objects.get(pk=1) 320 a = Article.objects.get(pk=1)
@@ -322,4 +324,4 @@ class CommentViewTests(CommentTestCase): @@ -322,4 +324,4 @@ class CommentViewTests(CommentTestCase):
322 response = self.client.post("/post/", data) 324 response = self.client.post("/post/", data)
323 location = response["Location"] 325 location = response["Location"]
324 match = re.search(r"^http://testserver/somewhere/else/\?c=\d+#baz$", location) 326 match = re.search(r"^http://testserver/somewhere/else/\?c=\d+#baz$", location)
325 - self.assertTrue(match != None, "Unexpected redirect location: %s" % location) 327 + self.assertIsNotNone(match, "Unexpected redirect location: %s" % location)
@@ -17,17 +17,17 @@ class CommentFeedTests(CommentTestCase): @@ -17,17 +17,17 @@ class CommentFeedTests(CommentTestCase):
17 feed_url = '/rss/comments/' 17 feed_url = '/rss/comments/'
18 18
19 def setUp(self): 19 def setUp(self):
20 - site_2 = Site.objects.create(id=settings.SITE_ID+1, 20 + site_2 = Site.objects.create(id=settings.SITE_ID + 1,
21 domain="example2.com", name="example2.com") 21 domain="example2.com", name="example2.com")
22 # A comment for another site 22 # A comment for another site
23 - c5 = Comment.objects.create(  
24 - content_type = ContentType.objects.get_for_model(Article),  
25 - object_pk = "1",  
26 - user_name = "Joe Somebody",  
27 - user_email = "jsomebody@example.com",  
28 - user_url = "http://example.com/~joe/",  
29 - comment = "A comment for the second site.",  
30 - site = site_2, 23 + Comment.objects.create(
  24 + content_type=ContentType.objects.get_for_model(Article),
  25 + object_pk="1",
  26 + user_name="Joe Somebody",
  27 + user_email="jsomebody@example.com",
  28 + user_url="http://example.com/~joe/",
  29 + comment="A comment for the second site.",
  30 + site=site_2,
31 ) 31 )
32 32
33 def test_feed(self): 33 def test_feed(self):
@@ -20,6 +20,7 @@ class CommentModelTests(CommentTestCase): @@ -20,6 +20,7 @@ class CommentModelTests(CommentTestCase):
20 self.assertEqual(c1.user, None) 20 self.assertEqual(c1.user, None)
21 self.assertEqual(c3.user, c4.user) 21 self.assertEqual(c3.user, c4.user)
22 22
  23 +
23 class CommentManagerTests(CommentTestCase): 24 class CommentManagerTests(CommentTestCase):
24 25
25 def testInModeration(self): 26 def testInModeration(self):
@@ -96,12 +96,14 @@ class FlagViewTests(CommentTestCase): @@ -96,12 +96,14 @@ class FlagViewTests(CommentTestCase):
96 96
97 signals.comment_was_flagged.disconnect(receive) 97 signals.comment_was_flagged.disconnect(receive)
98 98
  99 +
99 def makeModerator(username): 100 def makeModerator(username):
100 u = User.objects.get(username=username) 101 u = User.objects.get(username=username)
101 ct = ContentType.objects.get_for_model(Comment) 102 ct = ContentType.objects.get_for_model(Comment)
102 p = Permission.objects.get(content_type=ct, codename="can_moderate") 103 p = Permission.objects.get(content_type=ct, codename="can_moderate")
103 u.user_permissions.add(p) 104 u.user_permissions.add(p)
104 105
  106 +
105 class DeleteViewTests(CommentTestCase): 107 class DeleteViewTests(CommentTestCase):
106 108
107 def testDeletePermissions(self): 109 def testDeletePermissions(self):
@@ -175,6 +177,7 @@ class DeleteViewTests(CommentTestCase): @@ -175,6 +177,7 @@ class DeleteViewTests(CommentTestCase):
175 response = self.client.get("/deleted/", data={"c": pk}) 177 response = self.client.get("/deleted/", data={"c": pk})
176 self.assertTemplateUsed(response, "comments/deleted.html") 178 self.assertTemplateUsed(response, "comments/deleted.html")
177 179
  180 +
178 class ApproveViewTests(CommentTestCase): 181 class ApproveViewTests(CommentTestCase):
179 182
180 def testApprovePermissions(self): 183 def testApprovePermissions(self):
@@ -192,7 +195,8 @@ class ApproveViewTests(CommentTestCase): @@ -192,7 +195,8 @@ class ApproveViewTests(CommentTestCase):
192 def testApprovePost(self): 195 def testApprovePost(self):
193 """POSTing the approve view should mark the comment as removed""" 196 """POSTing the approve view should mark the comment as removed"""
194 c1, c2, c3, c4 = self.createSomeComments() 197 c1, c2, c3, c4 = self.createSomeComments()
195 - c1.is_public = False; c1.save() 198 + c1.is_public = False
  199 + c1.save()
196 200
197 makeModerator("normaluser") 201 makeModerator("normaluser")
198 self.client.login(username="normaluser", password="normaluser") 202 self.client.login(username="normaluser", password="normaluser")
@@ -208,7 +212,8 @@ class ApproveViewTests(CommentTestCase): @@ -208,7 +212,8 @@ class ApproveViewTests(CommentTestCase):
208 url. 212 url.
209 """ 213 """
210 c1, c2, c3, c4 = self.createSomeComments() 214 c1, c2, c3, c4 = self.createSomeComments()
211 - c1.is_public = False; c1.save() 215 + c1.is_public = False
  216 + c1.save()
212 217
213 makeModerator("normaluser") 218 makeModerator("normaluser")
214 self.client.login(username="normaluser", password="normaluser") 219 self.client.login(username="normaluser", password="normaluser")
@@ -223,7 +228,8 @@ class ApproveViewTests(CommentTestCase): @@ -223,7 +228,8 @@ class ApproveViewTests(CommentTestCase):
223 provided url when redirecting. 228 provided url when redirecting.
224 """ 229 """
225 c1, c2, c3, c4 = self.createSomeComments() 230 c1, c2, c3, c4 = self.createSomeComments()
226 - c1.is_public = False; c1.save() 231 + c1.is_public = False
  232 + c1.save()
227 233
228 makeModerator("normaluser") 234 makeModerator("normaluser")
229 self.client.login(username="normaluser", password="normaluser") 235 self.client.login(username="normaluser", password="normaluser")
@@ -249,9 +255,10 @@ class ApproveViewTests(CommentTestCase): @@ -249,9 +255,10 @@ class ApproveViewTests(CommentTestCase):
249 def testApprovedView(self): 255 def testApprovedView(self):
250 comments = self.createSomeComments() 256 comments = self.createSomeComments()
251 pk = comments[0].pk 257 pk = comments[0].pk
252 - response = self.client.get("/approved/", data={"c":pk}) 258 + response = self.client.get("/approved/", data={"c": pk})
253 self.assertTemplateUsed(response, "comments/approved.html") 259 self.assertTemplateUsed(response, "comments/approved.html")
254 260
  261 +
255 class AdminActionsTests(CommentTestCase): 262 class AdminActionsTests(CommentTestCase):
256 urls = "testapp.urls_admin" 263 urls = "testapp.urls_admin"
257 264
@@ -262,21 +269,21 @@ class AdminActionsTests(CommentTestCase): @@ -262,21 +269,21 @@ class AdminActionsTests(CommentTestCase):
262 u = User.objects.get(username="normaluser") 269 u = User.objects.get(username="normaluser")
263 u.is_staff = True 270 u.is_staff = True
264 perms = Permission.objects.filter( 271 perms = Permission.objects.filter(
265 - content_type__app_label = 'django_comments',  
266 - codename__endswith = 'comment' 272 + content_type__app_label='django_comments',
  273 + codename__endswith='comment'
267 ) 274 )
268 for perm in perms: 275 for perm in perms:
269 u.user_permissions.add(perm) 276 u.user_permissions.add(perm)
270 u.save() 277 u.save()
271 278
272 def testActionsNonModerator(self): 279 def testActionsNonModerator(self):
273 - comments = self.createSomeComments() 280 + self.createSomeComments()
274 self.client.login(username="normaluser", password="normaluser") 281 self.client.login(username="normaluser", password="normaluser")
275 response = self.client.get("/admin/django_comments/comment/") 282 response = self.client.get("/admin/django_comments/comment/")
276 self.assertNotContains(response, "approve_comments") 283 self.assertNotContains(response, "approve_comments")
277 284
278 def testActionsModerator(self): 285 def testActionsModerator(self):
279 - comments = self.createSomeComments() 286 + self.createSomeComments()
280 makeModerator("normaluser") 287 makeModerator("normaluser")
281 self.client.login(username="normaluser", password="normaluser") 288 self.client.login(username="normaluser", password="normaluser")
282 response = self.client.get("/admin/django_comments/comment/") 289 response = self.client.get("/admin/django_comments/comment/")
@@ -284,7 +291,7 @@ class AdminActionsTests(CommentTestCase): @@ -284,7 +291,7 @@ class AdminActionsTests(CommentTestCase):
284 291
285 def testActionsDisabledDelete(self): 292 def testActionsDisabledDelete(self):
286 "Tests a CommentAdmin where 'delete_selected' has been disabled." 293 "Tests a CommentAdmin where 'delete_selected' has been disabled."
287 - comments = self.createSomeComments() 294 + self.createSomeComments()
288 self.client.login(username="normaluser", password="normaluser") 295 self.client.login(username="normaluser", password="normaluser")
289 response = self.client.get('/admin2/django_comments/comment/') 296 response = self.client.get('/admin2/django_comments/comment/')
290 self.assertEqual(response.status_code, 200) 297 self.assertEqual(response.status_code, 200)
@@ -308,12 +315,18 @@ class AdminActionsTests(CommentTestCase): @@ -308,12 +315,18 @@ class AdminActionsTests(CommentTestCase):
308 makeModerator("normaluser") 315 makeModerator("normaluser")
309 self.client.login(username="normaluser", password="normaluser") 316 self.client.login(username="normaluser", password="normaluser")
310 with translation.override('en'): 317 with translation.override('en'):
311 - #Test approving  
312 - self.performActionAndCheckMessage('approve_comments', one_comment, '1 comment was successfully approved.')  
313 - self.performActionAndCheckMessage('approve_comments', many_comments, '3 comments were successfully approved.')  
314 - #Test flagging  
315 - self.performActionAndCheckMessage('flag_comments', one_comment, '1 comment was successfully flagged.')  
316 - self.performActionAndCheckMessage('flag_comments', many_comments, '3 comments were successfully flagged.')  
317 - #Test removing  
318 - self.performActionAndCheckMessage('remove_comments', one_comment, '1 comment was successfully removed.')  
319 - self.performActionAndCheckMessage('remove_comments', many_comments, '3 comments were successfully removed.') 318 + # Test approving
  319 + self.performActionAndCheckMessage('approve_comments', one_comment,
  320 + '1 comment was successfully approved.')
  321 + self.performActionAndCheckMessage('approve_comments', many_comments,
  322 + '3 comments were successfully approved.')
  323 + # Test flagging
  324 + self.performActionAndCheckMessage('flag_comments', one_comment,
  325 + '1 comment was successfully flagged.')
  326 + self.performActionAndCheckMessage('flag_comments', many_comments,
  327 + '3 comments were successfully flagged.')
  328 + # Test removing
  329 + self.performActionAndCheckMessage('remove_comments', one_comment,
  330 + '1 comment was successfully removed.')
  331 + self.performActionAndCheckMessage('remove_comments', many_comments,
  332 + '3 comments were successfully removed.')
@@ -12,6 +12,7 @@ from . import CommentTestCase @@ -12,6 +12,7 @@ from . import CommentTestCase
12 12
13 register = Library() 13 register = Library()
14 14
  15 +
15 @register.filter 16 @register.filter
16 def noop(variable, param=None): 17 def noop(variable, param=None):
17 return variable 18 return variable
@@ -87,7 +88,7 @@ class CommentTemplateTagTests(CommentTestCase): @@ -87,7 +88,7 @@ class CommentTemplateTagTests(CommentTestCase):
87 88
88 def verifyGetCommentList(self, tag=None): 89 def verifyGetCommentList(self, tag=None):
89 c1, c2, c3, c4 = Comment.objects.all()[:4] 90 c1, c2, c3, c4 = Comment.objects.all()[:4]
90 - t = "{% load comments %}" + (tag or "{% get_comment_list for testapp.author a.id as cl %}") 91 + t = "{% load comments %}" + (tag or "{% get_comment_list for testapp.author a.id as cl %}")
91 ctx, out = self.render(t, a=Author.objects.get(pk=1)) 92 ctx, out = self.render(t, a=Author.objects.get(pk=1))
92 self.assertEqual(out, "") 93 self.assertEqual(out, "")
93 self.assertEqual(list(ctx["cl"]), [c2]) 94 self.assertEqual(list(ctx["cl"]), [c2])
@@ -8,7 +8,7 @@ from custom_comments import views @@ -8,7 +8,7 @@ from custom_comments import views
8 8
9 9
10 feeds = { 10 feeds = {
11 - 'comments': LatestCommentFeed, 11 + 'comments': LatestCommentFeed,
12 } 12 }
13 13
14 urlpatterns = patterns('', 14 urlpatterns = patterns('',
Please register or login to post a comment