diff --git a/src/registrar/migrations/0057_domainapplication_submission_date.py b/src/registrar/migrations/0057_domainapplication_submission_date.py new file mode 100644 index 000000000..a2a170888 --- /dev/null +++ b/src/registrar/migrations/0057_domainapplication_submission_date.py @@ -0,0 +1,17 @@ +# Generated by Django 4.2.7 on 2023-12-13 15:04 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("registrar", "0056_alter_domain_state_alter_domainapplication_status_and_more"), + ] + + operations = [ + migrations.AddField( + model_name="domainapplication", + name="submission_date", + field=models.DateField(blank=True, default=None, help_text="Date submitted", null=True), + ), + ] diff --git a/src/registrar/models/domain.py b/src/registrar/models/domain.py index 44cb45433..ca2bc4951 100644 --- a/src/registrar/models/domain.py +++ b/src/registrar/models/domain.py @@ -8,6 +8,7 @@ from typing import Optional from django_fsm import FSMField, transition, TransitionNotAllowed # type: ignore from django.db import models +from django.utils import timezone from typing import Any @@ -200,6 +201,14 @@ class Domain(TimeStampedModel, DomainHelper): """Get the `cr_date` element from the registry.""" return self._get_property("cr_date") + @creation_date.setter # type: ignore + def creation_date(self, ex_date: date): + """ + Direct setting of the creation date in the registry is not implemented. + + Creation date can only be set by registry.""" + raise NotImplementedError() + @Cache def last_transferred_date(self) -> date: """Get the `tr_date` element from the registry.""" @@ -963,6 +972,16 @@ class Domain(TimeStampedModel, DomainHelper): def isActive(self): return self.state == Domain.State.CREATED + def is_expired(self): + """ + Check if the domain's expiration date is in the past. + Returns True if expired, False otherwise. + """ + if self.expiration_date is None: + return True + now = timezone.now().date() + return self.expiration_date < now + def map_epp_contact_to_public_contact(self, contact: eppInfo.InfoContactResultData, contact_id, contact_type): """Maps the Epp contact representation to a PublicContact object. @@ -1582,38 +1601,11 @@ class Domain(TimeStampedModel, DomainHelper): def _fetch_cache(self, fetch_hosts=False, fetch_contacts=False): """Contact registry for info about a domain.""" try: - # get info from registry data_response = self._get_or_create_domain() cache = self._extract_data_from_response(data_response) - - # remove null properties (to distinguish between "a value of None" and null) - cleaned = self._remove_null_properties(cache) - - if "statuses" in cleaned: - cleaned["statuses"] = [status.state for status in cleaned["statuses"]] - - cleaned["dnssecdata"] = self._get_dnssec_data(data_response.extensions) - - # Capture and store old hosts and contacts from cache if they exist - old_cache_hosts = self._cache.get("hosts") - old_cache_contacts = self._cache.get("contacts") - - if fetch_contacts: - cleaned["contacts"] = self._get_contacts(cleaned.get("_contacts", [])) - if old_cache_hosts is not None: - logger.debug("resetting cleaned['hosts'] to old_cache_hosts") - cleaned["hosts"] = old_cache_hosts - - if fetch_hosts: - cleaned["hosts"] = self._get_hosts(cleaned.get("_hosts", [])) - if old_cache_contacts is not None: - cleaned["contacts"] = old_cache_contacts - - # if expiration date from registry does not match what is in db, - # update the db - if "ex_date" in cleaned and cleaned["ex_date"] != self.expiration_date: - self.expiration_date = cleaned["ex_date"] - self.save() + cleaned = self._clean_cache(cache, data_response) + self._update_hosts_and_contacts(cleaned, fetch_hosts, fetch_contacts) + self._update_dates(cleaned) self._cache = cleaned @@ -1621,6 +1613,7 @@ class Domain(TimeStampedModel, DomainHelper): logger.error(e) def _extract_data_from_response(self, data_response): + """extract data from response from registry""" data = data_response.res_data[0] return { "auth_info": getattr(data, "auth_info", ...), @@ -1635,6 +1628,15 @@ class Domain(TimeStampedModel, DomainHelper): "up_date": getattr(data, "up_date", ...), } + def _clean_cache(self, cache, data_response): + """clean up the cache""" + # remove null properties (to distinguish between "a value of None" and null) + cleaned = self._remove_null_properties(cache) + if "statuses" in cleaned: + cleaned["statuses"] = [status.state for status in cleaned["statuses"]] + cleaned["dnssecdata"] = self._get_dnssec_data(data_response.extensions) + return cleaned + def _remove_null_properties(self, cache): return {k: v for k, v in cache.items() if v is not ...} @@ -1648,6 +1650,42 @@ class Domain(TimeStampedModel, DomainHelper): dnssec_data = extension return dnssec_data + def _update_hosts_and_contacts(self, cleaned, fetch_hosts, fetch_contacts): + """Capture and store old hosts and contacts from cache if the don't exist""" + old_cache_hosts = self._cache.get("hosts") + old_cache_contacts = self._cache.get("contacts") + + if fetch_contacts: + cleaned["contacts"] = self._get_contacts(cleaned.get("_contacts", [])) + if old_cache_hosts is not None: + logger.debug("resetting cleaned['hosts'] to old_cache_hosts") + cleaned["hosts"] = old_cache_hosts + + if fetch_hosts: + cleaned["hosts"] = self._get_hosts(cleaned.get("_hosts", [])) + if old_cache_contacts is not None: + cleaned["contacts"] = old_cache_contacts + + def _update_dates(self, cleaned): + """Update dates (expiration and creation) from cleaned""" + requires_save = False + + # if expiration date from registry does not match what is in db, + # update the db + if "ex_date" in cleaned and cleaned["ex_date"] != self.expiration_date: + self.expiration_date = cleaned["ex_date"] + requires_save = True + + # if creation_date from registry does not match what is in db, + # update the db + if "cr_date" in cleaned and cleaned["cr_date"] != self.created_at: + self.created_at = cleaned["cr_date"] + requires_save = True + + # if either registration date or creation date need updating + if requires_save: + self.save() + def _get_contacts(self, contacts): choices = PublicContact.ContactTypeChoices # We expect that all these fields get populated, diff --git a/src/registrar/models/domain_application.py b/src/registrar/models/domain_application.py index 303f0cd22..9dcafdad5 100644 --- a/src/registrar/models/domain_application.py +++ b/src/registrar/models/domain_application.py @@ -6,6 +6,7 @@ import logging from django.apps import apps from django.db import models from django_fsm import FSMField, transition # type: ignore +from django.utils import timezone from registrar.models.domain import Domain from .utility.time_stamped_model import TimeStampedModel @@ -547,6 +548,14 @@ class DomainApplication(TimeStampedModel): help_text="Acknowledged .gov acceptable use policy", ) + # submission date records when application is submitted + submission_date = models.DateField( + null=True, + blank=True, + default=None, + help_text="Date submitted", + ) + def __str__(self): try: if self.requested_domain and self.requested_domain.name: @@ -607,6 +616,10 @@ class DomainApplication(TimeStampedModel): if not DraftDomain.string_could_be_domain(self.requested_domain.name): raise ValueError("Requested domain is not a valid domain name.") + # Update submission_date to today + self.submission_date = timezone.now().date() + self.save() + self._send_status_update_email( "submission confirmation", "emails/submission_confirmation.txt", diff --git a/src/registrar/models/domain_information.py b/src/registrar/models/domain_information.py index 1d934f659..e6c323128 100644 --- a/src/registrar/models/domain_information.py +++ b/src/registrar/models/domain_information.py @@ -229,6 +229,7 @@ class DomainInformation(TimeStampedModel): da_dict.pop("alternative_domains", None) da_dict.pop("requested_domain", None) da_dict.pop("approved_domain", None) + da_dict.pop("submission_date", None) other_contacts = da_dict.pop("other_contacts", []) domain_info = cls(**da_dict) domain_info.domain_application = domain_application diff --git a/src/registrar/templates/domain_detail.html b/src/registrar/templates/domain_detail.html index 470df7537..6d67925bc 100644 --- a/src/registrar/templates/domain_detail.html +++ b/src/registrar/templates/domain_detail.html @@ -6,7 +6,7 @@
No DNS name servers have been added yet. Before your domain can be used we’ll need information about your domain name servers.
Add DNS name servers {% else %} diff --git a/src/registrar/templates/home.html b/src/registrar/templates/home.html index 38c3e35b4..15835920b 100644 --- a/src/registrar/templates/home.html +++ b/src/registrar/templates/home.html @@ -39,7 +39,7 @@
+ {% if domain.expiration_date %}
+ Expires:
+ {{ domain.expiration_date|date }}
+ {% if domain.is_expired %} (expired){% endif %}
+
+ {% endif %}
+ {% if domain.created_at %}
+ Date created: {{ domain.created_at|date }}{% endif %}
+