From 08efc6629ee14c30e313d8cfbf3b913d4e3f1b45 Mon Sep 17 00:00:00 2001 From: David Kennedy Date: Mon, 6 Jan 2025 16:32:28 -0500 Subject: [PATCH] in django admin, new domain invitations are auto retrieved when user exists --- src/registrar/admin.py | 20 +++++++++ src/registrar/tests/test_admin.py | 67 ++++++++++++++++++++++++++----- 2 files changed, 78 insertions(+), 9 deletions(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index fba675bf7..8c16c8bbe 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -1434,6 +1434,26 @@ class DomainInvitationAdmin(ListHeaderAdmin): # Get the filtered values return super().changelist_view(request, extra_context=extra_context) + def save_model(self, request, obj, form, change): + """ + Override the save_model method. + + On creation of a new domain invitation, attempt to retrieve the invitation, + which will be successful if a user exists for that email; otherwise, will + raise a RuntimeError, and in this case can continue to create the invitation. + """ + # NOTE: is a future ticket accounting for a 'not member of this org' scenario + # to mirror the logic in DomainAddUser view? + if not change: # Domain Invitation creation + try: + User.objects.get(email=obj.email) + obj.retrieve() + except User.DoesNotExist: + # Proceed with invitation as new as exception indicates user does not exist + pass + # Call the parent save method to save the object + super().save_model(request, obj, form, change) + class PortfolioInvitationAdmin(ListHeaderAdmin): """Custom portfolio invitation admin class.""" diff --git a/src/registrar/tests/test_admin.py b/src/registrar/tests/test_admin.py index dceb3a79e..c2a8b5e64 100644 --- a/src/registrar/tests/test_admin.py +++ b/src/registrar/tests/test_admin.py @@ -131,13 +131,11 @@ class TestDomainInvitationAdmin(TestCase): tests have available superuser, client, and admin """ - @classmethod - def setUpClass(cls): - cls.factory = RequestFactory() - cls.admin = ListHeaderAdmin(model=DomainInvitationAdmin, admin_site=AdminSite()) - cls.superuser = create_superuser() - def setUp(self): + self.factory = RequestFactory() + self.admin = ListHeaderAdmin(model=DomainInvitationAdmin, admin_site=AdminSite()) + self.superuser = create_superuser() + self.domain = Domain.objects.create(name="example.com") """Create a client object""" self.client = Client(HTTP_HOST="localhost:8080") @@ -145,9 +143,6 @@ class TestDomainInvitationAdmin(TestCase): """Delete all DomainInvitation objects""" DomainInvitation.objects.all().delete() Contact.objects.all().delete() - - @classmethod - def tearDownClass(self): User.objects.all().delete() @less_console_noise_decorator @@ -168,6 +163,7 @@ class TestDomainInvitationAdmin(TestCase): ) self.assertContains(response, "Show more") + @less_console_noise_decorator def test_get_filters(self): """Ensures that our filters are displaying correctly""" with less_console_noise(): @@ -192,6 +188,59 @@ class TestDomainInvitationAdmin(TestCase): self.assertContains(response, invited_html, count=1) self.assertContains(response, retrieved_html, count=1) + @less_console_noise_decorator + def test_save_model_user_exists(self): + """Test saving a domain invitation when the user exists. + + Should attempt to retrieve the domain invitation.""" + # Create a user with the same email + User.objects.create_user(email="test@example.com", password="password", username="username") + + # Create a domain invitation instance + invitation = DomainInvitation(email="test@example.com", domain=self.domain) + + admin_instance = DomainInvitationAdmin(DomainInvitation, admin_site=None) + + # Create a request object + request = self.factory.post("/admin/registrar/DomainInvitation/add/") + request.user = self.superuser + + # Patch the retrieve method + with patch.object(DomainInvitation, "retrieve") as mock_retrieve: + admin_instance.save_model(request, invitation, form=None, change=False) + + # Assert retrieve was called + mock_retrieve.assert_called_once() + + # Assert the invitation was saved + self.assertEqual(DomainInvitation.objects.count(), 1) + self.assertEqual(DomainInvitation.objects.first().email, "test@example.com") + + @less_console_noise_decorator + def test_save_model_user_does_not_exist(self): + """Test saving a domain invitation when the user does not exist. + + Should not attempt to retrieve the domain invitation.""" + # Create a domain invitation instance + invitation = DomainInvitation(email="nonexistent@example.com", domain=self.domain) + + admin_instance = DomainInvitationAdmin(DomainInvitation, admin_site=None) + + # Create a request object + request = self.factory.post("/admin/registrar/DomainInvitation/add/") + request.user = self.superuser + + # Patch the retrieve method to ensure it is not called + with patch.object(DomainInvitation, "retrieve") as mock_retrieve: + admin_instance.save_model(request, invitation, form=None, change=False) + + # Assert retrieve was not called + mock_retrieve.assert_not_called() + + # Assert the invitation was saved + self.assertEqual(DomainInvitation.objects.count(), 1) + self.assertEqual(DomainInvitation.objects.first().email, "nonexistent@example.com") + class TestUserPortfolioPermissionAdmin(TestCase): """Tests for the PortfolioInivtationAdmin class"""