This commit is contained in:
CocoByte 2024-11-24 23:42:42 -07:00
parent ca8cfda03d
commit 34ba850277
No known key found for this signature in database
GPG key ID: BBFAA2526384C97F
7 changed files with 263 additions and 189 deletions

View file

@ -1,11 +1,10 @@
import csv
from datetime import date from datetime import date
import logging import logging
import copy import copy
from django import forms from django import forms
from django.db.models import Value, CharField, Q from django.db.models import Value, CharField, Q
from django.db.models.functions import Concat, Coalesce from django.db.models.functions import Concat, Coalesce
from django.http import HttpResponse, HttpResponseRedirect from django.http import HttpResponseRedirect
from registrar.models.federal_agency import FederalAgency from registrar.models.federal_agency import FederalAgency
from registrar.utility.admin_helpers import ( from registrar.utility.admin_helpers import (
get_action_needed_reason_default_email, get_action_needed_reason_default_email,
@ -1457,17 +1456,17 @@ class DomainInformationResource(resources.ModelResource):
# Override exports for these columns in DomainInformation to use converted values. These values # Override exports for these columns in DomainInformation to use converted values. These values
# come from @Property functions, which are not automatically included in the export and which we # come from @Property functions, which are not automatically included in the export and which we
# want to use in place of the native fields. # want to use in place of the native fields.
organization_name = fields.Field(attribute='converted_organization_name', column_name='organization_name') organization_name = fields.Field(attribute="converted_organization_name", column_name="organization_name")
generic_org_type = fields.Field(attribute='converted_generic_org_type', column_name='generic_org_type') generic_org_type = fields.Field(attribute="converted_generic_org_type", column_name="generic_org_type")
federal_type = fields.Field(attribute='converted_federal_type', column_name='federal_type') federal_type = fields.Field(attribute="converted_federal_type", column_name="federal_type")
federal_agency = fields.Field(attribute='converted_federal_agency', column_name='federal_agency') federal_agency = fields.Field(attribute="converted_federal_agency", column_name="federal_agency")
senior_official = fields.Field(attribute='converted_senior_official', column_name='senior_official') senior_official = fields.Field(attribute="converted_senior_official", column_name="senior_official")
address_line1 = fields.Field(attribute='converted_address_line1', column_name='address_line1') address_line1 = fields.Field(attribute="converted_address_line1", column_name="address_line1")
address_line2 = fields.Field(attribute='converted_address_line2', column_name='address_line2') address_line2 = fields.Field(attribute="converted_address_line2", column_name="address_line2")
city = fields.Field(attribute='converted_city', column_name='city') city = fields.Field(attribute="converted_city", column_name="city")
state_territory = fields.Field(attribute='converted_state_territory', column_name='state_territory') state_territory = fields.Field(attribute="converted_state_territory", column_name="state_territory")
zipcode = fields.Field(attribute='converted_zipcode', column_name='zipcode') zipcode = fields.Field(attribute="converted_zipcode", column_name="zipcode")
urbanization = fields.Field(attribute='converted_urbanization', column_name='urbanization') urbanization = fields.Field(attribute="converted_urbanization", column_name="urbanization")
# Custom getters for the above columns that map to @property functions instead of fields # Custom getters for the above columns that map to @property functions instead of fields
def dehydrate_organization_name(self, obj): def dehydrate_organization_name(self, obj):
@ -1504,8 +1503,6 @@ class DomainInformationResource(resources.ModelResource):
return obj.converted_urbanization return obj.converted_urbanization
class DomainInformationAdmin(ListHeaderAdmin, ImportExportModelAdmin): class DomainInformationAdmin(ListHeaderAdmin, ImportExportModelAdmin):
"""Customize domain information admin class.""" """Customize domain information admin class."""
@ -1515,7 +1512,7 @@ class DomainInformationAdmin(ListHeaderAdmin, ImportExportModelAdmin):
organization in the Domain Information object.""" organization in the Domain Information object."""
title = "generic organization" title = "generic organization"
parameter_name = 'converted_generic_orgs' parameter_name = "converted_generic_orgs"
def lookups(self, request, model_admin): def lookups(self, request, model_admin):
converted_generic_orgs = set() converted_generic_orgs = set()
@ -1533,7 +1530,10 @@ class DomainInformationAdmin(ListHeaderAdmin, ImportExportModelAdmin):
return queryset.filter( return queryset.filter(
# Filter based on the generic org value returned by converted_generic_org_type # Filter based on the generic org value returned by converted_generic_org_type
id__in=[ id__in=[
domainInfo.id for domainInfo in queryset if domainInfo.converted_generic_org_type and domainInfo.converted_generic_org_type == self.value() domainInfo.id
for domainInfo in queryset
if domainInfo.converted_generic_org_type
and domainInfo.converted_generic_org_type == self.value()
] ]
) )
return queryset return queryset
@ -1709,18 +1709,18 @@ class DomainRequestResource(FsmModelResource):
# Override exports for these columns in DomainInformation to use converted values. These values # Override exports for these columns in DomainInformation to use converted values. These values
# come from @Property functions, which are not automatically included in the export and which we # come from @Property functions, which are not automatically included in the export and which we
# want to use in place of the native fields. # want to use in place of the native fields.
organization_name = fields.Field(attribute='converted_organization_name', column_name='organization_name') organization_name = fields.Field(attribute="converted_organization_name", column_name="organization_name")
generic_org_type = fields.Field(attribute='converted_generic_org_type', column_name='generic_org_type') generic_org_type = fields.Field(attribute="converted_generic_org_type", column_name="generic_org_type")
federal_type = fields.Field(attribute='converted_federal_type', column_name='federal_type') federal_type = fields.Field(attribute="converted_federal_type", column_name="federal_type")
federal_agency = fields.Field(attribute='converted_federal_agency', column_name='federal_agency') federal_agency = fields.Field(attribute="converted_federal_agency", column_name="federal_agency")
senior_official = fields.Field(attribute='converted_senior_official', column_name='senior_official') senior_official = fields.Field(attribute="converted_senior_official", column_name="senior_official")
address_line1 = fields.Field(attribute='converted_address_line1', column_name='address_line1') address_line1 = fields.Field(attribute="converted_address_line1", column_name="address_line1")
address_line2 = fields.Field(attribute='converted_address_line2', column_name='address_line2') address_line2 = fields.Field(attribute="converted_address_line2", column_name="address_line2")
city = fields.Field(attribute='converted_city', column_name='city') city = fields.Field(attribute="converted_city", column_name="city")
state_territory = fields.Field(attribute='converted_state_territory', column_name='state_territory') state_territory = fields.Field(attribute="converted_state_territory", column_name="state_territory")
zipcode = fields.Field(attribute='converted_zipcode', column_name='zipcode') zipcode = fields.Field(attribute="converted_zipcode", column_name="zipcode")
urbanization = fields.Field(attribute='converted_urbanization', column_name='urbanization') urbanization = fields.Field(attribute="converted_urbanization", column_name="urbanization")
senior_official = fields.Field(attribute='converted_urbanization', column_name='senior official') senior_official = fields.Field(attribute="converted_urbanization", column_name="senior official")
# Custom getters for the above columns that map to @property functions instead of fields # Custom getters for the above columns that map to @property functions instead of fields
def dehydrate_organization_name(self, obj): def dehydrate_organization_name(self, obj):
@ -2679,7 +2679,7 @@ class DomainResource(FsmModelResource):
class Meta: class Meta:
model = models.Domain model = models.Domain
#Override the default export so that it matches what is displayed in the admin table for Domains # Override the default export so that it matches what is displayed in the admin table for Domains
fields = ( fields = (
"name", "name",
"converted_generic_org_type", "converted_generic_org_type",
@ -2698,11 +2698,11 @@ class DomainResource(FsmModelResource):
) )
# Custom getters to retrieve the values from @Proprerty methods in DomainInfo # Custom getters to retrieve the values from @Proprerty methods in DomainInfo
converted_generic_org_type = fields.Field(attribute='converted_generic_org_type', column_name='generic org type') converted_generic_org_type = fields.Field(attribute="converted_generic_org_type", column_name="generic org type")
converted_federal_agency = fields.Field(attribute='converted_federal_agency', column_name='federal agency') converted_federal_agency = fields.Field(attribute="converted_federal_agency", column_name="federal agency")
converted_organization_name = fields.Field(attribute='converted_organization_name', column_name='organization name') converted_organization_name = fields.Field(attribute="converted_organization_name", column_name="organization name")
converted_city = fields.Field(attribute='converted_city', column_name='city') converted_city = fields.Field(attribute="converted_city", column_name="city")
converted_state_territory = fields.Field(attribute='converted_state_territory', column_name='state territory') converted_state_territory = fields.Field(attribute="converted_state_territory", column_name="state territory")
def dehydrate_converted_generic_org_type(self, obj): def dehydrate_converted_generic_org_type(self, obj):
return obj.domain_info.converted_generic_org_type return obj.domain_info.converted_generic_org_type
@ -2719,6 +2719,7 @@ class DomainResource(FsmModelResource):
def dehydrate_converted_state_territory(self, obj): def dehydrate_converted_state_territory(self, obj):
return obj.domain_info.converted_state_territory return obj.domain_info.converted_state_territory
class DomainAdmin(ListHeaderAdmin, ImportExportModelAdmin): class DomainAdmin(ListHeaderAdmin, ImportExportModelAdmin):
"""Custom domain admin class to add extra buttons.""" """Custom domain admin class to add extra buttons."""
@ -2749,7 +2750,7 @@ class DomainAdmin(ListHeaderAdmin, ImportExportModelAdmin):
organization in the Domain Information object.""" organization in the Domain Information object."""
title = "generic organization" title = "generic organization"
parameter_name = 'converted_generic_orgs' parameter_name = "converted_generic_orgs"
def lookups(self, request, model_admin): def lookups(self, request, model_admin):
converted_generic_orgs = set() converted_generic_orgs = set()
@ -2767,7 +2768,10 @@ class DomainAdmin(ListHeaderAdmin, ImportExportModelAdmin):
return queryset.filter( return queryset.filter(
# Filter based on the generic org value returned by converted_generic_org_type # Filter based on the generic org value returned by converted_generic_org_type
id__in=[ id__in=[
domain.id for domain in queryset if domain.domain_info.converted_generic_org_type and domain.domain_info.converted_generic_org_type == self.value() domain.id
for domain in queryset
if domain.domain_info.converted_generic_org_type
and domain.domain_info.converted_generic_org_type == self.value()
] ]
) )
return queryset return queryset
@ -2778,7 +2782,7 @@ class DomainAdmin(ListHeaderAdmin, ImportExportModelAdmin):
federal type in the Domain Information object.""" federal type in the Domain Information object."""
title = "federal type" title = "federal type"
parameter_name = 'converted_federal_types' parameter_name = "converted_federal_types"
def lookups(self, request, model_admin): def lookups(self, request, model_admin):
converted_federal_types = set() converted_federal_types = set()
@ -2797,12 +2801,14 @@ class DomainAdmin(ListHeaderAdmin, ImportExportModelAdmin):
return queryset.filter( return queryset.filter(
# Filter based on the generic org value returned by converted_generic_org_type # Filter based on the generic org value returned by converted_generic_org_type
id__in=[ id__in=[
domain.id for domain in queryset if domain.domain_info.converted_federal_type and domain.domain_info.converted_federal_type == self.value() domain.id
for domain in queryset
if domain.domain_info.converted_federal_type
and domain.domain_info.converted_federal_type == self.value()
] ]
) )
return queryset return queryset
def get_queryset(self, request): def get_queryset(self, request):
"""Custom get_queryset to filter by portfolio if portfolio is in the """Custom get_queryset to filter by portfolio if portfolio is in the
request params.""" request params."""
@ -2853,6 +2859,7 @@ class DomainAdmin(ListHeaderAdmin, ImportExportModelAdmin):
@admin.display(description=_("Generic Org Type")) @admin.display(description=_("Generic Org Type"))
def converted_generic_org_type(self, obj): def converted_generic_org_type(self, obj):
return obj.domain_info.converted_generic_org_type return obj.domain_info.converted_generic_org_type
converted_generic_org_type.admin_order_field = "domain_info__converted_generic_org_type" # type: ignore converted_generic_org_type.admin_order_field = "domain_info__converted_generic_org_type" # type: ignore
# Use native value for the change form # Use native value for the change form
@ -2863,6 +2870,7 @@ class DomainAdmin(ListHeaderAdmin, ImportExportModelAdmin):
@admin.display(description=_("Federal Agency")) @admin.display(description=_("Federal Agency"))
def converted_federal_agency(self, obj): def converted_federal_agency(self, obj):
return obj.domain_info.converted_federal_agency return obj.domain_info.converted_federal_agency
converted_federal_agency.admin_order_field = "domain_info__converted_federal_agency" # type: ignore converted_federal_agency.admin_order_field = "domain_info__converted_federal_agency" # type: ignore
# Use native value for the change form # Use native value for the change form
@ -2877,6 +2885,7 @@ class DomainAdmin(ListHeaderAdmin, ImportExportModelAdmin):
@admin.display(description=_("Federal Type")) @admin.display(description=_("Federal Type"))
def converted_federal_type(self, obj): def converted_federal_type(self, obj):
return obj.domain_info.converted_federal_type return obj.domain_info.converted_federal_type
converted_federal_type.admin_order_field = "domain_info__converted_federal_type" # type: ignore converted_federal_type.admin_order_field = "domain_info__converted_federal_type" # type: ignore
# Use native value for the change form # Use native value for the change form
@ -2888,6 +2897,7 @@ class DomainAdmin(ListHeaderAdmin, ImportExportModelAdmin):
@admin.display(description=_("Organization Name")) @admin.display(description=_("Organization Name"))
def converted_organization_name(self, obj): def converted_organization_name(self, obj):
return obj.domain_info.converted_organization_name return obj.domain_info.converted_organization_name
converted_organization_name.admin_order_field = "domain_info__converted_organization_name" # type: ignore converted_organization_name.admin_order_field = "domain_info__converted_organization_name" # type: ignore
# Use native value for the change form # Use native value for the change form
@ -2899,6 +2909,7 @@ class DomainAdmin(ListHeaderAdmin, ImportExportModelAdmin):
@admin.display(description=_("City")) @admin.display(description=_("City"))
def converted_city(self, obj): def converted_city(self, obj):
return obj.domain_info.converted_city return obj.domain_info.converted_city
converted_city.admin_order_field = "domain_info__converted_city" # type: ignore converted_city.admin_order_field = "domain_info__converted_city" # type: ignore
# Use native value for the change form # Use native value for the change form
@ -2910,13 +2921,13 @@ class DomainAdmin(ListHeaderAdmin, ImportExportModelAdmin):
@admin.display(description=_("State / territory")) @admin.display(description=_("State / territory"))
def converted_state_territory(self, obj): def converted_state_territory(self, obj):
return obj.domain_info.converted_state_territory return obj.domain_info.converted_state_territory
converted_state_territory.admin_order_field = "domain_info__converted_state_territory" # type: ignore converted_state_territory.admin_order_field = "domain_info__converted_state_territory" # type: ignore
# Use native value for the change form # Use native value for the change form
def state_territory(self, obj): def state_territory(self, obj):
return obj.domain_info.state_territory if obj.domain_info else None return obj.domain_info.state_territory if obj.domain_info else None
def dnssecdata(self, obj): def dnssecdata(self, obj):
return "Yes" if obj.dnssecdata else "No" return "Yes" if obj.dnssecdata else "No"
@ -2948,7 +2959,6 @@ class DomainAdmin(ListHeaderAdmin, ImportExportModelAdmin):
custom_election_board.admin_order_field = "domain_info__is_election_board" # type: ignore custom_election_board.admin_order_field = "domain_info__is_election_board" # type: ignore
custom_election_board.short_description = "Election office" # type: ignore custom_election_board.short_description = "Election office" # type: ignore
# Search # Search
search_fields = ["name"] search_fields = ["name"]
search_help_text = "Search by domain name." search_help_text = "Search by domain name."

View file

@ -493,5 +493,3 @@ class DomainInformation(TimeStampedModel):
if self.portfolio: if self.portfolio:
return self.portfolio.urbanization return self.portfolio.urbanization
return self.urbanization return self.urbanization

View file

@ -63,10 +63,10 @@ class CsvReportsTest(MockDbForSharedTests):
fake_open = mock_open() fake_open = mock_open()
expected_file_content = [ expected_file_content = [
call("Domain name,Domain type,Agency,Organization name,City,State,Security contact email\r\n"), call("Domain name,Domain type,Agency,Organization name,City,State,Security contact email\r\n"),
call('cdomain11.gov,Federal - Executive,183,,,,(blank)\r\n'), call("cdomain11.gov,Federal - Executive,183,,,,(blank)\r\n"),
call('cdomain1.gov,Federal - Executive,183,,,,(blank)\r\n'), call("cdomain1.gov,Federal - Executive,183,,,,(blank)\r\n"),
call('adomain10.gov,Federal,8,,,,(blank)\r\n'), call("adomain10.gov,Federal,8,,,,(blank)\r\n"),
call('ddomain3.gov,Federal,8,,,,(blank)\r\n'), call("ddomain3.gov,Federal,8,,,,(blank)\r\n"),
] ]
# We don't actually want to write anything for a test case, # We don't actually want to write anything for a test case,
# we just want to verify what is being written. # we just want to verify what is being written.
@ -85,11 +85,11 @@ class CsvReportsTest(MockDbForSharedTests):
fake_open = mock_open() fake_open = mock_open()
expected_file_content = [ expected_file_content = [
call("Domain name,Domain type,Agency,Organization name,City,State,Security contact email\r\n"), call("Domain name,Domain type,Agency,Organization name,City,State,Security contact email\r\n"),
call('cdomain11.gov,Federal - Executive,183,,,,(blank)\r\n'), call("cdomain11.gov,Federal - Executive,183,,,,(blank)\r\n"),
call('cdomain1.gov,Federal - Executive,183,,,,(blank)\r\n'), call("cdomain1.gov,Federal - Executive,183,,,,(blank)\r\n"),
call('adomain10.gov,Federal,8,,,,(blank)\r\n'), call("adomain10.gov,Federal,8,,,,(blank)\r\n"),
call('ddomain3.gov,Federal,8,,,,(blank)\r\n'), call("ddomain3.gov,Federal,8,,,,(blank)\r\n"),
call('zdomain12.gov,Interstate,,,,,(blank)\r\n'), call("zdomain12.gov,Interstate,,,,,(blank)\r\n"),
] ]
# We don't actually want to write anything for a test case, # We don't actually want to write anything for a test case,
# we just want to verify what is being written. # we just want to verify what is being written.
@ -247,7 +247,7 @@ class ExportDataTest(MockDbForIndividualTests, MockEppLib):
"SO email,Security contact email,Domain managers,Invited domain managers\n" "SO email,Security contact email,Domain managers,Invited domain managers\n"
"cdomain11.gov,Ready,2024-04-02,(blank),Federal - Executive,188,,,, ,,(blank),meoward@rocks.com,\n" "cdomain11.gov,Ready,2024-04-02,(blank),Federal - Executive,188,,,, ,,(blank),meoward@rocks.com,\n"
"defaultsecurity.gov,Ready,2023-11-01,(blank),Federal - Executive,188,,,, ,,(blank)," "defaultsecurity.gov,Ready,2023-11-01,(blank),Federal - Executive,188,,,, ,,(blank),"
"\"big_lebowski@dude.co, info@example.com, meoward@rocks.com\",woofwardthethird@rocks.com\n" '"big_lebowski@dude.co, info@example.com, meoward@rocks.com",woofwardthethird@rocks.com\n'
"adomain10.gov,Ready,2024-04-03,(blank),Federal,189,,,, ,,(blank),,squeaker@rocks.com\n" "adomain10.gov,Ready,2024-04-03,(blank),Federal,189,,,, ,,(blank),,squeaker@rocks.com\n"
"bdomain4.gov,Unknown,(blank),(blank),Federal,189,,,, ,,(blank),,\n" "bdomain4.gov,Unknown,(blank),(blank),Federal,189,,,, ,,(blank),,\n"
"bdomain5.gov,Deleted,(blank),(blank),Federal,189,,,, ,,(blank),,\n" "bdomain5.gov,Deleted,(blank),(blank),Federal,189,,,, ,,(blank),,\n"
@ -303,9 +303,9 @@ class ExportDataTest(MockDbForIndividualTests, MockEppLib):
"City,State,SO,SO email," "City,State,SO,SO email,"
"Security contact email,Domain managers,Invited domain managers\n" "Security contact email,Domain managers,Invited domain managers\n"
"defaultsecurity.gov,Ready,2023-11-01,(blank),Federal - Executive,190,,,, ,,(blank)," "defaultsecurity.gov,Ready,2023-11-01,(blank),Federal - Executive,190,,,, ,,(blank),"
"\"big_lebowski@dude.co, info@example.com, meoward@rocks.com\",woofwardthethird@rocks.com\n" '"big_lebowski@dude.co, info@example.com, meoward@rocks.com",woofwardthethird@rocks.com\n'
"adomain2.gov,Dns needed,(blank),(blank),Interstate,,,,, ,,(blank)," "adomain2.gov,Dns needed,(blank),(blank),Interstate,,,,, ,,(blank),"
"\"info@example.com, meoward@rocks.com\",squeaker@rocks.com\n" '"info@example.com, meoward@rocks.com",squeaker@rocks.com\n'
) )
# Normalize line endings and remove commas, # Normalize line endings and remove commas,
@ -313,8 +313,6 @@ class ExportDataTest(MockDbForIndividualTests, MockEppLib):
csv_content = csv_content.replace(",,", "").replace(",", "").replace(" ", "").replace("\r\n", "\n").strip() csv_content = csv_content.replace(",,", "").replace(",", "").replace(" ", "").replace("\r\n", "\n").strip()
expected_content = expected_content.replace(",,", "").replace(",", "").replace(" ", "").strip() expected_content = expected_content.replace(",,", "").replace(",", "").replace(" ", "").strip()
self.maxDiff = None self.maxDiff = None
self.assertEqual(csv_content, expected_content) self.assertEqual(csv_content, expected_content)

