1 # -*- coding: utf-8 -*-
2 # Copyright (C) 2015-2021 by the Free Software Foundation, Inc.
4 # This file is part of Postorius.
6 # Postorius is free software: you can redistribute it and/or modify it under
7 # the terms of the GNU General Public License as published by the Free
8 # Software Foundation, either version 3 of the License, or (at your option)
11 # Postorius is distributed in the hope that it will be useful, but WITHOUT
12 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 # You should have received a copy of the GNU General Public License along with
17 # Postorius. If not, see <http://www.gnu.org/licenses/>.
20 from urllib
.error
import HTTPError
22 from django_mailman3
.lib
import mailman
23 from mailmanclient
import MailmanConnectionError
25 from postorius
import utils
26 from postorius
.models
import MailmanApiError
29 logger
= logging
.getLogger('postorius')
33 'PostoriusMiddleware',
37 class PostoriusMiddleware(object):
39 def __init__(self
, get_response
=None):
40 self
.get_response
= get_response
42 def __call__(self
, request
):
43 return self
.get_response(request
)
45 def process_exception(self
, request
, exception
):
46 if isinstance(exception
, (MailmanApiError
, MailmanConnectionError
)):
47 logger
.exception('Mailman REST API not available')
48 return utils
.render_api_error(request
)
49 elif isinstance(exception
, HTTPError
):
50 logger
.exception('Un-handled exception: %s', str(exception
))
51 return utils
.render_client_error(request
, exception
)
54 class APICountingMiddleware
:
55 """Counts the total number of API calls made to Core and prints summary.
57 It hooks into mailmanclient's hooking mechanism, facilitated by
58 ``django_mailman3.lib.mailman.mailmanclient_request_hook``. It stores the
59 parameter of each API call made in `self.api_call_counter()` and prints it
60 *before* returning the response in `__call__`.
62 It hooks up ``_trace_api_calls()`` method into the Hooks API. Even if the
63 hooking happens multiple times, it is only added once since it
64 deduplicates the hooks.
66 Output looks something like:
68 DEBUG: =======================
69 DEBUG: Handle reqsponse for /postorius/lists/mylist.lists.araj.me/settings/
70 DEBUG: View function was postorius.views.list.list_settings
72 DEBUG: [GET] http://localhost:8001/3.1/lists/mylist.lists.araj.me with None
74 DEBUG: ======================
76 Note: If you don't see the output on console, check the 'postorius' logger
77 settings and make sure that it has `console` handler and level is set to
82 def __init__(self
, get_response
=None):
83 self
.get_response
= get_response
84 mailman
.mailmanclient_request_hook(self
._trace
_api
_calls
)
85 self
.api_call_counter
= []
88 def __call__(self
, request
):
89 self
.request
= request
90 response
= self
.get_response(request
)
91 logger
.debug('=======================')
92 logger
.debug('Handle reqsponse for %s', request
.path
)
93 logger
.debug('View function was %s', self
.view_func
)
94 logger
.debug('%s calls to API', len(self
.api_call_counter
))
95 for each
in self
.api_call_counter
:
96 logger
.debug('[%s] %s with %s',
97 each
.get('method'), each
.get('url'), each
.get('data'))
98 logger
.debug('=======================')
101 def _trace_api_calls(self
, params
):
102 """Hook that adds all the call parameters to self.api_call_counter.
104 :param params: List of request params from mailmanclient.
106 self
.api_call_counter
.append(params
)
109 def process_view(self
, request
, view_func
, view_args
, view_kwars
):
110 """Get a pointer to view function object."""
111 self
.view_func
= '{}.{}'.format(
112 view_func
.__module
__, view_func
.__name
__)