1 # -*- coding: utf-8 -*-
2 # Copyright (C) 2015-2022 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):
38 def __init__(self
, get_response
=None):
39 self
.get_response
= get_response
41 def __call__(self
, request
):
42 return self
.get_response(request
)
44 def process_exception(self
, request
, exception
):
45 if isinstance(exception
, (MailmanApiError
, MailmanConnectionError
)):
46 logger
.exception('Mailman REST API not available')
47 return utils
.render_api_error(request
)
48 elif isinstance(exception
, HTTPError
):
49 logger
.exception('Un-handled exception: %s', str(exception
))
50 return utils
.render_client_error(request
, exception
)
53 class APICountingMiddleware
:
54 """Counts the total number of API calls made to Core and prints summary.
56 It hooks into mailmanclient's hooking mechanism, facilitated by
57 ``django_mailman3.lib.mailman.mailmanclient_request_hook``. It stores the
58 parameter of each API call made in `self.api_call_counter()` and prints it
59 *before* returning the response in `__call__`.
61 It hooks up ``_trace_api_calls()`` method into the Hooks API. Even if the
62 hooking happens multiple times, it is only added once since it
63 deduplicates the hooks.
65 Output looks something like:
67 DEBUG: =======================
68 DEBUG: Handle reqsponse for /postorius/lists/mylist.lists.araj.me/settings/
69 DEBUG: View function was postorius.views.list.list_settings
71 DEBUG: [GET] http://localhost:8001/3.1/lists/mylist.lists.araj.me with None
73 DEBUG: ======================
75 Note: If you don't see the output on console, check the 'postorius' logger
76 settings and make sure that it has `console` handler and level is set to
81 def __init__(self
, get_response
=None):
82 self
.get_response
= get_response
83 mailman
.mailmanclient_request_hook(self
._trace
_api
_calls
)
84 self
.api_call_counter
= []
87 def __call__(self
, request
):
88 self
.request
= request
89 response
= self
.get_response(request
)
90 logger
.debug('=======================')
91 logger
.debug('Handle reqsponse for %s', request
.path
)
92 logger
.debug('View function was %s', self
.view_func
)
93 logger
.debug('%s calls to API', len(self
.api_call_counter
))
94 for each
in self
.api_call_counter
:
101 logger
.debug('=======================')
102 self
.api_call_counter
= []
105 def _trace_api_calls(self
, params
):
106 """Hook that adds all the call parameters to self.api_call_counter.
108 :param params: List of request params from mailmanclient.
110 self
.api_call_counter
.append(params
)
113 def process_view(self
, request
, view_func
, view_args
, view_kwars
):
114 """Get a pointer to view function object."""
115 self
.view_func
= '{}.{}'.format(
116 view_func
.__module
__, view_func
.__name
__