mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-05-19 19:09:22 +02:00
Merge pull request #1965 from cisagov/za/1909-change-org-field-to-new-format
Ticket #1909: Change organization field to support new format
This commit is contained in:
commit
7cecd84fbd
12 changed files with 809 additions and 25 deletions
|
@ -901,6 +901,7 @@ class DomainInformationAdmin(ListHeaderAdmin):
|
||||||
"fields": [
|
"fields": [
|
||||||
"generic_org_type",
|
"generic_org_type",
|
||||||
"is_election_board",
|
"is_election_board",
|
||||||
|
"organization_type",
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -943,7 +944,7 @@ class DomainInformationAdmin(ListHeaderAdmin):
|
||||||
]
|
]
|
||||||
|
|
||||||
# Readonly fields for analysts and superusers
|
# Readonly fields for analysts and superusers
|
||||||
readonly_fields = ("other_contacts",)
|
readonly_fields = ("other_contacts", "generic_org_type", "is_election_board")
|
||||||
|
|
||||||
# Read only that we'll leverage for CISA Analysts
|
# Read only that we'll leverage for CISA Analysts
|
||||||
analyst_readonly_fields = [
|
analyst_readonly_fields = [
|
||||||
|
@ -1139,6 +1140,7 @@ class DomainRequestAdmin(ListHeaderAdmin):
|
||||||
"fields": [
|
"fields": [
|
||||||
"generic_org_type",
|
"generic_org_type",
|
||||||
"is_election_board",
|
"is_election_board",
|
||||||
|
"organization_type",
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -1181,7 +1183,13 @@ class DomainRequestAdmin(ListHeaderAdmin):
|
||||||
]
|
]
|
||||||
|
|
||||||
# Readonly fields for analysts and superusers
|
# Readonly fields for analysts and superusers
|
||||||
readonly_fields = ("other_contacts", "current_websites", "alternative_domains")
|
readonly_fields = (
|
||||||
|
"other_contacts",
|
||||||
|
"current_websites",
|
||||||
|
"alternative_domains",
|
||||||
|
"generic_org_type",
|
||||||
|
"is_election_board",
|
||||||
|
)
|
||||||
|
|
||||||
# Read only that we'll leverage for CISA Analysts
|
# Read only that we'll leverage for CISA Analysts
|
||||||
analyst_readonly_fields = [
|
analyst_readonly_fields = [
|
||||||
|
|
|
@ -98,6 +98,8 @@ class DomainRequestFixture:
|
||||||
def _set_non_foreign_key_fields(cls, da: DomainRequest, app: dict):
|
def _set_non_foreign_key_fields(cls, da: DomainRequest, app: dict):
|
||||||
"""Helper method used by `load`."""
|
"""Helper method used by `load`."""
|
||||||
da.status = app["status"] if "status" in app else "started"
|
da.status = app["status"] if "status" in app else "started"
|
||||||
|
|
||||||
|
# TODO for a future ticket: Allow for more than just "federal" here
|
||||||
da.generic_org_type = app["generic_org_type"] if "generic_org_type" in app else "federal"
|
da.generic_org_type = app["generic_org_type"] if "generic_org_type" in app else "federal"
|
||||||
da.federal_agency = (
|
da.federal_agency = (
|
||||||
app["federal_agency"]
|
app["federal_agency"]
|
||||||
|
@ -235,9 +237,6 @@ class DomainFixture(DomainRequestFixture):
|
||||||
).last()
|
).last()
|
||||||
logger.debug(f"Approving {domain_request} for {user}")
|
logger.debug(f"Approving {domain_request} for {user}")
|
||||||
|
|
||||||
# We don't want fixtures sending out real emails to
|
|
||||||
# fake email addresses, so we just skip that and log it instead
|
|
||||||
|
|
||||||
# All approvals require an investigator, so if there is none,
|
# All approvals require an investigator, so if there is none,
|
||||||
# assign one.
|
# assign one.
|
||||||
if domain_request.investigator is None:
|
if domain_request.investigator is None:
|
||||||
|
|
|
@ -0,0 +1,83 @@
|
||||||
|
# Generated by Django 4.2.10 on 2024-04-01 15:32
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("registrar", "0081_create_groups_v10"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="domaininformation",
|
||||||
|
name="organization_type",
|
||||||
|
field=models.CharField(
|
||||||
|
blank=True,
|
||||||
|
choices=[
|
||||||
|
("federal", "Federal"),
|
||||||
|
("interstate", "Interstate"),
|
||||||
|
("state_or_territory", "State or territory"),
|
||||||
|
("tribal", "Tribal"),
|
||||||
|
("county", "County"),
|
||||||
|
("city", "City"),
|
||||||
|
("special_district", "Special district"),
|
||||||
|
("school_district", "School district"),
|
||||||
|
("state_or_territory_election", "State or territory - Election"),
|
||||||
|
("tribal_election", "Tribal - Election"),
|
||||||
|
("county_election", "County - Election"),
|
||||||
|
("city_election", "City - Election"),
|
||||||
|
("special_district_election", "Special district - Election"),
|
||||||
|
],
|
||||||
|
help_text="Type of organization - Election office",
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="domainrequest",
|
||||||
|
name="organization_type",
|
||||||
|
field=models.CharField(
|
||||||
|
blank=True,
|
||||||
|
choices=[
|
||||||
|
("federal", "Federal"),
|
||||||
|
("interstate", "Interstate"),
|
||||||
|
("state_or_territory", "State or territory"),
|
||||||
|
("tribal", "Tribal"),
|
||||||
|
("county", "County"),
|
||||||
|
("city", "City"),
|
||||||
|
("special_district", "Special district"),
|
||||||
|
("school_district", "School district"),
|
||||||
|
("state_or_territory_election", "State or territory - Election"),
|
||||||
|
("tribal_election", "Tribal - Election"),
|
||||||
|
("county_election", "County - Election"),
|
||||||
|
("city_election", "City - Election"),
|
||||||
|
("special_district_election", "Special district - Election"),
|
||||||
|
],
|
||||||
|
help_text="Type of organization - Election office",
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="domaininformation",
|
||||||
|
name="generic_org_type",
|
||||||
|
field=models.CharField(
|
||||||
|
blank=True,
|
||||||
|
choices=[
|
||||||
|
("federal", "Federal"),
|
||||||
|
("interstate", "Interstate"),
|
||||||
|
("state_or_territory", "State or territory"),
|
||||||
|
("tribal", "Tribal"),
|
||||||
|
("county", "County"),
|
||||||
|
("city", "City"),
|
||||||
|
("special_district", "Special district"),
|
||||||
|
("school_district", "School district"),
|
||||||
|
],
|
||||||
|
help_text="Type of organization",
|
||||||
|
max_length=255,
|
||||||
|
null=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
|
@ -198,7 +198,6 @@ class Domain(TimeStampedModel, DomainHelper):
|
||||||
is called in the validate function on the request/domain page
|
is called in the validate function on the request/domain page
|
||||||
|
|
||||||
throws- RegistryError or InvalidDomainError"""
|
throws- RegistryError or InvalidDomainError"""
|
||||||
|
|
||||||
if not cls.string_could_be_domain(domain):
|
if not cls.string_could_be_domain(domain):
|
||||||
logger.warning("Not a valid domain: %s" % str(domain))
|
logger.warning("Not a valid domain: %s" % str(domain))
|
||||||
# throw invalid domain error so that it can be caught in
|
# throw invalid domain error so that it can be caught in
|
||||||
|
|
|
@ -2,6 +2,7 @@ from __future__ import annotations
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
|
|
||||||
from registrar.models.utility.domain_helper import DomainHelper
|
from registrar.models.utility.domain_helper import DomainHelper
|
||||||
|
from registrar.models.utility.generic_helper import CreateOrUpdateOrganizationTypeHelper
|
||||||
from .domain_request import DomainRequest
|
from .domain_request import DomainRequest
|
||||||
from .utility.time_stamped_model import TimeStampedModel
|
from .utility.time_stamped_model import TimeStampedModel
|
||||||
|
|
||||||
|
@ -54,7 +55,23 @@ class DomainInformation(TimeStampedModel):
|
||||||
choices=OrganizationChoices.choices,
|
choices=OrganizationChoices.choices,
|
||||||
null=True,
|
null=True,
|
||||||
blank=True,
|
blank=True,
|
||||||
help_text="Type of Organization",
|
help_text="Type of organization",
|
||||||
|
)
|
||||||
|
|
||||||
|
# TODO - Ticket #1911: stub this data from DomainRequest
|
||||||
|
is_election_board = models.BooleanField(
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
help_text="Is your organization an election office?",
|
||||||
|
)
|
||||||
|
|
||||||
|
# TODO - Ticket #1911: stub this data from DomainRequest
|
||||||
|
organization_type = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
choices=DomainRequest.OrgChoicesElectionOffice.choices,
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
help_text="Type of organization - Election office",
|
||||||
)
|
)
|
||||||
|
|
||||||
federally_recognized_tribe = models.BooleanField(
|
federally_recognized_tribe = models.BooleanField(
|
||||||
|
@ -219,6 +236,34 @@ class DomainInformation(TimeStampedModel):
|
||||||
except Exception:
|
except Exception:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
def save(self, *args, **kwargs):
|
||||||
|
"""Save override for custom properties"""
|
||||||
|
|
||||||
|
# Define mappings between generic org and election org.
|
||||||
|
# These have to be defined here, as you'd get a cyclical import error
|
||||||
|
# otherwise.
|
||||||
|
|
||||||
|
# For any given organization type, return the "_election" variant.
|
||||||
|
# For example: STATE_OR_TERRITORY => STATE_OR_TERRITORY_ELECTION
|
||||||
|
generic_org_map = DomainRequest.OrgChoicesElectionOffice.get_org_generic_to_org_election()
|
||||||
|
|
||||||
|
# For any given "_election" variant, return the base org type.
|
||||||
|
# For example: STATE_OR_TERRITORY_ELECTION => STATE_OR_TERRITORY
|
||||||
|
election_org_map = DomainRequest.OrgChoicesElectionOffice.get_org_election_to_org_generic()
|
||||||
|
|
||||||
|
# Manages the "organization_type" variable and keeps in sync with
|
||||||
|
# "is_election_office" and "generic_organization_type"
|
||||||
|
org_type_helper = CreateOrUpdateOrganizationTypeHelper(
|
||||||
|
sender=self.__class__,
|
||||||
|
instance=self,
|
||||||
|
generic_org_to_org_map=generic_org_map,
|
||||||
|
election_org_to_generic_org_map=election_org_map,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Actually updates the organization_type field
|
||||||
|
org_type_helper.create_or_update_organization_type()
|
||||||
|
super().save(*args, **kwargs)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create_from_da(cls, domain_request: DomainRequest, domain=None):
|
def create_from_da(cls, domain_request: DomainRequest, domain=None):
|
||||||
"""Takes in a DomainRequest and converts it into DomainInformation"""
|
"""Takes in a DomainRequest and converts it into DomainInformation"""
|
||||||
|
|
|
@ -9,6 +9,7 @@ from django.db import models
|
||||||
from django_fsm import FSMField, transition # type: ignore
|
from django_fsm import FSMField, transition # type: ignore
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from registrar.models.domain import Domain
|
from registrar.models.domain import Domain
|
||||||
|
from registrar.models.utility.generic_helper import CreateOrUpdateOrganizationTypeHelper
|
||||||
from registrar.utility.errors import FSMDomainRequestError, FSMErrorCodes
|
from registrar.utility.errors import FSMDomainRequestError, FSMErrorCodes
|
||||||
|
|
||||||
from .utility.time_stamped_model import TimeStampedModel
|
from .utility.time_stamped_model import TimeStampedModel
|
||||||
|
@ -100,8 +101,8 @@ class DomainRequest(TimeStampedModel):
|
||||||
class OrganizationChoices(models.TextChoices):
|
class OrganizationChoices(models.TextChoices):
|
||||||
"""
|
"""
|
||||||
Primary organization choices:
|
Primary organization choices:
|
||||||
For use in django admin
|
For use in the domain request experience
|
||||||
Keys need to match OrganizationChoicesVerbose
|
Keys need to match OrgChoicesElectionOffice and OrganizationChoicesVerbose
|
||||||
"""
|
"""
|
||||||
|
|
||||||
FEDERAL = "federal", "Federal"
|
FEDERAL = "federal", "Federal"
|
||||||
|
@ -113,9 +114,77 @@ class DomainRequest(TimeStampedModel):
|
||||||
SPECIAL_DISTRICT = "special_district", "Special district"
|
SPECIAL_DISTRICT = "special_district", "Special district"
|
||||||
SCHOOL_DISTRICT = "school_district", "School district"
|
SCHOOL_DISTRICT = "school_district", "School district"
|
||||||
|
|
||||||
|
class OrgChoicesElectionOffice(models.TextChoices):
|
||||||
|
"""
|
||||||
|
Primary organization choices for Django admin:
|
||||||
|
Keys need to match OrganizationChoices and OrganizationChoicesVerbose.
|
||||||
|
|
||||||
|
The enums here come in two variants:
|
||||||
|
Regular (matches the choices from OrganizationChoices)
|
||||||
|
Election (Appends " - Election" to the string)
|
||||||
|
|
||||||
|
When adding the election variant, you must append "_election" to the end of the string.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# We can't inherit OrganizationChoices due to models.TextChoices being an enum.
|
||||||
|
# We can redefine these values instead.
|
||||||
|
FEDERAL = "federal", "Federal"
|
||||||
|
INTERSTATE = "interstate", "Interstate"
|
||||||
|
STATE_OR_TERRITORY = "state_or_territory", "State or territory"
|
||||||
|
TRIBAL = "tribal", "Tribal"
|
||||||
|
COUNTY = "county", "County"
|
||||||
|
CITY = "city", "City"
|
||||||
|
SPECIAL_DISTRICT = "special_district", "Special district"
|
||||||
|
SCHOOL_DISTRICT = "school_district", "School district"
|
||||||
|
|
||||||
|
# Election variants
|
||||||
|
STATE_OR_TERRITORY_ELECTION = "state_or_territory_election", "State or territory - Election"
|
||||||
|
TRIBAL_ELECTION = "tribal_election", "Tribal - Election"
|
||||||
|
COUNTY_ELECTION = "county_election", "County - Election"
|
||||||
|
CITY_ELECTION = "city_election", "City - Election"
|
||||||
|
SPECIAL_DISTRICT_ELECTION = "special_district_election", "Special district - Election"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_org_election_to_org_generic(cls):
|
||||||
|
"""
|
||||||
|
Creates and returns a dictionary mapping from election-specific organization
|
||||||
|
choice enums to their corresponding general organization choice enums.
|
||||||
|
|
||||||
|
If no such mapping exists, it is simple excluded from the map.
|
||||||
|
"""
|
||||||
|
# This can be mapped automatically but its harder to read.
|
||||||
|
# For clarity reasons, we manually define this.
|
||||||
|
org_election_map = {
|
||||||
|
cls.STATE_OR_TERRITORY_ELECTION: cls.STATE_OR_TERRITORY,
|
||||||
|
cls.TRIBAL_ELECTION: cls.TRIBAL,
|
||||||
|
cls.COUNTY_ELECTION: cls.COUNTY,
|
||||||
|
cls.CITY_ELECTION: cls.CITY,
|
||||||
|
cls.SPECIAL_DISTRICT_ELECTION: cls.SPECIAL_DISTRICT,
|
||||||
|
}
|
||||||
|
return org_election_map
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_org_generic_to_org_election(cls):
|
||||||
|
"""
|
||||||
|
Creates and returns a dictionary mapping from general organization
|
||||||
|
choice enums to their corresponding election-specific organization enums.
|
||||||
|
|
||||||
|
If no such mapping exists, it is simple excluded from the map.
|
||||||
|
"""
|
||||||
|
# This can be mapped automatically but its harder to read.
|
||||||
|
# For clarity reasons, we manually define this.
|
||||||
|
org_election_map = {
|
||||||
|
cls.STATE_OR_TERRITORY: cls.STATE_OR_TERRITORY_ELECTION,
|
||||||
|
cls.TRIBAL: cls.TRIBAL_ELECTION,
|
||||||
|
cls.COUNTY: cls.COUNTY_ELECTION,
|
||||||
|
cls.CITY: cls.CITY_ELECTION,
|
||||||
|
cls.SPECIAL_DISTRICT: cls.SPECIAL_DISTRICT_ELECTION,
|
||||||
|
}
|
||||||
|
return org_election_map
|
||||||
|
|
||||||
class OrganizationChoicesVerbose(models.TextChoices):
|
class OrganizationChoicesVerbose(models.TextChoices):
|
||||||
"""
|
"""
|
||||||
Secondary organization choices
|
Tertiary organization choices
|
||||||
For use in the domain request form and on the templates
|
For use in the domain request form and on the templates
|
||||||
Keys need to match OrganizationChoices
|
Keys need to match OrganizationChoices
|
||||||
"""
|
"""
|
||||||
|
@ -406,6 +475,21 @@ class DomainRequest(TimeStampedModel):
|
||||||
help_text="Type of organization",
|
help_text="Type of organization",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
is_election_board = models.BooleanField(
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
help_text="Is your organization an election office?",
|
||||||
|
)
|
||||||
|
|
||||||
|
# TODO - Ticket #1911: stub this data from DomainRequest
|
||||||
|
organization_type = models.CharField(
|
||||||
|
max_length=255,
|
||||||
|
choices=OrgChoicesElectionOffice.choices,
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
help_text="Type of organization - Election office",
|
||||||
|
)
|
||||||
|
|
||||||
federally_recognized_tribe = models.BooleanField(
|
federally_recognized_tribe = models.BooleanField(
|
||||||
null=True,
|
null=True,
|
||||||
help_text="Is the tribe federally recognized",
|
help_text="Is the tribe federally recognized",
|
||||||
|
@ -437,18 +521,13 @@ class DomainRequest(TimeStampedModel):
|
||||||
help_text="Federal government branch",
|
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.CharField(
|
organization_name = models.CharField(
|
||||||
null=True,
|
null=True,
|
||||||
blank=True,
|
blank=True,
|
||||||
help_text="Organization name",
|
help_text="Organization name",
|
||||||
db_index=True,
|
db_index=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
address_line1 = models.CharField(
|
address_line1 = models.CharField(
|
||||||
null=True,
|
null=True,
|
||||||
blank=True,
|
blank=True,
|
||||||
|
@ -525,6 +604,7 @@ class DomainRequest(TimeStampedModel):
|
||||||
related_name="domain_request",
|
related_name="domain_request",
|
||||||
on_delete=models.PROTECT,
|
on_delete=models.PROTECT,
|
||||||
)
|
)
|
||||||
|
|
||||||
alternative_domains = models.ManyToManyField(
|
alternative_domains = models.ManyToManyField(
|
||||||
"registrar.Website",
|
"registrar.Website",
|
||||||
blank=True,
|
blank=True,
|
||||||
|
@ -586,6 +666,34 @@ class DomainRequest(TimeStampedModel):
|
||||||
help_text="Notes about this request",
|
help_text="Notes about this request",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def save(self, *args, **kwargs):
|
||||||
|
"""Save override for custom properties"""
|
||||||
|
|
||||||
|
# Define mappings between generic org and election org.
|
||||||
|
# These have to be defined here, as you'd get a cyclical import error
|
||||||
|
# otherwise.
|
||||||
|
|
||||||
|
# For any given organization type, return the "_election" variant.
|
||||||
|
# For example: STATE_OR_TERRITORY => STATE_OR_TERRITORY_ELECTION
|
||||||
|
generic_org_map = self.OrgChoicesElectionOffice.get_org_generic_to_org_election()
|
||||||
|
|
||||||
|
# For any given "_election" variant, return the base org type.
|
||||||
|
# For example: STATE_OR_TERRITORY_ELECTION => STATE_OR_TERRITORY
|
||||||
|
election_org_map = self.OrgChoicesElectionOffice.get_org_election_to_org_generic()
|
||||||
|
|
||||||
|
# Manages the "organization_type" variable and keeps in sync with
|
||||||
|
# "is_election_office" and "generic_organization_type"
|
||||||
|
org_type_helper = CreateOrUpdateOrganizationTypeHelper(
|
||||||
|
sender=self.__class__,
|
||||||
|
instance=self,
|
||||||
|
generic_org_to_org_map=generic_org_map,
|
||||||
|
election_org_to_generic_org_map=election_org_map,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Actually updates the organization_type field
|
||||||
|
org_type_helper.create_or_update_organization_type()
|
||||||
|
super().save(*args, **kwargs)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
try:
|
try:
|
||||||
if self.requested_domain and self.requested_domain.name:
|
if self.requested_domain and self.requested_domain.name:
|
||||||
|
|
|
@ -35,3 +35,219 @@ class Timer:
|
||||||
self.end = time.time()
|
self.end = time.time()
|
||||||
self.duration = self.end - self.start
|
self.duration = self.end - self.start
|
||||||
logger.info(f"Execution time: {self.duration} seconds")
|
logger.info(f"Execution time: {self.duration} seconds")
|
||||||
|
|
||||||
|
|
||||||
|
class CreateOrUpdateOrganizationTypeHelper:
|
||||||
|
"""
|
||||||
|
A helper that manages the "organization_type" field in DomainRequest and DomainInformation
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, sender, instance, generic_org_to_org_map, election_org_to_generic_org_map):
|
||||||
|
# The "model type"
|
||||||
|
self.sender = sender
|
||||||
|
self.instance = instance
|
||||||
|
self.generic_org_to_org_map = generic_org_to_org_map
|
||||||
|
self.election_org_to_generic_org_map = election_org_to_generic_org_map
|
||||||
|
|
||||||
|
def create_or_update_organization_type(self):
|
||||||
|
"""The organization_type field on DomainRequest and DomainInformation is consituted from the
|
||||||
|
generic_org_type and is_election_board fields. To keep the organization_type
|
||||||
|
field up to date, we need to update it before save based off of those field
|
||||||
|
values.
|
||||||
|
|
||||||
|
If the instance is marked as an election board and the generic_org_type is not
|
||||||
|
one of the excluded types (FEDERAL, INTERSTATE, SCHOOL_DISTRICT), the
|
||||||
|
organization_type is set to a corresponding election variant. Otherwise, it directly
|
||||||
|
mirrors the generic_org_type value.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# A new record is added with organization_type not defined.
|
||||||
|
# This happens from the regular domain request flow.
|
||||||
|
is_new_instance = self.instance.id is None
|
||||||
|
if is_new_instance:
|
||||||
|
self._handle_new_instance()
|
||||||
|
else:
|
||||||
|
self._handle_existing_instance()
|
||||||
|
|
||||||
|
return self.instance
|
||||||
|
|
||||||
|
def _handle_new_instance(self):
|
||||||
|
# == Check for invalid conditions before proceeding == #
|
||||||
|
should_proceed = self._validate_new_instance()
|
||||||
|
if not should_proceed:
|
||||||
|
return None
|
||||||
|
# == Program flow will halt here if there is no reason to update == #
|
||||||
|
|
||||||
|
# == Update the linked values == #
|
||||||
|
organization_type_needs_update = self.instance.organization_type is None
|
||||||
|
generic_org_type_needs_update = self.instance.generic_org_type is None
|
||||||
|
|
||||||
|
# If a field is none, it indicates (per prior checks) that the
|
||||||
|
# related field (generic org type <-> org type) has data and we should update according to that.
|
||||||
|
if organization_type_needs_update:
|
||||||
|
self._update_org_type_from_generic_org_and_election()
|
||||||
|
elif generic_org_type_needs_update:
|
||||||
|
self._update_generic_org_and_election_from_org_type()
|
||||||
|
|
||||||
|
# Update the field
|
||||||
|
self._update_fields(organization_type_needs_update, generic_org_type_needs_update)
|
||||||
|
|
||||||
|
def _handle_existing_instance(self):
|
||||||
|
# == Init variables == #
|
||||||
|
# Instance is already in the database, fetch its current state
|
||||||
|
current_instance = self.sender.objects.get(id=self.instance.id)
|
||||||
|
|
||||||
|
# Check the new and old values
|
||||||
|
generic_org_type_changed = self.instance.generic_org_type != current_instance.generic_org_type
|
||||||
|
is_election_board_changed = self.instance.is_election_board != current_instance.is_election_board
|
||||||
|
organization_type_changed = self.instance.organization_type != current_instance.organization_type
|
||||||
|
|
||||||
|
# == Check for invalid conditions before proceeding == #
|
||||||
|
if organization_type_changed and (generic_org_type_changed or is_election_board_changed):
|
||||||
|
# Since organization type is linked with generic_org_type and election board,
|
||||||
|
# we have to update one or the other, not both.
|
||||||
|
# This will not happen in normal flow as it is not possible otherwise.
|
||||||
|
raise ValueError("Cannot update organization_type and generic_org_type simultaneously.")
|
||||||
|
elif not organization_type_changed and (not generic_org_type_changed and not is_election_board_changed):
|
||||||
|
# No values to update - do nothing
|
||||||
|
return None
|
||||||
|
# == Program flow will halt here if there is no reason to update == #
|
||||||
|
|
||||||
|
# == Update the linked values == #
|
||||||
|
# Find out which field needs updating
|
||||||
|
organization_type_needs_update = generic_org_type_changed or is_election_board_changed
|
||||||
|
generic_org_type_needs_update = organization_type_changed
|
||||||
|
|
||||||
|
# Update the field
|
||||||
|
self._update_fields(organization_type_needs_update, generic_org_type_needs_update)
|
||||||
|
|
||||||
|
def _update_fields(self, organization_type_needs_update, generic_org_type_needs_update):
|
||||||
|
"""
|
||||||
|
Validates the conditions for updating organization and generic organization types.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: If both organization_type_needs_update and generic_org_type_needs_update are True,
|
||||||
|
indicating an attempt to update both fields simultaneously, which is not allowed.
|
||||||
|
"""
|
||||||
|
# We shouldn't update both of these at the same time.
|
||||||
|
# It is more useful to have these as seperate variables, but it does impose
|
||||||
|
# this restraint.
|
||||||
|
if organization_type_needs_update and generic_org_type_needs_update:
|
||||||
|
raise ValueError("Cannot update both org type and generic org type at the same time.")
|
||||||
|
|
||||||
|
if organization_type_needs_update:
|
||||||
|
self._update_org_type_from_generic_org_and_election()
|
||||||
|
elif generic_org_type_needs_update:
|
||||||
|
self._update_generic_org_and_election_from_org_type()
|
||||||
|
|
||||||
|
def _update_org_type_from_generic_org_and_election(self):
|
||||||
|
"""Given a field values for generic_org_type and is_election_board, update the
|
||||||
|
organization_type field."""
|
||||||
|
|
||||||
|
# We convert to a string because the enum types are different.
|
||||||
|
generic_org_type = str(self.instance.generic_org_type)
|
||||||
|
if generic_org_type not in self.generic_org_to_org_map:
|
||||||
|
# Election board should always be reset to None if the record
|
||||||
|
# can't have one. For example, federal.
|
||||||
|
if self.instance.is_election_board is not None:
|
||||||
|
# This maintains data consistency.
|
||||||
|
# There is no avenue for this to occur in the UI,
|
||||||
|
# as such - this can only occur if the object is initialized in this way.
|
||||||
|
# Or if there are pre-existing data.
|
||||||
|
logger.warning(
|
||||||
|
"create_or_update_organization_type() -> is_election_board "
|
||||||
|
f"cannot exist for {generic_org_type}. Setting to None."
|
||||||
|
)
|
||||||
|
self.instance.is_election_board = None
|
||||||
|
self.instance.organization_type = generic_org_type
|
||||||
|
else:
|
||||||
|
# This can only happen with manual data tinkering, which causes these to be out of sync.
|
||||||
|
if self.instance.is_election_board is None:
|
||||||
|
logger.warning(
|
||||||
|
"create_or_update_organization_type() -> is_election_board is out of sync. Updating value."
|
||||||
|
)
|
||||||
|
self.instance.is_election_board = False
|
||||||
|
|
||||||
|
if self.instance.is_election_board:
|
||||||
|
self.instance.organization_type = self.generic_org_to_org_map[generic_org_type]
|
||||||
|
else:
|
||||||
|
self.instance.organization_type = generic_org_type
|
||||||
|
|
||||||
|
def _update_generic_org_and_election_from_org_type(self):
|
||||||
|
"""Given the field value for organization_type, update the
|
||||||
|
generic_org_type and is_election_board field."""
|
||||||
|
|
||||||
|
# We convert to a string because the enum types are different
|
||||||
|
# between OrgChoicesElectionOffice and OrganizationChoices.
|
||||||
|
# But their names are the same (for the most part).
|
||||||
|
current_org_type = str(self.instance.organization_type)
|
||||||
|
election_org_map = self.election_org_to_generic_org_map
|
||||||
|
generic_org_map = self.generic_org_to_org_map
|
||||||
|
|
||||||
|
# This essentially means: "_election" in current_org_type.
|
||||||
|
if current_org_type in election_org_map:
|
||||||
|
new_org = election_org_map[current_org_type]
|
||||||
|
self.instance.generic_org_type = new_org
|
||||||
|
self.instance.is_election_board = True
|
||||||
|
elif self.instance.organization_type is not None:
|
||||||
|
self.instance.generic_org_type = current_org_type
|
||||||
|
|
||||||
|
# This basically checks if the given org type
|
||||||
|
# can even have an election board in the first place.
|
||||||
|
# For instance, federal cannot so is_election_board = None
|
||||||
|
if current_org_type in generic_org_map:
|
||||||
|
self.instance.is_election_board = False
|
||||||
|
else:
|
||||||
|
# This maintains data consistency.
|
||||||
|
# There is no avenue for this to occur in the UI,
|
||||||
|
# as such - this can only occur if the object is initialized in this way.
|
||||||
|
# Or if there are pre-existing data.
|
||||||
|
logger.warning(
|
||||||
|
"create_or_update_organization_type() -> is_election_board "
|
||||||
|
f"cannot exist for {current_org_type}. Setting to None."
|
||||||
|
)
|
||||||
|
self.instance.is_election_board = None
|
||||||
|
else:
|
||||||
|
# if self.instance.organization_type is set to None, then this means
|
||||||
|
# we should clear the related fields.
|
||||||
|
# This will not occur if it just is None (i.e. default), only if it is set to be so.
|
||||||
|
self.instance.is_election_board = None
|
||||||
|
self.instance.generic_org_type = None
|
||||||
|
|
||||||
|
def _validate_new_instance(self):
|
||||||
|
"""
|
||||||
|
Validates whether a new instance of DomainRequest or DomainInformation can proceed with the update
|
||||||
|
based on the consistency between organization_type, generic_org_type, and is_election_board.
|
||||||
|
|
||||||
|
Returns a boolean determining if execution should proceed or not.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# We conditionally accept both of these values to exist simultaneously, as long as
|
||||||
|
# those values do not intefere with eachother.
|
||||||
|
# Because this condition can only be triggered through a dev (no user flow),
|
||||||
|
# we throw an error if an invalid state is found here.
|
||||||
|
if self.instance.organization_type and self.instance.generic_org_type:
|
||||||
|
generic_org_type = str(self.instance.generic_org_type)
|
||||||
|
organization_type = str(self.instance.organization_type)
|
||||||
|
|
||||||
|
# Strip "_election" if it exists
|
||||||
|
mapped_org_type = self.election_org_to_generic_org_map.get(organization_type)
|
||||||
|
|
||||||
|
# Do tests on the org update for election board changes.
|
||||||
|
is_election_type = "_election" in organization_type
|
||||||
|
can_have_election_board = organization_type in self.generic_org_to_org_map
|
||||||
|
|
||||||
|
election_board_mismatch = (is_election_type != self.instance.is_election_board) and can_have_election_board
|
||||||
|
org_type_mismatch = mapped_org_type is not None and (generic_org_type != mapped_org_type)
|
||||||
|
if election_board_mismatch or org_type_mismatch:
|
||||||
|
message = (
|
||||||
|
"Cannot add organization_type and generic_org_type simultaneously "
|
||||||
|
"when generic_org_type, is_election_board, and organization_type values do not match."
|
||||||
|
)
|
||||||
|
raise ValueError(message)
|
||||||
|
|
||||||
|
return True
|
||||||
|
elif not self.instance.organization_type and not self.instance.generic_org_type:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
|
|
@ -585,7 +585,7 @@ class MockDb(TestCase):
|
||||||
generic_org_type="federal",
|
generic_org_type="federal",
|
||||||
federal_agency="World War I Centennial Commission",
|
federal_agency="World War I Centennial Commission",
|
||||||
federal_type="executive",
|
federal_type="executive",
|
||||||
is_election_board=True,
|
is_election_board=False,
|
||||||
)
|
)
|
||||||
self.domain_information_2, _ = DomainInformation.objects.get_or_create(
|
self.domain_information_2, _ = DomainInformation.objects.get_or_create(
|
||||||
creator=self.user, domain=self.domain_2, generic_org_type="interstate", is_election_board=True
|
creator=self.user, domain=self.domain_2, generic_org_type="interstate", is_election_board=True
|
||||||
|
@ -595,14 +595,14 @@ class MockDb(TestCase):
|
||||||
domain=self.domain_3,
|
domain=self.domain_3,
|
||||||
generic_org_type="federal",
|
generic_org_type="federal",
|
||||||
federal_agency="Armed Forces Retirement Home",
|
federal_agency="Armed Forces Retirement Home",
|
||||||
is_election_board=True,
|
is_election_board=False,
|
||||||
)
|
)
|
||||||
self.domain_information_4, _ = DomainInformation.objects.get_or_create(
|
self.domain_information_4, _ = DomainInformation.objects.get_or_create(
|
||||||
creator=self.user,
|
creator=self.user,
|
||||||
domain=self.domain_4,
|
domain=self.domain_4,
|
||||||
generic_org_type="federal",
|
generic_org_type="federal",
|
||||||
federal_agency="Armed Forces Retirement Home",
|
federal_agency="Armed Forces Retirement Home",
|
||||||
is_election_board=True,
|
is_election_board=False,
|
||||||
)
|
)
|
||||||
self.domain_information_5, _ = DomainInformation.objects.get_or_create(
|
self.domain_information_5, _ = DomainInformation.objects.get_or_create(
|
||||||
creator=self.user,
|
creator=self.user,
|
||||||
|
@ -652,7 +652,7 @@ class MockDb(TestCase):
|
||||||
generic_org_type="federal",
|
generic_org_type="federal",
|
||||||
federal_agency="World War I Centennial Commission",
|
federal_agency="World War I Centennial Commission",
|
||||||
federal_type="executive",
|
federal_type="executive",
|
||||||
is_election_board=True,
|
is_election_board=False,
|
||||||
)
|
)
|
||||||
self.domain_information_12, _ = DomainInformation.objects.get_or_create(
|
self.domain_information_12, _ = DomainInformation.objects.get_or_create(
|
||||||
creator=self.user,
|
creator=self.user,
|
||||||
|
@ -801,6 +801,9 @@ def completed_domain_request(
|
||||||
submitter=False,
|
submitter=False,
|
||||||
name="city.gov",
|
name="city.gov",
|
||||||
investigator=None,
|
investigator=None,
|
||||||
|
generic_org_type="federal",
|
||||||
|
is_election_board=False,
|
||||||
|
organization_type=None,
|
||||||
):
|
):
|
||||||
"""A completed domain request."""
|
"""A completed domain request."""
|
||||||
if not user:
|
if not user:
|
||||||
|
@ -838,7 +841,8 @@ def completed_domain_request(
|
||||||
is_staff=True,
|
is_staff=True,
|
||||||
)
|
)
|
||||||
domain_request_kwargs = dict(
|
domain_request_kwargs = dict(
|
||||||
generic_org_type="federal",
|
generic_org_type=generic_org_type,
|
||||||
|
is_election_board=is_election_board,
|
||||||
federal_type="executive",
|
federal_type="executive",
|
||||||
purpose="Purpose of the site",
|
purpose="Purpose of the site",
|
||||||
is_policy_acknowledged=True,
|
is_policy_acknowledged=True,
|
||||||
|
@ -859,6 +863,9 @@ def completed_domain_request(
|
||||||
if has_anything_else:
|
if has_anything_else:
|
||||||
domain_request_kwargs["anything_else"] = "There is more"
|
domain_request_kwargs["anything_else"] = "There is more"
|
||||||
|
|
||||||
|
if organization_type:
|
||||||
|
domain_request_kwargs["organization_type"] = organization_type
|
||||||
|
|
||||||
domain_request, _ = DomainRequest.objects.get_or_create(**domain_request_kwargs)
|
domain_request, _ = DomainRequest.objects.get_or_create(**domain_request_kwargs)
|
||||||
|
|
||||||
if has_other_contacts:
|
if has_other_contacts:
|
||||||
|
|
|
@ -1652,6 +1652,8 @@ class TestDomainRequestAdmin(MockEppLib):
|
||||||
"other_contacts",
|
"other_contacts",
|
||||||
"current_websites",
|
"current_websites",
|
||||||
"alternative_domains",
|
"alternative_domains",
|
||||||
|
"generic_org_type",
|
||||||
|
"is_election_board",
|
||||||
"id",
|
"id",
|
||||||
"created_at",
|
"created_at",
|
||||||
"updated_at",
|
"updated_at",
|
||||||
|
@ -1660,12 +1662,13 @@ class TestDomainRequestAdmin(MockEppLib):
|
||||||
"creator",
|
"creator",
|
||||||
"investigator",
|
"investigator",
|
||||||
"generic_org_type",
|
"generic_org_type",
|
||||||
|
"is_election_board",
|
||||||
|
"organization_type",
|
||||||
"federally_recognized_tribe",
|
"federally_recognized_tribe",
|
||||||
"state_recognized_tribe",
|
"state_recognized_tribe",
|
||||||
"tribe_name",
|
"tribe_name",
|
||||||
"federal_agency",
|
"federal_agency",
|
||||||
"federal_type",
|
"federal_type",
|
||||||
"is_election_board",
|
|
||||||
"organization_name",
|
"organization_name",
|
||||||
"address_line1",
|
"address_line1",
|
||||||
"address_line2",
|
"address_line2",
|
||||||
|
@ -1700,6 +1703,8 @@ class TestDomainRequestAdmin(MockEppLib):
|
||||||
"other_contacts",
|
"other_contacts",
|
||||||
"current_websites",
|
"current_websites",
|
||||||
"alternative_domains",
|
"alternative_domains",
|
||||||
|
"generic_org_type",
|
||||||
|
"is_election_board",
|
||||||
"creator",
|
"creator",
|
||||||
"about_your_organization",
|
"about_your_organization",
|
||||||
"requested_domain",
|
"requested_domain",
|
||||||
|
@ -1725,6 +1730,8 @@ class TestDomainRequestAdmin(MockEppLib):
|
||||||
"other_contacts",
|
"other_contacts",
|
||||||
"current_websites",
|
"current_websites",
|
||||||
"alternative_domains",
|
"alternative_domains",
|
||||||
|
"generic_org_type",
|
||||||
|
"is_election_board",
|
||||||
]
|
]
|
||||||
|
|
||||||
self.assertEqual(readonly_fields, expected_fields)
|
self.assertEqual(readonly_fields, expected_fields)
|
||||||
|
@ -2323,6 +2330,8 @@ class TestDomainInformationAdmin(TestCase):
|
||||||
|
|
||||||
expected_fields = [
|
expected_fields = [
|
||||||
"other_contacts",
|
"other_contacts",
|
||||||
|
"generic_org_type",
|
||||||
|
"is_election_board",
|
||||||
"creator",
|
"creator",
|
||||||
"type_of_work",
|
"type_of_work",
|
||||||
"more_organization_information",
|
"more_organization_information",
|
||||||
|
|
|
@ -1161,3 +1161,309 @@ class TestContact(TestCase):
|
||||||
# test for a contact which is assigned as an authorizing official on a domain request
|
# test for a contact which is assigned as an authorizing official on a domain request
|
||||||
self.assertFalse(self.contact_as_ao.has_more_than_one_join("authorizing_official"))
|
self.assertFalse(self.contact_as_ao.has_more_than_one_join("authorizing_official"))
|
||||||
self.assertTrue(self.contact_as_ao.has_more_than_one_join("submitted_domain_requests"))
|
self.assertTrue(self.contact_as_ao.has_more_than_one_join("submitted_domain_requests"))
|
||||||
|
|
||||||
|
|
||||||
|
class TestDomainRequestCustomSave(TestCase):
|
||||||
|
"""Tests custom save behaviour on the DomainRequest object"""
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
DomainRequest.objects.all().delete()
|
||||||
|
super().tearDown()
|
||||||
|
|
||||||
|
def test_create_or_update_organization_type_new_instance(self):
|
||||||
|
"""Test create_or_update_organization_type when creating a new instance"""
|
||||||
|
domain_request = completed_domain_request(
|
||||||
|
status=DomainRequest.DomainRequestStatus.STARTED,
|
||||||
|
name="started.gov",
|
||||||
|
generic_org_type=DomainRequest.OrganizationChoices.CITY,
|
||||||
|
is_election_board=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(domain_request.organization_type, DomainRequest.OrgChoicesElectionOffice.CITY_ELECTION)
|
||||||
|
|
||||||
|
def test_create_or_update_organization_type_new_instance_federal_does_nothing(self):
|
||||||
|
"""Test if create_or_update_organization_type does nothing when creating a new instance for federal"""
|
||||||
|
domain_request = completed_domain_request(
|
||||||
|
status=DomainRequest.DomainRequestStatus.STARTED,
|
||||||
|
name="started.gov",
|
||||||
|
generic_org_type=DomainRequest.OrganizationChoices.FEDERAL,
|
||||||
|
is_election_board=True,
|
||||||
|
)
|
||||||
|
self.assertEqual(domain_request.organization_type, DomainRequest.OrgChoicesElectionOffice.FEDERAL)
|
||||||
|
self.assertEqual(domain_request.is_election_board, None)
|
||||||
|
|
||||||
|
def test_create_or_update_organization_type_existing_instance_updates_election_board(self):
|
||||||
|
"""Test create_or_update_organization_type for an existing instance."""
|
||||||
|
domain_request = completed_domain_request(
|
||||||
|
status=DomainRequest.DomainRequestStatus.STARTED,
|
||||||
|
name="started.gov",
|
||||||
|
generic_org_type=DomainRequest.OrganizationChoices.CITY,
|
||||||
|
is_election_board=False,
|
||||||
|
)
|
||||||
|
domain_request.is_election_board = True
|
||||||
|
domain_request.save()
|
||||||
|
|
||||||
|
self.assertEqual(domain_request.is_election_board, True)
|
||||||
|
self.assertEqual(domain_request.organization_type, DomainRequest.OrgChoicesElectionOffice.CITY_ELECTION)
|
||||||
|
|
||||||
|
# Try reverting the election board value
|
||||||
|
domain_request.is_election_board = False
|
||||||
|
domain_request.save()
|
||||||
|
|
||||||
|
self.assertEqual(domain_request.is_election_board, False)
|
||||||
|
self.assertEqual(domain_request.organization_type, DomainRequest.OrgChoicesElectionOffice.CITY)
|
||||||
|
|
||||||
|
# Try reverting setting an invalid value for election board (should revert to False)
|
||||||
|
domain_request.is_election_board = None
|
||||||
|
domain_request.save()
|
||||||
|
|
||||||
|
self.assertEqual(domain_request.is_election_board, False)
|
||||||
|
self.assertEqual(domain_request.organization_type, DomainRequest.OrgChoicesElectionOffice.CITY)
|
||||||
|
|
||||||
|
def test_create_or_update_organization_type_existing_instance_updates_generic_org_type(self):
|
||||||
|
"""Test create_or_update_organization_type when modifying generic_org_type on an existing instance."""
|
||||||
|
domain_request = completed_domain_request(
|
||||||
|
status=DomainRequest.DomainRequestStatus.STARTED,
|
||||||
|
name="started.gov",
|
||||||
|
generic_org_type=DomainRequest.OrganizationChoices.CITY,
|
||||||
|
is_election_board=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
domain_request.generic_org_type = DomainRequest.OrganizationChoices.INTERSTATE
|
||||||
|
domain_request.save()
|
||||||
|
|
||||||
|
# Election board should be None because interstate cannot have an election board.
|
||||||
|
self.assertEqual(domain_request.is_election_board, None)
|
||||||
|
self.assertEqual(domain_request.organization_type, DomainRequest.OrgChoicesElectionOffice.INTERSTATE)
|
||||||
|
|
||||||
|
# Try changing the org Type to something that CAN have an election board.
|
||||||
|
domain_request_tribal = completed_domain_request(
|
||||||
|
status=DomainRequest.DomainRequestStatus.STARTED,
|
||||||
|
name="startedTribal.gov",
|
||||||
|
generic_org_type=DomainRequest.OrganizationChoices.TRIBAL,
|
||||||
|
is_election_board=True,
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
domain_request_tribal.organization_type, DomainRequest.OrgChoicesElectionOffice.TRIBAL_ELECTION
|
||||||
|
)
|
||||||
|
|
||||||
|
# Change the org type
|
||||||
|
domain_request_tribal.generic_org_type = DomainRequest.OrganizationChoices.STATE_OR_TERRITORY
|
||||||
|
domain_request_tribal.save()
|
||||||
|
|
||||||
|
self.assertEqual(domain_request_tribal.is_election_board, True)
|
||||||
|
self.assertEqual(
|
||||||
|
domain_request_tribal.organization_type, DomainRequest.OrgChoicesElectionOffice.STATE_OR_TERRITORY_ELECTION
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_create_or_update_organization_type_no_update(self):
|
||||||
|
"""Test create_or_update_organization_type when there are no values to update."""
|
||||||
|
|
||||||
|
# Test for when both generic_org_type and organization_type is declared,
|
||||||
|
# and are both non-election board
|
||||||
|
domain_request = completed_domain_request(
|
||||||
|
status=DomainRequest.DomainRequestStatus.STARTED,
|
||||||
|
name="started.gov",
|
||||||
|
generic_org_type=DomainRequest.OrganizationChoices.CITY,
|
||||||
|
is_election_board=False,
|
||||||
|
)
|
||||||
|
domain_request.save()
|
||||||
|
self.assertEqual(domain_request.organization_type, DomainRequest.OrgChoicesElectionOffice.CITY)
|
||||||
|
self.assertEqual(domain_request.is_election_board, False)
|
||||||
|
self.assertEqual(domain_request.generic_org_type, DomainRequest.OrganizationChoices.CITY)
|
||||||
|
|
||||||
|
# Test for when both generic_org_type and organization_type is declared,
|
||||||
|
# and are both election board
|
||||||
|
domain_request_election = completed_domain_request(
|
||||||
|
status=DomainRequest.DomainRequestStatus.STARTED,
|
||||||
|
name="startedElection.gov",
|
||||||
|
generic_org_type=DomainRequest.OrganizationChoices.CITY,
|
||||||
|
is_election_board=True,
|
||||||
|
organization_type=DomainRequest.OrgChoicesElectionOffice.CITY_ELECTION,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
domain_request_election.organization_type, DomainRequest.OrgChoicesElectionOffice.CITY_ELECTION
|
||||||
|
)
|
||||||
|
self.assertEqual(domain_request_election.is_election_board, True)
|
||||||
|
self.assertEqual(domain_request_election.generic_org_type, DomainRequest.OrganizationChoices.CITY)
|
||||||
|
|
||||||
|
# Modify an unrelated existing value for both, and ensure that everything is still consistent
|
||||||
|
domain_request.city = "Fudge"
|
||||||
|
domain_request_election.city = "Caramel"
|
||||||
|
domain_request.save()
|
||||||
|
domain_request_election.save()
|
||||||
|
|
||||||
|
self.assertEqual(domain_request.city, "Fudge")
|
||||||
|
self.assertEqual(domain_request_election.city, "Caramel")
|
||||||
|
|
||||||
|
# Test for non-election
|
||||||
|
self.assertEqual(domain_request.organization_type, DomainRequest.OrgChoicesElectionOffice.CITY)
|
||||||
|
self.assertEqual(domain_request.is_election_board, False)
|
||||||
|
self.assertEqual(domain_request.generic_org_type, DomainRequest.OrganizationChoices.CITY)
|
||||||
|
|
||||||
|
# Test for election
|
||||||
|
self.assertEqual(
|
||||||
|
domain_request_election.organization_type, DomainRequest.OrgChoicesElectionOffice.CITY_ELECTION
|
||||||
|
)
|
||||||
|
self.assertEqual(domain_request_election.is_election_board, True)
|
||||||
|
self.assertEqual(domain_request_election.generic_org_type, DomainRequest.OrganizationChoices.CITY)
|
||||||
|
|
||||||
|
|
||||||
|
class TestDomainInformationCustomSave(TestCase):
|
||||||
|
"""Tests custom save behaviour on the DomainInformation object"""
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
DomainInformation.objects.all().delete()
|
||||||
|
DomainRequest.objects.all().delete()
|
||||||
|
Domain.objects.all().delete()
|
||||||
|
super().tearDown()
|
||||||
|
|
||||||
|
def test_create_or_update_organization_type_new_instance(self):
|
||||||
|
"""Test create_or_update_organization_type when creating a new instance"""
|
||||||
|
domain_request = completed_domain_request(
|
||||||
|
status=DomainRequest.DomainRequestStatus.STARTED,
|
||||||
|
name="started.gov",
|
||||||
|
generic_org_type=DomainRequest.OrganizationChoices.CITY,
|
||||||
|
is_election_board=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
domain_information = DomainInformation.create_from_da(domain_request)
|
||||||
|
self.assertEqual(domain_information.organization_type, DomainRequest.OrgChoicesElectionOffice.CITY_ELECTION)
|
||||||
|
|
||||||
|
def test_create_or_update_organization_type_new_instance_federal_does_nothing(self):
|
||||||
|
"""Test if create_or_update_organization_type does nothing when creating a new instance for federal"""
|
||||||
|
domain_request = completed_domain_request(
|
||||||
|
status=DomainRequest.DomainRequestStatus.STARTED,
|
||||||
|
name="started.gov",
|
||||||
|
generic_org_type=DomainRequest.OrganizationChoices.FEDERAL,
|
||||||
|
is_election_board=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
domain_information = DomainInformation.create_from_da(domain_request)
|
||||||
|
self.assertEqual(domain_information.organization_type, DomainRequest.OrgChoicesElectionOffice.FEDERAL)
|
||||||
|
self.assertEqual(domain_information.is_election_board, None)
|
||||||
|
|
||||||
|
def test_create_or_update_organization_type_existing_instance_updates_election_board(self):
|
||||||
|
"""Test create_or_update_organization_type for an existing instance."""
|
||||||
|
domain_request = completed_domain_request(
|
||||||
|
status=DomainRequest.DomainRequestStatus.STARTED,
|
||||||
|
name="started.gov",
|
||||||
|
generic_org_type=DomainRequest.OrganizationChoices.CITY,
|
||||||
|
is_election_board=False,
|
||||||
|
)
|
||||||
|
domain_information = DomainInformation.create_from_da(domain_request)
|
||||||
|
domain_information.is_election_board = True
|
||||||
|
domain_information.save()
|
||||||
|
|
||||||
|
self.assertEqual(domain_information.is_election_board, True)
|
||||||
|
self.assertEqual(domain_information.organization_type, DomainRequest.OrgChoicesElectionOffice.CITY_ELECTION)
|
||||||
|
|
||||||
|
# Try reverting the election board value
|
||||||
|
domain_information.is_election_board = False
|
||||||
|
domain_information.save()
|
||||||
|
domain_information.refresh_from_db()
|
||||||
|
|
||||||
|
self.assertEqual(domain_information.is_election_board, False)
|
||||||
|
self.assertEqual(domain_information.organization_type, DomainRequest.OrgChoicesElectionOffice.CITY)
|
||||||
|
|
||||||
|
# Try reverting setting an invalid value for election board (should revert to False)
|
||||||
|
domain_information.is_election_board = None
|
||||||
|
domain_information.save()
|
||||||
|
|
||||||
|
self.assertEqual(domain_information.is_election_board, False)
|
||||||
|
self.assertEqual(domain_information.organization_type, DomainRequest.OrgChoicesElectionOffice.CITY)
|
||||||
|
|
||||||
|
def test_create_or_update_organization_type_existing_instance_updates_generic_org_type(self):
|
||||||
|
"""Test create_or_update_organization_type when modifying generic_org_type on an existing instance."""
|
||||||
|
domain_request = completed_domain_request(
|
||||||
|
status=DomainRequest.DomainRequestStatus.STARTED,
|
||||||
|
name="started.gov",
|
||||||
|
generic_org_type=DomainRequest.OrganizationChoices.CITY,
|
||||||
|
is_election_board=True,
|
||||||
|
)
|
||||||
|
domain_information = DomainInformation.create_from_da(domain_request)
|
||||||
|
|
||||||
|
domain_information.generic_org_type = DomainRequest.OrganizationChoices.INTERSTATE
|
||||||
|
domain_information.save()
|
||||||
|
|
||||||
|
# Election board should be None because interstate cannot have an election board.
|
||||||
|
self.assertEqual(domain_information.is_election_board, None)
|
||||||
|
self.assertEqual(domain_information.organization_type, DomainRequest.OrgChoicesElectionOffice.INTERSTATE)
|
||||||
|
|
||||||
|
# Try changing the org Type to something that CAN have an election board.
|
||||||
|
domain_request_tribal = completed_domain_request(
|
||||||
|
status=DomainRequest.DomainRequestStatus.STARTED,
|
||||||
|
name="startedTribal.gov",
|
||||||
|
generic_org_type=DomainRequest.OrganizationChoices.TRIBAL,
|
||||||
|
is_election_board=True,
|
||||||
|
)
|
||||||
|
domain_information_tribal = DomainInformation.create_from_da(domain_request_tribal)
|
||||||
|
self.assertEqual(
|
||||||
|
domain_information_tribal.organization_type, DomainRequest.OrgChoicesElectionOffice.TRIBAL_ELECTION
|
||||||
|
)
|
||||||
|
|
||||||
|
# Change the org type
|
||||||
|
domain_information_tribal.generic_org_type = DomainRequest.OrganizationChoices.STATE_OR_TERRITORY
|
||||||
|
domain_information_tribal.save()
|
||||||
|
|
||||||
|
self.assertEqual(domain_information_tribal.is_election_board, True)
|
||||||
|
self.assertEqual(
|
||||||
|
domain_information_tribal.organization_type,
|
||||||
|
DomainRequest.OrgChoicesElectionOffice.STATE_OR_TERRITORY_ELECTION,
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_create_or_update_organization_type_no_update(self):
|
||||||
|
"""Test create_or_update_organization_type when there are no values to update."""
|
||||||
|
|
||||||
|
# Test for when both generic_org_type and organization_type is declared,
|
||||||
|
# and are both non-election board
|
||||||
|
domain_request = completed_domain_request(
|
||||||
|
status=DomainRequest.DomainRequestStatus.STARTED,
|
||||||
|
name="started.gov",
|
||||||
|
generic_org_type=DomainRequest.OrganizationChoices.CITY,
|
||||||
|
is_election_board=False,
|
||||||
|
)
|
||||||
|
domain_information = DomainInformation.create_from_da(domain_request)
|
||||||
|
domain_information.save()
|
||||||
|
self.assertEqual(domain_information.organization_type, DomainRequest.OrgChoicesElectionOffice.CITY)
|
||||||
|
self.assertEqual(domain_information.is_election_board, False)
|
||||||
|
self.assertEqual(domain_information.generic_org_type, DomainRequest.OrganizationChoices.CITY)
|
||||||
|
|
||||||
|
# Test for when both generic_org_type and organization_type is declared,
|
||||||
|
# and are both election board
|
||||||
|
domain_request_election = completed_domain_request(
|
||||||
|
status=DomainRequest.DomainRequestStatus.STARTED,
|
||||||
|
name="startedElection.gov",
|
||||||
|
generic_org_type=DomainRequest.OrganizationChoices.CITY,
|
||||||
|
is_election_board=True,
|
||||||
|
organization_type=DomainRequest.OrgChoicesElectionOffice.CITY_ELECTION,
|
||||||
|
)
|
||||||
|
domain_information_election = DomainInformation.create_from_da(domain_request_election)
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
domain_information_election.organization_type, DomainRequest.OrgChoicesElectionOffice.CITY_ELECTION
|
||||||
|
)
|
||||||
|
self.assertEqual(domain_information_election.is_election_board, True)
|
||||||
|
self.assertEqual(domain_information_election.generic_org_type, DomainRequest.OrganizationChoices.CITY)
|
||||||
|
|
||||||
|
# Modify an unrelated existing value for both, and ensure that everything is still consistent
|
||||||
|
domain_information.city = "Fudge"
|
||||||
|
domain_information_election.city = "Caramel"
|
||||||
|
domain_information.save()
|
||||||
|
domain_information_election.save()
|
||||||
|
|
||||||
|
self.assertEqual(domain_information.city, "Fudge")
|
||||||
|
self.assertEqual(domain_information_election.city, "Caramel")
|
||||||
|
|
||||||
|
# Test for non-election
|
||||||
|
self.assertEqual(domain_information.organization_type, DomainRequest.OrgChoicesElectionOffice.CITY)
|
||||||
|
self.assertEqual(domain_information.is_election_board, False)
|
||||||
|
self.assertEqual(domain_information.generic_org_type, DomainRequest.OrganizationChoices.CITY)
|
||||||
|
|
||||||
|
# Test for election
|
||||||
|
self.assertEqual(
|
||||||
|
domain_information_election.organization_type, DomainRequest.OrgChoicesElectionOffice.CITY_ELECTION
|
||||||
|
)
|
||||||
|
self.assertEqual(domain_information_election.is_election_board, True)
|
||||||
|
self.assertEqual(domain_information_election.generic_org_type, DomainRequest.OrganizationChoices.CITY)
|
||||||
|
|
|
@ -591,7 +591,7 @@ class ExportDataTest(MockDb, MockEppLib):
|
||||||
"MANAGED DOMAINS COUNTS AT END DATE\n"
|
"MANAGED DOMAINS COUNTS AT END DATE\n"
|
||||||
"Total,Federal,Interstate,State or territory,Tribal,County,City,"
|
"Total,Federal,Interstate,State or territory,Tribal,County,City,"
|
||||||
"Special district,School district,Election office\n"
|
"Special district,School district,Election office\n"
|
||||||
"3,2,1,0,0,0,0,0,0,2\n"
|
"3,2,1,0,0,0,0,0,0,0\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Domain name,Domain type,Domain manager 1,DM1 status,Domain manager 2,DM2 status,"
|
"Domain name,Domain type,Domain manager 1,DM1 status,Domain manager 2,DM2 status,"
|
||||||
"Domain manager 3,DM3 status,Domain manager 4,DM4 status\n"
|
"Domain manager 3,DM3 status,Domain manager 4,DM4 status\n"
|
||||||
|
@ -718,7 +718,12 @@ class HelperFunctions(MockDb):
|
||||||
}
|
}
|
||||||
# Test with distinct
|
# Test with distinct
|
||||||
managed_domains_sliced_at_end_date = get_sliced_domains(filter_condition)
|
managed_domains_sliced_at_end_date = get_sliced_domains(filter_condition)
|
||||||
expected_content = [3, 2, 1, 0, 0, 0, 0, 0, 0, 2]
|
expected_content = [3, 2, 1, 0, 0, 0, 0, 0, 0, 0]
|
||||||
|
self.assertEqual(managed_domains_sliced_at_end_date, expected_content)
|
||||||
|
|
||||||
|
# Test without distinct
|
||||||
|
managed_domains_sliced_at_end_date = get_sliced_domains(filter_condition)
|
||||||
|
expected_content = [3, 2, 1, 0, 0, 0, 0, 0, 0, 0]
|
||||||
self.assertEqual(managed_domains_sliced_at_end_date, expected_content)
|
self.assertEqual(managed_domains_sliced_at_end_date, expected_content)
|
||||||
|
|
||||||
def test_get_sliced_requests(self):
|
def test_get_sliced_requests(self):
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
|
|
||||||
from registrar.models import Contact
|
from registrar.models import Contact
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue