Merge lp:~widelands-dev/widelands-website/cleanup_threadedcomments into lp:widelands-website

Proposed by kaputtnik
Status: Merged
Merged at revision: 504
Proposed branch: lp:~widelands-dev/widelands-website/cleanup_threadedcomments
Merge into: lp:widelands-website
Diff against target: 894 lines (+72/-519)
12 files modified
pip_requirements.txt (+0/-1)
templates/news/inlines/post_detail.html (+1/-1)
templates/news/post_detail.html (+1/-1)
threadedcomments/admin.py (+2/-18)
threadedcomments/forms.py (+1/-21)
threadedcomments/management/commands/migratecomments.py (+0/-56)
threadedcomments/migrations/0002_auto_20181003_1238.py (+33/-0)
threadedcomments/models.py (+0/-157)
threadedcomments/moderation.py (+3/-4)
threadedcomments/templatetags/threadedcommentstags.py (+16/-162)
threadedcomments/urls.py (+0/-22)
threadedcomments/views.py (+15/-76)
To merge this branch: bzr merge lp:~widelands-dev/widelands-website/cleanup_threadedcomments
Reviewer Review Type Date Requested Status
GunChleoc Approve
Review via email: mp+356200@code.launchpad.net

Commit message

Removed model FreeThreadedComments and its dependencies
Remove IP-Adress field from Threadedcomments
Scroll directly to the comments when clicking on 'x comments' in the mainpage

Description of the change

This is a big cleanup for threadedcomments, with regard to bug 1762164

Since we do not allow commenting for not logged in users, i have removed the related model and all it's dependencies. The model does not contain any data, see https://wl.widelands.org/admin/threadedcomments/freethreadedcomment/

Removed the IPAddressField from the other model.

Removed django_comments, because it is not needed.

Clicking on 'x Comments' in the mainpage will directly scroll to the comments section in the related page.

To post a comment you must log in.
508. By kaputtnik

removed more unused functions

Revision history for this message
GunChleoc (gunchleoc) wrote :

LGTM, just 1 tiny nit - we have an extra indent that we could lose

review: Approve
509. By kaputtnik

unindented a row

Revision history for this message
kaputtnik (franku) wrote :

Will merge this at the next weekend

510. By kaputtnik

merged with trunk

Revision history for this message
kaputtnik (franku) wrote :

