mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-08-15 05:54:11 +02:00
Cleanup
This commit is contained in:
parent
34a9497372
commit
4a14296e6d
1 changed files with 74 additions and 54 deletions
|
@ -711,12 +711,12 @@ def export_data_unmanaged_domains_to_csv(csv_file, start_date, end_date):
|
||||||
class DomainRequestExport:
|
class DomainRequestExport:
|
||||||
"""
|
"""
|
||||||
A collection of functions which return csv files regarding the DomainRequest model.
|
A collection of functions which return csv files regarding the DomainRequest model.
|
||||||
Purely organizational -- all functions are independent.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Get all the field names of the DomainRequest object
|
# Get all the field names of the DomainRequest object
|
||||||
domain_request_fields = set(field.name for field in DomainRequest._meta.get_fields())
|
domain_request_fields = set(field.name for field in DomainRequest._meta.get_fields())
|
||||||
|
|
||||||
|
# Get all columns on the full metadata report
|
||||||
all_columns = [
|
all_columns = [
|
||||||
"Domain request",
|
"Domain request",
|
||||||
"Submitted at",
|
"Submitted at",
|
||||||
|
@ -763,6 +763,7 @@ class DomainRequestExport:
|
||||||
columns = [
|
columns = [
|
||||||
"Domain request",
|
"Domain request",
|
||||||
"Domain type",
|
"Domain type",
|
||||||
|
"Federal type",
|
||||||
"Submitted at",
|
"Submitted at",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -775,15 +776,31 @@ class DomainRequestExport:
|
||||||
"submission_date__gte": start_date_formatted,
|
"submission_date__gte": start_date_formatted,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# We don't want to annotate anything, but we do want to access the requested domain name
|
||||||
|
annotations = {}
|
||||||
|
additional_values = ["requested_domain__name"]
|
||||||
|
|
||||||
all_requests = DomainRequest.objects.filter(**filter_condition).order_by(*sort_fields).distinct()
|
all_requests = DomainRequest.objects.filter(**filter_condition).order_by(*sort_fields).distinct()
|
||||||
|
|
||||||
annotated_requests = cls.annotate_and_retrieve_fields(all_requests, {"requested_domain__name"})
|
annotated_requests = cls.annotate_and_retrieve_fields(all_requests, annotations, additional_values)
|
||||||
requests_dict = convert_queryset_to_dict(annotated_requests, is_model=False)
|
requests_dict = convert_queryset_to_dict(annotated_requests, is_model=False)
|
||||||
|
|
||||||
cls.write_csv_for_requests(writer, columns, requests_dict)
|
cls.write_csv_for_requests(writer, columns, requests_dict)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def export_full_domain_request_report(cls, csv_file):
|
def export_full_domain_request_report(cls, csv_file):
|
||||||
|
"""
|
||||||
|
Generates a detailed domain request report to a CSV file.
|
||||||
|
|
||||||
|
Retrieves and annotates DomainRequest objects, excluding 'STARTED' status,
|
||||||
|
with related data optimizations via select/prefetch and annotation.
|
||||||
|
|
||||||
|
Annotated with counts and aggregates of related entities.
|
||||||
|
Converts to dict and writes to CSV using predefined columns.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
csv_file (file-like object): Target CSV file.
|
||||||
|
"""
|
||||||
writer = csv.writer(csv_file)
|
writer = csv.writer(csv_file)
|
||||||
|
|
||||||
requests = (
|
requests = (
|
||||||
|
@ -792,17 +809,32 @@ class DomainRequestExport:
|
||||||
)
|
)
|
||||||
.prefetch_related("current_websites", "other_contacts", "alternative_domains")
|
.prefetch_related("current_websites", "other_contacts", "alternative_domains")
|
||||||
.exclude(status__in=[DomainRequest.DomainRequestStatus.STARTED])
|
.exclude(status__in=[DomainRequest.DomainRequestStatus.STARTED])
|
||||||
.order_by("status","requested_domain__name",)
|
.order_by(
|
||||||
|
"status",
|
||||||
|
"requested_domain__name",
|
||||||
|
)
|
||||||
.distinct()
|
.distinct()
|
||||||
)
|
)
|
||||||
|
|
||||||
# Annotations are custom columns returned to the queryset (AKA: computed in the DB)
|
# Annotations are custom columns returned to the queryset (AKA: computed in the DB)
|
||||||
|
delimiter = " | "
|
||||||
annotations = {
|
annotations = {
|
||||||
"creator_approved_domains_count": DomainRequestExport.get_creator_approved_domains_count_query(),
|
"creator_approved_domains_count": DomainRequestExport.get_creator_approved_domains_count_query(),
|
||||||
"creator_active_requests_count": DomainRequestExport.get_creator_active_requests_count_query(),
|
"creator_active_requests_count": DomainRequestExport.get_creator_active_requests_count_query(),
|
||||||
"all_other_contacts": DomainRequestExport.get_all_other_contacts_query(),
|
"all_current_websites": StringAgg("current_websites__website", delimiter=delimiter, distinct=True),
|
||||||
"all_current_websites": StringAgg("current_websites__website", delimiter=" | ", distinct=True),
|
"all_alternative_domains": StringAgg("alternative_domains__website", delimiter=delimiter, distinct=True),
|
||||||
"all_alternative_domains": StringAgg("alternative_domains__website", delimiter=" | ", distinct=True),
|
# Coerce the other contacts object to "{first_name} {last_name} {email}"
|
||||||
|
"all_other_contacts": StringAgg(
|
||||||
|
Concat(
|
||||||
|
"other_contacts__first_name",
|
||||||
|
Value(" "),
|
||||||
|
"other_contacts__last_name",
|
||||||
|
Value(" "),
|
||||||
|
"other_contacts__email",
|
||||||
|
),
|
||||||
|
delimiter=delimiter,
|
||||||
|
distinct=True,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
# .values can't go two levels deep (just returns the id) - so we have to include this.
|
# .values can't go two levels deep (just returns the id) - so we have to include this.
|
||||||
|
@ -816,7 +848,7 @@ class DomainRequestExport:
|
||||||
"creator__first_name",
|
"creator__first_name",
|
||||||
"creator__last_name",
|
"creator__last_name",
|
||||||
"creator__email",
|
"creator__email",
|
||||||
"investigator__email"
|
"investigator__email",
|
||||||
]
|
]
|
||||||
|
|
||||||
# Convert the domain request queryset to a dictionary (including annotated fields)
|
# Convert the domain request queryset to a dictionary (including annotated fields)
|
||||||
|
@ -851,27 +883,20 @@ class DomainRequestExport:
|
||||||
writer.writerows(rows)
|
writer.writerows(rows)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def parse_row_for_requests(columns, request, show_expanded_org_type=False):
|
def parse_row_for_requests(columns, request):
|
||||||
"""
|
"""
|
||||||
Given a set of columns and a request dictionary,
|
Given a set of columns and a request dictionary, generate a new row from cleaned column data.
|
||||||
generate a new row from cleaned column data
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# FK fields
|
|
||||||
federal_agency = "federal_agency"
|
|
||||||
ao = "authorizing_official"
|
|
||||||
creator = "creator"
|
|
||||||
investigator = "investigator"
|
|
||||||
|
|
||||||
# Handle the federal_type field. Defaults to the wrong format.
|
# Handle the federal_type field. Defaults to the wrong format.
|
||||||
federal_type = request.get("federal_type")
|
federal_type = request.get("federal_type")
|
||||||
human_readable_federal_type = DomainRequest.BranchChoices.get_branch_label(federal_type) if federal_type else None
|
human_readable_federal_type = (
|
||||||
|
DomainRequest.BranchChoices.get_branch_label(federal_type) if federal_type else None
|
||||||
|
)
|
||||||
|
|
||||||
# Handle the org_type field. Either "Tribal" or "Federal - Executive".
|
# Handle the org_type field
|
||||||
org_type = request.get("organization_type")
|
org_type = request.get("organization_type")
|
||||||
human_readable_org_type = DomainRequest.OrganizationChoices.get_org_label(org_type) if org_type else None
|
human_readable_org_type = DomainRequest.OrganizationChoices.get_org_label(org_type) if org_type else None
|
||||||
if human_readable_org_type and human_readable_federal_type and show_expanded_org_type:
|
|
||||||
human_readable_org_type = f"{human_readable_org_type} - {human_readable_federal_type}"
|
|
||||||
|
|
||||||
# Handle the status field. Defaults to the wrong format.
|
# Handle the status field. Defaults to the wrong format.
|
||||||
status = request.get("status")
|
status = request.get("status")
|
||||||
|
@ -881,6 +906,7 @@ class DomainRequestExport:
|
||||||
state_territory = request.get("state_territory")
|
state_territory = request.get("state_territory")
|
||||||
region = get_region(state_territory) if state_territory else None
|
region = get_region(state_territory) if state_territory else None
|
||||||
|
|
||||||
|
# Handle the requested_domain field (add a default if None)
|
||||||
requested_domain = request.get("requested_domain__name")
|
requested_domain = request.get("requested_domain__name")
|
||||||
requested_domain_name = requested_domain if requested_domain else "No requested domain"
|
requested_domain_name = requested_domain if requested_domain else "No requested domain"
|
||||||
|
|
||||||
|
@ -889,8 +915,9 @@ class DomainRequestExport:
|
||||||
if request.get("is_election_board") is not None:
|
if request.get("is_election_board") is not None:
|
||||||
human_readable_election_board = "Yes" if request.is_election_board else "No"
|
human_readable_election_board = "Yes" if request.is_election_board else "No"
|
||||||
|
|
||||||
# Handle the additional details field. Pipe seperated
|
# Handle the additional details field. Pipe sep.
|
||||||
details = [request.get("cisa_representative_email"), request.get("anything_else")]
|
cisa_rep = request.get("cisa_representative_email")
|
||||||
|
details = [cisa_rep, request.get("anything_else")]
|
||||||
additional_details = " | ".join([field for field in details if field is not None])
|
additional_details = " | ".join([field for field in details if field is not None])
|
||||||
|
|
||||||
# create a dictionary of fields which can be included in output.
|
# create a dictionary of fields which can be included in output.
|
||||||
|
@ -911,15 +938,15 @@ class DomainRequestExport:
|
||||||
"Other contacts": request.get("all_other_contacts"),
|
"Other contacts": request.get("all_other_contacts"),
|
||||||
"Current websites": request.get("all_current_websites"),
|
"Current websites": request.get("all_current_websites"),
|
||||||
# Untouched FK fields - passed into the request dict.
|
# Untouched FK fields - passed into the request dict.
|
||||||
"Federal agency": request.get(f"{federal_agency}__agency"),
|
"Federal agency": request.get("federal_agency__agency"),
|
||||||
"AO first name": request.get(f"{ao}__first_name"),
|
"AO first name": request.get("authorizing_official__first_name"),
|
||||||
"AO last name": request.get(f"{ao}__last_name"),
|
"AO last name": request.get("authorizing_official__last_name"),
|
||||||
"AO email": request.get(f"{ao}__email"),
|
"AO email": request.get("authorizing_official__email"),
|
||||||
"AO title/role": request.get(f"{ao}__title"),
|
"AO title/role": request.get("authorizing_official__title"),
|
||||||
"Creator first name": request.get(f"{creator}__first_name"),
|
"Creator first name": request.get("creator__first_name"),
|
||||||
"Creator last name": request.get(f"{creator}__last_name"),
|
"Creator last name": request.get("creator__last_name"),
|
||||||
"Creator email": request.get(f"{creator}__email"),
|
"Creator email": request.get("creator__email"),
|
||||||
"Investigator": request.get(f"{investigator}__email"),
|
"Investigator": request.get("investigator__email"),
|
||||||
# Untouched fields
|
# Untouched fields
|
||||||
"Organization name": request.get("organization_name"),
|
"Organization name": request.get("organization_name"),
|
||||||
"City": request.get("city"),
|
"City": request.get("city"),
|
||||||
|
@ -966,26 +993,14 @@ class DomainRequestExport:
|
||||||
# We are using these rather than pure python for speed reasons. #
|
# We are using these rather than pure python for speed reasons. #
|
||||||
# ============================================================= #
|
# ============================================================= #
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_all_other_contacts_query(delimiter=" | "):
|
|
||||||
""" """
|
|
||||||
|
|
||||||
all_other_contacts_query = StringAgg(
|
|
||||||
Concat(
|
|
||||||
"other_contacts__first_name",
|
|
||||||
Value(" "),
|
|
||||||
"other_contacts__last_name",
|
|
||||||
Value(" "),
|
|
||||||
"other_contacts__email",
|
|
||||||
),
|
|
||||||
delimiter=delimiter,
|
|
||||||
distinct=True,
|
|
||||||
)
|
|
||||||
return all_other_contacts_query
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_creator_approved_domains_count_query():
|
def get_creator_approved_domains_count_query():
|
||||||
""" """
|
"""
|
||||||
|
Generates a Count query for distinct approved domain requests per creator.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Count: Aggregates distinct 'APPROVED' domain requests by creator.
|
||||||
|
"""
|
||||||
|
|
||||||
query = Count(
|
query = Count(
|
||||||
"creator__domain_requests_created__id",
|
"creator__domain_requests_created__id",
|
||||||
|
@ -996,7 +1011,12 @@ class DomainRequestExport:
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_creator_active_requests_count_query():
|
def get_creator_active_requests_count_query():
|
||||||
""" """
|
"""
|
||||||
|
Generates a Count query for distinct approved domain requests per creator.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Count: Aggregates distinct 'SUBMITTED', 'IN_REVIEW', and 'ACTION_NEEDED' domain requests by creator.
|
||||||
|
"""
|
||||||
|
|
||||||
query = Count(
|
query = Count(
|
||||||
"creator__domain_requests_created__id",
|
"creator__domain_requests_created__id",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue