Coverage for benefits/core/middleware.py: 95%

84 statements  

« prev     ^ index     » next       coverage.py v7.8.0, created at 2025-04-22 21:13 +0000

1""" 

2The core application: middleware definitions for request/response cycle. 

3""" 

4 

5import logging 

6 

7from django.conf import settings 

8from django.http import HttpResponse 

9from django.template.response import TemplateResponse 

10from django.urls import reverse 

11from django.utils.decorators import decorator_from_middleware 

12from django.utils.deprecation import MiddlewareMixin 

13from django.views import i18n 

14 

15from benefits.routes import routes 

16from . import analytics, recaptcha, session 

17 

18 

19logger = logging.getLogger(__name__) 

20 

21HEALTHCHECK_PATH = "/healthcheck" 

22TEMPLATE_USER_ERROR = "200-user-error.html" 

23 

24 

25def user_error(request): 

26 return TemplateResponse(request, TEMPLATE_USER_ERROR) 

27 

28 

29class AgencySessionRequired(MiddlewareMixin): 

30 """Middleware raises an exception for sessions lacking an agency configuration.""" 

31 

32 def process_request(self, request): 

33 if session.active_agency(request): 

34 logger.debug("Session configured with agency") 

35 return None 

36 else: 

37 logger.debug("Session not configured with agency") 

38 return user_error(request) 

39 

40 

41class EligibleSessionRequired(MiddlewareMixin): 

42 """Middleware raises an exception for sessions lacking confirmed eligibility.""" 

43 

44 def process_request(self, request): 

45 if session.eligible(request): 

46 logger.debug("Session has confirmed eligibility") 

47 return None 

48 else: 

49 logger.debug("Session has no confirmed eligibility") 

50 return user_error(request) 

51 

52 

53class DebugSession(MiddlewareMixin): 

54 """Middleware to configure debug context in the request session.""" 

55 

56 def process_request(self, request): 

57 session.update(request, debug=settings.DEBUG) 

58 return None 

59 

60 

61class Healthcheck: 

62 """Middleware intercepts and accepts /healthcheck requests.""" 

63 

64 def __init__(self, get_response): 

65 self.get_response = get_response 

66 

67 def __call__(self, request): 

68 if request.path == HEALTHCHECK_PATH: 

69 return HttpResponse("Healthy", content_type="text/plain") 

70 return self.get_response(request) 

71 

72 

73class HealthcheckUserAgents(MiddlewareMixin): 

74 """Middleware to return healthcheck for user agents specified in HEALTHCHECK_USER_AGENTS.""" 

75 

76 def process_request(self, request): 

77 if hasattr(request, "META"): 77 ↛ 82line 77 didn't jump to line 82 because the condition on line 77 was always true

78 user_agent = request.META.get("HTTP_USER_AGENT", "") 

79 if user_agent in settings.HEALTHCHECK_USER_AGENTS: 

80 return HttpResponse("Healthy", content_type="text/plain") 

81 

82 return self.get_response(request) 

83 

84 

85class FlowSessionRequired(MiddlewareMixin): 

86 """Middleware raises an exception for sessions lacking a configured enrollment flow.""" 

87 

88 def process_request(self, request): 

89 if session.flow(request): 

90 logger.debug("Session configured with enrollment flow") 

91 return None 

92 else: 

93 logger.debug("Session not configured with enrollment flow") 

94 return user_error(request) 

95 

96 

97class ViewedPageEvent(MiddlewareMixin): 

98 """Middleware sends an analytics event for page views.""" 

99 

100 def process_response(self, request, response): 

101 event = analytics.ViewedPageEvent(request) 

102 try: 

103 analytics.send_event(event) 

104 except Exception: 

105 logger.warning(f"Failed to send event: {event}") 

106 finally: 

107 return response 

108 

109 

110pageview_decorator = decorator_from_middleware(ViewedPageEvent) 

111 

112 

113class ChangedLanguageEvent(MiddlewareMixin): 

114 """Middleware hooks into django.views.i18n.set_language to send an analytics event.""" 

115 

116 def process_view(self, request, view_func, view_args, view_kwargs): 

117 if view_func == i18n.set_language: 

118 new_lang = request.POST.get("language") 

119 if new_lang: 

120 event = analytics.ChangedLanguageEvent(request, new_lang) 

121 analytics.send_event(event) 

122 else: 

123 logger.warning("i18n.set_language POST without language") 

124 return None 

125 

126 

127class RecaptchaEnabled(MiddlewareMixin): 

128 """Middleware configures the request with required reCAPTCHA settings.""" 

129 

130 def process_request(self, request): 

131 if settings.RECAPTCHA_ENABLED: 131 ↛ 132line 131 didn't jump to line 132 because the condition on line 131 was never true

132 request.recaptcha = { 

133 "data_field": recaptcha.DATA_FIELD, 

134 "script_api": settings.RECAPTCHA_API_KEY_URL, 

135 "site_key": settings.RECAPTCHA_SITE_KEY, 

136 } 

137 return None 

138 

139 

140class IndexOrAgencyIndexOrigin(MiddlewareMixin): 

141 """Middleware sets the session.origin to either the index or agency index route, depending on agency config.""" 

142 

143 def process_request(self, request): 

144 if session.active_agency(request): 

145 session.update(request, origin=session.agency(request).index_url) 

146 else: 

147 session.update(request, origin=reverse(routes.INDEX)) 

148 return None 

149 

150 

151index_or_agencyindex_origin_decorator = decorator_from_middleware(IndexOrAgencyIndexOrigin)