# -*- coding: utf-8 -*-
# This file is part of Shuup.
#
# Copyright (c) 2012-2021, Shuup Commerce Inc. All rights reserved.
#
# This source code is licensed under the OSL-3.0 license found in the
# LICENSE file in the root directory of this source tree.
from __future__ import unicode_literals
from importlib import import_module
from django.conf import settings
from django.http import HttpResponse
from shuup.utils.importing import load
_URLCONF_ERROR_HANDLERS = {}
HANDLER_ATTR_FMT = "handler%s"
[docs]class ErrorPageHandler(object):
"""
A base class for error pages handling.
"""
@classmethod
[docs] def can_handle_error(cls, request, error_status):
"""
Returns whether this object can handle the error.
:rtype: bool
"""
raise NotImplementedError(
"Error! Not implemented: `ErrorPageHandler` -> `apply_for_product()`. Implement this method."
)
@classmethod
[docs] def handle_error(cls, request, error_status):
"""
Returns a response for the given request and error status.
:rtype: django.http.HttpResponse
"""
raise NotImplementedError(
"Error! Not implemented: `ErrorPageHandler` -> `handle_error(). Implement this method.`"
)
[docs]def make_error_view(error_status):
"""
A factory of error views which tries to find a compatible error handler.
If there is no handler that can do the job, use the Django's default or return a blank response.
"""
def view(request, *args, **kwargs):
handler_attr = HANDLER_ATTR_FMT % error_status
# look for compatible error handlers
for handler_spec in settings.SHUUP_ERROR_PAGE_HANDLERS_SPEC:
handler = load(handler_spec)()
# return a response for the error status
if handler.can_handle_error(request, error_status):
return handler.handle_error(request, error_status)
# tries to use the default handler (set in django's root urlconf)
# otherwise just a blank response
fallback_handler = _URLCONF_ERROR_HANDLERS.get(handler_attr)
if fallback_handler and callable(fallback_handler):
return fallback_handler(request)
else:
return HttpResponse(status=error_status)
return view
[docs]def install_error_handlers():
"""
Install custom error handlers.
Error handlers to be added are for errors 400, 403, 404, and 500.
"""
root_urlconf_module = getattr(settings, "ROOT_URLCONF", None)
if not root_urlconf_module: # That's weird, but let's not crash here.
return
try:
root_urlconf = import_module(root_urlconf_module)
except ImportError: # Also weird, but not worth a crash.
return
for error_status in (400, 403, 404, 500):
handler_attr = HANDLER_ATTR_FMT % error_status
# save the currenct handlers for fallbacks
if hasattr(root_urlconf, handler_attr):
_URLCONF_ERROR_HANDLERS[handler_attr] = getattr(root_urlconf, handler_attr)
# overwrite the error handlers by ours
setattr(root_urlconf, handler_attr, make_error_view(error_status))