Serotonin Storm

source>mptt_comments>views.py
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
import textwrap
from django import http
from django.conf import settings
from django.contrib.comments.views.utils import next_redirect
from django.core.exceptions import ObjectDoesNotExist
from django.db import models
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.template.loader import render_to_string
from django.utils.html import escape
import mptt_comments
from django.contrib.comments import signals
from mptt_comments.models import MpttComment
from django.utils import datastructures, simplejson


class CommentPostBadRequest(http.HttpResponseBadRequest):
    """
    Response returned when a comment post is invalid. If ``DEBUG`` is on a
    nice-ish error message will be displayed (for debugging purposes), but in
    production mode a simple opaque 400 page will be displayed.
    """
    def __init__(self, why):
        super(CommentPostBadRequest, self).__init__()
        if settings.DEBUG:
            self.content = render_to_string("comments/400-debug.html", {"why": why})

def new_comment(request, comment_id=None):
    
    is_ajax = request.GET.get('is_ajax') and '_ajax' or ''
    
    if not comment_id:
        return CommentPostBadRequest("Missing comment id.")
        
    parent_comment = MpttComment.objects.get(pk=comment_id)
    
    target = parent_comment.content_object
    model = target.__class__
    
    # Construct the initial comment form
    form = mptt_comments.get_form()(target, parent_comment=parent_comment)
        
    template_list = [
        "comments/%s_%s_new_form%s.html" % tuple(str(model._meta).split(".") + [is_ajax]),
        "comments/%s_new_form%s.html" % (model._meta.app_label, is_ajax),
        "comments/new_form%s.html" % is_ajax,
    ]
    return render_to_response(
        template_list, {
            "form" : form,
        }, 
        RequestContext(request, {})
    )
        
def post_comment(request, next=None):
    """
    Post a comment.

    HTTP POST is required unless a initial form is requested. If ``POST['submit'] == "preview"`` or if there are
    errors a preview template, ``comments/preview.html``, will be rendered.
    """

    # Require POST
    if request.method != 'POST' and not get_initial_form:
        return http.HttpResponseNotAllowed(["POST"])
        
    is_ajax = request.POST.get('is_ajax') and '_ajax' or ''

    # Fill out some initial data fields from an authenticated user, if present
    data = request.POST.copy()

    if request.user.is_authenticated():
        if not data.get('name', ''):
            data["name"] = request.user.get_full_name()
        if not data.get('email', ''):
            data["email"] = request.user.email

    # Look up the object we're trying to comment about
    ctype = data.get("content_type")
    object_pk = data.get("object_pk")
    parent_pk = data.get("parent_pk")
    parent_comment = None
    if ctype is None or object_pk is None:
        return CommentPostBadRequest("Missing content_type or object_pk field.")
    try:
        model = models.get_model(*ctype.split(".", 1))
        target = model._default_manager.get(pk=object_pk)
        if parent_pk:
            parent_comment = MpttComment.objects.get(pk=parent_pk)
    except TypeError:
        return CommentPostBadRequest(
            "Invalid content_type value: %r" % escape(ctype))
    except AttributeError:
        return CommentPostBadRequest(
            "The given content-type %r does not resolve to a valid model." % \
                escape(ctype))
    except MpttComment.DoesNotExist:
        return CommentPostBadRequest(
            "Parent comment with PK %r does not exist." % \
                escape(parent_pk))
    except ObjectDoesNotExist:
        return CommentPostBadRequest(
            "No object matching content-type %r and object PK %r exists." % \
                (escape(ctype), escape(object_pk)))

    # Do we want to preview the comment?
    preview = data.get("submit", "").lower() == "preview" or \
              data.get("preview", None) is not None
        
    # Construct the comment form 
    form = mptt_comments.get_form()(target, parent_comment=parent_comment, data=data)
            
    # Check security information
    if form.security_errors():
        return CommentPostBadRequest(
            "The comment form failed security verification: %s" % \
                escape(str(form.security_errors())))

    # If there are errors or if we requested a preview show the comment
    if form.errors or preview:
        template_list = [
            "comments/%s_%s_preview%s.html" % tuple(str(model._meta).split(".") + [is_ajax]),
            "comments/%s_preview%s.html" % (model._meta.app_label, is_ajax),
            "comments/preview%s.html" % is_ajax
        ]
        return render_to_response(
            template_list, {
                "comment" : form.data.get("comment", ""),
                "form" : form,
                "allow_post": not form.errors
            }, 
            RequestContext(request, {})
        )

    # Otherwise create the comment
    comment = form.get_comment_object()
    comment.ip_address = request.META.get("REMOTE_ADDR", None)
    if request.user.is_authenticated():
        comment.user = request.user

    # Signal that the comment is about to be saved
    responses = signals.comment_will_be_posted.send(
        sender  = comment.__class__,
        comment = comment,
        request = request
    )

    for (receiver, response) in responses:
        if response == False:
            return CommentPostBadRequest(
                "comment_will_be_posted receiver %r killed the comment" % receiver.__name__)

    # Save the comment and signal that it was saved
    comment.save()
    signals.comment_was_posted.send(
        sender  = comment.__class__,
        comment = comment,
        request = request
    )
    
    return next_redirect(data, next, 'comments-comment-done%s' % (is_ajax and '-ajax' or ''), c=comment._get_pk_val())
    
