mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-05-16 09:37:03 +02:00
Create a DraftDomain model for requested domains
This commit is contained in:
parent
93427ad072
commit
7a3e1bcb2c
15 changed files with 272 additions and 124 deletions
|
@ -37,7 +37,7 @@ def _domains():
|
|||
Fetch a file from DOMAIN_FILE_URL, parse the CSV for the domain,
|
||||
lowercase everything and return the list.
|
||||
"""
|
||||
Domain = apps.get_model("registrar.Domain")
|
||||
DraftDomain = apps.get_model("registrar.DraftDomain")
|
||||
# 5 second timeout
|
||||
file_contents = requests.get(DOMAIN_FILE_URL, timeout=5).text
|
||||
domains = set()
|
||||
|
@ -46,7 +46,7 @@ def _domains():
|
|||
# get the domain before the first comma
|
||||
domain = line.split(",", 1)[0]
|
||||
# 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
|
||||
domains.add(domain.lower())
|
||||
return domains
|
||||
|
@ -75,12 +75,12 @@ def available(request, domain=""):
|
|||
Response is a JSON dictionary with the key "available" and value true or
|
||||
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
|
||||
# not.
|
||||
if not (
|
||||
Domain.string_could_be_domain(domain)
|
||||
or Domain.string_could_be_domain(domain + ".gov")
|
||||
DraftDomain.string_could_be_domain(domain)
|
||||
or DraftDomain.string_could_be_domain(domain + ".gov")
|
||||
):
|
||||
return JsonResponse(
|
||||
{"available": False, "message": DOMAIN_API_MESSAGES["invalid"]}
|
||||
|
|
|
@ -5,7 +5,7 @@ from faker import Faker
|
|||
from registrar.models import (
|
||||
User,
|
||||
DomainApplication,
|
||||
Domain,
|
||||
DraftDomain,
|
||||
Contact,
|
||||
Website,
|
||||
)
|
||||
|
@ -216,11 +216,13 @@ class DomainApplicationFixture:
|
|||
|
||||
if not da.requested_domain:
|
||||
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"]
|
||||
)
|
||||
else:
|
||||
da.requested_domain = Domain.objects.create(name=cls.fake_dot_gov())
|
||||
da.requested_domain = DraftDomain.objects.create(
|
||||
name=cls.fake_dot_gov()
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def _set_many_to_many_relations(cls, da: DomainApplication, app: dict):
|
||||
|
|
|
@ -11,7 +11,7 @@ from django.utils.safestring import mark_safe
|
|||
|
||||
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
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
@ -453,7 +453,7 @@ class AlternativeDomainForm(RegistrarForm):
|
|||
"""Validation code for domain names."""
|
||||
try:
|
||||
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:
|
||||
raise forms.ValidationError(
|
||||
DOMAIN_API_MESSAGES["extra_dots"], code="extra_dots"
|
||||
|
@ -498,7 +498,7 @@ class BaseAlternativeDomainFormSet(RegistrarFormSet):
|
|||
|
||||
@classmethod
|
||||
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
|
||||
def from_database(cls, obj):
|
||||
|
@ -524,7 +524,7 @@ class DotGovDomainForm(RegistrarForm):
|
|||
requested_domain.name = f"{domain}.gov"
|
||||
requested_domain.save()
|
||||
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.save()
|
||||
|
||||
|
@ -535,14 +535,14 @@ class DotGovDomainForm(RegistrarForm):
|
|||
values = {}
|
||||
requested_domain = getattr(obj, "requested_domain", None)
|
||||
if requested_domain is not None:
|
||||
values["requested_domain"] = requested_domain.sld
|
||||
values["requested_domain"] = Domain.sld(requested_domain.name)
|
||||
return values
|
||||
|
||||
def clean_requested_domain(self):
|
||||
"""Validation code for domain names."""
|
||||
try:
|
||||
requested = self.cleaned_data.get("requested_domain", None)
|
||||
validated = Domain.validate(requested)
|
||||
validated = DraftDomain.validate(requested)
|
||||
except errors.BlankValueError:
|
||||
raise forms.ValidationError(
|
||||
DOMAIN_API_MESSAGES["required"], code="required"
|
||||
|
|
|
@ -54,16 +54,6 @@ class Command(BaseCommand):
|
|||
domains = []
|
||||
for row in reader:
|
||||
name = row["Name"].lower() # we typically use lowercase domains
|
||||
|
||||
# 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))
|
||||
domains.append(Domain(name=name))
|
||||
logger.info("Creating %d new domains", len(domains))
|
||||
Domain.objects.bulk_create(domains)
|
||||
|
|
|
@ -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",
|
||||
),
|
||||
),
|
||||
]
|
|
@ -4,6 +4,7 @@ from .contact import Contact
|
|||
from .domain_application import DomainApplication
|
||||
from .domain_information import DomainInformation
|
||||
from .domain import Domain
|
||||
from .draft_domain import DraftDomain
|
||||
from .host_ip import HostIP
|
||||
from .host import Host
|
||||
from .domain_invitation import DomainInvitation
|
||||
|
@ -18,6 +19,7 @@ __all__ = [
|
|||
"DomainApplication",
|
||||
"DomainInformation",
|
||||
"Domain",
|
||||
"DraftDomain",
|
||||
"DomainInvitation",
|
||||
"HostIP",
|
||||
"Host",
|
||||
|
@ -31,6 +33,7 @@ __all__ = [
|
|||
auditlog.register(Contact)
|
||||
auditlog.register(DomainApplication)
|
||||
auditlog.register(Domain)
|
||||
auditlog.register(DraftDomain)
|
||||
auditlog.register(DomainInvitation)
|
||||
auditlog.register(HostIP)
|
||||
auditlog.register(Host)
|
||||
|
|
|
@ -400,10 +400,19 @@ class DomainApplication(TimeStampedModel):
|
|||
related_name="current+",
|
||||
)
|
||||
|
||||
requested_domain = models.OneToOneField(
|
||||
approved_domain = models.OneToOneField(
|
||||
"Domain",
|
||||
null=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",
|
||||
related_name="domain_application",
|
||||
on_delete=models.PROTECT,
|
||||
|
@ -499,8 +508,8 @@ class DomainApplication(TimeStampedModel):
|
|||
if self.requested_domain is None:
|
||||
raise ValueError("Requested domain is missing.")
|
||||
|
||||
Domain = apps.get_model("registrar.Domain")
|
||||
if not Domain.string_could_be_domain(self.requested_domain.name):
|
||||
DraftDomain = apps.get_model("registrar.DraftDomain")
|
||||
if not DraftDomain.string_could_be_domain(self.requested_domain.name):
|
||||
raise ValueError("Requested domain is not a valid domain name.")
|
||||
|
||||
# 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.
|
||||
"""
|
||||
|
||||
# create the domain if it doesn't exist
|
||||
# create the 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
|
||||
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
|
||||
UserDomainRole = apps.get_model("registrar.UserDomainRole")
|
||||
|
|
|
@ -211,24 +211,24 @@ class DomainInformation(TimeStampedModel):
|
|||
return ""
|
||||
|
||||
@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"""
|
||||
da_dict = domain_application.to_dict()
|
||||
# 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
|
||||
# application, if so short circuit the create
|
||||
domain_info = cls.objects.filter(domain_application__id=da_id).first()
|
||||
if domain_info:
|
||||
return domain_info
|
||||
# the following information below is not needed in the domain information:
|
||||
da_dict.pop("status")
|
||||
da_dict.pop("current_websites")
|
||||
da_dict.pop("investigator")
|
||||
da_dict.pop("alternative_domains")
|
||||
# use the requested_domain to create information for this domain
|
||||
da_dict["domain"] = da_dict.pop("requested_domain")
|
||||
other_contacts = da_dict.pop("other_contacts")
|
||||
da_dict.pop("status", None)
|
||||
da_dict.pop("current_websites", None)
|
||||
da_dict.pop("investigator", None)
|
||||
da_dict.pop("alternative_domains", None)
|
||||
da_dict.pop("requested_domain", None)
|
||||
da_dict.pop("approved_domain", None)
|
||||
other_contacts = da_dict.pop("other_contacts", [])
|
||||
domain_info = cls(**da_dict)
|
||||
domain_info.domain_application = domain_application
|
||||
# Save so the object now have PK
|
||||
|
@ -237,6 +237,8 @@ class DomainInformation(TimeStampedModel):
|
|||
|
||||
# Process the remaining "many to many" stuff
|
||||
domain_info.other_contacts.add(*other_contacts)
|
||||
if domain:
|
||||
domain_info.domain = domain
|
||||
domain_info.save()
|
||||
return domain_info
|
||||
|
||||
|
|
22
src/registrar/models/draft_domain.py
Normal file
22
src/registrar/models/draft_domain.py
Normal 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",
|
||||
)
|
64
src/registrar/models/utility/domain_helper.py
Normal file
64
src/registrar/models/utility/domain_helper.py
Normal 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 ""
|
|
@ -1,5 +1,3 @@
|
|||
from django.apps import apps
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.db import models
|
||||
|
||||
from .utility.time_stamped_model import TimeStampedModel
|
||||
|
@ -18,35 +16,5 @@ class Website(TimeStampedModel):
|
|||
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:
|
||||
return str(self.website)
|
||||
|
|
|
@ -5,7 +5,7 @@ from unittest.mock import MagicMock
|
|||
from django.contrib.auth import get_user_model
|
||||
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
|
||||
|
||||
|
@ -28,7 +28,7 @@ class TestEmails(TestCase):
|
|||
email="testy@town.com",
|
||||
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")
|
||||
current, _ = Website.objects.get_or_create(website="city.com")
|
||||
you, _ = Contact.objects.get_or_create(
|
||||
|
|
|
@ -8,6 +8,7 @@ from registrar.models import (
|
|||
User,
|
||||
Website,
|
||||
Domain,
|
||||
DraftDomain,
|
||||
DomainInvitation,
|
||||
UserDomainRole,
|
||||
)
|
||||
|
@ -40,7 +41,7 @@ class TestDomainApplication(TestCase):
|
|||
contact = Contact.objects.create()
|
||||
com_website, _ = Website.objects.get_or_create(website="igorville.com")
|
||||
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(
|
||||
creator=user,
|
||||
investigator=user,
|
||||
|
@ -100,7 +101,7 @@ class TestDomainApplication(TestCase):
|
|||
|
||||
def test_status_fsm_submit_succeed(self):
|
||||
user, _ = User.objects.get_or_create()
|
||||
site = Domain.objects.create(name="igorville.gov")
|
||||
site = DraftDomain.objects.create(name="igorville.gov")
|
||||
application = DomainApplication.objects.create(
|
||||
creator=user, requested_domain=site
|
||||
)
|
||||
|
@ -113,7 +114,7 @@ class TestDomainApplication(TestCase):
|
|||
"""Create an application and submit it and see if email was sent."""
|
||||
user, _ = User.objects.get_or_create()
|
||||
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(
|
||||
creator=user,
|
||||
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):
|
||||
|
||||
"""Test the User-Domain-Role connection."""
|
||||
|
||||
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()
|
||||
application = DomainApplication.objects.create(
|
||||
creator=user, requested_domain=domain
|
||||
creator=user, requested_domain=draft_domain
|
||||
)
|
||||
# skip using the submit method
|
||||
application.status = DomainApplication.SUBMITTED
|
||||
application.approve()
|
||||
|
||||
# should be a role for this user
|
||||
domain = Domain.objects.get(name="igorville.gov")
|
||||
self.assertTrue(UserDomainRole.objects.get(user=user, domain=domain))
|
||||
|
||||
|
||||
|
@ -199,16 +160,17 @@ class TestDomainInfo(TestCase):
|
|||
"""Test creation of Domain Information when approved."""
|
||||
|
||||
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()
|
||||
application = DomainApplication.objects.create(
|
||||
creator=user, requested_domain=domain
|
||||
creator=user, requested_domain=draft_domain
|
||||
)
|
||||
# skip using the submit method
|
||||
application.status = DomainApplication.SUBMITTED
|
||||
application.approve()
|
||||
|
||||
# should be an information present for this domain
|
||||
domain = Domain.objects.get(name="igorville.gov")
|
||||
self.assertTrue(DomainInformation.objects.get(domain=domain))
|
||||
|
||||
|
||||
|
|
54
src/registrar/tests/test_models_domain.py
Normal file
54
src/registrar/tests/test_models_domain.py
Normal 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()
|
|
@ -13,6 +13,7 @@ import boto3_mocking # type: ignore
|
|||
from registrar.models import (
|
||||
DomainApplication,
|
||||
Domain,
|
||||
DraftDomain,
|
||||
DomainInvitation,
|
||||
Contact,
|
||||
Website,
|
||||
|
@ -75,7 +76,7 @@ class LoggedInTests(TestWithUser):
|
|||
def test_home_lists_domain_applications(self):
|
||||
response = self.client.get("/")
|
||||
self.assertNotContains(response, "igorville.gov")
|
||||
site = Domain.objects.create(name="igorville.gov")
|
||||
site = DraftDomain.objects.create(name="igorville.gov")
|
||||
application = DomainApplication.objects.create(
|
||||
creator=self.user, requested_domain=site
|
||||
)
|
||||
|
@ -1035,6 +1036,8 @@ class TestWithDomainPermissions(TestWithUser):
|
|||
|
||||
def tearDown(self):
|
||||
try:
|
||||
if hasattr(self.domain, "contacts"):
|
||||
self.domain.contacts.all().delete()
|
||||
self.domain.delete()
|
||||
self.role.delete()
|
||||
except ValueError: # pass if already deleted
|
||||
|
@ -1347,7 +1350,7 @@ class TestApplicationStatus(TestWithUser, WebTest):
|
|||
email="testy@town.com",
|
||||
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")
|
||||
current, _ = Website.objects.get_or_create(website="city.com")
|
||||
you, _ = Contact.objects.get_or_create(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue