Fine tuning

This commit is contained in:
zandercymatics 2024-06-05 15:13:36 -06:00
parent 6db7f138f4
commit f9cec62a03
No known key found for this signature in database
GPG key ID: FF4636ABEC9682B7
2 changed files with 81 additions and 51 deletions

View file

@ -124,6 +124,11 @@ 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"
@classmethod
def get_org_label(cls, org_name: str):
"""Returns the associated label for a given org name"""
return cls(org_name).label if org_name else None
class OrgChoicesElectionOffice(models.TextChoices): class OrgChoicesElectionOffice(models.TextChoices):
""" """
Primary organization choices for Django admin: Primary organization choices for Django admin:
@ -230,6 +235,11 @@ class DomainRequest(TimeStampedModel):
JUDICIAL = "judicial", "Judicial" JUDICIAL = "judicial", "Judicial"
LEGISLATIVE = "legislative", "Legislative" LEGISLATIVE = "legislative", "Legislative"
@classmethod
def get_branch_label(cls, branch_name: str):
"""Returns the associated label for a given org name"""
return cls(branch_name).label if branch_name else None
class RejectionReasons(models.TextChoices): class RejectionReasons(models.TextChoices):
DOMAIN_PURPOSE = "purpose_not_met", "Purpose requirements not met" DOMAIN_PURPOSE = "purpose_not_met", "Purpose requirements not met"
REQUESTOR = "requestor_not_eligible", "Requestor not eligible to make request" REQUESTOR = "requestor_not_eligible", "Requestor not eligible to make request"

View file

