Coverage for benefits/core/middleware.py: 96%
91 statements
« prev ^ index » next coverage.py v7.6.9, created at 2024-12-19 00:56 +0000
« prev ^ index » next coverage.py v7.6.9, created at 2024-12-19 00:56 +0000
1"""
2The core application: middleware definitions for request/response cycle.
3"""
5import logging
7from django.conf import settings
8from django.http import HttpResponse
9from django.shortcuts import redirect
10from django.template.response import TemplateResponse
11from django.urls import reverse
12from django.utils.decorators import decorator_from_middleware
13from django.utils.deprecation import MiddlewareMixin
14from django.views import i18n
16from benefits.routes import routes
17from . import analytics, recaptcha, session
20logger = logging.getLogger(__name__)
22HEALTHCHECK_PATH = "/healthcheck"
23TEMPLATE_USER_ERROR = "200-user-error.html"
26def user_error(request):
27 return TemplateResponse(request, TEMPLATE_USER_ERROR)
30class AgencySessionRequired(MiddlewareMixin):
31 """Middleware raises an exception for sessions lacking an agency configuration."""
33 def process_request(self, request):
34 if session.active_agency(request):
35 logger.debug("Session configured with agency")
36 return None
37 else:
38 logger.debug("Session not configured with agency")
39 return user_error(request)
42class EligibleSessionRequired(MiddlewareMixin):
43 """Middleware raises an exception for sessions lacking confirmed eligibility."""
45 def process_request(self, request):
46 if session.eligible(request):
47 logger.debug("Session has confirmed eligibility")
48 return None
49 else:
50 logger.debug("Session has no confirmed eligibility")
51 return user_error(request)
54class DebugSession(MiddlewareMixin):
55 """Middleware to configure debug context in the request session."""
57 def process_request(self, request):
58 session.update(request, debug=settings.DEBUG)
59 return None
62class Healthcheck:
63 """Middleware intercepts and accepts /healthcheck requests."""
65 def __init__(self, get_response):
66 self.get_response = get_response
68 def __call__(self, request):
69 if request.path == HEALTHCHECK_PATH:
70 return HttpResponse("Healthy", content_type="text/plain")
71 return self.get_response(request)
74class HealthcheckUserAgents(MiddlewareMixin):
75 """Middleware to return healthcheck for user agents specified in HEALTHCHECK_USER_AGENTS."""
77 def process_request(self, request):
78 if hasattr(request, "META"): 78 ↛ 83line 78 didn't jump to line 83 because the condition on line 78 was always true
79 user_agent = request.META.get("HTTP_USER_AGENT", "")
80 if user_agent in settings.HEALTHCHECK_USER_AGENTS:
81 return HttpResponse("Healthy", content_type="text/plain")
83 return self.get_response(request)
86class FlowSessionRequired(MiddlewareMixin):
87 """Middleware raises an exception for sessions lacking a configured enrollment flow."""
89 def process_request(self, request):
90 if session.flow(request):
91 logger.debug("Session configured with enrollment flow")
92 return None
93 else:
94 logger.debug("Session not configured with enrollment flow")
95 return user_error(request)
98class ViewedPageEvent(MiddlewareMixin):
99 """Middleware sends an analytics event for page views."""
101 def process_response(self, request, response):
102 event = analytics.ViewedPageEvent(request)
103 try:
104 analytics.send_event(event)
105 except Exception:
106 logger.warning(f"Failed to send event: {event}")
107 finally:
108 return response
111pageview_decorator = decorator_from_middleware(ViewedPageEvent)
114class ChangedLanguageEvent(MiddlewareMixin):
115 """Middleware hooks into django.views.i18n.set_language to send an analytics event."""
117 def process_view(self, request, view_func, view_args, view_kwargs):
118 if view_func == i18n.set_language:
119 new_lang = request.POST.get("language")
120 if new_lang:
121 event = analytics.ChangedLanguageEvent(request, new_lang)
122 analytics.send_event(event)
123 else:
124 logger.warning("i18n.set_language POST without language")
125 return None
128class LoginRequired(MiddlewareMixin):
129 """Middleware that checks whether a user is logged in."""
131 def process_view(self, request, view_func, view_args, view_kwargs):
132 # only require login if flow uses claims verification
133 flow = session.flow(request)
134 if not flow or not flow.uses_claims_verification or session.logged_in(request):
135 # pass through
136 return None
138 return redirect(routes.OAUTH_LOGIN)
141class RecaptchaEnabled(MiddlewareMixin):
142 """Middleware configures the request with required reCAPTCHA settings."""
144 def process_request(self, request):
145 if settings.RECAPTCHA_ENABLED: 145 ↛ 146line 145 didn't jump to line 146
146 request.recaptcha = {
147 "data_field": recaptcha.DATA_FIELD,
148 "script_api": settings.RECAPTCHA_API_KEY_URL,
149 "site_key": settings.RECAPTCHA_SITE_KEY,
150 }
151 return None
154class IndexOrAgencyIndexOrigin(MiddlewareMixin):
155 """Middleware sets the session.origin to either the index or agency index route, depending on agency config."""
157 def process_request(self, request):
158 if session.active_agency(request):
159 session.update(request, origin=session.agency(request).index_url)
160 else:
161 session.update(request, origin=reverse(routes.INDEX))
162 return None
165index_or_agencyindex_origin_decorator = decorator_from_middleware(IndexOrAgencyIndexOrigin)