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
|
import logging
from django.http import JsonResponse
from django.shortcuts import redirect
from .models import BankAccount, BankTransaction
from .views import \
(DebitLimitException, SameAccountException,
LoginFailed, RejectNoRightsException)
from .schemas import \
(URLParameterMissing, URLParameterMalformed,
JSONFieldException, UnknownCurrencyException)
from .amount import \
(CurrencyMismatch, BadFormatAmount,
NumberTooBig, NegativeNumber)
LOGGER = logging.getLogger()
##
# 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 = {
BankAccount.DoesNotExist: 0,
BankTransaction.DoesNotExist: 1,
SameAccountException: 2,
DebitLimitException: 3,
URLParameterMissing: 8,
URLParameterMalformed: 9,
JSONFieldException: 6,
CurrencyMismatch: 11,
BadFormatAmount: 11,
LoginFailed: 12,
RejectNoRightsException: 13,
UnknownCurrencyException: 14,
NumberTooBig: 1,
NegativeNumber: 0}
# List of all the HTTP endpoint that are likely
# to generate exceptions.
self.apis = {
"/withdraw": 5400,
"/reject": 5300,
"/history": 5200,
"/admin/add/incoming": 5100}
# Map between endpoints and Web pages to render
# after the exception gets managed.
self.render = {
"/profile": "profile",
"/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):
# 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)
# The way error codes compose matches
# definitions found in [1].
taler_ec += self.apis.get(request.path, 1000)
# 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#n1502
|