~widelands-dev/widelands-website/trunk

« back to all changes in this revision

Viewing changes to threadedcomments/views.py

  • Committer: franku
  • Date: 2016-05-15 14:41:54 UTC
  • mto: This revision was merged to the branch mainline in revision 409.
  • Revision ID: somal@arcor.de-20160515144154-00m3tiibyxm0nw2w
added the old threadedcomments app as wildelands app

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
from django.http import HttpResponseRedirect, Http404
 
2
from django.contrib.auth.decorators import login_required
 
3
from django.contrib.contenttypes.models import ContentType
 
4
from django.shortcuts import get_object_or_404, render_to_response
 
5
from django.template import RequestContext, Context, Template
 
6
from django.utils.http import urlquote
 
7
from django.conf import settings
 
8
from threadedcomments.forms import FreeThreadedCommentForm, ThreadedCommentForm
 
9
from threadedcomments.models import ThreadedComment, FreeThreadedComment, DEFAULT_MAX_COMMENT_LENGTH
 
10
from threadedcomments.utils import JSONResponse, XMLResponse
 
11
 
 
12
def _adjust_max_comment_length(form, field_name='comment'):
 
13
    """
 
14
    Sets the maximum comment length to that default specified in the settings.
 
15
    """
 
16
    form.base_fields['comment'].max_length = DEFAULT_MAX_COMMENT_LENGTH
 
17
 
 
18
def _get_next(request):
 
19
    """
 
20
    The part that's the least straightforward about views in this module is how they 
 
21
    determine their redirects after they have finished computation.
 
22
 
 
23
    In short, they will try and determine the next place to go in the following order:
 
24
 
 
25
    1. If there is a variable named ``next`` in the *POST* parameters, the view will
 
26
    redirect to that variable's value.
 
27
    2. If there is a variable named ``next`` in the *GET* parameters, the view will
 
28
    redirect to that variable's value.
 
29
    3. If Django can determine the previous page from the HTTP headers, the view will
 
30
    redirect to that previous page.
 
31
    4. Otherwise, the view raise a 404 Not Found.
 
32
    """
 
33
    next = request.POST.get('next', request.GET.get('next', request.META.get('HTTP_REFERER', None)))
 
34
    if not next or next == request.path:
 
35
        raise Http404 # No next url was supplied in GET or POST.
 
36
    return next
 
37
 
 
38
def _preview(request, context_processors, extra_context, form_class=ThreadedCommentForm):
 
39
    """
 
40
    Returns a preview of the comment so that the user may decide if he or she wants to
 
41
    edit it before submitting it permanently.
 
42
    """
 
43
    _adjust_max_comment_length(form_class)
 
44
    form = form_class(request.POST or None)
 
45
    context = {
 
46
        'next' : _get_next(request),
 
47
        'form' : form,
 
48
    }
 
49
    if form.is_valid():
 
50
        new_comment = form.save(commit=False)
 
51
        context['comment'] = new_comment
 
52
    else:
 
53
        context['comment'] = None
 
54
    return render_to_response(
 
55
        'threadedcomments/preview_comment.html',
 
56
        extra_context, 
 
57
        context_instance = RequestContext(request, context, context_processors)
 
58
    )
 
59
 
 
60
def 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={}):
 
61
    """
 
62
    Receives POST data and either creates a new ``ThreadedComment`` or 
 
63
    ``FreeThreadedComment``, or edits an old one based upon the specified parameters.
 
64
 
 
65
    If there is a 'preview' key in the POST request, a preview will be forced and the
 
66
    comment will not be saved until a 'preview' key is no longer in the POST request.
 
67
    
 
68
    If it is an *AJAX* request (either XML or JSON), it will return a serialized
 
69
    version of the last created ``ThreadedComment`` and there will be no redirect.
 
70
    
 
71
    If invalid POST data is submitted, this will go to the comment preview page
 
72
    where the comment may be edited until it does not contain errors.
 
73
    """
 
74
    if not edit_id and not (content_type and object_id):
 
75
        raise Http404 # Must specify either content_type and object_id or edit_id
 
76
    if "preview" in request.POST:
 
77
        return _preview(request, context_processors, extra_context, form_class=form_class)
 
78
    if edit_id:
 
79
        instance = get_object_or_404(model, id=edit_id)
 
80
    else:
 
81
        instance = None
 
82
    _adjust_max_comment_length(form_class)
 
83
    form = form_class(request.POST, instance=instance)
 
84
    if form.is_valid():
 
85
        new_comment = form.save(commit=False)
 
