Create a DraftDomain model for requested domains

This commit is contained in:
Seamus Johnston 2023-05-25 13:53:02 -05:00
parent 93427ad072
commit 7a3e1bcb2c
No known key found for this signature in database
GPG key ID: 2F21225985069105
15 changed files with 272 additions and 124 deletions

View file

@ -37,7 +37,7 @@ def _domains():
Fetch a file from DOMAIN_FILE_URL, parse the CSV for the domain, Fetch a file from DOMAIN_FILE_URL, parse the CSV for the domain,
lowercase everything and return the list. lowercase everything and return the list.
""" """
Domain = apps.get_model("registrar.Domain") DraftDomain = apps.get_model("registrar.DraftDomain")
# 5 second timeout # 5 second timeout
file_contents = requests.get(DOMAIN_FILE_URL, timeout=5).text file_contents = requests.get(DOMAIN_FILE_URL, timeout=5).text
domains = set() domains = set()
@ -46,7 +46,7 @@ def _domains():
# get the domain before the first comma # get the domain before the first comma
domain = line.split(",", 1)[0] domain = line.split(",", 1)[0]
# sanity-check the string we got from the file here # sanity-check the string we got from the file here
if Domain.string_could_be_domain(domain): if DraftDomain.string_could_be_domain(domain):
# lowercase everything when we put it in domains # lowercase everything when we put it in domains
domains.add(domain.lower()) domains.add(domain.lower())
return domains return domains
@ -75,12 +75,12 @@ def available(request, domain=""):
Response is a JSON dictionary with the key "available" and value true or Response is a JSON dictionary with the key "available" and value true or
false. false.
""" """
Domain = apps.get_model("registrar.Domain") DraftDomain = apps.get_model("registrar.DraftDomain")
# validate that the given domain could be a domain name and fail early if # validate that the given domain could be a domain name and fail early if
# not. # not.
if not ( if not (
Domain.string_could_be_domain(domain) DraftDomain.string_could_be_domain(domain)
or Domain.string_could_be_domain(domain + ".gov") or DraftDomain.string_could_be_domain(domain + ".gov")
): ):
return JsonResponse( return JsonResponse(
{"available": False, "message": DOMAIN_API_MESSAGES["invalid"]} {"available": False, "message": DOMAIN_API_MESSAGES["invalid"]}

View file

@ -5,7 +5,7 @@ from faker import Faker
from registrar.models import ( from registrar.models import (
User, User,
DomainApplication, DomainApplication,
Domain, DraftDomain,
Contact, Contact,
Website, Website,
) )
@ -216,11 +216,13 @@ class DomainApplicationFixture:
if not da.requested_domain: if not da.requested_domain:
if "requested_domain" in app and app["requested_domain"] is not None: if "requested_domain" in app and app["requested_domain"] is not None:
da.requested_domain, _ = Domain.objects.get_or_create( da.requested_domain, _ = DraftDomain.objects.get_or_create(
name=app["requested_domain"] name=app["requested_domain"]
) )
else: else:
da.requested_domain = Domain.objects.create(name=cls.fake_dot_gov()) da.requested_domain = DraftDomain.objects.create(
name=cls.fake_dot_gov()
)
@classmethod @classmethod
def _set_many_to_many_relations(cls, da: DomainApplication, app: dict): def _set_many_to_many_relations(cls, da: DomainApplication, app: dict):

View file

@ -11,7 +11,7 @@ from django.utils.safestring import mark_safe
from api.views import DOMAIN_API_MESSAGES from api.views import DOMAIN_API_MESSAGES
from registrar.models import Contact, DomainApplication, Domain from registrar.models import Contact, DomainApplication, DraftDomain, Domain
from registrar.utility import errors from registrar.utility import errors
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -453,7 +453,7 @@ class AlternativeDomainForm(RegistrarForm):
"""Validation code for domain names.""" """Validation code for domain names."""
try: try:
requested = self.cleaned_data.get("alternative_domain", None) requested = self.cleaned_data.get("alternative_domain", None)
validated = Domain.validate(requested, blank_ok=True) validated = DraftDomain.validate(requested, blank_ok=True)
except errors.ExtraDotsError: except errors.ExtraDotsError:
raise forms.ValidationError( raise forms.ValidationError(
DOMAIN_API_MESSAGES["extra_dots"], code="extra_dots" DOMAIN_API_MESSAGES["extra_dots"], code="extra_dots"
@ -498,7 +498,7 @@ class BaseAlternativeDomainFormSet(RegistrarFormSet):
@classmethod @classmethod
def on_fetch(cls, query): def on_fetch(cls, query):
return [{"alternative_domain": domain.sld} for domain in query] return [{"alternative_domain": Domain.sld(domain.name)} for domain in query]
@classmethod @classmethod
def from_database(cls, obj): def from_database(cls, obj):
@ -524,7 +524,7 @@ class DotGovDomainForm(RegistrarForm):
requested_domain.name = f"{domain}.gov" requested_domain.name = f"{domain}.gov"
requested_domain.save() requested_domain.save()
else: else:
requested_domain = Domain.objects.create(name=f"{domain}.gov") requested_domain = DraftDomain.objects.create(name=f"{domain}.gov")
obj.requested_domain = requested_domain obj.requested_domain = requested_domain
obj.save() obj.save()
@ -535,14 +535,14 @@ class DotGovDomainForm(RegistrarForm):
values = {} values = {}
requested_domain = getattr(obj, "requested_domain", None) requested_domain = getattr(obj, "requested_domain", None)
if requested_domain is not None: if requested_domain is not None:
values["requested_domain"] = requested_domain.sld values["requested_domain"] = Domain.sld(requested_domain.name)
return values return values
def clean_requested_domain(self): def clean_requested_domain(self):
"""Validation code for domain names.""" """Validation code for domain names."""
try: try:
requested = self.cleaned_data.get("requested_domain", None) requested = self.cleaned_data.get("requested_domain", None)
validated = Domain.validate(requested) validated = DraftDomain.validate(requested)
except errors.BlankValueError: except errors.BlankValueError:
raise forms.ValidationError( raise forms.ValidationError(
DOMAIN_API_MESSAGES["required"], code="required" DOMAIN_API_MESSAGES["required"], code="required"

View file

@ -54,16 +54,6 @@ class Command(BaseCommand):
domains = [] domains = []
for row in reader: for row in reader:
name = row["Name"].lower() # we typically use lowercase domains name = row["Name"].lower() # we typically use lowercase domains
domains.append(Domain(name=name))
# Ensure that there is a `Domain` object for each domain name in
# this file and that it is active. There is a uniqueness
# constraint for active Domain objects, so we are going to account
# for that here with this check so that our later bulk_create
# should succeed
if Domain.objects.filter(name=name, is_active=True).exists():
# don't do anything, this domain is here and active
continue
else:
domains.append(Domain(name=name, is_active=True))
logger.info("Creating %d new domains", len(domains)) logger.info("Creating %d new domains", len(domains))
Domain.objects.bulk_create(domains) Domain.objects.bulk_create(domains)

View file

@ -0,0 +1,66 @@
# Generated by Django 4.2.1 on 2023-05-26 13:14
from django.db import migrations, models
import django.db.models.deletion
import registrar.models.utility.domain_helper
class Migration(migrations.Migration):
dependencies = [
("registrar", "0021_publiccontact_domain_publiccontact_registry_id_and_more"),
]
operations = [
migrations.CreateModel(
name="DraftDomain",
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)),
(
"name",
models.CharField(
default=None,
help_text="Fully qualified domain name",
max_length=253,
),
),
],
options={
"abstract": False,
},
bases=(models.Model, registrar.models.utility.domain_helper.DomainHelper),
),
migrations.AddField(
model_name="domainapplication",
name="approved_domain",
field=models.OneToOneField(
blank=True,
help_text="The approved domain",
null=True,
on_delete=django.db.models.deletion.PROTECT,
related_name="domain_application",
to="registrar.domain",
),
),
migrations.AlterField(
model_name="domainapplication",
name="requested_domain",
field=models.OneToOneField(
blank=True,
help_text="The requested domain",
null=True,
on_delete=django.db.models.deletion.PROTECT,
related_name="domain_application",
to="registrar.draftdomain",
),
),
]

View file

@ -4,6 +4,7 @@ from .contact import Contact
from .domain_application import DomainApplication from .domain_application import DomainApplication
from .domain_information import DomainInformation from .domain_information import DomainInformation
from .domain import Domain from .domain import Domain
from .draft_domain import DraftDomain
from .host_ip import HostIP from .host_ip import HostIP
from .host import Host from .host import Host
from .domain_invitation import DomainInvitation from .domain_invitation import DomainInvitation
@ -18,6 +19,7 @@ __all__ = [
"DomainApplication", "DomainApplication",
"DomainInformation", "DomainInformation",
"Domain", "Domain",
"DraftDomain",
"DomainInvitation", "DomainInvitation",
"HostIP", "HostIP",
"Host", "Host",
@ -31,6 +33,7 @@ __all__ = [
auditlog.register(Contact) auditlog.register(Contact)
auditlog.register(DomainApplication) auditlog.register(DomainApplication)
auditlog.register(Domain) auditlog.register(Domain)
auditlog.register(DraftDomain)
auditlog.register(DomainInvitation) auditlog.register(DomainInvitation)
auditlog.register(HostIP) auditlog.register(HostIP)
auditlog.register(Host) auditlog.register(Host)

View file

@ -400,10 +400,19 @@ class DomainApplication(TimeStampedModel):
related_name="current+", related_name="current+",
) )
requested_domain = models.OneToOneField( approved_domain = models.OneToOneField(
"Domain", "Domain",
null=True, null=True,
blank=True, blank=True,
help_text="The approved domain",
related_name="domain_application",
on_delete=models.PROTECT,
)
requested_domain = models.OneToOneField(
"DraftDomain",
null=True,
blank=True,
help_text="The requested domain", help_text="The requested domain",
related_name="domain_application", related_name="domain_application",
on_delete=models.PROTECT, on_delete=models.PROTECT,
@ -499,8 +508,8 @@ class DomainApplication(TimeStampedModel):
if self.requested_domain is None: if self.requested_domain is None:
raise ValueError("Requested domain is missing.") raise ValueError("Requested domain is missing.")
Domain = apps.get_model("registrar.Domain") DraftDomain = apps.get_model("registrar.DraftDomain")
if not Domain.string_could_be_domain(self.requested_domain.name): if not DraftDomain.string_could_be_domain(self.requested_domain.name):
raise ValueError("Requested domain is not a valid domain name.") raise ValueError("Requested domain is not a valid domain name.")
# When an application is submitted, we need to send a confirmation email # When an application is submitted, we need to send a confirmation email
@ -516,13 +525,16 @@ class DomainApplication(TimeStampedModel):
application into an admin on that domain. application into an admin on that domain.
""" """
# create the domain if it doesn't exist # create the domain
Domain = apps.get_model("registrar.Domain") Domain = apps.get_model("registrar.Domain")
created_domain, _ = Domain.objects.get_or_create(name=self.requested_domain) if Domain.objects.filter(name=self.requested_domain.name).exists():
raise ValueError("Cannot approve. Requested domain is already in use.")
created_domain = Domain.objects.create(name=self.requested_domain.name)
self.approved_domain = created_domain
# copy the information from domainapplication into domaininformation # copy the information from domainapplication into domaininformation
DomainInformation = apps.get_model("registrar.DomainInformation") DomainInformation = apps.get_model("registrar.DomainInformation")
DomainInformation.create_from_da(self) DomainInformation.create_from_da(self, domain=created_domain)
# create the permission for the user # create the permission for the user
UserDomainRole = apps.get_model("registrar.UserDomainRole") UserDomainRole = apps.get_model("registrar.UserDomainRole")

View file

@ -211,24 +211,24 @@ class DomainInformation(TimeStampedModel):
return "" return ""
@classmethod @classmethod
def create_from_da(cls, domain_application): def create_from_da(cls, domain_application, domain=None):
"""Takes in a DomainApplication dict and converts it into DomainInformation""" """Takes in a DomainApplication dict and converts it into DomainInformation"""
da_dict = domain_application.to_dict() da_dict = domain_application.to_dict()
# remove the id so one can be assinged on creation # remove the id so one can be assinged on creation
da_id = da_dict.pop("id") da_id = da_dict.pop("id", None)
# check if we have a record that corresponds with the domain # check if we have a record that corresponds with the domain
# application, if so short circuit the create # application, if so short circuit the create
domain_info = cls.objects.filter(domain_application__id=da_id).first() domain_info = cls.objects.filter(domain_application__id=da_id).first()
if domain_info: if domain_info:
return domain_info return domain_info
# the following information below is not needed in the domain information: # the following information below is not needed in the domain information:
da_dict.pop("status") da_dict.pop("status", None)
da_dict.pop("current_websites") da_dict.pop("current_websites", None)
da_dict.pop("investigator") da_dict.pop("investigator", None)
da_dict.pop("alternative_domains") da_dict.pop("alternative_domains", None)
# use the requested_domain to create information for this domain da_dict.pop("requested_domain", None)
da_dict["domain"] = da_dict.pop("requested_domain") da_dict.pop("approved_domain", None)
other_contacts = da_dict.pop("other_contacts") other_contacts = da_dict.pop("other_contacts", [])
domain_info = cls(**da_dict) domain_info = cls(**da_dict)
domain_info.domain_application = domain_application domain_info.domain_application = domain_application
# Save so the object now have PK # Save so the object now have PK
@ -237,6 +237,8 @@ class DomainInformation(TimeStampedModel):
# Process the remaining "many to many" stuff # Process the remaining "many to many" stuff
domain_info.other_contacts.add(*other_contacts) domain_info.other_contacts.add(*other_contacts)
if domain:
domain_info.domain = domain
domain_info.save() domain_info.save()
return domain_info return domain_info

View file

@ -0,0 +1,22 @@
import logging
from django.db import models
from .utility.domain_helper import DomainHelper
from .utility.time_stamped_model import TimeStampedModel
logger = logging.getLogger(__name__)
class DraftDomain(TimeStampedModel, DomainHelper):
"""Store domain names which registrants have requested."""
def __str__(self) -> str:
return self.name
name = models.CharField(
max_length=253,
blank=False,
default=None, # prevent saving without a value
help_text="Fully qualified domain name",
)

View file

@ -0,0 +1,64 @@
import re
from api.views import in_domains
from registrar.utility import errors
class DomainHelper:
"""Utility functions and constants for domain names."""
# a domain name is alphanumeric or hyphen, up to 63 characters, doesn't
# begin or end with a hyphen, followed by a TLD of 2-6 alphabetic characters
DOMAIN_REGEX = re.compile(r"^(?!-)[A-Za-z0-9-]{1,63}(?<!-)\.[A-Za-z]{2,6}$")
# a domain name is alphanumeric or hyphen, has at least 2 dots, doesn't
# begin or end with a hyphen, followed by a TLD of 2-6 alphabetic characters
HOST_REGEX = re.compile(r"^((?!-)[A-Za-z0-9-]{1,63}(?<!-)\.){2,}([A-Za-z]){2,6}$")
# a domain can be no longer than 253 characters in total
MAX_LENGTH = 253
@classmethod
def string_could_be_domain(cls, domain: str | None) -> bool:
"""Return True if the string could be a domain name, otherwise False."""
if not isinstance(domain, str):
return False
return bool(cls.DOMAIN_REGEX.match(domain))
@classmethod
def validate(cls, domain: str | None, blank_ok=False) -> str:
"""Attempt to determine if a domain name could be requested."""
if domain is None:
raise errors.BlankValueError()
if not isinstance(domain, str):
raise ValueError("Domain name must be a string")
domain = domain.lower().strip()
if domain == "":
if blank_ok:
return domain
else:
raise errors.BlankValueError()
if domain.endswith(".gov"):
domain = domain[:-4]
if "." in domain:
raise errors.ExtraDotsError()
if not DomainHelper.string_could_be_domain(domain + ".gov"):
raise ValueError()
if in_domains(domain):
raise errors.DomainUnavailableError()
return domain
@classmethod
def sld(cls, domain: str):
"""
Get the second level domain. Example: `gsa.gov` -> `gsa`.
If no TLD is present, returns the original string.
"""
return domain.split(".")[0]
@classmethod
def tld(cls, domain: str):
"""Get the top level domain. Example: `gsa.gov` -> `gov`."""
parts = domain.rsplit(".")
return parts[-1] if len(parts) > 1 else ""

View file

@ -1,5 +1,3 @@
from django.apps import apps
from django.core.exceptions import ValidationError
from django.db import models from django.db import models
from .utility.time_stamped_model import TimeStampedModel from .utility.time_stamped_model import TimeStampedModel
@ -18,35 +16,5 @@ class Website(TimeStampedModel):
help_text="", help_text="",
) )
@property
def sld(self):
"""Get or set the second level domain string."""
return self.website.split(".")[0]
@sld.setter
def sld(self, value: str):
Domain = apps.get_model("registrar.Domain")
parts = self.website.split(".")
tld = parts[1] if len(parts) > 1 else ""
if Domain.string_could_be_domain(f"{value}.{tld}"):
self.website = f"{value}.{tld}"
else:
raise ValidationError("%s is not a valid second level domain" % value)
@property
def tld(self):
"""Get or set the top level domain string."""
parts = self.website.split(".")
return parts[1] if len(parts) > 1 else ""
@tld.setter
def tld(self, value: str):
Domain = apps.get_model("registrar.Domain")
sld = self.website.split(".")[0]
if Domain.string_could_be_domain(f"{sld}.{value}"):
self.website = f"{sld}.{value}"
else:
raise ValidationError("%s is not a valid top level domain" % value)
def __str__(self) -> str: def __str__(self) -> str:
return str(self.website) return str(self.website)

View file

@ -5,7 +5,7 @@ from unittest.mock import MagicMock
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.test import TestCase from django.test import TestCase
from registrar.models import Contact, Domain, Website, DomainApplication from registrar.models import Contact, DraftDomain, Website, DomainApplication
import boto3_mocking # type: ignore import boto3_mocking # type: ignore
@ -28,7 +28,7 @@ class TestEmails(TestCase):
email="testy@town.com", email="testy@town.com",
phone="(555) 555 5555", phone="(555) 555 5555",
) )
domain, _ = Domain.objects.get_or_create(name="city.gov") domain, _ = DraftDomain.objects.get_or_create(name="city.gov")
alt, _ = Website.objects.get_or_create(website="city1.gov") alt, _ = Website.objects.get_or_create(website="city1.gov")
current, _ = Website.objects.get_or_create(website="city.com") current, _ = Website.objects.get_or_create(website="city.com")
you, _ = Contact.objects.get_or_create( you, _ = Contact.objects.get_or_create(

View file

@ -8,6 +8,7 @@ from registrar.models import (
User, User,
Website, Website,
Domain, Domain,
DraftDomain,
DomainInvitation, DomainInvitation,
UserDomainRole, UserDomainRole,
) )
@ -40,7 +41,7 @@ class TestDomainApplication(TestCase):
contact = Contact.objects.create() contact = Contact.objects.create()
com_website, _ = Website.objects.get_or_create(website="igorville.com") com_website, _ = Website.objects.get_or_create(website="igorville.com")
gov_website, _ = Website.objects.get_or_create(website="igorville.gov") gov_website, _ = Website.objects.get_or_create(website="igorville.gov")
domain, _ = Domain.objects.get_or_create(name="igorville.gov") domain, _ = DraftDomain.objects.get_or_create(name="igorville.gov")
application = DomainApplication.objects.create( application = DomainApplication.objects.create(
creator=user, creator=user,
investigator=user, investigator=user,
@ -100,7 +101,7 @@ class TestDomainApplication(TestCase):
def test_status_fsm_submit_succeed(self): def test_status_fsm_submit_succeed(self):
user, _ = User.objects.get_or_create() user, _ = User.objects.get_or_create()
site = Domain.objects.create(name="igorville.gov") site = DraftDomain.objects.create(name="igorville.gov")
application = DomainApplication.objects.create( application = DomainApplication.objects.create(
creator=user, requested_domain=site creator=user, requested_domain=site
) )
@ -113,7 +114,7 @@ class TestDomainApplication(TestCase):
"""Create an application and submit it and see if email was sent.""" """Create an application and submit it and see if email was sent."""
user, _ = User.objects.get_or_create() user, _ = User.objects.get_or_create()
contact = Contact.objects.create(email="test@test.gov") contact = Contact.objects.create(email="test@test.gov")
domain, _ = Domain.objects.get_or_create(name="igorville.gov") domain, _ = DraftDomain.objects.get_or_create(name="igorville.gov")
application = DomainApplication.objects.create( application = DomainApplication.objects.create(
creator=user, creator=user,
requested_domain=domain, requested_domain=domain,
@ -135,62 +136,22 @@ class TestDomainApplication(TestCase):
) )
class TestDomain(TestCase):
def test_empty_create_fails(self):
"""Can't create a completely empty domain."""
with self.assertRaisesRegex(IntegrityError, "name"):
Domain.objects.create()
def test_minimal_create(self):
"""Can create with just a name."""
domain = Domain.objects.create(name="igorville.gov")
self.assertEqual(domain.is_active, False)
@skip("cannot activate a domain without mock registry")
def test_get_status(self):
"""Returns proper status based on `is_active`."""
domain = Domain.objects.create(name="igorville.gov")
domain.save()
self.assertEqual(None, domain.status)
domain.activate()
domain.save()
self.assertIn("ok", domain.status)
def test_fsm_activate_fail_unique(self):
"""Can't activate domain if name is not unique."""
d1, _ = Domain.objects.get_or_create(name="igorville.gov")
d2, _ = Domain.objects.get_or_create(name="igorville.gov")
d1.activate()
d1.save()
with self.assertRaises(ValueError):
d2.activate()
def test_fsm_activate_fail_unapproved(self):
"""Can't activate domain if application isn't approved."""
d1, _ = Domain.objects.get_or_create(name="igorville.gov")
user, _ = User.objects.get_or_create()
application = DomainApplication.objects.create(creator=user)
d1.domain_application = application
d1.save()
with self.assertRaises(ValueError):
d1.activate()
class TestPermissions(TestCase): class TestPermissions(TestCase):
"""Test the User-Domain-Role connection.""" """Test the User-Domain-Role connection."""
def test_approval_creates_role(self): def test_approval_creates_role(self):
domain, _ = Domain.objects.get_or_create(name="igorville.gov") draft_domain, _ = DraftDomain.objects.get_or_create(name="igorville.gov")
user, _ = User.objects.get_or_create() user, _ = User.objects.get_or_create()
application = DomainApplication.objects.create( application = DomainApplication.objects.create(
creator=user, requested_domain=domain creator=user, requested_domain=draft_domain
) )
# skip using the submit method # skip using the submit method
application.status = DomainApplication.SUBMITTED application.status = DomainApplication.SUBMITTED
application.approve() application.approve()
# should be a role for this user # should be a role for this user
domain = Domain.objects.get(name="igorville.gov")
self.assertTrue(UserDomainRole.objects.get(user=user, domain=domain)) self.assertTrue(UserDomainRole.objects.get(user=user, domain=domain))
@ -199,16 +160,17 @@ class TestDomainInfo(TestCase):
"""Test creation of Domain Information when approved.""" """Test creation of Domain Information when approved."""
def test_approval_creates_info(self): def test_approval_creates_info(self):
domain, _ = Domain.objects.get_or_create(name="igorville.gov") draft_domain, _ = DraftDomain.objects.get_or_create(name="igorville.gov")
user, _ = User.objects.get_or_create() user, _ = User.objects.get_or_create()
application = DomainApplication.objects.create( application = DomainApplication.objects.create(
creator=user, requested_domain=domain creator=user, requested_domain=draft_domain
) )
# skip using the submit method # skip using the submit method
application.status = DomainApplication.SUBMITTED application.status = DomainApplication.SUBMITTED
application.approve() application.approve()
# should be an information present for this domain # should be an information present for this domain
domain = Domain.objects.get(name="igorville.gov")
self.assertTrue(DomainInformation.objects.get(domain=domain)) self.assertTrue(DomainInformation.objects.get(domain=domain))

View file

@ -0,0 +1,54 @@
from django.test import TestCase
from django.db.utils import IntegrityError
from registrar.models import (
DomainApplication,
User,
Domain,
)
from unittest import skip
class TestDomain(TestCase):
def test_empty_create_fails(self):
"""Can't create a completely empty domain."""
with self.assertRaisesRegex(IntegrityError, "name"):
Domain.objects.create()
def test_minimal_create(self):
"""Can create with just a name."""
Domain.objects.create(name="igorville.gov")
# this assertion will not work -- for now, the fact that the
# above command didn't error out is proof enough
# self.assertEquals(domain.state, Domain.State.DRAFTED)
@skip("cannot activate a domain without mock registry")
def test_get_status(self):
"""Returns proper status based on `state`."""
domain = Domain.objects.create(name="igorville.gov")
domain.save()
self.assertEqual(None, domain.status)
domain.activate()
domain.save()
self.assertIn("ok", domain.status)
@skip("cannot activate a domain without mock registry")
def test_fsm_activate_fail_unique(self):
"""Can't activate domain if name is not unique."""
d1, _ = Domain.objects.get_or_create(name="igorville.gov")
d2, _ = Domain.objects.get_or_create(name="igorville.gov")
d1.activate()
d1.save()
with self.assertRaises(ValueError):
d2.activate()
@skip("cannot activate a domain without mock registry")
def test_fsm_activate_fail_unapproved(self):
"""Can't activate domain if application isn't approved."""
d1, _ = Domain.objects.get_or_create(name="igorville.gov")
user, _ = User.objects.get_or_create()
application = DomainApplication.objects.create(creator=user)
d1.domain_application = application
d1.save()
with self.assertRaises(ValueError):
d1.activate()

View file

@ -13,6 +13,7 @@ import boto3_mocking # type: ignore
from registrar.models import ( from registrar.models import (
DomainApplication, DomainApplication,
Domain, Domain,
DraftDomain,
DomainInvitation, DomainInvitation,
Contact, Contact,
Website, Website,
@ -75,7 +76,7 @@ class LoggedInTests(TestWithUser):
def test_home_lists_domain_applications(self): def test_home_lists_domain_applications(self):
response = self.client.get("/") response = self.client.get("/")
self.assertNotContains(response, "igorville.gov") self.assertNotContains(response, "igorville.gov")
site = Domain.objects.create(name="igorville.gov") site = DraftDomain.objects.create(name="igorville.gov")
application = DomainApplication.objects.create( application = DomainApplication.objects.create(
creator=self.user, requested_domain=site creator=self.user, requested_domain=site
) )
@ -1035,6 +1036,8 @@ class TestWithDomainPermissions(TestWithUser):
def tearDown(self): def tearDown(self):
try: try:
if hasattr(self.domain, "contacts"):
self.domain.contacts.all().delete()
self.domain.delete() self.domain.delete()
self.role.delete() self.role.delete()
except ValueError: # pass if already deleted except ValueError: # pass if already deleted
@ -1347,7 +1350,7 @@ class TestApplicationStatus(TestWithUser, WebTest):
email="testy@town.com", email="testy@town.com",
phone="(555) 555 5555", phone="(555) 555 5555",
) )
domain, _ = Domain.objects.get_or_create(name="citystatus.gov") domain, _ = DraftDomain.objects.get_or_create(name="citystatus.gov")
alt, _ = Website.objects.get_or_create(website="city1.gov") alt, _ = Website.objects.get_or_create(website="city1.gov")
current, _ = Website.objects.get_or_create(website="city.com") current, _ = Website.objects.get_or_create(website="city.com")
you, _ = Contact.objects.get_or_create( you, _ = Contact.objects.get_or_create(