Coverage for jutil/middleware.py: 78%
91 statements
« prev ^ index » next coverage.py v6.5.0, created at 2022-10-07 16:40 -0500
« prev ^ index » next coverage.py v6.5.0, created at 2022-10-07 16:40 -0500
1import logging
2import traceback
3from typing import Dict, Optional
4from urllib.parse import urlencode
5from django.conf import settings
6from django.http import HttpRequest
7from django.utils import timezone
8from ipware import get_client_ip # type: ignore
9from jutil.email import send_email
11logger = logging.getLogger(__name__)
14class EnsureOriginMiddleware:
15 """
16 Ensures that request META 'HTTP_ORIGIN' is set.
17 Uses request get_host() to set it if missing.
18 """
20 def __init__(self, get_response=None):
21 self.get_response = get_response
23 def __call__(self, request):
24 # Code to be executed for each request before
25 # the view (and later middleware) are called.
26 if not request.META.get("HTTP_ORIGIN", None): 26 ↛ 30line 26 didn't jump to line 30, because the condition on line 26 was never false
27 request.META["HTTP_ORIGIN"] = request.get_host()
29 # get response
30 response = self.get_response(request)
32 # Code to be executed for each request/response after
33 # the view is called.
34 return response
37class LogExceptionMiddleware:
38 """
39 Logs exception and sends email to admins about it.
40 Uses list of emails from settings.ADMINS.
41 """
43 def __init__(self, get_response=None):
44 self.get_response = get_response
46 def __call__(self, request):
47 return self.get_response(request)
49 def process_exception(self, request, e):
50 """
51 Logs exception error message and sends email to ADMINS if hostname is not testserver and DEBUG=False.
52 :param request: HttpRequest
53 :param e: Exception
54 """
55 assert isinstance(request, HttpRequest)
56 method = str(request.method).upper()
57 uri = request.build_absolute_uri()
58 user = request.user
59 msg = "{method} {uri}\n{err} (IP={ip}, user={user}) {trace}".format(
60 method=method, uri=uri, user=user, ip=get_client_ip(request)[0], err=e, trace=traceback.format_exc()
61 )
62 logger.error(msg)
63 hostname = request.get_host()
64 if not settings.DEBUG and hostname != "testserver": 64 ↛ 65line 64 didn't jump to line 65, because the condition on line 64 was never true
65 send_email(settings.ADMINS, "Error @ {}".format(hostname), msg)
68class EnsureLanguageCookieMiddleware:
69 """
70 Ensures language cookie (by name settings.LANGUAGE_COOKIE_NAME) is set.
71 Sets it as settings.LANGUAGE_CODE if missing.
72 Allows changing settings by passing querystring parameter named settings.LANGUAGE_COOKIE_NAME
73 (default: django_language).
75 Order of preference for the language (must be one of settings.LANGUAGES to be used):
76 1) Explicit querystring GET parameter (e.g. ?lang=en)
77 2) Previously stored cookie
78 3) settings.LANGUAGE_CODE
79 """
81 _languages: Optional[Dict[str, str]]
83 def __init__(self, get_response=None):
84 self.get_response = get_response
85 self._languages = None
87 @property
88 def languages(self) -> Dict[str, str]:
89 if self._languages is None:
90 self._languages = dict(settings.LANGUAGES)
91 return self._languages
93 def __call__(self, request):
94 lang_cookie_name = settings.LANGUAGE_COOKIE_NAME if hasattr(settings, "LANGUAGE_COOKIE_NAME") else "django_language"
95 lang_cookie = request.COOKIES.get(lang_cookie_name)
96 lang = request.GET.get(lang_cookie_name)
97 if not lang:
98 lang = lang_cookie
99 if not lang or lang not in self.languages:
100 lang = settings.LANGUAGE_CODE if hasattr(settings, "LANGUAGE_CODE") else "en"
101 request.COOKIES[lang_cookie_name] = lang
103 res = self.get_response(request)
105 if lang_cookie is None or lang != lang_cookie:
106 secure = hasattr(settings, "LANGUAGE_COOKIE_SECURE") and settings.LANGUAGE_COOKIE_SECURE
107 httponly = hasattr(settings, "LANGUAGE_COOKIE_HTTPONLY") and settings.LANGUAGE_COOKIE_HTTPONLY
108 res.set_cookie(lang_cookie_name, lang, secure=secure, httponly=httponly)
109 return res
112class ActivateUserProfileTimezoneMiddleware:
113 """
114 Uses 'timezone' string in request.user.profile to activate user-specific timezone.
115 """
117 def __init__(self, get_response=None):
118 self.get_response = get_response
120 def __call__(self, request):
121 # Code to be executed for each request before
122 # the view (and later middleware) are called.
123 activated = False
124 if request.user.is_authenticated: 124 ↛ 137line 124 didn't jump to line 137, because the condition on line 124 was never false
125 user = request.user
126 if hasattr(user, "profile") and user.profile: 126 ↛ 134line 126 didn't jump to line 134, because the condition on line 126 was never false
127 up = user.profile
128 if hasattr(up, "timezone") and up.timezone: 128 ↛ 132line 128 didn't jump to line 132, because the condition on line 128 was never false
129 timezone.activate(up.timezone)
130 activated = True
131 else:
132 logger.warning("User profile timezone missing so user.profile.timezone could not be activated")
133 else:
134 logger.warning("User profile missing so user.profile.timezone could not be activated")
136 # get response
137 response = self.get_response(request)
139 # Code to be executed for each request/response after
140 # the view is called.
141 if activated: 141 ↛ 143line 141 didn't jump to line 143, because the condition on line 141 was never false
142 timezone.deactivate()
143 return response
146class TestClientLoggerMiddleware:
147 """
148 Logs requests to be used with Django test framework client.
149 """
151 ignored_paths = {
152 "/admin/jsi18n/",
153 "/favicon.ico",
154 }
156 def __init__(self, get_response=None):
157 self.get_response = get_response
159 def __call__(self, request):
160 if settings.DEBUG:
161 assert isinstance(request, HttpRequest)
162 if request.path not in self.ignored_paths:
163 url = request.path
164 qs = request.GET.dict()
165 if qs:
166 url += "?" + urlencode(request.GET.dict())
167 logger.debug('self.client.%s("%s", data=%s)', request.method.lower(), url, request.POST.dict())
168 response = self.get_response(request)
169 return response