diff --git a/src/registrar/admin.py b/src/registrar/admin.py
index 15f1ccb79..8718da9ba 100644
--- a/src/registrar/admin.py
+++ b/src/registrar/admin.py
@@ -9,6 +9,7 @@ from django.conf import settings
from django.shortcuts import redirect
from django_fsm import get_available_FIELD_transitions, FSMField
from registrar.models.domain_information import DomainInformation
+from registrar.models.domain_invitation import DomainInvitation
from registrar.models.user_portfolio_permission import UserPortfolioPermission
from registrar.models.utility.portfolio_helper import UserPortfolioPermissionChoices, UserPortfolioRoleChoices
from waffle.decorators import flag_is_active
@@ -1564,7 +1565,7 @@ class DomainInformationAdmin(ListHeaderAdmin, ImportExportModelAdmin):
modified_fieldsets = []
for name, data in fieldsets:
fields = data.get("fields", [])
- fields = tuple(field for field in fields if field not in DomainInformationAdmin.superuser_only_fields)
+ fields = [field for field in fields if field not in DomainInformationAdmin.superuser_only_fields]
modified_fieldsets.append((name, {**data, "fields": fields}))
return modified_fieldsets
return fieldsets
@@ -2299,10 +2300,58 @@ class DomainInformationInline(admin.StackedInline):
template = "django/admin/includes/domain_info_inline_stacked.html"
model = models.DomainInformation
- fieldsets = DomainInformationAdmin.fieldsets
- readonly_fields = DomainInformationAdmin.readonly_fields
- analyst_readonly_fields = DomainInformationAdmin.analyst_readonly_fields
- autocomplete_fields = DomainInformationAdmin.autocomplete_fields
+ fieldsets = copy.deepcopy(list(DomainInformationAdmin.fieldsets))
+ analyst_readonly_fields = copy.deepcopy(DomainInformationAdmin.analyst_readonly_fields)
+ autocomplete_fields = copy.deepcopy(DomainInformationAdmin.autocomplete_fields)
+
+ def get_domain_managers(self, obj):
+ user_domain_roles = UserDomainRole.objects.filter(domain=obj.domain)
+ user_ids = user_domain_roles.values_list("user_id", flat=True)
+ domain_managers = User.objects.filter(id__in=user_ids)
+ return domain_managers
+
+ def get_domain_invitations(self, obj):
+ domain_invitations = DomainInvitation.objects.filter(
+ domain=obj.domain, status=DomainInvitation.DomainInvitationStatus.INVITED
+ )
+ return domain_invitations
+
+ def domain_managers(self, obj):
+ """Get domain managers for the domain, unpack and return an HTML block."""
+ domain_managers = self.get_domain_managers(obj)
+ if not domain_managers:
+ return "No domain managers found."
+
+ domain_manager_details = "
diff --git a/src/registrar/tests/test_admin_domain.py b/src/registrar/tests/test_admin_domain.py
index 49f095a25..a9b94781f 100644
--- a/src/registrar/tests/test_admin_domain.py
+++ b/src/registrar/tests/test_admin_domain.py
@@ -167,12 +167,6 @@ class TestDomainAdminAsStaff(MockEppLib):
expected_organization_name = "MonkeySeeMonkeyDo"
self.assertContains(response, expected_organization_name)
- # clean up this test's data
- domain.delete()
- domain_information.delete()
- _domain_request.delete()
- _creator.delete()
-
@less_console_noise_decorator
def test_deletion_is_successful(self):
"""
@@ -227,9 +221,6 @@ class TestDomainAdminAsStaff(MockEppLib):
self.assertEqual(domain.state, Domain.State.DELETED)
- # clean up data within this test
- domain.delete()
-
@less_console_noise_decorator
def test_deletion_ready_fsm_failure(self):
"""
@@ -269,9 +260,6 @@ class TestDomainAdminAsStaff(MockEppLib):
self.assertEqual(domain.state, Domain.State.READY)
- # delete data created in this test
- domain.delete()
-
@less_console_noise_decorator
def test_analyst_deletes_domain_idempotent(self):
"""
@@ -330,8 +318,130 @@ class TestDomainAdminAsStaff(MockEppLib):
)
self.assertEqual(domain.state, Domain.State.DELETED)
- # delete data created in this test
- domain.delete()
+
+class TestDomainInformationInline(MockEppLib):
+ """Test DomainAdmin class, specifically the DomainInformationInline class, as staff user.
+
+ Notes:
+ all tests share staffuser; do not change staffuser model in tests
+ tests have available staffuser, client, and admin
+ """
+
+ @classmethod
+ def setUpClass(cls):
+ super().setUpClass()
+ cls.staffuser = create_user()
+ cls.site = AdminSite()
+ cls.admin = DomainAdmin(model=Domain, admin_site=cls.site)
+ cls.factory = RequestFactory()
+
+ def setUp(self):
+ self.client = Client(HTTP_HOST="localhost:8080")
+ self.client.force_login(self.staffuser)
+ super().setUp()
+
+ def tearDown(self):
+ super().tearDown()
+ Host.objects.all().delete()
+ UserDomainRole.objects.all().delete()
+ Domain.objects.all().delete()
+ DomainInformation.objects.all().delete()
+ DomainRequest.objects.all().delete()
+
+ @classmethod
+ def tearDownClass(cls):
+ User.objects.all().delete()
+ super().tearDownClass()
+
+ @less_console_noise_decorator
+ def test_domain_managers_display(self):
+ """Tests the custom domain managers field"""
+ admin_user_1 = User.objects.create(
+ username="testuser1",
+ first_name="Gerald",
+ last_name="Meoward",
+ email="meoward@gov.gov",
+ )
+
+ domain_request = completed_domain_request(
+ status=DomainRequest.DomainRequestStatus.IN_REVIEW, user=self.staffuser, name="fake.gov"
+ )
+ domain_request.approve()
+ _domain_info = DomainInformation.objects.filter(domain=domain_request.approved_domain).get()
+ domain = Domain.objects.filter(domain_info=_domain_info).get()
+
+ UserDomainRole.objects.get_or_create(user=admin_user_1, domain=domain, role=UserDomainRole.Roles.MANAGER)
+
+ admin_user_2 = User.objects.create(
+ username="testuser2",
+ first_name="Arnold",
+ last_name="Poopy",
+ email="poopy@gov.gov",
+ )
+
+ UserDomainRole.objects.get_or_create(user=admin_user_2, domain=domain, role=UserDomainRole.Roles.MANAGER)
+
+ # Get the first inline (DomainInformationInline)
+ inline_instance = self.admin.inlines[0](self.admin.model, self.admin.admin_site)
+
+ # Call the domain_managers method
+ domain_managers = inline_instance.domain_managers(domain.domain_info)
+
+ self.assertIn(
+ f'
testuser1',
+ domain_managers,
+ )
+ self.assertIn("Gerald Meoward", domain_managers)
+ self.assertIn("meoward@gov.gov", domain_managers)
+ self.assertIn(f'
testuser2', domain_managers)
+ self.assertIn("Arnold Poopy", domain_managers)
+ self.assertIn("poopy@gov.gov", domain_managers)
+
+ @less_console_noise_decorator
+ def test_invited_domain_managers_display(self):
+ """Tests the custom invited domain managers field"""
+ admin_user_1 = User.objects.create(
+ username="testuser1",
+ first_name="Gerald",
+ last_name="Meoward",
+ email="meoward@gov.gov",
+ )
+
+ domain_request = completed_domain_request(
+ status=DomainRequest.DomainRequestStatus.IN_REVIEW, user=self.staffuser, name="fake.gov"
+ )
+ domain_request.approve()
+ _domain_info = DomainInformation.objects.filter(domain=domain_request.approved_domain).get()
+ domain = Domain.objects.filter(domain_info=_domain_info).get()
+
+ # domain, _ = Domain.objects.get_or_create(name="fake.gov", state=Domain.State.READY)
+ UserDomainRole.objects.get_or_create(user=admin_user_1, domain=domain, role=UserDomainRole.Roles.MANAGER)
+
+ admin_user_2 = User.objects.create(
+ username="testuser2",
+ first_name="Arnold",
+ last_name="Poopy",
+ email="poopy@gov.gov",
+ )
+
+ UserDomainRole.objects.get_or_create(user=admin_user_2, domain=domain, role=UserDomainRole.Roles.MANAGER)
+
+ # Get the first inline (DomainInformationInline)
+ inline_instance = self.admin.inlines[0](self.admin.model, self.admin.admin_site)
+
+ # Call the domain_managers method
+ domain_managers = inline_instance.domain_managers(domain.domain_info)
+ # domain_managers = self.admin.get_inlinesdomain_managers(self.domain)
+
+ self.assertIn(
+ f'
testuser1',
+ domain_managers,
+ )
+ self.assertIn("Gerald Meoward", domain_managers)
+ self.assertIn("meoward@gov.gov", domain_managers)
+ self.assertIn(f'
testuser2', domain_managers)
+ self.assertIn("Arnold Poopy", domain_managers)
+ self.assertIn("poopy@gov.gov", domain_managers)
class TestDomainAdminWithClient(TestCase):
@@ -415,17 +525,6 @@ class TestDomainAdminWithClient(TestCase):
self.assertContains(response, domain.name)
# Check that the fields have the right values.
- # == Check for the creator == #
-
- # Check for the right title, email, and phone number in the response.
- # We only need to check for the end tag
- # (Otherwise this test will fail if we change classes, etc)
- self.assertContains(response, "Treat inspector")
- self.assertContains(response, "meoward.jones@igorville.gov")
- self.assertContains(response, "(555) 123 12345")
-
- # Check for the field itself
- self.assertContains(response, "Meoward Jones")
# == Check for the senior_official == #
self.assertContains(response, "testy@town.com")
@@ -435,11 +534,6 @@ class TestDomainAdminWithClient(TestCase):
# Includes things like readonly fields
self.assertContains(response, "Testy Tester")
- # == Test the other_employees field == #
- self.assertContains(response, "testy2@town.com")
- self.assertContains(response, "Another Tester")
- self.assertContains(response, "(555) 555 5557")
-
# Test for the copy link
self.assertContains(response, "button--clipboard")