def confirmation_view(template, doc="Display a confirmation view."):
    """
    Confirmation view generator for the "comment was
    posted/flagged/deleted/approved" views.
    """
    def confirmed(request):
        comment = None
        if 'c' in request.GET:
            try:
                comment = mptt_comments.get_model().objects.get(pk=request.GET['c'])
            except ObjectDoesNotExist:
                pass
        return render_to_response(template,
            {'comment': comment},
            context_instance=RequestContext(request)
        )

    confirmed.__doc__ = textwrap.dedent("""\
        %s

        Templates: `%s``
        Context:
            comment
                The posted comment
        """ % (doc, template)
    )
    return confirmed
    
comment_done_ajax = confirmation_view(
    template = "comments/posted_ajax.html",
    doc = """Display a "comment was posted" success page."""
)

comment_done = confirmation_view(
    template = "comments/posted.html",
    doc = """Display a "comment was posted" success page."""
)


    
def comment_tree_json(request, object_list, tree_id, cutoff_level, bottom_level):
    
    if object_list:
        json_comments = {'end_level': object_list[-1].level, 'end_pk': object_list[-1].pk}
          
        template_list = [
            "comments/display_comments_tree.html",
        ]
        json_comments['html'] = render_to_string(
            template_list, {
                "comments" : object_list,
                "cutoff_level": cutoff_level,
                "bottom_level": bottom_level
            }, 
            RequestContext(request, {})
        )
        
        return json_comments
    return {}

def comments_more(request, from_comment_pk):
    
    offset = getattr(settings, 'MPTT_COMMENTS_OFFSET', 25)

    comment = MpttComment.objects.select_related('content_type').get(pk=from_comment_pk)

    cutoff_level = 3
    bottom_level = 0
             
    qs = MpttComment.objects.filter(
        tree_id=comment.tree_id,
        lft__gte=comment.lft+1,
        level__gte=1,
        level__lte=cutoff_level
    ).order_by('tree_id', 'lft').select_related('user')
    
    until_toplevel = []
    remaining = []
    toplevel_reached = False
    remaining_count = qs.count() - offset
    
    for comment in qs[:offset]:
        
        if comment.level == 1:
            toplevel_reached = True
            
        if toplevel_reached:
            remaining.append(comment)
        else:
            until_toplevel.append(comment)
    
    json_data = {'remaining_count': remaining_count, 'comments_for_update': [], 'comments_tree': {} }
    
    for comment in until_toplevel:    
        json_comment = {'level': comment.level, 'pk': comment.pk}
        template_list = [
            "comments/display_comment.html",
        ]
        json_comment['html'] = render_to_string(
            template_list, {
                "comment" : comment,
                "cutoff_level": cutoff_level,
                "collapse_levels_above": 2
            }, 
            RequestContext(request, {})
        )
        json_data['comments_for_update'].append(json_comment)
        
    json_data['comments_tree'] = comment_tree_json(request, remaining, comment.tree_id, cutoff_level, bottom_level)
    
    return http.HttpResponse(simplejson.dumps(json_data), mimetype='application/json')
    
def comments_subtree(request, from_comment_pk, include_self=None, include_ancestors=None):
    
    comment = MpttComment.objects.select_related('content_type').get(pk=from_comment_pk)     
    
    cutoff_level = comment.level + getattr(settings, 'MPTT_COMMENTS_CUTOFF', 3)
    bottom_level = not include_ancestors and (comment.level - (include_self and 1 or 0)) or 0
   
    related = getattr(settings, 'MPTT_COMMENTS_SELECT_RELATED', None)

    qs = MpttComment.objects.filter(
        tree_id=comment.tree_id, 
        lft__gte=comment.lft + (not include_self and 1 or 0),
        lft__lte=comment.rght,
        level__lte=cutoff_level - (include_self and 1 or 0)
    ).order_by('tree_id', 'lft')

    if related:
	qs = qs.select_related(*related)
	    
    is_ajax = request.GET.get('is_ajax') and '_ajax' or ''
    
    if is_ajax:    
        
        json_data = {'comments_for_update': [], 'comments_tree': {} }
        json_data['comments_tree'] = comment_tree_json(request, list(qs), comment.tree_id, cutoff_level, bottom_level)
        
        return http.HttpResponse(simplejson.dumps(json_data), mimetype='application/json')
        
    else:
        
        target = comment.content_object
        model = target.__class__

        template_list = [
            "comments/%s_%s_subtree.html" % tuple(str(model._meta).split(".")),
            "comments/%s_subtree.html" % model._meta.app_label,
            "comments/subtree.html"
        ]
        
        comments = list(qs)
        if include_ancestors:
            comments = list(comment.get_ancestors())[1:] + comments
        
        return render_to_response(
            template_list, {
                "comments" : comments,
                "bottom_level": bottom_level,
                "cutoff_level": cutoff_level - 1,
                "collapse_levels_above": cutoff_level - (include_self and 2 or 1),
                "collapse_levels_below": comment.level

            }, 
            RequestContext(request, {})
        )