Skip to content
This repository has been archived by the owner on Nov 9, 2017. It is now read-only.

Commit

Permalink
Replace abort() to pass exception info to error pages.
Browse files Browse the repository at this point in the history
  • Loading branch information
chromakode authored and Logan Hanks committed Aug 24, 2012
1 parent f6a994e commit 633a710
Show file tree
Hide file tree
Showing 7 changed files with 50 additions and 11 deletions.
5 changes: 5 additions & 0 deletions r2/r2/config/middleware.py
Expand Up @@ -69,6 +69,11 @@ def error_mapper(code, message, environ, global_conf=None, **kw):
if code in codes:
# StatusBasedForward expects a relative URL (no SCRIPT_NAME)
d = dict(code = code, message = message)

exception = environ.get('r2.controller.exception')
if exception:
d['explanation'] = exception.explanation

if environ.get('REDDIT_CNAME'):
d['cnameframe'] = 1
if environ.get('REDDIT_NAME'):
Expand Down
3 changes: 2 additions & 1 deletion r2/r2/controllers/error.py
Expand Up @@ -116,7 +116,8 @@ def send403(self):
else:
res = pages.RedditError(
title=_("forbidden (%(domain)s)") % dict(domain=g.domain),
message=_("you are not allowed to do that"))
message=_("you are not allowed to do that"),
explanation=request.GET.get('explanation'))
return res.render()

def send404(self):
Expand Down
7 changes: 7 additions & 0 deletions r2/r2/controllers/errors.py
Expand Up @@ -20,12 +20,14 @@
# Inc. All Rights Reserved.
###############################################################################

from paste.httpexceptions import HTTPForbidden
from r2.lib.utils import Storage, tup
from pylons.i18n import _
from copy import copy

error_list = dict((
('USER_REQUIRED', _("please login to do that")),
('HTTPS_REQUIRED', _("this page must be accessed using https")),
('VERIFIED_USER_REQUIRED', _("you need to set a valid email address to do that.")),
('NO_URL', _('a url is required')),
('BAD_URL', _('you should check that url')),
Expand Down Expand Up @@ -161,6 +163,11 @@ def remove(self, pair):
if self.errors.has_key(pair):
del self.errors[pair]

class ForbiddenError(HTTPForbidden):
def __init__(self, error):
HTTPForbidden.__init__(self)
self.explanation = error_list[error]

class UserRequiredException(Exception): pass
class VerifiedUserRequiredException(Exception): pass
class GoldRequiredException(Exception): pass
9 changes: 5 additions & 4 deletions r2/r2/controllers/reddit_base.py
Expand Up @@ -22,22 +22,23 @@

from mako.filters import url_escape
from pylons import c, g, request
from pylons.controllers.util import abort, redirect_to
from pylons.controllers.util import redirect_to
from pylons.i18n import _
from pylons.i18n.translation import LanguageError
from r2.lib.base import BaseController, proxyurl
from r2.lib import pages, utils, filters, amqp, stats
from r2.lib.utils import http_utils, is_subdomain, UniqueIterator, is_throttled
from r2.lib.cache import LocalCache, make_key, MemcachedError
import random as rand
from r2.models.account import valid_cookie, FakeAccount, valid_feed, valid_admin_cookie
from r2.models.subreddit import Subreddit, Frontpage
from r2.models import *
from errors import ErrorSet
from errors import ErrorSet, ForbiddenError, errors
from validator import *
from r2.lib.template_helpers import add_sr
from r2.config.extensions import is_api
from r2.lib.translation import set_lang
from r2.lib.contrib import ipaddress
from r2.lib.base import BaseController, proxyurl, abort

from Cookie import CookieError
from copy import copy
Expand Down Expand Up @@ -544,7 +545,7 @@ def cross_domain_handler(self, *args, **kwargs):

def require_https():
if not c.secure:
abort(403)
abort(ForbiddenError(errors.HTTPS_REQUIRED))

def prevent_framing_and_css(allow_cname_frame=False):
def wrap(f):
Expand Down
18 changes: 17 additions & 1 deletion r2/r2/lib/base.py
Expand Up @@ -26,8 +26,8 @@

from pylons import Response, c, g, request, session, config
from pylons.controllers import WSGIController, Controller
from pylons.controllers.util import abort
from pylons.i18n import N_, _, ungettext, get_lang
from paste import httpexceptions
from r2.lib.utils import to_js
from r2.lib.filters import spaceCompress, _force_unicode
from r2.lib.template_helpers import get_domain
Expand Down Expand Up @@ -63,6 +63,22 @@ def is_local_address(ip):
# TODO: support the /20 and /24 private networks? make this configurable?
return ip.startswith('10.')

def abort(code_or_exception=None, detail="", headers=None, comment=None):
"""Raise an HTTPException and save it in environ for use by error pages."""
# Pylons 0.9.6 makes it really hard to get your raised HTTPException,
# so this helper implements it manually using a familiar syntax.
# FIXME: when we upgrade Pylons, we can replace this with raise
# and access environ['pylons.controller.exception']
if isinstance(code_or_exception, httpexceptions.HTTPException):
exc = code_or_exception
else:
if type(code_or_exception) is type and issubclass(code_or_exception, httpexceptions.HTTPException):
exc_cls = code_or_exception
else:
exc_cls = httpexceptions.get_exception(code_or_exception)
exc = exc_cls(detail, headers, comment)
request.environ['r2.controller.exception'] = exc
raise exc

class BaseController(WSGIController):
def try_pagecache(self):
Expand Down
16 changes: 11 additions & 5 deletions r2/r2/lib/pages/pages.py
Expand Up @@ -1380,26 +1380,32 @@ def __init__(self, client, *args, **kwargs):

class RedditError(BoringPage):
site_tracking = False
def __init__(self, title, message, image=None, sr_description=None):
def __init__(self, title, message, image=None, sr_description=None,
explanation=None):
BoringPage.__init__(self, title, loginbox=False,
show_sidebar = False,
show_sidebar = False,
content=ErrorPage(title=title,
message=message,
image=image,
sr_description=sr_description))
sr_description=sr_description,
explanation=explanation))

class ErrorPage(Templated):
"""Wrapper for an error message"""
def __init__(self, title, message, image=None, **kwargs):
def __init__(self, title, message, image=None, explanation=None, **kwargs):
if not image:
letter = random.choice(['a', 'b', 'c', 'd', 'e'])
image = 'reddit404' + letter + '.png'
# Normalize explanation strings.
if explanation:
explanation = explanation.lower().rstrip('.') + '.'
Templated.__init__(self,
title=title,
message=message,
image_url=image,
explanation=explanation,
**kwargs)


class Over18(Templated):
"""The creepy 'over 18' check page for nsfw content."""
Expand Down
3 changes: 3 additions & 0 deletions r2/r2/templates/errorpage.html
Expand Up @@ -31,6 +31,9 @@
<h1>${thing.title}</h1>
<div class="errorpage-message">
${unsafe(safemarkdown(thing.message, wrap=False))}
%if thing.explanation:
&mdash; ${thing.explanation}
%endif
</div>

% if thing.sr_description:
Expand Down

0 comments on commit 633a710

Please sign in to comment.