mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-05-18 18:39:21 +02:00
Update migrations
This commit is contained in:
commit
1bfc2dfa79
25 changed files with 220 additions and 70 deletions
|
@ -816,3 +816,25 @@ Example: `cf ssh getgov-za`
|
||||||
| | Parameter | Description |
|
| | Parameter | Description |
|
||||||
|:-:|:-------------------------- |:-----------------------------------------------------------------------------------|
|
|:-:|:-------------------------- |:-----------------------------------------------------------------------------------|
|
||||||
| 1 | **federal_cio_csv_path** | Specifies where the federal CIO csv is |
|
| 1 | **federal_cio_csv_path** | Specifies where the federal CIO csv is |
|
||||||
|
|
||||||
|
## Populate Domain Request Dates
|
||||||
|
This section outlines how to run the populate_domain_request_dates script
|
||||||
|
|
||||||
|
### Running on sandboxes
|
||||||
|
|
||||||
|
#### Step 1: Login to CloudFoundry
|
||||||
|
```cf login -a api.fr.cloud.gov --sso```
|
||||||
|
|
||||||
|
#### Step 2: SSH into your environment
|
||||||
|
```cf ssh getgov-{space}```
|
||||||
|
|
||||||
|
Example: `cf ssh getgov-za`
|
||||||
|
|
||||||
|
#### Step 3: Create a shell instance
|
||||||
|
```/tmp/lifecycle/shell```
|
||||||
|
|
||||||
|
#### Step 4: Running the script
|
||||||
|
```./manage.py populate_domain_request_dates```
|
||||||
|
|
||||||
|
### Running locally
|
||||||
|
```docker-compose exec app ./manage.py populate_domain_request_dates```
|
||||||
|
|
|
@ -1691,7 +1691,9 @@ class DomainRequestAdmin(ListHeaderAdmin, ImportExportModelAdmin):
|
||||||
# Columns
|
# Columns
|
||||||
list_display = [
|
list_display = [
|
||||||
"requested_domain",
|
"requested_domain",
|
||||||
"submission_date",
|
"first_submitted_date",
|
||||||
|
"last_submitted_date",
|
||||||
|
"last_status_update",
|
||||||
"status",
|
"status",
|
||||||
"generic_org_type",
|
"generic_org_type",
|
||||||
"federal_type",
|
"federal_type",
|
||||||
|
@ -1889,7 +1891,7 @@ class DomainRequestAdmin(ListHeaderAdmin, ImportExportModelAdmin):
|
||||||
# Table ordering
|
# Table ordering
|
||||||
# NOTE: This impacts the select2 dropdowns (combobox)
|
# NOTE: This impacts the select2 dropdowns (combobox)
|
||||||
# Currentl, there's only one for requests on DomainInfo
|
# Currentl, there's only one for requests on DomainInfo
|
||||||
ordering = ["-submission_date", "requested_domain__name"]
|
ordering = ["-last_submitted_date", "requested_domain__name"]
|
||||||
|
|
||||||
change_form_template = "django/admin/domain_request_change_form.html"
|
change_form_template = "django/admin/domain_request_change_form.html"
|
||||||
|
|
||||||
|
|
|
@ -1599,7 +1599,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||||
const domainName = request.requested_domain ? request.requested_domain : `New domain request <br><span class="text-base font-body-xs">(${utcDateString(request.created_at)})</span>`;
|
const domainName = request.requested_domain ? request.requested_domain : `New domain request <br><span class="text-base font-body-xs">(${utcDateString(request.created_at)})</span>`;
|
||||||
const actionUrl = request.action_url;
|
const actionUrl = request.action_url;
|
||||||
const actionLabel = request.action_label;
|
const actionLabel = request.action_label;
|
||||||
const submissionDate = request.submission_date ? new Date(request.submission_date).toLocaleDateString('en-US', options) : `<span class="text-base">Not submitted</span>`;
|
const submissionDate = request.last_submitted_date ? new Date(request.last_submitted_date).toLocaleDateString('en-US', options) : `<span class="text-base">Not submitted</span>`;
|
||||||
|
|
||||||
// Even if the request is not deletable, we may need this empty string for the td if the deletable column is displayed
|
// Even if the request is not deletable, we may need this empty string for the td if the deletable column is displayed
|
||||||
let modalTrigger = '';
|
let modalTrigger = '';
|
||||||
|
@ -1699,7 +1699,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||||
<th scope="row" role="rowheader" data-label="Domain name">
|
<th scope="row" role="rowheader" data-label="Domain name">
|
||||||
${domainName}
|
${domainName}
|
||||||
</th>
|
</th>
|
||||||
<td data-sort-value="${new Date(request.submission_date).getTime()}" data-label="Date submitted">
|
<td data-sort-value="${new Date(request.last_submitted_date).getTime()}" data-label="Date submitted">
|
||||||
${submissionDate}
|
${submissionDate}
|
||||||
</td>
|
</td>
|
||||||
<td data-label="Status">
|
<td data-label="Status">
|
||||||
|
|
|
@ -94,7 +94,7 @@ class DomainRequestFixture:
|
||||||
|
|
||||||
# TODO for a future ticket: Allow for more than just "federal" here
|
# 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.submission_date = fake.date()
|
da.last_submitted_date = fake.date()
|
||||||
da.federal_type = (
|
da.federal_type = (
|
||||||
app["federal_type"]
|
app["federal_type"]
|
||||||
if "federal_type" in app
|
if "federal_type" in app
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
import logging
|
||||||
|
from django.core.management import BaseCommand
|
||||||
|
from registrar.management.commands.utility.terminal_helper import PopulateScriptTemplate, TerminalColors
|
||||||
|
from registrar.models import DomainRequest
|
||||||
|
from auditlog.models import LogEntry
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand, PopulateScriptTemplate):
|
||||||
|
help = "Loops through each domain request object and populates the last_status_update and first_submitted_date"
|
||||||
|
|
||||||
|
def handle(self, **kwargs):
|
||||||
|
"""Loops through each DomainRequest object and populates
|
||||||
|
its last_status_update and first_submitted_date values"""
|
||||||
|
self.mass_update_records(DomainRequest, None, ["last_status_update", "first_submitted_date"])
|
||||||
|
|
||||||
|
def update_record(self, record: DomainRequest):
|
||||||
|
"""Defines how we update the first_submitted_date and last_status_update fields"""
|
||||||
|
|
||||||
|
# Retrieve and order audit log entries by timestamp in descending order
|
||||||
|
audit_log_entries = LogEntry.objects.filter(object_pk=record.pk).order_by("-timestamp")
|
||||||
|
# Loop through logs in descending order to find most recent status change
|
||||||
|
for log_entry in audit_log_entries:
|
||||||
|
if "status" in log_entry.changes_dict:
|
||||||
|
record.last_status_update = log_entry.timestamp.date()
|
||||||
|
break
|
||||||
|
|
||||||
|
# Loop through logs in ascending order to find first submission
|
||||||
|
for log_entry in audit_log_entries.reverse():
|
||||||
|
status = log_entry.changes_dict.get("status")
|
||||||
|
if status and status[1] == "submitted":
|
||||||
|
record.first_submitted_date = log_entry.timestamp.date()
|
||||||
|
break
|
||||||
|
|
||||||
|
logger.info(
|
||||||
|
f"""{TerminalColors.OKCYAN}Updating {record} =>
|
||||||
|
first submitted date: {record.first_submitted_date},
|
||||||
|
last status update: {record.last_status_update}{TerminalColors.ENDC}
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
def should_skip_record(self, record) -> bool:
|
||||||
|
# make sure the record had some kind of history
|
||||||
|
return not LogEntry.objects.filter(object_pk=record.pk).exists()
|
|
@ -86,7 +86,7 @@ class PopulateScriptTemplate(ABC):
|
||||||
You must define update_record before you can use this function.
|
You must define update_record before you can use this function.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
records = object_class.objects.filter(**filter_conditions)
|
records = object_class.objects.filter(**filter_conditions) if filter_conditions else object_class.objects.all()
|
||||||
readable_class_name = self.get_class_name(object_class)
|
readable_class_name = self.get_class_name(object_class)
|
||||||
|
|
||||||
# Code execution will stop here if the user prompts "N"
|
# Code execution will stop here if the user prompts "N"
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
# Generated by Django 4.2.10 on 2024-08-16 15:28
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("registrar", "0119_remove_user_portfolio_and_more"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RenameField(
|
||||||
|
model_name="domainrequest",
|
||||||
|
old_name="submission_date",
|
||||||
|
new_name="last_submitted_date",
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="domainrequest",
|
||||||
|
name="last_submitted_date",
|
||||||
|
field=models.DateField(
|
||||||
|
blank=True, default=None, help_text="Date last submitted", null=True, verbose_name="last submitted on"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="domainrequest",
|
||||||
|
name="first_submitted_date",
|
||||||
|
field=models.DateField(
|
||||||
|
blank=True,
|
||||||
|
default=None,
|
||||||
|
help_text="Date initially submitted",
|
||||||
|
null=True,
|
||||||
|
verbose_name="first submitted on",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="domainrequest",
|
||||||
|
name="last_status_update",
|
||||||
|
field=models.DateField(
|
||||||
|
blank=True,
|
||||||
|
default=None,
|
||||||
|
help_text="Date of the last status update",
|
||||||
|
null=True,
|
||||||
|
verbose_name="last updated on",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
|
@ -8,7 +8,7 @@ import django.db.models.deletion
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
("registrar", "0119_remove_user_portfolio_and_more"),
|
("registrar", "0120_add_domainrequest_submission_dates"),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
|
@ -550,15 +550,32 @@ class DomainRequest(TimeStampedModel):
|
||||||
help_text="Acknowledged .gov acceptable use policy",
|
help_text="Acknowledged .gov acceptable use policy",
|
||||||
)
|
)
|
||||||
|
|
||||||
# submission date records when domain request is submitted
|
# Records when the domain request was first submitted
|
||||||
submission_date = models.DateField(
|
first_submitted_date = models.DateField(
|
||||||
null=True,
|
null=True,
|
||||||
blank=True,
|
blank=True,
|
||||||
default=None,
|
default=None,
|
||||||
verbose_name="submitted at",
|
verbose_name="first submitted on",
|
||||||
help_text="Date submitted",
|
help_text="Date initially submitted",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Records when domain request was last submitted
|
||||||
|
last_submitted_date = models.DateField(
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
default=None,
|
||||||
|
verbose_name="last submitted on",
|
||||||
|
help_text="Date last submitted",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Records when domain request status was last updated by an admin or analyst
|
||||||
|
last_status_update = models.DateField(
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
default=None,
|
||||||
|
verbose_name="last updated on",
|
||||||
|
help_text="Date of the last status update",
|
||||||
|
)
|
||||||
notes = models.TextField(
|
notes = models.TextField(
|
||||||
null=True,
|
null=True,
|
||||||
blank=True,
|
blank=True,
|
||||||
|
@ -608,6 +625,9 @@ class DomainRequest(TimeStampedModel):
|
||||||
self.sync_organization_type()
|
self.sync_organization_type()
|
||||||
self.sync_yes_no_form_fields()
|
self.sync_yes_no_form_fields()
|
||||||
|
|
||||||
|
if self._cached_status != self.status:
|
||||||
|
self.last_status_update = timezone.now().date()
|
||||||
|
|
||||||
super().save(*args, **kwargs)
|
super().save(*args, **kwargs)
|
||||||
|
|
||||||
# Handle the action needed email.
|
# Handle the action needed email.
|
||||||
|
@ -787,8 +807,12 @@ class DomainRequest(TimeStampedModel):
|
||||||
if not DraftDomain.string_could_be_domain(self.requested_domain.name):
|
if not DraftDomain.string_could_be_domain(self.requested_domain.name):
|
||||||
raise ValueError("Requested domain is not a valid domain name.")
|
raise ValueError("Requested domain is not a valid domain name.")
|
||||||
|
|
||||||
# Update submission_date to today
|
# if the domain has not been submitted before this must be the first time
|
||||||
self.submission_date = timezone.now().date()
|
if not self.first_submitted_date:
|
||||||
|
self.first_submitted_date = timezone.now().date()
|
||||||
|
|
||||||
|
# Update last_submitted_date to today
|
||||||
|
self.last_submitted_date = timezone.now().date()
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
# Limit email notifications to transitions from Started and Withdrawn
|
# Limit email notifications to transitions from Started and Withdrawn
|
||||||
|
|
|
@ -4,7 +4,7 @@ Hi, {{ recipient.first_name }}.
|
||||||
We've identified an action that you’ll need to complete before we continue reviewing your .gov domain request.
|
We've identified an action that you’ll need to complete before we continue reviewing your .gov domain request.
|
||||||
|
|
||||||
DOMAIN REQUESTED: {{ domain_request.requested_domain.name }}
|
DOMAIN REQUESTED: {{ domain_request.requested_domain.name }}
|
||||||
REQUEST RECEIVED ON: {{ domain_request.submission_date|date }}
|
REQUEST RECEIVED ON: {{ domain_request.last_submitted_date|date }}
|
||||||
STATUS: Action needed
|
STATUS: Action needed
|
||||||
|
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
|
|
|
@ -4,7 +4,7 @@ Hi, {{ recipient.first_name }}.
|
||||||
We've identified an action that you’ll need to complete before we continue reviewing your .gov domain request.
|
We've identified an action that you’ll need to complete before we continue reviewing your .gov domain request.
|
||||||
|
|
||||||
DOMAIN REQUESTED: {{ domain_request.requested_domain.name }}
|
DOMAIN REQUESTED: {{ domain_request.requested_domain.name }}
|
||||||
REQUEST RECEIVED ON: {{ domain_request.submission_date|date }}
|
REQUEST RECEIVED ON: {{ domain_request.last_submitted_date|date }}
|
||||||
STATUS: Action needed
|
STATUS: Action needed
|
||||||
|
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
|
|
|
@ -4,7 +4,7 @@ Hi, {{ recipient.first_name }}.
|
||||||
We've identified an action that you’ll need to complete before we continue reviewing your .gov domain request.
|
We've identified an action that you’ll need to complete before we continue reviewing your .gov domain request.
|
||||||
|
|
||||||
DOMAIN REQUESTED: {{ domain_request.requested_domain.name }}
|
DOMAIN REQUESTED: {{ domain_request.requested_domain.name }}
|
||||||
REQUEST RECEIVED ON: {{ domain_request.submission_date|date }}
|
REQUEST RECEIVED ON: {{ domain_request.last_submitted_date|date }}
|
||||||
STATUS: Action needed
|
STATUS: Action needed
|
||||||
|
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
|
|
|
@ -4,7 +4,7 @@ Hi, {{ recipient.first_name }}.
|
||||||
We've identified an action that you’ll need to complete before we continue reviewing your .gov domain request.
|
We've identified an action that you’ll need to complete before we continue reviewing your .gov domain request.
|
||||||
|
|
||||||
DOMAIN REQUESTED: {{ domain_request.requested_domain.name }}
|
DOMAIN REQUESTED: {{ domain_request.requested_domain.name }}
|
||||||
REQUEST RECEIVED ON: {{ domain_request.submission_date|date }}
|
REQUEST RECEIVED ON: {{ domain_request.last_submitted_date|date }}
|
||||||
STATUS: Action needed
|
STATUS: Action needed
|
||||||
|
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
|
|
|
@ -4,7 +4,7 @@ Hi, {{ recipient.first_name }}.
|
||||||
Your .gov domain request has been withdrawn and will not be reviewed by our team.
|
Your .gov domain request has been withdrawn and will not be reviewed by our team.
|
||||||
|
|
||||||
DOMAIN REQUESTED: {{ domain_request.requested_domain.name }}
|
DOMAIN REQUESTED: {{ domain_request.requested_domain.name }}
|
||||||
REQUEST RECEIVED ON: {{ domain_request.submission_date|date }}
|
REQUEST RECEIVED ON: {{ domain_request.last_submitted_date|date }}
|
||||||
STATUS: Withdrawn
|
STATUS: Withdrawn
|
||||||
|
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
|
|
|
@ -4,7 +4,7 @@ Hi, {{ recipient.first_name }}.
|
||||||
Congratulations! Your .gov domain request has been approved.
|
Congratulations! Your .gov domain request has been approved.
|
||||||
|
|
||||||
DOMAIN REQUESTED: {{ domain_request.requested_domain.name }}
|
DOMAIN REQUESTED: {{ domain_request.requested_domain.name }}
|
||||||
REQUEST RECEIVED ON: {{ domain_request.submission_date|date }}
|
REQUEST RECEIVED ON: {{ domain_request.last_submitted_date|date }}
|
||||||
STATUS: Approved
|
STATUS: Approved
|
||||||
|
|
||||||
You can manage your approved domain on the .gov registrar <https://manage.get.gov>.
|
You can manage your approved domain on the .gov registrar <https://manage.get.gov>.
|
||||||
|
|
|
@ -4,7 +4,7 @@ Hi, {{ recipient.first_name }}.
|
||||||
Your .gov domain request has been rejected.
|
Your .gov domain request has been rejected.
|
||||||
|
|
||||||
DOMAIN REQUESTED: {{ domain_request.requested_domain.name }}
|
DOMAIN REQUESTED: {{ domain_request.requested_domain.name }}
|
||||||
REQUEST RECEIVED ON: {{ domain_request.submission_date|date }}
|
REQUEST RECEIVED ON: {{ domain_request.last_submitted_date|date }}
|
||||||
STATUS: Rejected
|
STATUS: Rejected
|
||||||
|
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
|
|
|
@ -4,7 +4,7 @@ Hi, {{ recipient.first_name }}.
|
||||||
We received your .gov domain request.
|
We received your .gov domain request.
|
||||||
|
|
||||||
DOMAIN REQUESTED: {{ domain_request.requested_domain.name }}
|
DOMAIN REQUESTED: {{ domain_request.requested_domain.name }}
|
||||||
REQUEST RECEIVED ON: {{ domain_request.submission_date|date }}
|
REQUEST RECEIVED ON: {{ domain_request.last_submitted_date|date }}
|
||||||
STATUS: Submitted
|
STATUS: Submitted
|
||||||
|
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
|
|
|
@ -45,7 +45,7 @@
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th data-sortable="requested_domain__name" scope="col" role="columnheader">Domain name</th>
|
<th data-sortable="requested_domain__name" scope="col" role="columnheader">Domain name</th>
|
||||||
<th data-sortable="submission_date" scope="col" role="columnheader">Date submitted</th>
|
<th data-sortable="last_submitted_date" scope="col" role="columnheader">Date submitted</th>
|
||||||
<th data-sortable="status" scope="col" role="columnheader">Status</th>
|
<th data-sortable="status" scope="col" role="columnheader">Status</th>
|
||||||
<th scope="col" role="columnheader"><span class="usa-sr-only">Action</span></th>
|
<th scope="col" role="columnheader"><span class="usa-sr-only">Action</span></th>
|
||||||
<!-- AJAX will conditionally add a th for delete actions -->
|
<!-- AJAX will conditionally add a th for delete actions -->
|
||||||
|
|
|
@ -775,13 +775,13 @@ class MockDb(TestCase):
|
||||||
cls.domain_request_3.alternative_domains.add(website, website_2)
|
cls.domain_request_3.alternative_domains.add(website, website_2)
|
||||||
cls.domain_request_3.current_websites.add(website_3, website_4)
|
cls.domain_request_3.current_websites.add(website_3, website_4)
|
||||||
cls.domain_request_3.cisa_representative_email = "test@igorville.com"
|
cls.domain_request_3.cisa_representative_email = "test@igorville.com"
|
||||||
cls.domain_request_3.submission_date = get_time_aware_date(datetime(2024, 4, 2))
|
cls.domain_request_3.last_submitted_date = get_time_aware_date(datetime(2024, 4, 2))
|
||||||
cls.domain_request_3.save()
|
cls.domain_request_3.save()
|
||||||
|
|
||||||
cls.domain_request_4.submission_date = get_time_aware_date(datetime(2024, 4, 2))
|
cls.domain_request_4.last_submitted_date = get_time_aware_date(datetime(2024, 4, 2))
|
||||||
cls.domain_request_4.save()
|
cls.domain_request_4.save()
|
||||||
|
|
||||||
cls.domain_request_6.submission_date = get_time_aware_date(datetime(2024, 4, 2))
|
cls.domain_request_6.last_submitted_date = get_time_aware_date(datetime(2024, 4, 2))
|
||||||
cls.domain_request_6.save()
|
cls.domain_request_6.save()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|
|
@ -448,7 +448,7 @@ class TestDomainRequestAdmin(MockEppLib):
|
||||||
|
|
||||||
# Assert that our sort works correctly
|
# Assert that our sort works correctly
|
||||||
self.test_helper.assert_table_sorted(
|
self.test_helper.assert_table_sorted(
|
||||||
"11",
|
"13",
|
||||||
(
|
(
|
||||||
"creator__first_name",
|
"creator__first_name",
|
||||||
"creator__last_name",
|
"creator__last_name",
|
||||||
|
@ -457,7 +457,7 @@ class TestDomainRequestAdmin(MockEppLib):
|
||||||
|
|
||||||
# Assert that sorting in reverse works correctly
|
# Assert that sorting in reverse works correctly
|
||||||
self.test_helper.assert_table_sorted(
|
self.test_helper.assert_table_sorted(
|
||||||
"-11",
|
"-13",
|
||||||
(
|
(
|
||||||
"-creator__first_name",
|
"-creator__first_name",
|
||||||
"-creator__last_name",
|
"-creator__last_name",
|
||||||
|
@ -480,7 +480,7 @@ class TestDomainRequestAdmin(MockEppLib):
|
||||||
|
|
||||||
# Assert that our sort works correctly
|
# Assert that our sort works correctly
|
||||||
self.test_helper.assert_table_sorted(
|
self.test_helper.assert_table_sorted(
|
||||||
"12",
|
"14",
|
||||||
(
|
(
|
||||||
"investigator__first_name",
|
"investigator__first_name",
|
||||||
"investigator__last_name",
|
"investigator__last_name",
|
||||||
|
@ -489,7 +489,7 @@ class TestDomainRequestAdmin(MockEppLib):
|
||||||
|
|
||||||
# Assert that sorting in reverse works correctly
|
# Assert that sorting in reverse works correctly
|
||||||
self.test_helper.assert_table_sorted(
|
self.test_helper.assert_table_sorted(
|
||||||
"-12",
|
"-14",
|
||||||
(
|
(
|
||||||
"-investigator__first_name",
|
"-investigator__first_name",
|
||||||
"-investigator__last_name",
|
"-investigator__last_name",
|
||||||
|
@ -502,7 +502,7 @@ class TestDomainRequestAdmin(MockEppLib):
|
||||||
@less_console_noise_decorator
|
@less_console_noise_decorator
|
||||||
def test_default_sorting_in_domain_requests_list(self):
|
def test_default_sorting_in_domain_requests_list(self):
|
||||||
"""
|
"""
|
||||||
Make sure the default sortin in on the domain requests list page is reverse submission_date
|
Make sure the default sortin in on the domain requests list page is reverse last_submitted_date
|
||||||
then alphabetical requested_domain
|
then alphabetical requested_domain
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -512,12 +512,12 @@ class TestDomainRequestAdmin(MockEppLib):
|
||||||
for name in ["ccc.gov", "bbb.gov", "eee.gov", "aaa.gov", "zzz.gov", "ddd.gov"]
|
for name in ["ccc.gov", "bbb.gov", "eee.gov", "aaa.gov", "zzz.gov", "ddd.gov"]
|
||||||
]
|
]
|
||||||
|
|
||||||
domain_requests[0].submission_date = timezone.make_aware(datetime(2024, 10, 16))
|
domain_requests[0].last_submitted_date = timezone.make_aware(datetime(2024, 10, 16))
|
||||||
domain_requests[1].submission_date = timezone.make_aware(datetime(2001, 10, 16))
|
domain_requests[1].last_submitted_date = timezone.make_aware(datetime(2001, 10, 16))
|
||||||
domain_requests[2].submission_date = timezone.make_aware(datetime(1980, 10, 16))
|
domain_requests[2].last_submitted_date = timezone.make_aware(datetime(1980, 10, 16))
|
||||||
domain_requests[3].submission_date = timezone.make_aware(datetime(1998, 10, 16))
|
domain_requests[3].last_submitted_date = timezone.make_aware(datetime(1998, 10, 16))
|
||||||
domain_requests[4].submission_date = timezone.make_aware(datetime(2013, 10, 16))
|
domain_requests[4].last_submitted_date = timezone.make_aware(datetime(2013, 10, 16))
|
||||||
domain_requests[5].submission_date = timezone.make_aware(datetime(1980, 10, 16))
|
domain_requests[5].last_submitted_date = timezone.make_aware(datetime(1980, 10, 16))
|
||||||
|
|
||||||
# Save the modified domain requests to update their attributes in the database
|
# Save the modified domain requests to update their attributes in the database
|
||||||
for domain_request in domain_requests:
|
for domain_request in domain_requests:
|
||||||
|
@ -1649,7 +1649,9 @@ class TestDomainRequestAdmin(MockEppLib):
|
||||||
"cisa_representative_last_name",
|
"cisa_representative_last_name",
|
||||||
"has_cisa_representative",
|
"has_cisa_representative",
|
||||||
"is_policy_acknowledged",
|
"is_policy_acknowledged",
|
||||||
"submission_date",
|
"first_submitted_date",
|
||||||
|
"last_submitted_date",
|
||||||
|
"last_status_update",
|
||||||
"notes",
|
"notes",
|
||||||
"alternative_domains",
|
"alternative_domains",
|
||||||
]
|
]
|
||||||
|
|
|
@ -768,7 +768,7 @@ class HelperFunctions(MockDbForSharedTests):
|
||||||
with less_console_noise():
|
with less_console_noise():
|
||||||
filter_condition = {
|
filter_condition = {
|
||||||
"status": DomainRequest.DomainRequestStatus.SUBMITTED,
|
"status": DomainRequest.DomainRequestStatus.SUBMITTED,
|
||||||
"submission_date__lte": self.end_date,
|
"last_submitted_date__lte": self.end_date,
|
||||||
}
|
}
|
||||||
submitted_requests_sliced_at_end_date = DomainRequestExport.get_sliced_requests(filter_condition)
|
submitted_requests_sliced_at_end_date = DomainRequestExport.get_sliced_requests(filter_condition)
|
||||||
expected_content = [3, 2, 0, 0, 0, 0, 1, 0, 0, 1]
|
expected_content = [3, 2, 0, 0, 0, 0, 1, 0, 0, 1]
|
||||||
|
|
|
@ -25,91 +25,91 @@ class GetRequestsJsonTest(TestWithUser, WebTest):
|
||||||
DomainRequest.objects.create(
|
DomainRequest.objects.create(
|
||||||
creator=cls.user,
|
creator=cls.user,
|
||||||
requested_domain=lamb_chops,
|
requested_domain=lamb_chops,
|
||||||
submission_date="2024-01-01",
|
last_submitted_date="2024-01-01",
|
||||||
status=DomainRequest.DomainRequestStatus.STARTED,
|
status=DomainRequest.DomainRequestStatus.STARTED,
|
||||||
created_at="2024-01-01",
|
created_at="2024-01-01",
|
||||||
),
|
),
|
||||||
DomainRequest.objects.create(
|
DomainRequest.objects.create(
|
||||||
creator=cls.user,
|
creator=cls.user,
|
||||||
requested_domain=short_ribs,
|
requested_domain=short_ribs,
|
||||||
submission_date="2024-02-01",
|
last_submitted_date="2024-02-01",
|
||||||
status=DomainRequest.DomainRequestStatus.WITHDRAWN,
|
status=DomainRequest.DomainRequestStatus.WITHDRAWN,
|
||||||
created_at="2024-02-01",
|
created_at="2024-02-01",
|
||||||
),
|
),
|
||||||
DomainRequest.objects.create(
|
DomainRequest.objects.create(
|
||||||
creator=cls.user,
|
creator=cls.user,
|
||||||
requested_domain=beef_chuck,
|
requested_domain=beef_chuck,
|
||||||
submission_date="2024-03-01",
|
last_submitted_date="2024-03-01",
|
||||||
status=DomainRequest.DomainRequestStatus.REJECTED,
|
status=DomainRequest.DomainRequestStatus.REJECTED,
|
||||||
created_at="2024-03-01",
|
created_at="2024-03-01",
|
||||||
),
|
),
|
||||||
DomainRequest.objects.create(
|
DomainRequest.objects.create(
|
||||||
creator=cls.user,
|
creator=cls.user,
|
||||||
requested_domain=stew_beef,
|
requested_domain=stew_beef,
|
||||||
submission_date="2024-04-01",
|
last_submitted_date="2024-04-01",
|
||||||
status=DomainRequest.DomainRequestStatus.STARTED,
|
status=DomainRequest.DomainRequestStatus.STARTED,
|
||||||
created_at="2024-04-01",
|
created_at="2024-04-01",
|
||||||
),
|
),
|
||||||
DomainRequest.objects.create(
|
DomainRequest.objects.create(
|
||||||
creator=cls.user,
|
creator=cls.user,
|
||||||
requested_domain=None,
|
requested_domain=None,
|
||||||
submission_date="2024-05-01",
|
last_submitted_date="2024-05-01",
|
||||||
status=DomainRequest.DomainRequestStatus.STARTED,
|
status=DomainRequest.DomainRequestStatus.STARTED,
|
||||||
created_at="2024-05-01",
|
created_at="2024-05-01",
|
||||||
),
|
),
|
||||||
DomainRequest.objects.create(
|
DomainRequest.objects.create(
|
||||||
creator=cls.user,
|
creator=cls.user,
|
||||||
requested_domain=None,
|
requested_domain=None,
|
||||||
submission_date="2024-06-01",
|
last_submitted_date="2024-06-01",
|
||||||
status=DomainRequest.DomainRequestStatus.WITHDRAWN,
|
status=DomainRequest.DomainRequestStatus.WITHDRAWN,
|
||||||
created_at="2024-06-01",
|
created_at="2024-06-01",
|
||||||
),
|
),
|
||||||
DomainRequest.objects.create(
|
DomainRequest.objects.create(
|
||||||
creator=cls.user,
|
creator=cls.user,
|
||||||
requested_domain=None,
|
requested_domain=None,
|
||||||
submission_date="2024-07-01",
|
last_submitted_date="2024-07-01",
|
||||||
status=DomainRequest.DomainRequestStatus.REJECTED,
|
status=DomainRequest.DomainRequestStatus.REJECTED,
|
||||||
created_at="2024-07-01",
|
created_at="2024-07-01",
|
||||||
),
|
),
|
||||||
DomainRequest.objects.create(
|
DomainRequest.objects.create(
|
||||||
creator=cls.user,
|
creator=cls.user,
|
||||||
requested_domain=None,
|
requested_domain=None,
|
||||||
submission_date="2024-08-01",
|
last_submitted_date="2024-08-01",
|
||||||
status=DomainRequest.DomainRequestStatus.STARTED,
|
status=DomainRequest.DomainRequestStatus.STARTED,
|
||||||
created_at="2024-08-01",
|
created_at="2024-08-01",
|
||||||
),
|
),
|
||||||
DomainRequest.objects.create(
|
DomainRequest.objects.create(
|
||||||
creator=cls.user,
|
creator=cls.user,
|
||||||
requested_domain=None,
|
requested_domain=None,
|
||||||
submission_date="2024-09-01",
|
last_submitted_date="2024-09-01",
|
||||||
status=DomainRequest.DomainRequestStatus.STARTED,
|
status=DomainRequest.DomainRequestStatus.STARTED,
|
||||||
created_at="2024-09-01",
|
created_at="2024-09-01",
|
||||||
),
|
),
|
||||||
DomainRequest.objects.create(
|
DomainRequest.objects.create(
|
||||||
creator=cls.user,
|
creator=cls.user,
|
||||||
requested_domain=None,
|
requested_domain=None,
|
||||||
submission_date="2024-10-01",
|
last_submitted_date="2024-10-01",
|
||||||
status=DomainRequest.DomainRequestStatus.WITHDRAWN,
|
status=DomainRequest.DomainRequestStatus.WITHDRAWN,
|
||||||
created_at="2024-10-01",
|
created_at="2024-10-01",
|
||||||
),
|
),
|
||||||
DomainRequest.objects.create(
|
DomainRequest.objects.create(
|
||||||
creator=cls.user,
|
creator=cls.user,
|
||||||
requested_domain=None,
|
requested_domain=None,
|
||||||
submission_date="2024-11-01",
|
last_submitted_date="2024-11-01",
|
||||||
status=DomainRequest.DomainRequestStatus.REJECTED,
|
status=DomainRequest.DomainRequestStatus.REJECTED,
|
||||||
created_at="2024-11-01",
|
created_at="2024-11-01",
|
||||||
),
|
),
|
||||||
DomainRequest.objects.create(
|
DomainRequest.objects.create(
|
||||||
creator=cls.user,
|
creator=cls.user,
|
||||||
requested_domain=None,
|
requested_domain=None,
|
||||||
submission_date="2024-11-02",
|
last_submitted_date="2024-11-02",
|
||||||
status=DomainRequest.DomainRequestStatus.WITHDRAWN,
|
status=DomainRequest.DomainRequestStatus.WITHDRAWN,
|
||||||
created_at="2024-11-02",
|
created_at="2024-11-02",
|
||||||
),
|
),
|
||||||
DomainRequest.objects.create(
|
DomainRequest.objects.create(
|
||||||
creator=cls.user,
|
creator=cls.user,
|
||||||
requested_domain=None,
|
requested_domain=None,
|
||||||
submission_date="2024-12-01",
|
last_submitted_date="2024-12-01",
|
||||||
status=DomainRequest.DomainRequestStatus.APPROVED,
|
status=DomainRequest.DomainRequestStatus.APPROVED,
|
||||||
created_at="2024-12-01",
|
created_at="2024-12-01",
|
||||||
),
|
),
|
||||||
|
@ -138,7 +138,7 @@ class GetRequestsJsonTest(TestWithUser, WebTest):
|
||||||
|
|
||||||
# Extract fields from response
|
# Extract fields from response
|
||||||
requested_domains = [request["requested_domain"] for request in data["domain_requests"]]
|
requested_domains = [request["requested_domain"] for request in data["domain_requests"]]
|
||||||
submission_dates = [request["submission_date"] for request in data["domain_requests"]]
|
last_submitted_dates = [request["last_submitted_date"] for request in data["domain_requests"]]
|
||||||
statuses = [request["status"] for request in data["domain_requests"]]
|
statuses = [request["status"] for request in data["domain_requests"]]
|
||||||
created_ats = [request["created_at"] for request in data["domain_requests"]]
|
created_ats = [request["created_at"] for request in data["domain_requests"]]
|
||||||
ids = [request["id"] for request in data["domain_requests"]]
|
ids = [request["id"] for request in data["domain_requests"]]
|
||||||
|
@ -154,7 +154,7 @@ class GetRequestsJsonTest(TestWithUser, WebTest):
|
||||||
self.domain_requests[i].requested_domain.name if self.domain_requests[i].requested_domain else None,
|
self.domain_requests[i].requested_domain.name if self.domain_requests[i].requested_domain else None,
|
||||||
requested_domains[i],
|
requested_domains[i],
|
||||||
)
|
)
|
||||||
self.assertEqual(self.domain_requests[i].submission_date, submission_dates[i])
|
self.assertEqual(self.domain_requests[i].last_submitted_date, last_submitted_dates[i])
|
||||||
self.assertEqual(self.domain_requests[i].get_status_display(), statuses[i])
|
self.assertEqual(self.domain_requests[i].get_status_display(), statuses[i])
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
parse_datetime(self.domain_requests[i].created_at.isoformat()), parse_datetime(created_ats[i])
|
parse_datetime(self.domain_requests[i].created_at.isoformat()), parse_datetime(created_ats[i])
|
||||||
|
@ -287,26 +287,30 @@ class GetRequestsJsonTest(TestWithUser, WebTest):
|
||||||
|
|
||||||
def test_sorting(self):
|
def test_sorting(self):
|
||||||
"""test that sorting works properly on the result set"""
|
"""test that sorting works properly on the result set"""
|
||||||
response = self.app.get(reverse("get_domain_requests_json"), {"sort_by": "submission_date", "order": "desc"})
|
response = self.app.get(
|
||||||
|
reverse("get_domain_requests_json"), {"sort_by": "last_submitted_date", "order": "desc"}
|
||||||
|
)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
data = response.json
|
data = response.json
|
||||||
|
|
||||||
# Check if sorted by submission_date in descending order
|
# Check if sorted by last_submitted_date in descending order
|
||||||
submission_dates = [req["submission_date"] for req in data["domain_requests"]]
|
last_submitted_dates = [req["last_submitted_date"] for req in data["domain_requests"]]
|
||||||
self.assertEqual(submission_dates, sorted(submission_dates, reverse=True))
|
self.assertEqual(last_submitted_dates, sorted(last_submitted_dates, reverse=True))
|
||||||
|
|
||||||
response = self.app.get(reverse("get_domain_requests_json"), {"sort_by": "submission_date", "order": "asc"})
|
response = self.app.get(reverse("get_domain_requests_json"), {"sort_by": "last_submitted_date", "order": "asc"})
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
data = response.json
|
data = response.json
|
||||||
|
|
||||||
# Check if sorted by submission_date in ascending order
|
# Check if sorted by last_submitted_date in ascending order
|
||||||
submission_dates = [req["submission_date"] for req in data["domain_requests"]]
|
last_submitted_dates = [req["last_submitted_date"] for req in data["domain_requests"]]
|
||||||
self.assertEqual(submission_dates, sorted(submission_dates))
|
self.assertEqual(last_submitted_dates, sorted(last_submitted_dates))
|
||||||
|
|
||||||
def test_filter_approved_excluded(self):
|
def test_filter_approved_excluded(self):
|
||||||
"""test that approved requests are excluded from result set."""
|
"""test that approved requests are excluded from result set."""
|
||||||
# sort in reverse chronological order of submission date, since most recent request is approved
|
# sort in reverse chronological order of submission date, since most recent request is approved
|
||||||
response = self.app.get(reverse("get_domain_requests_json"), {"sort_by": "submission_date", "order": "desc"})
|
response = self.app.get(
|
||||||
|
reverse("get_domain_requests_json"), {"sort_by": "last_submitted_date", "order": "desc"}
|
||||||
|
)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
data = response.json
|
data = response.json
|
||||||
|
|
||||||
|
|
|
@ -1235,7 +1235,9 @@ class DomainRequestExport(BaseExport):
|
||||||
"State/territory": model.get("state_territory"),
|
"State/territory": model.get("state_territory"),
|
||||||
"Request purpose": model.get("purpose"),
|
"Request purpose": model.get("purpose"),
|
||||||
"CISA regional representative": model.get("cisa_representative_email"),
|
"CISA regional representative": model.get("cisa_representative_email"),
|
||||||
"Submitted at": model.get("submission_date"),
|
"Last submitted date": model.get("last_submitted_date"),
|
||||||
|
"First submitted date": model.get("first_submitted_date"),
|
||||||
|
"Last status update": model.get("last_status_update"),
|
||||||
}
|
}
|
||||||
|
|
||||||
row = [FIELDS.get(column, "") for column in columns]
|
row = [FIELDS.get(column, "") for column in columns]
|
||||||
|
@ -1279,8 +1281,8 @@ class DomainRequestGrowth(DomainRequestExport):
|
||||||
end_date_formatted = format_end_date(end_date)
|
end_date_formatted = format_end_date(end_date)
|
||||||
return Q(
|
return Q(
|
||||||
status=DomainRequest.DomainRequestStatus.SUBMITTED,
|
status=DomainRequest.DomainRequestStatus.SUBMITTED,
|
||||||
submission_date__lte=end_date_formatted,
|
last_submitted_date__lte=end_date_formatted,
|
||||||
submission_date__gte=start_date_formatted,
|
last_submitted_date__gte=start_date_formatted,
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -1304,7 +1306,9 @@ class DomainRequestDataFull(DomainRequestExport):
|
||||||
"""
|
"""
|
||||||
return [
|
return [
|
||||||
"Domain request",
|
"Domain request",
|
||||||
"Submitted at",
|
"Last submitted date",
|
||||||
|
"First submitted date",
|
||||||
|
"Last status update",
|
||||||
"Status",
|
"Status",
|
||||||
"Domain type",
|
"Domain type",
|
||||||
"Federal type",
|
"Federal type",
|
||||||
|
|
|
@ -46,7 +46,7 @@ def get_domain_requests_json(request):
|
||||||
domain_requests_data = [
|
domain_requests_data = [
|
||||||
{
|
{
|
||||||
"requested_domain": domain_request.requested_domain.name if domain_request.requested_domain else None,
|
"requested_domain": domain_request.requested_domain.name if domain_request.requested_domain else None,
|
||||||
"submission_date": domain_request.submission_date,
|
"last_submitted_date": domain_request.last_submitted_date,
|
||||||
"status": domain_request.get_status_display(),
|
"status": domain_request.get_status_display(),
|
||||||
"created_at": format(domain_request.created_at, "c"), # Serialize to ISO 8601
|
"created_at": format(domain_request.created_at, "c"), # Serialize to ISO 8601
|
||||||
"id": domain_request.id,
|
"id": domain_request.id,
|
||||||
|
|
|
@ -26,7 +26,7 @@ class AnalyticsView(View):
|
||||||
created_at__gt=thirty_days_ago, status=models.DomainRequest.DomainRequestStatus.APPROVED
|
created_at__gt=thirty_days_ago, status=models.DomainRequest.DomainRequestStatus.APPROVED
|
||||||
)
|
)
|
||||||
avg_approval_time = last_30_days_approved_applications.annotate(
|
avg_approval_time = last_30_days_approved_applications.annotate(
|
||||||
approval_time=F("approved_domain__created_at") - F("submission_date")
|
approval_time=F("approved_domain__created_at") - F("last_submitted_date")
|
||||||
).aggregate(Avg("approval_time"))["approval_time__avg"]
|
).aggregate(Avg("approval_time"))["approval_time__avg"]
|
||||||
# Format the timedelta to display only days
|
# Format the timedelta to display only days
|
||||||
if avg_approval_time is not None:
|
if avg_approval_time is not None:
|
||||||
|
@ -104,11 +104,11 @@ class AnalyticsView(View):
|
||||||
|
|
||||||
filter_submitted_requests_start_date = {
|
filter_submitted_requests_start_date = {
|
||||||
"status": models.DomainRequest.DomainRequestStatus.SUBMITTED,
|
"status": models.DomainRequest.DomainRequestStatus.SUBMITTED,
|
||||||
"submission_date__lte": start_date_formatted,
|
"last_submitted_date__lte": start_date_formatted,
|
||||||
}
|
}
|
||||||
filter_submitted_requests_end_date = {
|
filter_submitted_requests_end_date = {
|
||||||
"status": models.DomainRequest.DomainRequestStatus.SUBMITTED,
|
"status": models.DomainRequest.DomainRequestStatus.SUBMITTED,
|
||||||
"submission_date__lte": end_date_formatted,
|
"last_submitted_date__lte": end_date_formatted,
|
||||||
}
|
}
|
||||||
submitted_requests_sliced_at_start_date = csv_export.DomainRequestExport.get_sliced_requests(
|
submitted_requests_sliced_at_start_date = csv_export.DomainRequestExport.get_sliced_requests(
|
||||||
filter_submitted_requests_start_date
|
filter_submitted_requests_start_date
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue