Coverage for benefits/core/admin/enrollment.py: 90%

98 statements  

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

1from django import forms 

2from django.conf import settings 

3from django.core.exceptions import ValidationError 

4from django.contrib import admin 

5from django.http import HttpRequest 

6 

7from adminsortable2.admin import SortableAdminMixin 

8 

9from benefits.core import models 

10from .users import is_staff_member_or_superuser 

11 

12 

13@admin.register(models.EnrollmentEvent) 

14class EnrollmentEventAdmin(admin.ModelAdmin): 

15 list_display = ("enrollment_datetime", "transit_agency", "enrollment_flow", "enrollment_method", "verified_by") 

16 ordering = ("-enrollment_datetime",) 

17 

18 def has_add_permission(self, request: HttpRequest, obj=None): 

19 if settings.RUNTIME_ENVIRONMENT() == settings.RUNTIME_ENVS.PROD: 

20 return False 

21 elif request.user and is_staff_member_or_superuser(request.user): 21 ↛ 24line 21 didn't jump to line 24 because the condition on line 21 was always true

22 return True 

23 else: 

24 return False 

25 

26 def has_change_permission(self, request: HttpRequest, obj=None): 

27 if settings.RUNTIME_ENVIRONMENT() == settings.RUNTIME_ENVS.PROD: 

28 return False 

29 elif request.user and request.user.is_superuser: 

30 return True 

31 else: 

32 return False 

33 

34 def has_delete_permission(self, request: HttpRequest, obj=None): 

35 if settings.RUNTIME_ENVIRONMENT() == settings.RUNTIME_ENVS.PROD: 35 ↛ 36line 35 didn't jump to line 36 because the condition on line 35 was never true

36 return False 

37 elif request.user and is_staff_member_or_superuser(request.user): 37 ↛ 40line 37 didn't jump to line 40 because the condition on line 37 was always true

38 return True 

39 else: 

40 return False 

41 

42 def has_view_permission(self, request: HttpRequest, obj=None): 

43 if request.user and is_staff_member_or_superuser(request.user): 43 ↛ 46line 43 didn't jump to line 46 because the condition on line 43 was always true

44 return True 

45 else: 

46 return False 

47 

48 

49class EnrollmentFlowForm(forms.ModelForm): 

50 def has_field(self, field_name): 

51 return self.fields.get(field_name) is not None 

52 

53 def get(self, cleaned_data, field_name): 

54 """ 

55 If the field is present on the form, simply get the value from the cleaned_data. 

56 

57 If the field is not present on the form, that means the user doesn't have access to the field, 

58 so get the value from the form's instance of the object. 

59 """ 

60 return cleaned_data.get(field_name) if self.has_field(field_name) else getattr(self.instance, field_name) 

61 

62 def clean(self): 

63 cleaned_data = super().clean() 

64 

65 field_errors = {} 

66 non_field_errors = [] 

67 

68 supports_expiration = cleaned_data.get("supports_expiration") 

69 

70 if supports_expiration: 

71 expiration_days = cleaned_data.get("expiration_days") 

72 expiration_reenrollment_days = cleaned_data.get("expiration_reenrollment_days") 

73 reenrollment_error_template = self.get(cleaned_data, "reenrollment_error_template") 

74 

75 message = "When support_expiration is True, this value must be greater than 0." 

76 if expiration_days is None or expiration_days <= 0: 

77 field_errors.update(expiration_days=ValidationError(message)) 

78 if expiration_reenrollment_days is None or expiration_reenrollment_days <= 0: 

79 field_errors.update(expiration_reenrollment_days=ValidationError(message)) 

80 if not reenrollment_error_template: 

81 message = "Required when supports expiration is True" 

82 field_name = "reenrollment_error_template" 

83 if self.has_field(field_name): 

84 field_errors.update(reenrollment_error_template=ValidationError(f"{message}.")) 

85 else: 

86 non_field_errors.append(ValidationError(f"{message}: {field_name}")) 

87 

88 transit_agency = cleaned_data.get("transit_agency") 

89 

90 if transit_agency: 

91 # these fields might not be on the form, so use helper method to correctly get the value 

92 eligibility_api_url = self.get(cleaned_data, "eligibility_api_url") 

93 eligibility_form_class = self.get(cleaned_data, "eligibility_form_class") 

94 

95 if eligibility_api_url and eligibility_form_class: 

96 message = "Required for Eligibility API verification." 

97 needed = dict( 

98 eligibility_api_auth_header=self.get(cleaned_data, "eligibility_api_auth_header"), 

99 eligibility_api_auth_key_secret_name=self.get(cleaned_data, "eligibility_api_auth_key_secret_name"), 

100 eligibility_api_jwe_cek_enc=self.get(cleaned_data, "eligibility_api_jwe_cek_enc"), 

101 eligibility_api_jwe_encryption_alg=self.get(cleaned_data, "eligibility_api_jwe_encryption_alg"), 

102 eligibility_api_jws_signing_alg=self.get(cleaned_data, "eligibility_api_jws_signing_alg"), 

103 eligibility_api_public_key=self.get(cleaned_data, "eligibility_api_public_key"), 

104 ) 

105 for k, v in needed.items(): 

106 if self.has_field(k) and not v: 106 ↛ 108line 106 didn't jump to line 108 because the condition on line 106 was always true

107 field_errors.update({k: ValidationError(f"{message}.")}) 

108 elif not v: 

109 non_field_errors.append(ValidationError(f"{message}: {k}")) 

110 elif not cleaned_data.get("claims_request"): 

111 message = ( 

112 "Must configure either claims verification or Eligibility API verification before" 

113 + " adding to a transit agency." 

114 ) 

115 non_field_errors.append(ValidationError(message)) 

116 

117 for field_name, validation_error in field_errors.items(): 

118 self.add_error(field_name, validation_error) 

119 for validation_error in non_field_errors: 

120 self.add_error(None, validation_error) 

121 

122 

123@admin.register(models.EnrollmentFlow) 

124class SortableEnrollmentFlowAdmin(SortableAdminMixin, admin.ModelAdmin): 

125 list_display = ("label", "transit_agency", "supported_enrollment_methods") 

126 form = EnrollmentFlowForm 

127 

128 def get_exclude(self, request, obj=None): 

129 fields = [] 

130 

131 if not request.user.is_superuser: 

132 fields.extend( 

133 [ 

134 "eligibility_api_auth_header", 

135 "eligibility_api_auth_key_secret_name", 

136 "eligibility_api_public_key", 

137 "eligibility_api_jwe_cek_enc", 

138 "eligibility_api_jwe_encryption_alg", 

139 "eligibility_api_jws_signing_alg", 

140 ] 

141 ) 

142 

143 return fields or super().get_exclude(request, obj) 

144 

145 def get_readonly_fields(self, request, obj=None): 

146 fields = [] 

147 

148 if not request.user.is_superuser: 

149 fields.extend( 

150 [ 

151 "eligibility_api_url", 

152 "eligibility_form_class", 

153 "selection_label_template_override", 

154 "reenrollment_error_template", 

155 ] 

156 ) 

157 

158 return fields or super().get_readonly_fields(request, obj) 

159 

160 def has_add_permission(self, request: HttpRequest, obj=None): 

161 if settings.RUNTIME_ENVIRONMENT() != settings.RUNTIME_ENVS.PROD: 

162 return True 

163 elif request.user and is_staff_member_or_superuser(request.user): 163 ↛ 166line 163 didn't jump to line 166 because the condition on line 163 was always true

164 return True 

165 else: 

166 return False