86
        if not edit_id:
 
87
            new_comment.ip_address = request.META.get('REMOTE_ADDR', None)
 
88
            new_comment.content_type = get_object_or_404(ContentType, id = int(content_type))
 
89
            new_comment.object_id = int(object_id)
 
90
        if model == ThreadedComment:
 
91
            new_comment.user = request.user
 
92
        if parent_id:
 
93
            new_comment.parent = get_object_or_404(model, id = int(parent_id))
 
94
        new_comment.save()
 
95
        if model == ThreadedComment:
 
96
            if add_messages:
 
97
                request.user.message_set.create(message="Your message has been posted successfully.")
 
98
        else:
 
99
            request.session['successful_data'] = {
 
100
                'name' : form.cleaned_data['name'],
 
101
                'website' : form.cleaned_data['website'],
 
102
                'email' : form.cleaned_data['email'],
 
103
            }
 
104
        if ajax == 'json':
 
105
            return JSONResponse([new_comment,])
 
106
        elif ajax == 'xml':
 
107
            return XMLResponse([new_comment,])
 
108
        else:
 
109
            return HttpResponseRedirect(_get_next(request))
 
110
    elif ajax=="json":
 
111
        return JSONResponse({'errors' : form.errors}, is_iterable=False)
 
112
    elif ajax=="xml":
 
113
        template_str = """
 
114
<errorlist>
 
115
    {% for error,name in errors %}
 
116
    <field name="{{ name }}">
 
117
        {% for suberror in error %}<error>{{ suberror }}</error>{% endfor %}
 
118
    </field>
 
119
    {% endfor %}
 
120
</errorlist>
 
121
        """
 
122
        response_str = Template(template_str).render(Context({'errors' : zip(form.errors.values(), form.errors.keys())}))
 
123
        return XMLResponse(response_str, is_iterable=False)
 
124
    else:
 
125
        return _preview(request, context_processors, extra_context, form_class=form_class)
 
126
      
 
127
def comment(*args, **kwargs):
 
128
    """
 
129
    Thin wrapper around free_comment which adds login_required status and also assigns
 
130
    the ``model`` to be ``ThreadedComment``.
 
131
    """
 
132
    kwargs['model'] = ThreadedComment
 
133
    kwargs['form_class'] = ThreadedCommentForm
 
134
    return free_comment(*args, **kwargs)
 
135
# Require login to be required, as request.user must exist and be valid.
 
136
comment = login_required(comment)
 
137
 
 
138
def can_delete_comment(comment, user):
 
139
    """
 
140
    Default callback function to determine wether the given user has the
 
141
    ability to delete the given comment.
 
142
    """
 
143
    if user.is_staff or user.is_superuser:
 
144
        return True
 
145
    if hasattr(comment, 'user') and comment.user == user:
 
146
        return True
 
147
    return False
 
148
 
 
149
def comment_delete(request, object_id, model=ThreadedComment, extra_context = {}, context_processors = [], permission_callback=can_delete_comment):
 
150
    """
 
151
    Deletes the specified comment, which can be either a ``FreeThreadedComment`` or a
 
152
    ``ThreadedComment``.  If it is a POST request, then the comment will be deleted
 
153
    outright, however, if it is a GET request, a confirmation page will be shown.
 
154
    """
 
155
    tc = get_object_or_404(model, id=int(object_id))
 
156
    if not permission_callback(tc, request.user):
 
157
        login_url = settings.LOGIN_URL
 
158
        current_url = urlquote(request.get_full_path())
 
159
        return HttpResponseRedirect("%s?next=%s" % (login_url, current_url))
 
160
    if request.method == "POST":
 
161
        tc.delete()
 
162
        return HttpResponseRedirect(_get_next(request))
 
163
    else:
 
164
        if model == ThreadedComment:
 
165
            is_free_threaded_comment = False
 
166
            is_threaded_comment = True
 
167
        else:
 
168
            is_free_threaded_comment = True
 
169
            is_threaded_comment = False
 
170
        return render_to_response(
 
171
            'threadedcomments/confirm_delete.html',
 
172
            extra_context, 
 
173
            context_instance = RequestContext(
 
174
                request, 
 
175
                {
 
176
                    'comment' : tc, 
 
177
                    'is_free_threaded_comment' : is_free_threaded_comment,
 
178
                    'is_threaded_comment' : is_threaded_comment,
 
179
                    'next' : _get_next(request),
 
180
                },
 
181
                context_processors
 
182
            )
 
183
        )
 
 
b'\\ No newline at end of file'