aboutsummaryrefslogtreecommitdiffstats
path: root/mediagoblin/tools/response.py
blob: 1380633fbd362a20f2397cb6d131291888e82bb4 (plain)
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
# GNU MediaGoblin -- federated, autonomous media hosting
# Copyright (C) 2011, 2012 MediaGoblin contributors.  See AUTHORS.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import json

import six
import werkzeug.utils
from werkzeug.wrappers import Response as wz_Response
from mediagoblin.tools.template import render_template
from mediagoblin.tools.translate import (lazy_pass_to_ugettext as _,
                                         pass_to_ugettext)
from mediagoblin.db.models import UserBan, User
from datetime import date

class Response(wz_Response):
    """Set default response mimetype to HTML, otherwise we get text/plain"""
    default_mimetype = u'text/html'


def render_to_response(request, template, context, status=200):
    """Much like Django's shortcut.render()"""
    return Response(
        render_template(request, template, context),
        status=status)

def render_error(request, status=500, title=_('Oops!'),
                 err_msg=_('An error occured')):
    """Render any error page with a given error code, title and text body

    Title and description are passed through as-is to allow html. Make
    sure no user input is contained therein for security reasons. The
    description will be wrapped in <p></p> tags.
    """
    return Response(render_template(request, 'mediagoblin/error.html',
        {'err_code': status, 'title': title, 'err_msg': err_msg}),
        status=status)

def render_400(request, err_msg=None):
    """ Render a standard 400 page"""
    _ = pass_to_ugettext
    title = _("Bad Request")
    if err_msg is None:
        err_msg = _("The request sent to the server is invalid, \
please double check it")

    return render_error(request, 400, title, err_msg)

def render_403(request):
    """Render a standard 403 page"""
    _ = pass_to_ugettext
    title = _('Operation not allowed')
    err_msg = _("Sorry Dave, I can't let you do that!</p><p>You have tried "
                " to perform a function that you are not allowed to. Have you "
                "been trying to delete all user accounts again?")
    return render_error(request, 403, title, err_msg)

def render_404(request):
    """Render a standard 404 page."""
    _ = pass_to_ugettext
    err_msg = _("There doesn't seem to be a page at this address. Sorry!</p>"
                "<p>If you're sure the address is correct, maybe the page "
                "you're looking for has been moved or deleted.")
    return render_error(request, 404, err_msg=err_msg)

def render_user_banned(request):
    """Renders the page which tells a user they have been banned, for how long
    and the reason why they have been banned"
    """
    user_ban = UserBan.query.get(request.user.id)
    if (user_ban.expiration_date is not None and
            date.today()>user_ban.expiration_date):

        user_ban.delete()
        return redirect(request,
            'index')
    return render_to_response(request,
        'mediagoblin/banned.html',
        {'reason':user_ban.reason,
         'expiration_date':user_ban.expiration_date})

def render_http_exception(request, exc, description):
    """Return Response() given a werkzeug.HTTPException

    :param exc: werkzeug.HTTPException or subclass thereof
    :description: message describing the error."""
    # If we were passed the HTTPException stock description on
    # exceptions where we have localized ones, use those:
    stock_desc = (description == exc.__class__.description)

    if stock_desc and exc.code == 403:
        return render_403(request)
    elif stock_desc and exc.code == 404:
        return render_404(request)

    return render_error(request, title='{0} {1}'.format(exc.code, exc.name),
                        err_msg=description,
                        status=exc.code)


def redirect(request, *args, **kwargs):
    """Redirects to an URL, using urlgen params or location string

    :param querystring: querystring to be appended to the URL
    :param location: If the location keyword is given, redirect to the URL
    """
    querystring = kwargs.pop('querystring', None)

    # Redirect to URL if given by "location=..."
    if 'location' in kwargs:
        location = kwargs.pop('location')
    else:
        location = request.urlgen(*args, **kwargs)

    if querystring:
        location += querystring
    return werkzeug.utils.redirect(location)


def redirect_obj(request, obj):
    """Redirect to the page for the given object.

    Requires obj to have a .url_for_self method."""
    return redirect(request, location=obj.url_for_self(request.urlgen))

def json_response(serializable, _disable_cors=False, *args, **kw):
    '''
    Serializes a json objects and returns a werkzeug Response object with the
    serialized value as the response body and Content-Type: application/json.

    :param serializable: A json-serializable object

    Any extra arguments and keyword arguments are passed to the
    Response.__init__ method.
    '''

    response = wz_Response(json.dumps(serializable), *args, content_type='application/json', **kw)

    if not _disable_cors:
        cors_headers = {
                'Access-Control-Allow-Origin': '*',
                'Access-Control-Allow-Methods': 'POST, GET, OPTIONS',
                'Access-Control-Allow-Headers': 'Content-Type, X-Requested-With'}
        for key, value in six.iteritems(cors_headers):
            response.headers.set(key, value)

    return response

def form_response(data, *args, **kwargs):
    """
        Responds using application/x-www-form-urlencoded and returns a werkzeug
        Response object with the data argument as the body
        and 'application/x-www-form-urlencoded' as the Content-Type.

        Any extra arguments and keyword arguments are passed to the
        Response.__init__ method.
    """

    response = wz_Response(
            data,
            content_type="application/x-www-form-urlencoded",
            *args,
            **kwargs
            )

    return response