import logging import zlib from django.http import JsonResponse from django.shortcuts import redirect from .models import BankAccount, BankTransaction, \ BankAccountDoesNotExist, BankTransactionDoesNotExist from .views import \ (DebitLimitException, SameAccountException, LoginFailed, RejectNoRightsException) from .schemas import \ (JSONFieldException, URLParamValidationError, InvalidSession) from taler.util.amount import \ (CurrencyMismatch, BadFormatAmount, NumberTooBig, NegativeNumber) LOGGER = logging.getLogger() ## # Class decompressing requests. class DecompressionMiddleware: ## # Init constructor. # # @param self the object itself. # @param get_response a Django-provided callable that calls # whatever comes next in the chain: a further middleware # or the view itself (please refer to the official # documentation for more details). def __init__(self, get_response): self.get_response = get_response ## # This function is transparently invoked by Django when # a request traverses the chain made of middleware classes # and the view itself as the last element in the chain. # # Here happens the decompression. # # @param self this class. # @param request Django-specific request object (of the same # type that is handed to views). # @return Django-specific response object. def __call__(self, request): if "deflate" == request.META.get("HTTP_CONTENT_ENCODING"): request._body = zlib.decompress(request.body) return self.get_response(request) ## # Class holding data needed by the handling logic. class ExceptionMiddleware: ## # Init constructor. # # @param self the object itself. # @param get_response a Django-provided callable that calls # whatever comes next in the chain: a further middleware # or the view itself (please refer to the official # documentation for more details). def __init__(self, get_response): self.get_response = get_response # List of all the exceptions that are managed by # this module. self.excs = { BankAccountDoesNotExist: 5110, BankTransactionDoesNotExist: 5111, SameAccountException: 5102, URLParamValidationError: 5105, JSONFieldException: 5106, CurrencyMismatch: 5104, BadFormatAmount: 11, LoginFailed: 5312, NumberTooBig: 5108, NegativeNumber: 5107, DebitLimitException: 5103, RejectNoRightsException: 5200, } # Map between endpoints and Web pages to render # after the exception gets managed. self.render = { "/profile": "profile", "/accounts/register": "index", "/public-accounts": "index", "/pin/verify": "profile", "/withdraw": "profile" } ## # This function is transparently invoked by Django when # a request traverses the chain made of middleware classes # and the view itself as the last element in the chain. # # @param self this class. # @param request Django-specific request object (of the same # type that is handed to views). # @return Django-specific response object. def __call__(self, request): return self.get_response(request) ## # Main logic for processing the exception. It checks # if the exception captured can be managed, and does it # if so. Otherwise, it lets the native handler operate. # # @param self a @a ExceptionMiddleware object. # @param request Django-specific HTTP request. # @param exception the exception raised from the bank. def process_exception(self, request, exception): LOGGER.warning("Exception", exception) # See if we manage this exception. Return None if not. exc_class = None for e in self.excs: if isinstance(exception, e): exc_class = e break if not exc_class: return None # Managed exception. Build response. taler_ec = self.excs.get(exc_class) # Check if the endpoint should cause a human-readable # page to be returned. render_to = self.render.get(request.path) if not render_to: return JsonResponse({"ec": taler_ec, "error": exception.hint}, status=exception.http_status_code) request.session["profile_hint"] = \ True, False, exception.hint return redirect(render_to) # [1] https://git.taler.net/exchange.git/tree/src/include/taler_error_codes.h