@ -1,20 +1,12 @@
import csv import csv
import logging import logging
from datetime import datetime from datetime import datetime
from django.db.models import QuerySet from registrar.models import Domain, DomainInvitation, DomainRequest, DomainInformation, User, PublicContact, UserDomainRole
from registrar.models.domain import Domain from django.db.models import QuerySet, Value, Case, When, CharField, Count, Q, F, Value, CharField
from registrar.models.domain_invitation import DomainInvitation
from registrar.models.domain_request import DomainRequest
from registrar.models.domain_information import DomainInformation
from django.db.models import Value, Case, When, CharField, Count, Q
from django.utils import timezone from django.utils import timezone
from django.core.paginator import Paginator from django.core.paginator import Paginator
from django.db.models import F, Value, CharField
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.public_contact import PublicContact
from registrar.models.user_domain_role import UserDomainRole
from registrar.utility.enums import DefaultEmail from registrar.utility.enums import DefaultEmail
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -731,7 +723,7 @@ class DomainRequestExport:
rows = [] rows = []
for request in page.object_list: for request in page.object_list:
try: try:
row = parse_row_for_requests(columns, request) row = DomainRequestExport.parse_row_for_requests(columns, request)
rows.append(row) rows.append(row)
except ValueError as err: except ValueError as err:
logger.error(f"csv_export -> Error when parsing row: {err}") logger.error(f"csv_export -> Error when parsing row: {err}")
@ -751,11 +743,11 @@ class DomainRequestExport:
"Domain request": request.get('requested_domain_name'), "Domain request": request.get('requested_domain_name'),
"Submitted at": request.get('submission_date'), # TODO - different format? "Submitted at": request.get('submission_date'), # TODO - different format?
"Status": request.get('status_display'), "Status": request.get('status_display'),
"Domain type": request.get('request_type'), # todo - revisit this, redundant fields "Domain type": request.get('domain_type'),
"Federal type": request.get('federal_type'), "Federal type": request.get("human_readable_federal_type"),
"Federal agency": request.get('federal_agency'), "Federal agency": request.get('federal_agency_name'),
"Organization name": request.get('organization_name'), "Organization name": request.get('organization_name'),
"Election office": request.get('is_election_board'), "Election office": request.get("human_readable_election_board"),
"City": request.get('city'), "City": request.get('city'),
"State/territory": request.get('state_territory'), "State/territory": request.get('state_territory'),
"Region": None, # TODO - what is this field? "Region": None, # TODO - what is this field?
@ -772,7 +764,7 @@ class DomainRequestExport:
"AO last name": request.get('authorizing_official__last_name', ""), "AO last name": request.get('authorizing_official__last_name', ""),
"AO email": request.get('authorizing_official__email', ""), "AO email": request.get('authorizing_official__email', ""),
"AO title/role": request.get('authorizing_official__title', ""), "AO title/role": request.get('authorizing_official__title', ""),
# End pf AO # End of AO
"Request purpose": request.get('purpose'), "Request purpose": request.get('purpose'),
"Request additional details": request.get('additional_details'), "Request additional details": request.get('additional_details'),
"Other contacts": request.get('all_other_contacts'), "Other contacts": request.get('all_other_contacts'),
@ -818,12 +810,31 @@ class DomainRequestExport:
parsed_requests = all_requests.annotate( parsed_requests = all_requests.annotate(
requested_domain_name=DomainRequestExport.get_requested_domain_name_query(), requested_domain_name=DomainRequestExport.get_requested_domain_name_query(),
approved_domain_name=F('approved_domain__name'), approved_domain_name=F('approved_domain__name'),
request_type=DomainRequestExport.get_request_type_query(),
).values( ).values(
"requested_domain_name", "requested_domain_name",
"request_type", "generic_org_type",
"federal_type",
"submission_date" "submission_date"
) )
# Set the domain_type field.
# Relies on a python function, get_organization_type_display, so we have to
# do this manually.
for request in parsed_requests:
# Handle the domain_type field. Defaults to the wrong variant.
org_type = request.get("generic_org_type")
federal_type = request.get("federal_type")
request["domain_type"] = None
if org_type:
readable_org_type = DomainRequest.OrganizationChoices.get_org_label(org_type)
if federal_type:
readable_federal_type = DomainRequest.BranchChoices.get_branch_label(federal_type)
request["domain_type"] = f"{readable_org_type} - {readable_federal_type}"
else:
request["domain_type"] = readable_org_type
DomainRequestExport.write_csv_for_requests(writer, columns, parsed_requests, should_write_header=True) DomainRequestExport.write_csv_for_requests(writer, columns, parsed_requests, should_write_header=True)
@staticmethod @staticmethod
@ -882,7 +893,7 @@ class DomainRequestExport:
Annotations (python-readable equivalents): Annotations (python-readable equivalents):
- requested_domain_name: `requested_domain.name If requested_domain.name is not None else default_message`. - requested_domain_name: `requested_domain.name If requested_domain.name is not None else default_message`.
- request_type: `f"{organization_type} | {federal_type}" If request.federal_type is not None else organization_type`. - request_type: `f"{generic_org_type} | {federal_type}" If request.federal_type is not None else generic_org_type`.
- additional_details: `f"{cisa_rep} | {anything_else}" If anything_else or cisa_rep else None`. - additional_details: `f"{cisa_rep} | {anything_else}" If anything_else or cisa_rep else None`.
- all_other_contacts: `[f"{c.first_name} {c.last_name} {c.email}" for c in request.other_contacts.all()].join(" | ")`. - all_other_contacts: `[f"{c.first_name} {c.last_name} {c.email}" for c in request.other_contacts.all()].join(" | ")`.
- all_current_websites: `# [w.website for w in request.current_websites.all()].join(" | ")`. - all_current_websites: `# [w.website for w in request.current_websites.all()].join(" | ")`.
@ -890,12 +901,15 @@ class DomainRequestExport:
""" # noqa """ # noqa
# As stated, this is equivalent to performing a bunch of if-statement like operations to # As stated, this is equivalent to performing a bunch of if-statement like operations to
# each of these fields inside a for loop. However, we want to avoid that for the sake # each of these fields inside a for loop. However, we want to avoid that for the sake
# of performance - especially on many-to-many fields (which would require repeated DB calls in the loop). # of performance - especially on many-to-many fields (which would require repeated DB calls in the loop).
# By doing these operations in the DB, we save a lot of computation time. # By doing these operations in the DB, we save a lot of computation time.
# We can do this for most fields, except ones that require us to grab .label (such as generic_org_type).
# For those fields, they will otherwise just return the value representation so we parse those manually.
parsed_requests = requests_to_convert.annotate( parsed_requests = requests_to_convert.annotate(
requested_domain_name=DomainRequestExport.get_requested_domain_name_query(), requested_domain_name=DomainRequestExport.get_requested_domain_name_query(),
request_type=DomainRequestExport.get_request_type_query(),
additional_details=DomainRequestExport.get_additional_details_query(), additional_details=DomainRequestExport.get_additional_details_query(),
all_other_contacts=StringAgg( all_other_contacts=StringAgg(
Concat('other_contacts__first_name', Value(' '), 'other_contacts__last_name', Value(' '), 'other_contacts__email'), Concat('other_contacts__first_name', Value(' '), 'other_contacts__last_name', Value(' '), 'other_contacts__email'),
@ -904,18 +918,29 @@ class DomainRequestExport:
), ),
all_current_websites=StringAgg('current_websites__website', delimiter=' | ', distinct=True), all_current_websites=StringAgg('current_websites__website', delimiter=' | ', distinct=True),
all_alternative_domains=StringAgg('alternative_domains__website', delimiter=' | ', distinct=True), all_alternative_domains=StringAgg('alternative_domains__website', delimiter=' | ', distinct=True),
# TODO - this is returning the wrong count
creator_approved_domains_count=Count( creator_approved_domains_count=Count(
'creator__domainrequest_set', 'creator__domain_requests_created__id',
filter=Q(status=DomainRequest.DomainRequestStatus.APPROVED), distinct=True filter=Q(creator__domain_requests_created__status=DomainRequest.DomainRequestStatus.APPROVED),
distinct=True
), ),
# TODO - this is returning the wrong count
creator_active_requests_count=Count( creator_active_requests_count=Count(
'creator__domainrequest_set', 'creator__domain_requests_created__id',
filter=Q(status__in=[ filter=Q(creator__domain_requests_created__status__in=[
DomainRequest.DomainRequestStatus.SUBMITTED, DomainRequest.DomainRequestStatus.SUBMITTED,
DomainRequest.DomainRequestStatus.IN_REVIEW, DomainRequest.DomainRequestStatus.IN_REVIEW,
DomainRequest.DomainRequestStatus.ACTION_NEEDED DomainRequest.DomainRequestStatus.ACTION_NEEDED
]), ]),
distinct=True distinct=True
),
federal_agency_name = F("federal_agency__agency"),
human_readable_election_board=Case(
When(is_election_board=True, then=Value("Yes")),
When(is_election_board=False, then=Value("No")),
default=Value("N/A"),
output_field=CharField()
) )
) )
@ -925,8 +950,9 @@ class DomainRequestExport:
'all_other_contacts', 'all_other_contacts',
'all_current_websites', 'all_current_websites',
'additional_details', 'additional_details',
'request_type',
'requested_domain_name', 'requested_domain_name',
"federal_agency_name",
"human_readable_election_board",
# Creator # Creator
'creator__first_name', 'creator__first_name',
'creator__last_name', 'creator__last_name',
@ -939,19 +965,36 @@ class DomainRequestExport:
'authorizing_official__email', 'authorizing_official__email',
'authorizing_official__title', 'authorizing_official__title',
# Existing fields # Existing fields
"id",
'submission_date', 'submission_date',
'status', 'status',
'federal_type', 'federal_type',
'federal_agency',
'organization_name', 'organization_name',
'is_election_board', 'is_election_board',
'city', 'city',
'state_territory', 'state_territory',
'purpose', 'purpose',
'cisa_representative_email', 'cisa_representative_email',
'investigator', 'investigator',
"generic_org_type",
"federal_type",
) )
for request in requests_dict:
# Handle the domain_type field
org_type = request.get("generic_org_type")
request["domain_type"] = None
if org_type:
readable_org_type = DomainRequest.OrganizationChoices.get_org_label(org_type)
request["domain_type"] = readable_org_type
# Handle the federal_type field. Defaults to the wrong variant.
federal_type = request.get("federal_type")
if federal_type:
request["human_readable_federal_type"] = DomainRequest.BranchChoices.get_branch_label(federal_type)
else:
request["human_readable_federal_type"] = None
return requests_dict return requests_dict
# ============================================================= # # ============================================================= #
@ -980,29 +1023,6 @@ class DomainRequestExport:
return requested_domain_name_query return requested_domain_name_query
@staticmethod
def get_request_type_query():
"""
A SQL case statement for DomainRequest.organization_type and DomainRequest.federal_type.
When ran, returns a concatenation of organization_type and federal_type - seperated by " - ".
If federal_type is null, then we just return the organization_type.
Equivalent to:
`f"{organization_type} | {federal_type}" If request.federal_type is not None else organization_type`
"""
request_type_query = Case(
When(
federal_type__isnull=False,
then=Concat('organization_type', Value(' - '), 'federal_type')
),
default=F('organization_type'),
output_field=CharField(),
)
return request_type_query
@staticmethod @staticmethod
def get_additional_details_query(default_message=None): def get_additional_details_query(default_message=None):