mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-08-04 08:52:16 +02:00
Merge pull request #991 from cisagov/dk/803-domain-client-hold
Dk/803 domain client hold
This commit is contained in:
commit
5e0800862e
7 changed files with 174 additions and 28 deletions
|
@ -175,31 +175,59 @@ class DomainAdmin(ListHeaderAdmin):
|
|||
readonly_fields = ["state"]
|
||||
|
||||
def response_change(self, request, obj):
|
||||
PLACE_HOLD = "_place_client_hold"
|
||||
EDIT_DOMAIN = "_edit_domain"
|
||||
if PLACE_HOLD in request.POST:
|
||||
try:
|
||||
obj.place_client_hold()
|
||||
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(".")
|
||||
elif EDIT_DOMAIN in request.POST:
|
||||
# We want to know, globally, when an edit action occurs
|
||||
request.session["analyst_action"] = "edit"
|
||||
# Restricts this action to this domain (pk) only
|
||||
request.session["analyst_action_location"] = obj.id
|
||||
return HttpResponseRedirect(reverse("domain", args=(obj.id,)))
|
||||
# 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,
|
||||
}
|
||||
|
||||
# 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):
|
||||
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 do_edit_domain(self, request, obj):
|
||||
# We want to know, globally, when an edit action occurs
|
||||
request.session["analyst_action"] = "edit"
|
||||
# Restricts this action to this domain (pk) only
|
||||
request.session["analyst_action_location"] = obj.id
|
||||
return HttpResponseRedirect(reverse("domain", args=(obj.id,)))
|
||||
|
||||
def change_view(self, request, object_id):
|
||||
# If the analyst was recently editing a domain page,
|
||||
# delete any associated session values
|
||||
|
|
30
src/registrar/migrations/0031_alter_domain_state.py
Normal file
30
src/registrar/migrations/0031_alter_domain_state.py
Normal file
|
@ -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,
|
||||
),
|
||||
),
|
||||
]
|
|
@ -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 = []
|
|
@ -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,17 @@ 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
|
||||
|
|
|
@ -8,8 +8,12 @@
|
|||
|
||||
{% block field_sets %}
|
||||
<div class="submit-row">
|
||||
{% if original.state == original.State.READY %}
|
||||
<input type="submit" value="Place hold" name="_place_client_hold">
|
||||
{% elif original.state == original.State.ONHOLD %}
|
||||
<input type="submit" value="Remove hold" name="_remove_client_hold">
|
||||
{% endif %}
|
||||
<input id="manageDomainSubmitButton" type="submit" value="Manage Domain" name="_edit_domain">
|
||||
<input type="submit" value="Place hold" name="_place_client_hold">
|
||||
</div>
|
||||
{{ block.super }}
|
||||
{% endblock %}
|
|
@ -430,10 +430,16 @@ def create_user():
|
|||
return User.objects.create_user(
|
||||
username="staffuser",
|
||||
email="user@example.com",
|
||||
is_staff=True,
|
||||
password=p,
|
||||
)
|
||||
|
||||
|
||||
def create_ready_domain():
|
||||
domain, _ = Domain.objects.get_or_create(name="city.gov", state=Domain.State.READY)
|
||||
return domain
|
||||
|
||||
|
||||
def completed_application(
|
||||
has_other_contacts=True,
|
||||
has_current_website=True,
|
||||
|
|
|
@ -10,11 +10,11 @@ from registrar.admin import (
|
|||
AuditedAdmin,
|
||||
)
|
||||
from registrar.models import (
|
||||
Domain,
|
||||
DomainApplication,
|
||||
DomainInformation,
|
||||
User,
|
||||
DomainInvitation,
|
||||
Domain,
|
||||
)
|
||||
from .common import (
|
||||
completed_application,
|
||||
|
@ -22,11 +22,13 @@ from .common import (
|
|||
mock_user,
|
||||
create_superuser,
|
||||
create_user,
|
||||
create_ready_domain,
|
||||
multiple_unalphabetical_domain_objects,
|
||||
)
|
||||
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
|
||||
|
@ -36,6 +38,60 @@ import logging
|
|||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class TestDomainAdmin(TestCase):
|
||||
def setUp(self):
|
||||
self.site = AdminSite()
|
||||
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):
|
||||
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")
|
||||
|
||||
@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()
|
||||
|
||||
|
||||
class TestDomainApplicationAdmin(TestCase):
|
||||
def setUp(self):
|
||||
self.site = AdminSite()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue