Coverage for jutil/middleware.py : 78%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
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 full_path = request.get_full_path()
57 user = request.user
58 msg = "{full_path}\n{err} (IP={ip}, user={user}) {trace}".format(
59 full_path=full_path, user=user, ip=get_client_ip(request)[0], err=e, trace=str(traceback.format_exc())
60 )
61 logger.error(msg)
62 hostname = request.get_host()
63 if not settings.DEBUG and hostname != "testserver": 63 ↛ 64line 63 didn't jump to line 64, because the condition on line 63 was never true
64 send_email(settings.ADMINS, "Error @ {}".format(hostname), msg)
67class EnsureLanguageCookieMiddleware:
68 """
69 Ensures language cookie (by name settings.LANGUAGE_COOKIE_NAME) is set.
70 Sets it as settings.LANGUAGE_CODE if missing.
71 Allows changing settings by passing querystring parameter named settings.LANGUAGE_COOKIE_NAME
72 (default: django_language).
74 Order of preference for the language (must be one of settings.LANGUAGES to be used):
75 1) Explicit querystring GET parameter (e.g. ?lang=en)
76 2) Previously stored cookie
77 3) settings.LANGUAGE_CODE
78 """
80 _languages: Optional[Dict[str, str]]
82 def __init__(self, get_response=None):
83 self.get_response = get_response
84 self._languages = None
86 @property
87 def languages(self) -> Dict[str, str]:
88 if self._languages is None:
89 self._languages = dict(settings.LANGUAGES)
90 return self._languages
92 def __call__(self, request):
93 lang_cookie_name = (
94 settings.LANGUAGE_COOKIE_NAME if hasattr(settings, "LANGUAGE_COOKIE_NAME") else "django_language"
95 )
96 lang_cookie = request.COOKIES.get(lang_cookie_name)
97 lang = request.GET.get(lang_cookie_name)
98 if not lang:
99 lang = lang_cookie
100 if not lang or lang not in self.languages:
101 lang = settings.LANGUAGE_CODE if hasattr(settings, "LANGUAGE_CODE") else "en"
102 request.COOKIES[lang_cookie_name] = lang
104 res = self.get_response(request)
106 if lang_cookie is None or lang != lang_cookie:
107 secure = hasattr(settings, "LANGUAGE_COOKIE_SECURE") and settings.LANGUAGE_COOKIE_SECURE
108 httponly = hasattr(settings, "LANGUAGE_COOKIE_HTTPONLY") and settings.LANGUAGE_COOKIE_HTTPONLY
109 res.set_cookie(lang_cookie_name, lang, secure=secure, httponly=httponly)
110 return res
113class ActivateUserProfileTimezoneMiddleware:
114 """
115 Uses 'timezone' string in request.user.profile to activate user-specific timezone.
116 """
118 def __init__(self, get_response=None):
119 self.get_response = get_response
121 def __call__(self, request):
122 # Code to be executed for each request before
123 # the view (and later middleware) are called.
124 activated = False
125 if request.user.is_authenticated: 125 ↛ 138line 125 didn't jump to line 138, because the condition on line 125 was never false
126 user = request.user
127 if hasattr(user, "profile") and user.profile: 127 ↛ 135line 127 didn't jump to line 135, because the condition on line 127 was never false
128 up = user.profile
129 if hasattr(up, "timezone") and up.timezone: 129 ↛ 133line 129 didn't jump to line 133, because the condition on line 129 was never false
130 timezone.activate(up.timezone)
131 activated = True
132 else:
133 logger.warning("User profile timezone missing so user.profile.timezone could not be activated")
134 else:
135 logger.warning("User profile missing so user.profile.timezone could not be activated")
137 # get response
138 response = self.get_response(request)
140 # Code to be executed for each request/response after
141 # the view is called.
142 if activated: 142 ↛ 144line 142 didn't jump to line 144, because the condition on line 142 was never false
143 timezone.deactivate()
144 return response
147class TestClientLogger:
148 """
149 Logs requests for Django test client.
150 """
152 ignored_paths = {
153 "/admin/jsi18n/",
154 "/favicon.ico",
155 }
157 def __init__(self, get_response=None):
158 self.get_response = get_response
160 def __call__(self, request):
161 if settings.DEBUG:
162 assert isinstance(request, HttpRequest)
163 if request.path not in self.ignored_paths:
164 url = request.path
165 qs = request.GET.dict()
166 if qs:
167 url += "?" + urlencode(request.GET.dict())
168 logger.debug(
169 '[TestClientLogger] self.client.%s("%s", data=%s)', request.method.lower(), url, request.POST.dict()
170 )
171 response = self.get_response(request)
172 return response