merged and deployed now.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'pip_requirements.txt'
--- pip_requirements.txt 2018-04-14 15:03:31 +0000
+++ pip_requirements.txt 2018-10-12 19:57:27 +0000
@@ -2,7 +2,6 @@
22
3BeautifulSoup==3.2.03BeautifulSoup==3.2.0
4Django==1.11.124Django==1.11.12
5django-contrib-comments==1.8.0
6django-haystack==2.8.15django-haystack==2.8.1
7# django-messages is very old on pypi6# django-messages is very old on pypi
8# Do not install newer versions because our notifications app is affected7# Do not install newer versions because our notifications app is affected
98
=== modified file 'templates/news/inlines/post_detail.html'
--- templates/news/inlines/post_detail.html 2017-05-20 20:17:28 +0000
+++ templates/news/inlines/post_detail.html 2018-10-12 19:57:27 +0000
@@ -26,6 +26,6 @@
26 26
27 <hr />27 <hr />
28 {% get_comment_count for object as ccount %}28 {% get_comment_count for object as ccount %}
29 <span class="small posLeft"><a href="{{ object.get_absolute_url }}">{{ ccount }} comment{{ ccount|pluralize }}</a></span>29 <span class="small posLeft"><a href="{{ object.get_absolute_url }}#comment_anchor">{{ ccount }} comment{{ ccount|pluralize }}</a></span>
30 <span class="small posRight">Posted by {{object.author|user_link}} on {{ object.publish|custom_date:user }}</span>30 <span class="small posRight">Posted by {{object.author|user_link}} on {{ object.publish|custom_date:user }}</span>
31</div>31</div>
3232
=== modified file 'templates/news/post_detail.html'
--- templates/news/post_detail.html 2016-11-20 11:55:39 +0000
+++ templates/news/post_detail.html 2018-10-12 19:57:27 +0000
@@ -30,7 +30,7 @@
30 {% include "news/inlines/post_detail.html" %}30 {% include "news/inlines/post_detail.html" %}
3131
32 <div class="blogEntry">32 <div class="blogEntry">
33 <h3>Comments on this Post:</h3>33 <h3 id="comment_anchor">Comments on this Post:</h3>
34 {% include "threadedcomments/inlines/comments.html" %}34 {% include "threadedcomments/inlines/comments.html" %}
35 </div>35 </div>
36{% endblock %}36{% endblock %}
3737
=== modified file 'threadedcomments/admin.py'
--- threadedcomments/admin.py 2016-12-13 18:28:51 +0000
+++ threadedcomments/admin.py 2018-10-12 19:57:27 +0000
@@ -1,6 +1,6 @@
1from django.contrib import admin1from django.contrib import admin
2from django.utils.translation import ugettext_lazy as _2from django.utils.translation import ugettext_lazy as _
3from threadedcomments.models import ThreadedComment, FreeThreadedComment3from threadedcomments.models import ThreadedComment
44
55
6class ThreadedCommentAdmin(admin.ModelAdmin):6class ThreadedCommentAdmin(admin.ModelAdmin):
@@ -9,7 +9,7 @@
9 (_('Parent'), {'fields': ('parent',)}),9 (_('Parent'), {'fields': ('parent',)}),
10 (_('Content'), {'fields': ('user', 'comment')}),10 (_('Content'), {'fields': ('user', 'comment')}),
11 (_('Meta'), {'fields': ('is_public', 'date_submitted',11 (_('Meta'), {'fields': ('is_public', 'date_submitted',
12 'date_modified', 'date_approved', 'is_approved', 'ip_address')}),12 'date_modified', 'date_approved', 'is_approved')}),
13 )13 )
14 list_display = ('user', 'date_submitted', 'content_type',14 list_display = ('user', 'date_submitted', 'content_type',
15 'get_content_object', 'parent', '__unicode__')15 'get_content_object', 'parent', '__unicode__')
@@ -18,20 +18,4 @@
18 search_fields = ('comment', 'user__username')18 search_fields = ('comment', 'user__username')
1919
2020
21class FreeThreadedCommentAdmin(admin.ModelAdmin):
22 fieldsets = (
23 (None, {'fields': ('content_type', 'object_id')}),
24 (_('Parent'), {'fields': ('parent',)}),
25 (_('Content'), {'fields': ('name', 'website', 'email', 'comment')}),
26 (_('Meta'), {'fields': ('date_submitted', 'date_modified',
27 'date_approved', 'is_public', 'ip_address', 'is_approved')}),
28 )
29 list_display = ('name', 'date_submitted', 'content_type',
30 'get_content_object', 'parent', '__unicode__')
31 list_filter = ('date_submitted',)
32 date_hierarchy = 'date_submitted'
33 search_fields = ('comment', 'name', 'email', 'website')
34
35
36admin.site.register(ThreadedComment, ThreadedCommentAdmin)21admin.site.register(ThreadedComment, ThreadedCommentAdmin)
37admin.site.register(FreeThreadedComment, FreeThreadedCommentAdmin)
3822
=== modified file 'threadedcomments/forms.py'
--- threadedcomments/forms.py 2016-12-13 18:28:51 +0000
+++ threadedcomments/forms.py 2018-10-12 19:57:27 +0000
@@ -1,6 +1,6 @@
1from django import forms1from django import forms
2from threadedcomments.models import DEFAULT_MAX_COMMENT_LENGTH2from threadedcomments.models import DEFAULT_MAX_COMMENT_LENGTH
3from threadedcomments.models import FreeThreadedComment, ThreadedComment3from threadedcomments.models import ThreadedComment
4from django.utils.translation import ugettext_lazy as _4from django.utils.translation import ugettext_lazy as _
55
66
@@ -21,23 +21,3 @@
21 class Meta:21 class Meta:
22 model = ThreadedComment22 model = ThreadedComment
23 fields = ('comment', 'markup')23 fields = ('comment', 'markup')
24
25
26class FreeThreadedCommentForm(forms.ModelForm):
27 """
28 Form which can be used to validate data for a new FreeThreadedComment.
29 It consists of just a few fields: ``comment``, ``name``, ``website``,
30 ``email``, and ``markup``.
31
32 The fields ``comment``, and ``name`` are the only ones which are required.
33 """
34
35 comment = forms.CharField(
36 label=_('comment'),
37 max_length=DEFAULT_MAX_COMMENT_LENGTH,
38 widget=forms.Textarea
39 )
40
41 class Meta:
42 model = FreeThreadedComment
43 fields = ('comment', 'name', 'website', 'email', 'markup')
4424
=== removed directory 'threadedcomments/management'
=== removed file 'threadedcomments/management/__init__.py'
=== removed directory 'threadedcomments/management/commands'
=== removed file 'threadedcomments/management/commands/__init__.py'
=== removed file 'threadedcomments/management/commands/migratecomments.py'
--- threadedcomments/management/commands/migratecomments.py 2016-12-13 18:28:51 +0000
+++ threadedcomments/management/commands/migratecomments.py 1970-01-01 00:00:00 +0000
@@ -1,56 +0,0 @@
1from django.core.management.base import BaseCommand
2from django.contrib.comments.models import Comment, FreeComment
3from threadedcomments.models import ThreadedComment, FreeThreadedComment
4
5
6class Command(BaseCommand):
7 help = "Migrates Django's built-in django.contrib.comments data to threadedcomments data"
8
9 output_transaction = True
10
11 def handle(self, *args, **options):
12 """Converts all legacy ``Comment`` and ``FreeComment`` objects into
13 ``ThreadedComment`` and ``FreeThreadedComment`` objects,
14 respectively."""
15 self.handle_free_comments()
16 self.handle_comments()
17
18 def handle_free_comments(self):
19 """Converts all legacy ``FreeComment`` objects into
20 ``FreeThreadedComment`` objects."""
21 comments = FreeComment.objects.all()
22 for c in comments:
23 new = FreeThreadedComment(
24 content_type=c.content_type,
25 object_id=c.object_id,
26 comment=c.comment,
27 name=c.person_name,
28 website='',
29 email='',
30 date_submitted=c.submit_date,
31 date_modified=c.submit_date,
32 date_approved=c.submit_date,
33 is_public=c.is_public,
34 ip_address=c.ip_address,
35 is_approved=c.approved
36 )
37 new.save()
38
39 def handle_comments(self):
40 """Converts all legacy ``Comment`` objects into ``ThreadedComment``
41 objects."""
42 comments = Comment.objects.all()
43 for c in comments:
44 new = ThreadedComment(
45 content_type=c.content_type,
46 object_id=c.object_id,
47 comment=c.comment,
48 user=c.user,
49 date_submitted=c.submit_date,
50 date_modified=c.submit_date,
51 date_approved=c.submit_date,
52 is_public=c.is_public,
53 ip_address=c.ip_address,
54 is_approved=not c.is_removed
55 )
56 new.save()
570
=== added file 'threadedcomments/migrations/0002_auto_20181003_1238.py'
--- threadedcomments/migrations/0002_auto_20181003_1238.py 1970-01-01 00:00:00 +0000
+++ threadedcomments/migrations/0002_auto_20181003_1238.py 2018-10-12 19:57:27 +0000
@@ -0,0 +1,33 @@
1# -*- coding: utf-8 -*-
2# Generated by Django 1.11.12 on 2018-10-03 12:38
3from __future__ import unicode_literals
4
5from django.db import migrations
6
7
8class Migration(migrations.Migration):
9
10 dependencies = [
11 ('threadedcomments', '0001_initial'),
12 ]
13
14 operations = [
15 migrations.RemoveField(
16 model_name='freethreadedcomment',
17 name='content_type',
18 ),
19 migrations.RemoveField(
20 model_name='freethreadedcomment',
21 name='parent',
22 ),
23 migrations.DeleteModel(
24 name='TestModel',
25 ),
26 migrations.RemoveField(
27 model_name='threadedcomment',
28 name='ip_address',
29 ),
30 migrations.DeleteModel(
31 name='FreeThreadedComment',
32 ),
33 ]
034
=== modified file 'threadedcomments/models.py'
--- threadedcomments/models.py 2016-12-13 18:28:51 +0000
+++ threadedcomments/models.py 2018-10-12 19:57:27 +0000
@@ -1,6 +1,5 @@
1from django.db import models1from django.db import models
2from django.contrib.contenttypes.models import ContentType2from django.contrib.contenttypes.models import ContentType
3#from django.contrib.contenttypes import generic
4from django.contrib.contenttypes.fields import GenericForeignKey3from django.contrib.contenttypes.fields import GenericForeignKey
5from django.contrib.auth.models import User4from django.contrib.auth.models import User
6from datetime import datetime5from datetime import datetime
@@ -16,13 +15,11 @@
16MARKDOWN = 115MARKDOWN = 1
17TEXTILE = 216TEXTILE = 2
18REST = 317REST = 3
19#HTML = 4
20PLAINTEXT = 518PLAINTEXT = 5
21MARKUP_CHOICES = (19MARKUP_CHOICES = (
22 (MARKDOWN, _('markdown')),20 (MARKDOWN, _('markdown')),
23 (TEXTILE, _('textile')),21 (TEXTILE, _('textile')),
24 (REST, _('restructuredtext')),22 (REST, _('restructuredtext')),
25 # (HTML, _("html")),
26 (PLAINTEXT, _('plaintext')),23 (PLAINTEXT, _('plaintext')),
27)24)
2825
@@ -178,10 +175,6 @@
178 is_public = models.BooleanField(_('is public'), default=True)175 is_public = models.BooleanField(_('is public'), default=True)
179 is_approved = models.BooleanField(_('is approved'), default=False)176 is_approved = models.BooleanField(_('is approved'), default=False)
180177
181 # Extra Field
182 ip_address = models.GenericIPAddressField(
183 _('IP address'), null=True, blank=True)
184
185 objects = ThreadedCommentManager()178 objects = ThreadedCommentManager()
186 public = PublicThreadedCommentManager()179 public = PublicThreadedCommentManager()
187180
@@ -203,158 +196,8 @@
203 and due to ``list_display`` limitations."""196 and due to ``list_display`` limitations."""
204 return self.content_object197 return self.content_object
205198
206 def get_base_data(self, show_dates=True):
207 """Outputs a Python dictionary representing the most useful bits of
208 information about this particular object instance.
209
210 This is mostly useful for testing purposes, as the output from
211 the serializer changes from run to run. However, this may end
212 up being useful for JSON and/or XML data exchange going forward
213 and as the serializer system is changed.
214
215 """
216 markup = 'plaintext'
217 for markup_choice in MARKUP_CHOICES:
218 if self.markup == markup_choice[0]:
219 markup = markup_choice[1]
220 break
221 to_return = {
222 'content_object': self.content_object,
223 'parent': self.parent,
224 'user': self.user,
225 'comment': self.comment,
226 'is_public': self.is_public,
227 'is_approved': self.is_approved,
228 'ip_address': self.ip_address,
229 'markup': force_unicode(markup),
230 }
231 if show_dates:
232 to_return['date_submitted'] = self.date_submitted
233 to_return['date_modified'] = self.date_modified
234 to_return['date_approved'] = self.date_approved
235 return to_return
236
237 class Meta:199 class Meta:
238 ordering = ('-date_submitted',)200 ordering = ('-date_submitted',)
239 verbose_name = _('Threaded Comment')201 verbose_name = _('Threaded Comment')
240 verbose_name_plural = _('Threaded Comments')202 verbose_name_plural = _('Threaded Comments')
241 get_latest_by = 'date_submitted'203 get_latest_by = 'date_submitted'
242
243
244class FreeThreadedComment(models.Model):
245 """
246 A threaded comment which need not be associated with an instance of
247 ``django.contrib.auth.models.User``. Instead, it requires minimally a name,
248 and maximally a name, website, and e-mail address. It is given its hierarchy
249 by a nullable relationship back on itself named ``parent``.
250
251 This ``FreeThreadedComment`` supports several kinds of markup languages,
252 including Textile, Markdown, and ReST.
253
254 It also includes two Managers: ``objects``, which is the same as the normal
255 ``objects`` Manager with a few added utility functions (see above), and
256 ``public``, which has those same utility functions but limits the QuerySet to
257 only those values which are designated as public (``is_public=True``).
258 """
259 # Generic Foreign Key Fields
260 content_type = models.ForeignKey(ContentType)
261 object_id = models.PositiveIntegerField(_('object ID'))
262 content_object = GenericForeignKey()
263
264 # Hierarchy Field
265 parent = models.ForeignKey(
266 'self', null=True, blank=True, default=None, related_name='children')
267
268 # User-Replacement Fields
269 name = models.CharField(_('name'), max_length=128)
270 website = models.URLField(_('site'), blank=True)
271 email = models.EmailField(_('e-mail address'), blank=True)
272
273 # Date Fields
274 date_submitted = models.DateTimeField(
275 _('date/time submitted'), default=datetime.now)
276 date_modified = models.DateTimeField(
277 _('date/time modified'), default=datetime.now)
278 date_approved = models.DateTimeField(
279 _('date/time approved'), default=None, null=True, blank=True)
280
281 # Meat n' Potatoes
282 comment = models.TextField(_('comment'))
283 markup = models.IntegerField(
284 choices=MARKUP_CHOICES, default=DEFAULT_MARKUP, null=True, blank=True)
285
286 # Status Fields
287 is_public = models.BooleanField(_('is public'), default=True)
288 is_approved = models.BooleanField(_('is approved'), default=False)
289
290 # Extra Field
291 ip_address = models.GenericIPAddressField(
292 _('IP address'), null=True, blank=True)
293
294 objects = ThreadedCommentManager()
295 public = PublicThreadedCommentManager()
296
297 def __unicode__(self):
298 if len(self.comment) > 50:
299 return self.comment[:50] + '...'
300 return self.comment[:50]
301
302 def save(self, **kwargs):
303 if not self.markup:
304 self.markup = DEFAULT_MARKUP
305 self.date_modified = datetime.now()
306 if not self.date_approved and self.is_approved:
307 self.date_approved = datetime.now()
308 super(FreeThreadedComment, self).save()
309
310 def get_content_object(self, **kwargs):
311 """Wrapper around the GenericForeignKey due to compatibility reasons
312 and due to ``list_display`` limitations."""
313 return self.content_object
314
315 def get_base_data(self, show_dates=True):
316 """Outputs a Python dictionary representing the most useful bits of
317 information about this particular object instance.
318
319 This is mostly useful for testing purposes, as the output from
320 the serializer changes from run to run. However, this may end
321 up being useful for JSON and/or XML data exchange going forward
322 and as the serializer system is changed.
323
324 """
325 markup = 'plaintext'
326 for markup_choice in MARKUP_CHOICES:
327 if self.markup == markup_choice[0]:
328 markup = markup_choice[1]
329 break
330 to_return = {
331 'content_object': self.content_object,
332 'parent': self.parent,
333 'name': self.name,
334 'website': self.website,
335 'email': self.email,
336 'comment': self.comment,
337 'is_public': self.is_public,
338 'is_approved': self.is_approved,
339 'ip_address': self.ip_address,
340 'markup': force_unicode(markup),
341 }
342 if show_dates:
343 to_return['date_submitted'] = self.date_submitted
344 to_return['date_modified'] = self.date_modified
345 to_return['date_approved'] = self.date_approved
346 return to_return
347
348 class Meta:
349 ordering = ('-date_submitted',)
350 verbose_name = _('Free Threaded Comment')
351 verbose_name_plural = _('Free Threaded Comments')
352 get_latest_by = 'date_submitted'
353
354
355class TestModel(models.Model):
356 """This model is simply used by this application's test suite as a model to
357 which to attach comments."""
358 name = models.CharField(max_length=5)
359 is_public = models.BooleanField(default=True)
360 date = models.DateTimeField(default=datetime.now)
361204
=== modified file 'threadedcomments/moderation.py'
--- threadedcomments/moderation.py 2016-12-13 18:28:51 +0000
+++ threadedcomments/moderation.py 2018-10-12 19:57:27 +0000
@@ -1,5 +1,5 @@
1from django.db.models import signals1from django.db.models import signals
2from threadedcomments.models import ThreadedComment, FreeThreadedComment, MARKUP_CHOICES2from threadedcomments.models import ThreadedComment, MARKUP_CHOICES
3from threadedcomments.models import DEFAULT_MAX_COMMENT_LENGTH, DEFAULT_MAX_COMMENT_DEPTH3from threadedcomments.models import DEFAULT_MAX_COMMENT_LENGTH, DEFAULT_MAX_COMMENT_DEPTH
4from comment_utils import moderation4from comment_utils import moderation
55
@@ -37,9 +37,8 @@
37class Moderator(moderation.Moderator):37class Moderator(moderation.Moderator):
3838
39 def connect(self):39 def connect(self):
40 for model in (ThreadedComment, FreeThreadedComment):40 signals.pre_save.connect(self.pre_save_moderation, sender=ThreadedComment)
41 signals.pre_save.connect(self.pre_save_moderation, sender=model)41 signals.post_save.connect(self.post_save_moderation, sender=ThreadedComment)
42 signals.post_save.connect(self.post_save_moderation, sender=model)
4342
44 # THE FOLLOWING ARE HACKS UNTIL django-comment-utils GETS UPDATED SIGNALS43 # THE FOLLOWING ARE HACKS UNTIL django-comment-utils GETS UPDATED SIGNALS
45 # ####44 # ####
4645
=== modified file 'threadedcomments/templatetags/threadedcommentstags.py'
--- threadedcomments/templatetags/threadedcommentstags.py 2018-04-08 14:40:17 +0000
+++ threadedcomments/templatetags/threadedcommentstags.py 2018-10-12 19:57:27 +0000
@@ -4,8 +4,8 @@
4from django.urls import reverse4from django.urls import reverse
5from django.utils.encoding import force_unicode5from django.utils.encoding import force_unicode
6from django.utils.safestring import mark_safe6from django.utils.safestring import mark_safe
7from threadedcomments.models import ThreadedComment, FreeThreadedComment7from threadedcomments.models import ThreadedComment
8from threadedcomments.forms import ThreadedCommentForm, FreeThreadedCommentForm8from threadedcomments.forms import ThreadedCommentForm
9from mainpage.templatetags.wl_markdown import do_wl_markdown9from mainpage.templatetags.wl_markdown import do_wl_markdown
1010
11# Regular expressions for getting rid of newlines and witespace11# Regular expressions for getting rid of newlines and witespace
@@ -78,64 +78,8 @@
78 return ''78 return ''
7979
8080
81def get_free_comment_url(content_object, parent=None):
82 """Given an object and an optional parent, this tag gets the URL to POST to
83 for the creation of new ``FreeThreadedComment`` objects."""
84 kwargs = get_contenttype_kwargs(content_object)
85 if parent:
86 if not isinstance(parent, FreeThreadedComment):
87 raise template.TemplateSyntaxError, 'get_free_comment_url requires its parent object to be of type FreeThreadedComment'
88 kwargs.update({'parent_id': getattr(
89 parent, 'pk', getattr(parent, 'id'))})
90 return reverse('tc_free_comment_parent', kwargs=kwargs)
91 else:
92 return reverse('tc_free_comment', kwargs=kwargs)
93
94
95def get_free_comment_url_ajax(content_object, parent=None, ajax_type='json'):
96 """Given an object and an optional parent, this tag gets the URL to POST to
97 for the creation of new ``FreeThreadedComment`` objects.
98
99 It returns the latest created object in the AJAX form of the user's
100 choosing (json or xml).
101
102 """
103 kwargs = get_contenttype_kwargs(content_object)
104 kwargs.update({'ajax': ajax_type})
105 if parent:
106 if not isinstance(parent, FreeThreadedComment):
107 raise template.TemplateSyntaxError, 'get_free_comment_url_ajax requires its parent object to be of type FreeThreadedComment'
108 kwargs.update({'parent_id': getattr(
109 parent, 'pk', getattr(parent, 'id'))})
110 return reverse('tc_free_comment_parent_ajax', kwargs=kwargs)
111 else:
112 return reverse('tc_free_comment_ajax', kwargs=kwargs)
113
114
115def get_free_comment_url_json(content_object, parent=None):
116 """
117 Wraps ``get_free_comment_url_ajax`` with ``ajax_type='json'``
118 """
119 try:
120 return get_free_comment_url_ajax(content_object, parent, ajax_type='json')
121 except template.TemplateSyntaxError:
122 raise template.TemplateSyntaxError, 'get_free_comment_url_json requires its parent object to be of type FreeThreadedComment'
123 return ''
124
125
126def get_free_comment_url_xml(content_object, parent=None):
127 """
128 Wraps ``get_free_comment_url_ajax`` with ``ajax_type='xml'``
129 """
130 try:
131 return get_free_comment_url_ajax(content_object, parent, ajax_type='xml')
132 except template.TemplateSyntaxError:
133 raise template.TemplateSyntaxError, 'get_free_comment_url_xml requires its parent object to be of type FreeThreadedComment'
134 return ''
135
136
137def auto_transform_markup(comment):81def auto_transform_markup(comment):
138 """Given a comment (``ThreadedComment`` or ``FreeThreadedComment``), this82 """Given a comment, this
139 tag simply returns the comment after wl_markdown runs over it.83 tag simply returns the comment after wl_markdown runs over it.
14084
141 """85 """
@@ -190,24 +134,6 @@
190 raise template.TemplateSyntaxError(error_string)134 raise template.TemplateSyntaxError(error_string)
191135
192136
193def do_get_free_threaded_comment_tree(parser, token):
194 """Gets a tree (list of objects ordered by traversing tree in preorder, and
195 with an additional ``depth`` integer attribute annotated onto each
196 ``FreeThreadedComment.``"""
197 error_string = '%r tag must be of format {%% get_free_threaded_comment_tree for OBJECT [TREE_ROOT] as CONTEXT_VARIABLE %%}' % token.contents.split()[
198 0]
199 try:
200 split = token.split_contents()
201 except ValueError:
202 raise template.TemplateSyntaxError(error_string)
203 if len(split) == 5:
204 return FreeCommentTreeNode(split[2], split[4], split[3])
205 elif len(split) == 6:
206 return FreeCommentTreeNode(split[2], split[5], split[3])
207 else:
208 raise template.TemplateSyntaxError(error_string)
209
210
211class CommentTreeNode(template.Node):137class CommentTreeNode(template.Node):
212138
213 def __init__(self, content_object, context_name, tree_root):139 def __init__(self, content_object, context_name, tree_root):
@@ -233,31 +159,6 @@
233 return ''159 return ''
234160
235161
236class FreeCommentTreeNode(template.Node):
237
238 def __init__(self, content_object, context_name, tree_root):
239 self.content_object = template.Variable(content_object)
240 self.tree_root = template.Variable(tree_root)
241 self.tree_root_str = tree_root
242 self.context_name = context_name
243
244 def render(self, context):
245 content_object = self.content_object.resolve(context)
246 try:
247 tree_root = self.tree_root.resolve(context)
248 except template.VariableDoesNotExist:
249 if self.tree_root_str == 'as':
250 tree_root = None
251 else:
252 try:
253 tree_root = int(self.tree_root_str)
254 except ValueError:
255 tree_root = self.tree_root_str
256 context[self.context_name] = FreeThreadedComment.public.get_tree(
257 content_object, root=tree_root)
258 return ''
259
260
261def do_get_comment_count(parser, token):162def do_get_comment_count(parser, token):
262 """Gets a count of how many ThreadedComment objects are attached to the163 """Gets a count of how many ThreadedComment objects are attached to the
263 given object."""164 given object."""
@@ -285,33 +186,6 @@
285 return ''186 return ''
286187
287188
288def do_get_free_comment_count(parser, token):
289 """Gets a count of how many FreeThreadedComment objects are attached to the
290 given object."""
291 error_message = '%r tag must be of format {%% %r for OBJECT as CONTEXT_VARIABLE %%}' % (
292 token.contents.split()[0], token.contents.split()[0])
293 try:
294 split = token.split_contents()
295 except ValueError:
296 raise template.TemplateSyntaxError, error_message
297 if split[1] != 'for' or split[3] != 'as':
298 raise template.TemplateSyntaxError, error_message
299 return FreeThreadedCommentCountNode(split[2], split[4])
300
301
302class FreeThreadedCommentCountNode(template.Node):
303
304 def __init__(self, content_object, context_name):
305 self.content_object = template.Variable(content_object)
306 self.context_name = context_name
307
308 def render(self, context):
309 content_object = self.content_object.resolve(context)
310 context[self.context_name] = FreeThreadedComment.public.all_for_object(
311 content_object).count()
312 return ''
313
314
315def oneline(value):189def oneline(value):
316 """Takes some HTML and gets rid of newlines and spaces between tags,190 """Takes some HTML and gets rid of newlines and spaces between tags,
317 rendering the result all on one line."""191 rendering the result all on one line."""
@@ -322,7 +196,7 @@
322196
323197
324def do_get_threaded_comment_form(parser, token):198def do_get_threaded_comment_form(parser, token):
325 """Gets a FreeThreadedCommentForm and inserts it into the context."""199 """Gets a ThreadedCommentForm and inserts it into the context."""
326 error_message = '%r tag must be of format {%% %r as CONTEXT_VARIABLE %%}' % (200 error_message = '%r tag must be of format {%% %r as CONTEXT_VARIABLE %%}' % (
327 token.contents.split()[0], token.contents.split()[0])201 token.contents.split()[0], token.contents.split()[0])
328 try:202 try:
@@ -333,24 +207,18 @@
333 raise template.TemplateSyntaxError, error_message207 raise template.TemplateSyntaxError, error_message
334 if len(split) != 3:208 if len(split) != 3:
335 raise template.TemplateSyntaxError, error_message209 raise template.TemplateSyntaxError, error_message
336 if 'free' in split[0]:210
337 is_free = True211 return ThreadedCommentFormNode(split[2])
338 else:
339 is_free = False
340 return ThreadedCommentFormNode(split[2], free=is_free)
341212
342213
343class ThreadedCommentFormNode(template.Node):214class ThreadedCommentFormNode(template.Node):
344215
345 def __init__(self, context_name, free=False):216 def __init__(self, context_name):
346 self.context_name = context_name217 self.context_name = context_name
347 self.free = free218
348219
349 def render(self, context):220 def render(self, context):
350 if self.free:221 form = ThreadedCommentForm()
351 form = FreeThreadedCommentForm()
352 else:
353 form = ThreadedCommentForm()
354 context[self.context_name] = form222 context[self.context_name] = form
355 return ''223 return ''
356224
@@ -367,26 +235,18 @@
367 raise template.TemplateSyntaxError, error_message235 raise template.TemplateSyntaxError, error_message
368 if split[2] != 'as':236 if split[2] != 'as':
369 raise template.TemplateSyntaxError, error_message237 raise template.TemplateSyntaxError, error_message
370 if 'free' in split[0]:238
371 is_free = True239 return LatestCommentsNode(split[1], split[3])
372 else:
373 is_free = False
374 return LatestCommentsNode(split[1], split[3], free=is_free)
375240
376241
377class LatestCommentsNode(template.Node):242class LatestCommentsNode(template.Node):
378243
379 def __init__(self, num, context_name, free=False):244 def __init__(self, num, context_name):
380 self.num = num245 self.num = num
381 self.context_name = context_name246 self.context_name = context_name
382 self.free = free
383247
384 def render(self, context):248 def render(self, context):
385 if self.free:249 comments = ThreadedComment.objects.order_by(
386 comments = FreeThreadedComment.objects.order_by(
387 '-date_submitted')[:self.num]
388 else:
389 comments = ThreadedComment.objects.order_by(
390 '-date_submitted')[:self.num]250 '-date_submitted')[:self.num]
391 context[self.context_name] = comments251 context[self.context_name] = comments
392 return ''252 return ''
@@ -402,6 +262,7 @@
402 raise template.TemplateSyntaxError, error_message262 raise template.TemplateSyntaxError, error_message
403 if len(split) != 5:263 if len(split) != 5:
404 raise template.TemplateSyntaxError, error_message264 raise template.TemplateSyntaxError, error_message
265
405 return UserCommentsNode(split[2], split[4])266 return UserCommentsNode(split[2], split[4])
406267
407268
@@ -427,6 +288,7 @@
427 raise template.TemplateSyntaxError, error_message288 raise template.TemplateSyntaxError, error_message
428 if len(split) != 5:289 if len(split) != 5:
429 raise template.TemplateSyntaxError, error_message290 raise template.TemplateSyntaxError, error_message
291
430 return UserCommentCountNode(split[2], split[4])292 return UserCommentCountNode(split[2], split[4])
431293
432294
@@ -445,21 +307,13 @@
445register.simple_tag(get_comment_url)307register.simple_tag(get_comment_url)
446register.simple_tag(get_comment_url_json)308register.simple_tag(get_comment_url_json)
447register.simple_tag(get_comment_url_xml)309register.simple_tag(get_comment_url_xml)
448register.simple_tag(get_free_comment_url)
449register.simple_tag(get_free_comment_url_json)
450register.simple_tag(get_free_comment_url_xml)
451310
452register.filter('oneline', oneline)311register.filter('oneline', oneline)
453312
454register.tag('auto_transform_markup', do_auto_transform_markup)313register.tag('auto_transform_markup', do_auto_transform_markup)
314register.tag('get_comment_count', do_get_comment_count)
455register.tag('get_threaded_comment_tree', do_get_threaded_comment_tree)315register.tag('get_threaded_comment_tree', do_get_threaded_comment_tree)
456register.tag('get_free_threaded_comment_tree',
457 do_get_free_threaded_comment_tree)
458register.tag('get_comment_count', do_get_comment_count)
459register.tag('get_free_comment_count', do_get_free_comment_count)
460register.tag('get_free_threaded_comment_form', do_get_threaded_comment_form)
461register.tag('get_threaded_comment_form', do_get_threaded_comment_form)316register.tag('get_threaded_comment_form', do_get_threaded_comment_form)
462register.tag('get_latest_comments', do_get_latest_comments)317register.tag('get_latest_comments', do_get_latest_comments)
463register.tag('get_latest_free_comments', do_get_latest_comments)
464register.tag('get_user_comments', do_get_user_comments)318register.tag('get_user_comments', do_get_user_comments)
465register.tag('get_user_comment_count', do_get_user_comment_count)319register.tag('get_user_comment_count', do_get_user_comment_count)
466320
=== modified file 'threadedcomments/urls.py'
--- threadedcomments/urls.py 2016-12-13 18:28:51 +0000
+++ threadedcomments/urls.py 2018-10-12 19:57:27 +0000
@@ -1,8 +1,6 @@
1from django.conf.urls import url1from django.conf.urls import url
2from threadedcomments.models import FreeThreadedComment
3from threadedcomments import views2from threadedcomments import views
43
5free = {'model': FreeThreadedComment}
64
7urlpatterns = [5urlpatterns = [
8 ### Comments ###6 ### Comments ###
@@ -10,8 +8,6 @@
10 views.comment, name='tc_comment'),8 views.comment, name='tc_comment'),
11 url(r'^comment/(?P<content_type>\d+)/(?P<object_id>\d+)/(?P<parent_id>\d+)/$',9 url(r'^comment/(?P<content_type>\d+)/(?P<object_id>\d+)/(?P<parent_id>\d+)/$',
12 views.comment, name='tc_comment_parent'),10 views.comment, name='tc_comment_parent'),
13 url(r'^comment/(?P<object_id>\d+)/delete/$',
14 views.comment_delete, name='tc_comment_delete'),
15 url(r'^comment/(?P<edit_id>\d+)/edit/$',11 url(r'^comment/(?P<edit_id>\d+)/edit/$',
16 views.comment, name='tc_comment_edit'),12 views.comment, name='tc_comment_edit'),
1713
@@ -22,22 +18,4 @@
22 views.comment, name='tc_comment_parent_ajax'),18 views.comment, name='tc_comment_parent_ajax'),
23 url(r'^comment/(?P<edit_id>\d+)/edit/(?P<ajax>json|xml)/$',19 url(r'^comment/(?P<edit_id>\d+)/edit/(?P<ajax>json|xml)/$',
24 views.comment, name='tc_comment_edit_ajax'),20 views.comment, name='tc_comment_edit_ajax'),
25
26 ### Free Comments ###
27 url(r'^freecomment/(?P<content_type>\d+)/(?P<object_id>\d+)/$',
28 views.free_comment, name='tc_free_comment'),
29 url(r'^freecomment/(?P<content_type>\d+)/(?P<object_id>\d+)/(?P<parent_id>\d+)/$',
30 views.free_comment, name='tc_free_comment_parent'),
31 url(r'^freecomment/(?P<object_id>\d+)/delete/$',
32 views.comment_delete, free, name='tc_free_comment_delete'),
33 url(r'^freecomment/(?P<edit_id>\d+)/edit/$',
34 views.free_comment, name='tc_free_comment_edit'),
35
36 ### Free Comments (AJAX) ###
37 url(r'^freecomment/(?P<content_type>\d+)/(?P<object_id>\d+)/(?P<ajax>json|xml)/$',
38 views.free_comment, name='tc_free_comment_ajax'),
39 url(r'^freecomment/(?P<content_type>\d+)/(?P<object_id>\d+)/(?P<parent_id>\d+)/(?P<ajax>json|xml)/$',
40 views.free_comment, name='tc_free_comment_parent_ajax'),
41 url(r'^freecomment/(?P<edit_id>\d+)/edit/(?P<ajax>json|xml)/$',
42 views.free_comment, name='tc_free_comment_edit_ajax'),
43]21]
4422
=== modified file 'threadedcomments/views.py'
--- threadedcomments/views.py 2018-04-05 07:30:42 +0000
+++ threadedcomments/views.py 2018-10-12 19:57:27 +0000
@@ -5,8 +5,8 @@
5from django.template import RequestContext, Context, Template5from django.template import RequestContext, Context, Template
6from django.utils.http import urlquote6from django.utils.http import urlquote
7from django.conf import settings7from django.conf import settings
8from threadedcomments.forms import FreeThreadedCommentForm, ThreadedCommentForm8from threadedcomments.forms import ThreadedCommentForm
9from threadedcomments.models import ThreadedComment, FreeThreadedComment, DEFAULT_MAX_COMMENT_LENGTH9from threadedcomments.models import ThreadedComment, DEFAULT_MAX_COMMENT_LENGTH
10from threadedcomments.utils import JSONResponse, XMLResponse10from threadedcomments.utils import JSONResponse, XMLResponse
11from wl_utils import get_real_ip11from wl_utils import get_real_ip
1212
@@ -59,10 +59,10 @@
59 )59 )
6060
6161
62def free_comment(request, content_type=None, object_id=None, edit_id=None, parent_id=None, add_messages=False, ajax=False, model=FreeThreadedComment, form_class=FreeThreadedCommentForm, context_processors=[], extra_context={}):62@login_required
63 """Receives POST data and either creates a new ``ThreadedComment`` or63def comment(request, content_type=None, object_id=None, edit_id=None, parent_id=None, add_messages=False, ajax=False, context_processors=[], extra_context={}):
64 ``FreeThreadedComment``, or edits an old one based upon the specified64 """Receives POST data and creates a new ``ThreadedComment``, or
65 parameters.65 edits an old one based upon the specified parameters.
6666
67 If there is a 'preview' key in the POST request, a preview will be forced and the67 If there is a 'preview' key in the POST request, a preview will be forced and the
68 comment will not be saved until a 'preview' key is no longer in the POST request.68 comment will not be saved until a 'preview' key is no longer in the POST request.
@@ -74,6 +74,8 @@
74 where the comment may be edited until it does not contain errors.74 where the comment may be edited until it does not contain errors.
7575
76 """76 """
77 form_class = ThreadedCommentForm
78 model = ThreadedComment
77 if not edit_id and not (content_type and object_id):79 if not edit_id and not (content_type and object_id):
78 raise Http404 # Must specify either content_type and object_id or edit_id80 raise Http404 # Must specify either content_type and object_id or edit_id
79 if 'preview' in request.POST:81 if 'preview' in request.POST:
@@ -87,25 +89,19 @@
87 if form.is_valid():89 if form.is_valid():
88 new_comment = form.save(commit=False)90 new_comment = form.save(commit=False)
89 if not edit_id:91 if not edit_id:
90 new_comment.ip_address = get_real_ip(request)
91 new_comment.content_type = get_object_or_404(92 new_comment.content_type = get_object_or_404(
92 ContentType, id=int(content_type))93 ContentType, id=int(content_type))
93 new_comment.object_id = int(object_id)94 new_comment.object_id = int(object_id)
94 if model == ThreadedComment:95
95 new_comment.user = request.user96 new_comment.user = request.user
97
96 if parent_id:98 if parent_id:
97 new_comment.parent = get_object_or_404(model, id=int(parent_id))99 new_comment.parent = get_object_or_404(model, id=int(parent_id))
98 new_comment.save()100 new_comment.save()
99 if model == ThreadedComment:101 if add_messages:
100 if add_messages:102 request.user.message_set.create(
101 request.user.message_set.create(103 message='Your message has been posted successfully.')
102 message='Your message has been posted successfully.')104
103 else:
104 request.session['successful_data'] = {
105 'name': form.cleaned_data['name'],
106 'website': form.cleaned_data['website'],
107 'email': form.cleaned_data['email'],
108 }
109 if ajax == 'json':105 if ajax == 'json':
110 return JSONResponse([new_comment, ])106 return JSONResponse([new_comment, ])
111 elif ajax == 'xml':107 elif ajax == 'xml':
@@ -129,60 +125,3 @@
129 return XMLResponse(response_str, is_iterable=False)125 return XMLResponse(response_str, is_iterable=False)
130 else:126 else:
131 return _preview(request, context_processors, extra_context, form_class=form_class)127 return _preview(request, context_processors, extra_context, form_class=form_class)
132
133
134def comment(*args, **kwargs):
135 """Thin wrapper around free_comment which adds login_required status and
136 also assigns the ``model`` to be ``ThreadedComment``."""
137 kwargs['model'] = ThreadedComment
138 kwargs['form_class'] = ThreadedCommentForm
139 return free_comment(*args, **kwargs)
140# Require login to be required, as request.user must exist and be valid.
141comment = login_required(comment)
142
143
144def can_delete_comment(comment, user):
145 """Default callback function to determine wether the given user has the
146 ability to delete the given comment."""
147 if user.is_staff or user.is_superuser:
148 return True
149 if hasattr(comment, 'user') and comment.user == user:
150 return True
151 return False
152
153# Todo: Next one is not used so far and may need adjustments to the render()
154def comment_delete(request, object_id, model=ThreadedComment, extra_context={}, context_processors=[], permission_callback=can_delete_comment):
155 """Deletes the specified comment, which can be either a
156 ``FreeThreadedComment`` or a ``ThreadedComment``.
157
158 If it is a POST request, then the comment will be deleted outright,
159 however, if it is a GET request, a confirmation page will be shown.
160
161 """
162 tc = get_object_or_404(model, id=int(object_id))
163 if not permission_callback(tc, request.user):
164 login_url = settings.LOGIN_URL
165 current_url = urlquote(request.get_full_path())
166 return HttpResponseRedirect('%s?next=%s' % (login_url, current_url))
167 if request.method == 'POST':
168 tc.delete()
169 return HttpResponseRedirect(_get_next(request))
170 else:
171 if model == ThreadedComment:
172 is_free_threaded_comment = False
173 is_threaded_comment = True
174 else:
175 is_free_threaded_comment = True
176 is_threaded_comment = False
177
178 extra_context.update(
179 {'comment': tc,
180 'is_free_threaded_comment': is_free_threaded_comment,
181 'is_threaded_comment': is_threaded_comment,
182 'next': _get_next(request),
183 }
184 )
185 return render(request,
186 'threadedcomments/confirm_delete.html',
187 extra_context,
188 )

Subscribers

People subscribed via source and target branches