View file

@ -11,11 +11,21 @@ from registrar.models import (
PublicContact, PublicContact,
UserDomainRole, UserDomainRole,
) )
from django.db.models import Case, CharField, Count, DateField, F, ManyToManyField, Q, QuerySet, Value, When, ExpressionWrapper from django.db.models import (
Case,
CharField,
Count,
DateField,
F,
ManyToManyField,
Q,
QuerySet,
Value,
When,
)
from django.utils import timezone from django.utils import timezone
from django.db.models.functions import Concat, Coalesce from django.db.models.functions import Concat, Coalesce
from django.contrib.postgres.aggregates import StringAgg from django.contrib.postgres.aggregates import StringAgg
from registrar.models.user import User
from registrar.models.utility.generic_helper import convert_queryset_to_dict from registrar.models.utility.generic_helper import convert_queryset_to_dict
from registrar.templatetags.custom_filters import get_region from registrar.templatetags.custom_filters import get_region
from registrar.utility.constants import BranchChoices from registrar.utility.constants import BranchChoices
@ -297,56 +307,56 @@ class DomainExport(BaseExport):
# model objects as we export data, trying to reinstate model objects in order to grab @property # model objects as we export data, trying to reinstate model objects in order to grab @property
# values negatively impacts performance. Therefore, we will follow best practice and use annotations # values negatively impacts performance. Therefore, we will follow best practice and use annotations
return { return {
"converted_federal_agency" : Case( "converted_federal_agency": Case(
# When portfolio is present, use its value instead # When portfolio is present, use its value instead
When(portfolio__isnull=False, then=F("portfolio__federal_agency")), When(portfolio__isnull=False, then=F("portfolio__federal_agency")),
# Otherwise, return the natively assigned value # Otherwise, return the natively assigned value
default=F("federal_agency"), default=F("federal_agency"),
output_field=CharField(), output_field=CharField(),
), ),
"converted_organization_name" : Case( "converted_organization_name": Case(
# When portfolio is present, use its value instead # When portfolio is present, use its value instead
When(portfolio__isnull=False, then=F("portfolio__organization_name")), When(portfolio__isnull=False, then=F("portfolio__organization_name")),
# Otherwise, return the natively assigned value # Otherwise, return the natively assigned value
default=F("organization_name"), default=F("organization_name"),
output_field=CharField(), output_field=CharField(),
), ),
"converted_city" : Case( "converted_city": Case(
# When portfolio is present, use its value instead # When portfolio is present, use its value instead
When(portfolio__isnull=False, then=F("portfolio__city")), When(portfolio__isnull=False, then=F("portfolio__city")),
# Otherwise, return the natively assigned value # Otherwise, return the natively assigned value
default=F("city"), default=F("city"),
output_field=CharField(), output_field=CharField(),
), ),
"converted_state_territory" : Case( "converted_state_territory": Case(
# When portfolio is present, use its value instead # When portfolio is present, use its value instead
When(portfolio__isnull=False, then=F("portfolio__state_territory")), When(portfolio__isnull=False, then=F("portfolio__state_territory")),
# Otherwise, return the natively assigned value # Otherwise, return the natively assigned value
default=F("state_territory"), default=F("state_territory"),
output_field=CharField(), output_field=CharField(),
), ),
"converted_so_email" : Case( "converted_so_email": Case(
# When portfolio is present, use its value instead # When portfolio is present, use its value instead
When(portfolio__isnull=False, then=F("portfolio__senior_official__email")), When(portfolio__isnull=False, then=F("portfolio__senior_official__email")),
# Otherwise, return the natively assigned senior official # Otherwise, return the natively assigned senior official
default=F("senior_official__email"), default=F("senior_official__email"),
output_field=CharField(), output_field=CharField(),
), ),
"converted_senior_official_last_name" : Case( "converted_senior_official_last_name": Case(
# When portfolio is present, use its value instead # When portfolio is present, use its value instead
When(portfolio__isnull=False, then=F("portfolio__senior_official__last_name")), When(portfolio__isnull=False, then=F("portfolio__senior_official__last_name")),
# Otherwise, return the natively assigned senior official # Otherwise, return the natively assigned senior official
default=F("senior_official__last_name"), default=F("senior_official__last_name"),
output_field=CharField(), output_field=CharField(),
), ),
"converted_senior_official_first_name" : Case( "converted_senior_official_first_name": Case(
# When portfolio is present, use its value instead # When portfolio is present, use its value instead
When(portfolio__isnull=False, then=F("portfolio__senior_official__first_name")), When(portfolio__isnull=False, then=F("portfolio__senior_official__first_name")),
# Otherwise, return the natively assigned senior official # Otherwise, return the natively assigned senior official
default=F("senior_official__first_name"), default=F("senior_official__first_name"),
output_field=CharField(), output_field=CharField(),
), ),
"converted_senior_official_title" : Case( "converted_senior_official_title": Case(
# When portfolio is present, use its value instead # When portfolio is present, use its value instead
When(portfolio__isnull=False, then=F("portfolio__senior_official__title")), When(portfolio__isnull=False, then=F("portfolio__senior_official__title")),
# Otherwise, return the natively assigned senior official # Otherwise, return the natively assigned senior official
@ -355,12 +365,15 @@ class DomainExport(BaseExport):
), ),
"converted_so_name": Case( "converted_so_name": Case(
# When portfolio is present, use that senior official instead # When portfolio is present, use that senior official instead
When(portfolio__isnull=False, then=Concat( When(
portfolio__isnull=False,
then=Concat(
Coalesce(F("portfolio__senior_official__first_name"), Value("")), Coalesce(F("portfolio__senior_official__first_name"), Value("")),
Value(" "), Value(" "),
Coalesce(F("portfolio__senior_official__last_name"), Value("")), Coalesce(F("portfolio__senior_official__last_name"), Value("")),
output_field=CharField(), output_field=CharField(),
)), ),
),
# Otherwise, return the natively assigned senior official # Otherwise, return the natively assigned senior official
default=Concat( default=Concat(
Coalesce(F("senior_official__first_name"), Value("")), Coalesce(F("senior_official__first_name"), Value("")),
@ -479,7 +492,6 @@ class DomainExport(BaseExport):
): ):
security_contact_email = "(blank)" security_contact_email = "(blank)"
# create a dictionary of fields which can be included in output. # create a dictionary of fields which can be included in output.
# "extra_fields" are precomputed fields (generated in the DB or parsed). # "extra_fields" are precomputed fields (generated in the DB or parsed).
FIELDS = { FIELDS = {
@ -510,7 +522,9 @@ class DomainExport(BaseExport):
return domain_infos_to_filter.filter( return domain_infos_to_filter.filter(
# Filter based on the generic org value returned by converted_generic_org_type # Filter based on the generic org value returned by converted_generic_org_type
id__in=[ id__in=[
domainInfos.id for domainInfos in domain_infos_to_filter if domainInfos.converted_generic_org_type and domainInfos.converted_generic_org_type == org_to_filter_by domainInfos.id
for domainInfos in domain_infos_to_filter
if domainInfos.converted_generic_org_type and domainInfos.converted_generic_org_type == org_to_filter_by
] ]
) )
@ -523,19 +537,47 @@ class DomainExport(BaseExport):
domain_informations = DomainInformation.objects.all().filter(**filter_condition).distinct() domain_informations = DomainInformation.objects.all().filter(**filter_condition).distinct()
domains_count = domain_informations.count() domains_count = domain_informations.count()
federal = cls.get_filtered_domain_infos_by_org(domain_informations, DomainRequest.OrganizationChoices.FEDERAL).distinct().count() federal = (
interstate = cls.get_filtered_domain_infos_by_org(domain_informations, DomainRequest.OrganizationChoices.INTERSTATE).count() cls.get_filtered_domain_infos_by_org(domain_informations, DomainRequest.OrganizationChoices.FEDERAL)
state_or_territory = ( .distinct()
cls.get_filtered_domain_infos_by_org(domain_informations, DomainRequest.OrganizationChoices.STATE_OR_TERRITORY).distinct().count() .count()
)
interstate = cls.get_filtered_domain_infos_by_org(
domain_informations, DomainRequest.OrganizationChoices.INTERSTATE
).count()
state_or_territory = (
cls.get_filtered_domain_infos_by_org(
domain_informations, DomainRequest.OrganizationChoices.STATE_OR_TERRITORY
)
.distinct()
.count()
)
tribal = (
cls.get_filtered_domain_infos_by_org(domain_informations, DomainRequest.OrganizationChoices.TRIBAL)
.distinct()
.count()
)
county = (
cls.get_filtered_domain_infos_by_org(domain_informations, DomainRequest.OrganizationChoices.COUNTY)
.distinct()
.count()
)
city = (
cls.get_filtered_domain_infos_by_org(domain_informations, DomainRequest.OrganizationChoices.CITY)
.distinct()
.count()
) )
tribal = cls.get_filtered_domain_infos_by_org(domain_informations, DomainRequest.OrganizationChoices.TRIBAL).distinct().count()
county = cls.get_filtered_domain_infos_by_org(domain_informations, DomainRequest.OrganizationChoices.COUNTY).distinct().count()
city = cls.get_filtered_domain_infos_by_org(domain_informations, DomainRequest.OrganizationChoices.CITY).distinct().count()
special_district = ( special_district = (
cls.get_filtered_domain_infos_by_org(domain_informations, DomainRequest.OrganizationChoices.SPECIAL_DISTRICT).distinct().count() cls.get_filtered_domain_infos_by_org(
domain_informations, DomainRequest.OrganizationChoices.SPECIAL_DISTRICT
)
.distinct()
.count()
) )
school_district = ( school_district = (
cls.get_filtered_domain_infos_by_org(domain_informations, DomainRequest.OrganizationChoices.SCHOOL_DISTRICT).distinct().count() cls.get_filtered_domain_infos_by_org(domain_informations, DomainRequest.OrganizationChoices.SCHOOL_DISTRICT)
.distinct()
.count()
) )
election_board = domain_informations.filter(is_election_board=True).distinct().count() election_board = domain_informations.filter(is_election_board=True).distinct().count()
@ -632,7 +674,6 @@ class DomainDataType(DomainExport):
""" """
return ["permissions"] return ["permissions"]
@classmethod @classmethod
def get_related_table_fields(cls): def get_related_table_fields(cls):
""" """
@ -1287,11 +1328,13 @@ class DomainRequestExport(BaseExport):
return domain_requests_to_filter.filter( return domain_requests_to_filter.filter(
# Filter based on the generic org value returned by converted_generic_org_type # Filter based on the generic org value returned by converted_generic_org_type
id__in=[ id__in=[
domainRequest.id for domainRequest in domain_requests_to_filter if domainRequest.converted_generic_org_type and domainRequest.converted_generic_org_type == org_to_filter_by domainRequest.id
for domainRequest in domain_requests_to_filter
if domainRequest.converted_generic_org_type
and domainRequest.converted_generic_org_type == org_to_filter_by
] ]
) )
@classmethod @classmethod
def get_computed_fields(cls, delimiter=", "): def get_computed_fields(cls, delimiter=", "):
""" """
@ -1302,56 +1345,56 @@ class DomainRequestExport(BaseExport):
# model objects as we export data, trying to reinstate model objects in order to grab @property # model objects as we export data, trying to reinstate model objects in order to grab @property
# values negatively impacts performance. Therefore, we will follow best practice and use annotations # values negatively impacts performance. Therefore, we will follow best practice and use annotations
return { return {
"converted_federal_agency" : Case( "converted_federal_agency": Case(
# When portfolio is present, use its value instead # When portfolio is present, use its value instead
When(portfolio__isnull=False, then=F("portfolio__federal_agency")), When(portfolio__isnull=False, then=F("portfolio__federal_agency")),
# Otherwise, return the natively assigned value # Otherwise, return the natively assigned value
default=F("federal_agency"), default=F("federal_agency"),
output_field=CharField(), output_field=CharField(),
), ),
"converted_organization_name" : Case( "converted_organization_name": Case(
# When portfolio is present, use its value instead # When portfolio is present, use its value instead
When(portfolio__isnull=False, then=F("portfolio__organization_name")), When(portfolio__isnull=False, then=F("portfolio__organization_name")),
# Otherwise, return the natively assigned value # Otherwise, return the natively assigned value
default=F("organization_name"), default=F("organization_name"),
output_field=CharField(), output_field=CharField(),
), ),
"converted_city" : Case( "converted_city": Case(
# When portfolio is present, use its value instead # When portfolio is present, use its value instead
When(portfolio__isnull=False, then=F("portfolio__city")), When(portfolio__isnull=False, then=F("portfolio__city")),
# Otherwise, return the natively assigned value # Otherwise, return the natively assigned value
default=F("city"), default=F("city"),
output_field=CharField(), output_field=CharField(),
), ),
"converted_state_territory" : Case( "converted_state_territory": Case(
# When portfolio is present, use its value instead # When portfolio is present, use its value instead
When(portfolio__isnull=False, then=F("portfolio__state_territory")), When(portfolio__isnull=False, then=F("portfolio__state_territory")),
# Otherwise, return the natively assigned value # Otherwise, return the natively assigned value
default=F("state_territory"), default=F("state_territory"),
output_field=CharField(), output_field=CharField(),
), ),
"converted_so_email" : Case( "converted_so_email": Case(
# When portfolio is present, use its value instead # When portfolio is present, use its value instead
When(portfolio__isnull=False, then=F("portfolio__senior_official__email")), When(portfolio__isnull=False, then=F("portfolio__senior_official__email")),
# Otherwise, return the natively assigned senior official # Otherwise, return the natively assigned senior official
default=F("senior_official__email"), default=F("senior_official__email"),
output_field=CharField(), output_field=CharField(),
), ),
"converted_senior_official_last_name" : Case( "converted_senior_official_last_name": Case(
# When portfolio is present, use its value instead # When portfolio is present, use its value instead
When(portfolio__isnull=False, then=F("portfolio__senior_official__last_name")), When(portfolio__isnull=False, then=F("portfolio__senior_official__last_name")),
# Otherwise, return the natively assigned senior official # Otherwise, return the natively assigned senior official
default=F("senior_official__last_name"), default=F("senior_official__last_name"),
output_field=CharField(), output_field=CharField(),
), ),
"converted_senior_official_first_name" : Case( "converted_senior_official_first_name": Case(
# When portfolio is present, use its value instead # When portfolio is present, use its value instead
When(portfolio__isnull=False, then=F("portfolio__senior_official__first_name")), When(portfolio__isnull=False, then=F("portfolio__senior_official__first_name")),
# Otherwise, return the natively assigned senior official # Otherwise, return the natively assigned senior official
default=F("senior_official__first_name"), default=F("senior_official__first_name"),
output_field=CharField(), output_field=CharField(),
), ),
"converted_senior_official_title" : Case( "converted_senior_official_title": Case(
# When portfolio is present, use its value instead # When portfolio is present, use its value instead
When(portfolio__isnull=False, then=F("portfolio__senior_official__title")), When(portfolio__isnull=False, then=F("portfolio__senior_official__title")),
# Otherwise, return the natively assigned senior official # Otherwise, return the natively assigned senior official
@ -1360,12 +1403,15 @@ class DomainRequestExport(BaseExport):
), ),
"converted_so_name": Case( "converted_so_name": Case(
# When portfolio is present, use that senior official instead # When portfolio is present, use that senior official instead
When(portfolio__isnull=False, then=Concat( When(
portfolio__isnull=False,
then=Concat(
Coalesce(F("portfolio__senior_official__first_name"), Value("")), Coalesce(F("portfolio__senior_official__first_name"), Value("")),
Value(" "), Value(" "),
Coalesce(F("portfolio__senior_official__last_name"), Value("")), Coalesce(F("portfolio__senior_official__last_name"), Value("")),
output_field=CharField(), output_field=CharField(),
)), ),
),
# Otherwise, return the natively assigned senior official # Otherwise, return the natively assigned senior official
default=Concat( default=Concat(
Coalesce(F("senior_official__first_name"), Value("")), Coalesce(F("senior_official__first_name"), Value("")),
@ -1382,19 +1428,43 @@ class DomainRequestExport(BaseExport):
"""Get filtered requests counts sliced by org type and election office.""" """Get filtered requests counts sliced by org type and election office."""
requests = DomainRequest.objects.all().filter(**filter_condition).distinct() requests = DomainRequest.objects.all().filter(**filter_condition).distinct()
requests_count = requests.count() requests_count = requests.count()
federal = cls.get_filtered_domain_requests_by_org(requests, DomainRequest.OrganizationChoices.FEDERAL).distinct().count() federal = (
interstate = cls.get_filtered_domain_requests_by_org(requests, DomainRequest.OrganizationChoices.INTERSTATE).distinct().count() cls.get_filtered_domain_requests_by_org(requests, DomainRequest.OrganizationChoices.FEDERAL)
state_or_territory = ( .distinct()
cls.get_filtered_domain_requests_by_org(requests, DomainRequest.OrganizationChoices.STATE_OR_TERRITORY).distinct().count() .count()
)
interstate = (
cls.get_filtered_domain_requests_by_org(requests, DomainRequest.OrganizationChoices.INTERSTATE)
.distinct()
.count()
)
state_or_territory = (
cls.get_filtered_domain_requests_by_org(requests, DomainRequest.OrganizationChoices.STATE_OR_TERRITORY)
.distinct()
.count()
)
tribal = (
cls.get_filtered_domain_requests_by_org(requests, DomainRequest.OrganizationChoices.TRIBAL)
.distinct()
.count()
)
county = (
cls.get_filtered_domain_requests_by_org(requests, DomainRequest.OrganizationChoices.COUNTY)
.distinct()
.count()
)
city = (
cls.get_filtered_domain_requests_by_org(requests, DomainRequest.OrganizationChoices.CITY).distinct().count()
) )
tribal = cls.get_filtered_domain_requests_by_org(requests, DomainRequest.OrganizationChoices.TRIBAL).distinct().count()
county = cls.get_filtered_domain_requests_by_org(requests, DomainRequest.OrganizationChoices.COUNTY).distinct().count()
city = cls.get_filtered_domain_requests_by_org(requests, DomainRequest.OrganizationChoices.CITY).distinct().count()
special_district = ( special_district = (
cls.get_filtered_domain_requests_by_org(requests, DomainRequest.OrganizationChoices.SPECIAL_DISTRICT).distinct().count() cls.get_filtered_domain_requests_by_org(requests, DomainRequest.OrganizationChoices.SPECIAL_DISTRICT)
.distinct()
.count()
) )
school_district = ( school_district = (
cls.get_filtered_domain_requests_by_org(requests, DomainRequest.OrganizationChoices.SCHOOL_DISTRICT).distinct().count() cls.get_filtered_domain_requests_by_org(requests, DomainRequest.OrganizationChoices.SCHOOL_DISTRICT)
.distinct()
.count()
) )
election_board = requests.filter(is_election_board=True).distinct().count() election_board = requests.filter(is_election_board=True).distinct().count()
@ -1542,6 +1612,7 @@ class DomainRequestGrowth(DomainRequestExport):
""" """
return ["requested_domain__name"] return ["requested_domain__name"]
class DomainRequestDataFull(DomainRequestExport): class DomainRequestDataFull(DomainRequestExport):
""" """
Shows all but STARTED requests Shows all but STARTED requests
@ -1625,11 +1696,14 @@ class DomainRequestDataFull(DomainRequestExport):
computed_fields = super().get_computed_fields() computed_fields = super().get_computed_fields()
# Add additional computed fields # Add additional computed fields
computed_fields.update({ computed_fields.update(
{
"creator_approved_domains_count": cls.get_creator_approved_domains_count_query(), "creator_approved_domains_count": cls.get_creator_approved_domains_count_query(),
"creator_active_requests_count": cls.get_creator_active_requests_count_query(), "creator_active_requests_count": cls.get_creator_active_requests_count_query(),
"all_current_websites": StringAgg("current_websites__website", delimiter=delimiter, distinct=True), "all_current_websites": StringAgg("current_websites__website", delimiter=delimiter, distinct=True),
"all_alternative_domains": StringAgg("alternative_domains__website", delimiter=delimiter, distinct=True), "all_alternative_domains": StringAgg(
"alternative_domains__website", delimiter=delimiter, distinct=True
),
# Coerce the other contacts object to "{first_name} {last_name} {email}" # Coerce the other contacts object to "{first_name} {last_name} {email}"
"all_other_contacts": StringAgg( "all_other_contacts": StringAgg(
Concat( Concat(
@ -1642,7 +1716,8 @@ class DomainRequestDataFull(DomainRequestExport):
delimiter=delimiter, delimiter=delimiter,
distinct=True, distinct=True,
), ),
}) }
)
return computed_fields return computed_fields

View file

@ -13,13 +13,9 @@ from registrar.utility import csv_export
import logging import logging
# ---Logger
import logging
from venv import logger
from registrar.management.commands.utility.terminal_helper import TerminalColors, TerminalHelper
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class AnalyticsView(View): class AnalyticsView(View):
def get(self, request): def get(self, request):
thirty_days_ago = datetime.datetime.today() - datetime.timedelta(days=30) thirty_days_ago = datetime.datetime.today() - datetime.timedelta(days=30)
@ -165,10 +161,7 @@ class ExportDataType(View):
class ExportDataTypeUser(View): class ExportDataTypeUser(View):
"""Returns a domain report for a given user on the request""" """Returns a domain report for a given user on the request"""
TerminalHelper.colorful_logger(logger.info, TerminalColors.OKGREEN, f"ExportDataTypeUser")
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
TerminalHelper.colorful_logger(logger.info, TerminalColors.OKGREEN, f"ExportDataTypeUser -- get")
# match the CSV example with all the fields # match the CSV example with all the fields
response = HttpResponse(content_type="text/csv") response = HttpResponse(content_type="text/csv")
response["Content-Disposition"] = 'attachment; filename="your-domains.csv"' response["Content-Disposition"] = 'attachment; filename="your-domains.csv"'