mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-08-23 17:51:03 +02:00
Merge pull request #582 from cisagov/jon/541
Domain Application Information 🎉
This commit is contained in:
commit
1ec355290e
8 changed files with 652 additions and 1 deletions
|
@ -55,6 +55,7 @@ admin.site.register(models.UserDomainRole, AuditedAdmin)
|
||||||
admin.site.register(models.Contact, AuditedAdmin)
|
admin.site.register(models.Contact, AuditedAdmin)
|
||||||
admin.site.register(models.DomainInvitation, AuditedAdmin)
|
admin.site.register(models.DomainInvitation, AuditedAdmin)
|
||||||
admin.site.register(models.DomainApplication, AuditedAdmin)
|
admin.site.register(models.DomainApplication, AuditedAdmin)
|
||||||
|
admin.site.register(models.DomainInformation, AuditedAdmin)
|
||||||
admin.site.register(models.Domain, AuditedAdmin)
|
admin.site.register(models.Domain, AuditedAdmin)
|
||||||
admin.site.register(models.Host, MyHostAdmin)
|
admin.site.register(models.Host, MyHostAdmin)
|
||||||
admin.site.register(models.Nameserver, MyHostAdmin)
|
admin.site.register(models.Nameserver, MyHostAdmin)
|
||||||
|
|
|
@ -44,6 +44,11 @@ class UserFixture:
|
||||||
"first_name": "Neil",
|
"first_name": "Neil",
|
||||||
"last_name": "Martinsen-Burrell",
|
"last_name": "Martinsen-Burrell",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"username": "7185e6cd-d3c8-4adc-90a3-ceddba71d24f",
|
||||||
|
"first_name": "Jon",
|
||||||
|
"last_name": "Roberts",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"username": "5f283494-31bd-49b5-b024-a7e7cae00848",
|
"username": "5f283494-31bd-49b5-b024-a7e7cae00848",
|
||||||
"first_name": "Rachid",
|
"first_name": "Rachid",
|
||||||
|
|
273
src/registrar/migrations/0018_domaininformation.py
Normal file
273
src/registrar/migrations/0018_domaininformation.py
Normal file
|
@ -0,0 +1,273 @@
|
||||||
|
# Generated by Django 4.1.6 on 2023-05-08 15:30
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
("registrar", "0017_alter_domainapplication_status_and_more"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="DomainInformation",
|
||||||
|
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)),
|
||||||
|
(
|
||||||
|
"organization_type",
|
||||||
|
models.CharField(
|
||||||
|
blank=True,
|
||||||
|
choices=[
|
||||||
|
(
|
||||||
|
"federal",
|
||||||
|
"Federal: an agency of the U.S. government's executive, legislative, or judicial branches",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"interstate",
|
||||||
|
"Interstate: an organization of two or more states",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"state_or_territory",
|
||||||
|
"State or territory: one of the 50 U.S. states, the District of Columbia, American Samoa, Guam, Northern Mariana Islands, Puerto Rico, or the U.S. Virgin Islands",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"tribal",
|
||||||
|
"Tribal: a tribal government recognized by the federal or a state government",
|
||||||
|
),
|
||||||
|
("county", "County: a county, parish, or borough"),
|
||||||
|
("city", "City: a city, town, township, village, etc."),
|
||||||
|
(
|
||||||
|
"special_district",
|
||||||
|
"Special district: an independent organization within a single state",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"school_district",
|
||||||
|
"School district: a school district that is not part of a local government",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
help_text="Type of Organization",
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"federally_recognized_tribe",
|
||||||
|
models.BooleanField(
|
||||||
|
help_text="Is the tribe federally recognized", null=True
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"state_recognized_tribe",
|
||||||
|
models.BooleanField(
|
||||||
|
help_text="Is the tribe recognized by a state", null=True
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"tribe_name",
|
||||||
|
models.TextField(blank=True, help_text="Name of tribe", null=True),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"federal_agency",
|
||||||
|
models.TextField(blank=True, help_text="Federal agency", null=True),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"federal_type",
|
||||||
|
models.CharField(
|
||||||
|
blank=True,
|
||||||
|
choices=[
|
||||||
|
("executive", "Executive"),
|
||||||
|
("judicial", "Judicial"),
|
||||||
|
("legislative", "Legislative"),
|
||||||
|
],
|
||||||
|
help_text="Federal government branch",
|
||||||
|
max_length=50,
|
||||||
|
null=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"is_election_board",
|
||||||
|
models.BooleanField(
|
||||||
|
blank=True,
|
||||||
|
help_text="Is your organization an election office?",
|
||||||
|
null=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"organization_name",
|
||||||
|
models.TextField(
|
||||||
|
blank=True,
|
||||||
|
db_index=True,
|
||||||
|
help_text="Organization name",
|
||||||
|
null=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"address_line1",
|
||||||
|
models.TextField(blank=True, help_text="Street address", null=True),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"address_line2",
|
||||||
|
models.CharField(
|
||||||
|
blank=True,
|
||||||
|
help_text="Street address line 2",
|
||||||
|
max_length=15,
|
||||||
|
null=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("city", models.TextField(blank=True, help_text="City", null=True)),
|
||||||
|
(
|
||||||
|
"state_territory",
|
||||||
|
models.CharField(
|
||||||
|
blank=True,
|
||||||
|
help_text="State, territory, or military post",
|
||||||
|
max_length=2,
|
||||||
|
null=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"zipcode",
|
||||||
|
models.CharField(
|
||||||
|
blank=True,
|
||||||
|
db_index=True,
|
||||||
|
help_text="Zip code",
|
||||||
|
max_length=10,
|
||||||
|
null=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"urbanization",
|
||||||
|
models.TextField(
|
||||||
|
blank=True,
|
||||||
|
help_text="Urbanization (Puerto Rico only)",
|
||||||
|
null=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"type_of_work",
|
||||||
|
models.TextField(
|
||||||
|
blank=True,
|
||||||
|
help_text="Type of work of the organization",
|
||||||
|
null=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"more_organization_information",
|
||||||
|
models.TextField(
|
||||||
|
blank=True,
|
||||||
|
help_text="Further information about the government organization",
|
||||||
|
null=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"purpose",
|
||||||
|
models.TextField(
|
||||||
|
blank=True, help_text="Purpose of your domain", null=True
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"no_other_contacts_rationale",
|
||||||
|
models.TextField(
|
||||||
|
blank=True,
|
||||||
|
help_text="Reason for listing no additional contacts",
|
||||||
|
null=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"anything_else",
|
||||||
|
models.TextField(
|
||||||
|
blank=True, help_text="Anything else we should know?", null=True
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"is_policy_acknowledged",
|
||||||
|
models.BooleanField(
|
||||||
|
blank=True,
|
||||||
|
help_text="Acknowledged .gov acceptable use policy",
|
||||||
|
null=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"security_email",
|
||||||
|
models.EmailField(
|
||||||
|
blank=True,
|
||||||
|
help_text="Security email for public use",
|
||||||
|
max_length=320,
|
||||||
|
null=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"authorizing_official",
|
||||||
|
models.ForeignKey(
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.PROTECT,
|
||||||
|
related_name="information_authorizing_official",
|
||||||
|
to="registrar.contact",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"creator",
|
||||||
|
models.ForeignKey(
|
||||||
|
on_delete=django.db.models.deletion.PROTECT,
|
||||||
|
related_name="information_created",
|
||||||
|
to=settings.AUTH_USER_MODEL,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"domain",
|
||||||
|
models.OneToOneField(
|
||||||
|
blank=True,
|
||||||
|
help_text="Domain to which this information belongs",
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.PROTECT,
|
||||||
|
related_name="domain_info",
|
||||||
|
to="registrar.domain",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"domain_application",
|
||||||
|
models.OneToOneField(
|
||||||
|
blank=True,
|
||||||
|
help_text="Associated domain application",
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.PROTECT,
|
||||||
|
related_name="domainapplication_info",
|
||||||
|
to="registrar.domainapplication",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"other_contacts",
|
||||||
|
models.ManyToManyField(
|
||||||
|
blank=True,
|
||||||
|
related_name="contact_applications_information",
|
||||||
|
to="registrar.contact",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"submitter",
|
||||||
|
models.ForeignKey(
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.PROTECT,
|
||||||
|
related_name="submitted_applications_information",
|
||||||
|
to="registrar.contact",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
"verbose_name_plural": "Domain Information",
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,47 @@
|
||||||
|
# Generated by Django 4.1.6 on 2023-05-09 19:50
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
("registrar", "0018_domaininformation"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="domainapplication",
|
||||||
|
name="organization_type",
|
||||||
|
field=models.CharField(
|
||||||
|
blank=True,
|
||||||
|
choices=[
|
||||||
|
(
|
||||||
|
"federal",
|
||||||
|
"Federal: an agency of the U.S. government's executive, legislative, or judicial branches",
|
||||||
|
),
|
||||||
|
("interstate", "Interstate: an organization of two or more states"),
|
||||||
|
(
|
||||||
|
"state_or_territory",
|
||||||
|
"State or territory: one of the 50 U.S. states, the District of Columbia, American Samoa, Guam, Northern Mariana Islands, Puerto Rico, or the U.S. Virgin Islands",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"tribal",
|
||||||
|
"Tribal: a tribal government recognized by the federal or a state government",
|
||||||
|
),
|
||||||
|
("county", "County: a county, parish, or borough"),
|
||||||
|
("city", "City: a city, town, township, village, etc."),
|
||||||
|
(
|
||||||
|
"special_district",
|
||||||
|
"Special district: an independent organization within a single state",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"school_district",
|
||||||
|
"School district: a school district that is not part of a local government",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
help_text="Type of organization",
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
|
@ -2,6 +2,7 @@ from auditlog.registry import auditlog # type: ignore
|
||||||
|
|
||||||
from .contact import Contact
|
from .contact import Contact
|
||||||
from .domain_application import DomainApplication
|
from .domain_application import DomainApplication
|
||||||
|
from .domain_information import DomainInformation
|
||||||
from .domain import Domain
|
from .domain import Domain
|
||||||
from .host_ip import HostIP
|
from .host_ip import HostIP
|
||||||
from .host import Host
|
from .host import Host
|
||||||
|
@ -15,6 +16,7 @@ from .website import Website
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"Contact",
|
"Contact",
|
||||||
"DomainApplication",
|
"DomainApplication",
|
||||||
|
"DomainInformation",
|
||||||
"Domain",
|
"Domain",
|
||||||
"DomainInvitation",
|
"DomainInvitation",
|
||||||
"HostIP",
|
"HostIP",
|
||||||
|
|
|
@ -9,7 +9,7 @@ from django_fsm import FSMField, transition # type: ignore
|
||||||
|
|
||||||
from .utility.time_stamped_model import TimeStampedModel
|
from .utility.time_stamped_model import TimeStampedModel
|
||||||
from ..utility.email import send_templated_email, EmailSendingError
|
from ..utility.email import send_templated_email, EmailSendingError
|
||||||
|
from itertools import chain
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -520,6 +520,10 @@ class DomainApplication(TimeStampedModel):
|
||||||
Domain = apps.get_model("registrar.Domain")
|
Domain = apps.get_model("registrar.Domain")
|
||||||
created_domain, _ = Domain.objects.get_or_create(name=self.requested_domain)
|
created_domain, _ = Domain.objects.get_or_create(name=self.requested_domain)
|
||||||
|
|
||||||
|
# copy the information from domainapplication into domaininformation
|
||||||
|
DomainInformation = apps.get_model("registrar.DomainInformation")
|
||||||
|
DomainInformation.create_from_da(self)
|
||||||
|
|
||||||
# create the permission for the user
|
# create the permission for the user
|
||||||
UserDomainRole = apps.get_model("registrar.UserDomainRole")
|
UserDomainRole = apps.get_model("registrar.UserDomainRole")
|
||||||
UserDomainRole.objects.get_or_create(
|
UserDomainRole.objects.get_or_create(
|
||||||
|
@ -577,3 +581,26 @@ class DomainApplication(TimeStampedModel):
|
||||||
if self.organization_type == DomainApplication.OrganizationChoices.FEDERAL:
|
if self.organization_type == DomainApplication.OrganizationChoices.FEDERAL:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def to_dict(self):
|
||||||
|
"""This is to process to_dict for Domain Information, making it friendly
|
||||||
|
to "copy" it
|
||||||
|
|
||||||
|
More information can be found at this- (This used #5)
|
||||||
|
https://stackoverflow.com/questions/21925671/convert-django-model-object-to-dict-with-all-of-the-fields-intact/29088221#29088221
|
||||||
|
""" # noqa 590
|
||||||
|
opts = self._meta
|
||||||
|
data = {}
|
||||||
|
for field in chain(opts.concrete_fields, opts.private_fields):
|
||||||
|
if field.get_internal_type() in ("ForeignKey", "OneToOneField"):
|
||||||
|
# get the related instance of the FK value
|
||||||
|
fk_id = field.value_from_object(self)
|
||||||
|
if fk_id:
|
||||||
|
data[field.name] = field.related_model.objects.get(id=fk_id)
|
||||||
|
else:
|
||||||
|
data[field.name] = None
|
||||||
|
else:
|
||||||
|
data[field.name] = field.value_from_object(self)
|
||||||
|
for field in opts.many_to_many:
|
||||||
|
data[field.name] = field.value_from_object(self)
|
||||||
|
return data
|
||||||
|
|
250
src/registrar/models/domain_information.py
Normal file
250
src/registrar/models/domain_information.py
Normal file
|
@ -0,0 +1,250 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
from .domain_application import DomainApplication
|
||||||
|
from .utility.time_stamped_model import TimeStampedModel
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class DomainInformation(TimeStampedModel):
|
||||||
|
|
||||||
|
"""A registrant's domain information for that domain, exported from
|
||||||
|
DomainApplication. We use these field from DomainApplication with few exceptation
|
||||||
|
which are 'removed' via pop at the bottom of this file. Most of design for domain
|
||||||
|
management's user information are based on application, but we cannot change
|
||||||
|
the application once approved, so copying them that way we can make changes
|
||||||
|
after its approved. Most fields here are copied from Application."""
|
||||||
|
|
||||||
|
StateTerritoryChoices = DomainApplication.StateTerritoryChoices
|
||||||
|
|
||||||
|
OrganizationChoices = DomainApplication.OrganizationChoices
|
||||||
|
|
||||||
|
BranchChoices = DomainApplication.BranchChoices
|
||||||
|
|
||||||
|
AGENCY_CHOICES = DomainApplication.AGENCY_CHOICES
|
||||||
|
|
||||||
|
# This is the application user who created this application. The contact
|
||||||
|
# information that they gave is in the `submitter` field
|
||||||
|
creator = models.ForeignKey(
|
||||||
|
"registrar.User",
|
||||||
|
on_delete=models.PROTECT,
|
||||||
|
related_name="information_created",
|
||||||
|
)
|
||||||
|
|
||||||
|
domain_application = models.OneToOneField(
|
||||||
|
"registrar.DomainApplication",
|
||||||
|
on_delete=models.PROTECT,
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
related_name="domainapplication_info",
|
||||||
|
help_text="Associated domain application",
|
||||||
|
unique=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
# ##### data fields from the initial form #####
|
||||||
|
organization_type = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
choices=OrganizationChoices.choices,
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
help_text="Type of Organization",
|
||||||
|
)
|
||||||
|
|
||||||
|
federally_recognized_tribe = models.BooleanField(
|
||||||
|
null=True,
|
||||||
|
help_text="Is the tribe federally recognized",
|
||||||
|
)
|
||||||
|
|
||||||
|
state_recognized_tribe = models.BooleanField(
|
||||||
|
null=True,
|
||||||
|
help_text="Is the tribe recognized by a state",
|
||||||
|
)
|
||||||
|
|
||||||
|
tribe_name = models.TextField(
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
help_text="Name of tribe",
|
||||||
|
)
|
||||||
|
|
||||||
|
federal_agency = models.TextField(
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
help_text="Federal agency",
|
||||||
|
)
|
||||||
|
|
||||||
|
federal_type = models.CharField(
|
||||||
|
max_length=50,
|
||||||
|
choices=BranchChoices.choices,
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
help_text="Federal government branch",
|
||||||
|
)
|
||||||
|
|
||||||
|
is_election_board = models.BooleanField(
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
help_text="Is your organization an election office?",
|
||||||
|
)
|
||||||
|
|
||||||
|
organization_name = models.TextField(
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
help_text="Organization name",
|
||||||
|
db_index=True,
|
||||||
|
)
|
||||||
|
address_line1 = models.TextField(
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
help_text="Street address",
|
||||||
|
)
|
||||||
|
address_line2 = models.CharField(
|
||||||
|
max_length=15,
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
help_text="Street address line 2",
|
||||||
|
)
|
||||||
|
city = models.TextField(
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
help_text="City",
|
||||||
|
)
|
||||||
|
state_territory = models.CharField(
|
||||||
|
max_length=2,
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
help_text="State, territory, or military post",
|
||||||
|
)
|
||||||
|
zipcode = models.CharField(
|
||||||
|
max_length=10,
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
help_text="Zip code",
|
||||||
|
db_index=True,
|
||||||
|
)
|
||||||
|
urbanization = models.TextField(
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
help_text="Urbanization (Puerto Rico only)",
|
||||||
|
)
|
||||||
|
|
||||||
|
type_of_work = models.TextField(
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
help_text="Type of work of the organization",
|
||||||
|
)
|
||||||
|
|
||||||
|
more_organization_information = models.TextField(
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
help_text="Further information about the government organization",
|
||||||
|
)
|
||||||
|
|
||||||
|
authorizing_official = models.ForeignKey(
|
||||||
|
"registrar.Contact",
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
related_name="information_authorizing_official",
|
||||||
|
on_delete=models.PROTECT,
|
||||||
|
)
|
||||||
|
|
||||||
|
domain = models.OneToOneField(
|
||||||
|
"registrar.Domain",
|
||||||
|
on_delete=models.PROTECT,
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
# Access this information via Domain as "domain.domain_info"
|
||||||
|
related_name="domain_info",
|
||||||
|
help_text="Domain to which this information belongs",
|
||||||
|
)
|
||||||
|
|
||||||
|
# This is the contact information provided by the applicant. The
|
||||||
|
# application user who created it is in the `creator` field.
|
||||||
|
submitter = models.ForeignKey(
|
||||||
|
"registrar.Contact",
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
related_name="submitted_applications_information",
|
||||||
|
on_delete=models.PROTECT,
|
||||||
|
)
|
||||||
|
|
||||||
|
purpose = models.TextField(
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
help_text="Purpose of your domain",
|
||||||
|
)
|
||||||
|
|
||||||
|
other_contacts = models.ManyToManyField(
|
||||||
|
"registrar.Contact",
|
||||||
|
blank=True,
|
||||||
|
related_name="contact_applications_information",
|
||||||
|
)
|
||||||
|
|
||||||
|
no_other_contacts_rationale = models.TextField(
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
help_text="Reason for listing no additional contacts",
|
||||||
|
)
|
||||||
|
|
||||||
|
anything_else = models.TextField(
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
help_text="Anything else we should know?",
|
||||||
|
)
|
||||||
|
|
||||||
|
is_policy_acknowledged = models.BooleanField(
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
help_text="Acknowledged .gov acceptable use policy",
|
||||||
|
)
|
||||||
|
security_email = models.EmailField(
|
||||||
|
max_length=320,
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
help_text="Security email for public use",
|
||||||
|
)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
try:
|
||||||
|
if self.domain and self.domain.name:
|
||||||
|
return self.domain.name
|
||||||
|
else:
|
||||||
|
return f"domain info set up and created by {self.creator}"
|
||||||
|
except Exception:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def create_from_da(cls, domain_application):
|
||||||
|
"""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")
|
||||||
|
# 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")
|
||||||
|
domain_info = cls(**da_dict)
|
||||||
|
domain_info.domain_application = domain_application
|
||||||
|
# Save so the object now have PK
|
||||||
|
# (needed to process the manytomany below before, first)
|
||||||
|
domain_info.save()
|
||||||
|
|
||||||
|
# Process the remaining "many to many" stuff
|
||||||
|
domain_info.other_contacts.add(*other_contacts)
|
||||||
|
domain_info.save()
|
||||||
|
return domain_info
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name_plural = "Domain Information"
|
|
@ -4,6 +4,7 @@ from django.db.utils import IntegrityError
|
||||||
from registrar.models import (
|
from registrar.models import (
|
||||||
Contact,
|
Contact,
|
||||||
DomainApplication,
|
DomainApplication,
|
||||||
|
DomainInformation,
|
||||||
User,
|
User,
|
||||||
Website,
|
Website,
|
||||||
Domain,
|
Domain,
|
||||||
|
@ -63,6 +64,33 @@ class TestDomainApplication(TestCase):
|
||||||
application.other_contacts.add(contact)
|
application.other_contacts.add(contact)
|
||||||
application.save()
|
application.save()
|
||||||
|
|
||||||
|
def test_domain_info(self):
|
||||||
|
"""Can create domain info with all fields."""
|
||||||
|
user, _ = User.objects.get_or_create()
|
||||||
|
contact = Contact.objects.create()
|
||||||
|
domain, _ = Domain.objects.get_or_create(name="igorville.gov")
|
||||||
|
information = DomainInformation.objects.create(
|
||||||
|
creator=user,
|
||||||
|
organization_type=DomainInformation.OrganizationChoices.FEDERAL,
|
||||||
|
federal_type=DomainInformation.BranchChoices.EXECUTIVE,
|
||||||
|
is_election_board=False,
|
||||||
|
organization_name="Test",
|
||||||
|
address_line1="100 Main St.",
|
||||||
|
address_line2="APT 1A",
|
||||||
|
state_territory="CA",
|
||||||
|
zipcode="12345-6789",
|
||||||
|
authorizing_official=contact,
|
||||||
|
submitter=contact,
|
||||||
|
purpose="Igorville rules!",
|
||||||
|
anything_else="All of Igorville loves the dotgov program.",
|
||||||
|
is_policy_acknowledged=True,
|
||||||
|
domain=domain,
|
||||||
|
)
|
||||||
|
information.other_contacts.add(contact)
|
||||||
|
information.save()
|
||||||
|
self.assertEqual(information.domain.id, domain.id)
|
||||||
|
self.assertEqual(information.id, domain.domain_info.id)
|
||||||
|
|
||||||
def test_status_fsm_submit_fail(self):
|
def test_status_fsm_submit_fail(self):
|
||||||
user, _ = User.objects.get_or_create()
|
user, _ = User.objects.get_or_create()
|
||||||
application = DomainApplication.objects.create(creator=user)
|
application = DomainApplication.objects.create(creator=user)
|
||||||
|
@ -166,6 +194,24 @@ class TestPermissions(TestCase):
|
||||||
self.assertTrue(UserDomainRole.objects.get(user=user, domain=domain))
|
self.assertTrue(UserDomainRole.objects.get(user=user, domain=domain))
|
||||||
|
|
||||||
|
|
||||||
|
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")
|
||||||
|
user, _ = User.objects.get_or_create()
|
||||||
|
application = DomainApplication.objects.create(
|
||||||
|
creator=user, requested_domain=domain
|
||||||
|
)
|
||||||
|
# skip using the submit method
|
||||||
|
application.status = DomainApplication.SUBMITTED
|
||||||
|
application.approve()
|
||||||
|
|
||||||
|
# should be an information present for this domain
|
||||||
|
self.assertTrue(DomainInformation.objects.get(domain=domain))
|
||||||
|
|
||||||
|
|
||||||
class TestInvitations(TestCase):
|
class TestInvitations(TestCase):
|
||||||
|
|
||||||
"""Test the retrieval of invitations."""
|
"""Test the retrieval of invitations."""
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue