From 888ddda9e982e46e1b23eaa1783f4584bff904bb Mon Sep 17 00:00:00 2001 From: David Kennedy Date: Fri, 1 Sep 2023 17:40:54 -0400 Subject: [PATCH 01/14] implemented add client hold and remove client hold; extended change permission on domain admin to staff; conditionally display buttons based on state; added states to domain to match state diagram --- src/registrar/admin.py | 31 ++++++++++++++++--- src/registrar/models/domain.py | 20 ++++++++++-- .../django/admin/domain_change_form.html | 6 +++- 3 files changed, 49 insertions(+), 8 deletions(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index 4696a15bf..f4b395524 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -164,7 +164,6 @@ class MyHostAdmin(AuditedAdmin): inlines = [HostIPInline] - class DomainAdmin(ListHeaderAdmin): """Custom domain admin class to add extra buttons.""" @@ -175,10 +174,12 @@ class DomainAdmin(ListHeaderAdmin): readonly_fields = ["state"] def response_change(self, request, obj): - ACTION_BUTTON = "_place_client_hold" - if ACTION_BUTTON in request.POST: + PLACE_HOLD = "_place_client_hold" + REMOVE_HOLD = "_remove_client_hold" + if PLACE_HOLD in request.POST: try: obj.place_client_hold() + obj.save() except Exception as err: self.message_user(request, err, messages.ERROR) else: @@ -191,9 +192,31 @@ class DomainAdmin(ListHeaderAdmin): % obj.name, ) return HttpResponseRedirect(".") - + elif REMOVE_HOLD in request.POST: + try: + obj.remove_client_hold() + obj.save() + except Exception as err: + self.message_user(request, err, messages.ERROR) + else: + self.message_user( + request, + ( + "%s is ready. This domain is accessible on the public " + "internet." + ) + % obj.name, + ) + return HttpResponseRedirect(".") return super().response_change(request, obj) + def has_change_permission(self, request, obj=None): + # Fixes a bug wherein users which are only is_staff + # can access 'change' when GET, + # but cannot access this page when it is a request of type POST. + if request.user.is_staff: + return True + return super().has_change_permission(request, obj) class ContactAdmin(ListHeaderAdmin): """Custom contact admin class to add search.""" diff --git a/src/registrar/models/domain.py b/src/registrar/models/domain.py index a7e46f888..2192bd370 100644 --- a/src/registrar/models/domain.py +++ b/src/registrar/models/domain.py @@ -2,7 +2,7 @@ import logging from datetime import date from string import digits -from django_fsm import FSMField # type: ignore +from django_fsm import FSMField, transition # type: ignore from django.db import models @@ -114,6 +114,12 @@ class Domain(TimeStampedModel, DomainHelper): # the state is indeterminate UNKNOWN = "unknown" + # the ready state for a domain object + READY = "ready" + + # when a domain is on hold + ONHOLD="onhold" + class Cache(property): """ Python descriptor to turn class methods into properties. @@ -311,13 +317,21 @@ class Domain(TimeStampedModel, DomainHelper): """Time to renew. Not implemented.""" raise NotImplementedError() + @transition( + field="state", source=[State.READY], target=State.ONHOLD + ) def place_client_hold(self): """This domain should not be active.""" - raise NotImplementedError("This is not implemented yet.") + # This method is changing the state of the domain in registrar + # TODO: implement EPP call + @transition( + field="state", source=[State.ONHOLD], target=State.READY + ) def remove_client_hold(self): """This domain is okay to be active.""" - raise NotImplementedError() + # This method is changing the state of the domain in registrar + # TODO: implement EPP call def __str__(self) -> str: return self.name diff --git a/src/registrar/templates/django/admin/domain_change_form.html b/src/registrar/templates/django/admin/domain_change_form.html index 5fa89f20a..933d7ae25 100644 --- a/src/registrar/templates/django/admin/domain_change_form.html +++ b/src/registrar/templates/django/admin/domain_change_form.html @@ -2,7 +2,11 @@ {% block field_sets %}
- + {% if original.state == original.State.READY %} + + {% elif original.state == original.State.ONHOLD %} + + {% endif %}
{{ block.super }} {% endblock %} \ No newline at end of file From c52ccf8a9acba3b3b35566c9e1cf2f02a764ae31 Mon Sep 17 00:00:00 2001 From: David Kennedy Date: Fri, 1 Sep 2023 17:48:30 -0400 Subject: [PATCH 02/14] fixed formatting for lint --- src/registrar/admin.py | 2 ++ src/registrar/models/domain.py | 10 +++------- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index f4b395524..5c621ee56 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -164,6 +164,7 @@ class MyHostAdmin(AuditedAdmin): inlines = [HostIPInline] + class DomainAdmin(ListHeaderAdmin): """Custom domain admin class to add extra buttons.""" @@ -218,6 +219,7 @@ class DomainAdmin(ListHeaderAdmin): return True return super().has_change_permission(request, obj) + class ContactAdmin(ListHeaderAdmin): """Custom contact admin class to add search.""" diff --git a/src/registrar/models/domain.py b/src/registrar/models/domain.py index 2192bd370..9eb54b3d1 100644 --- a/src/registrar/models/domain.py +++ b/src/registrar/models/domain.py @@ -118,7 +118,7 @@ class Domain(TimeStampedModel, DomainHelper): READY = "ready" # when a domain is on hold - ONHOLD="onhold" + ONHOLD = "onhold" class Cache(property): """ @@ -317,17 +317,13 @@ class Domain(TimeStampedModel, DomainHelper): """Time to renew. Not implemented.""" raise NotImplementedError() - @transition( - field="state", source=[State.READY], target=State.ONHOLD - ) + @transition(field="state", source=[State.READY], target=State.ONHOLD) def place_client_hold(self): """This domain should not be active.""" # This method is changing the state of the domain in registrar # TODO: implement EPP call - @transition( - field="state", source=[State.ONHOLD], target=State.READY - ) + @transition(field="state", source=[State.ONHOLD], target=State.READY) def remove_client_hold(self): """This domain is okay to be active.""" # This method is changing the state of the domain in registrar From 744c6fa48a9aa54d0850a8e547d4e92131e03c9c Mon Sep 17 00:00:00 2001 From: David Kennedy Date: Wed, 6 Sep 2023 17:06:55 -0400 Subject: [PATCH 03/14] added test for DomainAdmin to test_place_and_remove_hold; added mock data for mock domain --- src/registrar/tests/common.py | 9 +++++- src/registrar/tests/test_admin.py | 49 +++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/src/registrar/tests/common.py b/src/registrar/tests/common.py index c4a2772b0..fbd359b75 100644 --- a/src/registrar/tests/common.py +++ b/src/registrar/tests/common.py @@ -427,11 +427,18 @@ def create_superuser(): def create_user(): User = get_user_model() p = "userpass" - return User.objects.create_user( + staffuser = User.objects.create_user( username="staffuser", email="user@example.com", password=p, ) + staffuser.is_staff = True + staffuser.save() + + +def create_ready_domain(): + domain, _ = Domain.objects.get_or_create(name="city.gov", state=Domain.State.READY) + return domain def completed_application( diff --git a/src/registrar/tests/test_admin.py b/src/registrar/tests/test_admin.py index fc5478dd9..ca5a7b93c 100644 --- a/src/registrar/tests/test_admin.py +++ b/src/registrar/tests/test_admin.py @@ -2,12 +2,14 @@ from django.test import TestCase, RequestFactory, Client from django.contrib.admin.sites import AdminSite from registrar.admin import ( + DomainAdmin, DomainApplicationAdmin, ListHeaderAdmin, MyUserAdmin, AuditedAdmin, ) from registrar.models import ( + Domain, DomainApplication, DomainInformation, User, @@ -18,6 +20,7 @@ from .common import ( mock_user, create_superuser, create_user, + create_ready_domain, multiple_unalphabetical_domain_objects, ) @@ -32,6 +35,52 @@ import logging logger = logging.getLogger(__name__) +class TestDomainAdmin(TestCase): + def setUp(self): + self.site = AdminSite() + self.factory = RequestFactory() + self.admin = DomainAdmin(model=Domain, admin_site=self.site) + self.client = Client(HTTP_HOST="localhost:8080") + self.staffuser = create_user() + + def test_place_and_remove_hold(self): + domain = create_ready_domain() + + # get admin page and assert Place Hold button + p = "userpass" + self.client.login(username="staffuser", password=p) + response = self.client.get( + "/admin/registrar/domain/{}/change/".format(domain.pk), + follow=True, + ) + self.assertEqual(response.status_code, 200) + self.assertContains(response, domain.name) + self.assertContains(response, "Place hold") + self.assertNotContains(response, "Remove hold") + + # submit place_client_hold and assert Remove Hold button + response = self.client.post( + "/admin/registrar/domain/{}/change/".format(domain.pk), + {"_place_client_hold": "Place hold", "name": domain.name}, + follow=True, + ) + self.assertEqual(response.status_code, 200) + self.assertContains(response, domain.name) + self.assertContains(response, "Remove hold") + self.assertNotContains(response, "Place hold") + + # submit remove client hold and assert Place hold button + response = self.client.post( + "/admin/registrar/domain/{}/change/".format(domain.pk), + {"_remove_client_hold": "Remove hold", "name": domain.name}, + follow=True, + ) + self.assertEqual(response.status_code, 200) + self.assertContains(response, domain.name) + self.assertContains(response, "Place hold") + self.assertNotContains(response, "Remove hold") + + class TestDomainApplicationAdmin(TestCase): def setUp(self): self.site = AdminSite() From 5c41e4a28fffde503adfe181d4d71f1c74dbd17d Mon Sep 17 00:00:00 2001 From: David Kennedy Date: Thu, 7 Sep 2023 07:18:38 -0400 Subject: [PATCH 04/14] refactored DomainAdmin response_change into multiple methods; updated create_user in common.py for properly setting is_staff for test users; added tearDown for TestDomainAdmin --- src/registrar/admin.py | 66 +++++++++++++++++-------------- src/registrar/tests/common.py | 1 + src/registrar/tests/test_admin.py | 5 +++ 3 files changed, 42 insertions(+), 30 deletions(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index 5c621ee56..2f55b1061 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -178,39 +178,45 @@ class DomainAdmin(ListHeaderAdmin): PLACE_HOLD = "_place_client_hold" REMOVE_HOLD = "_remove_client_hold" if PLACE_HOLD in request.POST: - try: - obj.place_client_hold() - obj.save() - except Exception as err: - self.message_user(request, err, messages.ERROR) - else: - self.message_user( - request, - ( - "%s is in client hold. This domain is no longer accessible on" - " the public internet." - ) - % obj.name, - ) - return HttpResponseRedirect(".") + return self.do_place_client_hold(request, obj) elif REMOVE_HOLD in request.POST: - try: - obj.remove_client_hold() - obj.save() - except Exception as err: - self.message_user(request, err, messages.ERROR) - else: - self.message_user( - request, - ( - "%s is ready. This domain is accessible on the public " - "internet." - ) - % obj.name, - ) - return HttpResponseRedirect(".") + return self.do_remove_client_hold(request, obj) return super().response_change(request, obj) + def do_place_client_hold(self, request, obj): + try: + obj.place_client_hold() + obj.save() + except Exception as err: + self.message_user(request, err, messages.ERROR) + else: + self.message_user( + request, + ( + "%s is in client hold. This domain is no longer accessible on" + " the public internet." + ) + % obj.name, + ) + return HttpResponseRedirect(".") + + def do_remove_client_hold(self, request, obj): + try: + obj.remove_client_hold() + obj.save() + except Exception as err: + self.message_user(request, err, messages.ERROR) + else: + self.message_user( + request, + ( + "%s is ready. This domain is accessible on the public " + "internet." + ) + % obj.name, + ) + return HttpResponseRedirect(".") + def has_change_permission(self, request, obj=None): # Fixes a bug wherein users which are only is_staff # can access 'change' when GET, diff --git a/src/registrar/tests/common.py b/src/registrar/tests/common.py index fbd359b75..8f8e70ec3 100644 --- a/src/registrar/tests/common.py +++ b/src/registrar/tests/common.py @@ -434,6 +434,7 @@ def create_user(): ) staffuser.is_staff = True staffuser.save() + return staffuser def create_ready_domain(): diff --git a/src/registrar/tests/test_admin.py b/src/registrar/tests/test_admin.py index ca5a7b93c..421b02994 100644 --- a/src/registrar/tests/test_admin.py +++ b/src/registrar/tests/test_admin.py @@ -41,6 +41,7 @@ class TestDomainAdmin(TestCase): self.factory = RequestFactory() self.admin = DomainAdmin(model=Domain, admin_site=self.site) self.client = Client(HTTP_HOST="localhost:8080") + self.superuser = create_superuser() self.staffuser = create_user() def test_place_and_remove_hold(self): @@ -80,6 +81,10 @@ class TestDomainAdmin(TestCase): self.assertContains(response, "Place hold") self.assertNotContains(response, "Remove hold") + def tearDown(self): + Domain.objects.all().delete() + User.objects.all().delete() + class TestDomainApplicationAdmin(TestCase): def setUp(self): From 0c1e8a2dda4a08b400710ab066edc5c4a6e1215b Mon Sep 17 00:00:00 2001 From: David Kennedy Date: Thu, 7 Sep 2023 07:42:07 -0400 Subject: [PATCH 05/14] fixed a merge issue, and some code reformatting --- src/registrar/admin.py | 5 +---- src/registrar/tests/test_admin.py | 1 - 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index 46ba254a6..e4619737e 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -212,10 +212,7 @@ class DomainAdmin(ListHeaderAdmin): else: self.message_user( request, - ( - "%s is ready. This domain is accessible on the public " - "internet." - ) + ("%s is ready. This domain is accessible on the public internet.") % obj.name, ) return HttpResponseRedirect(".") diff --git a/src/registrar/tests/test_admin.py b/src/registrar/tests/test_admin.py index e8b07ed5c..e556adcec 100644 --- a/src/registrar/tests/test_admin.py +++ b/src/registrar/tests/test_admin.py @@ -15,7 +15,6 @@ from registrar.models import ( DomainInformation, User, DomainInvitation, - Domain, ) from .common import ( completed_application, From 627bb38f5a7680cd40a2a8daa5aea249d2242ab8 Mon Sep 17 00:00:00 2001 From: David Kennedy Date: Thu, 7 Sep 2023 08:22:49 -0400 Subject: [PATCH 06/14] added dictionary of ACTION_BUTTONS for DomainAdmin to admin.py --- src/registrar/admin.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index e4619737e..4c9cd11a5 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -175,14 +175,16 @@ class DomainAdmin(ListHeaderAdmin): readonly_fields = ["state"] def response_change(self, request, obj): - PLACE_HOLD = "_place_client_hold" - REMOVE_HOLD = "_remove_client_hold" - EDIT_DOMAIN = "_edit_domain" - if PLACE_HOLD in request.POST: + ACTION_BUTTONS = { + "PLACE_HOLD": "_place_client_hold", + "REMOVE_HOLD": "_remove_client_hold", + "EDIT_DOMAIN": "_edit_domain", + } + if ACTION_BUTTONS["PLACE_HOLD"] in request.POST: return self.do_place_client_hold(request, obj) - elif REMOVE_HOLD in request.POST: + elif ACTION_BUTTONS["REMOVE_HOLD"] in request.POST: return self.do_remove_client_hold(request, obj) - elif EDIT_DOMAIN in request.POST: + elif ACTION_BUTTONS["EDIT_DOMAIN"] in request.POST: return self.do_edit_domain(request, obj) return super().response_change(request, obj) From 956f4c6f50e69f21d579467702cc0a328e9fe39a Mon Sep 17 00:00:00 2001 From: David Kennedy Date: Thu, 7 Sep 2023 13:53:42 -0400 Subject: [PATCH 07/14] make migrations --- .../migrations/0031_alter_domain_state.py | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 src/registrar/migrations/0031_alter_domain_state.py diff --git a/src/registrar/migrations/0031_alter_domain_state.py b/src/registrar/migrations/0031_alter_domain_state.py new file mode 100644 index 000000000..2545adb27 --- /dev/null +++ b/src/registrar/migrations/0031_alter_domain_state.py @@ -0,0 +1,30 @@ +# Generated by Django 4.2.1 on 2023-09-07 17:53 + +from django.db import migrations +import django_fsm + + +class Migration(migrations.Migration): + dependencies = [ + ("registrar", "0030_alter_user_status"), + ] + + operations = [ + migrations.AlterField( + model_name="domain", + name="state", + field=django_fsm.FSMField( + choices=[ + ("created", "Created"), + ("deleted", "Deleted"), + ("unknown", "Unknown"), + ("ready", "Ready"), + ("onhold", "Onhold"), + ], + default="unknown", + help_text="Very basic info about the lifecycle of this domain object", + max_length=21, + protected=True, + ), + ), + ] From 334279cfe757d17d6b925ec01a29b6550aedb462 Mon Sep 17 00:00:00 2001 From: David Kennedy Date: Fri, 8 Sep 2023 06:58:13 -0400 Subject: [PATCH 08/14] add back button to manage submitted application --- src/registrar/templates/application_status.html | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/registrar/templates/application_status.html b/src/registrar/templates/application_status.html index 2d59a32eb..67e8e7664 100644 --- a/src/registrar/templates/application_status.html +++ b/src/registrar/templates/application_status.html @@ -6,6 +6,15 @@ {% block content %}
+ + + +

+ Back to manage your domains +

+

Domain request for {{ domainapplication.requested_domain.name }}

Date: Fri, 8 Sep 2023 16:48:35 -0600 Subject: [PATCH 09/14] added Transition Domain model --- src/registrar/admin.py | 1 + src/registrar/fixtures.py | 2 +- .../migrations/0031_transitiondomain.py | 68 +++++++++++++++++++ src/registrar/models/__init__.py | 3 + src/registrar/models/transition_domain.py | 45 ++++++++++++ 5 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 src/registrar/migrations/0031_transitiondomain.py create mode 100644 src/registrar/models/transition_domain.py diff --git a/src/registrar/admin.py b/src/registrar/admin.py index d6109a0cc..f2305d3c0 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -410,3 +410,4 @@ admin.site.register(models.Host, MyHostAdmin) admin.site.register(models.Nameserver, MyHostAdmin) admin.site.register(models.Website, AuditedAdmin) admin.site.register(models.DomainApplication, DomainApplicationAdmin) +admin.site.register(models.TransitionDomain, AuditedAdmin) diff --git a/src/registrar/fixtures.py b/src/registrar/fixtures.py index f37474e71..30924b8bf 100644 --- a/src/registrar/fixtures.py +++ b/src/registrar/fixtures.py @@ -131,7 +131,7 @@ class UserFixture: { "username": "cfe7c2fc-e24a-480e-8b78-28645a1459b3", "first_name": "Nicolle-Analyst", - "last_name": "LeClair", + "last_name": "LeClair-Analyst", "email": "nicolle.leclair@ecstech.com", }, ] diff --git a/src/registrar/migrations/0031_transitiondomain.py b/src/registrar/migrations/0031_transitiondomain.py new file mode 100644 index 000000000..f353f0cf0 --- /dev/null +++ b/src/registrar/migrations/0031_transitiondomain.py @@ -0,0 +1,68 @@ +# Generated by Django 4.2.1 on 2023-09-08 22:38 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("registrar", "0030_alter_user_status"), + ] + + operations = [ + migrations.CreateModel( + name="TransitionDomain", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("created_at", models.DateTimeField(auto_now_add=True)), + ("updated_at", models.DateTimeField(auto_now=True)), + ( + "username", + models.TextField( + help_text="Username - this will be an email address", + verbose_name="Username", + ), + ), + ( + "domain_name", + models.TextField(blank=True, null=True, verbose_name="Domain name"), + ), + ( + "status", + models.CharField( + blank=True, + choices=[("created", "Created"), ("hold", "Hold")], + help_text="domain status during the transfer", + max_length=255, + verbose_name="Status", + ), + ), + ( + "ignoreServerHold", + models.BooleanField( + default=False, + help_text="specifies whether to ignore server hold", + verbose_name="ignore Server Hold", + ), + ), + ( + "email_sent", + models.BooleanField( + default=False, + help_text="indicates whether email was sent", + verbose_name="email sent", + ), + ), + ], + options={ + "abstract": False, + }, + ), + ] diff --git a/src/registrar/models/__init__.py b/src/registrar/models/__init__.py index 542cb00e1..e22328801 100644 --- a/src/registrar/models/__init__.py +++ b/src/registrar/models/__init__.py @@ -13,6 +13,7 @@ from .user_domain_role import UserDomainRole from .public_contact import PublicContact from .user import User from .website import Website +from .transition_domain import TransitionDomain __all__ = [ "Contact", @@ -28,6 +29,7 @@ __all__ = [ "PublicContact", "User", "Website", + "TransitionDomain" ] auditlog.register(Contact) @@ -42,3 +44,4 @@ auditlog.register(UserDomainRole) auditlog.register(PublicContact) auditlog.register(User) auditlog.register(Website) +auditlog.register(TransitionDomain) diff --git a/src/registrar/models/transition_domain.py b/src/registrar/models/transition_domain.py new file mode 100644 index 000000000..b2639a5dd --- /dev/null +++ b/src/registrar/models/transition_domain.py @@ -0,0 +1,45 @@ +from django.db import models + +from .utility.time_stamped_model import TimeStampedModel + +class TransitionDomain(TimeStampedModel): + """Transition Domain model stores information about the state of a domain upon transition between registry providers""" + + class StatusChoices(models.TextChoices): + CREATED = "created", "Created" + HOLD = "hold", "Hold" + + username = models.TextField( + null=False, + blank=False, + verbose_name="Username", + help_text="Username - this will be an email address", + ) + domain_name = models.TextField( + null=True, + blank=True, + verbose_name="Domain name", + ) + status = models.CharField( + max_length=255, + null=False, + blank=True, + choices=StatusChoices.choices, + verbose_name="Status", + help_text="domain status during the transfer", + ) + ignoreServerHold = models.BooleanField( + null=False, + default=False, #--COMMENT: this was not specified in the ticket #921 + verbose_name="ignore Server Hold", + help_text="specifies whether to ignore server hold", + ) + email_sent = models.BooleanField( + null=False, + default=False, + verbose_name="email sent", + help_text="indicates whether email was sent", + ) + + def __str__(self): + return self.username From d6f6433e8e12d20637bcec536452ea80cec6dc06 Mon Sep 17 00:00:00 2001 From: CuriousX Date: Fri, 8 Sep 2023 17:35:44 -0600 Subject: [PATCH 10/14] linted --- src/registrar/models/__init__.py | 2 +- src/registrar/models/transition_domain.py | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/registrar/models/__init__.py b/src/registrar/models/__init__.py index e22328801..fa4ce7e2a 100644 --- a/src/registrar/models/__init__.py +++ b/src/registrar/models/__init__.py @@ -29,7 +29,7 @@ __all__ = [ "PublicContact", "User", "Website", - "TransitionDomain" + "TransitionDomain", ] auditlog.register(Contact) diff --git a/src/registrar/models/transition_domain.py b/src/registrar/models/transition_domain.py index b2639a5dd..710d4ca08 100644 --- a/src/registrar/models/transition_domain.py +++ b/src/registrar/models/transition_domain.py @@ -2,8 +2,11 @@ from django.db import models from .utility.time_stamped_model import TimeStampedModel + class TransitionDomain(TimeStampedModel): - """Transition Domain model stores information about the state of a domain upon transition between registry providers""" + """Transition Domain model stores information about the + state of a domain upon transition between registry + providers""" class StatusChoices(models.TextChoices): CREATED = "created", "Created" @@ -30,13 +33,13 @@ class TransitionDomain(TimeStampedModel): ) ignoreServerHold = models.BooleanField( null=False, - default=False, #--COMMENT: this was not specified in the ticket #921 + default=False, verbose_name="ignore Server Hold", help_text="specifies whether to ignore server hold", ) email_sent = models.BooleanField( null=False, - default=False, + default=False, verbose_name="email sent", help_text="indicates whether email was sent", ) From 7cc52e6c117b138b93bfd25fffcf86950db00d1c Mon Sep 17 00:00:00 2001 From: CuriousX Date: Mon, 11 Sep 2023 09:22:25 -0600 Subject: [PATCH 11/14] 921: ignore server hold column removed and migration recreated --- src/registrar/migrations/0031_transitiondomain.py | 10 +--------- src/registrar/models/transition_domain.py | 6 ------ 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/src/registrar/migrations/0031_transitiondomain.py b/src/registrar/migrations/0031_transitiondomain.py index f353f0cf0..e72a8d85a 100644 --- a/src/registrar/migrations/0031_transitiondomain.py +++ b/src/registrar/migrations/0031_transitiondomain.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.1 on 2023-09-08 22:38 +# Generated by Django 4.2.1 on 2023-09-11 14:44 from django.db import migrations, models @@ -44,14 +44,6 @@ class Migration(migrations.Migration): verbose_name="Status", ), ), - ( - "ignoreServerHold", - models.BooleanField( - default=False, - help_text="specifies whether to ignore server hold", - verbose_name="ignore Server Hold", - ), - ), ( "email_sent", models.BooleanField( diff --git a/src/registrar/models/transition_domain.py b/src/registrar/models/transition_domain.py index 710d4ca08..31da70704 100644 --- a/src/registrar/models/transition_domain.py +++ b/src/registrar/models/transition_domain.py @@ -31,12 +31,6 @@ class TransitionDomain(TimeStampedModel): verbose_name="Status", help_text="domain status during the transfer", ) - ignoreServerHold = models.BooleanField( - null=False, - default=False, - verbose_name="ignore Server Hold", - help_text="specifies whether to ignore server hold", - ) email_sent = models.BooleanField( null=False, default=False, From 889289f54e0f750d8ce71642c9af43fc3b64b7e9 Mon Sep 17 00:00:00 2001 From: David Kennedy Date: Tue, 12 Sep 2023 10:16:22 -0400 Subject: [PATCH 12/14] make migrations, fix conflict from merge --- ..._0031_alter_domain_state_0031_transitiondomain.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 src/registrar/migrations/0032_merge_0031_alter_domain_state_0031_transitiondomain.py diff --git a/src/registrar/migrations/0032_merge_0031_alter_domain_state_0031_transitiondomain.py b/src/registrar/migrations/0032_merge_0031_alter_domain_state_0031_transitiondomain.py new file mode 100644 index 000000000..4c0a38427 --- /dev/null +++ b/src/registrar/migrations/0032_merge_0031_alter_domain_state_0031_transitiondomain.py @@ -0,0 +1,12 @@ +# Generated by Django 4.2.1 on 2023-09-12 14:12 + +from django.db import migrations + + +class Migration(migrations.Migration): + dependencies = [ + ("registrar", "0031_alter_domain_state"), + ("registrar", "0031_transitiondomain"), + ] + + operations = [] From a398a5c92756f08168f374562e7dbe174d63c4cc Mon Sep 17 00:00:00 2001 From: David Kennedy Date: Tue, 12 Sep 2023 11:04:26 -0400 Subject: [PATCH 13/14] refactored response_change to use a dictionary of action functions --- src/registrar/admin.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index daa5f00a2..1427cb054 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -175,17 +175,19 @@ class DomainAdmin(ListHeaderAdmin): readonly_fields = ["state"] def response_change(self, request, obj): - ACTION_BUTTONS = { - "PLACE_HOLD": "_place_client_hold", - "REMOVE_HOLD": "_remove_client_hold", - "EDIT_DOMAIN": "_edit_domain", + # Create dictionary of action functions + ACTION_FUNCTIONS = { + "_place_client_hold": self.do_place_client_hold, + "_remove_client_hold": self.do_remove_client_hold, + "_edit_domain": self.do_edit_domain, } - if ACTION_BUTTONS["PLACE_HOLD"] in request.POST: - return self.do_place_client_hold(request, obj) - elif ACTION_BUTTONS["REMOVE_HOLD"] in request.POST: - return self.do_remove_client_hold(request, obj) - elif ACTION_BUTTONS["EDIT_DOMAIN"] in request.POST: - return self.do_edit_domain(request, obj) + + # Check which action button was pressed and call the corresponding function + for action, function in ACTION_FUNCTIONS.items(): + if action in request.POST: + return function(request, obj) + + # If no matching action button is found, return the super method return super().response_change(request, obj) def do_place_client_hold(self, request, obj): From 4b86a056db0f7f8462e3383ea36e4387c53c3d89 Mon Sep 17 00:00:00 2001 From: David Kennedy Date: Tue, 12 Sep 2023 12:16:58 -0400 Subject: [PATCH 14/14] some updates to test code --- src/registrar/tests/common.py | 6 ++---- src/registrar/tests/test_admin.py | 6 +++++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/registrar/tests/common.py b/src/registrar/tests/common.py index 8f859b6d1..c6cd8ebfd 100644 --- a/src/registrar/tests/common.py +++ b/src/registrar/tests/common.py @@ -427,14 +427,12 @@ def create_superuser(): def create_user(): User = get_user_model() p = "userpass" - staffuser = User.objects.create_user( + return User.objects.create_user( username="staffuser", email="user@example.com", + is_staff=True, password=p, ) - staffuser.is_staff = True - staffuser.save() - return staffuser def create_ready_domain(): diff --git a/src/registrar/tests/test_admin.py b/src/registrar/tests/test_admin.py index e556adcec..28d407a35 100644 --- a/src/registrar/tests/test_admin.py +++ b/src/registrar/tests/test_admin.py @@ -28,6 +28,7 @@ from .common import ( from django.contrib.sessions.backends.db import SessionStore from django.contrib.auth import get_user_model from unittest.mock import patch +from unittest import skip from django.conf import settings from unittest.mock import MagicMock @@ -40,7 +41,6 @@ logger = logging.getLogger(__name__) class TestDomainAdmin(TestCase): def setUp(self): self.site = AdminSite() - self.factory = RequestFactory() self.admin = DomainAdmin(model=Domain, admin_site=self.site) self.client = Client(HTTP_HOST="localhost:8080") self.superuser = create_superuser() @@ -83,6 +83,10 @@ class TestDomainAdmin(TestCase): self.assertContains(response, "Place hold") self.assertNotContains(response, "Remove hold") + @skip("Waiting on epp lib to implement") + def test_place_and_remove_hold_epp(self): + raise + def tearDown(self): Domain.objects.all().delete() User.objects.all().delete()