Coverage for jutil/middleware.py: 78%

# Coverage for jutil/middleware.py : 78%

## 90 statements

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

1 import logging

2 import traceback

3 from typing import Dict, Optional

4 from urllib.parse import urlencode

5 from django.conf import settings

6 from django.http import HttpRequest

7 from django.utils import timezone

8 from ipware import get_client_ip # type: ignore

9 from jutil.email import send_email

10

11 logger = logging.getLogger(__name__)

12

13

14 class EnsureOriginMiddleware:

15 """

16 Ensures that request META 'HTTP_ORIGIN' is set.

17 Uses request get_host() to set it if missing.

18 """

19

20 def __init__(self, get_response=None):

21 self.get_response = get_response

22

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()

28

29 # get response

30 response = self.get_response(request)

31

32 # Code to be executed for each request/response after

33 # the view is called.

34 return response

35

36

37 class LogExceptionMiddleware:

38 """

39 Logs exception and sends email to admins about it.

40 Uses list of emails from settings.ADMINS.

41 """

42

43 def __init__(self, get_response=None):

44 self.get_response = get_response

45

46 def __call__(self, request):

47 return self.get_response(request)

48

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)

65

66

67 class 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).

73

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 """

79

80 _languages: Optional[Dict[str, str]]

81

82 def __init__(self, get_response=None):

83 self.get_response = get_response

84 self._languages = None

85

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

91

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

103

104 res = self.get_response(request)

105

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

111

112

113 class ActivateUserProfileTimezoneMiddleware:

114 """

115 Uses 'timezone' string in request.user.profile to activate user-specific timezone.

116 """

117

118 def __init__(self, get_response=None):

119 self.get_response = get_response

120

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")

136

137 # get response

138 response = self.get_response(request)

139

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

145

146

147 class TestClientLogger:

148 """

149 Logs requests for Django test client.

150 """

151

152 ignored_paths = {

153 "/admin/jsi18n/",

154 "/favicon.ico",

155 }

156

157 def __init__(self, get_response=None):

158 self.get_response = get_response

159

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