/comment_utils/templatetags/moderated_comments.py
Python | 192 lines | 182 code | 5 blank | 5 comment | 5 complexity | 5324adb5bd0dceab201ed76ede442a8b MD5 | raw file
1""" 2Template tags designed to work with applications which use comment 3moderation. 4 5""" 6 7 8from django import template 9from django.core.exceptions import ObjectDoesNotExist 10from django.db.models import get_model 11from django.contrib.comments.models import Comment, FreeComment 12from django.contrib.comments.templatetags import comments 13from django.contrib.contenttypes.models import ContentType 14 15from comment_utils.moderation import moderator 16 17 18class PublicCommentCountNode(comments.CommentCountNode): 19 def render(self, context): 20 from django.conf import settings 21 manager = self.free and FreeComment.objects or Comment.objects 22 if self.context_var_name is not None: 23 object_id = self.context_var_name.resolve(context) 24 comment_count = manager.filter(object_id__exact=object_id, 25 content_type__app_label__exact=self.package, 26 content_type__model__exact=self.module, 27 site__id__exact=settings.SITE_ID, 28 is_public__exact=True).count() 29 context[self.var_name] = comment_count 30 return '' 31 32 33class DoPublicCommentList(comments.DoGetCommentList): 34 """ 35 Retrieves comments for a particular object and stores them in a 36 context variable. 37 38 The difference between this tag and Django's built-in comment list 39 tags is that this tag will only return comments with 40 ``is_public=True``. If your application uses any sort of comment 41 moderation which sets ``is_public=False``, you'll probably want to 42 use this tag, as it makes the template logic simpler by only 43 returning approved comments. 44 45 Syntax:: 46 47 {% get_public_comment_list for [app_name].[model_name] [object_id] as [varname] %} 48 49 or:: 50 51 {% get_public_free_comment_list for [app_name].[model_name] [object_id] as [varname] %} 52 53 When called as ``get_public_comment_list``, this tag retrieves 54 instances of ``Comment`` (comments which require 55 registration). When called as ``get_public_free_comment_list``, 56 this tag retrieves instances of ``FreeComment`` (comments which do 57 not require registration). 58 59 To retrieve comments in reverse order (e.g., newest comments 60 first), pass 'reversed' as an extra argument after ``varname``. 61 62 So, for example, to retrieve registered comments for a flatpage 63 with ``id`` 12, use like this:: 64 65 {% get_public_comment_list for flatpages.flatpage 12 as comment_list %} 66 67 To retrieve unregistered comments for the same object:: 68 69 {% get_public_free_comment_list for flatpages.flatpage 12 as comment_list %} 70 71 To retrieve in reverse order (newest comments first):: 72 73 {% get_public_free_comment_list for flatpages.flatpage 12 as comment_list reversed %} 74 75 """ 76 def __call__(self, parser, token): 77 bits = token.contents.split() 78 if len(bits) not in (6, 7): 79 raise template.TemplateSyntaxError("'%s' tag takes 5 or 6 arguments" % bits[0]) 80 if bits[1] != 'for': 81 raise template.TemplateSyntaxError("first argument to '%s' tag must be 'for'" % bits[0]) 82 try: 83 app_name, model_name = bits[2].split('.') 84 except ValueError: 85 raise template.TemplateSyntaxError("second argument to '%s' tag must be in the form 'app_name.model_name'" % bits[0]) 86 model = get_model(app_name, model_name) 87 if model is None: 88 raise template.TemplateSyntaxError("'%s' tag got invalid model '%s.%s'" % (bits[0], app_name, model_name)) 89 content_type = ContentType.objects.get_for_model(model) 90 var_name, object_id = None, None 91 if bits[3].isdigit(): 92 object_id = bits[3] 93 try: 94 content_type.get_object_for_this_type(pk=object_id) 95 except ObjectDoesNotExist: 96 raise template.TemplateSyntaxError("'%s' tag got reference to %s object with id %s, which doesn't exist" % (bits[0], content_type.name, object_id)) 97 else: 98 var_name = bits[3] 99 if bits[4] != 'as': 100 raise template.TemplateSyntaxError("fourth argument to '%s' tag must be 'as'" % bits[0]) 101 if len(bits) == 7: 102 if bits[6] != 'reversed': 103 raise template.TemplateSyntaxError("sixth argument to '%s' tag, if given, must be 'reversed'" % bits[0]) 104 ordering = '-' 105 else: 106 ordering = '' 107 return comments.CommentListNode(app_name, model_name, var_name, object_id, bits[5], self.free, ordering, extra_kwargs={ 'is_public__exact': True }) 108 109 110class DoPublicCommentCount(comments.DoCommentCount): 111 """ 112 Retrieves the number of comments attached to a particular object 113 and stores them in a context variable. 114 115 The difference between this tag and Django's built-in comment 116 count tags is that this tag will only count comments with 117 ``is_public=True``. If your application uses any sort of comment 118 moderation which sets ``is_public=False``, you'll probably want to 119 use this tag, as it gives an accurate count of the comments which 120 will be publicly displayed. 121 122 Syntax:: 123 124 {% get_public_comment_count for [app_name].[model_name] [object_id] as [varname] %} 125 126 or:: 127 128 {% get_public_free_comment_count for [app_name].[model_name] [object_id] as [varname] %} 129 130 Example:: 131 132 {% get_public_comment_count for weblog.entry entry.id as comment_count %} 133 134 When called as ``get_public_comment_list``, this tag counts 135 instances of ``Comment`` (comments which require 136 registration). When called as ``get_public_free_comment_count``, 137 this tag counts instances of ``FreeComment`` (comments which do 138 not require registration). 139 140 """ 141 def __call__(self, parser, token): 142 bits = token.contents.split() 143 if len(bits) != 6: 144 raise template.TemplateSyntaxError("'%s' tag takes five arguments" % bits[0]) 145 if bits[1] != 'for': 146 raise template.TemplateSyntaxError("first argument to '%s' tag must be 'for'" % bits[0]) 147 try: 148 app_name, model_name = bits[2].split('.') 149 except ValueError: 150 raise template.TemplateSyntaxError("second argument to '%s tag must be in the format app_name.model_name'" % bits[0]) 151 model = get_model(app_name, model_name) 152 if model is None: 153 raise template.TemplateSyntaxError("'%s' tag got invalid model '%s.%s'" % (bits[0], app_name, model_name)) 154 content_type = ContentType.objects.get_for_model(model) 155 var_name, object_id = None, None 156 if bits[3].isdigit(): 157 object_id = bits[3] 158 try: 159 content_type.get_object_for_this_type(pk=object_id) 160 except ObjectDoesNotExist: 161 raise template.TemplateSyntaxError("'%s' tag got reference to %s object with id %s, which doesn't exist" % (bits[0], content_type.name, object_id)) 162 else: 163 var_name = bits[3] 164 if bits[4] != 'as': 165 raise template.TemplateSyntaxError("fourth argument to '%s' tag must be 'as'" % bits[0]) 166 167 return PublicCommentCountNode(app_name, model_name, var_name, object_id, bits[5], self.free) 168 169def comments_open(value): 170 """ 171 Return ``True`` if new comments are allowed for an object, 172 ``False`` otherwise. 173 174 """ 175 return moderator.comments_open(value) 176 177def comments_moderated(value): 178 """ 179 Return ``True`` if new comments for an object are being 180 automatically sent into moderation, ``False`` otherwise. 181 182 """ 183 return moderator.comments_moderated(value) 184 185 186register = template.Library() 187register.tag('get_public_comment_list', DoPublicCommentList(False)) 188register.tag('get_public_free_comment_list', DoPublicCommentList(True)) 189register.tag('get_public_comment_count', DoPublicCommentCount(False)) 190register.tag('get_public_free_comment_count', DoPublicCommentCount(True)) 191register.filter(comments_open) 192register.filter(comments_moderated)