Coverage for benefits/urls.py: 72%

51 statements  

« prev     ^ index     » next       coverage.py v7.16.2, created at 2026-10-08 19:50 +0000

1""" 

2benefits URL Configuration 

3 

4The `urlpatterns` list routes URLs to views. For more information please see: 

5 https://docs.djangoproject.com/en/stable/topics/http/urls/ 

6""" 

7 

8import logging 

9import re 

10 

11from django.conf import settings 

12from django.contrib import admin 

13from django.core.exceptions import BadRequest, PermissionDenied 

14from django.http import Http404, HttpResponse 

15from django.urls import include, path, re_path 

16from django.views.static import serve 

17 

18from benefits.core.admin.views import ( 

19 BenefitsPasswordResetConfirmView, 

20 BenefitsPasswordResetDoneView, 

21 BenefitsPasswordResetView, 

22) 

23from benefits.views import BadRequestView, ForbiddenView, NotFoundView, server_error_handler 

24 

25logger = logging.getLogger(__name__) 

26 

27handler400 = BadRequestView.as_view() 

28handler403 = ForbiddenView.as_view() 

29handler404 = NotFoundView.as_view() 

30handler500 = server_error_handler 

31 

32urlpatterns = [ 

33 path("", include("benefits.core.urls")), 

34 path("eligibility/", include("benefits.eligibility.urls")), 

35 path("enrollment/", include("benefits.enrollment.urls")), 

36 path("i18n/", include("django.conf.urls.i18n")), 

37 path("oauth/", include("benefits.oauth.urls")), 

38 path("in_person/", include("benefits.in_person.urls")), 

39 path("init/", include("benefits.enrollment_init.urls")), 

40 path("littlepay/", include("benefits.enrollment_littlepay.urls")), 

41 path("switchio/", include("benefits.enrollment_switchio.urls")), 

42] 

43 

44# TODO: move this URL pattern back into the main block above 

45# once MMW is going live 

46if settings.RUNTIME_ENVIRONMENT() != settings.RUNTIME_ENVS.PROD: 46 ↛ 49line 46 didn't jump to line 49 because the condition on line 46 was always true

47 urlpatterns.append(path("metro-mobility-wallet/", include("benefits.metro_mobility_wallet.urls"))) 

48 

49if settings.RUNTIME_ENVIRONMENT() == settings.RUNTIME_ENVS.LOCAL: 49 ↛ 88line 49 didn't jump to line 88 because the condition on line 49 was always true

50 # serve user-uploaded media files 

51 # 

52 # the helper function `django.conf.urls.static.static` mentioned in 

53 # https://docs.djangoproject.com/en/stable/howto/static-files/#serving-files-uploaded-by-a-user-during-development 

54 # only works when settings.DEBUG = True, so here we add the URL pattern ourselves so it works regardless of DEBUG. 

55 prefix = settings.MEDIA_URL 

56 urlpatterns.extend( 

57 [re_path(r"^%s(?P<path>.*)$" % re.escape(prefix.lstrip("/")), serve, {"document_root": settings.MEDIA_ROOT})] 

58 ) 

59 

60 # based on 

61 # https://docs.sentry.io/platforms/python/guides/django/#verify 

62 def trigger_400(request): 

63 raise BadRequest("Test 400") 

64 

65 def trigger_403(request): 

66 raise PermissionDenied("Test 403") 

67 

68 def trigger_404(request): 

69 raise Http404("Test 404") 

70 

71 def trigger_500(request): 

72 raise Exception("Test 500") 

73 

74 def trigger_csrf(request): 

75 if request.method == "POST": 

76 return HttpResponse("Should not reach here") 

77 return HttpResponse( 

78 "<html><body><form method='post' action='/testcsrf/'>" 

79 "<button type='submit'>Submit CSRF failure</button></form></body></html>" 

80 ) 

81 

82 urlpatterns.append(path("test400/", trigger_400)) 

83 urlpatterns.append(path("test403/", trigger_403)) 

84 urlpatterns.append(path("test404/", trigger_404)) 

85 urlpatterns.append(path("test500/", trigger_500)) 

86 urlpatterns.append(path("testcsrf/", trigger_csrf)) 

87 

88if settings.DEBUG_TOOLBAR: 88 ↛ 89line 88 didn't jump to line 89 because the condition on line 88 was never true

89 from debug_toolbar.toolbar import debug_toolbar_urls 

90 

91 urlpatterns.extend(debug_toolbar_urls()) 

92 

93 

94if settings.RUNTIME_ENVIRONMENT() in (settings.RUNTIME_ENVS.LOCAL, settings.RUNTIME_ENVS.DEV): 94 ↛ 106line 94 didn't jump to line 106 because the condition on line 94 was always true

95 # simple route to read a pre-defined "secret" 

96 # this "secret" does not contain sensitive information 

97 # and is only configured in the dev environment for testing/debugging 

98 

99 def test_secret(request): 

100 from benefits.secrets import get_secret_by_name 

101 

102 return HttpResponse(get_secret_by_name("testsecret")) 

103 

104 urlpatterns.append(path("testsecret/", test_secret)) 

105 

106logger.debug("Register admin urls") 

107password_reset_patterns = [ 

108 path( 

109 "admin/password_reset/", 

110 BenefitsPasswordResetView.as_view(extra_context={"site_header": admin.site.site_header}), 

111 name="admin_password_reset", 

112 ), 

113 path( 

114 "admin/password_reset/done/", 

115 BenefitsPasswordResetDoneView.as_view(extra_context={"site_header": admin.site.site_header}), 

116 name="password_reset_done", 

117 ), 

118 path( 

119 "admin/password_reset/<uidb64>/<token>/", 

120 BenefitsPasswordResetConfirmView.as_view(extra_context={"site_header": admin.site.site_header}), 

121 name="password_reset_confirm", 

122 ), 

123] 

124urlpatterns.extend(password_reset_patterns) 

125urlpatterns.append(path("admin/", admin.site.urls)) 

126urlpatterns.append(path("google_sso/", include("django_google_sso.urls", namespace="django_google_sso")))