fixed some fields that should have been readonly in Domains and Domain Requests

This commit is contained in:
David Kennedy 2025-03-09 19:21:09 -04:00
parent 6702dca37d
commit bb913a9372
No known key found for this signature in database
GPG key ID: 6528A5386E66B96B
2 changed files with 136 additions and 16 deletions

View file

@ -411,17 +411,6 @@ class DomainInformationAdminForm(forms.ModelForm):
class DomainInformationInlineForm(forms.ModelForm): class DomainInformationInlineForm(forms.ModelForm):
"""This form utilizes the custom widget for its class's ManyToMany UIs.""" """This form utilizes the custom widget for its class's ManyToMany UIs."""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# for OMB analysts, limit portfolio dropdown to FEB portfolios
user = self.request.user if hasattr(self, 'request') else None
if user and user.groups.filter(name="omb_analysts_group").exists():
self.fields["portfolio"].queryset = models.Portfolio.objects.filter(
Q(organization_type=DomainRequest.OrganizationChoices.FEDERAL) &
Q(federal_agency__federal_type=BranchChoices.EXECUTIVE)
)
class Meta: class Meta:
model = models.DomainInformation model = models.DomainInformation
@ -2343,6 +2332,47 @@ class DomainInformationAdmin(ListHeaderAdmin, ImportExportRegistrarModelAdmin):
"is_policy_acknowledged", "is_policy_acknowledged",
] ]
# Read only that we'll leverage for OMB Analysts
omb_analyst_readonly_fields = [
"federal_agency",
"creator",
"about_your_organization",
"anything_else",
"cisa_representative_first_name",
"cisa_representative_last_name",
"cisa_representative_email",
"domain_request",
"notes",
"senior_official",
"organization_type",
"organization_name",
"state_territory",
"address_line1",
"address_line2",
"city",
"zipcode",
"urbanization",
"portfolio_organization_type",
"portfolio_federal_type",
"portfolio_organization_name",
"portfolio_federal_agency",
"portfolio_state_territory",
"portfolio_address_line1",
"portfolio_address_line2",
"portfolio_city",
"portfolio_zipcode",
"portfolio_urbanization",
"organization_type",
"federal_type",
"federal_agency",
"tribe_name",
"federally_recognized_tribe",
"state_recognized_tribe",
"about_your_organization",
"portfolio",
"sub_organization",
]
# For each filter_horizontal, init in admin js initFilterHorizontalWidget # For each filter_horizontal, init in admin js initFilterHorizontalWidget
# to activate the edit/delete/view buttons # to activate the edit/delete/view buttons
filter_horizontal = ("other_contacts",) filter_horizontal = ("other_contacts",)
@ -2371,6 +2401,10 @@ class DomainInformationAdmin(ListHeaderAdmin, ImportExportRegistrarModelAdmin):
if request.user.has_perm("registrar.full_access_permission"): if request.user.has_perm("registrar.full_access_permission"):
return readonly_fields return readonly_fields
# Return restrictive Read-only fields for OMB analysts
if request.user.groups.filter(name="omb_analysts_group").exists():
readonly_fields.extend([field for field in self.omb_analyst_readonly_fields])
return readonly_fields
# Return restrictive Read-only fields for analysts and # Return restrictive Read-only fields for analysts and
# users who might not belong to groups # users who might not belong to groups
readonly_fields.extend([field for field in self.analyst_readonly_fields]) readonly_fields.extend([field for field in self.analyst_readonly_fields])
@ -2992,6 +3026,10 @@ class DomainRequestAdmin(ListHeaderAdmin, ImportExportRegistrarModelAdmin):
"action_needed_reason", "action_needed_reason",
"action_needed_reason_email", "action_needed_reason_email",
"portfolio", "portfolio",
"sub_organization",
"requested_suborganization",
"suborganization_city",
"suborganization_state_territory",
] ]
autocomplete_fields = [ autocomplete_fields = [
@ -3619,6 +3657,7 @@ class DomainInformationInline(admin.StackedInline):
fieldsets = copy.deepcopy(list(DomainInformationAdmin.fieldsets)) fieldsets = copy.deepcopy(list(DomainInformationAdmin.fieldsets))
readonly_fields = copy.deepcopy(DomainInformationAdmin.readonly_fields) readonly_fields = copy.deepcopy(DomainInformationAdmin.readonly_fields)
analyst_readonly_fields = copy.deepcopy(DomainInformationAdmin.analyst_readonly_fields) analyst_readonly_fields = copy.deepcopy(DomainInformationAdmin.analyst_readonly_fields)
omb_analyst_readonly_fields = copy.deepcopy(DomainInformationAdmin.omb_analyst_readonly_fields)
autocomplete_fields = copy.deepcopy(DomainInformationAdmin.autocomplete_fields) autocomplete_fields = copy.deepcopy(DomainInformationAdmin.autocomplete_fields)
def get_domain_managers(self, obj): def get_domain_managers(self, obj):

View file

@ -51,6 +51,7 @@ class TestDomainAdminAsStaff(MockEppLib):
@classmethod @classmethod
def setUpClass(self): def setUpClass(self):
super().setUpClass() super().setUpClass()
self.superuser = create_superuser()
self.staffuser = create_user() self.staffuser = create_user()
self.omb_analyst = create_omb_analyst_user() self.omb_analyst = create_omb_analyst_user()
self.site = AdminSite() self.site = AdminSite()
@ -127,13 +128,93 @@ class TestDomainAdminAsStaff(MockEppLib):
self.assertContains(response, "Save") self.assertContains(response, "Save")
self.assertNotContains(response, ">Delete<") self.assertNotContains(response, ">Delete<")
# test whether fields are readonly or editable # test whether fields are readonly or editable
self.assertNotContains(response, "id_domain_info-0-portfolio")
self.assertNotContains(response, "id_domain_info-0-sub_organization")
self.assertNotContains(response, "id_domain_info-0-creator")
self.assertNotContains(response, "id_domain_info-0-federal_agency")
self.assertNotContains(response, "id_domain_info-0-about_your_organization")
self.assertNotContains(response, "id_domain_info-0-anything_else")
self.assertNotContains(response, "id_domain_info-0-cisa_representative_first_name")
self.assertNotContains(response, "id_domain_info-0-cisa_representative_last_name")
self.assertNotContains(response, "id_domain_info-0-cisa_representative_email")
self.assertNotContains(response, "id_domain_info-0-domain_request")
self.assertNotContains(response, "id_domain_info-0-notes")
self.assertNotContains(response, "id_domain_info-0-senior_official")
self.assertNotContains(response, "id_domain_info-0-organization_type")
self.assertNotContains(response, "id_domain_info-0-state_territory")
self.assertNotContains(response, "id_domain_info-0-address_line1")
self.assertNotContains(response, "id_domain_info-0-address_line2")
self.assertNotContains(response, "id_domain_info-0-city")
self.assertNotContains(response, "id_domain_info-0-zipcode")
self.assertNotContains(response, "id_domain_info-0-urbanization")
self.assertNotContains(response, "id_domain_info-0-portfolio_organization_type")
self.assertNotContains(response, "id_domain_info-0-portfolio_federal_type")
self.assertNotContains(response, "id_domain_info-0-portfolio_organization_name")
self.assertNotContains(response, "id_domain_info-0-portfolio_federal_agency")
self.assertNotContains(response, "id_domain_info-0-portfolio_state_territory")
self.assertNotContains(response, "id_domain_info-0-portfolio_address_line1")
self.assertNotContains(response, "id_domain_info-0-portfolio_address_line2")
self.assertNotContains(response, "id_domain_info-0-portfolio_city")
self.assertNotContains(response, "id_domain_info-0-portfolio_zipcode")
self.assertNotContains(response, "id_domain_info-0-portfolio_urbanization")
self.assertNotContains(response, "id_domain_info-0-organization_type")
self.assertNotContains(response, "id_domain_info-0-federal_type")
self.assertNotContains(response, "id_domain_info-0-federal_agency")
self.assertNotContains(response, "id_domain_info-0-tribe_name")
self.assertNotContains(response, "id_domain_info-0-federally_recognized_tribe")
self.assertNotContains(response, "id_domain_info-0-state_recognized_tribe")
self.assertNotContains(response, "id_domain_info-0-about_your_organization")
self.assertNotContains(response, "id_domain_info-0-portfolio")
self.assertNotContains(response, "id_domain_info-0-sub_organization")
@less_console_noise_decorator
def test_superuser_change(self):
"""Ensure super user can view/edit all domains."""
self.client.force_login(self.superuser)
response = self.client.get(reverse("admin:registrar_domain_change", args=[self.nonfebdomain.id]))
self.assertEqual(response.status_code, 200)
response = self.client.get(reverse("admin:registrar_domain_change", args=[self.febdomain.id]))
self.assertEqual(response.status_code, 200)
self.assertContains(response, self.febdomain.name)
# test portfolio dropdown
self.assertContains(response, self.portfolio.organization_name)
# test buttons
self.assertContains(response, "Manage domain")
self.assertContains(response, "Get registry status")
self.assertContains(response, "Extend expiration date")
self.assertContains(response, "Remove from registry")
self.assertContains(response, "Place hold")
self.assertContains(response, "Save")
self.assertContains(response, ">Delete<")
# test whether fields are readonly or editable
self.assertContains(response, "id_domain_info-0-portfolio")
self.assertContains(response, "id_domain_info-0-sub_organization")
self.assertContains(response, "id_domain_info-0-creator")
self.assertContains(response, "id_domain_info-0-federal_agency")
self.assertContains(response, "id_domain_info-0-about_your_organization")
self.assertContains(response, "id_domain_info-0-anything_else")
self.assertContains(response, "id_domain_info-0-cisa_representative_first_name")
self.assertContains(response, "id_domain_info-0-cisa_representative_last_name")
self.assertContains(response, "id_domain_info-0-cisa_representative_email")
self.assertContains(response, "id_domain_info-0-domain_request")
self.assertContains(response, "id_domain_info-0-notes")
self.assertContains(response, "id_domain_info-0-senior_official")
self.assertContains(response, "id_domain_info-0-organization_type")
self.assertContains(response, "id_domain_info-0-state_territory")
self.assertContains(response, "id_domain_info-0-address_line1")
self.assertContains(response, "id_domain_info-0-address_line2")
self.assertContains(response, "id_domain_info-0-city")
self.assertContains(response, "id_domain_info-0-zipcode")
self.assertContains(response, "id_domain_info-0-urbanization")
self.assertContains(response, "id_domain_info-0-organization_type")
self.assertContains(response, "id_domain_info-0-federal_type")
self.assertContains(response, "id_domain_info-0-federal_agency")
self.assertContains(response, "id_domain_info-0-tribe_name")
self.assertContains(response, "id_domain_info-0-federally_recognized_tribe")
self.assertContains(response, "id_domain_info-0-state_recognized_tribe")
self.assertContains(response, "id_domain_info-0-about_your_organization")
self.assertContains(response, "id_domain_info-0-portfolio") self.assertContains(response, "id_domain_info-0-portfolio")
self.assertContains(response, "id_domain_info-0-sub_organization") self.assertContains(response, "id_domain_info-0-sub_organization")
self.assertNotContains(response, "id_domain_info-0-creator")
# self.assertNotContains(response, "id_email")
# self.assertContains(response, "closelink")
# self.assertNotContains(response, "Save")
# self.assertNotContains(response, "Delete")
@less_console_noise_decorator @less_console_noise_decorator
def test_staff_can_see_cisa_region_federal(self): def test_staff_can_see_cisa_region_federal(self):