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

104 statements  

« prev     ^ index     » next       coverage.py v7.6.12, created at 2025-03-13 23:09 +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 

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

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

19 return False 

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

21 return True 

22 else: 

23 return False 

24 

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

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

27 return False 

28 elif request.user and request.user.is_superuser: 

29 return True 

30 else: 

31 return False 

32 

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

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

35 return False 

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

37 return True 

38 else: 

39 return False 

40 

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

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

43 return True 

44 else: 

45 return False 

46 

47 

48class EnrollmentFlowForm(forms.ModelForm): 

49 def has_field(self, field_name): 

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

51 

52 def get(self, cleaned_data, field_name): 

53 """ 

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

55 

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

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

58 """ 

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

60 

61 def clean(self): 

62 cleaned_data = super().clean() 

63 

64 field_errors = {} 

65 non_field_errors = [] 

66 

67 supports_expiration = cleaned_data.get("supports_expiration") 

68 

69 if supports_expiration: 

70 expiration_days = cleaned_data.get("expiration_days") 

71 expiration_reenrollment_days = cleaned_data.get("expiration_reenrollment_days") 

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

73 

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

75 if expiration_days is None or expiration_days <= 0: 

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

77 if expiration_reenrollment_days is None or expiration_reenrollment_days <= 0: 

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

79 if not reenrollment_error_template: 

80 message = "Required when supports expiration is True" 

81 field_name = "reenrollment_error_template" 

82 if self.has_field(field_name): 

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

84 else: 

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

86 

87 transit_agency = cleaned_data.get("transit_agency") 

88 

89 if transit_agency: 

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

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

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

93 

94 if cleaned_data.get("claims_provider"): 

95 message = "Required for claims verification" 

96 needed = dict( 

97 claims_scope=cleaned_data.get("claims_scope"), 

98 claims_eligibility_claim=cleaned_data.get("claims_eligibility_claim"), 

99 ) 

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

101 if self.has_field(k) and not v: 

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

103 elif not v: 103 ↛ 104line 103 didn't jump to line 104 because the condition on line 103 was never true

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

105 elif eligibility_api_url and eligibility_form_class: 

106 message = "Required for Eligibility API verification." 

107 needed = dict( 

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

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

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

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

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

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

114 ) 

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

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

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

118 elif not v: 

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

120 else: 

121 message = ( 

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

123 + " adding to a transit agency." 

124 ) 

125 non_field_errors.append(ValidationError(message)) 

126 

127 if field_errors: 

128 raise ValidationError(field_errors) 

129 if non_field_errors: 

130 raise ValidationError(non_field_errors) 

131 

132 

133@admin.register(models.EnrollmentFlow) 

134class SortableEnrollmentFlowAdmin(SortableAdminMixin, admin.ModelAdmin): 

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

136 form = EnrollmentFlowForm 

137 

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

139 fields = [] 

140 

141 if not request.user.is_superuser: 

142 fields.extend( 

143 [ 

144 "eligibility_api_auth_header", 

145 "eligibility_api_auth_key_secret_name", 

146 "eligibility_api_public_key", 

147 "eligibility_api_jwe_cek_enc", 

148 "eligibility_api_jwe_encryption_alg", 

149 "eligibility_api_jws_signing_alg", 

150 ] 

151 ) 

152 

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

154 

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

156 fields = [] 

157 

158 if not request.user.is_superuser: 

159 fields.extend( 

160 [ 

161 "eligibility_api_url", 

162 "eligibility_form_class", 

163 "selection_label_template_override", 

164 "eligibility_start_template_override", 

165 "eligibility_unverified_template_override", 

166 "help_template", 

167 "enrollment_index_template_override", 

168 "reenrollment_error_template", 

169 "enrollment_success_template_override", 

170 ] 

171 ) 

172 

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

174 

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

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

177 return True 

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

179 return True 

180 else: 

181 return False