From fb1735e23fec05bd016e833aca427dff4a2d2fff Mon Sep 17 00:00:00 2001 From: Rebecca Hsieh Date: Thu, 22 Feb 2024 16:51:36 -0800 Subject: [PATCH 001/103] Update yaml to include metadata, readme with new directions an d pseudocode for s3 and SES work --- .github/workflows/daily-csv-upload.yaml | 9 +++ docs/developer/README.md | 9 +-- .../generate_current_metadata_report.py | 67 +++++++++++++++++++ src/registrar/utility/email.py | 4 ++ 4 files changed, 85 insertions(+), 4 deletions(-) create mode 100644 src/registrar/management/commands/generate_current_metadata_report.py diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 724a19457..84881398e 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -31,3 +31,12 @@ jobs: cf_space: ${{ secrets.CF_REPORT_ENV }} cf_command: "run-task getgov-${{ secrets.CF_REPORT_ENV }} --command 'python manage.py generate_current_full_report' --name full" + - name: Generate current-metadata.csv + uses: cloud-gov/cg-cli-tools@main + with: + cf_username: ${{ secrets[env.CF_USERNAME] }} + cf_password: ${{ secrets[env.CF_PASSWORD] }} + cf_org: cisa-dotgov + cf_space: ${{ secrets.CF_REPORT_ENV }} + cf_command: "run-task getgov-${{ secrets.CF_REPORT_ENV }} --command 'python manage.py generate_current_metadata_report' --name metadata" + diff --git a/docs/developer/README.md b/docs/developer/README.md index dc4c9ddd2..7dc64ae56 100644 --- a/docs/developer/README.md +++ b/docs/developer/README.md @@ -330,11 +330,12 @@ To associate a S3 instance to your sandbox, follow these steps: 3. Click `Services` on the application nav bar 4. Add a new service (plus symbol) 5. Click `Marketplace Service` -6. On the `Select the service` dropdown, select `s3` -7. Under the dropdown on `Select Plan`, select `basic-sandbox` -8. Under `Service Instance` enter `getgov-s3` for the name +6. For Space, put in your sandbox initials +7. On the `Select the service` dropdown, select `s3` +8. Under the dropdown on `Select Plan`, select `basic-sandbox` +9. Under `Service Instance` enter `getgov-s3` for the name and leave the other fields empty -See this [resource](https://cloud.gov/docs/services/s3/) for information on associating an S3 instance with your sandbox through the CLI. +See this [resource](https://cloud.gov/docs/services/s3/) for information on associating an S3 instance with your sandbox through the CLI. The basic commands should be `cf bind-service getgov- ` and `cf restage getgov-`. ### Testing your S3 instance locally To test the S3 bucket associated with your sandbox, you will need to add four additional variables to your `.env` file. These are as follows: diff --git a/src/registrar/management/commands/generate_current_metadata_report.py b/src/registrar/management/commands/generate_current_metadata_report.py new file mode 100644 index 000000000..d8f5a4693 --- /dev/null +++ b/src/registrar/management/commands/generate_current_metadata_report.py @@ -0,0 +1,67 @@ +"""Generates current-metadata.csv then uploads to S3 + sends email""" + +import logging +import os + +from django.core.management import BaseCommand +from registrar.utility import csv_export +from registrar.utility.s3_bucket import S3ClientHelper + + +logger = logging.getLogger(__name__) + +class Command(BaseCommand): + help = ( + "Generates and uploads a current-metadata.csv file to our S3 bucket " "which is based off of all existing Domains." + ) + + def add_arguments(self, parser): + """Add our two filename arguments.""" + parser.add_argument("--directory", default="migrationdata", help="Desired directory") + parser.add_argument( + "--checkpath", + default=True, + help="Flag that determines if we do a check for os.path.exists. Used for test cases", + ) + + def handle(self, **options): + """Grabs the directory then creates current-metadata.csv in that directory""" + file_name = "current-metadata.csv" + # Ensures a slash is added + directory = os.path.join(options.get("directory"), "") + check_path = options.get("checkpath") + + logger.info("Generating report...") + try: + self.generate_current_metadata_report(directory, file_name, check_path) + except Exception as err: + # TODO - #1317: Notify operations when auto report generation fails + raise err + else: + logger.info(f"Success! Created {file_name}") + + def generate_current_metadata_report(self, directory, file_name, check_path): + """Creates a current-full.csv file under the specified directory, + then uploads it to a AWS S3 bucket""" + s3_client = S3ClientHelper() + file_path = os.path.join(directory, file_name) + + # Generate a file locally for upload + with open(file_path, "w") as file: + csv_export.export_data_type_to_csv(file) + + if check_path and not os.path.exists(file_path): + raise FileNotFoundError(f"Could not find newly created file at '{file_path}'") + + # Upload this generated file for our S3 instance + s3_client.upload_file(file_path, file_name) + """ + We want to make sure to upload to s3 for back up + And now we also want to get the file and encrypt it so we can send it in an email + """ + # metadata_file = s3_client.get_file(file_name) + # metadata_file.encryptthisthingherewithpyzipper + # email.blasend_email(metadata_file) + + + diff --git a/src/registrar/utility/email.py b/src/registrar/utility/email.py index 461637f23..e4e997d9d 100644 --- a/src/registrar/utility/email.py +++ b/src/registrar/utility/email.py @@ -41,6 +41,7 @@ def send_templated_email(template_name: str, subject_template_name: str, to_addr raise EmailSendingError("Could not access the SES client.") from exc try: + #if not attachment: ses_client.send_email( FromEmailAddress=settings.DEFAULT_FROM_EMAIL, Destination={"ToAddresses": [to_address]}, @@ -51,5 +52,8 @@ def send_templated_email(template_name: str, subject_template_name: str, to_addr }, }, ) + # else: # has attachment + # same as above but figure out how to attach a file + # via boto3 "boto3 SES file attachment" except Exception as exc: raise EmailSendingError("Could not send SES email.") from exc From f8f0d7bced1f03d45453fc03c0b6e1df2d8d205b Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 23 Feb 2024 10:17:52 -0700 Subject: [PATCH 002/103] Slight perf improvement for fixtures --- src/registrar/fixtures_applications.py | 30 +++++++++++++-- src/registrar/fixtures_users.py | 12 +++++- src/registrar/models/domain_application.py | 19 ++++++++- src/registrar/utility/errors.py | 45 ++++++++++++++++++++++ 4 files changed, 100 insertions(+), 6 deletions(-) diff --git a/src/registrar/fixtures_applications.py b/src/registrar/fixtures_applications.py index 3e4e0e362..29e95e02b 100644 --- a/src/registrar/fixtures_applications.py +++ b/src/registrar/fixtures_applications.py @@ -1,7 +1,7 @@ import logging import random from faker import Faker - +from django.db import transaction from registrar.models import ( User, DomainApplication, @@ -184,6 +184,14 @@ class DomainApplicationFixture: logger.warning(e) return + # Lumped under .atomic to ensure we don't make redundant DB calls. + # This bundles them all together, and then saves it in a single call. + with transaction.atomic(): + cls._create_applications(users) + + @classmethod + def _create_applications(cls, users): + """Creates DomainApplications given a list of users""" for user in users: logger.debug("Loading domain applications for %s" % user) for app in cls.DA: @@ -211,8 +219,16 @@ class DomainFixture(DomainApplicationFixture): logger.warning(e) return + # Lumped under .atomic to ensure we don't make redundant DB calls. + # This bundles them all together, and then saves it in a single call. + with transaction.atomic(): + # approve each user associated with `in review` status domains + DomainFixture._approve_applications(users) + + @staticmethod + def _approve_applications(users): + """Approves all provided applications if they are in the state in_review""" for user in users: - # approve one of each users in review status domains application = DomainApplication.objects.filter( creator=user, status=DomainApplication.ApplicationStatus.IN_REVIEW ).last() @@ -220,5 +236,13 @@ class DomainFixture(DomainApplicationFixture): # We don't want fixtures sending out real emails to # fake email addresses, so we just skip that and log it instead + + # All approvals require an investigator, so if there is none, + # assign one. + if application.investigator is None: + # All "users" in fixtures have admin perms per prior config. + # No need to check for that. + application.investigator = random.choice(users) + application.approve(send_email=False) - application.save() + application.save() \ No newline at end of file diff --git a/src/registrar/fixtures_users.py b/src/registrar/fixtures_users.py index f03fb025d..830adb5bf 100644 --- a/src/registrar/fixtures_users.py +++ b/src/registrar/fixtures_users.py @@ -1,5 +1,6 @@ import logging from faker import Faker +from django.db import transaction from registrar.models import ( User, @@ -186,5 +187,12 @@ class UserFixture: @classmethod def load(cls): - cls.load_users(cls, cls.ADMINS, "full_access_group") - cls.load_users(cls, cls.STAFF, "cisa_analysts_group") + # Lumped under .atomic to ensure we don't make redundant DB calls. + # This bundles them all together, and then saves it in a single call. + # This is slightly different then bulk_create or bulk_update, in that + # you still get the same behaviour of .save(), but those incremental + # steps now do not need to close/reopen a db connection, + # instead they share one. + with transaction.atomic(): + cls.load_users(cls, cls.ADMINS, "full_access_group") + cls.load_users(cls, cls.STAFF, "cisa_analysts_group") diff --git a/src/registrar/models/domain_application.py b/src/registrar/models/domain_application.py index 17bc71cbe..5f204d3e3 100644 --- a/src/registrar/models/domain_application.py +++ b/src/registrar/models/domain_application.py @@ -8,6 +8,7 @@ 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 registrar.utility.errors import ApplicationStatusError, FSMErrorCodes from .utility.time_stamped_model import TimeStampedModel from ..utility.email import send_templated_email, EmailSendingError @@ -736,8 +737,23 @@ class DomainApplication(TimeStampedModel): # create the domain Domain = apps.get_model("registrar.Domain") + + # == Check that the application is valid == # if Domain.objects.filter(name=self.requested_domain.name).exists(): - raise ValueError("Cannot approve. Requested domain is already in use.") + raise ApplicationStatusError(code=FSMErrorCodes.APPROVE_DOMAIN_IN_USE) + + # Check if an investigator is assigned. No approval is possible without one. + # TODO - add form level error + # TODO - maybe add modal if approver is not investigator as superuser + if self.investigator is None: + raise ApplicationStatusError(code=FSMErrorCodes.APPROVE_NO_INVESTIGATOR) + + # Investigators must be staff users. + # This is handled elsewhere, but we should check here as a precaution. + if not self.investigator.is_staff: + raise ApplicationStatusError(code=FSMErrorCodes.APPROVE_INVESTIGATOR_NOT_STAFF) + + # == Create the domain and related components == # created_domain = Domain.objects.create(name=self.requested_domain.name) self.approved_domain = created_domain @@ -751,6 +767,7 @@ class DomainApplication(TimeStampedModel): user=self.creator, domain=created_domain, role=UserDomainRole.Roles.MANAGER ) + # == Send out an email == # self._send_status_update_email( "application approved", "emails/status_change_approved.txt", diff --git a/src/registrar/utility/errors.py b/src/registrar/utility/errors.py index 03cb81893..21bdeefc6 100644 --- a/src/registrar/utility/errors.py +++ b/src/registrar/utility/errors.py @@ -70,6 +70,51 @@ class GenericError(Exception): def get_error_message(self, code=None): return self._error_mapping.get(code) +# (Q for reviewers) What should this be called? +# Not a fan of this name. +class FSMErrorCodes(IntEnum): + """Used when doing FSM transitions. + Overview of generic error codes: + - 1 APPROVE_DOMAIN_IN_USE The domain is already in use + - 2 APPROVE_NO_INVESTIGATOR No investigator is assigned when approving + - 3 APPROVE_INVESTIGATOR_NOT_STAFF Investigator is a non-staff user + """ + APPROVE_DOMAIN_IN_USE = 1 + APPROVE_NO_INVESTIGATOR = 2 + APPROVE_INVESTIGATOR_NOT_STAFF = 3 + + +class ApplicationStatusError(Exception): + """ + Used to raise exceptions when doing FSM Transitions. + Uses `FSMErrorCodes` as an enum. + """ + + _error_mapping = { + FSMErrorCodes.APPROVE_DOMAIN_IN_USE: ( + "Cannot approve. Requested domain is already in use." + ), + FSMErrorCodes.APPROVE_NO_INVESTIGATOR: ( + "Cannot approve. No investigator was assigned." + ), + FSMErrorCodes.APPROVE_INVESTIGATOR_NOT_STAFF: ( + "Cannot approve. Investigator is not a staff user." + ), + } + + def __init__(self, *args, code=None, **kwargs): + super().__init__(*args, **kwargs) + self.code = code + if self.code in self._error_mapping: + self.message = self._error_mapping.get(self.code) + + def __str__(self): + return f"{self.message}" + + @classmethod + def get_error_message(self, code=None): + return self._error_mapping.get(code) + class NameserverErrorCodes(IntEnum): """Used in the NameserverError class for From 1a20583b487dc965af13d322e1ac54188603942d Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 23 Feb 2024 11:25:23 -0700 Subject: [PATCH 003/103] Update admin.py --- src/registrar/admin.py | 105 +++++++++++++++++++++-------------------- 1 file changed, 55 insertions(+), 50 deletions(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index 0ab6c3022..349d0ddc1 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -953,57 +953,10 @@ class DomainApplicationAdmin(ListHeaderAdmin): # Trigger action when a fieldset is changed def save_model(self, request, obj, form, change): - if obj and obj.creator.status != models.User.RESTRICTED: - if change: # Check if the application is being edited - # Get the original application from the database - original_obj = models.DomainApplication.objects.get(pk=obj.pk) - if ( - obj - and original_obj.status == models.DomainApplication.ApplicationStatus.APPROVED - and obj.status != models.DomainApplication.ApplicationStatus.APPROVED - and not obj.domain_is_not_active() - ): - # If an admin tried to set an approved application to - # another status and the related domain is already - # active, shortcut the action and throw a friendly - # error message. This action would still not go through - # shortcut or not as the rules are duplicated on the model, - # but the error would be an ugly Django error screen. - - # Clear the success message - messages.set_level(request, messages.ERROR) - - messages.error( - request, - "This action is not permitted. The domain is already active.", - ) - - else: - if obj.status != original_obj.status: - status_method_mapping = { - models.DomainApplication.ApplicationStatus.STARTED: None, - models.DomainApplication.ApplicationStatus.SUBMITTED: obj.submit, - models.DomainApplication.ApplicationStatus.IN_REVIEW: obj.in_review, - models.DomainApplication.ApplicationStatus.ACTION_NEEDED: obj.action_needed, - models.DomainApplication.ApplicationStatus.APPROVED: obj.approve, - models.DomainApplication.ApplicationStatus.WITHDRAWN: obj.withdraw, - models.DomainApplication.ApplicationStatus.REJECTED: obj.reject, - models.DomainApplication.ApplicationStatus.INELIGIBLE: (obj.reject_with_prejudice), - } - selected_method = status_method_mapping.get(obj.status) - if selected_method is None: - logger.warning("Unknown status selected in django admin") - else: - # This is an fsm in model which will throw an error if the - # transition condition is violated, so we roll back the - # status to what it was before the admin user changed it and - # let the fsm method set it. - obj.status = original_obj.status - selected_method() - - super().save_model(request, obj, form, change) - else: + # If the user is restricted or we're saving an invalid model, + # forbid this action. + if not obj or obj.creator.status == models.User.RESTRICTED: # Clear the success message messages.set_level(request, messages.ERROR) @@ -1012,6 +965,58 @@ class DomainApplicationAdmin(ListHeaderAdmin): "This action is not permitted for applications with a restricted creator.", ) + return None + + if change: # Check if the application is being edited + # Get the original application from the database + original_obj = models.DomainApplication.objects.get(pk=obj.pk) + + if ( + obj + and original_obj.status == models.DomainApplication.ApplicationStatus.APPROVED + and obj.status != models.DomainApplication.ApplicationStatus.APPROVED + and not obj.domain_is_not_active() + ): + # If an admin tried to set an approved application to + # another status and the related domain is already + # active, shortcut the action and throw a friendly + # error message. This action would still not go through + # shortcut or not as the rules are duplicated on the model, + # but the error would be an ugly Django error screen. + + # Clear the success message + messages.set_level(request, messages.ERROR) + + messages.error( + request, + "This action is not permitted. The domain is already active.", + ) + + else: + if obj.status != original_obj.status: + status_method_mapping = { + models.DomainApplication.ApplicationStatus.STARTED: None, + models.DomainApplication.ApplicationStatus.SUBMITTED: obj.submit, + models.DomainApplication.ApplicationStatus.IN_REVIEW: obj.in_review, + models.DomainApplication.ApplicationStatus.ACTION_NEEDED: obj.action_needed, + models.DomainApplication.ApplicationStatus.APPROVED: obj.approve, + models.DomainApplication.ApplicationStatus.WITHDRAWN: obj.withdraw, + models.DomainApplication.ApplicationStatus.REJECTED: obj.reject, + models.DomainApplication.ApplicationStatus.INELIGIBLE: (obj.reject_with_prejudice), + } + selected_method = status_method_mapping.get(obj.status) + if selected_method is None: + logger.warning("Unknown status selected in django admin") + else: + # This is an fsm in model which will throw an error if the + # transition condition is violated, so we roll back the + # status to what it was before the admin user changed it and + # let the fsm method set it. + obj.status = original_obj.status + selected_method() + + super().save_model(request, obj, form, change) + def get_readonly_fields(self, request, obj=None): """Set the read-only state on form elements. We have 2 conditions that determine which fields are read-only: From 527f586419b9b986a8b88ecc3dd0edd9373b64b3 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 23 Feb 2024 12:03:04 -0700 Subject: [PATCH 004/103] Additional refactoring --- src/registrar/admin.py | 24 ++++++++++++++++++---- src/registrar/models/domain_application.py | 5 +---- src/registrar/utility/errors.py | 2 ++ 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index 349d0ddc1..f58a481df 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -16,6 +16,7 @@ from dateutil.relativedelta import relativedelta # type: ignore from epplibwrapper.errors import ErrorCode, RegistryError from registrar.models import Contact, Domain, DomainApplication, DraftDomain, User, Website from registrar.utility import csv_export +from registrar.utility.errors import ApplicationStatusError from registrar.views.utility.mixins import OrderableFieldsMixin from django.contrib.admin.views.main import ORDER_VAR from . import models @@ -953,6 +954,8 @@ class DomainApplicationAdmin(ListHeaderAdmin): # Trigger action when a fieldset is changed def save_model(self, request, obj, form, change): + # TODO - there is an existing bug in these in that they redirect + # to the table rather than back, on message display # If the user is restricted or we're saving an invalid model, # forbid this action. @@ -966,8 +969,8 @@ class DomainApplicationAdmin(ListHeaderAdmin): ) return None - - if change: # Check if the application is being edited + + if change: # Get the original application from the database original_obj = models.DomainApplication.objects.get(pk=obj.pk) @@ -1013,9 +1016,22 @@ class DomainApplicationAdmin(ListHeaderAdmin): # status to what it was before the admin user changed it and # let the fsm method set it. obj.status = original_obj.status - selected_method() - super().save_model(request, obj, form, change) + # Try to perform the status change. + # Catch ApplicationStatusError's and return the message, + # as these are typically user errors. + try: + selected_method() + except ApplicationStatusError as err: + # Clear the success message, if any + messages.set_level(request, messages.ERROR) + + messages.error( + request, + err.message, + ) + + super().save_model(request, obj, form, change) def get_readonly_fields(self, request, obj=None): """Set the read-only state on form elements. diff --git a/src/registrar/models/domain_application.py b/src/registrar/models/domain_application.py index 5f204d3e3..5de6dc482 100644 --- a/src/registrar/models/domain_application.py +++ b/src/registrar/models/domain_application.py @@ -638,10 +638,7 @@ class DomainApplication(TimeStampedModel): # can raise more informative exceptions # requested_domain could be None here - if not hasattr(self, "requested_domain"): - raise ValueError("Requested domain is missing.") - - if self.requested_domain is None: + if not hasattr(self, "requested_domain") or self.requested_domain is None: raise ValueError("Requested domain is missing.") DraftDomain = apps.get_model("registrar.DraftDomain") diff --git a/src/registrar/utility/errors.py b/src/registrar/utility/errors.py index 21bdeefc6..1d82ea49a 100644 --- a/src/registrar/utility/errors.py +++ b/src/registrar/utility/errors.py @@ -84,6 +84,8 @@ class FSMErrorCodes(IntEnum): APPROVE_INVESTIGATOR_NOT_STAFF = 3 +# (Q for reviewers) What should this be called? +# Not a fan of this name. class ApplicationStatusError(Exception): """ Used to raise exceptions when doing FSM Transitions. From cf7bf4d30491d5894a0220dda5ea0cf94d709285 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 23 Feb 2024 13:14:36 -0700 Subject: [PATCH 005/103] Add form level errors --- src/registrar/admin.py | 27 ++++++++++++++++++++++++++- src/registrar/utility/errors.py | 4 ++-- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index f58a481df..9c3b8075e 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -16,7 +16,7 @@ from dateutil.relativedelta import relativedelta # type: ignore from epplibwrapper.errors import ErrorCode, RegistryError from registrar.models import Contact, Domain, DomainApplication, DraftDomain, User, Website from registrar.utility import csv_export -from registrar.utility.errors import ApplicationStatusError +from registrar.utility.errors import ApplicationStatusError, FSMErrorCodes from registrar.views.utility.mixins import OrderableFieldsMixin from django.contrib.admin.views.main import ORDER_VAR from . import models @@ -808,6 +808,31 @@ class DomainApplicationAdminForm(forms.ModelForm): if not application.creator.is_restricted(): self.fields["status"].widget.choices = available_transitions + def clean(self): + # clean is called from clean_forms, which is called from is_valid + # after clean_fields. it is used to determine form level errors. + # is_valid is typically called from view during a post + cleaned_data = super().clean() + investigator = cleaned_data.get("investigator") + status = cleaned_data.get("status") + requested_domain = cleaned_data.get("requested_domain") + + # Check if an investigator is assigned. No approval is possible without one. + # TODO - add form level error + # TODO - maybe add modal if approver is not investigator as superuser + if investigator is None: + error_message = ApplicationStatusError.get_error_message(FSMErrorCodes.APPROVE_NO_INVESTIGATOR) + self.add_error("investigator", error_message) + else: + # Investigators must be staff users. + # This is handled elsewhere, but we should check here as a precaution. + if not investigator.is_staff: + error_message = ApplicationStatusError.get_error_message(FSMErrorCodes.APPROVE_INVESTIGATOR_NOT_STAFF) + self.add_error("investigator", error_message) + #if status == DomainApplication.ApplicationStatus.APPROVED and investigator != request.user: + #raise ValidationError("Only the assigned investigator can approve this application.") + + return cleaned_data class DomainApplicationAdmin(ListHeaderAdmin): """Custom domain applications admin class.""" diff --git a/src/registrar/utility/errors.py b/src/registrar/utility/errors.py index 1d82ea49a..8d77ecd2e 100644 --- a/src/registrar/utility/errors.py +++ b/src/registrar/utility/errors.py @@ -114,8 +114,8 @@ class ApplicationStatusError(Exception): return f"{self.message}" @classmethod - def get_error_message(self, code=None): - return self._error_mapping.get(code) + def get_error_message(cls, code=None): + return cls._error_mapping.get(code) class NameserverErrorCodes(IntEnum): From c02e99b972fe42599c7b618321288d5f9e9b1281 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 23 Feb 2024 14:21:08 -0700 Subject: [PATCH 006/103] Add logic for same investigator is approver --- src/registrar/admin.py | 66 ++++++++++++++++------ src/registrar/models/domain_application.py | 2 - src/registrar/utility/errors.py | 5 ++ 3 files changed, 54 insertions(+), 19 deletions(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index 9c3b8075e..a33b8eaa9 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -786,8 +786,8 @@ class DomainApplicationAdminForm(forms.ModelForm): fields = "__all__" def __init__(self, *args, **kwargs): + self.request = kwargs.pop("request", None) super().__init__(*args, **kwargs) - application = kwargs.get("instance") if application and application.pk: current_state = application.status @@ -813,27 +813,42 @@ class DomainApplicationAdminForm(forms.ModelForm): # after clean_fields. it is used to determine form level errors. # is_valid is typically called from view during a post cleaned_data = super().clean() - investigator = cleaned_data.get("investigator") status = cleaned_data.get("status") - requested_domain = cleaned_data.get("requested_domain") + investigator = cleaned_data.get("investigator") - # Check if an investigator is assigned. No approval is possible without one. - # TODO - add form level error - # TODO - maybe add modal if approver is not investigator as superuser - if investigator is None: - error_message = ApplicationStatusError.get_error_message(FSMErrorCodes.APPROVE_NO_INVESTIGATOR) - self.add_error("investigator", error_message) - else: - # Investigators must be staff users. - # This is handled elsewhere, but we should check here as a precaution. - if not investigator.is_staff: - error_message = ApplicationStatusError.get_error_message(FSMErrorCodes.APPROVE_INVESTIGATOR_NOT_STAFF) - self.add_error("investigator", error_message) - #if status == DomainApplication.ApplicationStatus.APPROVED and investigator != request.user: - #raise ValidationError("Only the assigned investigator can approve this application.") + if status == DomainApplication.ApplicationStatus.APPROVED: + # Checks the "investigators" field for validity. + # That field must obey certain conditions when an application is approved. + # Will call "add_error" if any issues are found. + self._check_investigators_on_approval(investigator) return cleaned_data + def _check_investigators_on_approval(self, investigator): + """Checks the investigator field when an approval occurs""" + + error_message = None + # Check if an investigator is assigned. No approval is possible without one. + if investigator is not None: + + if not investigator.is_staff: + # Investigators must be staff users. + # This is handled elsewhere, but we should check here as a precaution. + error_message = ApplicationStatusError.get_error_message(FSMErrorCodes.APPROVE_INVESTIGATOR_NOT_STAFF) + elif investigator != self.request.user: + # If the submitting user is not the investigator, block this action. + # This is to enforce accountability. Superusers do not have this restriction. + error_message = ApplicationStatusError.get_error_message( + FSMErrorCodes.APPROVE_INVESTIGATOR_NOT_SUBMITTER + ) + else: + error_message = ApplicationStatusError.get_error_message(FSMErrorCodes.APPROVE_NO_INVESTIGATOR) + + # Add the error + if error_message is not None: + self.add_error("investigator", error_message) + + class DomainApplicationAdmin(ListHeaderAdmin): """Custom domain applications admin class.""" @@ -977,6 +992,23 @@ class DomainApplicationAdmin(ListHeaderAdmin): # Table ordering ordering = ["requested_domain__name"] + def get_form(self, request, obj=None, **kwargs): + """ + Workaround to pass the request context to the underlying DomainApplicationAdminForm form object. + This is so we can do things like check the current user against a form value at submission. + """ + # Call the superclass's get_form method to get the form class + da_form = super().get_form(request, obj, **kwargs) + + # Define a wrapper class for the form that includes the request in its initialization. + # This is needed such that we can inject request without otherwise altering it. + class DomainApplicationFormWrapper(da_form): + def __new__(cls, *args, **form_kwargs): + form_kwargs["request"] = request + return da_form(*args, **form_kwargs) + + return DomainApplicationFormWrapper + # Trigger action when a fieldset is changed def save_model(self, request, obj, form, change): # TODO - there is an existing bug in these in that they redirect diff --git a/src/registrar/models/domain_application.py b/src/registrar/models/domain_application.py index 5de6dc482..5f4ce8a01 100644 --- a/src/registrar/models/domain_application.py +++ b/src/registrar/models/domain_application.py @@ -740,8 +740,6 @@ class DomainApplication(TimeStampedModel): raise ApplicationStatusError(code=FSMErrorCodes.APPROVE_DOMAIN_IN_USE) # Check if an investigator is assigned. No approval is possible without one. - # TODO - add form level error - # TODO - maybe add modal if approver is not investigator as superuser if self.investigator is None: raise ApplicationStatusError(code=FSMErrorCodes.APPROVE_NO_INVESTIGATOR) diff --git a/src/registrar/utility/errors.py b/src/registrar/utility/errors.py index 8d77ecd2e..a4359b0c7 100644 --- a/src/registrar/utility/errors.py +++ b/src/registrar/utility/errors.py @@ -78,10 +78,12 @@ class FSMErrorCodes(IntEnum): - 1 APPROVE_DOMAIN_IN_USE The domain is already in use - 2 APPROVE_NO_INVESTIGATOR No investigator is assigned when approving - 3 APPROVE_INVESTIGATOR_NOT_STAFF Investigator is a non-staff user + - 4 APPROVE_INVESTIGATOR_NOT_SUBMITTER The form submitter is not the investigator """ APPROVE_DOMAIN_IN_USE = 1 APPROVE_NO_INVESTIGATOR = 2 APPROVE_INVESTIGATOR_NOT_STAFF = 3 + APPROVE_INVESTIGATOR_NOT_SUBMITTER = 4 # (Q for reviewers) What should this be called? @@ -102,6 +104,9 @@ class ApplicationStatusError(Exception): FSMErrorCodes.APPROVE_INVESTIGATOR_NOT_STAFF: ( "Cannot approve. Investigator is not a staff user." ), + FSMErrorCodes.APPROVE_INVESTIGATOR_NOT_SUBMITTER: ( + "Cannot approve. Only the assigned investigator can approve this application." + ) } def __init__(self, *args, code=None, **kwargs): From afeb0f55b1122cc002fd90942620b2652b28cf9e Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 23 Feb 2024 14:25:48 -0700 Subject: [PATCH 007/103] Add logic for superuser --- src/registrar/admin.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index a33b8eaa9..71c347fed 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -827,15 +827,18 @@ class DomainApplicationAdminForm(forms.ModelForm): def _check_investigators_on_approval(self, investigator): """Checks the investigator field when an approval occurs""" + # Get information about the current user making the request + current_user = self.request.user + is_superuser = current_user.has_perm("registrar.full_access_permission") + error_message = None # Check if an investigator is assigned. No approval is possible without one. if investigator is not None: - if not investigator.is_staff: # Investigators must be staff users. # This is handled elsewhere, but we should check here as a precaution. error_message = ApplicationStatusError.get_error_message(FSMErrorCodes.APPROVE_INVESTIGATOR_NOT_STAFF) - elif investigator != self.request.user: + elif investigator != current_user and not is_superuser: # If the submitting user is not the investigator, block this action. # This is to enforce accountability. Superusers do not have this restriction. error_message = ApplicationStatusError.get_error_message( From 4eae72d983442f89fc2c845cbe5a76c86ceac9fe Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 23 Feb 2024 14:51:29 -0700 Subject: [PATCH 008/103] Add todo --- src/registrar/admin.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index 71c347fed..d724a91fd 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -816,6 +816,7 @@ class DomainApplicationAdminForm(forms.ModelForm): status = cleaned_data.get("status") investigator = cleaned_data.get("investigator") + # TODO - need some way of determining if a change has actually occurred and to enforce this only then if status == DomainApplication.ApplicationStatus.APPROVED: # Checks the "investigators" field for validity. # That field must obey certain conditions when an application is approved. From b30802d3d737dc36f7c5f9dddca354f4506675b8 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 23 Feb 2024 15:20:25 -0700 Subject: [PATCH 009/103] Fix some unit tests, linting Have a few more to nail down, but this is most of them --- src/registrar/admin.py | 10 +++--- src/registrar/models/domain_application.py | 2 +- src/registrar/tests/common.py | 2 ++ src/registrar/tests/test_models.py | 38 +++++++++++++++------- src/registrar/tests/test_models_domain.py | 5 ++- 5 files changed, 38 insertions(+), 19 deletions(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index d724a91fd..5cfacc172 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -836,7 +836,7 @@ class DomainApplicationAdminForm(forms.ModelForm): # Check if an investigator is assigned. No approval is possible without one. if investigator is not None: if not investigator.is_staff: - # Investigators must be staff users. + # Investigators must be staff users. # This is handled elsewhere, but we should check here as a precaution. error_message = ApplicationStatusError.get_error_message(FSMErrorCodes.APPROVE_INVESTIGATOR_NOT_STAFF) elif investigator != current_user and not is_superuser: @@ -847,7 +847,7 @@ class DomainApplicationAdminForm(forms.ModelForm): ) else: error_message = ApplicationStatusError.get_error_message(FSMErrorCodes.APPROVE_NO_INVESTIGATOR) - + # Add the error if error_message is not None: self.add_error("investigator", error_message) @@ -1003,14 +1003,14 @@ class DomainApplicationAdmin(ListHeaderAdmin): """ # Call the superclass's get_form method to get the form class da_form = super().get_form(request, obj, **kwargs) - + # Define a wrapper class for the form that includes the request in its initialization. # This is needed such that we can inject request without otherwise altering it. class DomainApplicationFormWrapper(da_form): def __new__(cls, *args, **form_kwargs): form_kwargs["request"] = request return da_form(*args, **form_kwargs) - + return DomainApplicationFormWrapper # Trigger action when a fieldset is changed @@ -1030,7 +1030,7 @@ class DomainApplicationAdmin(ListHeaderAdmin): ) return None - + if change: # Get the original application from the database original_obj = models.DomainApplication.objects.get(pk=obj.pk) diff --git a/src/registrar/models/domain_application.py b/src/registrar/models/domain_application.py index 5f4ce8a01..19f82101e 100644 --- a/src/registrar/models/domain_application.py +++ b/src/registrar/models/domain_application.py @@ -743,7 +743,7 @@ class DomainApplication(TimeStampedModel): if self.investigator is None: raise ApplicationStatusError(code=FSMErrorCodes.APPROVE_NO_INVESTIGATOR) - # Investigators must be staff users. + # Investigators must be staff users. # This is handled elsewhere, but we should check here as a precaution. if not self.investigator.is_staff: raise ApplicationStatusError(code=FSMErrorCodes.APPROVE_INVESTIGATOR_NOT_STAFF) diff --git a/src/registrar/tests/common.py b/src/registrar/tests/common.py index 17833d689..35c093ad5 100644 --- a/src/registrar/tests/common.py +++ b/src/registrar/tests/common.py @@ -530,6 +530,7 @@ def completed_application( user=False, submitter=False, name="city.gov", + investigator=None, ): """A completed domain application.""" if not user: @@ -574,6 +575,7 @@ def completed_application( submitter=submitter, creator=user, status=status, + investigator=investigator, ) if has_about_your_organization: domain_application_kwargs["about_your_organization"] = "e-Government" diff --git a/src/registrar/tests/test_models.py b/src/registrar/tests/test_models.py index cb7906d7a..433ad98ab 100644 --- a/src/registrar/tests/test_models.py +++ b/src/registrar/tests/test_models.py @@ -27,29 +27,30 @@ from django_fsm import TransitionNotAllowed @boto3_mocking.patching class TestDomainApplication(TestCase): def setUp(self): + user, _ = User.objects.get_or_create(username="testpancakesyrup", is_staff=True) self.started_application = completed_application( - status=DomainApplication.ApplicationStatus.STARTED, name="started.gov" + status=DomainApplication.ApplicationStatus.STARTED, name="started.gov", investigator=user ) self.submitted_application = completed_application( - status=DomainApplication.ApplicationStatus.SUBMITTED, name="submitted.gov" + status=DomainApplication.ApplicationStatus.SUBMITTED, name="submitted.gov", investigator=user ) self.in_review_application = completed_application( - status=DomainApplication.ApplicationStatus.IN_REVIEW, name="in-review.gov" + status=DomainApplication.ApplicationStatus.IN_REVIEW, name="in-review.gov", investigator=user ) self.action_needed_application = completed_application( - status=DomainApplication.ApplicationStatus.ACTION_NEEDED, name="action-needed.gov" + status=DomainApplication.ApplicationStatus.ACTION_NEEDED, name="action-needed.gov", investigator=user ) self.approved_application = completed_application( - status=DomainApplication.ApplicationStatus.APPROVED, name="approved.gov" + status=DomainApplication.ApplicationStatus.APPROVED, name="approved.gov", investigator=user ) self.withdrawn_application = completed_application( - status=DomainApplication.ApplicationStatus.WITHDRAWN, name="withdrawn.gov" + status=DomainApplication.ApplicationStatus.WITHDRAWN, name="withdrawn.gov", investigator=user ) self.rejected_application = completed_application( - status=DomainApplication.ApplicationStatus.REJECTED, name="rejected.gov" + status=DomainApplication.ApplicationStatus.REJECTED, name="rejected.gov", investigator=user ) self.ineligible_application = completed_application( - status=DomainApplication.ApplicationStatus.INELIGIBLE, name="ineligible.gov" + status=DomainApplication.ApplicationStatus.INELIGIBLE, name="ineligible.gov", investigator=user ) self.mock_client = MockSESClient() @@ -161,7 +162,7 @@ class TestDomainApplication(TestCase): application.submit() self.assertEqual(application.status, application.ApplicationStatus.SUBMITTED) - def check_email_sent(self, application, msg, action, expected_count): + def check_email_sent(self, application: DomainApplication, msg, action, expected_count): """Check if an email was sent after performing an action.""" with self.subTest(msg=msg, action=action): @@ -169,7 +170,14 @@ class TestDomainApplication(TestCase): with less_console_noise(): # Perform the specified action action_method = getattr(application, action) - action_method() + if action == "approve" and not application.investigator: + user, _ = User.objects.get_or_create(username="testwafflesyrup", is_staff=True) + application.investigator = user + application.save() + application.refresh_from_db() + action_method() + else: + action_method() # Check if an email was sent sent_emails = [ @@ -616,7 +624,10 @@ class TestPermissions(TestCase): def test_approval_creates_role(self): draft_domain, _ = DraftDomain.objects.get_or_create(name="igorville.gov") user, _ = User.objects.get_or_create() - application = DomainApplication.objects.create(creator=user, requested_domain=draft_domain) + investigator, _ = User.objects.get_or_create(username="frenchtoast", is_staff=True) + application = DomainApplication.objects.create( + creator=user, requested_domain=draft_domain, investigator=investigator + ) with boto3_mocking.clients.handler_for("sesv2", self.mock_client): with less_console_noise(): @@ -650,7 +661,10 @@ class TestDomainInformation(TestCase): self.maxDiff = None draft_domain, _ = DraftDomain.objects.get_or_create(name="igorville.gov") user, _ = User.objects.get_or_create() - application = DomainApplication.objects.create(creator=user, requested_domain=draft_domain, notes="test notes") + investigator, _ = User.objects.get_or_create(username="frenchtoast", is_staff=True) + application = DomainApplication.objects.create( + creator=user, requested_domain=draft_domain, notes="test notes", investigator=investigator + ) with boto3_mocking.clients.handler_for("sesv2", self.mock_client): with less_console_noise(): diff --git a/src/registrar/tests/test_models_domain.py b/src/registrar/tests/test_models_domain.py index 2bd581734..b59d548db 100644 --- a/src/registrar/tests/test_models_domain.py +++ b/src/registrar/tests/test_models_domain.py @@ -270,7 +270,10 @@ class TestDomainCreation(MockEppLib): """ draft_domain, _ = DraftDomain.objects.get_or_create(name="igorville.gov") user, _ = User.objects.get_or_create() - application = DomainApplication.objects.create(creator=user, requested_domain=draft_domain) + investigator, _ = User.objects.get_or_create(username="frenchtoast", is_staff=True) + application = DomainApplication.objects.create( + creator=user, requested_domain=draft_domain, investigator=investigator + ) mock_client = MockSESClient() with boto3_mocking.clients.handler_for("sesv2", mock_client): From 010853a5f038047d0ee5a0b1b09b4848e101f233 Mon Sep 17 00:00:00 2001 From: Rebecca Hsieh Date: Fri, 23 Feb 2024 15:26:53 -0800 Subject: [PATCH 010/103] Update readme directions for s3 --- docs/developer/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/developer/README.md b/docs/developer/README.md index 7dc64ae56..53e1182c4 100644 --- a/docs/developer/README.md +++ b/docs/developer/README.md @@ -335,7 +335,7 @@ To associate a S3 instance to your sandbox, follow these steps: 8. Under the dropdown on `Select Plan`, select `basic-sandbox` 9. Under `Service Instance` enter `getgov-s3` for the name and leave the other fields empty -See this [resource](https://cloud.gov/docs/services/s3/) for information on associating an S3 instance with your sandbox through the CLI. The basic commands should be `cf bind-service getgov- ` and `cf restage getgov-`. +See this [resource](https://cloud.gov/docs/services/s3/) for information on associating an S3 instance with your sandbox through the CLI. ### Testing your S3 instance locally To test the S3 bucket associated with your sandbox, you will need to add four additional variables to your `.env` file. These are as follows: From 02e0d00544c9ad126c1c2d1ce2f222647bcec6d3 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Mon, 26 Feb 2024 08:56:03 -0700 Subject: [PATCH 011/103] Add default investigator --- src/registrar/tests/common.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/registrar/tests/common.py b/src/registrar/tests/common.py index b89f0fe1a..f7bca00be 100644 --- a/src/registrar/tests/common.py +++ b/src/registrar/tests/common.py @@ -560,6 +560,13 @@ def completed_application( email="testy2@town.com", phone="(555) 555 5557", ) + if not investigator: + investigator, _ = User.objects.get_or_create( + username="incrediblyfakeinvestigator", + first_name = "Joe", + last_name = "Bob" + is_staff=True + ) domain_application_kwargs = dict( organization_type="federal", federal_type="executive", From 25a5cd02269d048fc0d4ce3bbc771886b71888ad Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Mon, 26 Feb 2024 09:00:33 -0700 Subject: [PATCH 012/103] Linting, unit tests --- src/registrar/fixtures_applications.py | 4 ++-- src/registrar/fixtures_users.py | 4 ++-- src/registrar/tests/common.py | 10 +++++----- src/registrar/utility/errors.py | 22 +++++++++------------- 4 files changed, 18 insertions(+), 22 deletions(-) diff --git a/src/registrar/fixtures_applications.py b/src/registrar/fixtures_applications.py index 29e95e02b..d1ef25211 100644 --- a/src/registrar/fixtures_applications.py +++ b/src/registrar/fixtures_applications.py @@ -188,7 +188,7 @@ class DomainApplicationFixture: # This bundles them all together, and then saves it in a single call. with transaction.atomic(): cls._create_applications(users) - + @classmethod def _create_applications(cls, users): """Creates DomainApplications given a list of users""" @@ -245,4 +245,4 @@ class DomainFixture(DomainApplicationFixture): application.investigator = random.choice(users) application.approve(send_email=False) - application.save() \ No newline at end of file + application.save() diff --git a/src/registrar/fixtures_users.py b/src/registrar/fixtures_users.py index 830adb5bf..e89809484 100644 --- a/src/registrar/fixtures_users.py +++ b/src/registrar/fixtures_users.py @@ -190,8 +190,8 @@ class UserFixture: # Lumped under .atomic to ensure we don't make redundant DB calls. # This bundles them all together, and then saves it in a single call. # This is slightly different then bulk_create or bulk_update, in that - # you still get the same behaviour of .save(), but those incremental - # steps now do not need to close/reopen a db connection, + # you still get the same behaviour of .save(), but those incremental + # steps now do not need to close/reopen a db connection, # instead they share one. with transaction.atomic(): cls.load_users(cls, cls.ADMINS, "full_access_group") diff --git a/src/registrar/tests/common.py b/src/registrar/tests/common.py index f7bca00be..a195ccb63 100644 --- a/src/registrar/tests/common.py +++ b/src/registrar/tests/common.py @@ -562,11 +562,11 @@ def completed_application( ) if not investigator: investigator, _ = User.objects.get_or_create( - username="incrediblyfakeinvestigator", - first_name = "Joe", - last_name = "Bob" - is_staff=True - ) + username="incrediblyfakeinvestigator", + first_name="Joe", + last_name="Bob", + is_staff=True, + ) domain_application_kwargs = dict( organization_type="federal", federal_type="executive", diff --git a/src/registrar/utility/errors.py b/src/registrar/utility/errors.py index a4359b0c7..fba3410f6 100644 --- a/src/registrar/utility/errors.py +++ b/src/registrar/utility/errors.py @@ -70,23 +70,25 @@ class GenericError(Exception): def get_error_message(self, code=None): return self._error_mapping.get(code) -# (Q for reviewers) What should this be called? + +# (Q for reviewers) What should this be called? # Not a fan of this name. class FSMErrorCodes(IntEnum): """Used when doing FSM transitions. Overview of generic error codes: - - 1 APPROVE_DOMAIN_IN_USE The domain is already in use + - 1 APPROVE_DOMAIN_IN_USE The domain is already in use - 2 APPROVE_NO_INVESTIGATOR No investigator is assigned when approving - 3 APPROVE_INVESTIGATOR_NOT_STAFF Investigator is a non-staff user - 4 APPROVE_INVESTIGATOR_NOT_SUBMITTER The form submitter is not the investigator """ + APPROVE_DOMAIN_IN_USE = 1 APPROVE_NO_INVESTIGATOR = 2 APPROVE_INVESTIGATOR_NOT_STAFF = 3 APPROVE_INVESTIGATOR_NOT_SUBMITTER = 4 -# (Q for reviewers) What should this be called? +# (Q for reviewers) What should this be called? # Not a fan of this name. class ApplicationStatusError(Exception): """ @@ -95,18 +97,12 @@ class ApplicationStatusError(Exception): """ _error_mapping = { - FSMErrorCodes.APPROVE_DOMAIN_IN_USE: ( - "Cannot approve. Requested domain is already in use." - ), - FSMErrorCodes.APPROVE_NO_INVESTIGATOR: ( - "Cannot approve. No investigator was assigned." - ), - FSMErrorCodes.APPROVE_INVESTIGATOR_NOT_STAFF: ( - "Cannot approve. Investigator is not a staff user." - ), + FSMErrorCodes.APPROVE_DOMAIN_IN_USE: ("Cannot approve. Requested domain is already in use."), + FSMErrorCodes.APPROVE_NO_INVESTIGATOR: ("Cannot approve. No investigator was assigned."), + FSMErrorCodes.APPROVE_INVESTIGATOR_NOT_STAFF: ("Cannot approve. Investigator is not a staff user."), FSMErrorCodes.APPROVE_INVESTIGATOR_NOT_SUBMITTER: ( "Cannot approve. Only the assigned investigator can approve this application." - ) + ), } def __init__(self, *args, code=None, **kwargs): From 4d4cd8257ce1b4f899683790cdad1e12a9061996 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Mon, 26 Feb 2024 09:05:34 -0700 Subject: [PATCH 013/103] Update fixtures_applications.py --- src/registrar/fixtures_applications.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/registrar/fixtures_applications.py b/src/registrar/fixtures_applications.py index d1ef25211..e1cfc859e 100644 --- a/src/registrar/fixtures_applications.py +++ b/src/registrar/fixtures_applications.py @@ -242,7 +242,7 @@ class DomainFixture(DomainApplicationFixture): if application.investigator is None: # All "users" in fixtures have admin perms per prior config. # No need to check for that. - application.investigator = random.choice(users) + application.investigator = random.choice(users) # nosec application.approve(send_email=False) application.save() From d416ea5138926ca44d2d6cc3b37352ed06198826 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Mon, 26 Feb 2024 10:49:38 -0700 Subject: [PATCH 014/103] Add checks for other fields --- src/registrar/admin.py | 51 +++++++++++++++++---------------- src/registrar/utility/errors.py | 20 ++++++------- 2 files changed, 36 insertions(+), 35 deletions(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index 95036812d..e68943272 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -824,41 +824,42 @@ class DomainApplicationAdminForm(forms.ModelForm): status = cleaned_data.get("status") investigator = cleaned_data.get("investigator") - # TODO - need some way of determining if a change has actually occurred and to enforce this only then - if status == DomainApplication.ApplicationStatus.APPROVED: - # Checks the "investigators" field for validity. - # That field must obey certain conditions when an application is approved. - # Will call "add_error" if any issues are found. - self._check_investigators_on_approval(investigator) + checked_statuses = [ + DomainApplication.ApplicationStatus.APPROVED, + DomainApplication.ApplicationStatus.IN_REVIEW, + DomainApplication.ApplicationStatus.ACTION_NEEDED, + DomainApplication.ApplicationStatus.REJECTED, + DomainApplication.ApplicationStatus.INELIGIBLE + ] + # Checks the "investigators" field for validity. + # That field must obey certain conditions when an application is approved. + # Will call "add_error" if any issues are found. + #if status in checked_statuses: + #self._check_for_valid_investigator(investigator) return cleaned_data - def _check_investigators_on_approval(self, investigator): - """Checks the investigator field when an approval occurs""" + def _check_for_valid_investigator(self, investigator) -> bool: + """ + Checks if the investigator field is not none, and is staff. + Adds form errors on failure. + """ - # Get information about the current user making the request - current_user = self.request.user - is_superuser = current_user.has_perm("registrar.full_access_permission") + is_valid = False - error_message = None # Check if an investigator is assigned. No approval is possible without one. - if investigator is not None: - if not investigator.is_staff: - # Investigators must be staff users. - # This is handled elsewhere, but we should check here as a precaution. - error_message = ApplicationStatusError.get_error_message(FSMErrorCodes.APPROVE_INVESTIGATOR_NOT_STAFF) - elif investigator != current_user and not is_superuser: - # If the submitting user is not the investigator, block this action. - # This is to enforce accountability. Superusers do not have this restriction. - error_message = ApplicationStatusError.get_error_message( - FSMErrorCodes.APPROVE_INVESTIGATOR_NOT_SUBMITTER - ) + error_message = None + if investigator is None: + error_message = ApplicationStatusError.get_error_message(FSMErrorCodes.NO_INVESTIGATOR) + elif not investigator.is_staff: + error_message = ApplicationStatusError.get_error_message(FSMErrorCodes.INVESTIGATOR_NOT_STAFF) else: - error_message = ApplicationStatusError.get_error_message(FSMErrorCodes.APPROVE_NO_INVESTIGATOR) + is_valid = True - # Add the error if error_message is not None: self.add_error("investigator", error_message) + + return is_valid class DomainApplicationAdmin(ListHeaderAdmin): diff --git a/src/registrar/utility/errors.py b/src/registrar/utility/errors.py index fba3410f6..f399299ff 100644 --- a/src/registrar/utility/errors.py +++ b/src/registrar/utility/errors.py @@ -77,15 +77,15 @@ class FSMErrorCodes(IntEnum): """Used when doing FSM transitions. Overview of generic error codes: - 1 APPROVE_DOMAIN_IN_USE The domain is already in use - - 2 APPROVE_NO_INVESTIGATOR No investigator is assigned when approving - - 3 APPROVE_INVESTIGATOR_NOT_STAFF Investigator is a non-staff user - - 4 APPROVE_INVESTIGATOR_NOT_SUBMITTER The form submitter is not the investigator + - 2 NO_INVESTIGATOR No investigator is assigned + - 3 INVESTIGATOR_NOT_STAFF Investigator is a non-staff user + - 4 INVESTIGATOR_NOT_SUBMITTER The form submitter is not the investigator """ APPROVE_DOMAIN_IN_USE = 1 - APPROVE_NO_INVESTIGATOR = 2 - APPROVE_INVESTIGATOR_NOT_STAFF = 3 - APPROVE_INVESTIGATOR_NOT_SUBMITTER = 4 + NO_INVESTIGATOR = 2 + INVESTIGATOR_NOT_STAFF = 3 + INVESTIGATOR_NOT_SUBMITTER = 4 # (Q for reviewers) What should this be called? @@ -98,10 +98,10 @@ class ApplicationStatusError(Exception): _error_mapping = { FSMErrorCodes.APPROVE_DOMAIN_IN_USE: ("Cannot approve. Requested domain is already in use."), - FSMErrorCodes.APPROVE_NO_INVESTIGATOR: ("Cannot approve. No investigator was assigned."), - FSMErrorCodes.APPROVE_INVESTIGATOR_NOT_STAFF: ("Cannot approve. Investigator is not a staff user."), - FSMErrorCodes.APPROVE_INVESTIGATOR_NOT_SUBMITTER: ( - "Cannot approve. Only the assigned investigator can approve this application." + FSMErrorCodes.NO_INVESTIGATOR: ("No investigator was assigned."), + FSMErrorCodes.INVESTIGATOR_NOT_STAFF: ("Investigator is not a staff user."), + FSMErrorCodes.INVESTIGATOR_NOT_SUBMITTER: ( + "Only the assigned investigator can make this change." ), } From 6542d03bc5a8ec8e3b53c51a72a5de5fab2ed0a0 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Mon, 26 Feb 2024 10:50:38 -0700 Subject: [PATCH 015/103] Use FSM instead --- src/registrar/assets/js/get-gov-admin.js | 35 ++++++++++++++++++++++ src/registrar/models/domain_application.py | 26 ++++++++-------- 2 files changed, 48 insertions(+), 13 deletions(-) diff --git a/src/registrar/assets/js/get-gov-admin.js b/src/registrar/assets/js/get-gov-admin.js index 29aa9ce03..687346b37 100644 --- a/src/registrar/assets/js/get-gov-admin.js +++ b/src/registrar/assets/js/get-gov-admin.js @@ -49,6 +49,41 @@ function openInNewTab(el, removeAttribute = false){ } createPhantomModalFormButtons(); + + document.addEventListener("DOMContentLoaded", function() { + const statusSelect = document.getElementById('id_status'); + const investigatorSelect = document.getElementById('id_investigator'); // Adjust the ID based on your actual field name + + function checkInvestigatorAndShowMessage() { + // Assuming the first option is the default "---------" or similar + const investigatorSelected = investigatorSelect.selectedIndex > 0; + + // Remove existing messages to prevent duplicates + const existingMessage = document.querySelector('.no-investigator-exists'); + if (existingMessage) { + existingMessage.remove(); + } + + const flexContainerParent = statusSelect.closest('.flex-container'); + if (!investigatorSelected && flexContainerParent) { + const message = document.createElement("div"); + message.classList.add("no-investigator-exists"); + message.classList.add("padding-top-1") + message.classList.add("font-1") + message.textContent = '* An investigator must be added before other options will display.'; + + // Insert the message before the flex-container parent + flexContainerParent.insertAdjacentElement('afterend', message); + } + + } + + // Initial check in case the form is loaded with a selection already + checkInvestigatorAndShowMessage(); + + // Add event listener to re-check whenever the investigator selection changes + investigatorSelect.addEventListener('change', checkInvestigatorAndShowMessage); + }); })(); /** An IIFE for pages in DjangoAdmin which may need custom JS implementation. * Currently only appends target="_blank" to the domain_form object, diff --git a/src/registrar/models/domain_application.py b/src/registrar/models/domain_application.py index 19f82101e..84a06fa39 100644 --- a/src/registrar/models/domain_application.py +++ b/src/registrar/models/domain_application.py @@ -619,6 +619,14 @@ class DomainApplication(TimeStampedModel): except EmailSendingError: logger.warning("Failed to send confirmation email", exc_info=True) + def investigator_exists_and_is_staff(self): + """Checks if the current investigator is in a valid state for a state transition""" + is_valid = True + # Check if an investigator is assigned. No approval is possible without one. + if self.investigator is None or not self.investigator.is_staff: + is_valid = False + return is_valid + @transition( field="status", source=[ @@ -669,7 +677,7 @@ class DomainApplication(TimeStampedModel): ApplicationStatus.INELIGIBLE, ], target=ApplicationStatus.IN_REVIEW, - conditions=[domain_is_not_active], + conditions=[domain_is_not_active, investigator_exists_and_is_staff], ) def in_review(self): """Investigate an application that has been submitted. @@ -696,7 +704,7 @@ class DomainApplication(TimeStampedModel): ApplicationStatus.INELIGIBLE, ], target=ApplicationStatus.ACTION_NEEDED, - conditions=[domain_is_not_active], + conditions=[domain_is_not_active, investigator_exists_and_is_staff], ) def action_needed(self): """Send back an application that is under investigation or rejected. @@ -723,6 +731,7 @@ class DomainApplication(TimeStampedModel): ApplicationStatus.REJECTED, ], target=ApplicationStatus.APPROVED, + conditions=[investigator_exists_and_is_staff] ) def approve(self, send_email=True): """Approve an application that has been submitted. @@ -739,15 +748,6 @@ class DomainApplication(TimeStampedModel): if Domain.objects.filter(name=self.requested_domain.name).exists(): raise ApplicationStatusError(code=FSMErrorCodes.APPROVE_DOMAIN_IN_USE) - # Check if an investigator is assigned. No approval is possible without one. - if self.investigator is None: - raise ApplicationStatusError(code=FSMErrorCodes.APPROVE_NO_INVESTIGATOR) - - # Investigators must be staff users. - # This is handled elsewhere, but we should check here as a precaution. - if not self.investigator.is_staff: - raise ApplicationStatusError(code=FSMErrorCodes.APPROVE_INVESTIGATOR_NOT_STAFF) - # == Create the domain and related components == # created_domain = Domain.objects.create(name=self.requested_domain.name) self.approved_domain = created_domain @@ -788,7 +788,7 @@ class DomainApplication(TimeStampedModel): field="status", source=[ApplicationStatus.IN_REVIEW, ApplicationStatus.ACTION_NEEDED, ApplicationStatus.APPROVED], target=ApplicationStatus.REJECTED, - conditions=[domain_is_not_active], + conditions=[domain_is_not_active, investigator_exists_and_is_staff], ) def reject(self): """Reject an application that has been submitted. @@ -814,7 +814,7 @@ class DomainApplication(TimeStampedModel): ApplicationStatus.REJECTED, ], target=ApplicationStatus.INELIGIBLE, - conditions=[domain_is_not_active], + conditions=[domain_is_not_active, investigator_exists_and_is_staff], ) def reject_with_prejudice(self): """The applicant is a bad actor, reject with prejudice. From 79d3c1821d838094fd900d483a015ae965109654 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Mon, 26 Feb 2024 11:23:40 -0700 Subject: [PATCH 016/103] Cleanup --- src/registrar/admin.py | 17 ++++++++++++----- src/registrar/models/domain_application.py | 9 --------- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index e68943272..ec6b625fb 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -824,6 +824,10 @@ class DomainApplicationAdminForm(forms.ModelForm): status = cleaned_data.get("status") investigator = cleaned_data.get("investigator") + # Get the old status + initial_status = self.initial.get("status", None) + + # We only care about investigator when in these statuses checked_statuses = [ DomainApplication.ApplicationStatus.APPROVED, DomainApplication.ApplicationStatus.IN_REVIEW, @@ -831,11 +835,13 @@ class DomainApplicationAdminForm(forms.ModelForm): DomainApplication.ApplicationStatus.REJECTED, DomainApplication.ApplicationStatus.INELIGIBLE ] - # Checks the "investigators" field for validity. - # That field must obey certain conditions when an application is approved. - # Will call "add_error" if any issues are found. - #if status in checked_statuses: - #self._check_for_valid_investigator(investigator) + + # If a status change occured, check for validity + if status != initial_status and status in checked_statuses: + # Checks the "investigators" field for validity. + # That field must obey certain conditions when an application is approved. + # Will call "add_error" if any issues are found. + self._check_for_valid_investigator(investigator) return cleaned_data @@ -850,6 +856,7 @@ class DomainApplicationAdminForm(forms.ModelForm): # Check if an investigator is assigned. No approval is possible without one. error_message = None if investigator is None: + # Lets grab the error message from a common location error_message = ApplicationStatusError.get_error_message(FSMErrorCodes.NO_INVESTIGATOR) elif not investigator.is_staff: error_message = ApplicationStatusError.get_error_message(FSMErrorCodes.INVESTIGATOR_NOT_STAFF) diff --git a/src/registrar/models/domain_application.py b/src/registrar/models/domain_application.py index 19f82101e..3337c8c7a 100644 --- a/src/registrar/models/domain_application.py +++ b/src/registrar/models/domain_application.py @@ -739,15 +739,6 @@ class DomainApplication(TimeStampedModel): if Domain.objects.filter(name=self.requested_domain.name).exists(): raise ApplicationStatusError(code=FSMErrorCodes.APPROVE_DOMAIN_IN_USE) - # Check if an investigator is assigned. No approval is possible without one. - if self.investigator is None: - raise ApplicationStatusError(code=FSMErrorCodes.APPROVE_NO_INVESTIGATOR) - - # Investigators must be staff users. - # This is handled elsewhere, but we should check here as a precaution. - if not self.investigator.is_staff: - raise ApplicationStatusError(code=FSMErrorCodes.APPROVE_INVESTIGATOR_NOT_STAFF) - # == Create the domain and related components == # created_domain = Domain.objects.create(name=self.requested_domain.name) self.approved_domain = created_domain From 3a9683cf490e12d3da019e178b7c9c91a9f71ab6 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Mon, 26 Feb 2024 13:02:12 -0700 Subject: [PATCH 017/103] Add custom field transitions Kudos to rachid --- src/registrar/admin.py | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index e68943272..c5e177bf4 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -803,9 +803,14 @@ class DomainApplicationAdminForm(forms.ModelForm): # first option in status transitions is current state available_transitions = [(current_state, application.get_status_display())] - transitions = get_available_FIELD_transitions( - application, models.DomainApplication._meta.get_field("status") - ) + if application.investigator is not None: + transitions = get_available_FIELD_transitions( + application, models.DomainApplication._meta.get_field("status") + ) + else: + transitions = self.get_custom_field_transitions( + application, models.DomainApplication._meta.get_field("status") + ) for transition in transitions: available_transitions.append((transition.target, transition.target.label)) @@ -816,6 +821,17 @@ class DomainApplicationAdminForm(forms.ModelForm): if not application.creator.is_restricted(): self.fields["status"].widget.choices = available_transitions + def get_custom_field_transitions(self, instance, field): + """Custom implementation of get_available_FIELD_transitions + in the FSM. Allows us to still display fields filtered out by a condition.""" + curr_state = field.get_state(instance) + transitions = field.transitions[instance.__class__] + + for name, transition in transitions.items(): + meta = transition._django_fsm + if meta.has_transition(curr_state): + yield meta.get_transition(curr_state) + def clean(self): # clean is called from clean_forms, which is called from is_valid # after clean_fields. it is used to determine form level errors. From 66ba6919190c7593d56120b2a62da0d0e08c022b Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Mon, 26 Feb 2024 13:03:36 -0700 Subject: [PATCH 018/103] Revert admin change --- src/registrar/assets/js/get-gov-admin.js | 35 ------------------------ 1 file changed, 35 deletions(-) diff --git a/src/registrar/assets/js/get-gov-admin.js b/src/registrar/assets/js/get-gov-admin.js index 687346b37..29aa9ce03 100644 --- a/src/registrar/assets/js/get-gov-admin.js +++ b/src/registrar/assets/js/get-gov-admin.js @@ -49,41 +49,6 @@ function openInNewTab(el, removeAttribute = false){ } createPhantomModalFormButtons(); - - document.addEventListener("DOMContentLoaded", function() { - const statusSelect = document.getElementById('id_status'); - const investigatorSelect = document.getElementById('id_investigator'); // Adjust the ID based on your actual field name - - function checkInvestigatorAndShowMessage() { - // Assuming the first option is the default "---------" or similar - const investigatorSelected = investigatorSelect.selectedIndex > 0; - - // Remove existing messages to prevent duplicates - const existingMessage = document.querySelector('.no-investigator-exists'); - if (existingMessage) { - existingMessage.remove(); - } - - const flexContainerParent = statusSelect.closest('.flex-container'); - if (!investigatorSelected && flexContainerParent) { - const message = document.createElement("div"); - message.classList.add("no-investigator-exists"); - message.classList.add("padding-top-1") - message.classList.add("font-1") - message.textContent = '* An investigator must be added before other options will display.'; - - // Insert the message before the flex-container parent - flexContainerParent.insertAdjacentElement('afterend', message); - } - - } - - // Initial check in case the form is loaded with a selection already - checkInvestigatorAndShowMessage(); - - // Add event listener to re-check whenever the investigator selection changes - investigatorSelect.addEventListener('change', checkInvestigatorAndShowMessage); - }); })(); /** An IIFE for pages in DjangoAdmin which may need custom JS implementation. * Currently only appends target="_blank" to the domain_form object, From 932f32b3dcb7979cc3392fb1781bff85199b5abc Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Mon, 26 Feb 2024 14:09:08 -0700 Subject: [PATCH 019/103] Add some test cases Still need to add a few more --- src/registrar/tests/test_models.py | 166 +++++++++++++++++++++++++++++ 1 file changed, 166 insertions(+) diff --git a/src/registrar/tests/test_models.py b/src/registrar/tests/test_models.py index 433ad98ab..a4eac03e4 100644 --- a/src/registrar/tests/test_models.py +++ b/src/registrar/tests/test_models.py @@ -227,6 +227,33 @@ class TestDomainApplication(TestCase): application = completed_application(status=DomainApplication.ApplicationStatus.APPROVED) self.check_email_sent(application, msg, "reject_with_prejudice", 0) + def test_submit_transition_allowed_with_no_investigator(self): + """ + Tests for attempting to transition without an investigator. + For submit, this should be valid in all cases. + """ + + test_cases = [ + (self.in_review_application, TransitionNotAllowed), + (self.action_needed_application, TransitionNotAllowed), + ] + + # Set all investigators to none + self.in_review_application.investigator = None + self.action_needed_application.investigator = None + + # Save changes + self.in_review_application.save() + self.action_needed_application.save() + + with boto3_mocking.clients.handler_for("sesv2", self.mock_client), less_console_noise(): + for application, exception_type in test_cases: + with self.subTest(application=application, exception_type=exception_type): + try: + application.submit() + except TransitionNotAllowed: + self.fail("TransitionNotAllowed was raised, but it was not expected.") + def test_submit_transition_allowed(self): """ Test that calling submit from allowable statuses does raises TransitionNotAllowed. @@ -247,6 +274,27 @@ class TestDomainApplication(TestCase): except TransitionNotAllowed: self.fail("TransitionNotAllowed was raised, but it was not expected.") + + def test_submit_transition_allowed_twice(self): + """ + Test that rotating between submit and in_review doesn't throw an error + """ + with boto3_mocking.clients.handler_for("sesv2", self.mock_client): + with less_console_noise(): + try: + # Make a submission + self.in_review_application.submit() + + # Rerun the old method to get back to the original state + self.in_review_application.in_review() + + # Make another submission + self.in_review_application.submit() + except TransitionNotAllowed: + self.fail("TransitionNotAllowed was raised, but it was not expected.") + + self.assertEqual(self.in_review_application.status, DomainApplication.ApplicationStatus.SUBMITTED) + def test_submit_transition_not_allowed(self): """ Test that calling submit against transition rules raises TransitionNotAllowed. @@ -286,6 +334,36 @@ class TestDomainApplication(TestCase): except TransitionNotAllowed: self.fail("TransitionNotAllowed was raised, but it was not expected.") + def test_in_review_transition_not_allowed_with_no_investigator(self): + """ + Tests for attempting to transition without an investigator + """ + + test_cases = [ + (self.action_needed_application, TransitionNotAllowed), + (self.approved_application, TransitionNotAllowed), + (self.rejected_application, TransitionNotAllowed), + (self.ineligible_application, TransitionNotAllowed), + ] + + # Set all investigators to none + self.approved_application.investigator = None + self.action_needed_application.investigator = None + self.rejected_application.investigator = None + self.ineligible_application.investigator = None + + # Save changes + self.approved_application.save() + self.action_needed_application.save() + self.rejected_application.save() + self.ineligible_application.save() + + with boto3_mocking.clients.handler_for("sesv2", self.mock_client), less_console_noise(): + for application, exception_type in test_cases: + with self.subTest(application=application, exception_type=exception_type): + with self.assertRaises(exception_type): + application.in_review() + def test_in_review_transition_not_allowed(self): """ Test that calling in_review against transition rules raises TransitionNotAllowed. @@ -321,6 +399,37 @@ class TestDomainApplication(TestCase): except TransitionNotAllowed: self.fail("TransitionNotAllowed was raised, but it was not expected.") + def test_action_needed_transition_not_allowed_with_no_investigator(self): + """ + Tests for attempting to transition without an investigator + """ + + test_cases = [ + (self.in_review_application, TransitionNotAllowed), + (self.approved_application, TransitionNotAllowed), + (self.rejected_application, TransitionNotAllowed), + (self.ineligible_application, TransitionNotAllowed), + ] + + # Set all investigators to none + self.in_review_application.investigator = None + self.approved_application.investigator = None + self.action_needed_application.investigator = None + self.rejected_application.investigator = None + self.ineligible_application.investigator = None + + # Save changes + self.in_review_application.save() + self.action_needed_application.save() + self.rejected_application.save() + self.ineligible_application.save() + + with boto3_mocking.clients.handler_for("sesv2", self.mock_client), less_console_noise(): + for application, exception_type in test_cases: + with self.subTest(application=application, exception_type=exception_type): + with self.assertRaises(exception_type): + application.action_needed() + def test_action_needed_transition_not_allowed(self): """ Test that calling action_needed against transition rules raises TransitionNotAllowed. @@ -357,6 +466,33 @@ class TestDomainApplication(TestCase): except TransitionNotAllowed: self.fail("TransitionNotAllowed was raised, but it was not expected.") + def test_approved_transition_not_allowed_with_no_investigator(self): + """ + Tests for attempting to transition without an investigator + """ + + test_cases = [ + (self.in_review_application, TransitionNotAllowed), + (self.action_needed_application, TransitionNotAllowed), + (self.rejected_application, TransitionNotAllowed), + ] + + # Set all investigators to none + self.in_review_application.investigator = None + self.action_needed_application.investigator = None + self.rejected_application.investigator = None + + # Save changes + self.in_review_application.save() + self.action_needed_application.save() + self.rejected_application.save() + + with boto3_mocking.clients.handler_for("sesv2", self.mock_client), less_console_noise(): + for application, exception_type in test_cases: + with self.subTest(application=application, exception_type=exception_type): + with self.assertRaises(exception_type): + application.approve() + def test_approved_skips_sending_email(self): """ Test that calling .approve with send_email=False doesn't actually send @@ -407,6 +543,36 @@ class TestDomainApplication(TestCase): except TransitionNotAllowed: self.fail("TransitionNotAllowed was raised, but it was not expected.") + def test_withdraw_transition_allowed_with_no_investigator(self): + """ + Tests for attempting to transition without an investigator. + For withdraw, this should be valid in all cases. + """ + + test_cases = [ + (self.submitted_application, TransitionNotAllowed), + (self.in_review_application, TransitionNotAllowed), + (self.action_needed_application, TransitionNotAllowed), + ] + + # Set all investigators to none + self.submitted_application.investigator = None + self.in_review_application.investigator = None + self.action_needed_application.investigator = None + + # Save changes + self.submitted_application.save() + self.in_review_application.save() + self.action_needed_application.save() + + with boto3_mocking.clients.handler_for("sesv2", self.mock_client), less_console_noise(): + for application, exception_type in test_cases: + with self.subTest(application=application, exception_type=exception_type): + try: + application.withdraw() + except TransitionNotAllowed: + self.fail("TransitionNotAllowed was raised, but it was not expected.") + def test_withdraw_transition_not_allowed(self): """ Test that calling action_needed against transition rules raises TransitionNotAllowed. From d978211c6d7d84fd00ce4bcdde53b698e628cbe2 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Mon, 26 Feb 2024 14:13:02 -0700 Subject: [PATCH 020/103] Update test_models.py --- src/registrar/tests/test_models.py | 57 ++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/src/registrar/tests/test_models.py b/src/registrar/tests/test_models.py index a4eac03e4..4c07abe64 100644 --- a/src/registrar/tests/test_models.py +++ b/src/registrar/tests/test_models.py @@ -611,6 +611,33 @@ class TestDomainApplication(TestCase): except TransitionNotAllowed: self.fail("TransitionNotAllowed was raised, but it was not expected.") + def test_reject_transition_not_allowed_with_no_investigator(self): + """ + Tests for attempting to transition without an investigator + """ + + test_cases = [ + (self.in_review_application, TransitionNotAllowed), + (self.action_needed_application, TransitionNotAllowed), + (self.approved_application, TransitionNotAllowed), + ] + + # Set all investigators to none + self.in_review_application.investigator = None + self.action_needed_application.investigator = None + self.approved_application.investigator = None + + # Save changes + self.in_review_application.save() + self.action_needed_application.save() + self.approved_application.save() + + with boto3_mocking.clients.handler_for("sesv2", self.mock_client), less_console_noise(): + for application, exception_type in test_cases: + with self.subTest(application=application, exception_type=exception_type): + with self.assertRaises(exception_type): + application.reject() + def test_reject_transition_not_allowed(self): """ Test that calling action_needed against transition rules raises TransitionNotAllowed. @@ -650,6 +677,36 @@ class TestDomainApplication(TestCase): except TransitionNotAllowed: self.fail("TransitionNotAllowed was raised, but it was not expected.") + def test_reject_with_prejudice_transition_not_allowed_with_no_investigator(self): + """ + Tests for attempting to transition without an investigator + """ + + test_cases = [ + (self.in_review_application, TransitionNotAllowed), + (self.action_needed_application, TransitionNotAllowed), + (self.approved_application, TransitionNotAllowed), + (self.rejected_application, TransitionNotAllowed), + ] + + # Set all investigators to none + self.in_review_application.investigator = None + self.action_needed_application.investigator = None + self.approved_application.investigator = None + self.rejected_application.investigator = None + + # Save changes + self.in_review_application.save() + self.action_needed_application.save() + self.approved_application.save() + self.rejected_application.save() + + with boto3_mocking.clients.handler_for("sesv2", self.mock_client), less_console_noise(): + for application, exception_type in test_cases: + with self.subTest(application=application, exception_type=exception_type): + with self.assertRaises(exception_type): + application.reject_with_prejudice() + def test_reject_with_prejudice_transition_not_allowed(self): """ Test that calling action_needed against transition rules raises TransitionNotAllowed. From d60ff230208e8fba9df3845b1a66cf87eba1de12 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Mon, 26 Feb 2024 14:47:42 -0700 Subject: [PATCH 021/103] Simplify FSM tests --- src/registrar/tests/common.py | 7 + src/registrar/tests/test_models.py | 261 ++++++++++++++--------------- 2 files changed, 133 insertions(+), 135 deletions(-) diff --git a/src/registrar/tests/common.py b/src/registrar/tests/common.py index a195ccb63..81a8cee6e 100644 --- a/src/registrar/tests/common.py +++ b/src/registrar/tests/common.py @@ -601,6 +601,13 @@ def completed_application( return application +def set_applications_investigators(application_list: list[DomainApplication], investigator_user: User): + """Helper method that sets the investigator field of all provided applications""" + for application in application_list: + application.investigator = investigator_user + application.save() + + def multiple_unalphabetical_domain_objects( domain_type=AuditedAdminMockData.APPLICATION, ): diff --git a/src/registrar/tests/test_models.py b/src/registrar/tests/test_models.py index 4c07abe64..9d3c7fc27 100644 --- a/src/registrar/tests/test_models.py +++ b/src/registrar/tests/test_models.py @@ -17,7 +17,7 @@ from registrar.models import ( import boto3_mocking from registrar.models.transition_domain import TransitionDomain from registrar.models.verified_by_staff import VerifiedByStaff # type: ignore -from .common import MockSESClient, less_console_noise, completed_application +from .common import MockSESClient, less_console_noise, completed_application, set_applications_investigators from django_fsm import TransitionNotAllowed @@ -27,32 +27,43 @@ from django_fsm import TransitionNotAllowed @boto3_mocking.patching class TestDomainApplication(TestCase): def setUp(self): - user, _ = User.objects.get_or_create(username="testpancakesyrup", is_staff=True) self.started_application = completed_application( - status=DomainApplication.ApplicationStatus.STARTED, name="started.gov", investigator=user + status=DomainApplication.ApplicationStatus.STARTED, name="started.gov" ) self.submitted_application = completed_application( - status=DomainApplication.ApplicationStatus.SUBMITTED, name="submitted.gov", investigator=user + status=DomainApplication.ApplicationStatus.SUBMITTED, name="submitted.gov" ) self.in_review_application = completed_application( - status=DomainApplication.ApplicationStatus.IN_REVIEW, name="in-review.gov", investigator=user + status=DomainApplication.ApplicationStatus.IN_REVIEW, name="in-review.gov" ) self.action_needed_application = completed_application( - status=DomainApplication.ApplicationStatus.ACTION_NEEDED, name="action-needed.gov", investigator=user + status=DomainApplication.ApplicationStatus.ACTION_NEEDED, name="action-needed.gov" ) self.approved_application = completed_application( - status=DomainApplication.ApplicationStatus.APPROVED, name="approved.gov", investigator=user + status=DomainApplication.ApplicationStatus.APPROVED, name="approved.gov" ) self.withdrawn_application = completed_application( - status=DomainApplication.ApplicationStatus.WITHDRAWN, name="withdrawn.gov", investigator=user + status=DomainApplication.ApplicationStatus.WITHDRAWN, name="withdrawn.gov" ) self.rejected_application = completed_application( - status=DomainApplication.ApplicationStatus.REJECTED, name="rejected.gov", investigator=user + status=DomainApplication.ApplicationStatus.REJECTED, name="rejected.gov" ) self.ineligible_application = completed_application( - status=DomainApplication.ApplicationStatus.INELIGIBLE, name="ineligible.gov", investigator=user + status=DomainApplication.ApplicationStatus.INELIGIBLE, name="ineligible.gov" ) - + + # Store all aplpication statuses in a variable for ease of use + self.all_applications = [ + self.started_application, + self.submitted_application, + self.in_review_application, + self.action_needed_application, + self.approved_application, + self.withdrawn_application, + self.rejected_application, + self.ineligible_application, + ] + self.mock_client = MockSESClient() def tearDown(self): @@ -227,6 +238,17 @@ class TestDomainApplication(TestCase): application = completed_application(status=DomainApplication.ApplicationStatus.APPROVED) self.check_email_sent(application, msg, "reject_with_prejudice", 0) + def assert_fsm_transition_raises_error(self, test_cases, method_to_run): + """Given a list of test cases, check if each transition throws the intended error""" + with boto3_mocking.clients.handler_for("sesv2", self.mock_client), less_console_noise(): + for application, exception_type in test_cases: + with self.subTest(application=application, exception_type=exception_type): + with self.assertRaises(exception_type): + # Retrieve the method by name from the application object and call it + method = getattr(application, method_to_run) + # Call the method + method() + def test_submit_transition_allowed_with_no_investigator(self): """ Tests for attempting to transition without an investigator. @@ -239,12 +261,30 @@ class TestDomainApplication(TestCase): ] # Set all investigators to none - self.in_review_application.investigator = None - self.action_needed_application.investigator = None + set_applications_investigators(self.all_applications, None) - # Save changes - self.in_review_application.save() - self.action_needed_application.save() + with boto3_mocking.clients.handler_for("sesv2", self.mock_client), less_console_noise(): + for application, exception_type in test_cases: + with self.subTest(application=application, exception_type=exception_type): + try: + application.submit() + except TransitionNotAllowed: + self.fail("TransitionNotAllowed was raised, but it was not expected.") + + def test_submit_transition_allowed_with_investigator_not_staff(self): + """ + Tests for attempting to transition with an investigator user that is not staff. + For submit, this should be valid in all cases. + """ + + test_cases = [ + (self.in_review_application, TransitionNotAllowed), + (self.action_needed_application, TransitionNotAllowed), + ] + + # Set all investigators to a user with no staff privs + user, _ = User.objects.get_or_create(username="pancakesyrup", is_staff=False) + set_applications_investigators(self.all_applications, user) with boto3_mocking.clients.handler_for("sesv2", self.mock_client), less_console_noise(): for application, exception_type in test_cases: @@ -306,12 +346,7 @@ class TestDomainApplication(TestCase): (self.ineligible_application, TransitionNotAllowed), ] - with boto3_mocking.clients.handler_for("sesv2", self.mock_client): - with less_console_noise(): - for application, exception_type in test_cases: - with self.subTest(application=application, exception_type=exception_type): - with self.assertRaises(exception_type): - application.submit() + self.assert_fsm_transition_raises_error(test_cases, "submit") def test_in_review_transition_allowed(self): """ @@ -347,22 +382,28 @@ class TestDomainApplication(TestCase): ] # Set all investigators to none - self.approved_application.investigator = None - self.action_needed_application.investigator = None - self.rejected_application.investigator = None - self.ineligible_application.investigator = None + set_applications_investigators(self.all_applications, None) - # Save changes - self.approved_application.save() - self.action_needed_application.save() - self.rejected_application.save() - self.ineligible_application.save() + self.assert_fsm_transition_raises_error(test_cases, "in_review") + + def test_in_review_transition_not_allowed_with_investigator_not_staff(self): + """ + Tests for attempting to transition with an investigator that is not staff. + This should throw an exception. + """ - with boto3_mocking.clients.handler_for("sesv2", self.mock_client), less_console_noise(): - for application, exception_type in test_cases: - with self.subTest(application=application, exception_type=exception_type): - with self.assertRaises(exception_type): - application.in_review() + test_cases = [ + (self.action_needed_application, TransitionNotAllowed), + (self.approved_application, TransitionNotAllowed), + (self.rejected_application, TransitionNotAllowed), + (self.ineligible_application, TransitionNotAllowed), + ] + + # Set all investigators to a user with no staff privs + user, _ = User.objects.get_or_create(username="pancakesyrup", is_staff=False) + set_applications_investigators(self.all_applications, user) + + self.assert_fsm_transition_raises_error(test_cases, "in_review") def test_in_review_transition_not_allowed(self): """ @@ -374,12 +415,7 @@ class TestDomainApplication(TestCase): (self.withdrawn_application, TransitionNotAllowed), ] - with boto3_mocking.clients.handler_for("sesv2", self.mock_client): - with less_console_noise(): - for application, exception_type in test_cases: - with self.subTest(application=application, exception_type=exception_type): - with self.assertRaises(exception_type): - application.in_review() + self.assert_fsm_transition_raises_error(test_cases, "in_review") def test_action_needed_transition_allowed(self): """ @@ -412,23 +448,27 @@ class TestDomainApplication(TestCase): ] # Set all investigators to none - self.in_review_application.investigator = None - self.approved_application.investigator = None - self.action_needed_application.investigator = None - self.rejected_application.investigator = None - self.ineligible_application.investigator = None + set_applications_investigators(self.all_applications, None) - # Save changes - self.in_review_application.save() - self.action_needed_application.save() - self.rejected_application.save() - self.ineligible_application.save() + self.assert_fsm_transition_raises_error(test_cases, "action_needed") - with boto3_mocking.clients.handler_for("sesv2", self.mock_client), less_console_noise(): - for application, exception_type in test_cases: - with self.subTest(application=application, exception_type=exception_type): - with self.assertRaises(exception_type): - application.action_needed() + def test_action_needed_transition_not_allowed_with_investigator_not_staff(self): + """ + Tests for attempting to transition with an investigator that is not staff + """ + + test_cases = [ + (self.in_review_application, TransitionNotAllowed), + (self.approved_application, TransitionNotAllowed), + (self.rejected_application, TransitionNotAllowed), + (self.ineligible_application, TransitionNotAllowed), + ] + + # Set all investigators to a user with no staff privs + user, _ = User.objects.get_or_create(username="pancakesyrup", is_staff=False) + set_applications_investigators(self.all_applications, user) + + self.assert_fsm_transition_raises_error(test_cases, "action_needed") def test_action_needed_transition_not_allowed(self): """ @@ -440,11 +480,8 @@ class TestDomainApplication(TestCase): (self.action_needed_application, TransitionNotAllowed), (self.withdrawn_application, TransitionNotAllowed), ] - with less_console_noise(): - for application, exception_type in test_cases: - with self.subTest(application=application, exception_type=exception_type): - with self.assertRaises(exception_type): - application.action_needed() + + self.assert_fsm_transition_raises_error(test_cases, "action_needed") def test_approved_transition_allowed(self): """ @@ -478,20 +515,26 @@ class TestDomainApplication(TestCase): ] # Set all investigators to none - self.in_review_application.investigator = None - self.action_needed_application.investigator = None - self.rejected_application.investigator = None + set_applications_investigators(self.all_applications, None) - # Save changes - self.in_review_application.save() - self.action_needed_application.save() - self.rejected_application.save() + self.assert_fsm_transition_raises_error(test_cases, "approve") - with boto3_mocking.clients.handler_for("sesv2", self.mock_client), less_console_noise(): - for application, exception_type in test_cases: - with self.subTest(application=application, exception_type=exception_type): - with self.assertRaises(exception_type): - application.approve() + def test_approved_transition_not_allowed_with_investigator_not_staff(self): + """ + Tests for attempting to transition with an investigator that is not staff + """ + + test_cases = [ + (self.in_review_application, TransitionNotAllowed), + (self.action_needed_application, TransitionNotAllowed), + (self.rejected_application, TransitionNotAllowed), + ] + + # Set all investigators to a user with no staff privs + user, _ = User.objects.get_or_create(username="pancakesyrup", is_staff=False) + set_applications_investigators(self.all_applications, user) + + self.assert_fsm_transition_raises_error(test_cases, "approve") def test_approved_skips_sending_email(self): """ @@ -516,13 +559,7 @@ class TestDomainApplication(TestCase): (self.withdrawn_application, TransitionNotAllowed), (self.ineligible_application, TransitionNotAllowed), ] - - with boto3_mocking.clients.handler_for("sesv2", self.mock_client): - with less_console_noise(): - for application, exception_type in test_cases: - with self.subTest(application=application, exception_type=exception_type): - with self.assertRaises(exception_type): - application.approve() + self.assert_fsm_transition_raises_error(test_cases, "approve") def test_withdraw_transition_allowed(self): """ @@ -556,14 +593,7 @@ class TestDomainApplication(TestCase): ] # Set all investigators to none - self.submitted_application.investigator = None - self.in_review_application.investigator = None - self.action_needed_application.investigator = None - - # Save changes - self.submitted_application.save() - self.in_review_application.save() - self.action_needed_application.save() + set_applications_investigators(self.all_applications, None) with boto3_mocking.clients.handler_for("sesv2", self.mock_client), less_console_noise(): for application, exception_type in test_cases: @@ -585,12 +615,7 @@ class TestDomainApplication(TestCase): (self.ineligible_application, TransitionNotAllowed), ] - with boto3_mocking.clients.handler_for("sesv2", self.mock_client): - with less_console_noise(): - for application, exception_type in test_cases: - with self.subTest(application=application, exception_type=exception_type): - with self.assertRaises(exception_type): - application.withdraw() + self.assert_fsm_transition_raises_error(test_cases, "withdraw") def test_reject_transition_allowed(self): """ @@ -623,20 +648,9 @@ class TestDomainApplication(TestCase): ] # Set all investigators to none - self.in_review_application.investigator = None - self.action_needed_application.investigator = None - self.approved_application.investigator = None + set_applications_investigators(self.all_applications, None) - # Save changes - self.in_review_application.save() - self.action_needed_application.save() - self.approved_application.save() - - with boto3_mocking.clients.handler_for("sesv2", self.mock_client), less_console_noise(): - for application, exception_type in test_cases: - with self.subTest(application=application, exception_type=exception_type): - with self.assertRaises(exception_type): - application.reject() + self.assert_fsm_transition_raises_error(test_cases, "reject") def test_reject_transition_not_allowed(self): """ @@ -650,12 +664,7 @@ class TestDomainApplication(TestCase): (self.ineligible_application, TransitionNotAllowed), ] - with boto3_mocking.clients.handler_for("sesv2", self.mock_client): - with less_console_noise(): - for application, exception_type in test_cases: - with self.subTest(application=application, exception_type=exception_type): - with self.assertRaises(exception_type): - application.reject() + self.assert_fsm_transition_raises_error(test_cases, "reject") def test_reject_with_prejudice_transition_allowed(self): """ @@ -690,22 +699,9 @@ class TestDomainApplication(TestCase): ] # Set all investigators to none - self.in_review_application.investigator = None - self.action_needed_application.investigator = None - self.approved_application.investigator = None - self.rejected_application.investigator = None + set_applications_investigators(self.all_applications, None) - # Save changes - self.in_review_application.save() - self.action_needed_application.save() - self.approved_application.save() - self.rejected_application.save() - - with boto3_mocking.clients.handler_for("sesv2", self.mock_client), less_console_noise(): - for application, exception_type in test_cases: - with self.subTest(application=application, exception_type=exception_type): - with self.assertRaises(exception_type): - application.reject_with_prejudice() + self.assert_fsm_transition_raises_error(test_cases, "reject_with_prejudice") def test_reject_with_prejudice_transition_not_allowed(self): """ @@ -718,12 +714,7 @@ class TestDomainApplication(TestCase): (self.ineligible_application, TransitionNotAllowed), ] - with boto3_mocking.clients.handler_for("sesv2", self.mock_client): - with less_console_noise(): - for application, exception_type in test_cases: - with self.subTest(application=application, exception_type=exception_type): - with self.assertRaises(exception_type): - application.reject_with_prejudice() + self.assert_fsm_transition_raises_error(test_cases, "reject_with_prejudice") def test_transition_not_allowed_approved_in_review_when_domain_is_active(self): """Create an application with status approved, create a matching domain that From 3b4e470f0c197557664210f86600e46bb227c39f Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Mon, 26 Feb 2024 14:52:35 -0700 Subject: [PATCH 022/103] Even more unit testing Almost done with it! --- src/registrar/tests/test_models.py | 60 +++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/src/registrar/tests/test_models.py b/src/registrar/tests/test_models.py index 9d3c7fc27..bcd68d539 100644 --- a/src/registrar/tests/test_models.py +++ b/src/registrar/tests/test_models.py @@ -314,7 +314,6 @@ class TestDomainApplication(TestCase): except TransitionNotAllowed: self.fail("TransitionNotAllowed was raised, but it was not expected.") - def test_submit_transition_allowed_twice(self): """ Test that rotating between submit and in_review doesn't throw an error @@ -603,6 +602,30 @@ class TestDomainApplication(TestCase): except TransitionNotAllowed: self.fail("TransitionNotAllowed was raised, but it was not expected.") + def test_withdraw_transition_allowed_with_investigator_not_staff(self): + """ + Tests for attempting to transition when investigator is not staff. + For withdraw, this should be valid in all cases. + """ + + test_cases = [ + (self.submitted_application, TransitionNotAllowed), + (self.in_review_application, TransitionNotAllowed), + (self.action_needed_application, TransitionNotAllowed), + ] + + # Set all investigators to a user with no staff privs + user, _ = User.objects.get_or_create(username="pancakesyrup", is_staff=False) + set_applications_investigators(self.all_applications, user) + + with boto3_mocking.clients.handler_for("sesv2", self.mock_client), less_console_noise(): + for application, exception_type in test_cases: + with self.subTest(application=application, exception_type=exception_type): + try: + application.withdraw() + except TransitionNotAllowed: + self.fail("TransitionNotAllowed was raised, but it was not expected.") + def test_withdraw_transition_not_allowed(self): """ Test that calling action_needed against transition rules raises TransitionNotAllowed. @@ -652,6 +675,23 @@ class TestDomainApplication(TestCase): self.assert_fsm_transition_raises_error(test_cases, "reject") + def test_reject_transition_not_allowed_with_investigator_not_staff(self): + """ + Tests for attempting to transition when investigator is not staff + """ + + test_cases = [ + (self.in_review_application, TransitionNotAllowed), + (self.action_needed_application, TransitionNotAllowed), + (self.approved_application, TransitionNotAllowed), + ] + + # Set all investigators to a user with no staff privs + user, _ = User.objects.get_or_create(username="pancakesyrup", is_staff=False) + set_applications_investigators(self.all_applications, user) + + self.assert_fsm_transition_raises_error(test_cases, "reject") + def test_reject_transition_not_allowed(self): """ Test that calling action_needed against transition rules raises TransitionNotAllowed. @@ -703,6 +743,24 @@ class TestDomainApplication(TestCase): self.assert_fsm_transition_raises_error(test_cases, "reject_with_prejudice") + def test_reject_with_prejudice_not_allowed_with_investigator_not_staff(self): + """ + Tests for attempting to transition when investigator is not staff + """ + + test_cases = [ + (self.in_review_application, TransitionNotAllowed), + (self.action_needed_application, TransitionNotAllowed), + (self.approved_application, TransitionNotAllowed), + (self.rejected_application, TransitionNotAllowed), + ] + + # Set all investigators to a user with no staff privs + user, _ = User.objects.get_or_create(username="pancakesyrup", is_staff=False) + set_applications_investigators(self.all_applications, user) + + self.assert_fsm_transition_raises_error(test_cases, "reject_with_prejudice") + def test_reject_with_prejudice_transition_not_allowed(self): """ Test that calling action_needed against transition rules raises TransitionNotAllowed. From 3d6f63846270a40c1362fda1b5f4dbf92a517247 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Mon, 26 Feb 2024 15:02:54 -0700 Subject: [PATCH 023/103] Simplify test cases further, linting --- src/registrar/admin.py | 6 +- src/registrar/models/domain_application.py | 2 +- src/registrar/tests/test_models.py | 116 ++++++--------------- 3 files changed, 33 insertions(+), 91 deletions(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index 847e8595c..176c0bb87 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -849,7 +849,7 @@ class DomainApplicationAdminForm(forms.ModelForm): DomainApplication.ApplicationStatus.IN_REVIEW, DomainApplication.ApplicationStatus.ACTION_NEEDED, DomainApplication.ApplicationStatus.REJECTED, - DomainApplication.ApplicationStatus.INELIGIBLE + DomainApplication.ApplicationStatus.INELIGIBLE, ] # If a status change occured, check for validity @@ -864,7 +864,7 @@ class DomainApplicationAdminForm(forms.ModelForm): def _check_for_valid_investigator(self, investigator) -> bool: """ Checks if the investigator field is not none, and is staff. - Adds form errors on failure. + Adds form errors on failure. """ is_valid = False @@ -881,7 +881,7 @@ class DomainApplicationAdminForm(forms.ModelForm): if error_message is not None: self.add_error("investigator", error_message) - + return is_valid diff --git a/src/registrar/models/domain_application.py b/src/registrar/models/domain_application.py index 84a06fa39..51f832ec2 100644 --- a/src/registrar/models/domain_application.py +++ b/src/registrar/models/domain_application.py @@ -731,7 +731,7 @@ class DomainApplication(TimeStampedModel): ApplicationStatus.REJECTED, ], target=ApplicationStatus.APPROVED, - conditions=[investigator_exists_and_is_staff] + conditions=[investigator_exists_and_is_staff], ) def approve(self, send_email=True): """Approve an application that has been submitted. diff --git a/src/registrar/tests/test_models.py b/src/registrar/tests/test_models.py index bcd68d539..8e9b9dc4e 100644 --- a/src/registrar/tests/test_models.py +++ b/src/registrar/tests/test_models.py @@ -51,7 +51,7 @@ class TestDomainApplication(TestCase): self.ineligible_application = completed_application( status=DomainApplication.ApplicationStatus.INELIGIBLE, name="ineligible.gov" ) - + # Store all aplpication statuses in a variable for ease of use self.all_applications = [ self.started_application, @@ -63,7 +63,7 @@ class TestDomainApplication(TestCase): self.rejected_application, self.ineligible_application, ] - + self.mock_client = MockSESClient() def tearDown(self): @@ -249,6 +249,19 @@ class TestDomainApplication(TestCase): # Call the method method() + def assert_fsm_transition_does_not_raise_error(self, test_cases, method_to_run): + """Given a list of test cases, ensure that none of them throw transition errors""" + with boto3_mocking.clients.handler_for("sesv2", self.mock_client), less_console_noise(): + for application, exception_type in test_cases: + with self.subTest(application=application, exception_type=exception_type): + try: + # Retrieve the method by name from the application object and call it + method = getattr(application, method_to_run) + # Call the method + method() + except exception_type: + self.fail(f"{exception_type} was raised, but it was not expected.") + def test_submit_transition_allowed_with_no_investigator(self): """ Tests for attempting to transition without an investigator. @@ -263,13 +276,7 @@ class TestDomainApplication(TestCase): # Set all investigators to none set_applications_investigators(self.all_applications, None) - with boto3_mocking.clients.handler_for("sesv2", self.mock_client), less_console_noise(): - for application, exception_type in test_cases: - with self.subTest(application=application, exception_type=exception_type): - try: - application.submit() - except TransitionNotAllowed: - self.fail("TransitionNotAllowed was raised, but it was not expected.") + self.assert_fsm_transition_does_not_raise_error(test_cases, "submit") def test_submit_transition_allowed_with_investigator_not_staff(self): """ @@ -286,13 +293,7 @@ class TestDomainApplication(TestCase): user, _ = User.objects.get_or_create(username="pancakesyrup", is_staff=False) set_applications_investigators(self.all_applications, user) - with boto3_mocking.clients.handler_for("sesv2", self.mock_client), less_console_noise(): - for application, exception_type in test_cases: - with self.subTest(application=application, exception_type=exception_type): - try: - application.submit() - except TransitionNotAllowed: - self.fail("TransitionNotAllowed was raised, but it was not expected.") + self.assert_fsm_transition_does_not_raise_error(test_cases, "submit") def test_submit_transition_allowed(self): """ @@ -305,14 +306,7 @@ class TestDomainApplication(TestCase): (self.withdrawn_application, TransitionNotAllowed), ] - with boto3_mocking.clients.handler_for("sesv2", self.mock_client): - with less_console_noise(): - for application, exception_type in test_cases: - with self.subTest(application=application, exception_type=exception_type): - try: - application.submit() - except TransitionNotAllowed: - self.fail("TransitionNotAllowed was raised, but it was not expected.") + self.assert_fsm_transition_does_not_raise_error(test_cases, "submit") def test_submit_transition_allowed_twice(self): """ @@ -331,7 +325,7 @@ class TestDomainApplication(TestCase): self.in_review_application.submit() except TransitionNotAllowed: self.fail("TransitionNotAllowed was raised, but it was not expected.") - + self.assertEqual(self.in_review_application.status, DomainApplication.ApplicationStatus.SUBMITTED) def test_submit_transition_not_allowed(self): @@ -359,14 +353,7 @@ class TestDomainApplication(TestCase): (self.ineligible_application, TransitionNotAllowed), ] - with boto3_mocking.clients.handler_for("sesv2", self.mock_client): - with less_console_noise(): - for application, exception_type in test_cases: - with self.subTest(application=application, exception_type=exception_type): - try: - application.in_review() - except TransitionNotAllowed: - self.fail("TransitionNotAllowed was raised, but it was not expected.") + self.assert_fsm_transition_does_not_raise_error(test_cases, "in_review") def test_in_review_transition_not_allowed_with_no_investigator(self): """ @@ -384,7 +371,7 @@ class TestDomainApplication(TestCase): set_applications_investigators(self.all_applications, None) self.assert_fsm_transition_raises_error(test_cases, "in_review") - + def test_in_review_transition_not_allowed_with_investigator_not_staff(self): """ Tests for attempting to transition with an investigator that is not staff. @@ -426,13 +413,8 @@ class TestDomainApplication(TestCase): (self.rejected_application, TransitionNotAllowed), (self.ineligible_application, TransitionNotAllowed), ] - with less_console_noise(): - for application, exception_type in test_cases: - with self.subTest(application=application, exception_type=exception_type): - try: - application.action_needed() - except TransitionNotAllowed: - self.fail("TransitionNotAllowed was raised, but it was not expected.") + + self.assert_fsm_transition_does_not_raise_error(test_cases, "action_needed") def test_action_needed_transition_not_allowed_with_no_investigator(self): """ @@ -493,14 +475,7 @@ class TestDomainApplication(TestCase): (self.rejected_application, TransitionNotAllowed), ] - with boto3_mocking.clients.handler_for("sesv2", self.mock_client): - with less_console_noise(): - for application, exception_type in test_cases: - with self.subTest(application=application, exception_type=exception_type): - try: - application.approve() - except TransitionNotAllowed: - self.fail("TransitionNotAllowed was raised, but it was not expected.") + self.assert_fsm_transition_does_not_raise_error(test_cases, "approve") def test_approved_transition_not_allowed_with_no_investigator(self): """ @@ -570,14 +545,7 @@ class TestDomainApplication(TestCase): (self.action_needed_application, TransitionNotAllowed), ] - with boto3_mocking.clients.handler_for("sesv2", self.mock_client): - with less_console_noise(): - for application, exception_type in test_cases: - with self.subTest(application=application, exception_type=exception_type): - try: - application.withdraw() - except TransitionNotAllowed: - self.fail("TransitionNotAllowed was raised, but it was not expected.") + self.assert_fsm_transition_does_not_raise_error(test_cases, "withdraw") def test_withdraw_transition_allowed_with_no_investigator(self): """ @@ -594,13 +562,7 @@ class TestDomainApplication(TestCase): # Set all investigators to none set_applications_investigators(self.all_applications, None) - with boto3_mocking.clients.handler_for("sesv2", self.mock_client), less_console_noise(): - for application, exception_type in test_cases: - with self.subTest(application=application, exception_type=exception_type): - try: - application.withdraw() - except TransitionNotAllowed: - self.fail("TransitionNotAllowed was raised, but it was not expected.") + self.assert_fsm_transition_does_not_raise_error(test_cases, "withdraw") def test_withdraw_transition_allowed_with_investigator_not_staff(self): """ @@ -618,13 +580,7 @@ class TestDomainApplication(TestCase): user, _ = User.objects.get_or_create(username="pancakesyrup", is_staff=False) set_applications_investigators(self.all_applications, user) - with boto3_mocking.clients.handler_for("sesv2", self.mock_client), less_console_noise(): - for application, exception_type in test_cases: - with self.subTest(application=application, exception_type=exception_type): - try: - application.withdraw() - except TransitionNotAllowed: - self.fail("TransitionNotAllowed was raised, but it was not expected.") + self.assert_fsm_transition_does_not_raise_error(test_cases, "withdraw") def test_withdraw_transition_not_allowed(self): """ @@ -650,14 +606,7 @@ class TestDomainApplication(TestCase): (self.approved_application, TransitionNotAllowed), ] - with boto3_mocking.clients.handler_for("sesv2", self.mock_client): - with less_console_noise(): - for application, exception_type in test_cases: - with self.subTest(application=application, exception_type=exception_type): - try: - application.reject() - except TransitionNotAllowed: - self.fail("TransitionNotAllowed was raised, but it was not expected.") + self.assert_fsm_transition_does_not_raise_error(test_cases, "reject") def test_reject_transition_not_allowed_with_no_investigator(self): """ @@ -717,14 +666,7 @@ class TestDomainApplication(TestCase): (self.rejected_application, TransitionNotAllowed), ] - with boto3_mocking.clients.handler_for("sesv2", self.mock_client): - with less_console_noise(): - for application, exception_type in test_cases: - with self.subTest(application=application, exception_type=exception_type): - try: - application.reject_with_prejudice() - except TransitionNotAllowed: - self.fail("TransitionNotAllowed was raised, but it was not expected.") + self.assert_fsm_transition_does_not_raise_error(test_cases, "reject_with_prejudice") def test_reject_with_prejudice_transition_not_allowed_with_no_investigator(self): """ From 92c85dbb16b621fd20010e8ab8c4daee87970f31 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Mon, 26 Feb 2024 15:10:03 -0700 Subject: [PATCH 024/103] Linting --- src/registrar/tests/test_models.py | 11 ++--------- src/registrar/utility/errors.py | 4 +--- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/src/registrar/tests/test_models.py b/src/registrar/tests/test_models.py index 8e9b9dc4e..73d86dfd7 100644 --- a/src/registrar/tests/test_models.py +++ b/src/registrar/tests/test_models.py @@ -52,7 +52,7 @@ class TestDomainApplication(TestCase): status=DomainApplication.ApplicationStatus.INELIGIBLE, name="ineligible.gov" ) - # Store all aplpication statuses in a variable for ease of use + # Store all application statuses in a variable for ease of use self.all_applications = [ self.started_application, self.submitted_application, @@ -181,14 +181,7 @@ class TestDomainApplication(TestCase): with less_console_noise(): # Perform the specified action action_method = getattr(application, action) - if action == "approve" and not application.investigator: - user, _ = User.objects.get_or_create(username="testwafflesyrup", is_staff=True) - application.investigator = user - application.save() - application.refresh_from_db() - action_method() - else: - action_method() + action_method() # Check if an email was sent sent_emails = [ diff --git a/src/registrar/utility/errors.py b/src/registrar/utility/errors.py index f399299ff..10e1809aa 100644 --- a/src/registrar/utility/errors.py +++ b/src/registrar/utility/errors.py @@ -100,9 +100,7 @@ class ApplicationStatusError(Exception): FSMErrorCodes.APPROVE_DOMAIN_IN_USE: ("Cannot approve. Requested domain is already in use."), FSMErrorCodes.NO_INVESTIGATOR: ("No investigator was assigned."), FSMErrorCodes.INVESTIGATOR_NOT_STAFF: ("Investigator is not a staff user."), - FSMErrorCodes.INVESTIGATOR_NOT_SUBMITTER: ( - "Only the assigned investigator can make this change." - ), + FSMErrorCodes.INVESTIGATOR_NOT_SUBMITTER: ("Only the assigned investigator can make this change."), } def __init__(self, *args, code=None, **kwargs): From a81d4d18458fb926450e9d24184bf773e78b914a Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 27 Feb 2024 08:21:28 -0700 Subject: [PATCH 025/103] Update admin.py --- src/registrar/admin.py | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index 176c0bb87..5ad274ab1 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -794,7 +794,6 @@ class DomainApplicationAdminForm(forms.ModelForm): fields = "__all__" def __init__(self, *args, **kwargs): - self.request = kwargs.pop("request", None) super().__init__(*args, **kwargs) application = kwargs.get("instance") if application and application.pk: @@ -833,6 +832,10 @@ class DomainApplicationAdminForm(forms.ModelForm): yield meta.get_transition(curr_state) def clean(self): + """ + Override of the default clean on the form. + This is so we can inject custom form-level error messages. + """ # clean is called from clean_forms, which is called from is_valid # after clean_fields. it is used to determine form level errors. # is_valid is typically called from view during a post @@ -1028,23 +1031,6 @@ class DomainApplicationAdmin(ListHeaderAdmin): # Table ordering ordering = ["requested_domain__name"] - def get_form(self, request, obj=None, **kwargs): - """ - Workaround to pass the request context to the underlying DomainApplicationAdminForm form object. - This is so we can do things like check the current user against a form value at submission. - """ - # Call the superclass's get_form method to get the form class - da_form = super().get_form(request, obj, **kwargs) - - # Define a wrapper class for the form that includes the request in its initialization. - # This is needed such that we can inject request without otherwise altering it. - class DomainApplicationFormWrapper(da_form): - def __new__(cls, *args, **form_kwargs): - form_kwargs["request"] = request - return da_form(*args, **form_kwargs) - - return DomainApplicationFormWrapper - # Trigger action when a fieldset is changed def save_model(self, request, obj, form, change): # TODO - there is an existing bug in these in that they redirect From 2ef573ddfaf01f5aa1ded9b394be3cf977009244 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 27 Feb 2024 08:49:22 -0700 Subject: [PATCH 026/103] Fix indent --- src/registrar/tests/test_models_domain.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/registrar/tests/test_models_domain.py b/src/registrar/tests/test_models_domain.py index 626cdae8f..e50cc357b 100644 --- a/src/registrar/tests/test_models_domain.py +++ b/src/registrar/tests/test_models_domain.py @@ -329,16 +329,16 @@ class TestDomainCreation(MockEppLib): creator=user, requested_domain=draft_domain, investigator=investigator ) - mock_client = MockSESClient() - with boto3_mocking.clients.handler_for("sesv2", mock_client): - # skip using the submit method - application.status = DomainApplication.ApplicationStatus.SUBMITTED - # transition to approve state - application.approve() - # should have information present for this domain - domain = Domain.objects.get(name="igorville.gov") - self.assertTrue(domain) - self.mockedSendFunction.assert_not_called() + mock_client = MockSESClient() + with boto3_mocking.clients.handler_for("sesv2", mock_client): + # skip using the submit method + application.status = DomainApplication.ApplicationStatus.SUBMITTED + # transition to approve state + application.approve() + # should have information present for this domain + domain = Domain.objects.get(name="igorville.gov") + self.assertTrue(domain) + self.mockedSendFunction.assert_not_called() def test_accessing_domain_properties_creates_domain_in_registry(self): """ From 6b5d6009d196a54cd58014699b23f1e94e8f1ace Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 27 Feb 2024 09:36:06 -0700 Subject: [PATCH 027/103] Add some none returns - needs cleaning --- src/registrar/admin.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index 6a7198556..50ee54547 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -1110,6 +1110,7 @@ class DomainApplicationAdmin(ListHeaderAdmin): request, "This action is not permitted. The domain is already active.", ) + return None elif ( obj and obj.status == models.DomainApplication.ApplicationStatus.REJECTED @@ -1126,7 +1127,7 @@ class DomainApplicationAdmin(ListHeaderAdmin): request, "A rejection reason is required.", ) - + return None else: if obj.status != original_obj.status: status_method_mapping = { @@ -1162,6 +1163,7 @@ class DomainApplicationAdmin(ListHeaderAdmin): request, err.message, ) + return None super().save_model(request, obj, form, change) From db8c363d43b6df4b107abcb6132690e918fef3a2 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 27 Feb 2024 11:34:05 -0700 Subject: [PATCH 028/103] Save_model refactor --- src/registrar/admin.py | 194 +++++++++++++++++++++++++---------------- 1 file changed, 121 insertions(+), 73 deletions(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index 50ee54547..68103968f 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -1070,8 +1070,20 @@ class DomainApplicationAdmin(ListHeaderAdmin): # Trigger action when a fieldset is changed def save_model(self, request, obj, form, change): - # TODO - there is an existing bug in these in that they redirect - # to the table rather than back, on message display + """Custom save_model definition that handles edge cases""" + + # == Check that the obj is in a valid state == # + + # If obj is none, something went very wrong. + # The form should have blocked this, so lets forbid it. + if not obj: + logger.error(f"Invalid value for obj ({obj})") + messages.set_level(request, messages.ERROR) + messages.error( + request, + "Could not save DomainApplication. Something went wrong.", + ) + return None # If the user is restricted or we're saving an invalid model, # forbid this action. @@ -1086,86 +1098,122 @@ class DomainApplicationAdmin(ListHeaderAdmin): return None - if change: - # Get the original application from the database - original_obj = models.DomainApplication.objects.get(pk=obj.pk) + # == Check if we're making a change or not == # - if ( - obj - and original_obj.status == models.DomainApplication.ApplicationStatus.APPROVED - and obj.status != models.DomainApplication.ApplicationStatus.APPROVED - and not obj.domain_is_not_active() - ): - # If an admin tried to set an approved application to - # another status and the related domain is already - # active, shortcut the action and throw a friendly - # error message. This action would still not go through - # shortcut or not as the rules are duplicated on the model, - # but the error would be an ugly Django error screen. + # If we're not making a change (adding a record), run save model as we do normally + if not change: + return super().save_model(request, obj, form, change) - # Clear the success message - messages.set_level(request, messages.ERROR) + # == Handle non-status changes == # + + # Get the original application from the database. + original_obj = models.DomainApplication.objects.get(pk=obj.pk) + if obj.status == original_obj.status: + # If the status hasn't changed, let the base function take care of it + return super().save_model(request, obj, form, change) - messages.error( - request, - "This action is not permitted. The domain is already active.", + # == Handle status changes == # + + # Run some checks on the current object for invalid status changes + obj, should_save = self._handle_status_change(request, obj, original_obj) + + # We should only save if we don't display any errors in the step above. + if should_save: + return super().save_model(request, obj, form, change) + + def _handle_status_change(self, request, obj, original_obj): + """ + Checks for various conditions when a status change is triggered. + In the event that it is valid, the status will be mapped to + the appropriate method. + + In the event that we should not status change, an error message + will be displayed. + + Returns a tuple: (obj: DomainApplication, should_proceed: bool) + """ + + should_proceed = True + error_message = None + + # Get the method that should be run given the status + selected_method = self.get_status_method_mapping(obj) + if selected_method is None: + logger.warning("Unknown status selected in django admin") + + # If the status is not mapped properly, saving could cause + # weird issues down the line. Instead, we should block this. + should_proceed = False + return should_proceed + + original_is_approved_and_current_is_not = ( + original_obj.status == models.DomainApplication.ApplicationStatus.APPROVED, + obj.status != models.DomainApplication.ApplicationStatus.APPROVED + ) + if (original_is_approved_and_current_is_not and not obj.domain_is_not_active()): + # If an admin tried to set an approved application to + # another status and the related domain is already + # active, shortcut the action and throw a friendly + # error message. This action would still not go through + # shortcut or not as the rules are duplicated on the model, + # but the error would be an ugly Django error screen. + error_message = "This action is not permitted. The domain is already active." + elif ( + obj.status == models.DomainApplication.ApplicationStatus.REJECTED + and not obj.rejection_reason + ): + # This condition should never be triggered. + # The opposite of this condition is acceptable (rejected -> other status and rejection_reason) + # because we clean up the rejection reason in the transition in the model. + error_message = "A rejection reason is required." + else: + # This is an fsm in model which will throw an error if the + # transition condition is violated, so we roll back the + # status to what it was before the admin user changed it and + # let the fsm method set it. + obj.status = original_obj.status + + # Try to perform the status change. + # Catch ApplicationStatusError's and return the message, + # as these are typically user errors. + try: + selected_method() + except ApplicationStatusError as err: + logger.warning( + f"User error encountered when trying to change status: {err}" ) - return None - elif ( - obj - and obj.status == models.DomainApplication.ApplicationStatus.REJECTED - and not obj.rejection_reason - ): - # This condition should never be triggered. - # The opposite of this condition is acceptable (rejected -> other status and rejection_reason) - # because we clean up the rejection reason in the transition in the model. + error_message = err.message - # Clear the success message - messages.set_level(request, messages.ERROR) + if error_message is not None: + # Clear the success message + messages.set_level(request, messages.ERROR) + # Display the error + messages.error( + request, + error_message, + ) - messages.error( - request, - "A rejection reason is required.", - ) - return None - else: - if obj.status != original_obj.status: - status_method_mapping = { - models.DomainApplication.ApplicationStatus.STARTED: None, - models.DomainApplication.ApplicationStatus.SUBMITTED: obj.submit, - models.DomainApplication.ApplicationStatus.IN_REVIEW: obj.in_review, - models.DomainApplication.ApplicationStatus.ACTION_NEEDED: obj.action_needed, - models.DomainApplication.ApplicationStatus.APPROVED: obj.approve, - models.DomainApplication.ApplicationStatus.WITHDRAWN: obj.withdraw, - models.DomainApplication.ApplicationStatus.REJECTED: obj.reject, - models.DomainApplication.ApplicationStatus.INELIGIBLE: (obj.reject_with_prejudice), - } - selected_method = status_method_mapping.get(obj.status) - if selected_method is None: - logger.warning("Unknown status selected in django admin") - else: - # This is an fsm in model which will throw an error if the - # transition condition is violated, so we roll back the - # status to what it was before the admin user changed it and - # let the fsm method set it. - obj.status = original_obj.status + # If an error message exists, we shouldn't proceed + should_proceed = False - # Try to perform the status change. - # Catch ApplicationStatusError's and return the message, - # as these are typically user errors. - try: - selected_method() - except ApplicationStatusError as err: - # Clear the success message, if any - messages.set_level(request, messages.ERROR) + return (obj, should_proceed) - messages.error( - request, - err.message, - ) - return None + def get_status_method_mapping(self, application): + """Returns what method should be ran given an application object""" + # Define a per-object mapping + status_method_mapping = { + models.DomainApplication.ApplicationStatus.STARTED: None, + models.DomainApplication.ApplicationStatus.SUBMITTED: application.submit, + models.DomainApplication.ApplicationStatus.IN_REVIEW: application.in_review, + models.DomainApplication.ApplicationStatus.ACTION_NEEDED: application.action_needed, + models.DomainApplication.ApplicationStatus.APPROVED: application.approve, + models.DomainApplication.ApplicationStatus.WITHDRAWN: application.withdraw, + models.DomainApplication.ApplicationStatus.REJECTED: application.reject, + models.DomainApplication.ApplicationStatus.INELIGIBLE: (application.reject_with_prejudice), + } - super().save_model(request, obj, form, change) + # Grab the method + return status_method_mapping.get(application.status, None) def get_readonly_fields(self, request, obj=None): """Set the read-only state on form elements. From 3268fa44db4badac0db111fc640ae0c0d87de3b9 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 27 Feb 2024 11:35:52 -0700 Subject: [PATCH 029/103] Linting --- src/registrar/admin.py | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index 68103968f..df39a36cc 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -1071,8 +1071,8 @@ class DomainApplicationAdmin(ListHeaderAdmin): # Trigger action when a fieldset is changed def save_model(self, request, obj, form, change): """Custom save_model definition that handles edge cases""" - - # == Check that the obj is in a valid state == # + + # == Check that the obj is in a valid state == # # If obj is none, something went very wrong. # The form should have blocked this, so lets forbid it. @@ -1105,7 +1105,7 @@ class DomainApplicationAdmin(ListHeaderAdmin): return super().save_model(request, obj, form, change) # == Handle non-status changes == # - + # Get the original application from the database. original_obj = models.DomainApplication.objects.get(pk=obj.pk) if obj.status == original_obj.status: @@ -1124,7 +1124,7 @@ class DomainApplicationAdmin(ListHeaderAdmin): def _handle_status_change(self, request, obj, original_obj): """ Checks for various conditions when a status change is triggered. - In the event that it is valid, the status will be mapped to + In the event that it is valid, the status will be mapped to the appropriate method. In the event that we should not status change, an error message @@ -1148,9 +1148,9 @@ class DomainApplicationAdmin(ListHeaderAdmin): original_is_approved_and_current_is_not = ( original_obj.status == models.DomainApplication.ApplicationStatus.APPROVED, - obj.status != models.DomainApplication.ApplicationStatus.APPROVED + obj.status != models.DomainApplication.ApplicationStatus.APPROVED, ) - if (original_is_approved_and_current_is_not and not obj.domain_is_not_active()): + if original_is_approved_and_current_is_not and not obj.domain_is_not_active(): # If an admin tried to set an approved application to # another status and the related domain is already # active, shortcut the action and throw a friendly @@ -1158,10 +1158,7 @@ class DomainApplicationAdmin(ListHeaderAdmin): # shortcut or not as the rules are duplicated on the model, # but the error would be an ugly Django error screen. error_message = "This action is not permitted. The domain is already active." - elif ( - obj.status == models.DomainApplication.ApplicationStatus.REJECTED - and not obj.rejection_reason - ): + elif obj.status == models.DomainApplication.ApplicationStatus.REJECTED and not obj.rejection_reason: # This condition should never be triggered. # The opposite of this condition is acceptable (rejected -> other status and rejection_reason) # because we clean up the rejection reason in the transition in the model. @@ -1179,9 +1176,7 @@ class DomainApplicationAdmin(ListHeaderAdmin): try: selected_method() except ApplicationStatusError as err: - logger.warning( - f"User error encountered when trying to change status: {err}" - ) + logger.warning(f"An error encountered when trying to change status: {err}") error_message = err.message if error_message is not None: From 7d8cd5498bef44fb2985ffe587d3da7d1fe13b2e Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 27 Feb 2024 12:55:16 -0700 Subject: [PATCH 030/103] Merge conflict --- src/registrar/admin.py | 180 +++++++++++++++++------------------------ 1 file changed, 75 insertions(+), 105 deletions(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index aaa3b1f03..68e9bc4bb 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -93,9 +93,14 @@ class DomainApplicationAdminForm(forms.ModelForm): # first option in status transitions is current state available_transitions = [(current_state, application.get_status_display())] - transitions = get_available_FIELD_transitions( - application, models.DomainApplication._meta.get_field("status") - ) + if application.investigator is not None: + transitions = get_available_FIELD_transitions( + application, models.DomainApplication._meta.get_field("status") + ) + else: + transitions = self.get_custom_field_transitions( + application, models.DomainApplication._meta.get_field("status") + ) for transition in transitions: available_transitions.append((transition.target, transition.target.label)) @@ -106,6 +111,73 @@ class DomainApplicationAdminForm(forms.ModelForm): if not application.creator.is_restricted(): self.fields["status"].widget.choices = available_transitions + def get_custom_field_transitions(self, instance, field): + """Custom implementation of get_available_FIELD_transitions + in the FSM. Allows us to still display fields filtered out by a condition.""" + curr_state = field.get_state(instance) + transitions = field.transitions[instance.__class__] + + for name, transition in transitions.items(): + meta = transition._django_fsm + if meta.has_transition(curr_state): + yield meta.get_transition(curr_state) + + def clean(self): + """ + Override of the default clean on the form. + This is so we can inject custom form-level error messages. + """ + # clean is called from clean_forms, which is called from is_valid + # after clean_fields. it is used to determine form level errors. + # is_valid is typically called from view during a post + cleaned_data = super().clean() + status = cleaned_data.get("status") + investigator = cleaned_data.get("investigator") + + # Get the old status + initial_status = self.initial.get("status", None) + + # We only care about investigator when in these statuses + checked_statuses = [ + DomainApplication.ApplicationStatus.APPROVED, + DomainApplication.ApplicationStatus.IN_REVIEW, + DomainApplication.ApplicationStatus.ACTION_NEEDED, + DomainApplication.ApplicationStatus.REJECTED, + DomainApplication.ApplicationStatus.INELIGIBLE, + ] + + # If a status change occured, check for validity + if status != initial_status and status in checked_statuses: + # Checks the "investigators" field for validity. + # That field must obey certain conditions when an application is approved. + # Will call "add_error" if any issues are found. + self._check_for_valid_investigator(investigator) + + return cleaned_data + + def _check_for_valid_investigator(self, investigator) -> bool: + """ + Checks if the investigator field is not none, and is staff. + Adds form errors on failure. + """ + + is_valid = False + + # Check if an investigator is assigned. No approval is possible without one. + error_message = None + if investigator is None: + # Lets grab the error message from a common location + error_message = ApplicationStatusError.get_error_message(FSMErrorCodes.NO_INVESTIGATOR) + elif not investigator.is_staff: + error_message = ApplicationStatusError.get_error_message(FSMErrorCodes.INVESTIGATOR_NOT_STAFF) + else: + is_valid = True + + if error_message is not None: + self.add_error("investigator", error_message) + + return is_valid + # Based off of this excellent example: https://djangosnippets.org/snippets/10471/ class MultiFieldSortableChangeList(admin.views.main.ChangeList): @@ -867,108 +939,6 @@ class DomainInformationAdmin(ListHeaderAdmin): return readonly_fields # Read-only fields for analysts -class DomainApplicationAdminForm(forms.ModelForm): - """Custom form to limit transitions to available transitions""" - - class Meta: - model = models.DomainApplication - fields = "__all__" - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - application = kwargs.get("instance") - if application and application.pk: - current_state = application.status - - # first option in status transitions is current state - available_transitions = [(current_state, application.get_status_display())] - - if application.investigator is not None: - transitions = get_available_FIELD_transitions( - application, models.DomainApplication._meta.get_field("status") - ) - else: - transitions = self.get_custom_field_transitions( - application, models.DomainApplication._meta.get_field("status") - ) - - for transition in transitions: - available_transitions.append((transition.target, transition.target.label)) - - # only set the available transitions if the user is not restricted - # from editing the domain application; otherwise, the form will be - # readonly and the status field will not have a widget - if not application.creator.is_restricted(): - self.fields["status"].widget.choices = available_transitions - - def get_custom_field_transitions(self, instance, field): - """Custom implementation of get_available_FIELD_transitions - in the FSM. Allows us to still display fields filtered out by a condition.""" - curr_state = field.get_state(instance) - transitions = field.transitions[instance.__class__] - - for name, transition in transitions.items(): - meta = transition._django_fsm - if meta.has_transition(curr_state): - yield meta.get_transition(curr_state) - - def clean(self): - """ - Override of the default clean on the form. - This is so we can inject custom form-level error messages. - """ - # clean is called from clean_forms, which is called from is_valid - # after clean_fields. it is used to determine form level errors. - # is_valid is typically called from view during a post - cleaned_data = super().clean() - status = cleaned_data.get("status") - investigator = cleaned_data.get("investigator") - - # Get the old status - initial_status = self.initial.get("status", None) - - # We only care about investigator when in these statuses - checked_statuses = [ - DomainApplication.ApplicationStatus.APPROVED, - DomainApplication.ApplicationStatus.IN_REVIEW, - DomainApplication.ApplicationStatus.ACTION_NEEDED, - DomainApplication.ApplicationStatus.REJECTED, - DomainApplication.ApplicationStatus.INELIGIBLE, - ] - - # If a status change occured, check for validity - if status != initial_status and status in checked_statuses: - # Checks the "investigators" field for validity. - # That field must obey certain conditions when an application is approved. - # Will call "add_error" if any issues are found. - self._check_for_valid_investigator(investigator) - - return cleaned_data - - def _check_for_valid_investigator(self, investigator) -> bool: - """ - Checks if the investigator field is not none, and is staff. - Adds form errors on failure. - """ - - is_valid = False - - # Check if an investigator is assigned. No approval is possible without one. - error_message = None - if investigator is None: - # Lets grab the error message from a common location - error_message = ApplicationStatusError.get_error_message(FSMErrorCodes.NO_INVESTIGATOR) - elif not investigator.is_staff: - error_message = ApplicationStatusError.get_error_message(FSMErrorCodes.INVESTIGATOR_NOT_STAFF) - else: - is_valid = True - - if error_message is not None: - self.add_error("investigator", error_message) - - return is_valid - - class DomainApplicationAdmin(ListHeaderAdmin): """Custom domain applications admin class.""" From a4f51c6477bdfa9bf3bbd59d94dbe8d418dbde0f Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 27 Feb 2024 14:34:35 -0700 Subject: [PATCH 031/103] Update admin.py --- src/registrar/admin.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index 68e9bc4bb..c440d0ea3 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -1203,11 +1203,10 @@ class DomainApplicationAdmin(ListHeaderAdmin): should_proceed = False return should_proceed - original_is_approved_and_current_is_not = ( - original_obj.status == models.DomainApplication.ApplicationStatus.APPROVED, - obj.status != models.DomainApplication.ApplicationStatus.APPROVED, + application_is_not_approved = ( + obj.status != models.DomainApplication.ApplicationStatus.APPROVED ) - if original_is_approved_and_current_is_not and not obj.domain_is_not_active(): + if application_is_not_approved and not obj.domain_is_not_active(): # If an admin tried to set an approved application to # another status and the related domain is already # active, shortcut the action and throw a friendly From 820d6f3f58dfc492b5e84157ff99e14d8bc16cf1 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 27 Feb 2024 14:38:12 -0700 Subject: [PATCH 032/103] Linting, once more --- src/registrar/admin.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index c440d0ea3..598b612b5 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -1203,9 +1203,7 @@ class DomainApplicationAdmin(ListHeaderAdmin): should_proceed = False return should_proceed - application_is_not_approved = ( - obj.status != models.DomainApplication.ApplicationStatus.APPROVED - ) + application_is_not_approved = obj.status != models.DomainApplication.ApplicationStatus.APPROVED if application_is_not_approved and not obj.domain_is_not_active(): # If an admin tried to set an approved application to # another status and the related domain is already From 2ba62bf1741646d4ac5383dca36f1a79c805dc3d Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Wed, 28 Feb 2024 10:00:13 -0700 Subject: [PATCH 033/103] Update name --- src/registrar/admin.py | 10 +++++----- src/registrar/models/domain_application.py | 4 ++-- src/registrar/utility/errors.py | 6 +----- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index 598b612b5..6dc6cd94d 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -16,7 +16,7 @@ from dateutil.relativedelta import relativedelta # type: ignore from epplibwrapper.errors import ErrorCode, RegistryError from registrar.models import Contact, Domain, DomainApplication, DraftDomain, User, Website from registrar.utility import csv_export -from registrar.utility.errors import ApplicationStatusError, FSMErrorCodes +from registrar.utility.errors import FSMApplicationError, FSMErrorCodes from registrar.views.utility.mixins import OrderableFieldsMixin from django.contrib.admin.views.main import ORDER_VAR from registrar.widgets import NoAutocompleteFilteredSelectMultiple @@ -167,9 +167,9 @@ class DomainApplicationAdminForm(forms.ModelForm): error_message = None if investigator is None: # Lets grab the error message from a common location - error_message = ApplicationStatusError.get_error_message(FSMErrorCodes.NO_INVESTIGATOR) + error_message = FSMApplicationError.get_error_message(FSMErrorCodes.NO_INVESTIGATOR) elif not investigator.is_staff: - error_message = ApplicationStatusError.get_error_message(FSMErrorCodes.INVESTIGATOR_NOT_STAFF) + error_message = FSMApplicationError.get_error_message(FSMErrorCodes.INVESTIGATOR_NOT_STAFF) else: is_valid = True @@ -1225,11 +1225,11 @@ class DomainApplicationAdmin(ListHeaderAdmin): obj.status = original_obj.status # Try to perform the status change. - # Catch ApplicationStatusError's and return the message, + # Catch FSMApplicationError's and return the message, # as these are typically user errors. try: selected_method() - except ApplicationStatusError as err: + except FSMApplicationError as err: logger.warning(f"An error encountered when trying to change status: {err}") error_message = err.message diff --git a/src/registrar/models/domain_application.py b/src/registrar/models/domain_application.py index 29c4d63a5..6076497ad 100644 --- a/src/registrar/models/domain_application.py +++ b/src/registrar/models/domain_application.py @@ -9,7 +9,7 @@ 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 registrar.utility.errors import ApplicationStatusError, FSMErrorCodes +from registrar.utility.errors import FSMApplicationError, FSMErrorCodes from .utility.time_stamped_model import TimeStampedModel from ..utility.email import send_templated_email, EmailSendingError @@ -791,7 +791,7 @@ class DomainApplication(TimeStampedModel): # == Check that the application is valid == # if Domain.objects.filter(name=self.requested_domain.name).exists(): - raise ApplicationStatusError(code=FSMErrorCodes.APPROVE_DOMAIN_IN_USE) + raise FSMApplicationError(code=FSMErrorCodes.APPROVE_DOMAIN_IN_USE) # == Create the domain and related components == # created_domain = Domain.objects.create(name=self.requested_domain.name) diff --git a/src/registrar/utility/errors.py b/src/registrar/utility/errors.py index 10e1809aa..f5804ac2f 100644 --- a/src/registrar/utility/errors.py +++ b/src/registrar/utility/errors.py @@ -71,8 +71,6 @@ class GenericError(Exception): return self._error_mapping.get(code) -# (Q for reviewers) What should this be called? -# Not a fan of this name. class FSMErrorCodes(IntEnum): """Used when doing FSM transitions. Overview of generic error codes: @@ -88,9 +86,7 @@ class FSMErrorCodes(IntEnum): INVESTIGATOR_NOT_SUBMITTER = 4 -# (Q for reviewers) What should this be called? -# Not a fan of this name. -class ApplicationStatusError(Exception): +class FSMApplicationError(Exception): """ Used to raise exceptions when doing FSM Transitions. Uses `FSMErrorCodes` as an enum. From fdb7fb659464a199972e4948e6dd544088e6ac1a Mon Sep 17 00:00:00 2001 From: Rebecca Hsieh Date: Wed, 28 Feb 2024 09:17:59 -0800 Subject: [PATCH 034/103] Biz logic --- .../generate_current_metadata_report.py | 28 ++++++++-- src/registrar/utility/email.py | 54 +++++++++++++++++++ 2 files changed, 78 insertions(+), 4 deletions(-) diff --git a/src/registrar/management/commands/generate_current_metadata_report.py b/src/registrar/management/commands/generate_current_metadata_report.py index d8f5a4693..69d111f4c 100644 --- a/src/registrar/management/commands/generate_current_metadata_report.py +++ b/src/registrar/management/commands/generate_current_metadata_report.py @@ -2,10 +2,12 @@ import logging import os +import pyzipper from django.core.management import BaseCommand from registrar.utility import csv_export from registrar.utility.s3_bucket import S3ClientHelper +from ...utility.email import send_templated_email, EmailSendingError logger = logging.getLogger(__name__) @@ -59,9 +61,27 @@ class Command(BaseCommand): We want to make sure to upload to s3 for back up And now we also want to get the file and encrypt it so we can send it in an email """ - # metadata_file = s3_client.get_file(file_name) - # metadata_file.encryptthisthingherewithpyzipper - # email.blasend_email(metadata_file) + unencrypted_metadata_input = s3_client.get_file(file_name) + + # Encrypt metadata into a zip file + + # pre-setting zip file name + encrypted_metadata_output = 'encrypted_metadata.zip' + # set this to be an env var somewhere + password = b'somepasswordhere' + # encrypted_metadata is the encrypted output + encrypted_metadata = _encrypt_metadata(unencrypted_metadata_input, encrypted_metadata_output, password) + print("encrypted_metadata is:", encrypted_metadata) + + # Send the metadata file that is zipped + # Q: Would we set the vars I set in email.py here to pass in to the helper function or best way to invoke + # send_templated_email(encrypted_metadata, attachment=True) - + def _encrypt_metadata(input_file, output_file, password): + with open(input_file, 'rb') as f_in: + with pyzipper.AESZipFile(output_file, 'w', compression=pyzipper.ZIP_LZMA, encryption=pyzipper.WZ_AES) as f_out: + f_out.setpassword(password) + f_out.writestr(input_file, f_in.read()) + return output_file + diff --git a/src/registrar/utility/email.py b/src/registrar/utility/email.py index e4e997d9d..199a6c304 100644 --- a/src/registrar/utility/email.py +++ b/src/registrar/utility/email.py @@ -40,6 +40,8 @@ def send_templated_email(template_name: str, subject_template_name: str, to_addr except Exception as exc: raise EmailSendingError("Could not access the SES client.") from exc + # Are we okay with passing in "attachment" var in as boolean parameter + # If so, TODO: add attachment boolean to other functions try: #if not attachment: ses_client.send_email( @@ -55,5 +57,57 @@ def send_templated_email(template_name: str, subject_template_name: str, to_addr # else: # has attachment # same as above but figure out how to attach a file # via boto3 "boto3 SES file attachment" + # we also want this to only send to the help email + + # from email.mime.multipart import MIMEMultipart + # from email.mime.text import MIMEText + # from email.mime.application import MIMEApplication + + # sender_email = 'sender@example.com' + # recipient_email = 'help@get.gov' + # subject = 'DOTGOV-Full Domain Metadata' + # body = 'Domain metadata email, should have an attachment included change here later.' + # attachment_path = 'path/to/attachment/file.pdf' + # aws_region = 'sesv2' + + # response = send_email_with_attachment(sender_email, recipient_email, subject, body, attachment_path, aws_region) + # print(response) except Exception as exc: raise EmailSendingError("Could not send SES email.") from exc + + +# def send_email_with_attachment(sender, recipient, subject, body, attachment_path, aws_region): + # # Create a multipart/mixed parent container + # msg = MIMEMultipart('mixed') + # msg['Subject'] = subject + # msg['From'] = sender_email + # msg['To'] = recipient_email + + # # Add the text part + # text_part = MIMEText(body, 'plain') + # msg.attach(text_part) + + # # Add the attachment part + # with open(attachment_path, 'rb') as attachment_file: + # attachment_data = attachment_file.read() + # attachment_part = MIMEApplication(attachment_data) + # attachment_part.add_header('Content-Disposition', f'attachment; filename="{attachment_path}"') + # msg.attach(attachment_part) + + # # Send the email + # response = ses_client.send_raw_email( + # Source=sender, + # Destinations=[recipient], + # RawMessage={'Data': msg.as_string()} + # ) + + # ses_client.send_email( + # FromEmailAddress=settings.DEFAULT_FROM_EMAIL, + # Destination={"ToAddresses": [to_address]}, + # Content={ + # "Simple": { + # "Subject": {"Data": subject}, + # "Body": {"Text": {"Data": email_body}}, + # }, + # }, + # ) \ No newline at end of file From 8148b9099656e51ca26a2f514003d237eba29340 Mon Sep 17 00:00:00 2001 From: Rebecca Hsieh Date: Thu, 29 Feb 2024 09:06:58 -0800 Subject: [PATCH 035/103] Update documentation and add in the pyzipper import and associated biz logic --- .../runbooks/update_python_dependencies.md | 4 +- src/Pipfile | 2 + src/Pipfile.lock | 561 +++++++++--------- src/docker-compose.yml | 2 + src/registrar/config/settings.py | 3 + .../generate_current_metadata_report.py | 24 +- src/requirements.txt | 33 +- 7 files changed, 325 insertions(+), 304 deletions(-) diff --git a/docs/operations/runbooks/update_python_dependencies.md b/docs/operations/runbooks/update_python_dependencies.md index b94c0f39f..04fb936c6 100644 --- a/docs/operations/runbooks/update_python_dependencies.md +++ b/docs/operations/runbooks/update_python_dependencies.md @@ -2,7 +2,7 @@ ======================== 1. Check the [Pipfile](../../../src/Pipfile) for pinned dependencies and manually adjust the version numbers - +2. Run `docker-compose stop` to spin down the current containers and images so we can start afresh 2. Run cd src @@ -16,6 +16,6 @@ 3. Change geventconnpool back to what it was originally within the Pipfile.lock and requirements.txt. This is done by either saving what it was originally or opening a PR and using that as a reference to undo changes to any mention of geventconnpool. Geventconnpool, when set as a requirement without the reference portion, is defaulting to get a commit from 2014 which then breaks the code, as we want the newest version from them. -4. (optional) Run `docker-compose stop` and `docker-compose build` to build a new image for local development with the updated dependencies. +4. Run `docker-compose build` to build a new image for local development with the updated dependencies. The reason for de-coupling the `build` and `lock` steps is to increase consistency between builds--a run of `build` will always get exactly the dependencies listed in `Pipfile.lock`, nothing more, nothing less. \ No newline at end of file diff --git a/src/Pipfile b/src/Pipfile index 51417d578..8e43d1bab 100644 --- a/src/Pipfile +++ b/src/Pipfile @@ -30,6 +30,7 @@ greenlet = "*" gevent = "*" fred-epplib = {git = "https://github.com/cisagov/epplib.git", ref = "master"} geventconnpool = {git = "https://github.com/rasky/geventconnpool.git", ref = "1bbb93a714a331a069adf27265fe582d9ba7ecd4"} +pyzipper="*" [dev-packages] django-debug-toolbar = "*" @@ -45,3 +46,4 @@ types-cachetools = "*" boto3-mocking = "*" boto3-stubs = "*" django-model2puml = "*" + diff --git a/src/Pipfile.lock b/src/Pipfile.lock index 7d511a0e5..c410630e1 100644 --- a/src/Pipfile.lock +++ b/src/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "a672aeb8951fd850e90ad87c6f03cf71e2fc2b387d56fd3942361cb0b45bb449" + "sha256": "8c15011f6c6e0447e4ca675ce840fe6b67048e90255e7c083be357b373f96a47" }, "pipfile-spec": 6, "requires": {}, @@ -32,29 +32,29 @@ }, "boto3": { "hashes": [ - "sha256:65acfe7f1cf2a9b7df3d4edb87c8022e02685825bd1957e7bb678cc0d09f5e5f", - "sha256:73f5ec89cb3ddb3ed577317889fd2f2df783f66b6502a9a4239979607e33bf74" + "sha256:66303b5f26d92afb72656ff490b22ea72dfff8bf1a29e4a0c5d5f11ec56245dd", + "sha256:898ad2123b18cae8efd85adc56ac2d1925be54592aebc237020d4f16e9a9e7a9" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==1.34.37" + "version": "==1.34.52" }, "botocore": { "hashes": [ - "sha256:2a5bf33aacd2d970afd3d492e179e06ea98a5469030d5cfe7a2ad9995f7bb2ef", - "sha256:3c46ddb1679e6ef45ca78b48665398636bda532a07cd476e4b500697d13d9a99" + "sha256:05567d8aba344826060481ea309555432c96f0febe22bee7cf5a3b6d3a03cec8", + "sha256:187da93aec3f2e87d8a31eced16fa2cb9c71fe2d69b0a797f9f7a9220f5bf7ae" ], "markers": "python_version >= '3.8'", - "version": "==1.34.37" + "version": "==1.34.52" }, "cachetools": { "hashes": [ - "sha256:086ee420196f7b2ab9ca2db2520aca326318b68fe5ba8bc4d49cca91add450f2", - "sha256:861f35a13a451f94e301ce2bec7cac63e881232ccce7ed67fab9b5df4d3beaa1" + "sha256:0abad1021d3f8325b2fc1d2e9c8b9c9d57b04c3932657a72465447332c24d945", + "sha256:ba29e2dfa0b8b556606f097407ed1aa62080ee108ab0dc5ec9d6a723a007d105" ], "index": "pypi", "markers": "python_version >= '3.7'", - "version": "==5.3.2" + "version": "==5.3.3" }, "certifi": { "hashes": [ @@ -228,41 +228,41 @@ }, "cryptography": { "hashes": [ - "sha256:087887e55e0b9c8724cf05361357875adb5c20dec27e5816b653492980d20380", - "sha256:09a77e5b2e8ca732a19a90c5bca2d124621a1edb5438c5daa2d2738bfeb02589", - "sha256:130c0f77022b2b9c99d8cebcdd834d81705f61c68e91ddd614ce74c657f8b3ea", - "sha256:141e2aa5ba100d3788c0ad7919b288f89d1fe015878b9659b307c9ef867d3a65", - "sha256:28cb2c41f131a5758d6ba6a0504150d644054fd9f3203a1e8e8d7ac3aea7f73a", - "sha256:2f9f14185962e6a04ab32d1abe34eae8a9001569ee4edb64d2304bf0d65c53f3", - "sha256:320948ab49883557a256eab46149df79435a22d2fefd6a66fe6946f1b9d9d008", - "sha256:36d4b7c4be6411f58f60d9ce555a73df8406d484ba12a63549c88bd64f7967f1", - "sha256:3b15c678f27d66d247132cbf13df2f75255627bcc9b6a570f7d2fd08e8c081d2", - "sha256:3dbd37e14ce795b4af61b89b037d4bc157f2cb23e676fa16932185a04dfbf635", - "sha256:4383b47f45b14459cab66048d384614019965ba6c1a1a141f11b5a551cace1b2", - "sha256:44c95c0e96b3cb628e8452ec060413a49002a247b2b9938989e23a2c8291fc90", - "sha256:4b063d3413f853e056161eb0c7724822a9740ad3caa24b8424d776cebf98e7ee", - "sha256:52ed9ebf8ac602385126c9a2fe951db36f2cb0c2538d22971487f89d0de4065a", - "sha256:55d1580e2d7e17f45d19d3b12098e352f3a37fe86d380bf45846ef257054b242", - "sha256:5ef9bc3d046ce83c4bbf4c25e1e0547b9c441c01d30922d812e887dc5f125c12", - "sha256:5fa82a26f92871eca593b53359c12ad7949772462f887c35edaf36f87953c0e2", - "sha256:61321672b3ac7aade25c40449ccedbc6db72c7f5f0fdf34def5e2f8b51ca530d", - "sha256:701171f825dcab90969596ce2af253143b93b08f1a716d4b2a9d2db5084ef7be", - "sha256:841ec8af7a8491ac76ec5a9522226e287187a3107e12b7d686ad354bb78facee", - "sha256:8a06641fb07d4e8f6c7dda4fc3f8871d327803ab6542e33831c7ccfdcb4d0ad6", - "sha256:8e88bb9eafbf6a4014d55fb222e7360eef53e613215085e65a13290577394529", - "sha256:a00aee5d1b6c20620161984f8ab2ab69134466c51f58c052c11b076715e72929", - "sha256:a047682d324ba56e61b7ea7c7299d51e61fd3bca7dad2ccc39b72bd0118d60a1", - "sha256:a7ef8dd0bf2e1d0a27042b231a3baac6883cdd5557036f5e8df7139255feaac6", - "sha256:ad28cff53f60d99a928dfcf1e861e0b2ceb2bc1f08a074fdd601b314e1cc9e0a", - "sha256:b9097a208875fc7bbeb1286d0125d90bdfed961f61f214d3f5be62cd4ed8a446", - "sha256:b97fe7d7991c25e6a31e5d5e795986b18fbbb3107b873d5f3ae6dc9a103278e9", - "sha256:e0ec52ba3c7f1b7d813cd52649a5b3ef1fc0d433219dc8c93827c57eab6cf888", - "sha256:ea2c3ffb662fec8bbbfce5602e2c159ff097a4631d96235fcf0fb00e59e3ece4", - "sha256:fa3dec4ba8fb6e662770b74f62f1a0c7d4e37e25b58b2bf2c1be4c95372b4a33", - "sha256:fbeb725c9dc799a574518109336acccaf1303c30d45c075c665c0793c2f79a7f" + "sha256:0270572b8bd2c833c3981724b8ee9747b3ec96f699a9665470018594301439ee", + "sha256:111a0d8553afcf8eb02a4fea6ca4f59d48ddb34497aa8706a6cf536f1a5ec576", + "sha256:16a48c23a62a2f4a285699dba2e4ff2d1cff3115b9df052cdd976a18856d8e3d", + "sha256:1b95b98b0d2af784078fa69f637135e3c317091b615cd0905f8b8a087e86fa30", + "sha256:1f71c10d1e88467126f0efd484bd44bca5e14c664ec2ede64c32f20875c0d413", + "sha256:2424ff4c4ac7f6b8177b53c17ed5d8fa74ae5955656867f5a8affaca36a27abb", + "sha256:2bce03af1ce5a5567ab89bd90d11e7bbdff56b8af3acbbec1faded8f44cb06da", + "sha256:329906dcc7b20ff3cad13c069a78124ed8247adcac44b10bea1130e36caae0b4", + "sha256:37dd623507659e08be98eec89323469e8c7b4c1407c85112634ae3dbdb926fdd", + "sha256:3eaafe47ec0d0ffcc9349e1708be2aaea4c6dd4978d76bf6eb0cb2c13636c6fc", + "sha256:5e6275c09d2badf57aea3afa80d975444f4be8d3bc58f7f80d2a484c6f9485c8", + "sha256:6fe07eec95dfd477eb9530aef5bead34fec819b3aaf6c5bd6d20565da607bfe1", + "sha256:7367d7b2eca6513681127ebad53b2582911d1736dc2ffc19f2c3ae49997496bc", + "sha256:7cde5f38e614f55e28d831754e8a3bacf9ace5d1566235e39d91b35502d6936e", + "sha256:9481ffe3cf013b71b2428b905c4f7a9a4f76ec03065b05ff499bb5682a8d9ad8", + "sha256:98d8dc6d012b82287f2c3d26ce1d2dd130ec200c8679b6213b3c73c08b2b7940", + "sha256:a011a644f6d7d03736214d38832e030d8268bcff4a41f728e6030325fea3e400", + "sha256:a2913c5375154b6ef2e91c10b5720ea6e21007412f6437504ffea2109b5a33d7", + "sha256:a30596bae9403a342c978fb47d9b0ee277699fa53bbafad14706af51fe543d16", + "sha256:b03c2ae5d2f0fc05f9a2c0c997e1bc18c8229f392234e8a0194f202169ccd278", + "sha256:b6cd2203306b63e41acdf39aa93b86fb566049aeb6dc489b70e34bcd07adca74", + "sha256:b7ffe927ee6531c78f81aa17e684e2ff617daeba7f189f911065b2ea2d526dec", + "sha256:b8cac287fafc4ad485b8a9b67d0ee80c66bf3574f655d3b97ef2e1082360faf1", + "sha256:ba334e6e4b1d92442b75ddacc615c5476d4ad55cc29b15d590cc6b86efa487e2", + "sha256:ba3e4a42397c25b7ff88cdec6e2a16c2be18720f317506ee25210f6d31925f9c", + "sha256:c41fb5e6a5fe9ebcd58ca3abfeb51dffb5d83d6775405305bfa8715b76521922", + "sha256:cd2030f6650c089aeb304cf093f3244d34745ce0cfcc39f20c6fbfe030102e2a", + "sha256:cd65d75953847815962c84a4654a84850b2bb4aed3f26fadcc1c13892e1e29f6", + "sha256:e4985a790f921508f36f81831817cbc03b102d643b5fcb81cd33df3fa291a1a1", + "sha256:e807b3188f9eb0eaa7bbb579b462c5ace579f1cedb28107ce8b48a9f7ad3679e", + "sha256:f12764b8fffc7a123f641d7d049d382b73f96a34117e0b637b80643169cec8ac", + "sha256:f8837fe1d6ac4a8052a9a8ddab256bc006242696f03368a4009be7ee3075cdb7" ], "markers": "python_version >= '3.7'", - "version": "==42.0.2" + "version": "==42.0.5" }, "defusedxml": { "hashes": [ @@ -384,12 +384,12 @@ }, "faker": { "hashes": [ - "sha256:60e89e5c0b584e285a7db05eceba35011a241954afdab2853cb246c8a56700a2", - "sha256:b7f76bb1b2ac4cdc54442d955e36e477c387000f31ce46887fb9722a041be60b" + "sha256:117ce1a2805c1bc5ca753b3dc6f9d567732893b2294b827d3164261ee8f20267", + "sha256:458d93580de34403a8dec1e8d5e6be2fee96c4deca63b95d71df7a6a80a690de" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==23.1.0" + "version": "==23.3.0" }, "fred-epplib": { "git": "https://github.com/cisagov/epplib.git", @@ -404,61 +404,63 @@ }, "future": { "hashes": [ - "sha256:34a17436ed1e96697a86f9de3d15a3b0be01d8bc8de9c1dffd59fb8234ed5307" + "sha256:929292d34f5872e70396626ef385ec22355a1fae8ad29e1a734c3e43f9fbc216", + "sha256:bd2968309307861edae1458a4f8a4f3598c03be43b97521076aebf5d94c07b05" ], "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==0.18.3" + "version": "==1.0.0" }, "gevent": { "hashes": [ - "sha256:272cffdf535978d59c38ed837916dfd2b5d193be1e9e5dcc60a5f4d5025dd98a", - "sha256:2c7b5c9912378e5f5ccf180d1fdb1e83f42b71823483066eddbe10ef1a2fcaa2", - "sha256:36a549d632c14684bcbbd3014a6ce2666c5f2a500f34d58d32df6c9ea38b6535", - "sha256:4368f341a5f51611411ec3fc62426f52ac3d6d42eaee9ed0f9eebe715c80184e", - "sha256:43daf68496c03a35287b8b617f9f91e0e7c0d042aebcc060cadc3f049aadd653", - "sha256:455e5ee8103f722b503fa45dedb04f3ffdec978c1524647f8ba72b4f08490af1", - "sha256:45792c45d60f6ce3d19651d7fde0bc13e01b56bb4db60d3f32ab7d9ec467374c", - "sha256:4e24c2af9638d6c989caffc691a039d7c7022a31c0363da367c0d32ceb4a0648", - "sha256:52b4abf28e837f1865a9bdeef58ff6afd07d1d888b70b6804557e7908032e599", - "sha256:52e9f12cd1cda96603ce6b113d934f1aafb873e2c13182cf8e86d2c5c41982ea", - "sha256:5f3c781c84794926d853d6fb58554dc0dcc800ba25c41d42f6959c344b4db5a6", - "sha256:62d121344f7465e3739989ad6b91f53a6ca9110518231553fe5846dbe1b4518f", - "sha256:65883ac026731ac112184680d1f0f1e39fa6f4389fd1fc0bf46cc1388e2599f9", - "sha256:707904027d7130ff3e59ea387dddceedb133cc742b00b3ffe696d567147a9c9e", - "sha256:72c002235390d46f94938a96920d8856d4ffd9ddf62a303a0d7c118894097e34", - "sha256:7532c17bc6c1cbac265e751b95000961715adef35a25d2b0b1813aa7263fb397", - "sha256:78eebaf5e73ff91d34df48f4e35581ab4c84e22dd5338ef32714264063c57507", - "sha256:7c1abc6f25f475adc33e5fc2dbcc26a732608ac5375d0d306228738a9ae14d3b", - "sha256:7c28e38dcde327c217fdafb9d5d17d3e772f636f35df15ffae2d933a5587addd", - "sha256:7ccf0fd378257cb77d91c116e15c99e533374a8153632c48a3ecae7f7f4f09fe", - "sha256:921dda1c0b84e3d3b1778efa362d61ed29e2b215b90f81d498eb4d8eafcd0b7a", - "sha256:a2898b7048771917d85a1d548fd378e8a7b2ca963db8e17c6d90c76b495e0e2b", - "sha256:a3c5e9b1f766a7a64833334a18539a362fb563f6c4682f9634dea72cbe24f771", - "sha256:ada07076b380918829250201df1d016bdafb3acf352f35e5693b59dceee8dd2e", - "sha256:b101086f109168b23fa3586fccd1133494bdb97f86920a24dc0b23984dc30b69", - "sha256:bf456bd6b992eb0e1e869e2fd0caf817f0253e55ca7977fd0e72d0336a8c1c6a", - "sha256:bf7af500da05363e66f122896012acb6e101a552682f2352b618e541c941a011", - "sha256:c3e5d2fa532e4d3450595244de8ccf51f5721a05088813c1abd93ad274fe15e7", - "sha256:c84d34256c243b0a53d4335ef0bc76c735873986d478c53073861a92566a8d71", - "sha256:d163d59f1be5a4c4efcdd13c2177baaf24aadf721fdf2e1af9ee54a998d160f5", - "sha256:d57737860bfc332b9b5aa438963986afe90f49645f6e053140cfa0fa1bdae1ae", - "sha256:dbb22a9bbd6a13e925815ce70b940d1578dbe5d4013f20d23e8a11eddf8d14a7", - "sha256:dcb8612787a7f4626aa881ff15ff25439561a429f5b303048f0fca8a1c781c39", - "sha256:dd6c32ab977ecf7c7b8c2611ed95fa4aaebd69b74bf08f4b4960ad516861517d", - "sha256:de350fde10efa87ea60d742901e1053eb2127ebd8b59a7d3b90597eb4e586599", - "sha256:e1ead6863e596a8cc2a03e26a7a0981f84b6b3e956101135ff6d02df4d9a6b07", - "sha256:ed7a048d3e526a5c1d55c44cb3bc06cfdc1947d06d45006cc4cf60dedc628904", - "sha256:f632487c87866094546a74eefbca2c74c1d03638b715b6feb12e80120960185a", - "sha256:fae8d5b5b8fa2a8f63b39f5447168b02db10c888a3e387ed7af2bd1b8612e543", - "sha256:fde6402c5432b835fbb7698f1c7f2809c8d6b2bd9d047ac1f5a7c1d5aa569303" + "sha256:03aa5879acd6b7076f6a2a307410fb1e0d288b84b03cdfd8c74db8b4bc882fc5", + "sha256:117e5837bc74a1673605fb53f8bfe22feb6e5afa411f524c835b2ddf768db0de", + "sha256:141a2b24ad14f7b9576965c0c84927fc85f824a9bb19f6ec1e61e845d87c9cd8", + "sha256:14532a67f7cb29fb055a0e9b39f16b88ed22c66b96641df8c04bdc38c26b9ea5", + "sha256:1dffb395e500613e0452b9503153f8f7ba587c67dd4a85fc7cd7aa7430cb02cc", + "sha256:2955eea9c44c842c626feebf4459c42ce168685aa99594e049d03bedf53c2800", + "sha256:2ae3a25ecce0a5b0cd0808ab716bfca180230112bb4bc89b46ae0061d62d4afe", + "sha256:2e9ac06f225b696cdedbb22f9e805e2dd87bf82e8fa5e17756f94e88a9d37cf7", + "sha256:368a277bd9278ddb0fde308e6a43f544222d76ed0c4166e0d9f6b036586819d9", + "sha256:3adfb96637f44010be8abd1b5e73b5070f851b817a0b182e601202f20fa06533", + "sha256:3d5325ccfadfd3dcf72ff88a92fb8fc0b56cacc7225f0f4b6dcf186c1a6eeabc", + "sha256:432fc76f680acf7cf188c2ee0f5d3ab73b63c1f03114c7cd8a34cebbe5aa2056", + "sha256:44098038d5e2749b0784aabb27f1fcbb3f43edebedf64d0af0d26955611be8d6", + "sha256:5a1df555431f5cd5cc189a6ee3544d24f8c52f2529134685f1e878c4972ab026", + "sha256:6c47ae7d1174617b3509f5d884935e788f325eb8f1a7efc95d295c68d83cce40", + "sha256:6f947a9abc1a129858391b3d9334c45041c08a0f23d14333d5b844b6e5c17a07", + "sha256:782a771424fe74bc7e75c228a1da671578c2ba4ddb2ca09b8f959abdf787331e", + "sha256:7899a38d0ae7e817e99adb217f586d0a4620e315e4de577444ebeeed2c5729be", + "sha256:7b00f8c9065de3ad226f7979154a7b27f3b9151c8055c162332369262fc025d8", + "sha256:8f4b8e777d39013595a7740b4463e61b1cfe5f462f1b609b28fbc1e4c4ff01e5", + "sha256:90cbac1ec05b305a1b90ede61ef73126afdeb5a804ae04480d6da12c56378df1", + "sha256:918cdf8751b24986f915d743225ad6b702f83e1106e08a63b736e3a4c6ead789", + "sha256:9202f22ef811053077d01f43cc02b4aaf4472792f9fd0f5081b0b05c926cca19", + "sha256:94138682e68ec197db42ad7442d3cf9b328069c3ad8e4e5022e6b5cd3e7ffae5", + "sha256:968581d1717bbcf170758580f5f97a2925854943c45a19be4d47299507db2eb7", + "sha256:9d8d0642c63d453179058abc4143e30718b19a85cbf58c2744c9a63f06a1d388", + "sha256:a7ceb59986456ce851160867ce4929edaffbd2f069ae25717150199f8e1548b8", + "sha256:b9913c45d1be52d7a5db0c63977eebb51f68a2d5e6fd922d1d9b5e5fd758cc98", + "sha256:bde283313daf0b34a8d1bab30325f5cb0f4e11b5869dbe5bc61f8fe09a8f66f3", + "sha256:bf5b9c72b884c6f0c4ed26ef204ee1f768b9437330422492c319470954bc4cc7", + "sha256:ca80b121bbec76d7794fcb45e65a7eca660a76cc1a104ed439cdbd7df5f0b060", + "sha256:cdf66977a976d6a3cfb006afdf825d1482f84f7b81179db33941f2fc9673bb1d", + "sha256:d4faf846ed132fd7ebfbbf4fde588a62d21faa0faa06e6f468b7faa6f436b661", + "sha256:d7f87c2c02e03d99b95cfa6f7a776409083a9e4d468912e18c7680437b29222c", + "sha256:dd23df885318391856415e20acfd51a985cba6919f0be78ed89f5db9ff3a31cb", + "sha256:f5de3c676e57177b38857f6e3cdfbe8f38d1cd754b63200c0615eaa31f514b4f", + "sha256:f5e8e8d60e18d5f7fd49983f0c4696deeddaf6e608fbab33397671e2fcc6cc91", + "sha256:f7cac622e11b4253ac4536a654fe221249065d9a69feb6cdcd4d9af3503602e0", + "sha256:f8a04cf0c5b7139bc6368b461257d4a757ea2fe89b3773e494d235b7dd51119f", + "sha256:f8bb35ce57a63c9a6896c71a285818a3922d8ca05d150fd1fe49a7f57287b836", + "sha256:fbfdce91239fe306772faab57597186710d5699213f4df099d1612da7320d682" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==23.9.1" + "version": "==24.2.1" }, "geventconnpool": { "git": "https://github.com/rasky/geventconnpool.git", - "ref": "1bbb93a714a331a069adf27265fe582d9ba7ecd4" + "ref": null }, "greenlet": { "hashes": [ @@ -710,11 +712,11 @@ }, "marshmallow": { "hashes": [ - "sha256:4c1daff273513dc5eb24b219a8035559dc573c8f322558ef85f5438ddd1236dd", - "sha256:c21d4b98fee747c130e6bc8f45c4b3199ea66bc00c12ee1f639f0aeca034d5e9" + "sha256:20f53be28c6e374a711a16165fb22a8dc6003e3f7cda1285e3ca777b9193885b", + "sha256:e7997f83571c7fd476042c2c188e4ee8a78900ca5e74bd9c8097afa56624e9bd" ], "markers": "python_version >= '3.8'", - "version": "==3.20.2" + "version": "==3.21.0" }, "oic": { "hashes": [ @@ -742,10 +744,10 @@ }, "phonenumberslite": { "hashes": [ - "sha256:2b04a53401d01ab42564c1abc762fc9808ad398e71dacfa3b38d4321e112ecb3", - "sha256:74e3ee63dfa2bb562ce2e6ce74ce76ae74a2f81472005b80343235fb43426db4" + "sha256:137d53d5d78dca30bc2becf81a3e2ac74deb8f0997e9bbe44de515ece4bd92bd", + "sha256:e1f4359bff90c86d1b52db0e726d3334df00cc7d9c9c2ef66561d5f7a774d4ba" ], - "version": "==8.13.29" + "version": "==8.13.31" }, "psycopg2-binary": { "hashes": [ @@ -874,104 +876,104 @@ }, "pydantic": { "hashes": [ - "sha256:0b6a909df3192245cb736509a92ff69e4fef76116feffec68e93a567347bae6f", - "sha256:4fd5c182a2488dc63e6d32737ff19937888001e2a6d86e94b3f233104a5d1fa9" + "sha256:72c6034df47f46ccdf81869fddb81aade68056003900a8724a4f160700016a2a", + "sha256:e07805c4c7f5c6826e33a1d4c9d47950d7eaf34868e2690f8594d2e30241f11f" ], "markers": "python_version >= '3.8'", - "version": "==2.6.1" + "version": "==2.6.3" }, "pydantic-core": { "hashes": [ - "sha256:02906e7306cb8c5901a1feb61f9ab5e5c690dbbeaa04d84c1b9ae2a01ebe9379", - "sha256:0ba503850d8b8dcc18391f10de896ae51d37fe5fe43dbfb6a35c5c5cad271a06", - "sha256:16aa02e7a0f539098e215fc193c8926c897175d64c7926d00a36188917717a05", - "sha256:18de31781cdc7e7b28678df7c2d7882f9692ad060bc6ee3c94eb15a5d733f8f7", - "sha256:22c5f022799f3cd6741e24f0443ead92ef42be93ffda0d29b2597208c94c3753", - "sha256:2924b89b16420712e9bb8192396026a8fbd6d8726224f918353ac19c4c043d2a", - "sha256:308974fdf98046db28440eb3377abba274808bf66262e042c412eb2adf852731", - "sha256:396fdf88b1b503c9c59c84a08b6833ec0c3b5ad1a83230252a9e17b7dfb4cffc", - "sha256:3ac426704840877a285d03a445e162eb258924f014e2f074e209d9b4ff7bf380", - "sha256:3b052c753c4babf2d1edc034c97851f867c87d6f3ea63a12e2700f159f5c41c3", - "sha256:3fab4e75b8c525a4776e7630b9ee48aea50107fea6ca9f593c98da3f4d11bf7c", - "sha256:406fac1d09edc613020ce9cf3f2ccf1a1b2f57ab00552b4c18e3d5276c67eb11", - "sha256:40a0bd0bed96dae5712dab2aba7d334a6c67cbcac2ddfca7dbcc4a8176445990", - "sha256:41dac3b9fce187a25c6253ec79a3f9e2a7e761eb08690e90415069ea4a68ff7a", - "sha256:459c0d338cc55d099798618f714b21b7ece17eb1a87879f2da20a3ff4c7628e2", - "sha256:459d6be6134ce3b38e0ef76f8a672924460c455d45f1ad8fdade36796df1ddc8", - "sha256:46b0d5520dbcafea9a8645a8164658777686c5c524d381d983317d29687cce97", - "sha256:47924039e785a04d4a4fa49455e51b4eb3422d6eaacfde9fc9abf8fdef164e8a", - "sha256:4bfcbde6e06c56b30668a0c872d75a7ef3025dc3c1823a13cf29a0e9b33f67e8", - "sha256:4f9ee4febb249c591d07b2d4dd36ebcad0ccd128962aaa1801508320896575ef", - "sha256:55749f745ebf154c0d63d46c8c58594d8894b161928aa41adbb0709c1fe78b77", - "sha256:5864b0242f74b9dd0b78fd39db1768bc3f00d1ffc14e596fd3e3f2ce43436a33", - "sha256:5f60f920691a620b03082692c378661947d09415743e437a7478c309eb0e4f82", - "sha256:60eb8ceaa40a41540b9acae6ae7c1f0a67d233c40dc4359c256ad2ad85bdf5e5", - "sha256:69a7b96b59322a81c2203be537957313b07dd333105b73db0b69212c7d867b4b", - "sha256:6ad84731a26bcfb299f9eab56c7932d46f9cad51c52768cace09e92a19e4cf55", - "sha256:6db58c22ac6c81aeac33912fb1af0e930bc9774166cdd56eade913d5f2fff35e", - "sha256:70651ff6e663428cea902dac297066d5c6e5423fda345a4ca62430575364d62b", - "sha256:72f7919af5de5ecfaf1eba47bf9a5d8aa089a3340277276e5636d16ee97614d7", - "sha256:732bd062c9e5d9582a30e8751461c1917dd1ccbdd6cafb032f02c86b20d2e7ec", - "sha256:7924e54f7ce5d253d6160090ddc6df25ed2feea25bfb3339b424a9dd591688bc", - "sha256:7afb844041e707ac9ad9acad2188a90bffce2c770e6dc2318be0c9916aef1469", - "sha256:7b883af50eaa6bb3299780651e5be921e88050ccf00e3e583b1e92020333304b", - "sha256:7beec26729d496a12fd23cf8da9944ee338c8b8a17035a560b585c36fe81af20", - "sha256:7bf26c2e2ea59d32807081ad51968133af3025c4ba5753e6a794683d2c91bf6e", - "sha256:7c31669e0c8cc68400ef0c730c3a1e11317ba76b892deeefaf52dcb41d56ed5d", - "sha256:7e6231aa5bdacda78e96ad7b07d0c312f34ba35d717115f4b4bff6cb87224f0f", - "sha256:870dbfa94de9b8866b37b867a2cb37a60c401d9deb4a9ea392abf11a1f98037b", - "sha256:88646cae28eb1dd5cd1e09605680c2b043b64d7481cdad7f5003ebef401a3039", - "sha256:8aafeedb6597a163a9c9727d8a8bd363a93277701b7bfd2749fbefee2396469e", - "sha256:8bde5b48c65b8e807409e6f20baee5d2cd880e0fad00b1a811ebc43e39a00ab2", - "sha256:8f9142a6ed83d90c94a3efd7af8873bf7cefed2d3d44387bf848888482e2d25f", - "sha256:936a787f83db1f2115ee829dd615c4f684ee48ac4de5779ab4300994d8af325b", - "sha256:98dc6f4f2095fc7ad277782a7c2c88296badcad92316b5a6e530930b1d475ebc", - "sha256:9957433c3a1b67bdd4c63717eaf174ebb749510d5ea612cd4e83f2d9142f3fc8", - "sha256:99af961d72ac731aae2a1b55ccbdae0733d816f8bfb97b41909e143de735f522", - "sha256:9b5f13857da99325dcabe1cc4e9e6a3d7b2e2c726248ba5dd4be3e8e4a0b6d0e", - "sha256:9d776d30cde7e541b8180103c3f294ef7c1862fd45d81738d156d00551005784", - "sha256:9da90d393a8227d717c19f5397688a38635afec89f2e2d7af0df037f3249c39a", - "sha256:a3b7352b48fbc8b446b75f3069124e87f599d25afb8baa96a550256c031bb890", - "sha256:a477932664d9611d7a0816cc3c0eb1f8856f8a42435488280dfbf4395e141485", - "sha256:a7e41e3ada4cca5f22b478c08e973c930e5e6c7ba3588fb8e35f2398cdcc1545", - "sha256:a90fec23b4b05a09ad988e7a4f4e081711a90eb2a55b9c984d8b74597599180f", - "sha256:a9e523474998fb33f7c1a4d55f5504c908d57add624599e095c20fa575b8d943", - "sha256:aa057095f621dad24a1e906747179a69780ef45cc8f69e97463692adbcdae878", - "sha256:aa6c8c582036275997a733427b88031a32ffa5dfc3124dc25a730658c47a572f", - "sha256:ae34418b6b389d601b31153b84dce480351a352e0bb763684a1b993d6be30f17", - "sha256:b0d7a9165167269758145756db43a133608a531b1e5bb6a626b9ee24bc38a8f7", - "sha256:b30b0dd58a4509c3bd7eefddf6338565c4905406aee0c6e4a5293841411a1286", - "sha256:b8f9186ca45aee030dc8234118b9c0784ad91a0bb27fc4e7d9d6608a5e3d386c", - "sha256:b94cbda27267423411c928208e89adddf2ea5dd5f74b9528513f0358bba019cb", - "sha256:cc6f6c9be0ab6da37bc77c2dda5f14b1d532d5dbef00311ee6e13357a418e646", - "sha256:ce232a6170dd6532096cadbf6185271e4e8c70fc9217ebe105923ac105da9978", - "sha256:cf903310a34e14651c9de056fcc12ce090560864d5a2bb0174b971685684e1d8", - "sha256:d5362d099c244a2d2f9659fb3c9db7c735f0004765bbe06b99be69fbd87c3f15", - "sha256:dffaf740fe2e147fedcb6b561353a16243e654f7fe8e701b1b9db148242e1272", - "sha256:e0f686549e32ccdb02ae6f25eee40cc33900910085de6aa3790effd391ae10c2", - "sha256:e4b52776a2e3230f4854907a1e0946eec04d41b1fc64069ee774876bbe0eab55", - "sha256:e4ba0884a91f1aecce75202473ab138724aa4fb26d7707f2e1fa6c3e68c84fbf", - "sha256:e6294e76b0380bb7a61eb8a39273c40b20beb35e8c87ee101062834ced19c545", - "sha256:ebb892ed8599b23fa8f1799e13a12c87a97a6c9d0f497525ce9858564c4575a4", - "sha256:eca58e319f4fd6df004762419612122b2c7e7d95ffafc37e890252f869f3fb2a", - "sha256:ed957db4c33bc99895f3a1672eca7e80e8cda8bd1e29a80536b4ec2153fa9804", - "sha256:ef551c053692b1e39e3f7950ce2296536728871110e7d75c4e7753fb30ca87f4", - "sha256:ef6113cd31411eaf9b39fc5a8848e71c72656fd418882488598758b2c8c6dfa0", - "sha256:f685dbc1fdadb1dcd5b5e51e0a378d4685a891b2ddaf8e2bba89bd3a7144e44a", - "sha256:f8ed79883b4328b7f0bd142733d99c8e6b22703e908ec63d930b06be3a0e7113", - "sha256:fe56851c3f1d6f5384b3051c536cc81b3a93a73faf931f404fef95217cf1e10d", - "sha256:ff7c97eb7a29aba230389a2661edf2e9e06ce616c7e35aa764879b6894a44b25" + "sha256:00ee1c97b5364b84cb0bd82e9bbf645d5e2871fb8c58059d158412fee2d33d8a", + "sha256:0d32576b1de5a30d9a97f300cc6a3f4694c428d956adbc7e6e2f9cad279e45ed", + "sha256:0df446663464884297c793874573549229f9eca73b59360878f382a0fc085979", + "sha256:0f56ae86b60ea987ae8bcd6654a887238fd53d1384f9b222ac457070b7ac4cff", + "sha256:13dcc4802961b5f843a9385fc821a0b0135e8c07fc3d9949fd49627c1a5e6ae5", + "sha256:162e498303d2b1c036b957a1278fa0899d02b2842f1ff901b6395104c5554a45", + "sha256:1b662180108c55dfbf1280d865b2d116633d436cfc0bba82323554873967b340", + "sha256:1cac689f80a3abab2d3c0048b29eea5751114054f032a941a32de4c852c59cad", + "sha256:21b888c973e4f26b7a96491c0965a8a312e13be108022ee510248fe379a5fa23", + "sha256:287073c66748f624be4cef893ef9174e3eb88fe0b8a78dc22e88eca4bc357ca6", + "sha256:2a1ef6a36fdbf71538142ed604ad19b82f67b05749512e47f247a6ddd06afdc7", + "sha256:2a72fb9963cba4cd5793854fd12f4cfee731e86df140f59ff52a49b3552db241", + "sha256:2acca2be4bb2f2147ada8cac612f8a98fc09f41c89f87add7256ad27332c2fda", + "sha256:2f583bd01bbfbff4eaee0868e6fc607efdfcc2b03c1c766b06a707abbc856187", + "sha256:33809aebac276089b78db106ee692bdc9044710e26f24a9a2eaa35a0f9fa70ba", + "sha256:36fa178aacbc277bc6b62a2c3da95226520da4f4e9e206fdf076484363895d2c", + "sha256:4204e773b4b408062960e65468d5346bdfe139247ee5f1ca2a378983e11388a2", + "sha256:4384a8f68ddb31a0b0c3deae88765f5868a1b9148939c3f4121233314ad5532c", + "sha256:456855f57b413f077dff513a5a28ed838dbbb15082ba00f80750377eed23d132", + "sha256:49d5d58abd4b83fb8ce763be7794d09b2f50f10aa65c0f0c1696c677edeb7cbf", + "sha256:4ac6b4ce1e7283d715c4b729d8f9dab9627586dafce81d9eaa009dd7f25dd972", + "sha256:4df8a199d9f6afc5ae9a65f8f95ee52cae389a8c6b20163762bde0426275b7db", + "sha256:500960cb3a0543a724a81ba859da816e8cf01b0e6aaeedf2c3775d12ee49cade", + "sha256:519ae0312616026bf4cedc0fe459e982734f3ca82ee8c7246c19b650b60a5ee4", + "sha256:578114bc803a4c1ff9946d977c221e4376620a46cf78da267d946397dc9514a8", + "sha256:5c5cbc703168d1b7a838668998308018a2718c2130595e8e190220238addc96f", + "sha256:6162f8d2dc27ba21027f261e4fa26f8bcb3cf9784b7f9499466a311ac284b5b9", + "sha256:704d35ecc7e9c31d48926150afada60401c55efa3b46cd1ded5a01bdffaf1d48", + "sha256:716b542728d4c742353448765aa7cdaa519a7b82f9564130e2b3f6766018c9ec", + "sha256:72282ad4892a9fb2da25defeac8c2e84352c108705c972db82ab121d15f14e6d", + "sha256:7233d65d9d651242a68801159763d09e9ec96e8a158dbf118dc090cd77a104c9", + "sha256:732da3243e1b8d3eab8c6ae23ae6a58548849d2e4a4e03a1924c8ddf71a387cb", + "sha256:75b81e678d1c1ede0785c7f46690621e4c6e63ccd9192af1f0bd9d504bbb6bf4", + "sha256:75f76ee558751746d6a38f89d60b6228fa174e5172d143886af0f85aa306fd89", + "sha256:7ee8d5f878dccb6d499ba4d30d757111847b6849ae07acdd1205fffa1fc1253c", + "sha256:7f752826b5b8361193df55afcdf8ca6a57d0232653494ba473630a83ba50d8c9", + "sha256:86b3d0033580bd6bbe07590152007275bd7af95f98eaa5bd36f3da219dcd93da", + "sha256:8d62da299c6ecb04df729e4b5c52dc0d53f4f8430b4492b93aa8de1f541c4aac", + "sha256:8e47755d8152c1ab5b55928ab422a76e2e7b22b5ed8e90a7d584268dd49e9c6b", + "sha256:9091632a25b8b87b9a605ec0e61f241c456e9248bfdcf7abdf344fdb169c81cf", + "sha256:936e5db01dd49476fa8f4383c259b8b1303d5dd5fb34c97de194560698cc2c5e", + "sha256:99b6add4c0b39a513d323d3b93bc173dac663c27b99860dd5bf491b240d26137", + "sha256:9c865a7ee6f93783bd5d781af5a4c43dadc37053a5b42f7d18dc019f8c9d2bd1", + "sha256:a425479ee40ff021f8216c9d07a6a3b54b31c8267c6e17aa88b70d7ebd0e5e5b", + "sha256:a4b2bf78342c40b3dc830880106f54328928ff03e357935ad26c7128bbd66ce8", + "sha256:a6b1bb0827f56654b4437955555dc3aeeebeddc47c2d7ed575477f082622c49e", + "sha256:aaf09e615a0bf98d406657e0008e4a8701b11481840be7d31755dc9f97c44053", + "sha256:b1f6f5938d63c6139860f044e2538baeee6f0b251a1816e7adb6cbce106a1f01", + "sha256:b29eeb887aa931c2fcef5aa515d9d176d25006794610c264ddc114c053bf96fe", + "sha256:b3992a322a5617ded0a9f23fd06dbc1e4bd7cf39bc4ccf344b10f80af58beacd", + "sha256:b5b6079cc452a7c53dd378c6f881ac528246b3ac9aae0f8eef98498a75657805", + "sha256:b60cc1a081f80a2105a59385b92d82278b15d80ebb3adb200542ae165cd7d183", + "sha256:b926dd38db1519ed3043a4de50214e0d600d404099c3392f098a7f9d75029ff8", + "sha256:bd87f48924f360e5d1c5f770d6155ce0e7d83f7b4e10c2f9ec001c73cf475c99", + "sha256:bda1ee3e08252b8d41fa5537413ffdddd58fa73107171a126d3b9ff001b9b820", + "sha256:be0ec334369316fa73448cc8c982c01e5d2a81c95969d58b8f6e272884df0074", + "sha256:c6119dc90483a5cb50a1306adb8d52c66e447da88ea44f323e0ae1a5fcb14256", + "sha256:c9803edf8e29bd825f43481f19c37f50d2b01899448273b3a7758441b512acf8", + "sha256:c9bd22a2a639e26171068f8ebb5400ce2c1bc7d17959f60a3b753ae13c632975", + "sha256:cbcc558401de90a746d02ef330c528f2e668c83350f045833543cd57ecead1ad", + "sha256:cf6204fe865da605285c34cf1172879d0314ff267b1c35ff59de7154f35fdc2e", + "sha256:d33dd21f572545649f90c38c227cc8631268ba25c460b5569abebdd0ec5974ca", + "sha256:d89ca19cdd0dd5f31606a9329e309d4fcbb3df860960acec32630297d61820df", + "sha256:d8f99b147ff3fcf6b3cc60cb0c39ea443884d5559a30b1481e92495f2310ff2b", + "sha256:d937653a696465677ed583124b94a4b2d79f5e30b2c46115a68e482c6a591c8a", + "sha256:dcca5d2bf65c6fb591fff92da03f94cd4f315972f97c21975398bd4bd046854a", + "sha256:ded1c35f15c9dea16ead9bffcde9bb5c7c031bff076355dc58dcb1cb436c4721", + "sha256:e3e70c94a0c3841e6aa831edab1619ad5c511199be94d0c11ba75fe06efe107a", + "sha256:e56f8186d6210ac7ece503193ec84104da7ceb98f68ce18c07282fcc2452e76f", + "sha256:e7774b570e61cb998490c5235740d475413a1f6de823169b4cf94e2fe9e9f6b2", + "sha256:e7c6ed0dc9d8e65f24f5824291550139fe6f37fac03788d4580da0d33bc00c97", + "sha256:ec08be75bb268473677edb83ba71e7e74b43c008e4a7b1907c6d57e940bf34b6", + "sha256:ecdf6bf5f578615f2e985a5e1f6572e23aa632c4bd1dc67f8f406d445ac115ed", + "sha256:ed25e1835c00a332cb10c683cd39da96a719ab1dfc08427d476bce41b92531fc", + "sha256:f4cb85f693044e0f71f394ff76c98ddc1bc0953e48c061725e540396d5c8a2e1", + "sha256:f53aace168a2a10582e570b7736cc5bef12cae9cf21775e3eafac597e8551fbe", + "sha256:f651dd19363c632f4abe3480a7c87a9773be27cfe1341aef06e8759599454120", + "sha256:fc4ad7f7ee1a13d9cb49d8198cd7d7e3aa93e425f371a68235f784e99741561f", + "sha256:fee427241c2d9fb7192b658190f9f5fd6dfe41e02f3c1489d2ec1e6a5ab1e04a" ], "markers": "python_version >= '3.8'", - "version": "==2.16.2" + "version": "==2.16.3" }, "pydantic-settings": { "hashes": [ - "sha256:26b1492e0a24755626ac5e6d715e9077ab7ad4fb5f19a8b7ed7011d52f36141c", - "sha256:7621c0cb5d90d1140d2f0ef557bdf03573aac7035948109adf2574770b77605a" + "sha256:00b9f6a5e95553590434c0fa01ead0b216c3e10bc54ae02e37f359948643c5ed", + "sha256:0235391d26db4d2190cb9b31051c4b46882d28a51533f97440867f012d4da091" ], "markers": "python_version >= '3.8'", - "version": "==2.1.0" + "version": "==2.2.1" }, "pyjwkest": { "hashes": [ @@ -996,6 +998,15 @@ "markers": "python_version >= '3.8'", "version": "==1.0.1" }, + "pyzipper": { + "hashes": [ + "sha256:0adca90a00c36a93fbe49bfa8c5add452bfe4ef85a1b8e3638739dd1c7b26bfc", + "sha256:6d097f465bfa47796b1494e12ea65d1478107d38e13bc56f6e58eedc4f6c1a87" + ], + "index": "pypi", + "markers": "python_version >= '3.4'", + "version": "==0.3.6" + }, "requests": { "hashes": [ "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f", @@ -1015,11 +1026,11 @@ }, "setuptools": { "hashes": [ - "sha256:385eb4edd9c9d5c17540511303e39a147ce2fc04bc55289c322b9e5904fe2c05", - "sha256:be1af57fc409f93647f2e8e4573a142ed38724b8cdd389706a867bb4efcf1e78" + "sha256:02fa291a0471b3a18b2b2481ed902af520c69e8ae0919c13da936542754b4c56", + "sha256:5c0806c7d9af348e6dd3777b4f4dbb42c7ad85b190104837488eab9a7c945cf8" ], "markers": "python_version >= '3.8'", - "version": "==69.0.3" + "version": "==69.1.1" }, "six": { "hashes": [ @@ -1039,12 +1050,12 @@ }, "typing-extensions": { "hashes": [ - "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783", - "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd" + "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475", + "sha256:b0abd7c89e8fb96f98db18d86106ff1d90ab692004eb746cf6eda2682f91b3cb" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==4.9.0" + "version": "==4.10.0" }, "urllib3": { "hashes": [ @@ -1073,45 +1084,45 @@ }, "zope.interface": { "hashes": [ - "sha256:0c8cf55261e15590065039696607f6c9c1aeda700ceee40c70478552d323b3ff", - "sha256:13b7d0f2a67eb83c385880489dbb80145e9d344427b4262c49fbf2581677c11c", - "sha256:1f294a15f7723fc0d3b40701ca9b446133ec713eafc1cc6afa7b3d98666ee1ac", - "sha256:239a4a08525c080ff833560171d23b249f7f4d17fcbf9316ef4159f44997616f", - "sha256:2f8d89721834524a813f37fa174bac074ec3d179858e4ad1b7efd4401f8ac45d", - "sha256:2fdc7ccbd6eb6b7df5353012fbed6c3c5d04ceaca0038f75e601060e95345309", - "sha256:34c15ca9248f2e095ef2e93af2d633358c5f048c49fbfddf5fdfc47d5e263736", - "sha256:387545206c56b0315fbadb0431d5129c797f92dc59e276b3ce82db07ac1c6179", - "sha256:43b576c34ef0c1f5a4981163b551a8781896f2a37f71b8655fd20b5af0386abb", - "sha256:57d0a8ce40ce440f96a2c77824ee94bf0d0925e6089df7366c2272ccefcb7941", - "sha256:5a804abc126b33824a44a7aa94f06cd211a18bbf31898ba04bd0924fbe9d282d", - "sha256:67be3ca75012c6e9b109860820a8b6c9a84bfb036fbd1076246b98e56951ca92", - "sha256:6af47f10cfc54c2ba2d825220f180cc1e2d4914d783d6fc0cd93d43d7bc1c78b", - "sha256:6dc998f6de015723196a904045e5a2217f3590b62ea31990672e31fbc5370b41", - "sha256:70d2cef1bf529bff41559be2de9d44d47b002f65e17f43c73ddefc92f32bf00f", - "sha256:7ebc4d34e7620c4f0da7bf162c81978fce0ea820e4fa1e8fc40ee763839805f3", - "sha256:964a7af27379ff4357dad1256d9f215047e70e93009e532d36dcb8909036033d", - "sha256:97806e9ca3651588c1baaebb8d0c5ee3db95430b612db354c199b57378312ee8", - "sha256:9b9bc671626281f6045ad61d93a60f52fd5e8209b1610972cf0ef1bbe6d808e3", - "sha256:9ffdaa5290422ac0f1688cb8adb1b94ca56cee3ad11f29f2ae301df8aecba7d1", - "sha256:a0da79117952a9a41253696ed3e8b560a425197d4e41634a23b1507efe3273f1", - "sha256:a41f87bb93b8048fe866fa9e3d0c51e27fe55149035dcf5f43da4b56732c0a40", - "sha256:aa6fd016e9644406d0a61313e50348c706e911dca29736a3266fc9e28ec4ca6d", - "sha256:ad54ed57bdfa3254d23ae04a4b1ce405954969c1b0550cc2d1d2990e8b439de1", - "sha256:b012d023b4fb59183909b45d7f97fb493ef7a46d2838a5e716e3155081894605", - "sha256:b51b64432eed4c0744241e9ce5c70dcfecac866dff720e746d0a9c82f371dfa7", - "sha256:bbe81def9cf3e46f16ce01d9bfd8bea595e06505e51b7baf45115c77352675fd", - "sha256:c9559138690e1bd4ea6cd0954d22d1e9251e8025ce9ede5d0af0ceae4a401e43", - "sha256:e30506bcb03de8983f78884807e4fd95d8db6e65b69257eea05d13d519b83ac0", - "sha256:e33e86fd65f369f10608b08729c8f1c92ec7e0e485964670b4d2633a4812d36b", - "sha256:e441e8b7d587af0414d25e8d05e27040d78581388eed4c54c30c0c91aad3a379", - "sha256:e8bb9c990ca9027b4214fa543fd4025818dc95f8b7abce79d61dc8a2112b561a", - "sha256:ef43ee91c193f827e49599e824385ec7c7f3cd152d74cb1dfe02cb135f264d83", - "sha256:ef467d86d3cfde8b39ea1b35090208b0447caaabd38405420830f7fd85fbdd56", - "sha256:f89b28772fc2562ed9ad871c865f5320ef761a7fcc188a935e21fe8b31a38ca9", - "sha256:fddbab55a2473f1d3b8833ec6b7ac31e8211b0aa608df5ab09ce07f3727326de" + "sha256:02adbab560683c4eca3789cc0ac487dcc5f5a81cc48695ec247f00803cafe2fe", + "sha256:14e02a6fc1772b458ebb6be1c276528b362041217b9ca37e52ecea2cbdce9fac", + "sha256:25e0af9663eeac6b61b231b43c52293c2cb7f0c232d914bdcbfd3e3bd5c182ad", + "sha256:2606955a06c6852a6cff4abeca38346ed01e83f11e960caa9a821b3626a4467b", + "sha256:396f5c94654301819a7f3a702c5830f0ea7468d7b154d124ceac823e2419d000", + "sha256:3b240883fb43160574f8f738e6d09ddbdbf8fa3e8cea051603d9edfd947d9328", + "sha256:3b6c62813c63c543a06394a636978b22dffa8c5410affc9331ce6cdb5bfa8565", + "sha256:4ae9793f114cee5c464cc0b821ae4d36e1eba961542c6086f391a61aee167b6f", + "sha256:4bce517b85f5debe07b186fc7102b332676760f2e0c92b7185dd49c138734b70", + "sha256:4d45d2ba8195850e3e829f1f0016066a122bfa362cc9dc212527fc3d51369037", + "sha256:4dd374927c00764fcd6fe1046bea243ebdf403fba97a937493ae4be2c8912c2b", + "sha256:506f5410b36e5ba494136d9fa04c548eaf1a0d9c442b0b0e7a0944db7620e0ab", + "sha256:59f7374769b326a217d0b2366f1c176a45a4ff21e8f7cebb3b4a3537077eff85", + "sha256:5ee9789a20b0081dc469f65ff6c5007e67a940d5541419ca03ef20c6213dd099", + "sha256:6fc711acc4a1c702ca931fdbf7bf7c86f2a27d564c85c4964772dadf0e3c52f5", + "sha256:75d2ec3d9b401df759b87bc9e19d1b24db73083147089b43ae748aefa63067ef", + "sha256:76e0531d86523be7a46e15d379b0e975a9db84316617c0efe4af8338dc45b80c", + "sha256:8af82afc5998e1f307d5e72712526dba07403c73a9e287d906a8aa2b1f2e33dd", + "sha256:8f5d2c39f3283e461de3655e03faf10e4742bb87387113f787a7724f32db1e48", + "sha256:97785604824981ec8c81850dd25c8071d5ce04717a34296eeac771231fbdd5cd", + "sha256:a3046e8ab29b590d723821d0785598e0b2e32b636a0272a38409be43e3ae0550", + "sha256:abb0b3f2cb606981c7432f690db23506b1db5899620ad274e29dbbbdd740e797", + "sha256:ac7c2046d907e3b4e2605a130d162b1b783c170292a11216479bb1deb7cadebe", + "sha256:af27b3fe5b6bf9cd01b8e1c5ddea0a0d0a1b8c37dc1c7452f1e90bf817539c6d", + "sha256:b386b8b9d2b6a5e1e4eadd4e62335571244cb9193b7328c2b6e38b64cfda4f0e", + "sha256:b66335bbdbb4c004c25ae01cc4a54fd199afbc1fd164233813c6d3c2293bb7e1", + "sha256:d54f66c511ea01b9ef1d1a57420a93fbb9d48a08ec239f7d9c581092033156d0", + "sha256:de125151a53ecdb39df3cb3deb9951ed834dd6a110a9e795d985b10bb6db4532", + "sha256:de7916380abaef4bb4891740879b1afcba2045aee51799dfd6d6ca9bdc71f35f", + "sha256:e2fefad268ff5c5b314794e27e359e48aeb9c8bb2cbb5748a071757a56f6bb8f", + "sha256:e7b2bed4eea047a949296e618552d3fed00632dc1b795ee430289bdd0e3717f3", + "sha256:e87698e2fea5ca2f0a99dff0a64ce8110ea857b640de536c76d92aaa2a91ff3a", + "sha256:ede888382882f07b9e4cd942255921ffd9f2901684198b88e247c7eabd27a000", + "sha256:f444de0565db46d26c9fa931ca14f497900a295bd5eba480fc3fad25af8c763e", + "sha256:fa994e8937e8ccc7e87395b7b35092818905cf27c651e3ff3e7f29729f5ce3ce", + "sha256:febceb04ee7dd2aef08c2ff3d6f8a07de3052fc90137c507b0ede3ea80c21440" ], "markers": "python_version >= '3.7'", - "version": "==6.1" + "version": "==6.2" } }, "develop": { @@ -1142,32 +1153,32 @@ }, "black": { "hashes": [ - "sha256:0269dfdea12442022e88043d2910429bed717b2d04523867a85dacce535916b8", - "sha256:07204d078e25327aad9ed2c64790d681238686bce254c910de640c7cc4fc3aa6", - "sha256:08b34e85170d368c37ca7bf81cf67ac863c9d1963b2c1780c39102187ec8dd62", - "sha256:1a95915c98d6e32ca43809d46d932e2abc5f1f7d582ffbe65a5b4d1588af7445", - "sha256:2588021038bd5ada078de606f2a804cadd0a3cc6a79cb3e9bb3a8bf581325a4c", - "sha256:2fa6a0e965779c8f2afb286f9ef798df770ba2b6cee063c650b96adec22c056a", - "sha256:34afe9da5056aa123b8bfda1664bfe6fb4e9c6f311d8e4a6eb089da9a9173bf9", - "sha256:3897ae5a21ca132efa219c029cce5e6bfc9c3d34ed7e892113d199c0b1b444a2", - "sha256:40657e1b78212d582a0edecafef133cf1dd02e6677f539b669db4746150d38f6", - "sha256:48b5760dcbfe5cf97fd4fba23946681f3a81514c6ab8a45b50da67ac8fbc6c7b", - "sha256:5242ecd9e990aeb995b6d03dc3b2d112d4a78f2083e5a8e86d566340ae80fec4", - "sha256:5cdc2e2195212208fbcae579b931407c1fa9997584f0a415421748aeafff1168", - "sha256:5d7b06ea8816cbd4becfe5f70accae953c53c0e53aa98730ceccb0395520ee5d", - "sha256:7258c27115c1e3b5de9ac6c4f9957e3ee2c02c0b39222a24dc7aa03ba0e986f5", - "sha256:854c06fb86fd854140f37fb24dbf10621f5dab9e3b0c29a690ba595e3d543024", - "sha256:a21725862d0e855ae05da1dd25e3825ed712eaaccef6b03017fe0853a01aa45e", - "sha256:a83fe522d9698d8f9a101b860b1ee154c1d25f8a82ceb807d319f085b2627c5b", - "sha256:b3d64db762eae4a5ce04b6e3dd745dcca0fb9560eb931a5be97472e38652a161", - "sha256:e298d588744efda02379521a19639ebcd314fba7a49be22136204d7ed1782717", - "sha256:e2c8dfa14677f90d976f68e0c923947ae68fa3961d61ee30976c388adc0b02c8", - "sha256:ecba2a15dfb2d97105be74bbfe5128bc5e9fa8477d8c46766505c1dda5883aac", - "sha256:fc1ec9aa6f4d98d022101e015261c056ddebe3da6a8ccfc2c792cbe0349d48b7" + "sha256:057c3dc602eaa6fdc451069bd027a1b2635028b575a6c3acfd63193ced20d9c8", + "sha256:08654d0797e65f2423f850fc8e16a0ce50925f9337fb4a4a176a7aa4026e63f8", + "sha256:163baf4ef40e6897a2a9b83890e59141cc8c2a98f2dda5080dc15c00ee1e62cd", + "sha256:1e08fb9a15c914b81dd734ddd7fb10513016e5ce7e6704bdd5e1251ceee51ac9", + "sha256:4dd76e9468d5536abd40ffbc7a247f83b2324f0c050556d9c371c2b9a9a95e31", + "sha256:4f9de21bafcba9683853f6c96c2d515e364aee631b178eaa5145fc1c61a3cc92", + "sha256:61a0391772490ddfb8a693c067df1ef5227257e72b0e4108482b8d41b5aee13f", + "sha256:6981eae48b3b33399c8757036c7f5d48a535b962a7c2310d19361edeef64ce29", + "sha256:7e53a8c630f71db01b28cd9602a1ada68c937cbf2c333e6ed041390d6968faf4", + "sha256:810d445ae6069ce64030c78ff6127cd9cd178a9ac3361435708b907d8a04c693", + "sha256:93601c2deb321b4bad8f95df408e3fb3943d85012dddb6121336b8e24a0d1218", + "sha256:992e451b04667116680cb88f63449267c13e1ad134f30087dec8527242e9862a", + "sha256:9db528bccb9e8e20c08e716b3b09c6bdd64da0dd129b11e160bf082d4642ac23", + "sha256:a0057f800de6acc4407fe75bb147b0c2b5cbb7c3ed110d3e5999cd01184d53b0", + "sha256:ba15742a13de85e9b8f3239c8f807723991fbfae24bad92d34a2b12e81904982", + "sha256:bce4f25c27c3435e4dace4815bcb2008b87e167e3bf4ee47ccdc5ce906eb4894", + "sha256:ca610d29415ee1a30a3f30fab7a8f4144e9d34c89a235d81292a1edb2b55f540", + "sha256:d533d5e3259720fdbc1b37444491b024003e012c5173f7d06825a77508085430", + "sha256:d84f29eb3ee44859052073b7636533ec995bd0f64e2fb43aeceefc70090e752b", + "sha256:e37c99f89929af50ffaf912454b3e3b47fd64109659026b678c091a4cd450fb2", + "sha256:e8a6ae970537e67830776488bca52000eaa37fa63b9988e8c487458d9cd5ace6", + "sha256:faf2ee02e6612577ba0181f4347bcbcf591eb122f7841ae5ba233d12c39dcb4d" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==24.1.1" + "version": "==24.2.0" }, "blinker": { "hashes": [ @@ -1179,12 +1190,12 @@ }, "boto3": { "hashes": [ - "sha256:65acfe7f1cf2a9b7df3d4edb87c8022e02685825bd1957e7bb678cc0d09f5e5f", - "sha256:73f5ec89cb3ddb3ed577317889fd2f2df783f66b6502a9a4239979607e33bf74" + "sha256:66303b5f26d92afb72656ff490b22ea72dfff8bf1a29e4a0c5d5f11ec56245dd", + "sha256:898ad2123b18cae8efd85adc56ac2d1925be54592aebc237020d4f16e9a9e7a9" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==1.34.37" + "version": "==1.34.52" }, "boto3-mocking": { "hashes": [ @@ -1197,28 +1208,28 @@ }, "boto3-stubs": { "hashes": [ - "sha256:97b5ca3d3145385acde5af46ca2da3fc74f433545034c36183f389e99771516e", - "sha256:c6618c7126bac0337c05e161e9c428febc57d6a24d7ff62de46e67761f402c57" + "sha256:644381a404fb5884154f7dcc40bb819f0c7f37de21b7a7b493585277b51c9a5f", + "sha256:823c41059f836d6877daaa1cbd20f813c8f1a78b9fdf290bc0b853127e127ba3" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==1.34.37" + "version": "==1.34.52" }, "botocore": { "hashes": [ - "sha256:2a5bf33aacd2d970afd3d492e179e06ea98a5469030d5cfe7a2ad9995f7bb2ef", - "sha256:3c46ddb1679e6ef45ca78b48665398636bda532a07cd476e4b500697d13d9a99" + "sha256:05567d8aba344826060481ea309555432c96f0febe22bee7cf5a3b6d3a03cec8", + "sha256:187da93aec3f2e87d8a31eced16fa2cb9c71fe2d69b0a797f9f7a9220f5bf7ae" ], "markers": "python_version >= '3.8'", - "version": "==1.34.37" + "version": "==1.34.52" }, "botocore-stubs": { "hashes": [ - "sha256:087cd42973edcb5527dc97eec87fa29fffecc39691249486e02045677d4a2dbe", - "sha256:d6bcea8a6872aa46d389027dc5c022241fd0a2047a8b858aa5005e6151ed30a7" + "sha256:8748b9fe01f66bb1e7b13f45e3336e2e2c5460d232816d45941573425459c66e", + "sha256:d0f4d9859d9f6affbe4b0b46e37fe729860eaab55ebefe7e09cf567396b2feda" ], "markers": "python_version >= '3.8' and python_version < '4.0'", - "version": "==1.34.37" + "version": "==1.34.51" }, "click": { "hashes": [ @@ -1492,11 +1503,11 @@ }, "rich": { "hashes": [ - "sha256:5cb5123b5cf9ee70584244246816e9114227e0b98ad9176eede6ad54bf5403fa", - "sha256:6da14c108c4866ee9520bbffa71f6fe3962e193b7da68720583850cd4548e235" + "sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222", + "sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432" ], "markers": "python_full_version >= '3.7.0'", - "version": "==13.7.0" + "version": "==13.7.1" }, "s3transfer": { "hashes": [ @@ -1532,11 +1543,11 @@ }, "stevedore": { "hashes": [ - "sha256:8cc040628f3cea5d7128f2e76cf486b2251a4e543c7b938f58d9a377f6694a2d", - "sha256:a54534acf9b89bc7ed264807013b505bf07f74dbe4bcfa37d32bd063870b087c" + "sha256:1c15d95766ca0569cad14cb6272d4d31dae66b011a929d7c18219c176ea1b5c9", + "sha256:46b93ca40e1114cea93d738a6c1e365396981bb6bb78c27045b7587c9473544d" ], "markers": "python_version >= '3.8'", - "version": "==5.1.0" + "version": "==5.2.0" }, "tomli": { "hashes": [ @@ -1548,11 +1559,11 @@ }, "types-awscrt": { "hashes": [ - "sha256:06a859189a329ca8e66d56ceeef2391488e39b878fbd2141f115eab4d416fe22", - "sha256:f61a120d3e98ee1387bc5ca4b93437f258cc5c2af1f55f8634ec4cee5729f178" + "sha256:10245570c7285e949362b4ae710c54bf285d64a27453d42762477bcee5cd77a3", + "sha256:73be0a2720d6f76b924df6917d4edf4c9958f83e5c25bf7d9f0c1e9cdf836941" ], "markers": "python_version >= '3.7' and python_version < '4.0'", - "version": "==0.20.3" + "version": "==0.20.4" }, "types-cachetools": { "hashes": [ @@ -1580,12 +1591,12 @@ }, "types-requests": { "hashes": [ - "sha256:03a28ce1d7cd54199148e043b2079cdded22d6795d19a2c2a6791a4b2b5e2eb5", - "sha256:9592a9a4cb92d6d75d9b491a41477272b710e021011a2a3061157e2fb1f1a5d1" + "sha256:a82807ec6ddce8f00fe0e949da6d6bc1fbf1715420218a9640d695f70a9e5a9b", + "sha256:f1721dba8385958f504a5386240b92de4734e047a08a40751c1654d1ac3349c5" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==2.31.0.20240125" + "version": "==2.31.0.20240218" }, "types-s3transfer": { "hashes": [ @@ -1597,12 +1608,12 @@ }, "typing-extensions": { "hashes": [ - "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783", - "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd" + "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475", + "sha256:b0abd7c89e8fb96f98db18d86106ff1d90ab692004eb746cf6eda2682f91b3cb" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==4.9.0" + "version": "==4.10.0" }, "urllib3": { "hashes": [ diff --git a/src/docker-compose.yml b/src/docker-compose.yml index fdf069f56..600347fa8 100644 --- a/src/docker-compose.yml +++ b/src/docker-compose.yml @@ -58,6 +58,8 @@ services: - AWS_S3_SECRET_ACCESS_KEY - AWS_S3_REGION - AWS_S3_BUCKET_NAME + # File encryption credentials + - SECRET_ENCRYPT_METADATA stdin_open: true tty: true ports: diff --git a/src/registrar/config/settings.py b/src/registrar/config/settings.py index 009baa1c6..f763a71ce 100644 --- a/src/registrar/config/settings.py +++ b/src/registrar/config/settings.py @@ -74,6 +74,8 @@ secret_aws_s3_key_id = secret("access_key_id", None) or secret("AWS_S3_ACCESS_KE secret_aws_s3_key = secret("secret_access_key", None) or secret("AWS_S3_SECRET_ACCESS_KEY", None) secret_aws_s3_bucket_name = secret("bucket", None) or secret("AWS_S3_BUCKET_NAME", None) +secret_encrypt_metadata = secret("SECRET_ENCRYPT_METADATA", None) + secret_registry_cl_id = secret("REGISTRY_CL_ID") secret_registry_password = secret("REGISTRY_PASSWORD") secret_registry_cert = b64decode(secret("REGISTRY_CERT", "")) @@ -94,6 +96,7 @@ DEBUG = env_debug # Controls production specific feature toggles IS_PRODUCTION = env_is_production +SECRET_ENCRYPT_METADATA = secret_encrypt_metadata # Applications are modular pieces of code. # They are provided by Django, by third-parties, or by yourself. diff --git a/src/registrar/management/commands/generate_current_metadata_report.py b/src/registrar/management/commands/generate_current_metadata_report.py index 69d111f4c..a27199cdb 100644 --- a/src/registrar/management/commands/generate_current_metadata_report.py +++ b/src/registrar/management/commands/generate_current_metadata_report.py @@ -5,6 +5,7 @@ import os import pyzipper from django.core.management import BaseCommand +from django.conf import settings from registrar.utility import csv_export from registrar.utility.s3_bucket import S3ClientHelper from ...utility.email import send_templated_email, EmailSendingError @@ -61,27 +62,28 @@ class Command(BaseCommand): We want to make sure to upload to s3 for back up And now we also want to get the file and encrypt it so we can send it in an email """ - unencrypted_metadata_input = s3_client.get_file(file_name) - # Encrypt metadata into a zip file # pre-setting zip file name encrypted_metadata_output = 'encrypted_metadata.zip' - # set this to be an env var somewhere - password = b'somepasswordhere' + + # Secret is encrypted into getgov-credentials + # TODO: Update secret in getgov-credentials via cloud.gov and my own .env when ready + # encrypted_metadata is the encrypted output - encrypted_metadata = _encrypt_metadata(unencrypted_metadata_input, encrypted_metadata_output, password) + encrypted_metadata = self._encrypt_metadata(s3_client.get_file(file_name), encrypted_metadata_output, str.encode(settings.SECRET_ENCRYPT_METADATA)) print("encrypted_metadata is:", encrypted_metadata) # Send the metadata file that is zipped # Q: Would we set the vars I set in email.py here to pass in to the helper function or best way to invoke # send_templated_email(encrypted_metadata, attachment=True) - def _encrypt_metadata(input_file, output_file, password): - with open(input_file, 'rb') as f_in: - with pyzipper.AESZipFile(output_file, 'w', compression=pyzipper.ZIP_LZMA, encryption=pyzipper.WZ_AES) as f_out: - f_out.setpassword(password) - f_out.writestr(input_file, f_in.read()) - return output_file + def _encrypt_metadata(self, input_file, output_file, password): + # Using ZIP_DEFLATED bc it's a more common compression method supported by most zip utilities + # Could also use compression=pyzipper.ZIP_LZMA? + with pyzipper.AESZipFile(output_file, 'w', compression=pyzipper.ZIP_DEFLATED, encryption=pyzipper.WZ_AES) as f_out: + f_out.setpassword(password) + f_out.writestr('encrypted_metadata.txt', input_file) + return output_file diff --git a/src/requirements.txt b/src/requirements.txt index a6130a3bf..4b904cddd 100644 --- a/src/requirements.txt +++ b/src/requirements.txt @@ -1,14 +1,14 @@ -i https://pypi.python.org/simple annotated-types==0.6.0; python_version >= '3.8' asgiref==3.7.2; python_version >= '3.7' -boto3==1.34.37; python_version >= '3.8' -botocore==1.34.37; python_version >= '3.8' -cachetools==5.3.2; python_version >= '3.7' +boto3==1.34.52; python_version >= '3.8' +botocore==1.34.52; python_version >= '3.8' +cachetools==5.3.3; python_version >= '3.7' certifi==2024.2.2; python_version >= '3.6' cfenv==0.5.3 cffi==1.16.0; platform_python_implementation != 'PyPy' charset-normalizer==3.3.2; python_full_version >= '3.7.0' -cryptography==42.0.2; python_version >= '3.7' +cryptography==42.0.5; python_version >= '3.7' defusedxml==0.7.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' dj-database-url==2.1.0 dj-email-url==1.0.6 @@ -23,12 +23,12 @@ django-login-required-middleware==0.9.0 django-phonenumber-field[phonenumberslite]==7.3.0; python_version >= '3.8' django-widget-tweaks==1.5.0; python_version >= '3.8' environs[django]==10.3.0; python_version >= '3.8' -faker==23.1.0; python_version >= '3.8' +faker==23.3.0; python_version >= '3.8' fred-epplib@ git+https://github.com/cisagov/epplib.git@d56d183f1664f34c40ca9716a3a9a345f0ef561c furl==2.1.3 -future==0.18.3; python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3' -gevent==23.9.1; python_version >= '3.8' -geventconnpool@ git+https://github.com/rasky/geventconnpool.git@1bbb93a714a331a069adf27265fe582d9ba7ecd4 +future==1.0.0; python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3' +gevent==24.2.1; python_version >= '3.8' +geventconnpool@ git+https://github.com/rasky/geventconnpool.git greenlet==3.0.3; python_version >= '3.7' gunicorn==21.2.0; python_version >= '3.5' idna==3.6; python_version >= '3.5' @@ -36,27 +36,28 @@ jmespath==1.0.1; python_version >= '3.7' lxml==5.1.0; python_version >= '3.6' mako==1.3.2; python_version >= '3.8' markupsafe==2.1.5; python_version >= '3.7' -marshmallow==3.20.2; python_version >= '3.8' +marshmallow==3.21.0; python_version >= '3.8' oic==1.6.1; python_version ~= '3.7' orderedmultidict==1.0.1 packaging==23.2; python_version >= '3.7' -phonenumberslite==8.13.29 +phonenumberslite==8.13.31 psycopg2-binary==2.9.9; python_version >= '3.7' pycparser==2.21 pycryptodomex==3.20.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' -pydantic==2.6.1; python_version >= '3.8' -pydantic-core==2.16.2; python_version >= '3.8' -pydantic-settings==2.1.0; python_version >= '3.8' +pydantic==2.6.3; python_version >= '3.8' +pydantic-core==2.16.3; python_version >= '3.8' +pydantic-settings==2.2.1; python_version >= '3.8' pyjwkest==1.4.2 python-dateutil==2.8.2; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' python-dotenv==1.0.1; python_version >= '3.8' +pyzipper==0.3.6; python_version >= '3.4' requests==2.31.0; python_version >= '3.7' s3transfer==0.10.0; python_version >= '3.8' -setuptools==69.0.3; python_version >= '3.8' +setuptools==69.1.1; python_version >= '3.8' six==1.16.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3' sqlparse==0.4.4; python_version >= '3.5' -typing-extensions==4.9.0; python_version >= '3.8' +typing-extensions==4.10.0; python_version >= '3.8' urllib3==2.0.7; python_version >= '3.7' whitenoise==6.6.0; python_version >= '3.8' zope.event==5.0; python_version >= '3.7' -zope.interface==6.1; python_version >= '3.7' +zope.interface==6.2; python_version >= '3.7' From 0ce03d21c7748079bae85e349f9ad294e607c83f Mon Sep 17 00:00:00 2001 From: CocoByte Date: Thu, 29 Feb 2024 14:11:43 -0700 Subject: [PATCH 036/103] Find-replace "domain application", "domain_application", "domain-application" with "domain request", "domain_request", "domain-request". Preserved camel-cases through strict find-replace conditions. --- .github/ISSUE_TEMPLATE/bug.yml | 2 +- .github/ISSUE_TEMPLATE/story.yml | 8 +- .../decisions/0015-use-django-fsm.md | 4 +- .../decisions/0016-django-form-wizard.md | 2 +- .../0022-submit-domain-request-user-flow.md | 2 +- docs/architecture/diagrams/model_timeline.md | 26 +- docs/architecture/diagrams/model_timeline.svg | 2 +- docs/architecture/diagrams/models_diagram.md | 26 +- docs/architecture/diagrams/models_diagram.svg | 2 +- src/registrar/admin.py | 60 +-- src/registrar/config/urls.py | 2 +- src/registrar/fixtures_applications.py | 32 +- src/registrar/forms/application_wizard.py | 28 +- src/registrar/management/commands/load.py | 4 +- .../transfer_transition_domains_to_domains.py | 8 +- src/registrar/migrations/0001_initial.py | 2 +- ..._domain_host_nameserver_hostip_and_more.py | 4 +- ...napplication_is_election_board_and_more.py | 22 +- .../0004_domainapplication_federal_agency.py | 4 +- .../0005_domainapplication_city_and_more.py | 8 +- .../migrations/0006_alter_contact_phone.py | 2 +- ..._more_organization_information_and_more.py | 22 +- ..._remove_userprofile_created_at_and_more.py | 2 +- ...ion_federally_recognized_tribe_and_more.py | 6 +- ...application_no_other_contacts_rationale.py | 4 +- ...remove_domainapplication_security_email.py | 4 +- .../migrations/0012_delete_userprofile.py | 2 +- ...alter_domainapplication_status_and_more.py | 2 +- .../migrations/0018_domaininformation.py | 10 +- ...ter_domainapplication_organization_type.py | 2 +- ...remove_domaininformation_security_email.py | 2 +- ...ainapplication_approved_domain_and_more.py | 8 +- ...t_name_alter_contact_last_name_and_more.py | 2 +- ...omainapplication_address_line2_and_more.py | 2 +- ...omaininformation_address_line1_and_more.py | 2 +- .../0028_alter_domainapplication_status.py | 2 +- ...r_status_alter_domainapplication_status.py | 4 +- .../migrations/0030_alter_user_status.py | 2 +- .../0031_transitiondomain_and_more.py | 10 +- ...napplication_organization_type_and_more.py | 2 +- .../migrations/0042_create_groups_v03.py | 2 +- ...inapplication_current_websites_and_more.py | 4 +- ...0050_alter_contact_middle_name_and_more.py | 4 +- ...domainapplication_urbanization_and_more.py | 2 +- ...omainapplication_anything_else_and_more.py | 4 +- .../migrations/0053_create_groups_v05.py | 2 +- ...mainapplication_federal_agency_and_more.py | 4 +- .../0055_transitiondomain_processed.py | 2 +- ...alter_domainapplication_status_and_more.py | 2 +- .../0057_domainapplication_submission_date.py | 4 +- .../0058_alter_domaininformation_options.py | 2 +- ...omainapplication_address_line1_and_more.py | 4 +- .../migrations/0065_create_groups_v06.py | 2 +- ...plication_notes_domaininformation_notes.py | 2 +- ...email_alter_contact_first_name_and_more.py | 2 +- ...0070_domainapplication_rejection_reason.py | 2 +- ...t_name_alter_contact_last_name_and_more.py | 16 +- src/registrar/models/__init__.py | 6 +- src/registrar/models/domain.py | 4 +- src/registrar/models/domain_application.py | 30 +- src/registrar/models/domain_information.py | 48 +-- src/registrar/models/user_group.py | 4 +- src/registrar/models/utility/domain_helper.py | 2 +- .../templates/application_status.html | 80 ++-- .../application_withdraw_confirmation.html | 8 +- src/registrar/templates/home.html | 4 +- src/registrar/templatetags/custom_filters.py | 4 +- src/registrar/tests/common.py | 54 +-- src/registrar/tests/test_admin.py | 356 +++++++++--------- src/registrar/tests/test_migrations.py | 2 +- src/registrar/tests/test_models.py | 90 ++--- src/registrar/tests/test_models_domain.py | 14 +- src/registrar/tests/test_views.py | 4 +- src/registrar/tests/test_views_application.py | 170 ++++----- src/registrar/tests/test_views_domain.py | 6 +- src/registrar/views/application.py | 70 ++-- src/registrar/views/index.py | 14 +- src/registrar/views/utility/__init__.py | 4 +- src/registrar/views/utility/mixins.py | 40 +- .../views/utility/permission_views.py | 28 +- 80 files changed, 721 insertions(+), 721 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml index 7cd332156..d4d3497ac 100644 --- a/.github/ISSUE_TEMPLATE/bug.yml +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -22,7 +22,7 @@ body: attributes: label: Expected Behavior description: "Please add a concise description of the behavior you would expect if this issue were not occurring" - placeholder: "Example: When submitting a new domain application, the request should be successful, OR if there is a problem with the user's application preventing submission, errors should be enumerated to the user" + placeholder: "Example: When submitting a new domain request, the request should be successful, OR if there is a problem with the user's application preventing submission, errors should be enumerated to the user" validations: required: true - type: textarea diff --git a/.github/ISSUE_TEMPLATE/story.yml b/.github/ISSUE_TEMPLATE/story.yml index 41516cc29..e7d81ad3a 100644 --- a/.github/ISSUE_TEMPLATE/story.yml +++ b/.github/ISSUE_TEMPLATE/story.yml @@ -19,7 +19,7 @@ body: Example: As an analyst - I want the ability to approve a domain application + I want the ability to approve a domain request so that a request can be fulfilled and a new .gov domain can be provisioned value: | As a @@ -36,11 +36,11 @@ body: Example: - Application sends an email when analysts approve domain requests - - Domain application status is "approved" + - Domain request status is "approved" Example ("given, when, then" format): - Given that I am an analyst who has finished reviewing a domain application - When I click to approve a domain application + Given that I am an analyst who has finished reviewing a domain request + When I click to approve a domain request Then the domain provisioning process should be initiated, and the applicant should receive an email update. validations: required: true diff --git a/docs/architecture/decisions/0015-use-django-fsm.md b/docs/architecture/decisions/0015-use-django-fsm.md index 60f4cf902..c291f509f 100644 --- a/docs/architecture/decisions/0015-use-django-fsm.md +++ b/docs/architecture/decisions/0015-use-django-fsm.md @@ -1,4 +1,4 @@ -# 15. Use Django-FSM library for domain application state +# 15. Use Django-FSM library for domain request state Date: 2022-11-03 @@ -10,7 +10,7 @@ Accepted The applications that registrants submit for domains move through a variety of different states or stages as they are processed by CISA staff. Traditionally, -there would be a “domain application” data model with a “status” field. The +there would be a “domain request” data model with a “status” field. The rules in the application code that control what changes are permitted to the statuses are called “domain logic”. diff --git a/docs/architecture/decisions/0016-django-form-wizard.md b/docs/architecture/decisions/0016-django-form-wizard.md index 8e785a196..1d0bf0852 100644 --- a/docs/architecture/decisions/0016-django-form-wizard.md +++ b/docs/architecture/decisions/0016-django-form-wizard.md @@ -18,7 +18,7 @@ However, a significant portion of the user workflow had already been coded, so i ## Decision -To maintain each page of the domain application as its own Django view class, inheriting common code from a parent class. +To maintain each page of the domain request as its own Django view class, inheriting common code from a parent class. To maintain Django form and formset class in accordance with the Django models whose data they collect, independently of the pages on which they appear. diff --git a/docs/architecture/decisions/0022-submit-domain-request-user-flow.md b/docs/architecture/decisions/0022-submit-domain-request-user-flow.md index cc0ca83b8..e0e94fc16 100644 --- a/docs/architecture/decisions/0022-submit-domain-request-user-flow.md +++ b/docs/architecture/decisions/0022-submit-domain-request-user-flow.md @@ -8,7 +8,7 @@ Accepted ## Context -Historically, the .gov vendor managed initial identity verification and organizational affiliation for users that request a .gov domain. With the new registrar, _any user with a valid Login.gov account_ will be able to make a request. As a primary layer of abuse prevention (i.e., DDoSing the registry program with illegitimate requests), we need a way to stop new users from submitting multiple domain requests before they are known to the .gov registry. In this case, "known" means they have at least one approved domain application or existing domain. +Historically, the .gov vendor managed initial identity verification and organizational affiliation for users that request a .gov domain. With the new registrar, _any user with a valid Login.gov account_ will be able to make a request. As a primary layer of abuse prevention (i.e., DDoSing the registry program with illegitimate requests), we need a way to stop new users from submitting multiple domain requests before they are known to the .gov registry. In this case, "known" means they have at least one approved domain request or existing domain. ## Considered Options diff --git a/docs/architecture/diagrams/model_timeline.md b/docs/architecture/diagrams/model_timeline.md index 967c63eb2..47e449162 100644 --- a/docs/architecture/diagrams/model_timeline.md +++ b/docs/architecture/diagrams/model_timeline.md @@ -3,9 +3,9 @@ This diagram connects the data models along with various workflow stages. 1. The applicant starts the process at `/request` interacting with the - `DomainApplication` object. + `DomainRequest` object. -2. The analyst approves the application using the `DomainApplication`'s +2. The analyst approves the application using the `DomainRequest`'s `approve()` method which creates many related objects: `UserDomainRole`, `Domain`, and `DomainInformation`. @@ -36,7 +36,7 @@ $ docker run -v $(pwd):$(pwd) -w $(pwd) -it plantuml/plantuml -tsvg model_timeli allowmixing left to right direction -class DomainApplication { +class DomainRequest { Application for a domain -- creator (User) @@ -66,7 +66,7 @@ note left of User username is the Login UUID end note -DomainApplication -l- User : creator, investigator +DomainRequest -l- User : creator, investigator class Contact { Contact info for a person @@ -80,7 +80,7 @@ class Contact { -- } -DomainApplication *-r-* Contact : authorizing_official, submitter, other_contacts +DomainRequest *-r-* Contact : authorizing_official, submitter, other_contacts class DraftDomain { Requested domain @@ -89,7 +89,7 @@ class DraftDomain { -- } -DomainApplication -l- DraftDomain : requested_domain +DomainRequest -l- DraftDomain : requested_domain class Domain { Approved domain @@ -99,21 +99,21 @@ class Domain { EPP methods } -DomainApplication .right[#blue].> Domain : approve() +DomainRequest .right[#blue].> Domain : approve() class DomainInformation { Registrar information on a domain -- domain (Domain) - domain_application (DomainApplication) + domain_request (DomainRequest) security_email -- Request information... } DomainInformation -- Domain -DomainInformation -- DomainApplication -DomainApplication .[#blue].> DomainInformation : approve() +DomainInformation -- DomainRequest +DomainRequest .[#blue].> DomainInformation : approve() class UserDomainRole { Permissions @@ -125,7 +125,7 @@ class UserDomainRole { } UserDomainRole -- User UserDomainRole -- Domain -DomainApplication .[#blue].> UserDomainRole : approve() +DomainRequest .[#blue].> UserDomainRole : approve() class DomainInvitation { Email invitations sent @@ -139,10 +139,10 @@ DomainInvitation -- Domain DomainInvitation .[#green].> UserDomainRole : User.on_each_login() actor applicant #Red -applicant -d-> DomainApplication : **/request** +applicant -d-> DomainRequest : **/request** actor analyst #Blue -analyst -[#blue]-> DomainApplication : **approve()** +analyst -[#blue]-> DomainRequest : **approve()** actor user1 #Green user1 -[#green]-> Domain : **/domain//nameservers** diff --git a/docs/architecture/diagrams/model_timeline.svg b/docs/architecture/diagrams/model_timeline.svg index 5410bf25f..c64c5a023 100644 --- a/docs/architecture/diagrams/model_timeline.svg +++ b/docs/architecture/diagrams/model_timeline.svg @@ -1 +1 @@ -DomainApplicationApplication for a domaincreator (User)investigator (User)authorizing_official (Contact)submitter (Contact)other_contacts (Contacts)approved_domain (Domain)requested_domain (DraftDomain)current_websites (Websites)alternative_domains (Websites)Request information...UserDjango's user class...Created by DjangoOIDCwhen users arrive backfrom Login.gov usernameis the Login UUIDContactContact info for a personfirst_namemiddle_namelast_nametitleemailphoneDraftDomainRequested domainnameDomainApproved domainnameEPP methodsDomainInformationRegistrar information on a domaindomain (Domain)domain_application (DomainApplication)security_emailRequest information...UserDomainRolePermissionsdomain (Domain)user (User)role="ADMIN"DomainInvitationEmail invitations sentemaildomain (Domain)statusapplicantanalystuser1user2user3creator, investigatorauthorizing_official, submitter, other_contactsrequested_domainapprove()approve()approve()User.on_each_login()/registerapprove()/domain/<id>/nameservers/domain/<id>/?????/domain/<id>/users/add/domain/<id>/users/add \ No newline at end of file +DomainRequestApplication for a domaincreator (User)investigator (User)authorizing_official (Contact)submitter (Contact)other_contacts (Contacts)approved_domain (Domain)requested_domain (DraftDomain)current_websites (Websites)alternative_domains (Websites)Request information...UserDjango's user class...Created by DjangoOIDCwhen users arrive backfrom Login.gov usernameis the Login UUIDContactContact info for a personfirst_namemiddle_namelast_nametitleemailphoneDraftDomainRequested domainnameDomainApproved domainnameEPP methodsDomainInformationRegistrar information on a domaindomain (Domain)domain_request (DomainRequest)security_emailRequest information...UserDomainRolePermissionsdomain (Domain)user (User)role="ADMIN"DomainInvitationEmail invitations sentemaildomain (Domain)statusapplicantanalystuser1user2user3creator, investigatorauthorizing_official, submitter, other_contactsrequested_domainapprove()approve()approve()User.on_each_login()/registerapprove()/domain/<id>/nameservers/domain/<id>/?????/domain/<id>/users/add/domain/<id>/users/add \ No newline at end of file diff --git a/docs/architecture/diagrams/models_diagram.md b/docs/architecture/diagrams/models_diagram.md index 000d480c7..df0e39b7e 100644 --- a/docs/architecture/diagrams/models_diagram.md +++ b/docs/architecture/diagrams/models_diagram.md @@ -39,8 +39,8 @@ class "registrar.Contact " as registrar.Contact #d6f4e9 { registrar.Contact -- registrar.User -class "registrar.DomainApplication " as registrar.DomainApplication #d6f4e9 { - domain application +class "registrar.DomainRequest " as registrar.DomainRequest #d6f4e9 { + domain request -- + id (BigAutoField) + created_at (DateTimeField) @@ -77,15 +77,15 @@ class "registrar.DomainApplication " as registrar.DomainApplication # # other_contacts (ManyToManyField) -- } -registrar.DomainApplication -- registrar.User -registrar.DomainApplication -- registrar.User -registrar.DomainApplication -- registrar.Contact -registrar.DomainApplication -- registrar.DraftDomain -registrar.DomainApplication -- registrar.Domain -registrar.DomainApplication -- registrar.Contact -registrar.DomainApplication *--* registrar.Website -registrar.DomainApplication *--* registrar.Website -registrar.DomainApplication *--* registrar.Contact +registrar.DomainRequest -- registrar.User +registrar.DomainRequest -- registrar.User +registrar.DomainRequest -- registrar.Contact +registrar.DomainRequest -- registrar.DraftDomain +registrar.DomainRequest -- registrar.Domain +registrar.DomainRequest -- registrar.Contact +registrar.DomainRequest *--* registrar.Website +registrar.DomainRequest *--* registrar.Website +registrar.DomainRequest *--* registrar.Contact class "registrar.DomainInformation " as registrar.DomainInformation #d6f4e9 { @@ -95,7 +95,7 @@ class "registrar.DomainInformation " as registrar.DomainInformation # + created_at (DateTimeField) + updated_at (DateTimeField) ~ creator (ForeignKey) - ~ domain_application (OneToOneField) + ~ domain_request (OneToOneField) + organization_type (CharField) + federally_recognized_tribe (BooleanField) + state_recognized_tribe (BooleanField) @@ -124,7 +124,7 @@ class "registrar.DomainInformation " as registrar.DomainInformation # -- } registrar.DomainInformation -- registrar.User -registrar.DomainInformation -- registrar.DomainApplication +registrar.DomainInformation -- registrar.DomainRequest registrar.DomainInformation -- registrar.Contact registrar.DomainInformation -- registrar.Domain registrar.DomainInformation -- registrar.Contact diff --git a/docs/architecture/diagrams/models_diagram.svg b/docs/architecture/diagrams/models_diagram.svg index 0075c44cb..49999454c 100644 --- a/docs/architecture/diagrams/models_diagram.svg +++ b/docs/architecture/diagrams/models_diagram.svg @@ -1 +1 @@ -registrarregistrar.ContactRegistrarcontactid (BigAutoField)created_at (DateTimeField)updated_at (DateTimeField)user (OneToOneField)first_name (TextField)middle_name (TextField)last_name (TextField)title (TextField)email (TextField)phone (PhoneNumberField)registrar.UserRegistraruserid (BigAutoField)password (CharField)last_login (DateTimeField)is_superuser (BooleanField)username (CharField)first_name (CharField)last_name (CharField)email (EmailField)is_staff (BooleanField)is_active (BooleanField)date_joined (DateTimeField)phone (PhoneNumberField)groups (ManyToManyField)user_permissions (ManyToManyField)domains (ManyToManyField)registrar.DomainApplicationRegistrardomain applicationid (BigAutoField)created_at (DateTimeField)updated_at (DateTimeField)status (FSMField)creator (ForeignKey)investigator (ForeignKey)organization_type (CharField)federally_recognized_tribe (BooleanField)state_recognized_tribe (BooleanField)tribe_name (TextField)federal_agency (TextField)federal_type (CharField)is_election_board (BooleanField)organization_name (TextField)address_line1 (TextField)address_line2 (CharField)city (TextField)state_territory (CharField)zipcode (CharField)urbanization (TextField)type_of_work (TextField)more_organization_information (TextField)authorizing_official (ForeignKey)approved_domain (OneToOneField)requested_domain (OneToOneField)submitter (ForeignKey)purpose (TextField)no_other_contacts_rationale (TextField)anything_else (TextField)is_policy_acknowledged (BooleanField)current_websites (ManyToManyField)alternative_domains (ManyToManyField)other_contacts (ManyToManyField)registrar.DraftDomainRegistrardraft domainid (BigAutoField)created_at (DateTimeField)updated_at (DateTimeField)name (CharField)registrar.DomainRegistrardomainid (BigAutoField)created_at (DateTimeField)updated_at (DateTimeField)name (CharField)registrar.WebsiteRegistrarwebsiteid (BigAutoField)created_at (DateTimeField)updated_at (DateTimeField)website (CharField)registrar.DomainInformationRegistrardomain informationid (BigAutoField)created_at (DateTimeField)updated_at (DateTimeField)creator (ForeignKey)domain_application (OneToOneField)organization_type (CharField)federally_recognized_tribe (BooleanField)state_recognized_tribe (BooleanField)tribe_name (TextField)federal_agency (TextField)federal_type (CharField)is_election_board (BooleanField)organization_name (TextField)address_line1 (TextField)address_line2 (CharField)city (TextField)state_territory (CharField)zipcode (CharField)urbanization (TextField)type_of_work (TextField)more_organization_information (TextField)authorizing_official (ForeignKey)domain (OneToOneField)submitter (ForeignKey)purpose (TextField)no_other_contacts_rationale (TextField)anything_else (TextField)is_policy_acknowledged (BooleanField)security_email (EmailField)other_contacts (ManyToManyField)registrar.HostIPRegistrarhost ipid (BigAutoField)created_at (DateTimeField)updated_at (DateTimeField)address (CharField)host (ForeignKey)registrar.HostRegistrarhostid (BigAutoField)created_at (DateTimeField)updated_at (DateTimeField)name (CharField)domain (ForeignKey)registrar.UserDomainRoleRegistraruser domain roleid (BigAutoField)created_at (DateTimeField)updated_at (DateTimeField)user (ForeignKey)domain (ForeignKey)role (TextField)registrar.DomainInvitationRegistrardomain invitationid (BigAutoField)created_at (DateTimeField)updated_at (DateTimeField)email (EmailField)domain (ForeignKey)status (FSMField)registrar.NameserverRegistrarnameserverid (BigAutoField)created_at (DateTimeField)updated_at (DateTimeField)name (CharField)domain (ForeignKey)host_ptr (OneToOneField)registrar.PublicContactRegistrarpublic contactid (BigAutoField)created_at (DateTimeField)updated_at (DateTimeField)contact_type (CharField)registry_id (CharField)domain (ForeignKey)name (TextField)org (TextField)street1 (TextField)street2 (TextField)street3 (TextField)city (TextField)sp (TextField)pc (TextField)cc (TextField)email (TextField)voice (TextField)fax (TextField)pw (TextField) \ No newline at end of file +registrarregistrar.ContactRegistrarcontactid (BigAutoField)created_at (DateTimeField)updated_at (DateTimeField)user (OneToOneField)first_name (TextField)middle_name (TextField)last_name (TextField)title (TextField)email (TextField)phone (PhoneNumberField)registrar.UserRegistraruserid (BigAutoField)password (CharField)last_login (DateTimeField)is_superuser (BooleanField)username (CharField)first_name (CharField)last_name (CharField)email (EmailField)is_staff (BooleanField)is_active (BooleanField)date_joined (DateTimeField)phone (PhoneNumberField)groups (ManyToManyField)user_permissions (ManyToManyField)domains (ManyToManyField)registrar.DomainRequestRegistrardomain requestid (BigAutoField)created_at (DateTimeField)updated_at (DateTimeField)status (FSMField)creator (ForeignKey)investigator (ForeignKey)organization_type (CharField)federally_recognized_tribe (BooleanField)state_recognized_tribe (BooleanField)tribe_name (TextField)federal_agency (TextField)federal_type (CharField)is_election_board (BooleanField)organization_name (TextField)address_line1 (TextField)address_line2 (CharField)city (TextField)state_territory (CharField)zipcode (CharField)urbanization (TextField)type_of_work (TextField)more_organization_information (TextField)authorizing_official (ForeignKey)approved_domain (OneToOneField)requested_domain (OneToOneField)submitter (ForeignKey)purpose (TextField)no_other_contacts_rationale (TextField)anything_else (TextField)is_policy_acknowledged (BooleanField)current_websites (ManyToManyField)alternative_domains (ManyToManyField)other_contacts (ManyToManyField)registrar.DraftDomainRegistrardraft domainid (BigAutoField)created_at (DateTimeField)updated_at (DateTimeField)name (CharField)registrar.DomainRegistrardomainid (BigAutoField)created_at (DateTimeField)updated_at (DateTimeField)name (CharField)registrar.WebsiteRegistrarwebsiteid (BigAutoField)created_at (DateTimeField)updated_at (DateTimeField)website (CharField)registrar.DomainInformationRegistrardomain informationid (BigAutoField)created_at (DateTimeField)updated_at (DateTimeField)creator (ForeignKey)domain_request (OneToOneField)organization_type (CharField)federally_recognized_tribe (BooleanField)state_recognized_tribe (BooleanField)tribe_name (TextField)federal_agency (TextField)federal_type (CharField)is_election_board (BooleanField)organization_name (TextField)address_line1 (TextField)address_line2 (CharField)city (TextField)state_territory (CharField)zipcode (CharField)urbanization (TextField)type_of_work (TextField)more_organization_information (TextField)authorizing_official (ForeignKey)domain (OneToOneField)submitter (ForeignKey)purpose (TextField)no_other_contacts_rationale (TextField)anything_else (TextField)is_policy_acknowledged (BooleanField)security_email (EmailField)other_contacts (ManyToManyField)registrar.HostIPRegistrarhost ipid (BigAutoField)created_at (DateTimeField)updated_at (DateTimeField)address (CharField)host (ForeignKey)registrar.HostRegistrarhostid (BigAutoField)created_at (DateTimeField)updated_at (DateTimeField)name (CharField)domain (ForeignKey)registrar.UserDomainRoleRegistraruser domain roleid (BigAutoField)created_at (DateTimeField)updated_at (DateTimeField)user (ForeignKey)domain (ForeignKey)role (TextField)registrar.DomainInvitationRegistrardomain invitationid (BigAutoField)created_at (DateTimeField)updated_at (DateTimeField)email (EmailField)domain (ForeignKey)status (FSMField)registrar.NameserverRegistrarnameserverid (BigAutoField)created_at (DateTimeField)updated_at (DateTimeField)name (CharField)domain (ForeignKey)host_ptr (OneToOneField)registrar.PublicContactRegistrarpublic contactid (BigAutoField)created_at (DateTimeField)updated_at (DateTimeField)contact_type (CharField)registry_id (CharField)domain (ForeignKey)name (TextField)org (TextField)street1 (TextField)street2 (TextField)street3 (TextField)city (TextField)sp (TextField)pc (TextField)cc (TextField)email (TextField)voice (TextField)fax (TextField)pw (TextField) \ No newline at end of file diff --git a/src/registrar/admin.py b/src/registrar/admin.py index 92e477667..a985a971e 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -14,7 +14,7 @@ from django.contrib.contenttypes.models import ContentType from django.urls import reverse from dateutil.relativedelta import relativedelta # type: ignore from epplibwrapper.errors import ErrorCode, RegistryError -from registrar.models import Contact, Domain, DomainApplication, DraftDomain, User, Website +from registrar.models import Contact, Domain, DomainRequest, DraftDomain, User, Website from registrar.utility import csv_export from registrar.views.utility.mixins import OrderableFieldsMixin from django.contrib.admin.views.main import ORDER_VAR @@ -69,12 +69,12 @@ class DomainInformationInlineForm(forms.ModelForm): } -class DomainApplicationAdminForm(forms.ModelForm): +class DomainRequestAdminForm(forms.ModelForm): """Custom form to limit transitions to available transitions. This form utilizes the custom widget for its class's ManyToMany UIs.""" class Meta: - model = models.DomainApplication + model = models.DomainRequest fields = "__all__" widgets = { "current_websites": NoAutocompleteFilteredSelectMultiple("current_websites", False), @@ -93,14 +93,14 @@ class DomainApplicationAdminForm(forms.ModelForm): available_transitions = [(current_state, application.get_status_display())] transitions = get_available_FIELD_transitions( - application, models.DomainApplication._meta.get_field("status") + application, models.DomainRequest._meta.get_field("status") ) for transition in transitions: available_transitions.append((transition.target, transition.target.label)) # only set the available transitions if the user is not restricted - # from editing the domain application; otherwise, the form will be + # from editing the domain request; otherwise, the form will be # readonly and the status field will not have a widget if not application.creator.is_restricted(): self.fields["status"].widget.choices = available_transitions @@ -218,8 +218,8 @@ class AdminSortFields: "alternative_domains": (Website, "website"), # == DraftDomain == # "requested_domain": (DraftDomain, "name"), - # == DomainApplication == # - "domain_application": (DomainApplication, "requested_domain__name"), + # == DomainRequest == # + "domain_request": (DomainRequest, "requested_domain__name"), # == Domain == # "domain": (Domain, "name"), "approved_domain": (Domain, "name"), @@ -466,7 +466,7 @@ class MyUserAdmin(BaseUserAdmin): def get_search_results(self, request, queryset, search_term): """ Override for get_search_results. This affects any upstream model using autocomplete_fields, - such as DomainApplication. This is because autocomplete_fields uses an API call to fetch data, + such as DomainRequest. This is because autocomplete_fields uses an API call to fetch data, and this fetch comes from this method. """ # Custom filtering logic @@ -480,13 +480,13 @@ class MyUserAdmin(BaseUserAdmin): request_get = request.GET # The request defines model name and field name. - # For instance, model_name could be "DomainApplication" + # For instance, model_name could be "DomainRequest" # and field_name could be "investigator". model_name = request_get.get("model_name", None) field_name = request_get.get("field_name", None) # Make sure we're only modifying requests from these models. - models_to_target = {"domainapplication"} + models_to_target = {"DomainRequest"} if model_name in models_to_target: # Define rules per field match field_name: @@ -777,7 +777,7 @@ class DomainInformationAdmin(ListHeaderAdmin): search_help_text = "Search by domain." fieldsets = [ - (None, {"fields": ["creator", "domain_application", "notes"]}), + (None, {"fields": ["creator", "domain_request", "notes"]}), ( "Type of organization", { @@ -828,7 +828,7 @@ class DomainInformationAdmin(ListHeaderAdmin): "type_of_work", "more_organization_information", "domain", - "domain_application", + "domain_request", "submitter", "no_other_contacts_rationale", "anything_else", @@ -841,7 +841,7 @@ class DomainInformationAdmin(ListHeaderAdmin): autocomplete_fields = [ "creator", - "domain_application", + "domain_request", "authorizing_official", "domain", "submitter", @@ -866,10 +866,10 @@ class DomainInformationAdmin(ListHeaderAdmin): return readonly_fields # Read-only fields for analysts -class DomainApplicationAdmin(ListHeaderAdmin): +class DomainRequestAdmin(ListHeaderAdmin): """Custom domain applications admin class.""" - form = DomainApplicationAdminForm + form = DomainRequestAdminForm class InvestigatorFilter(admin.SimpleListFilter): """Custom investigator filter that only displays users with the manager role""" @@ -884,7 +884,7 @@ class DomainApplicationAdmin(ListHeaderAdmin): """ # Select all investigators that are staff, then order by name and email privileged_users = ( - DomainApplication.objects.select_related("investigator") + DomainRequest.objects.select_related("investigator") .filter(investigator__is_staff=True) .order_by("investigator__first_name", "investigator__last_name", "investigator__email") ) @@ -1057,12 +1057,12 @@ class DomainApplicationAdmin(ListHeaderAdmin): if obj and obj.creator.status != models.User.RESTRICTED: if change: # Check if the application is being edited # Get the original application from the database - original_obj = models.DomainApplication.objects.get(pk=obj.pk) + original_obj = models.DomainRequest.objects.get(pk=obj.pk) if ( obj - and original_obj.status == models.DomainApplication.ApplicationStatus.APPROVED - and obj.status != models.DomainApplication.ApplicationStatus.APPROVED + and original_obj.status == models.DomainRequest.ApplicationStatus.APPROVED + and obj.status != models.DomainRequest.ApplicationStatus.APPROVED and not obj.domain_is_not_active() ): # If an admin tried to set an approved application to @@ -1082,7 +1082,7 @@ class DomainApplicationAdmin(ListHeaderAdmin): elif ( obj - and obj.status == models.DomainApplication.ApplicationStatus.REJECTED + and obj.status == models.DomainRequest.ApplicationStatus.REJECTED and not obj.rejection_reason ): # This condition should never be triggered. @@ -1100,14 +1100,14 @@ class DomainApplicationAdmin(ListHeaderAdmin): else: if obj.status != original_obj.status: status_method_mapping = { - models.DomainApplication.ApplicationStatus.STARTED: None, - models.DomainApplication.ApplicationStatus.SUBMITTED: obj.submit, - models.DomainApplication.ApplicationStatus.IN_REVIEW: obj.in_review, - models.DomainApplication.ApplicationStatus.ACTION_NEEDED: obj.action_needed, - models.DomainApplication.ApplicationStatus.APPROVED: obj.approve, - models.DomainApplication.ApplicationStatus.WITHDRAWN: obj.withdraw, - models.DomainApplication.ApplicationStatus.REJECTED: obj.reject, - models.DomainApplication.ApplicationStatus.INELIGIBLE: (obj.reject_with_prejudice), + models.DomainRequest.ApplicationStatus.STARTED: None, + models.DomainRequest.ApplicationStatus.SUBMITTED: obj.submit, + models.DomainRequest.ApplicationStatus.IN_REVIEW: obj.in_review, + models.DomainRequest.ApplicationStatus.ACTION_NEEDED: obj.action_needed, + models.DomainRequest.ApplicationStatus.APPROVED: obj.approve, + models.DomainRequest.ApplicationStatus.WITHDRAWN: obj.withdraw, + models.DomainRequest.ApplicationStatus.REJECTED: obj.reject, + models.DomainRequest.ApplicationStatus.INELIGIBLE: (obj.reject_with_prejudice), } selected_method = status_method_mapping.get(obj.status) if selected_method is None: @@ -1202,7 +1202,7 @@ class DomainInformationInline(admin.StackedInline): autocomplete_fields = [ "creator", - "domain_application", + "domain_request", "authorizing_official", "domain", "submitter", @@ -1712,6 +1712,6 @@ admin.site.register(models.DraftDomain, DraftDomainAdmin) admin.site.register(models.Host, MyHostAdmin) admin.site.register(models.Website, WebsiteAdmin) admin.site.register(models.PublicContact, AuditedAdmin) -admin.site.register(models.DomainApplication, DomainApplicationAdmin) +admin.site.register(models.DomainRequest, DomainRequestAdmin) admin.site.register(models.TransitionDomain, TransitionDomainAdmin) admin.site.register(models.VerifiedByStaff, VerifiedByStaffAdmin) diff --git a/src/registrar/config/urls.py b/src/registrar/config/urls.py index 4bd7b4baf..153c3448f 100644 --- a/src/registrar/config/urls.py +++ b/src/registrar/config/urls.py @@ -139,7 +139,7 @@ urlpatterns = [ ), path( "application//delete", - views.DomainApplicationDeleteView.as_view(http_method_names=["post"]), + views.DomainRequestDeleteView.as_view(http_method_names=["post"]), name="application-delete", ), path( diff --git a/src/registrar/fixtures_applications.py b/src/registrar/fixtures_applications.py index 3e4e0e362..cfba61fa9 100644 --- a/src/registrar/fixtures_applications.py +++ b/src/registrar/fixtures_applications.py @@ -4,7 +4,7 @@ from faker import Faker from registrar.models import ( User, - DomainApplication, + DomainRequest, DraftDomain, Contact, Website, @@ -14,7 +14,7 @@ fake = Faker() logger = logging.getLogger(__name__) -class DomainApplicationFixture: +class DomainRequestFixture: """ Load domain applications into the database. @@ -49,27 +49,27 @@ class DomainApplicationFixture: # }, DA = [ { - "status": DomainApplication.ApplicationStatus.STARTED, + "status": DomainRequest.ApplicationStatus.STARTED, "organization_name": "Example - Finished but not submitted", }, { - "status": DomainApplication.ApplicationStatus.SUBMITTED, + "status": DomainRequest.ApplicationStatus.SUBMITTED, "organization_name": "Example - Submitted but pending investigation", }, { - "status": DomainApplication.ApplicationStatus.IN_REVIEW, + "status": DomainRequest.ApplicationStatus.IN_REVIEW, "organization_name": "Example - In investigation", }, { - "status": DomainApplication.ApplicationStatus.IN_REVIEW, + "status": DomainRequest.ApplicationStatus.IN_REVIEW, "organization_name": "Example - Approved", }, { - "status": DomainApplication.ApplicationStatus.WITHDRAWN, + "status": DomainRequest.ApplicationStatus.WITHDRAWN, "organization_name": "Example - Withdrawn", }, { - "status": DomainApplication.ApplicationStatus.ACTION_NEEDED, + "status": DomainRequest.ApplicationStatus.ACTION_NEEDED, "organization_name": "Example - Action needed", }, { @@ -94,7 +94,7 @@ class DomainApplicationFixture: return f"{fake.slug()}.gov" @classmethod - def _set_non_foreign_key_fields(cls, da: DomainApplication, app: dict): + def _set_non_foreign_key_fields(cls, da: DomainRequest, app: dict): """Helper method used by `load`.""" da.status = app["status"] if "status" in app else "started" da.organization_type = app["organization_type"] if "organization_type" in app else "federal" @@ -102,7 +102,7 @@ class DomainApplicationFixture: app["federal_agency"] if "federal_agency" in app # Random choice of agency for selects, used as placeholders for testing. - else random.choice(DomainApplication.AGENCIES) # nosec + else random.choice(DomainRequest.AGENCIES) # nosec ) da.submission_date = fake.date() da.federal_type = ( @@ -121,7 +121,7 @@ class DomainApplicationFixture: da.is_policy_acknowledged = app["is_policy_acknowledged"] if "is_policy_acknowledged" in app else True @classmethod - def _set_foreign_key_fields(cls, da: DomainApplication, app: dict, user: User): + def _set_foreign_key_fields(cls, da: DomainRequest, app: dict, user: User): """Helper method used by `load`.""" if not da.investigator: da.investigator = User.objects.get(username=user.username) if "investigator" in app else None @@ -145,7 +145,7 @@ class DomainApplicationFixture: da.requested_domain = DraftDomain.objects.create(name=cls.fake_dot_gov()) @classmethod - def _set_many_to_many_relations(cls, da: DomainApplication, app: dict): + def _set_many_to_many_relations(cls, da: DomainRequest, app: dict): """Helper method used by `load`.""" if "other_contacts" in app: for contact in app["other_contacts"]: @@ -188,7 +188,7 @@ class DomainApplicationFixture: logger.debug("Loading domain applications for %s" % user) for app in cls.DA: try: - da, _ = DomainApplication.objects.get_or_create( + da, _ = DomainRequest.objects.get_or_create( creator=user, organization_name=app["organization_name"], ) @@ -200,7 +200,7 @@ class DomainApplicationFixture: logger.warning(e) -class DomainFixture(DomainApplicationFixture): +class DomainFixture(DomainRequestFixture): """Create one domain and permissions on it for each user.""" @classmethod @@ -213,8 +213,8 @@ class DomainFixture(DomainApplicationFixture): for user in users: # approve one of each users in review status domains - application = DomainApplication.objects.filter( - creator=user, status=DomainApplication.ApplicationStatus.IN_REVIEW + application = DomainRequest.objects.filter( + creator=user, status=DomainRequest.ApplicationStatus.IN_REVIEW ).last() logger.debug(f"Approving {application} for {user}") diff --git a/src/registrar/forms/application_wizard.py b/src/registrar/forms/application_wizard.py index df5b195c6..ed81bf8a9 100644 --- a/src/registrar/forms/application_wizard.py +++ b/src/registrar/forms/application_wizard.py @@ -10,7 +10,7 @@ from django.core.validators import RegexValidator, MaxLengthValidator from django.utils.safestring import mark_safe from django.db.models.fields.related import ForeignObjectRel -from registrar.models import Contact, DomainApplication, DraftDomain, Domain +from registrar.models import Contact, DomainRequest, DraftDomain, Domain from registrar.templatetags.url_helpers import public_site_url from registrar.utility.enums import ValidationReturnType @@ -21,7 +21,7 @@ class RegistrarForm(forms.Form): """ A common set of methods and configuration. - The registrar's domain application is several pages of "steps". + The registrar's domain request is several pages of "steps". Each step is an HTML form containing one or more Django "forms". Subclass this class to create new forms. @@ -33,7 +33,7 @@ class RegistrarForm(forms.Form): self.application = kwargs.pop("application", None) super(RegistrarForm, self).__init__(*args, **kwargs) - def to_database(self, obj: DomainApplication | Contact): + def to_database(self, obj: DomainRequest | Contact): """ Adds this form's cleaned data to `obj` and saves `obj`. @@ -46,7 +46,7 @@ class RegistrarForm(forms.Form): obj.save() @classmethod - def from_database(cls, obj: DomainApplication | Contact | None): + def from_database(cls, obj: DomainRequest | Contact | None): """Returns a dict of form field values gotten from `obj`.""" if obj is None: return {} @@ -85,7 +85,7 @@ class RegistrarFormSet(forms.BaseFormSet): """Code to run before an item in the formset is created in the database.""" return cleaned - def to_database(self, obj: DomainApplication): + def to_database(self, obj: DomainRequest): """ Adds this form's cleaned data to `obj` and saves `obj`. @@ -97,7 +97,7 @@ class RegistrarFormSet(forms.BaseFormSet): def _to_database( self, - obj: DomainApplication, + obj: DomainRequest, join: str, should_delete: Callable, pre_update: Callable, @@ -163,7 +163,7 @@ class RegistrarFormSet(forms.BaseFormSet): return query.values() @classmethod - def from_database(cls, obj: DomainApplication, join: str, on_fetch: Callable): + def from_database(cls, obj: DomainRequest, join: str, on_fetch: Callable): """Returns a dict of form field values gotten from `obj`.""" return on_fetch(getattr(obj, join).order_by("created_at")) # order matters @@ -171,7 +171,7 @@ class RegistrarFormSet(forms.BaseFormSet): class OrganizationTypeForm(RegistrarForm): organization_type = forms.ChoiceField( # use the long names in the application form - choices=DomainApplication.OrganizationChoicesVerbose.choices, + choices=DomainRequest.OrganizationChoicesVerbose.choices, widget=forms.RadioSelect, error_messages={"required": "Select the type of organization you represent."}, ) @@ -215,7 +215,7 @@ class TribalGovernmentForm(RegistrarForm): class OrganizationFederalForm(RegistrarForm): federal_type = forms.ChoiceField( - choices=DomainApplication.BranchChoices.choices, + choices=DomainRequest.BranchChoices.choices, widget=forms.RadioSelect, error_messages={"required": ("Select the part of the federal government your organization is in.")}, ) @@ -251,7 +251,7 @@ class OrganizationContactForm(RegistrarForm): # it is a federal agency. Use clean to check programatically # if it has been filled in when required. required=False, - choices=[("", "--Select--")] + DomainApplication.AGENCY_CHOICES, + choices=[("", "--Select--")] + DomainRequest.AGENCY_CHOICES, ) organization_name = forms.CharField( label="Organization name", @@ -271,7 +271,7 @@ class OrganizationContactForm(RegistrarForm): ) state_territory = forms.ChoiceField( label="State, territory, or military post", - choices=[("", "--Select--")] + DomainApplication.StateTerritoryChoices.choices, + choices=[("", "--Select--")] + DomainRequest.StateTerritoryChoices.choices, error_messages={ "required": ("Select the state, territory, or military post where your organization is located.") }, @@ -390,7 +390,7 @@ class BaseCurrentSitesFormSet(RegistrarFormSet): website = cleaned.get("website", "") return website.strip() == "" - def to_database(self, obj: DomainApplication): + def to_database(self, obj: DomainRequest): # If we want to test against multiple joins for a website object, replace the empty array # and change the JOIN in the models to allow for reverse references self._to_database(obj, self.JOIN, self.should_delete, self.pre_update, self.pre_create) @@ -444,7 +444,7 @@ class BaseAlternativeDomainFormSet(RegistrarFormSet): else: return {} - def to_database(self, obj: DomainApplication): + def to_database(self, obj: DomainRequest): # If we want to test against multiple joins for a website object, replace the empty array and # change the JOIN in the models to allow for reverse references self._to_database(obj, self.JOIN, self.should_delete, self.pre_update, self.pre_create) @@ -722,7 +722,7 @@ class BaseOtherContactsFormSet(RegistrarFormSet): cleaned.pop("DELETE") return cleaned - def to_database(self, obj: DomainApplication): + def to_database(self, obj: DomainRequest): self._to_database(obj, self.JOIN, self.should_delete, self.pre_update, self.pre_create) @classmethod diff --git a/src/registrar/management/commands/load.py b/src/registrar/management/commands/load.py index 757d1a6e9..369e9d5ba 100644 --- a/src/registrar/management/commands/load.py +++ b/src/registrar/management/commands/load.py @@ -5,7 +5,7 @@ from auditlog.context import disable_auditlog # type: ignore from registrar.fixtures_users import UserFixture -from registrar.fixtures_applications import DomainApplicationFixture, DomainFixture +from registrar.fixtures_applications import DomainRequestFixture, DomainFixture logger = logging.getLogger(__name__) @@ -16,6 +16,6 @@ class Command(BaseCommand): # https://github.com/jazzband/django-auditlog/issues/17 with disable_auditlog(): UserFixture.load() - DomainApplicationFixture.load() + DomainRequestFixture.load() DomainFixture.load() logger.info("All fixtures loaded.") diff --git a/src/registrar/management/commands/transfer_transition_domains_to_domains.py b/src/registrar/management/commands/transfer_transition_domains_to_domains.py index 15cd7376d..7f09d8de7 100644 --- a/src/registrar/management/commands/transfer_transition_domains_to_domains.py +++ b/src/registrar/management/commands/transfer_transition_domains_to_domains.py @@ -15,7 +15,7 @@ from registrar.management.commands.utility.terminal_helper import ( TerminalHelper, ) from registrar.models.contact import Contact -from registrar.models.domain_application import DomainApplication +from registrar.models.domain_request import DomainRequest from registrar.models.domain_information import DomainInformation from registrar.models.user import User @@ -817,9 +817,9 @@ class Command(BaseCommand): raise Exception(f"Domain {existing_domain} wants to be added" "but doesn't exist in the DB") invitation.save() - valid_org_choices = [(name, value) for name, value in DomainApplication.OrganizationChoices.choices] - valid_fed_choices = [value for name, value in DomainApplication.BranchChoices.choices] - valid_agency_choices = DomainApplication.AGENCIES + valid_org_choices = [(name, value) for name, value in DomainRequest.OrganizationChoices.choices] + valid_fed_choices = [value for name, value in DomainRequest.BranchChoices.choices] + valid_agency_choices = DomainRequest.AGENCIES # ====================================================== # ================= DOMAIN INFORMATION ================= logger.info( diff --git a/src/registrar/migrations/0001_initial.py b/src/registrar/migrations/0001_initial.py index 8c50c750d..70bcde188 100644 --- a/src/registrar/migrations/0001_initial.py +++ b/src/registrar/migrations/0001_initial.py @@ -168,7 +168,7 @@ class Migration(migrations.Migration): ], ), migrations.CreateModel( - name="DomainApplication", + name="DomainRequest", fields=[ ( "id", diff --git a/src/registrar/migrations/0002_domain_host_nameserver_hostip_and_more.py b/src/registrar/migrations/0002_domain_host_nameserver_hostip_and_more.py index f1049c252..d4a4a3918 100644 --- a/src/registrar/migrations/0002_domain_host_nameserver_hostip_and_more.py +++ b/src/registrar/migrations/0002_domain_host_nameserver_hostip_and_more.py @@ -142,14 +142,14 @@ class Migration(migrations.Migration): }, ), migrations.AlterField( - model_name="domainapplication", + model_name="DomainRequest", name="requested_domain", field=models.OneToOneField( blank=True, help_text="The requested domain", null=True, on_delete=django.db.models.deletion.PROTECT, - related_name="domain_application", + related_name="domain_request", to="registrar.domain", ), ), diff --git a/src/registrar/migrations/0003_rename_is_election_office_domainapplication_is_election_board_and_more.py b/src/registrar/migrations/0003_rename_is_election_office_domainapplication_is_election_board_and_more.py index a6844bfaf..587747ea8 100644 --- a/src/registrar/migrations/0003_rename_is_election_office_domainapplication_is_election_board_and_more.py +++ b/src/registrar/migrations/0003_rename_is_election_office_domainapplication_is_election_board_and_more.py @@ -10,48 +10,48 @@ class Migration(migrations.Migration): operations = [ migrations.RenameField( - model_name="domainapplication", + model_name="DomainRequest", old_name="is_election_office", new_name="is_election_board", ), migrations.RenameField( - model_name="domainapplication", + model_name="DomainRequest", old_name="acknowledged_policy", new_name="is_policy_acknowledged", ), migrations.RenameField( - model_name="domainapplication", + model_name="DomainRequest", old_name="zip_code", new_name="zipcode", ), migrations.RemoveField( - model_name="domainapplication", + model_name="DomainRequest", name="federal_branch", ), migrations.RemoveField( - model_name="domainapplication", + model_name="DomainRequest", name="street_address", ), migrations.RemoveField( - model_name="domainapplication", + model_name="DomainRequest", name="unit_number", ), migrations.RemoveField( - model_name="domainapplication", + model_name="DomainRequest", name="unit_type", ), migrations.AddField( - model_name="domainapplication", + model_name="DomainRequest", name="address_line1", field=models.TextField(blank=True, help_text="Address line 1", null=True), ), migrations.AddField( - model_name="domainapplication", + model_name="DomainRequest", name="address_line2", field=models.CharField(blank=True, help_text="Address line 2", max_length=15, null=True), ), migrations.AddField( - model_name="domainapplication", + model_name="DomainRequest", name="federal_type", field=models.CharField( blank=True, @@ -66,7 +66,7 @@ class Migration(migrations.Migration): ), ), migrations.AlterField( - model_name="domainapplication", + model_name="DomainRequest", name="organization_type", field=models.CharField( blank=True, diff --git a/src/registrar/migrations/0004_domainapplication_federal_agency.py b/src/registrar/migrations/0004_domainapplication_federal_agency.py index a00d46ac2..cffe5a864 100644 --- a/src/registrar/migrations/0004_domainapplication_federal_agency.py +++ b/src/registrar/migrations/0004_domainapplication_federal_agency.py @@ -7,13 +7,13 @@ class Migration(migrations.Migration): dependencies = [ ( "registrar", - "0003_rename_is_election_office_domainapplication_is_election_board_and_more", + "0003_rename_is_election_office_DomainRequest_is_election_board_and_more", ), ] operations = [ migrations.AddField( - model_name="domainapplication", + model_name="DomainRequest", name="federal_agency", field=models.TextField(help_text="Top level federal agency", null=True), ), diff --git a/src/registrar/migrations/0005_domainapplication_city_and_more.py b/src/registrar/migrations/0005_domainapplication_city_and_more.py index bd4683b8c..4f933ceb2 100644 --- a/src/registrar/migrations/0005_domainapplication_city_and_more.py +++ b/src/registrar/migrations/0005_domainapplication_city_and_more.py @@ -5,22 +5,22 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ("registrar", "0004_domainapplication_federal_agency"), + ("registrar", "0004_DomainRequest_federal_agency"), ] operations = [ migrations.AddField( - model_name="domainapplication", + model_name="DomainRequest", name="city", field=models.TextField(blank=True, help_text="City", null=True), ), migrations.AddField( - model_name="domainapplication", + model_name="DomainRequest", name="urbanization", field=models.TextField(blank=True, help_text="Urbanization", null=True), ), migrations.AlterField( - model_name="domainapplication", + model_name="DomainRequest", name="federal_agency", field=models.TextField(blank=True, help_text="Top level federal agency", null=True), ), diff --git a/src/registrar/migrations/0006_alter_contact_phone.py b/src/registrar/migrations/0006_alter_contact_phone.py index 1e055694f..09bcc1fbb 100644 --- a/src/registrar/migrations/0006_alter_contact_phone.py +++ b/src/registrar/migrations/0006_alter_contact_phone.py @@ -6,7 +6,7 @@ import phonenumber_field.modelfields # type: ignore class Migration(migrations.Migration): dependencies = [ - ("registrar", "0005_domainapplication_city_and_more"), + ("registrar", "0005_DomainRequest_city_and_more"), ] operations = [ diff --git a/src/registrar/migrations/0007_domainapplication_more_organization_information_and_more.py b/src/registrar/migrations/0007_domainapplication_more_organization_information_and_more.py index 49df16fbb..e6199ea86 100644 --- a/src/registrar/migrations/0007_domainapplication_more_organization_information_and_more.py +++ b/src/registrar/migrations/0007_domainapplication_more_organization_information_and_more.py @@ -10,7 +10,7 @@ class Migration(migrations.Migration): operations = [ migrations.AddField( - model_name="domainapplication", + model_name="DomainRequest", name="more_organization_information", field=models.TextField( blank=True, @@ -19,27 +19,27 @@ class Migration(migrations.Migration): ), ), migrations.AddField( - model_name="domainapplication", + model_name="DomainRequest", name="type_of_work", field=models.TextField(blank=True, help_text="Type of work of the organization", null=True), ), migrations.AlterField( - model_name="domainapplication", + model_name="DomainRequest", name="address_line1", field=models.TextField(blank=True, help_text="Street address", null=True), ), migrations.AlterField( - model_name="domainapplication", + model_name="DomainRequest", name="address_line2", field=models.CharField(blank=True, help_text="Street address line 2", max_length=15, null=True), ), migrations.AlterField( - model_name="domainapplication", + model_name="DomainRequest", name="federal_agency", field=models.TextField(blank=True, help_text="Federal agency", null=True), ), migrations.AlterField( - model_name="domainapplication", + model_name="DomainRequest", name="federal_type", field=models.CharField( blank=True, @@ -54,7 +54,7 @@ class Migration(migrations.Migration): ), ), migrations.AlterField( - model_name="domainapplication", + model_name="DomainRequest", name="organization_type", field=models.CharField( blank=True, @@ -89,12 +89,12 @@ class Migration(migrations.Migration): ), ), migrations.AlterField( - model_name="domainapplication", + model_name="DomainRequest", name="purpose", field=models.TextField(blank=True, help_text="Purpose of your domain", null=True), ), migrations.AlterField( - model_name="domainapplication", + model_name="DomainRequest", name="state_territory", field=models.CharField( blank=True, @@ -104,12 +104,12 @@ class Migration(migrations.Migration): ), ), migrations.AlterField( - model_name="domainapplication", + model_name="DomainRequest", name="urbanization", field=models.TextField(blank=True, help_text="Urbanization (Puerto Rico only)", null=True), ), migrations.AlterField( - model_name="domainapplication", + model_name="DomainRequest", name="zipcode", field=models.CharField( blank=True, diff --git a/src/registrar/migrations/0008_remove_userprofile_created_at_and_more.py b/src/registrar/migrations/0008_remove_userprofile_created_at_and_more.py index 2e2dbed6c..045e83f49 100644 --- a/src/registrar/migrations/0008_remove_userprofile_created_at_and_more.py +++ b/src/registrar/migrations/0008_remove_userprofile_created_at_and_more.py @@ -6,7 +6,7 @@ import django.utils.timezone class Migration(migrations.Migration): dependencies = [ - ("registrar", "0007_domainapplication_more_organization_information_and_more"), + ("registrar", "0007_DomainRequest_more_organization_information_and_more"), ] operations = [ diff --git a/src/registrar/migrations/0009_domainapplication_federally_recognized_tribe_and_more.py b/src/registrar/migrations/0009_domainapplication_federally_recognized_tribe_and_more.py index 7fce25b9e..2c9c26888 100644 --- a/src/registrar/migrations/0009_domainapplication_federally_recognized_tribe_and_more.py +++ b/src/registrar/migrations/0009_domainapplication_federally_recognized_tribe_and_more.py @@ -10,17 +10,17 @@ class Migration(migrations.Migration): operations = [ migrations.AddField( - model_name="domainapplication", + model_name="DomainRequest", name="federally_recognized_tribe", field=models.BooleanField(help_text="Is the tribe federally recognized", null=True), ), migrations.AddField( - model_name="domainapplication", + model_name="DomainRequest", name="state_recognized_tribe", field=models.BooleanField(help_text="Is the tribe recognized by a state", null=True), ), migrations.AddField( - model_name="domainapplication", + model_name="DomainRequest", name="tribe_name", field=models.TextField(blank=True, help_text="Name of tribe", null=True), ), diff --git a/src/registrar/migrations/0010_domainapplication_no_other_contacts_rationale.py b/src/registrar/migrations/0010_domainapplication_no_other_contacts_rationale.py index bf8d83d60..412fcc6db 100644 --- a/src/registrar/migrations/0010_domainapplication_no_other_contacts_rationale.py +++ b/src/registrar/migrations/0010_domainapplication_no_other_contacts_rationale.py @@ -5,12 +5,12 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ("registrar", "0009_domainapplication_federally_recognized_tribe_and_more"), + ("registrar", "0009_DomainRequest_federally_recognized_tribe_and_more"), ] operations = [ migrations.AddField( - model_name="domainapplication", + model_name="DomainRequest", name="no_other_contacts_rationale", field=models.TextField( blank=True, diff --git a/src/registrar/migrations/0011_remove_domainapplication_security_email.py b/src/registrar/migrations/0011_remove_domainapplication_security_email.py index c717408da..5d5c278ac 100644 --- a/src/registrar/migrations/0011_remove_domainapplication_security_email.py +++ b/src/registrar/migrations/0011_remove_domainapplication_security_email.py @@ -5,12 +5,12 @@ from django.db import migrations class Migration(migrations.Migration): dependencies = [ - ("registrar", "0010_domainapplication_no_other_contacts_rationale"), + ("registrar", "0010_DomainRequest_no_other_contacts_rationale"), ] operations = [ migrations.RemoveField( - model_name="domainapplication", + model_name="DomainRequest", name="security_email", ), ] diff --git a/src/registrar/migrations/0012_delete_userprofile.py b/src/registrar/migrations/0012_delete_userprofile.py index b5bcebb95..29305d519 100644 --- a/src/registrar/migrations/0012_delete_userprofile.py +++ b/src/registrar/migrations/0012_delete_userprofile.py @@ -7,7 +7,7 @@ import django.db.models.deletion class Migration(migrations.Migration): dependencies = [ - ("registrar", "0011_remove_domainapplication_security_email"), + ("registrar", "0011_remove_DomainRequest_security_email"), ] operations = [ diff --git a/src/registrar/migrations/0017_alter_domainapplication_status_and_more.py b/src/registrar/migrations/0017_alter_domainapplication_status_and_more.py index 5d20551d7..341c83994 100644 --- a/src/registrar/migrations/0017_alter_domainapplication_status_and_more.py +++ b/src/registrar/migrations/0017_alter_domainapplication_status_and_more.py @@ -11,7 +11,7 @@ class Migration(migrations.Migration): operations = [ migrations.AlterField( - model_name="domainapplication", + model_name="DomainRequest", name="status", field=django_fsm.FSMField( choices=[ diff --git a/src/registrar/migrations/0018_domaininformation.py b/src/registrar/migrations/0018_domaininformation.py index 582a6e244..38a24f7d8 100644 --- a/src/registrar/migrations/0018_domaininformation.py +++ b/src/registrar/migrations/0018_domaininformation.py @@ -7,7 +7,7 @@ import django.db.models.deletion class Migration(migrations.Migration): dependencies = [ - ("registrar", "0017_alter_domainapplication_status_and_more"), + ("registrar", "0017_alter_DomainRequest_status_and_more"), ] operations = [ @@ -229,14 +229,14 @@ class Migration(migrations.Migration): ), ), ( - "domain_application", + "domain_request", models.OneToOneField( blank=True, - help_text="Associated domain application", + help_text="Associated domain request", null=True, on_delete=django.db.models.deletion.PROTECT, - related_name="domainapplication_info", - to="registrar.domainapplication", + related_name="DomainRequest_info", + to="registrar.DomainRequest", ), ), ( diff --git a/src/registrar/migrations/0019_alter_domainapplication_organization_type.py b/src/registrar/migrations/0019_alter_domainapplication_organization_type.py index 1a7397255..60273e854 100644 --- a/src/registrar/migrations/0019_alter_domainapplication_organization_type.py +++ b/src/registrar/migrations/0019_alter_domainapplication_organization_type.py @@ -10,7 +10,7 @@ class Migration(migrations.Migration): operations = [ migrations.AlterField( - model_name="domainapplication", + model_name="DomainRequest", name="organization_type", field=models.CharField( blank=True, diff --git a/src/registrar/migrations/0020_remove_domaininformation_security_email.py b/src/registrar/migrations/0020_remove_domaininformation_security_email.py index 9742c294a..b48133ade 100644 --- a/src/registrar/migrations/0020_remove_domaininformation_security_email.py +++ b/src/registrar/migrations/0020_remove_domaininformation_security_email.py @@ -5,7 +5,7 @@ from django.db import migrations class Migration(migrations.Migration): dependencies = [ - ("registrar", "0019_alter_domainapplication_organization_type"), + ("registrar", "0019_alter_DomainRequest_organization_type"), ] operations = [ diff --git a/src/registrar/migrations/0022_draftdomain_domainapplication_approved_domain_and_more.py b/src/registrar/migrations/0022_draftdomain_domainapplication_approved_domain_and_more.py index fb89e0eb2..6a44c93d9 100644 --- a/src/registrar/migrations/0022_draftdomain_domainapplication_approved_domain_and_more.py +++ b/src/registrar/migrations/0022_draftdomain_domainapplication_approved_domain_and_more.py @@ -40,26 +40,26 @@ class Migration(migrations.Migration): bases=(models.Model, registrar.models.utility.domain_helper.DomainHelper), # type: ignore ), migrations.AddField( - model_name="domainapplication", + model_name="DomainRequest", name="approved_domain", field=models.OneToOneField( blank=True, help_text="The approved domain", null=True, on_delete=django.db.models.deletion.PROTECT, - related_name="domain_application", + related_name="domain_request", to="registrar.domain", ), ), migrations.AlterField( - model_name="domainapplication", + model_name="DomainRequest", name="requested_domain", field=models.OneToOneField( blank=True, help_text="The requested domain", null=True, on_delete=django.db.models.deletion.PROTECT, - related_name="domain_application", + related_name="domain_request", to="registrar.draftdomain", ), ), diff --git a/src/registrar/migrations/0023_alter_contact_first_name_alter_contact_last_name_and_more.py b/src/registrar/migrations/0023_alter_contact_first_name_alter_contact_last_name_and_more.py index b2259f650..85ba6268b 100644 --- a/src/registrar/migrations/0023_alter_contact_first_name_alter_contact_last_name_and_more.py +++ b/src/registrar/migrations/0023_alter_contact_first_name_alter_contact_last_name_and_more.py @@ -5,7 +5,7 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ("registrar", "0022_draftdomain_domainapplication_approved_domain_and_more"), + ("registrar", "0022_draftdomain_DomainRequest_approved_domain_and_more"), ] operations = [ diff --git a/src/registrar/migrations/0026_alter_domainapplication_address_line2_and_more.py b/src/registrar/migrations/0026_alter_domainapplication_address_line2_and_more.py index 77da9e79c..5ec43af43 100644 --- a/src/registrar/migrations/0026_alter_domainapplication_address_line2_and_more.py +++ b/src/registrar/migrations/0026_alter_domainapplication_address_line2_and_more.py @@ -10,7 +10,7 @@ class Migration(migrations.Migration): operations = [ migrations.AlterField( - model_name="domainapplication", + model_name="DomainRequest", name="address_line2", field=models.TextField(blank=True, help_text="Street address line 2", null=True), ), diff --git a/src/registrar/migrations/0027_alter_domaininformation_address_line1_and_more.py b/src/registrar/migrations/0027_alter_domaininformation_address_line1_and_more.py index 9f362c956..0d25ec506 100644 --- a/src/registrar/migrations/0027_alter_domaininformation_address_line1_and_more.py +++ b/src/registrar/migrations/0027_alter_domaininformation_address_line1_and_more.py @@ -5,7 +5,7 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ("registrar", "0026_alter_domainapplication_address_line2_and_more"), + ("registrar", "0026_alter_DomainRequest_address_line2_and_more"), ] operations = [ diff --git a/src/registrar/migrations/0028_alter_domainapplication_status.py b/src/registrar/migrations/0028_alter_domainapplication_status.py index 61b1c0505..ed2544779 100644 --- a/src/registrar/migrations/0028_alter_domainapplication_status.py +++ b/src/registrar/migrations/0028_alter_domainapplication_status.py @@ -13,7 +13,7 @@ class Migration(migrations.Migration): operations = [ migrations.AlterField( - model_name="domainapplication", + model_name="DomainRequest", name="status", field=django_fsm.FSMField( choices=[ diff --git a/src/registrar/migrations/0029_user_status_alter_domainapplication_status.py b/src/registrar/migrations/0029_user_status_alter_domainapplication_status.py index 504358665..f3c9bea83 100644 --- a/src/registrar/migrations/0029_user_status_alter_domainapplication_status.py +++ b/src/registrar/migrations/0029_user_status_alter_domainapplication_status.py @@ -6,7 +6,7 @@ import django_fsm class Migration(migrations.Migration): dependencies = [ - ("registrar", "0028_alter_domainapplication_status"), + ("registrar", "0028_alter_DomainRequest_status"), ] operations = [ @@ -22,7 +22,7 @@ class Migration(migrations.Migration): ), ), migrations.AlterField( - model_name="domainapplication", + model_name="DomainRequest", name="status", field=django_fsm.FSMField( choices=[ diff --git a/src/registrar/migrations/0030_alter_user_status.py b/src/registrar/migrations/0030_alter_user_status.py index 7dd27bfa4..a1055017b 100644 --- a/src/registrar/migrations/0030_alter_user_status.py +++ b/src/registrar/migrations/0030_alter_user_status.py @@ -5,7 +5,7 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ("registrar", "0029_user_status_alter_domainapplication_status"), + ("registrar", "0029_user_status_alter_DomainRequest_status"), ] operations = [ diff --git a/src/registrar/migrations/0031_transitiondomain_and_more.py b/src/registrar/migrations/0031_transitiondomain_and_more.py index 9d1153764..a3982fd6a 100644 --- a/src/registrar/migrations/0031_transitiondomain_and_more.py +++ b/src/registrar/migrations/0031_transitiondomain_and_more.py @@ -77,11 +77,11 @@ class Migration(migrations.Migration): }, ), migrations.RemoveField( - model_name="domainapplication", + model_name="DomainRequest", name="more_organization_information", ), migrations.RemoveField( - model_name="domainapplication", + model_name="DomainRequest", name="type_of_work", ), migrations.RemoveField( @@ -93,7 +93,7 @@ class Migration(migrations.Migration): name="type_of_work", ), migrations.AddField( - model_name="domainapplication", + model_name="DomainRequest", name="about_your_organization", field=models.TextField(blank=True, help_text="Information about your organization", null=True), ), @@ -103,14 +103,14 @@ class Migration(migrations.Migration): field=models.TextField(blank=True, help_text="Information about your organization", null=True), ), migrations.AlterField( - model_name="domainapplication", + model_name="DomainRequest", name="approved_domain", field=models.OneToOneField( blank=True, help_text="The approved domain", null=True, on_delete=django.db.models.deletion.SET_NULL, - related_name="domain_application", + related_name="domain_request", to="registrar.domain", ), ), diff --git a/src/registrar/migrations/0041_alter_domainapplication_organization_type_and_more.py b/src/registrar/migrations/0041_alter_domainapplication_organization_type_and_more.py index 07cfe0e77..57201c1bf 100644 --- a/src/registrar/migrations/0041_alter_domainapplication_organization_type_and_more.py +++ b/src/registrar/migrations/0041_alter_domainapplication_organization_type_and_more.py @@ -10,7 +10,7 @@ class Migration(migrations.Migration): operations = [ migrations.AlterField( - model_name="domainapplication", + model_name="DomainRequest", name="organization_type", field=models.CharField( blank=True, diff --git a/src/registrar/migrations/0042_create_groups_v03.py b/src/registrar/migrations/0042_create_groups_v03.py index 01b7985bf..2d23d870f 100644 --- a/src/registrar/migrations/0042_create_groups_v03.py +++ b/src/registrar/migrations/0042_create_groups_v03.py @@ -25,7 +25,7 @@ def create_groups(apps, schema_editor) -> Any: class Migration(migrations.Migration): dependencies = [ - ("registrar", "0041_alter_domainapplication_organization_type_and_more"), + ("registrar", "0041_alter_DomainRequest_organization_type_and_more"), ] operations = [ diff --git a/src/registrar/migrations/0049_alter_domainapplication_current_websites_and_more.py b/src/registrar/migrations/0049_alter_domainapplication_current_websites_and_more.py index 4341bdad6..49516deb7 100644 --- a/src/registrar/migrations/0049_alter_domainapplication_current_websites_and_more.py +++ b/src/registrar/migrations/0049_alter_domainapplication_current_websites_and_more.py @@ -10,14 +10,14 @@ class Migration(migrations.Migration): operations = [ migrations.AlterField( - model_name="domainapplication", + model_name="DomainRequest", name="current_websites", field=models.ManyToManyField( blank=True, related_name="current+", to="registrar.website", verbose_name="websites" ), ), migrations.AlterField( - model_name="domainapplication", + model_name="DomainRequest", name="other_contacts", field=models.ManyToManyField( blank=True, related_name="contact_applications", to="registrar.contact", verbose_name="contacts" diff --git a/src/registrar/migrations/0050_alter_contact_middle_name_and_more.py b/src/registrar/migrations/0050_alter_contact_middle_name_and_more.py index 4009d17d9..67ad4e1c6 100644 --- a/src/registrar/migrations/0050_alter_contact_middle_name_and_more.py +++ b/src/registrar/migrations/0050_alter_contact_middle_name_and_more.py @@ -5,7 +5,7 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ("registrar", "0049_alter_domainapplication_current_websites_and_more"), + ("registrar", "0049_alter_DomainRequest_current_websites_and_more"), ] operations = [ @@ -15,7 +15,7 @@ class Migration(migrations.Migration): field=models.TextField(blank=True, help_text="Middle name (optional)", null=True), ), migrations.AlterField( - model_name="domainapplication", + model_name="DomainRequest", name="address_line2", field=models.TextField(blank=True, help_text="Street address line 2 (optional)", null=True), ), diff --git a/src/registrar/migrations/0051_alter_domainapplication_urbanization_and_more.py b/src/registrar/migrations/0051_alter_domainapplication_urbanization_and_more.py index 9b012042d..93865b021 100644 --- a/src/registrar/migrations/0051_alter_domainapplication_urbanization_and_more.py +++ b/src/registrar/migrations/0051_alter_domainapplication_urbanization_and_more.py @@ -10,7 +10,7 @@ class Migration(migrations.Migration): operations = [ migrations.AlterField( - model_name="domainapplication", + model_name="DomainRequest", name="urbanization", field=models.TextField(blank=True, help_text="Urbanization (required for Puerto Rico only)", null=True), ), diff --git a/src/registrar/migrations/0052_alter_domainapplication_anything_else_and_more.py b/src/registrar/migrations/0052_alter_domainapplication_anything_else_and_more.py index 1d5607aad..c4d8d8807 100644 --- a/src/registrar/migrations/0052_alter_domainapplication_anything_else_and_more.py +++ b/src/registrar/migrations/0052_alter_domainapplication_anything_else_and_more.py @@ -5,12 +5,12 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ("registrar", "0051_alter_domainapplication_urbanization_and_more"), + ("registrar", "0051_alter_DomainRequest_urbanization_and_more"), ] operations = [ migrations.AlterField( - model_name="domainapplication", + model_name="DomainRequest", name="anything_else", field=models.TextField(blank=True, help_text="Anything else?", null=True), ), diff --git a/src/registrar/migrations/0053_create_groups_v05.py b/src/registrar/migrations/0053_create_groups_v05.py index aaf74a9db..3df23d152 100644 --- a/src/registrar/migrations/0053_create_groups_v05.py +++ b/src/registrar/migrations/0053_create_groups_v05.py @@ -25,7 +25,7 @@ def create_groups(apps, schema_editor) -> Any: class Migration(migrations.Migration): dependencies = [ - ("registrar", "0052_alter_domainapplication_anything_else_and_more"), + ("registrar", "0052_alter_DomainRequest_anything_else_and_more"), ] operations = [ diff --git a/src/registrar/migrations/0054_alter_domainapplication_federal_agency_and_more.py b/src/registrar/migrations/0054_alter_domainapplication_federal_agency_and_more.py index d16c9befd..2f00c1958 100644 --- a/src/registrar/migrations/0054_alter_domainapplication_federal_agency_and_more.py +++ b/src/registrar/migrations/0054_alter_domainapplication_federal_agency_and_more.py @@ -10,7 +10,7 @@ class Migration(migrations.Migration): operations = [ migrations.AlterField( - model_name="domainapplication", + model_name="DomainRequest", name="federal_agency", field=models.TextField( blank=True, @@ -317,7 +317,7 @@ class Migration(migrations.Migration): ), ), migrations.AlterField( - model_name="domainapplication", + model_name="DomainRequest", name="state_territory", field=models.CharField( blank=True, diff --git a/src/registrar/migrations/0055_transitiondomain_processed.py b/src/registrar/migrations/0055_transitiondomain_processed.py index a2fb78edd..1261fb451 100644 --- a/src/registrar/migrations/0055_transitiondomain_processed.py +++ b/src/registrar/migrations/0055_transitiondomain_processed.py @@ -5,7 +5,7 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ("registrar", "0054_alter_domainapplication_federal_agency_and_more"), + ("registrar", "0054_alter_DomainRequest_federal_agency_and_more"), ] operations = [ diff --git a/src/registrar/migrations/0056_alter_domain_state_alter_domainapplication_status_and_more.py b/src/registrar/migrations/0056_alter_domain_state_alter_domainapplication_status_and_more.py index 097cddf8a..7ee51b73e 100644 --- a/src/registrar/migrations/0056_alter_domain_state_alter_domainapplication_status_and_more.py +++ b/src/registrar/migrations/0056_alter_domain_state_alter_domainapplication_status_and_more.py @@ -28,7 +28,7 @@ class Migration(migrations.Migration): ), ), migrations.AlterField( - model_name="domainapplication", + model_name="DomainRequest", name="status", field=django_fsm.FSMField( choices=[ diff --git a/src/registrar/migrations/0057_domainapplication_submission_date.py b/src/registrar/migrations/0057_domainapplication_submission_date.py index a2a170888..7e914e8f1 100644 --- a/src/registrar/migrations/0057_domainapplication_submission_date.py +++ b/src/registrar/migrations/0057_domainapplication_submission_date.py @@ -5,12 +5,12 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ("registrar", "0056_alter_domain_state_alter_domainapplication_status_and_more"), + ("registrar", "0056_alter_domain_state_alter_DomainRequest_status_and_more"), ] operations = [ migrations.AddField( - model_name="domainapplication", + model_name="DomainRequest", name="submission_date", field=models.DateField(blank=True, default=None, help_text="Date submitted", null=True), ), diff --git a/src/registrar/migrations/0058_alter_domaininformation_options.py b/src/registrar/migrations/0058_alter_domaininformation_options.py index 2e128cbda..db6e7b24f 100644 --- a/src/registrar/migrations/0058_alter_domaininformation_options.py +++ b/src/registrar/migrations/0058_alter_domaininformation_options.py @@ -5,7 +5,7 @@ from django.db import migrations class Migration(migrations.Migration): dependencies = [ - ("registrar", "0057_domainapplication_submission_date"), + ("registrar", "0057_DomainRequest_submission_date"), ] operations = [ diff --git a/src/registrar/migrations/0064_alter_domainapplication_address_line1_and_more.py b/src/registrar/migrations/0064_alter_domainapplication_address_line1_and_more.py index 7241c7164..238f084f3 100644 --- a/src/registrar/migrations/0064_alter_domainapplication_address_line1_and_more.py +++ b/src/registrar/migrations/0064_alter_domainapplication_address_line1_and_more.py @@ -10,12 +10,12 @@ class Migration(migrations.Migration): operations = [ migrations.AlterField( - model_name="domainapplication", + model_name="DomainRequest", name="address_line1", field=models.TextField(blank=True, help_text="Street address", null=True, verbose_name="Address line 1"), ), migrations.AlterField( - model_name="domainapplication", + model_name="DomainRequest", name="address_line2", field=models.TextField( blank=True, help_text="Street address line 2 (optional)", null=True, verbose_name="Address line 2" diff --git a/src/registrar/migrations/0065_create_groups_v06.py b/src/registrar/migrations/0065_create_groups_v06.py index d2cb32cee..aa943c174 100644 --- a/src/registrar/migrations/0065_create_groups_v06.py +++ b/src/registrar/migrations/0065_create_groups_v06.py @@ -25,7 +25,7 @@ def create_groups(apps, schema_editor) -> Any: class Migration(migrations.Migration): dependencies = [ - ("registrar", "0064_alter_domainapplication_address_line1_and_more"), + ("registrar", "0064_alter_DomainRequest_address_line1_and_more"), ] operations = [ diff --git a/src/registrar/migrations/0068_domainapplication_notes_domaininformation_notes.py b/src/registrar/migrations/0068_domainapplication_notes_domaininformation_notes.py index ea94be77e..ddf3dc914 100644 --- a/src/registrar/migrations/0068_domainapplication_notes_domaininformation_notes.py +++ b/src/registrar/migrations/0068_domainapplication_notes_domaininformation_notes.py @@ -10,7 +10,7 @@ class Migration(migrations.Migration): operations = [ migrations.AddField( - model_name="domainapplication", + model_name="DomainRequest", name="notes", field=models.TextField(blank=True, help_text="Notes about this request", null=True), ), diff --git a/src/registrar/migrations/0069_alter_contact_email_alter_contact_first_name_and_more.py b/src/registrar/migrations/0069_alter_contact_email_alter_contact_first_name_and_more.py index 5869e6fae..b6b546d67 100644 --- a/src/registrar/migrations/0069_alter_contact_email_alter_contact_first_name_and_more.py +++ b/src/registrar/migrations/0069_alter_contact_email_alter_contact_first_name_and_more.py @@ -6,7 +6,7 @@ import phonenumber_field.modelfields class Migration(migrations.Migration): dependencies = [ - ("registrar", "0068_domainapplication_notes_domaininformation_notes"), + ("registrar", "0068_DomainRequest_notes_domaininformation_notes"), ] operations = [ diff --git a/src/registrar/migrations/0070_domainapplication_rejection_reason.py b/src/registrar/migrations/0070_domainapplication_rejection_reason.py index d559973e2..4ce7aa83f 100644 --- a/src/registrar/migrations/0070_domainapplication_rejection_reason.py +++ b/src/registrar/migrations/0070_domainapplication_rejection_reason.py @@ -10,7 +10,7 @@ class Migration(migrations.Migration): operations = [ migrations.AddField( - model_name="domainapplication", + model_name="DomainRequest", name="rejection_reason", field=models.TextField( blank=True, diff --git a/src/registrar/migrations/0071_alter_contact_first_name_alter_contact_last_name_and_more.py b/src/registrar/migrations/0071_alter_contact_first_name_alter_contact_last_name_and_more.py index bc594138e..af28dbf56 100644 --- a/src/registrar/migrations/0071_alter_contact_first_name_alter_contact_last_name_and_more.py +++ b/src/registrar/migrations/0071_alter_contact_first_name_alter_contact_last_name_and_more.py @@ -7,7 +7,7 @@ import phonenumber_field.modelfields class Migration(migrations.Migration): dependencies = [ - ("registrar", "0070_domainapplication_rejection_reason"), + ("registrar", "0070_DomainRequest_rejection_reason"), ] operations = [ @@ -32,24 +32,24 @@ class Migration(migrations.Migration): field=models.CharField(blank=True, null=True, verbose_name="title or role in your organization"), ), migrations.AlterField( - model_name="domainapplication", + model_name="DomainRequest", name="address_line1", field=models.CharField(blank=True, help_text="Street address", null=True, verbose_name="Address line 1"), ), migrations.AlterField( - model_name="domainapplication", + model_name="DomainRequest", name="address_line2", field=models.CharField( blank=True, help_text="Street address line 2 (optional)", null=True, verbose_name="Address line 2" ), ), migrations.AlterField( - model_name="domainapplication", + model_name="DomainRequest", name="city", field=models.CharField(blank=True, help_text="City", null=True), ), migrations.AlterField( - model_name="domainapplication", + model_name="DomainRequest", name="federal_agency", field=models.CharField( blank=True, @@ -356,17 +356,17 @@ class Migration(migrations.Migration): ), ), migrations.AlterField( - model_name="domainapplication", + model_name="DomainRequest", name="organization_name", field=models.CharField(blank=True, db_index=True, help_text="Organization name", null=True), ), migrations.AlterField( - model_name="domainapplication", + model_name="DomainRequest", name="tribe_name", field=models.CharField(blank=True, help_text="Name of tribe", null=True), ), migrations.AlterField( - model_name="domainapplication", + model_name="DomainRequest", name="urbanization", field=models.CharField(blank=True, help_text="Urbanization (required for Puerto Rico only)", null=True), ), diff --git a/src/registrar/models/__init__.py b/src/registrar/models/__init__.py index d9ccd64cb..d203421ac 100644 --- a/src/registrar/models/__init__.py +++ b/src/registrar/models/__init__.py @@ -1,6 +1,6 @@ from auditlog.registry import auditlog # type: ignore from .contact import Contact -from .domain_application import DomainApplication +from .domain_request import DomainRequest from .domain_information import DomainInformation from .domain import Domain from .draft_domain import DraftDomain @@ -17,7 +17,7 @@ from .verified_by_staff import VerifiedByStaff __all__ = [ "Contact", - "DomainApplication", + "DomainRequest", "DomainInformation", "Domain", "DraftDomain", @@ -34,7 +34,7 @@ __all__ = [ ] auditlog.register(Contact) -auditlog.register(DomainApplication) +auditlog.register(DomainRequest) auditlog.register(Domain) auditlog.register(DraftDomain) auditlog.register(DomainInvitation) diff --git a/src/registrar/models/domain.py b/src/registrar/models/domain.py index 449c4c4bb..079fce3bc 100644 --- a/src/registrar/models/domain.py +++ b/src/registrar/models/domain.py @@ -897,8 +897,8 @@ class Domain(TimeStampedModel, DomainHelper): def security_contact(self, contact: PublicContact): """makes the contact in the registry, for security the public contact should have the org or registrant information - from domain information (not domain application) - and should have the security email from DomainApplication""" + from domain information (not domain request) + and should have the security email from DomainRequest""" logger.info("making security contact in registry") self._set_singleton_contact(contact, expectedType=contact.ContactTypeChoices.SECURITY) diff --git a/src/registrar/models/domain_application.py b/src/registrar/models/domain_application.py index 8c417b51a..5a1865b3a 100644 --- a/src/registrar/models/domain_application.py +++ b/src/registrar/models/domain_application.py @@ -17,7 +17,7 @@ from itertools import chain logger = logging.getLogger(__name__) -class DomainApplication(TimeStampedModel): +class DomainRequest(TimeStampedModel): """A registrant's application for a new domain.""" # Constants for choice fields @@ -512,7 +512,7 @@ class DomainApplication(TimeStampedModel): null=True, blank=True, help_text="The approved domain", - related_name="domain_application", + related_name="domain_request", on_delete=models.SET_NULL, ) @@ -521,7 +521,7 @@ class DomainApplication(TimeStampedModel): null=True, blank=True, help_text="The requested domain", - related_name="domain_application", + related_name="domain_request", on_delete=models.PROTECT, ) alternative_domains = models.ManyToManyField( @@ -722,7 +722,7 @@ class DomainApplication(TimeStampedModel): if self.status == self.ApplicationStatus.REJECTED: self.rejection_reason = None - literal = DomainApplication.ApplicationStatus.IN_REVIEW + literal = DomainRequest.ApplicationStatus.IN_REVIEW # Check if the tuple exists, then grab its value in_review = literal if literal is not None else "In Review" logger.info(f"A status change occurred. {self} was changed to '{in_review}'") @@ -754,7 +754,7 @@ class DomainApplication(TimeStampedModel): if self.status == self.ApplicationStatus.REJECTED: self.rejection_reason = None - literal = DomainApplication.ApplicationStatus.ACTION_NEEDED + literal = DomainRequest.ApplicationStatus.ACTION_NEEDED # Check if the tuple is setup correctly, then grab its value action_needed = literal if literal is not None else "Action Needed" logger.info(f"A status change occurred. {self} was changed to '{action_needed}'") @@ -786,9 +786,9 @@ class DomainApplication(TimeStampedModel): created_domain = Domain.objects.create(name=self.requested_domain.name) self.approved_domain = created_domain - # copy the information from domainapplication into domaininformation + # copy the information from DomainRequest into domaininformation DomainInformation = apps.get_model("registrar.DomainInformation") - DomainInformation.create_from_da(domain_application=self, domain=created_domain) + DomainInformation.create_from_da(domain_request=self, domain=created_domain) # create the permission for the user UserDomainRole = apps.get_model("registrar.UserDomainRole") @@ -875,12 +875,12 @@ class DomainApplication(TimeStampedModel): def show_organization_federal(self) -> bool: """Show this step if the answer to the first question was "federal".""" user_choice = self.organization_type - return user_choice == DomainApplication.OrganizationChoices.FEDERAL + return user_choice == DomainRequest.OrganizationChoices.FEDERAL def show_tribal_government(self) -> bool: """Show this step if the answer to the first question was "tribal".""" user_choice = self.organization_type - return user_choice == DomainApplication.OrganizationChoices.TRIBAL + return user_choice == DomainRequest.OrganizationChoices.TRIBAL def show_organization_election(self) -> bool: """Show this step if the answer to the first question implies it. @@ -890,9 +890,9 @@ class DomainApplication(TimeStampedModel): """ user_choice = self.organization_type excluded = [ - DomainApplication.OrganizationChoices.FEDERAL, - DomainApplication.OrganizationChoices.INTERSTATE, - DomainApplication.OrganizationChoices.SCHOOL_DISTRICT, + DomainRequest.OrganizationChoices.FEDERAL, + DomainRequest.OrganizationChoices.INTERSTATE, + DomainRequest.OrganizationChoices.SCHOOL_DISTRICT, ] return bool(user_choice and user_choice not in excluded) @@ -900,8 +900,8 @@ class DomainApplication(TimeStampedModel): """Show this step if this is a special district or interstate.""" user_choice = self.organization_type return user_choice in [ - DomainApplication.OrganizationChoices.SPECIAL_DISTRICT, - DomainApplication.OrganizationChoices.INTERSTATE, + DomainRequest.OrganizationChoices.SPECIAL_DISTRICT, + DomainRequest.OrganizationChoices.INTERSTATE, ] def has_rationale(self) -> bool: @@ -920,7 +920,7 @@ class DomainApplication(TimeStampedModel): if not self.organization_type: # organization_type is either blank or None, can't answer return None - if self.organization_type == DomainApplication.OrganizationChoices.FEDERAL: + if self.organization_type == DomainRequest.OrganizationChoices.FEDERAL: return True return False diff --git a/src/registrar/models/domain_information.py b/src/registrar/models/domain_information.py index 861171c5c..3d8f76a5d 100644 --- a/src/registrar/models/domain_information.py +++ b/src/registrar/models/domain_information.py @@ -2,7 +2,7 @@ from __future__ import annotations from django.db import transaction from registrar.models.utility.domain_helper import DomainHelper -from .domain_application import DomainApplication +from .domain_request import DomainRequest from .utility.time_stamped_model import TimeStampedModel import logging @@ -15,20 +15,20 @@ logger = logging.getLogger(__name__) class DomainInformation(TimeStampedModel): """A registrant's domain information for that domain, exported from - DomainApplication. We use these field from DomainApplication with few exceptions + DomainRequest. We use these field from DomainRequest with few exceptions which are 'removed' via pop at the bottom of this file. Most of design for domain management's user information are based on application, but we cannot change the application once approved, so copying them that way we can make changes after its approved. Most fields here are copied from Application.""" - StateTerritoryChoices = DomainApplication.StateTerritoryChoices + StateTerritoryChoices = DomainRequest.StateTerritoryChoices # use the short names in Django admin - OrganizationChoices = DomainApplication.OrganizationChoices + OrganizationChoices = DomainRequest.OrganizationChoices - BranchChoices = DomainApplication.BranchChoices + BranchChoices = DomainRequest.BranchChoices - AGENCY_CHOICES = DomainApplication.AGENCY_CHOICES + AGENCY_CHOICES = DomainRequest.AGENCY_CHOICES # This is the application user who created this application. The contact # information that they gave is in the `submitter` field @@ -38,13 +38,13 @@ class DomainInformation(TimeStampedModel): related_name="information_created", ) - domain_application = models.OneToOneField( - "registrar.DomainApplication", + domain_request = models.OneToOneField( + "registrar.DomainRequest", on_delete=models.PROTECT, blank=True, null=True, - related_name="domainapplication_info", - help_text="Associated domain application", + related_name="DomainRequest_info", + help_text="Associated domain request", unique=True, ) @@ -220,25 +220,25 @@ class DomainInformation(TimeStampedModel): return "" @classmethod - def create_from_da(cls, domain_application: DomainApplication, domain=None): - """Takes in a DomainApplication and converts it into DomainInformation""" + def create_from_da(cls, domain_request: DomainRequest, domain=None): + """Takes in a DomainRequest and converts it into DomainInformation""" # Throw an error if we get None - we can't create something from nothing - if domain_application is None: - raise ValueError("The provided DomainApplication is None") + if domain_request is None: + raise ValueError("The provided DomainRequest is None") # Throw an error if the da doesn't have an id - if not hasattr(domain_application, "id"): - raise ValueError("The provided DomainApplication has no id") + if not hasattr(domain_request, "id"): + raise ValueError("The provided DomainRequest has no id") # check if we have a record that corresponds with the domain # application, if so short circuit the create - existing_domain_info = cls.objects.filter(domain_application__id=domain_application.id).first() + existing_domain_info = cls.objects.filter(domain_request__id=domain_request.id).first() if existing_domain_info: return existing_domain_info - # Get the fields that exist on both DomainApplication and DomainInformation - common_fields = DomainHelper.get_common_fields(DomainApplication, DomainInformation) + # Get the fields that exist on both DomainRequest and DomainInformation + common_fields = DomainHelper.get_common_fields(DomainRequest, DomainInformation) # Get a list of all many_to_many relations on DomainInformation (needs to be saved differently) info_many_to_many_fields = DomainInformation._get_many_to_many_fields() @@ -249,11 +249,11 @@ class DomainInformation(TimeStampedModel): for field in common_fields: # If the field isn't many_to_many, populate the da_dict. # If it is, populate da_many_to_many_dict as we need to save this later. - if hasattr(domain_application, field): + if hasattr(domain_request, field): if field not in info_many_to_many_fields: - da_dict[field] = getattr(domain_application, field) + da_dict[field] = getattr(domain_request, field) else: - da_many_to_many_dict[field] = getattr(domain_application, field).all() + da_many_to_many_dict[field] = getattr(domain_request, field).all() # This will not happen in normal code flow, but having some redundancy doesn't hurt. # da_dict should not have "id" under any circumstances. @@ -266,8 +266,8 @@ class DomainInformation(TimeStampedModel): # Create a placeholder DomainInformation object domain_info = DomainInformation(**da_dict) - # Add the domain_application and domain fields - domain_info.domain_application = domain_application + # Add the domain_request and domain fields + domain_info.domain_request = domain_request if domain: domain_info.domain = domain diff --git a/src/registrar/models/user_group.py b/src/registrar/models/user_group.py index a32406a05..8cf52cc6d 100644 --- a/src/registrar/models/user_group.py +++ b/src/registrar/models/user_group.py @@ -33,8 +33,8 @@ class UserGroup(Group): }, { "app_label": "registrar", - "model": "domainapplication", - "permissions": ["change_domainapplication"], + "model": "DomainRequest", + "permissions": ["change_DomainRequest"], }, { "app_label": "registrar", diff --git a/src/registrar/models/utility/domain_helper.py b/src/registrar/models/utility/domain_helper.py index 8b9391add..27a78403c 100644 --- a/src/registrar/models/utility/domain_helper.py +++ b/src/registrar/models/utility/domain_helper.py @@ -184,7 +184,7 @@ class DomainHelper: model_1_fields = set(field.name for field in model_1._meta.get_fields() if field.name != "id") model_2_fields = set(field.name for field in model_2._meta.get_fields() if field.name != "id") - # Get the fields that exist on both DomainApplication and DomainInformation + # Get the fields that exist on both DomainRequest and DomainInformation common_fields = model_1_fields & model_2_fields return common_fields diff --git a/src/registrar/templates/application_status.html b/src/registrar/templates/application_status.html index bb17dfcfa..80676ce35 100644 --- a/src/registrar/templates/application_status.html +++ b/src/registrar/templates/application_status.html @@ -2,7 +2,7 @@ {% load custom_filters %} -{% block title %}Domain request status | {{ domainapplication.requested_domain.name }} | {% endblock %} +{% block title %}Domain request status | {{ DomainRequest.requested_domain.name }} | {% endblock %} {% load static url_helpers %} {% block content %} @@ -17,7 +17,7 @@ Back to manage your domains

-

Domain request for {{ domainapplication.requested_domain.name }}

+

Domain request for {{ DomainRequest.requested_domain.name }}

Status: - {% if domainapplication.status == 'approved' %} Approved - {% elif domainapplication.status == 'in review' %} In review - {% elif domainapplication.status == 'rejected' %} Rejected - {% elif domainapplication.status == 'submitted' %} Submitted - {% elif domainapplication.status == 'ineligible' %} Ineligible + {% if DomainRequest.status == 'approved' %} Approved + {% elif DomainRequest.status == 'in review' %} In review + {% elif DomainRequest.status == 'rejected' %} Rejected + {% elif DomainRequest.status == 'submitted' %} Submitted + {% elif DomainRequest.status == 'ineligible' %} Ineligible {% else %}ERROR Please contact technical support/dev {% endif %}


-

Last updated: {{domainapplication.updated_at|date:"F j, Y"}}
- Request #: {{domainapplication.id}}

-

{% include "includes/domain_application.html" %}

-

+

Last updated: {{DomainRequest.updated_at|date:"F j, Y"}}
+ Request #: {{DomainRequest.id}}

+

{% include "includes/domain_request.html" %}

+

Withdraw request

@@ -52,72 +52,72 @@

Summary of your domain request

{% with heading_level='h3' %} - {% with org_type=domainapplication.get_organization_type_display %} + {% with org_type=DomainRequest.get_organization_type_display %} {% include "includes/summary_item.html" with title='Type of organization' value=org_type heading_level=heading_level %} {% endwith %} - {% if domainapplication.tribe_name %} - {% include "includes/summary_item.html" with title='Tribal government' value=domainapplication.tribe_name heading_level=heading_level %} + {% if DomainRequest.tribe_name %} + {% include "includes/summary_item.html" with title='Tribal government' value=DomainRequest.tribe_name heading_level=heading_level %} - {% if domainapplication.federally_recognized_tribe %} + {% if DomainRequest.federally_recognized_tribe %}

Federally-recognized tribe

{% endif %} - {% if domainapplication.state_recognized_tribe %} + {% if DomainRequest.state_recognized_tribe %}

State-recognized tribe

{% endif %} {% endif %} - {% if domainapplication.get_federal_type_display %} - {% include "includes/summary_item.html" with title='Federal government branch' value=domainapplication.get_federal_type_display heading_level=heading_level %} + {% if DomainRequest.get_federal_type_display %} + {% include "includes/summary_item.html" with title='Federal government branch' value=DomainRequest.get_federal_type_display heading_level=heading_level %} {% endif %} - {% if domainapplication.is_election_board %} - {% with value=domainapplication.is_election_board|yesno:"Yes,No,Incomplete" %} + {% if DomainRequest.is_election_board %} + {% with value=DomainRequest.is_election_board|yesno:"Yes,No,Incomplete" %} {% include "includes/summary_item.html" with title='Election office' value=value heading_level=heading_level %} {% endwith %} {% endif %} - {% if domainapplication.organization_name %} - {% include "includes/summary_item.html" with title='Organization name and mailing address' value=domainapplication address='true' heading_level=heading_level %} + {% if DomainRequest.organization_name %} + {% include "includes/summary_item.html" with title='Organization name and mailing address' value=DomainRequest address='true' heading_level=heading_level %} {% endif %} - {% if domainapplication.about_your_organization %} - {% include "includes/summary_item.html" with title='About your organization' value=domainapplication.about_your_organization heading_level=heading_level %} + {% if DomainRequest.about_your_organization %} + {% include "includes/summary_item.html" with title='About your organization' value=DomainRequest.about_your_organization heading_level=heading_level %} {% endif %} - {% if domainapplication.authorizing_official %} - {% include "includes/summary_item.html" with title='Authorizing official' value=domainapplication.authorizing_official contact='true' heading_level=heading_level %} + {% if DomainRequest.authorizing_official %} + {% include "includes/summary_item.html" with title='Authorizing official' value=DomainRequest.authorizing_official contact='true' heading_level=heading_level %} {% endif %} - {% if domainapplication.current_websites.all %} - {% include "includes/summary_item.html" with title='Current websites' value=domainapplication.current_websites.all list='true' heading_level=heading_level %} + {% if DomainRequest.current_websites.all %} + {% include "includes/summary_item.html" with title='Current websites' value=DomainRequest.current_websites.all list='true' heading_level=heading_level %} {% endif %} - {% if domainapplication.requested_domain %} - {% include "includes/summary_item.html" with title='.gov domain' value=domainapplication.requested_domain heading_level=heading_level %} + {% if DomainRequest.requested_domain %} + {% include "includes/summary_item.html" with title='.gov domain' value=DomainRequest.requested_domain heading_level=heading_level %} {% endif %} - {% if domainapplication.alternative_domains.all %} - {% include "includes/summary_item.html" with title='Alternative domains' value=domainapplication.alternative_domains.all list='true' heading_level=heading_level %} + {% if DomainRequest.alternative_domains.all %} + {% include "includes/summary_item.html" with title='Alternative domains' value=DomainRequest.alternative_domains.all list='true' heading_level=heading_level %} {% endif %} - {% if domainapplication.purpose %} - {% include "includes/summary_item.html" with title='Purpose of your domain' value=domainapplication.purpose heading_level=heading_level %} + {% if DomainRequest.purpose %} + {% include "includes/summary_item.html" with title='Purpose of your domain' value=DomainRequest.purpose heading_level=heading_level %} {% endif %} - {% if domainapplication.submitter %} - {% include "includes/summary_item.html" with title='Your contact information' value=domainapplication.submitter contact='true' heading_level=heading_level %} + {% if DomainRequest.submitter %} + {% include "includes/summary_item.html" with title='Your contact information' value=DomainRequest.submitter contact='true' heading_level=heading_level %} {% endif %} - {% if domainapplication.other_contacts.all %} - {% include "includes/summary_item.html" with title='Other employees from your organization' value=domainapplication.other_contacts.all contact='true' list='true' heading_level=heading_level %} + {% if DomainRequest.other_contacts.all %} + {% include "includes/summary_item.html" with title='Other employees from your organization' value=DomainRequest.other_contacts.all contact='true' list='true' heading_level=heading_level %} {% else %} - {% include "includes/summary_item.html" with title='Other employees from your organization' value=domainapplication.no_other_contacts_rationale heading_level=heading_level %} + {% include "includes/summary_item.html" with title='Other employees from your organization' value=DomainRequest.no_other_contacts_rationale heading_level=heading_level %} {% endif %} - {% include "includes/summary_item.html" with title='Anything else?' value=domainapplication.anything_else|default:"No" heading_level=heading_level %} + {% include "includes/summary_item.html" with title='Anything else?' value=DomainRequest.anything_else|default:"No" heading_level=heading_level %} {% endwith %}
diff --git a/src/registrar/templates/application_withdraw_confirmation.html b/src/registrar/templates/application_withdraw_confirmation.html index 98d838ae1..077bb4301 100644 --- a/src/registrar/templates/application_withdraw_confirmation.html +++ b/src/registrar/templates/application_withdraw_confirmation.html @@ -1,6 +1,6 @@ {% extends 'base.html' %} -{% block title %}Withdraw request for {{ domainapplication.requested_domain.name }} | {% endblock %} +{% block title %}Withdraw request for {{ DomainRequest.requested_domain.name }} | {% endblock %} {% load static url_helpers %} {% block content %} @@ -8,12 +8,12 @@
-

Withdraw request for {{ domainapplication.requested_domain.name }}?

+

Withdraw request for {{ DomainRequest.requested_domain.name }}?

If you withdraw your request, we won't review it. Once you withdraw your request, you can edit it and submit it again.

-

Withdraw request - Cancel

+

Withdraw request + Cancel

diff --git a/src/registrar/templates/home.html b/src/registrar/templates/home.html index 93f1243ea..c33c5153c 100644 --- a/src/registrar/templates/home.html +++ b/src/registrar/templates/home.html @@ -103,7 +103,7 @@

Domain requests

- {% if domain_applications %} + {% if domain_requests %} @@ -118,7 +118,7 @@ - {% for application in domain_applications %} + {% for application in domain_requests %} - {% if has_deletable_applications %} + {% if has_deletable_domain_requests %} {% endif %} @@ -121,52 +121,52 @@ {% for application in domain_requests %} - - + - {% if has_deletable_applications %} + {% if has_deletable_domain_requests %} - {% for application in domain_requests %} + {% for domain_request in domain_requests %} ', count=1) @@ -441,12 +441,12 @@ class TestDomainAdmin(MockEppLib, WebTest): class TestDomainRequestAdminForm(TestCase): def setUp(self): - # Create a test application with an initial state of started + # Create a test domain request with an initial state of started self.domain_request = completed_domain_request() def test_form_choices(self): with less_console_noise(): - # Create a form instance with the test application + # Create a form instance with the test domain request form = DomainRequestAdminForm(instance=self.domain_request) # Verify that the form choices match the available transitions for started @@ -460,7 +460,7 @@ class TestDomainRequestAdminForm(TestCase): # Verify that the form choices show all choices when no instance is provided; # this is necessary to show all choices when creating a new domain - # application in django admin; + # request in django admin; # note that FSM ensures that no domain request exists with invalid status, # so don't need to test for invalid status self.assertEqual( @@ -473,7 +473,7 @@ class TestDomainRequestAdminForm(TestCase): # Create a form instance with a domain request with ineligible status ineligible_domain_request = DomainRequest(status="ineligible") - # Attempt to create a form with the ineligible application + # Attempt to create a form with the ineligible domain request # The form should not raise an error, but choices should be the # full list of possible choices form = DomainRequestAdminForm(instance=ineligible_domain_request) @@ -587,7 +587,7 @@ class TestDomainRequestAdmin(MockEppLib): completed_domain_request() response = self.client.get("/admin/registrar/DomainRequest/") # There are 4 template references to Federal (4) plus two references in the table - # for our actual application + # for our actual domain request self.assertContains(response, "Federal", count=6) # This may be a bit more robust self.assertContains(response, '', count=1) @@ -657,7 +657,7 @@ class TestDomainRequestAdmin(MockEppLib): EMAIL = "mayor@igorville.gov" User.objects.filter(email=EMAIL).delete() - # Create a sample application + # Create a sample domain request domain_request = completed_domain_request() # Test Submitted Status from started @@ -714,7 +714,7 @@ class TestDomainRequestAdmin(MockEppLib): BCC_EMAIL = settings.DEFAULT_FROM_EMAIL - # Create a sample application + # Create a sample domain request domain_request = completed_domain_request() # Test Submitted Status from started @@ -763,7 +763,7 @@ class TestDomainRequestAdmin(MockEppLib): EMAIL = "mayor@igorville.gov" User.objects.filter(email=EMAIL).delete() - # Create a sample application + # Create a sample domain request domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.IN_REVIEW) # Test Submitted Status @@ -773,7 +773,7 @@ class TestDomainRequestAdmin(MockEppLib): # Test Withdrawn Status self.transition_state_and_send_email( - application, + domain_request, DomainRequest.DomainRequestStatus.REJECTED, DomainRequest.RejectionReasons.DOMAIN_PURPOSE, ) @@ -793,12 +793,12 @@ class TestDomainRequestAdmin(MockEppLib): EMAIL = "mayor@igorville.gov" User.objects.filter(email=EMAIL).delete() - # Create a sample application + # Create a sample domain request domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.IN_REVIEW) # Reject for reason DOMAIN_PURPOSE and test email self.transition_state_and_send_email( - application, + domain_request, DomainRequest.DomainRequestStatus.REJECTED, DomainRequest.RejectionReasons.DOMAIN_PURPOSE, ) @@ -823,7 +823,7 @@ class TestDomainRequestAdmin(MockEppLib): EMAIL = "mayor@igorville.gov" User.objects.filter(email=EMAIL).delete() - # Create a sample application + # Create a sample domain request domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.IN_REVIEW) # Reject for reason REQUESTOR and test email including dynamic organization name @@ -852,12 +852,12 @@ class TestDomainRequestAdmin(MockEppLib): EMAIL = "mayor@igorville.gov" User.objects.filter(email=EMAIL).delete() - # Create a sample application + # Create a sample domain request domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.IN_REVIEW) # Reject for reason SECOND_DOMAIN_REASONING and test email including dynamic organization name self.transition_state_and_send_email( - application, + domain_request, DomainRequest.DomainRequestStatus.REJECTED, DomainRequest.RejectionReasons.SECOND_DOMAIN_REASONING, ) @@ -880,12 +880,12 @@ class TestDomainRequestAdmin(MockEppLib): EMAIL = "mayor@igorville.gov" User.objects.filter(email=EMAIL).delete() - # Create a sample application + # Create a sample domain request domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.IN_REVIEW) # Reject for reason CONTACTS_OR_ORGANIZATION_LEGITIMACY and test email including dynamic organization name self.transition_state_and_send_email( - application, + domain_request, DomainRequest.DomainRequestStatus.REJECTED, DomainRequest.RejectionReasons.CONTACTS_OR_ORGANIZATION_LEGITIMACY, ) @@ -911,12 +911,12 @@ class TestDomainRequestAdmin(MockEppLib): EMAIL = "mayor@igorville.gov" User.objects.filter(email=EMAIL).delete() - # Create a sample application + # Create a sample domain request domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.IN_REVIEW) # Reject for reason ORGANIZATION_ELIGIBILITY and test email including dynamic organization name self.transition_state_and_send_email( - application, + domain_request, DomainRequest.DomainRequestStatus.REJECTED, DomainRequest.RejectionReasons.ORGANIZATION_ELIGIBILITY, ) @@ -942,12 +942,12 @@ class TestDomainRequestAdmin(MockEppLib): EMAIL = "mayor@igorville.gov" User.objects.filter(email=EMAIL).delete() - # Create a sample application + # Create a sample domain request domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.IN_REVIEW) # Reject for reason NAMING_REQUIREMENTS and test email including dynamic organization name self.transition_state_and_send_email( - application, + domain_request, DomainRequest.DomainRequestStatus.REJECTED, DomainRequest.RejectionReasons.NAMING_REQUIREMENTS, ) @@ -970,12 +970,12 @@ class TestDomainRequestAdmin(MockEppLib): EMAIL = "mayor@igorville.gov" User.objects.filter(email=EMAIL).delete() - # Create a sample application + # Create a sample domain request domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.IN_REVIEW) # Reject for reason NAMING_REQUIREMENTS and test email including dynamic organization name self.transition_state_and_send_email( - application, + domain_request, DomainRequest.DomainRequestStatus.REJECTED, DomainRequest.RejectionReasons.OTHER, ) @@ -1050,7 +1050,7 @@ class TestDomainRequestAdmin(MockEppLib): EMAIL = "mayor@igorville.gov" User.objects.filter(email=EMAIL).delete() - # Create a sample application + # Create a sample domain request domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.IN_REVIEW) # Test Submitted Status @@ -1075,7 +1075,7 @@ class TestDomainRequestAdmin(MockEppLib): EMAIL = "mayor@igorville.gov" User.objects.filter(email=EMAIL).delete() - # Create a sample application + # Create a sample domain request domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.IN_REVIEW) # Create a mock request @@ -1097,7 +1097,7 @@ class TestDomainRequestAdmin(MockEppLib): EMAIL = "mayor@igorville.gov" User.objects.filter(email=EMAIL).delete() - # Create a sample application + # Create a sample domain request domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.IN_REVIEW) # Create a mock request @@ -1217,7 +1217,7 @@ class TestDomainRequestAdmin(MockEppLib): # Assert that the error message was called with the correct argument mock_error.assert_called_once_with( request, - "This action is not permitted for applications with a restricted creator.", + "This action is not permitted for domain requests with a restricted creator.", ) # Assert that the status has not changed @@ -1395,7 +1395,7 @@ class TestDomainRequestAdmin(MockEppLib): with less_console_noise(): # Create a mock DomainRequest object, with a fake investigator - application: DomainRequest = generic_domain_object("domain_request", "SomeGuy") + domain_request: DomainRequest = generic_domain_object("domain_request", "SomeGuy") investigator_user = User.objects.filter(username=domain_request.investigator.username).get() investigator_user.is_staff = True investigator_user.save() @@ -1440,7 +1440,7 @@ class TestDomainRequestAdmin(MockEppLib): with less_console_noise(): # Create a mock DomainRequest object, with a fake investigator - application: DomainRequest = generic_domain_object("domain_request", "SomeGuy") + domain_request: DomainRequest = generic_domain_object("domain_request", "SomeGuy") investigator_user = User.objects.filter(username=domain_request.investigator.username).get() investigator_user.is_staff = True investigator_user.save() @@ -1484,7 +1484,7 @@ class TestDomainRequestAdmin(MockEppLib): """ with less_console_noise(): # Create a mock DomainRequest object, with a fake investigator - application: DomainRequest = generic_domain_object("domain_request", "SomeGuy") + domain_request: DomainRequest = generic_domain_object("domain_request", "SomeGuy") investigator_user = User.objects.filter(username=domain_request.investigator.username).get() investigator_user.is_staff = True investigator_user.save() @@ -1872,7 +1872,7 @@ class ListHeaderAdminTest(TestCase): ) def tearDown(self): - # delete any applications too + # delete any domain requests too DomainInformation.objects.all().delete() DomainRequest.objects.all().delete() User.objects.all().delete() @@ -1947,11 +1947,11 @@ class AuditedAdminTest(TestCase): """Tests if the investigator field is alphabetically sorted by mimicking the call event flow""" # Creates multiple domain requests - review status does not matter - applications = multiple_unalphabetical_domain_objects("domain_request") + domain_requests = multiple_unalphabetical_domain_objects("domain_request") # Create a mock request domain_request_request = self.factory.post( - "/admin/registrar/DomainRequest/{}/change/".format(applications[0].pk) + "/admin/registrar/DomainRequest/{}/change/".format(domain_requests[0].pk) ) # Get the formfield data from the domain request page @@ -1989,10 +1989,10 @@ class AuditedAdminTest(TestCase): ] # Creates multiple domain requests - review status does not matter - applications = multiple_unalphabetical_domain_objects("domain_request") + domain_requests = multiple_unalphabetical_domain_objects("domain_request") # Create a mock request - request = self.factory.post("/admin/registrar/DomainRequest/{}/change/".format(applications[0].pk)) + request = self.factory.post("/admin/registrar/DomainRequest/{}/change/".format(domain_requests[0].pk)) model_admin = AuditedAdmin(DomainRequest, self.site) @@ -2046,10 +2046,10 @@ class AuditedAdminTest(TestCase): (DomainInformation.domain_request.field, ["requested_domain__name"]), ] # Creates multiple domain requests - review status does not matter - applications = multiple_unalphabetical_domain_objects("information") + domain_requests = multiple_unalphabetical_domain_objects("information") # Create a mock request - request = self.factory.post("/admin/registrar/domaininformation/{}/change/".format(applications[0].pk)) + request = self.factory.post("/admin/registrar/domaininformation/{}/change/".format(domain_requests[0].pk)) model_admin = AuditedAdmin(DomainInformation, self.site) @@ -2101,10 +2101,10 @@ class AuditedAdminTest(TestCase): tested_fields = [DomainInvitation.domain.field] # Creates multiple domain requests - review status does not matter - applications = multiple_unalphabetical_domain_objects("invitation") + domain_requests = multiple_unalphabetical_domain_objects("invitation") # Create a mock request - request = self.factory.post("/admin/registrar/domaininvitation/{}/change/".format(applications[0].pk)) + request = self.factory.post("/admin/registrar/domaininvitation/{}/change/".format(domain_requests[0].pk)) model_admin = AuditedAdmin(DomainInvitation, self.site) @@ -2328,10 +2328,10 @@ class ContactAdminTest(TestCase): contact, _ = Contact.objects.get_or_create(user=self.staffuser) # join it to 4 domain requests. The 5th join will be a user. - application1 = completed_domain_request(submitter=contact, name="city1.gov") - application2 = completed_domain_request(submitter=contact, name="city2.gov") - application3 = completed_domain_request(submitter=contact, name="city3.gov") - application4 = completed_domain_request(submitter=contact, name="city4.gov") + domain_request1 = completed_domain_request(submitter=contact, name="city1.gov") + domain_request2 = completed_domain_request(submitter=contact, name="city2.gov") + domain_request3 = completed_domain_request(submitter=contact, name="city3.gov") + domain_request4 = completed_domain_request(submitter=contact, name="city4.gov") with patch("django.contrib.messages.warning") as mock_warning: # Use the test client to simulate the request @@ -2343,13 +2343,13 @@ class ContactAdminTest(TestCase): response.wsgi_request, "
    " "
  • Joined to DomainRequest: city1.gov
  • " + f"DomainRequest/{domain_request1.pk}/change/'>city1.gov" "
  • Joined to DomainRequest: city2.gov
  • " + f"DomainRequest/{domain_request2.pk}/change/'>city2.gov" "
  • Joined to DomainRequest: city3.gov
  • " + f"DomainRequest/{domain_request3.pk}/change/'>city3.gov" "
  • Joined to DomainRequest: city4.gov
  • " + f"DomainRequest/{domain_request4.pk}/change/'>city4.gov" "
  • Joined to User: staff@example.com
  • " "
", @@ -2363,11 +2363,11 @@ class ContactAdminTest(TestCase): # Create an instance of the model # join it to 5 domain requests. The 6th join will be a user. contact, _ = Contact.objects.get_or_create(user=self.staffuser) - application1 = completed_domain_request(submitter=contact, name="city1.gov") - application2 = completed_domain_request(submitter=contact, name="city2.gov") - application3 = completed_domain_request(submitter=contact, name="city3.gov") - application4 = completed_domain_request(submitter=contact, name="city4.gov") - application5 = completed_domain_request(submitter=contact, name="city5.gov") + domain_request1 = completed_domain_request(submitter=contact, name="city1.gov") + domain_request2 = completed_domain_request(submitter=contact, name="city2.gov") + domain_request3 = completed_domain_request(submitter=contact, name="city3.gov") + domain_request4 = completed_domain_request(submitter=contact, name="city4.gov") + domain_request5 = completed_domain_request(submitter=contact, name="city5.gov") with patch("django.contrib.messages.warning") as mock_warning: # Use the test client to simulate the request response = self.client.get(reverse("admin:registrar_contact_change", args=[contact.pk])) @@ -2378,15 +2378,15 @@ class ContactAdminTest(TestCase): response.wsgi_request, "
    " "
  • Joined to DomainRequest: city1.gov
  • " + f"DomainRequest/{domain_request1.pk}/change/'>city1.gov" "
  • Joined to DomainRequest: city2.gov
  • " + f"DomainRequest/{domain_request2.pk}/change/'>city2.gov" "
  • Joined to DomainRequest: city3.gov
  • " + f"DomainRequest/{domain_request3.pk}/change/'>city3.gov" "
  • Joined to DomainRequest: city4.gov
  • " + f"DomainRequest/{domain_request4.pk}/change/'>city4.gov" "
  • Joined to DomainRequest: city5.gov
  • " + f"DomainRequest/{domain_request5.pk}/change/'>city5.gov" "
" "

And 1 more...

", ) diff --git a/src/registrar/tests/test_models.py b/src/registrar/tests/test_models.py index baa5ef3b5..9b12dbf98 100644 --- a/src/registrar/tests/test_models.py +++ b/src/registrar/tests/test_models.py @@ -185,7 +185,7 @@ class TestDomainRequest(TestCase): self.check_email_sent(domain_request, msg, "submit", 1) def test_submit_from_withdrawn_sends_email(self): - msg = "Create a withdrawn application and submit it and see if email was sent." + msg = "Create a withdrawn domain request and submit it and see if email was sent." domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.WITHDRAWN) self.check_email_sent(domain_request, msg, "submit", 1) @@ -195,7 +195,7 @@ class TestDomainRequest(TestCase): self.check_email_sent(domain_request, msg, "submit", 0) def test_submit_from_in_review_does_not_send_email(self): - msg = "Create a withdrawn application and submit it and see if email was sent." + msg = "Create a withdrawn domain request and submit it and see if email was sent." domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.IN_REVIEW) self.check_email_sent(domain_request, msg, "submit", 0) @@ -579,7 +579,7 @@ class TestDomainRequest(TestCase): the rejection_reason is cleared.""" with less_console_noise(): - # Create a sample application + # Create a sample domain request domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.REJECTED) domain_request.rejection_reason = DomainRequest.RejectionReasons.DOMAIN_PURPOSE @@ -595,7 +595,7 @@ class TestDomainRequest(TestCase): the rejection_reason is cleared.""" with less_console_noise(): - # Create a sample application + # Create a sample domain request domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.REJECTED) domain_request.domain_is_not_active = True domain_request.rejection_reason = DomainRequest.RejectionReasons.DOMAIN_PURPOSE @@ -612,7 +612,7 @@ class TestDomainRequest(TestCase): the rejection_reason is cleared.""" with less_console_noise(): - # Create a sample application + # Create a sample domain request domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.REJECTED) domain_request.domain_is_not_active = True domain_request.rejection_reason = DomainRequest.RejectionReasons.DOMAIN_PURPOSE @@ -719,7 +719,7 @@ class TestDomainInformation(TestCase): creator=user, domain=domain, notes="test notes", - domain_request=application, + domain_request=domain_request, ).__dict__ # Test the two records for consistency diff --git a/src/registrar/tests/test_views.py b/src/registrar/tests/test_views.py index b4ec1288a..eec12e463 100644 --- a/src/registrar/tests/test_views.py +++ b/src/registrar/tests/test_views.py @@ -45,7 +45,7 @@ class TestWithUser(MockEppLib): ) def tearDown(self): - # delete any applications too + # delete any domain requests too super().tearDown() DomainRequest.objects.all().delete() DomainInformation.objects.all().delete() diff --git a/src/registrar/tests/test_views_application.py b/src/registrar/tests/test_views_application.py index ca75a3774..1414d4525 100644 --- a/src/registrar/tests/test_views_application.py +++ b/src/registrar/tests/test_views_application.py @@ -43,7 +43,7 @@ class DomainRequestTests(TestWithUser, WebTest): def test_domain_request_form_intro_acknowledgement(self): """Tests that user is presented with intro acknowledgement page""" - intro_page = self.app.get(reverse("application:")) + intro_page = self.app.get(reverse("domain-request:")) self.assertContains(intro_page, "You’re about to start your .gov domain request") def test_domain_request_form_intro_is_skipped_when_edit_access(self): @@ -61,7 +61,7 @@ class DomainRequestTests(TestWithUser, WebTest): def test_domain_request_form_empty_submit(self): """Tests empty submit on the first page after the acknowledgement page""" - intro_page = self.app.get(reverse("application:")) + intro_page = self.app.get(reverse("domain-request:")) # django-webtest does not handle cookie-based sessions well because it keeps # resetting the session key on each new request, thus destroying the concept # of a "session". We are going to do it manually, saving the session ID here @@ -82,7 +82,7 @@ class DomainRequestTests(TestWithUser, WebTest): self.assertIn("What kind of U.S.-based government organization do you represent?", result) def test_domain_request_multiple_domain_requests_exist(self): - """Test that an info message appears when user has multiple applications already""" + """Test that an info message appears when user has multiple domain requests already""" # create and submit a domain request domain_request = completed_domain_request(user=self.user) mock_client = MockSESClient() @@ -93,7 +93,7 @@ class DomainRequestTests(TestWithUser, WebTest): # now, attempt to create another one with less_console_noise(): - intro_page = self.app.get(reverse("application:")) + intro_page = self.app.get(reverse("domain-request:")) session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] intro_form = intro_page.forms[0] self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) @@ -123,7 +123,7 @@ class DomainRequestTests(TestWithUser, WebTest): SKIPPED_PAGES = 3 num_pages = len(self.TITLES) - SKIPPED_PAGES - intro_page = self.app.get(reverse("application:")) + intro_page = self.app.get(reverse("domain-request:")) # django-webtest does not handle cookie-based sessions well because it keeps # resetting the session key on each new request, thus destroying the concept # of a "session". We are going to do it manually, saving the session ID here @@ -481,13 +481,13 @@ class DomainRequestTests(TestWithUser, WebTest): self.assertContains(home_page, "Started") num_pages_tested += 1 - # TODO: For some reason this click results in a new application being generated + # TODO: For some reason this click results in a new domain request being generated # This appraoch is an alternatie to using get as is being done below # # type_page = home_page.click("Edit") session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - url = reverse("edit-application", kwargs={"id": domain_request.pk}) + url = reverse("edit-domain-request", kwargs={"id": domain_request.pk}) self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) # TODO: The following line results in a django error on middleware @@ -500,7 +500,7 @@ class DomainRequestTests(TestWithUser, WebTest): def test_domain_request_form_conditional_federal(self): """Federal branch question is shown for federal organizations.""" - intro_page = self.app.get(reverse("application:")) + intro_page = self.app.get(reverse("domain-request:")) # django-webtest does not handle cookie-based sessions well because it keeps # resetting the session key on each new request, thus destroying the concept # of a "session". We are going to do it manually, saving the session ID here @@ -555,7 +555,7 @@ class DomainRequestTests(TestWithUser, WebTest): def test_domain_request_form_conditional_elections(self): """Election question is shown for other organizations.""" - intro_page = self.app.get(reverse("application:")) + intro_page = self.app.get(reverse("domain-request:")) # django-webtest does not handle cookie-based sessions well because it keeps # resetting the session key on each new request, thus destroying the concept # of a "session". We are going to do it manually, saving the session ID here @@ -609,7 +609,7 @@ class DomainRequestTests(TestWithUser, WebTest): def test_domain_request_form_section_skipping(self): """Can skip forward and back in sections""" - intro_page = self.app.get(reverse("application:")) + intro_page = self.app.get(reverse("domain-request:")) # django-webtest does not handle cookie-based sessions well because it keeps # resetting the session key on each new request, thus destroying the concept # of a "session". We are going to do it manually, saving the session ID here @@ -646,7 +646,7 @@ class DomainRequestTests(TestWithUser, WebTest): def test_domain_request_form_nonfederal(self): """Non-federal organizations don't have to provide their federal agency.""" - intro_page = self.app.get(reverse("application:")) + intro_page = self.app.get(reverse("domain-request:")) # django-webtest does not handle cookie-based sessions well because it keeps # resetting the session key on each new request, thus destroying the concept # of a "session". We are going to do it manually, saving the session ID here @@ -691,7 +691,7 @@ class DomainRequestTests(TestWithUser, WebTest): def test_domain_request_about_your_organization_special(self): """Special districts have to answer an additional question.""" - intro_page = self.app.get(reverse("application:")) + intro_page = self.app.get(reverse("domain-request:")) # django-webtest does not handle cookie-based sessions well because it keeps # resetting the session key on each new request, thus destroying the concept # of a "session". We are going to do it manually, saving the session ID here @@ -719,18 +719,18 @@ class DomainRequestTests(TestWithUser, WebTest): def test_yes_no_form_inits_blank_for_new_domain_request(self): """On the Other Contacts page, the yes/no form gets initialized with nothing selected for - new applications""" - other_contacts_page = self.app.get(reverse("application:other_contacts")) + new domain requests""" + other_contacts_page = self.app.get(reverse("domain-request:other_contacts")) other_contacts_form = other_contacts_page.forms[0] self.assertEquals(other_contacts_form["other_contacts-has_other_contacts"].value, None) def test_yes_no_form_inits_yes_for_domain_request_with_other_contacts(self): """On the Other Contacts page, the yes/no form gets initialized with YES selected if the - application has other contacts""" - # Application has other contacts by default + domain request has other contacts""" + # Domain Request has other contacts by default domain_request = completed_domain_request(user=self.user) # prime the form by visiting /edit - self.app.get(reverse("edit-application", kwargs={"id": domain_request.pk})) + self.app.get(reverse("edit-domain-request", kwargs={"id": domain_request.pk})) # django-webtest does not handle cookie-based sessions well because it keeps # resetting the session key on each new request, thus destroying the concept # of a "session". We are going to do it manually, saving the session ID here @@ -738,7 +738,7 @@ class DomainRequestTests(TestWithUser, WebTest): session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - other_contacts_page = self.app.get(reverse("application:other_contacts")) + other_contacts_page = self.app.get(reverse("domain-request:other_contacts")) self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) other_contacts_form = other_contacts_page.forms[0] @@ -746,13 +746,13 @@ class DomainRequestTests(TestWithUser, WebTest): def test_yes_no_form_inits_no_for_domain_request_with_no_other_contacts_rationale(self): """On the Other Contacts page, the yes/no form gets initialized with NO selected if the - application has no other contacts""" - # Application has other contacts by default + domain request has no other contacts""" + # Domain request has other contacts by default domain_request = completed_domain_request(user=self.user, has_other_contacts=False) domain_request.no_other_contacts_rationale = "Hello!" domain_request.save() # prime the form by visiting /edit - self.app.get(reverse("edit-application", kwargs={"id": domain_request.pk})) + self.app.get(reverse("edit-domain-request", kwargs={"id": domain_request.pk})) # django-webtest does not handle cookie-based sessions well because it keeps # resetting the session key on each new request, thus destroying the concept # of a "session". We are going to do it manually, saving the session ID here @@ -760,7 +760,7 @@ class DomainRequestTests(TestWithUser, WebTest): session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - other_contacts_page = self.app.get(reverse("application:other_contacts")) + other_contacts_page = self.app.get(reverse("domain-request:other_contacts")) self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) other_contacts_form = other_contacts_page.forms[0] @@ -769,12 +769,12 @@ class DomainRequestTests(TestWithUser, WebTest): def test_submitting_other_contacts_deletes_no_other_contacts_rationale(self): """When a user submits the Other Contacts form with other contacts selected, the domain request's no other contacts rationale gets deleted""" - # Application has other contacts by default + # Domain request has other contacts by default domain_request = completed_domain_request(user=self.user, has_other_contacts=False) domain_request.no_other_contacts_rationale = "Hello!" domain_request.save() # prime the form by visiting /edit - self.app.get(reverse("edit-application", kwargs={"id": domain_request.pk})) + self.app.get(reverse("edit-domain-request", kwargs={"id": domain_request.pk})) # django-webtest does not handle cookie-based sessions well because it keeps # resetting the session key on each new request, thus destroying the concept # of a "session". We are going to do it manually, saving the session ID here @@ -782,7 +782,7 @@ class DomainRequestTests(TestWithUser, WebTest): session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - other_contacts_page = self.app.get(reverse("application:other_contacts")) + other_contacts_page = self.app.get(reverse("domain-request:other_contacts")) self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) other_contacts_form = other_contacts_page.forms[0] @@ -818,10 +818,10 @@ class DomainRequestTests(TestWithUser, WebTest): """When a user submits the Other Contacts form with no other contacts selected, the domain request's other contacts get deleted for other contacts that exist and are not joined to other objects """ - # Application has other contacts by default + # Domain request has other contacts by default domain_request = completed_domain_request(user=self.user) # prime the form by visiting /edit - self.app.get(reverse("edit-application", kwargs={"id": domain_request.pk})) + self.app.get(reverse("edit-domain-request", kwargs={"id": domain_request.pk})) # django-webtest does not handle cookie-based sessions well because it keeps # resetting the session key on each new request, thus destroying the concept # of a "session". We are going to do it manually, saving the session ID here @@ -829,7 +829,7 @@ class DomainRequestTests(TestWithUser, WebTest): session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - other_contacts_page = self.app.get(reverse("application:other_contacts")) + other_contacts_page = self.app.get(reverse("domain-request:other_contacts")) self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) other_contacts_form = other_contacts_page.forms[0] @@ -905,7 +905,7 @@ class DomainRequestTests(TestWithUser, WebTest): domain_info.other_contacts.set([other]) # prime the form by visiting /edit - self.app.get(reverse("edit-application", kwargs={"id": domain_request.pk})) + self.app.get(reverse("edit-domain-request", kwargs={"id": domain_request.pk})) # django-webtest does not handle cookie-based sessions well because it keeps # resetting the session key on each new request, thus destroying the concept # of a "session". We are going to do it manually, saving the session ID here @@ -913,7 +913,7 @@ class DomainRequestTests(TestWithUser, WebTest): session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - other_contacts_page = self.app.get(reverse("application:other_contacts")) + other_contacts_page = self.app.get(reverse("domain-request:other_contacts")) self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) other_contacts_form = other_contacts_page.forms[0] @@ -953,7 +953,7 @@ class DomainRequestTests(TestWithUser, WebTest): def test_if_yes_no_form_is_no_then_no_other_contacts_required(self): """Applicants with no other contacts have to give a reason.""" - other_contacts_page = self.app.get(reverse("application:other_contacts")) + other_contacts_page = self.app.get(reverse("domain-request:other_contacts")) other_contacts_form = other_contacts_page.forms[0] other_contacts_form["other_contacts-has_other_contacts"] = "False" response = other_contacts_page.forms[0].submit() @@ -968,7 +968,7 @@ class DomainRequestTests(TestWithUser, WebTest): def test_if_yes_no_form_is_yes_then_other_contacts_required(self): """Applicants with other contacts do not have to give a reason.""" - other_contacts_page = self.app.get(reverse("application:other_contacts")) + other_contacts_page = self.app.get(reverse("domain-request:other_contacts")) other_contacts_form = other_contacts_page.forms[0] other_contacts_form["other_contacts-has_other_contacts"] = "True" response = other_contacts_page.forms[0].submit() @@ -1036,7 +1036,7 @@ class DomainRequestTests(TestWithUser, WebTest): domain_request.other_contacts.add(other2) # prime the form by visiting /edit - self.app.get(reverse("edit-application", kwargs={"id": domain_request.pk})) + self.app.get(reverse("edit-domain-request", kwargs={"id": domain_request.pk})) # django-webtest does not handle cookie-based sessions well because it keeps # resetting the session key on each new request, thus destroying the concept # of a "session". We are going to do it manually, saving the session ID here @@ -1044,7 +1044,7 @@ class DomainRequestTests(TestWithUser, WebTest): session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - other_contacts_page = self.app.get(reverse("application:other_contacts")) + other_contacts_page = self.app.get(reverse("domain-request:other_contacts")) self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) other_contacts_form = other_contacts_page.forms[0] @@ -1109,7 +1109,7 @@ class DomainRequestTests(TestWithUser, WebTest): domain_request.other_contacts.add(other) # prime the form by visiting /edit - self.app.get(reverse("edit-application", kwargs={"id": domain_request.pk})) + self.app.get(reverse("edit-domain-request", kwargs={"id": domain_request.pk})) # django-webtest does not handle cookie-based sessions well because it keeps # resetting the session key on each new request, thus destroying the concept # of a "session". We are going to do it manually, saving the session ID here @@ -1117,7 +1117,7 @@ class DomainRequestTests(TestWithUser, WebTest): session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - other_contacts_page = self.app.get(reverse("application:other_contacts")) + other_contacts_page = self.app.get(reverse("domain-request:other_contacts")) self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) other_contacts_form = other_contacts_page.forms[0] @@ -1186,7 +1186,7 @@ class DomainRequestTests(TestWithUser, WebTest): domain_request.other_contacts.add(other) # prime the form by visiting /edit - self.app.get(reverse("edit-application", kwargs={"id": domain_request.pk})) + self.app.get(reverse("edit-domain-request", kwargs={"id": domain_request.pk})) # django-webtest does not handle cookie-based sessions well because it keeps # resetting the session key on each new request, thus destroying the concept # of a "session". We are going to do it manually, saving the session ID here @@ -1194,7 +1194,7 @@ class DomainRequestTests(TestWithUser, WebTest): session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - other_contacts_page = self.app.get(reverse("application:other_contacts")) + other_contacts_page = self.app.get(reverse("domain-request:other_contacts")) self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) other_contacts_form = other_contacts_page.forms[0] @@ -1266,7 +1266,7 @@ class DomainRequestTests(TestWithUser, WebTest): other_contact_pk = other.id # prime the form by visiting /edit - self.app.get(reverse("edit-application", kwargs={"id": domain_request.pk})) + self.app.get(reverse("edit-domain-request", kwargs={"id": domain_request.pk})) # django-webtest does not handle cookie-based sessions well because it keeps # resetting the session key on each new request, thus destroying the concept # of a "session". We are going to do it manually, saving the session ID here @@ -1274,7 +1274,7 @@ class DomainRequestTests(TestWithUser, WebTest): session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - other_contacts_page = self.app.get(reverse("application:other_contacts")) + other_contacts_page = self.app.get(reverse("domain-request:other_contacts")) self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) other_contacts_form = other_contacts_page.forms[0] @@ -1342,7 +1342,7 @@ class DomainRequestTests(TestWithUser, WebTest): other_contact_pk = ao.id # prime the form by visiting /edit - self.app.get(reverse("edit-application", kwargs={"id": domain_request.pk})) + self.app.get(reverse("edit-domain-request", kwargs={"id": domain_request.pk})) # django-webtest does not handle cookie-based sessions well because it keeps # resetting the session key on each new request, thus destroying the concept # of a "session". We are going to do it manually, saving the session ID here @@ -1350,7 +1350,7 @@ class DomainRequestTests(TestWithUser, WebTest): session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - other_contacts_page = self.app.get(reverse("application:other_contacts")) + other_contacts_page = self.app.get(reverse("domain-request:other_contacts")) self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) other_contacts_form = other_contacts_page.forms[0] @@ -1411,7 +1411,7 @@ class DomainRequestTests(TestWithUser, WebTest): ao_pk = ao.id # prime the form by visiting /edit - self.app.get(reverse("edit-application", kwargs={"id": domain_request.pk})) + self.app.get(reverse("edit-domain-request", kwargs={"id": domain_request.pk})) # django-webtest does not handle cookie-based sessions well because it keeps # resetting the session key on each new request, thus destroying the concept # of a "session". We are going to do it manually, saving the session ID here @@ -1419,7 +1419,7 @@ class DomainRequestTests(TestWithUser, WebTest): session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - ao_page = self.app.get(reverse("application:authorizing_official")) + ao_page = self.app.get(reverse("domain-request:authorizing_official")) self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) ao_form = ao_page.forms[0] @@ -1479,7 +1479,7 @@ class DomainRequestTests(TestWithUser, WebTest): ao_pk = ao.id # prime the form by visiting /edit - self.app.get(reverse("edit-application", kwargs={"id": domain_request.pk})) + self.app.get(reverse("edit-domain-request", kwargs={"id": domain_request.pk})) # django-webtest does not handle cookie-based sessions well because it keeps # resetting the session key on each new request, thus destroying the concept # of a "session". We are going to do it manually, saving the session ID here @@ -1487,7 +1487,7 @@ class DomainRequestTests(TestWithUser, WebTest): session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - ao_page = self.app.get(reverse("application:authorizing_official")) + ao_page = self.app.get(reverse("domain-request:authorizing_official")) self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) ao_form = ao_page.forms[0] @@ -1548,7 +1548,7 @@ class DomainRequestTests(TestWithUser, WebTest): submitter_pk = you.id # prime the form by visiting /edit - self.app.get(reverse("edit-application", kwargs={"id": domain_request.pk})) + self.app.get(reverse("edit-domain-request", kwargs={"id": domain_request.pk})) # django-webtest does not handle cookie-based sessions well because it keeps # resetting the session key on each new request, thus destroying the concept # of a "session". We are going to do it manually, saving the session ID here @@ -1556,7 +1556,7 @@ class DomainRequestTests(TestWithUser, WebTest): session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - your_contact_page = self.app.get(reverse("application:your_contact")) + your_contact_page = self.app.get(reverse("domain-request:your_contact")) self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) your_contact_form = your_contact_page.forms[0] @@ -1615,7 +1615,7 @@ class DomainRequestTests(TestWithUser, WebTest): submitter_pk = submitter.id # prime the form by visiting /edit - self.app.get(reverse("edit-application", kwargs={"id": domain_request.pk})) + self.app.get(reverse("edit-domain-request", kwargs={"id": domain_request.pk})) # django-webtest does not handle cookie-based sessions well because it keeps # resetting the session key on each new request, thus destroying the concept # of a "session". We are going to do it manually, saving the session ID here @@ -1623,7 +1623,7 @@ class DomainRequestTests(TestWithUser, WebTest): session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) - your_contact_page = self.app.get(reverse("application:your_contact")) + your_contact_page = self.app.get(reverse("domain-request:your_contact")) self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) your_contact_form = your_contact_page.forms[0] @@ -1650,7 +1650,7 @@ class DomainRequestTests(TestWithUser, WebTest): def test_domain_request_about_your_organiztion_interstate(self): """Special districts have to answer an additional question.""" - intro_page = self.app.get(reverse("application:")) + intro_page = self.app.get(reverse("domain-request:")) # django-webtest does not handle cookie-based sessions well because it keeps # resetting the session key on each new request, thus destroying the concept # of a "session". We are going to do it manually, saving the session ID here @@ -1678,7 +1678,7 @@ class DomainRequestTests(TestWithUser, WebTest): def test_domain_request_tribal_government(self): """Tribal organizations have to answer an additional question.""" - intro_page = self.app.get(reverse("application:")) + intro_page = self.app.get(reverse("domain-request:")) # django-webtest does not handle cookie-based sessions well because it keeps # resetting the session key on each new request, thus destroying the concept # of a "session". We are going to do it manually, saving the session ID here @@ -1708,7 +1708,7 @@ class DomainRequestTests(TestWithUser, WebTest): self.assertContains(tribal_government_page, self.TITLES[Step.TRIBAL_GOVERNMENT]) def test_domain_request_ao_dynamic_text(self): - intro_page = self.app.get(reverse("application:")) + intro_page = self.app.get(reverse("domain-request:")) # django-webtest does not handle cookie-based sessions well because it keeps # resetting the session key on each new request, thus destroying the concept # of a "session". We are going to do it manually, saving the session ID here @@ -1779,7 +1779,7 @@ class DomainRequestTests(TestWithUser, WebTest): self.assertContains(ao_page, "Domain requests from cities") def test_domain_request_dotgov_domain_dynamic_text(self): - intro_page = self.app.get(reverse("application:")) + intro_page = self.app.get(reverse("domain-request:")) # django-webtest does not handle cookie-based sessions well because it keeps # resetting the session key on each new request, thus destroying the concept # of a "session". We are going to do it manually, saving the session ID here @@ -1881,7 +1881,7 @@ class DomainRequestTests(TestWithUser, WebTest): def test_domain_request_formsets(self): """Users are able to add more than one of some fields.""" - current_sites_page = self.app.get(reverse("application:current_sites")) + current_sites_page = self.app.get(reverse("domain-request:current_sites")) session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] # fill in the form field current_sites_form = current_sites_page.forms[0] @@ -1909,7 +1909,7 @@ class DomainRequestTests(TestWithUser, WebTest): @skip("WIP") def test_domain_request_edit_restore(self): """ - Test that a previously saved application is available at the /edit endpoint. + Test that a previously saved domain request is available at the /edit endpoint. """ ao, _ = Contact.objects.get_or_create( first_name="Testy", @@ -1955,7 +1955,7 @@ class DomainRequestTests(TestWithUser, WebTest): domain_request.alternative_domains.add(alt) # prime the form by visiting /edit - url = reverse("edit-application", kwargs={"id": domain_request.pk}) + url = reverse("edit-domain-request", kwargs={"id": domain_request.pk}) response = self.client.get(url) # TODO: this is a sketch of each page in the wizard which needs to be tested @@ -1965,7 +1965,7 @@ class DomainRequestTests(TestWithUser, WebTest): # -- the best that can/should be done here is to ensure the correct values # are being passed to the templating engine - url = reverse("application:organization_type") + url = reverse("domain-request:organization_type") response = self.client.get(url, follow=True) self.assertContains(response, "") # choices = response.context['wizard']['form']['organization_type'].subwidgets @@ -1973,62 +1973,62 @@ class DomainRequestTests(TestWithUser, WebTest): # checked = radio.data["selected"] # self.assertTrue(checked) - # url = reverse("application:organization_federal") + # url = reverse("domain-request:organization_federal") # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) # page = self.app.get(url) # self.assertNotContains(page, "VALUE") - # url = reverse("application:organization_contact") + # url = reverse("domain-request:organization_contact") # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) # page = self.app.get(url) # self.assertNotContains(page, "VALUE") - # url = reverse("application:authorizing_official") + # url = reverse("domain-request:authorizing_official") # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) # page = self.app.get(url) # self.assertNotContains(page, "VALUE") - # url = reverse("application:current_sites") + # url = reverse("domain-request:current_sites") # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) # page = self.app.get(url) # self.assertNotContains(page, "VALUE") - # url = reverse("application:dotgov_domain") + # url = reverse("domain-request:dotgov_domain") # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) # page = self.app.get(url) # self.assertNotContains(page, "VALUE") - # url = reverse("application:purpose") + # url = reverse("domain-request:purpose") # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) # page = self.app.get(url) # self.assertNotContains(page, "VALUE") - # url = reverse("application:your_contact") + # url = reverse("domain-request:your_contact") # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) # page = self.app.get(url) # self.assertNotContains(page, "VALUE") - # url = reverse("application:other_contacts") + # url = reverse("domain-request:other_contacts") # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) # page = self.app.get(url) # self.assertNotContains(page, "VALUE") - # url = reverse("application:other_contacts") + # url = reverse("domain-request:other_contacts") # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) # page = self.app.get(url) # self.assertNotContains(page, "VALUE") - # url = reverse("application:security_email") + # url = reverse("domain-request:security_email") # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) # page = self.app.get(url) # self.assertNotContains(page, "VALUE") - # url = reverse("application:anything_else") + # url = reverse("domain-request:anything_else") # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) # page = self.app.get(url) # self.assertNotContains(page, "VALUE") - # url = reverse("application:requirements") + # url = reverse("domain-request:requirements") # self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) # page = self.app.get(url) # self.assertNotContains(page, "VALUE") @@ -2038,7 +2038,7 @@ class DomainRequestTests(TestWithUser, WebTest): Make sure the long name is displaying in the domain request form, org step """ - intro_page = self.app.get(reverse("application:")) + intro_page = self.app.get(reverse("domain-request:")) # django-webtest does not handle cookie-based sessions well because it keeps # resetting the session key on each new request, thus destroying the concept # of a "session". We are going to do it manually, saving the session ID here @@ -2063,7 +2063,7 @@ class DomainRequestTests(TestWithUser, WebTest): NOTE: This may be a moot point if we implement a more solid pattern in the future, like not a submit action at all on the review page.""" - review_page = self.app.get(reverse("application:review")) + review_page = self.app.get(reverse("domain-request:review")) self.assertContains(review_page, "toggle-submit-domain-request") self.assertContains(review_page, "You are about to submit an incomplete request") @@ -2075,7 +2075,7 @@ class DomainRequestTestDifferentStatuses(TestWithUser, WebTest): self.client.force_login(self.user) def test_domain_request_status(self): - """Checking application status page""" + """Checking domain request status page""" domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.SUBMITTED, user=self.user) domain_request.save() @@ -2091,7 +2091,7 @@ class DomainRequestTestDifferentStatuses(TestWithUser, WebTest): self.assertContains(detail_page, "Status:") def test_domain_request_status_with_ineligible_user(self): - """Checking application status page whith a blocked user. + """Checking domain request status page whith a blocked user. The user should still have access to view.""" self.user.status = "ineligible" self.user.save() @@ -2110,7 +2110,7 @@ class DomainRequestTestDifferentStatuses(TestWithUser, WebTest): self.assertContains(detail_page, "Status:") def test_domain_request_withdraw(self): - """Checking application status page""" + """Checking domain request status page""" domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.SUBMITTED, user=self.user) domain_request.save() @@ -2143,7 +2143,7 @@ class DomainRequestTestDifferentStatuses(TestWithUser, WebTest): self.assertContains(home_page, "Withdrawn") def test_domain_request_withdraw_no_permissions(self): - """Can't withdraw applications as a restricted user.""" + """Can't withdraw domain requests as a restricted user.""" self.user.status = User.RESTRICTED self.user.save() domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.SUBMITTED, user=self.user) @@ -2162,15 +2162,15 @@ class DomainRequestTestDifferentStatuses(TestWithUser, WebTest): # Restricted user trying to withdraw results in 403 error with less_console_noise(): for url_name in [ - "application-withdraw-confirmation", - "application-withdrawn", + "domain-request-withdraw-confirmation", + "domain-request-withdrawn", ]: with self.subTest(url_name=url_name): page = self.client.get(reverse(url_name, kwargs={"pk": domain_request.pk})) self.assertEqual(page.status_code, 403) def test_domain_request_status_no_permissions(self): - """Can't access applications without being the creator.""" + """Can't access domain requests without being the creator.""" domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.SUBMITTED, user=self.user) other_user = User() other_user.save() @@ -2180,23 +2180,23 @@ class DomainRequestTestDifferentStatuses(TestWithUser, WebTest): # PermissionDeniedErrors make lots of noise in test output with less_console_noise(): for url_name in [ - "application-status", - "application-withdraw-confirmation", - "application-withdrawn", + "domain-request-status", + "domain-request-withdraw-confirmation", + "domain-request-withdrawn", ]: with self.subTest(url_name=url_name): page = self.client.get(reverse(url_name, kwargs={"pk": domain_request.pk})) self.assertEqual(page.status_code, 403) def test_approved_domain_request_not_in_active_requests(self): - """An approved application is not shown in the Active + """An approved domain request is not shown in the Active Requests table on home.html.""" domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.APPROVED, user=self.user) domain_request.save() home_page = self.app.get("/") # This works in our test environment because creating - # an approved application here does not generate a + # an approved domain request here does not generate a # domain object, so we do not expect to see 'city.gov' # in either the Domains or Requests tables. self.assertNotContains(home_page, "city.gov") @@ -2481,7 +2481,7 @@ class HomeTests(TestWithUser): self.assertContains(home_page, "button-toggle-delete-domain-alert-1") # Trigger the delete logic - response = self.client.post(reverse("application-delete", kwargs={"pk": domain_request.pk}), follow=True) + response = self.client.post(reverse("domain-request-delete", kwargs={"pk": domain_request.pk}), follow=True) self.assertNotContains(response, "igorville.gov") @@ -2505,7 +2505,7 @@ class HomeTests(TestWithUser): self.assertContains(home_page, "button-toggle-delete-domain-alert-1") # Trigger the delete logic - response = self.client.post(reverse("application-delete", kwargs={"pk": domain_request.pk}), follow=True) + response = self.client.post(reverse("domain-request-delete", kwargs={"pk": domain_request.pk}), follow=True) self.assertNotContains(response, "igorville.gov") @@ -2513,7 +2513,7 @@ class HomeTests(TestWithUser): domain_request.delete() def test_home_doesnt_delete_other_domain_requests(self): - """Tests to ensure the user can't delete Applications not in the status of STARTED or WITHDRAWN""" + """Tests to ensure the user can't delete domain requests not in the status of STARTED or WITHDRAWN""" # Given that we are including a subset of items that can be deleted while excluding the rest, # subTest is appropriate here as otherwise we would need many duplicate tests for the same reason. @@ -2531,7 +2531,7 @@ class HomeTests(TestWithUser): # Trigger the delete logic response = self.client.post( - reverse("application-delete", kwargs={"pk": domain_request.pk}), follow=True + reverse("domain-request-delete", kwargs={"pk": domain_request.pk}), follow=True ) # Check for a 403 error - the end user should not be allowed to do this @@ -2577,7 +2577,7 @@ class HomeTests(TestWithUser): ) domain_request.other_contacts.set([contact_2]) - # Create a second application to attach contacts to + # Create a second domain request to attach contacts to site_2 = DraftDomain.objects.create(name="teaville.gov") domain_request_2 = DomainRequest.objects.create( creator=self.user, @@ -2593,7 +2593,7 @@ class HomeTests(TestWithUser): self.assertContains(home_page, "igorville.gov") # Trigger the delete logic - response = self.client.post(reverse("application-delete", kwargs={"pk": domain_request.pk}), follow=True) + response = self.client.post(reverse("domain-request-delete", kwargs={"pk": domain_request.pk}), follow=True) # igorville is now deleted self.assertNotContains(response, "igorville.gov") @@ -2649,7 +2649,7 @@ class HomeTests(TestWithUser): ) domain_request.other_contacts.set([contact_2]) - # Create a second application to attach contacts to + # Create a second domain request to attach contacts to site_2 = DraftDomain.objects.create(name="teaville.gov") domain_request_2 = DomainRequest.objects.create( creator=self.user, @@ -2664,7 +2664,7 @@ class HomeTests(TestWithUser): self.assertContains(home_page, "teaville.gov") # Trigger the delete logic - response = self.client.post(reverse("application-delete", kwargs={"pk": domain_request_2.pk}), follow=True) + response = self.client.post(reverse("domain-request-delete", kwargs={"pk": domain_request_2.pk}), follow=True) self.assertNotContains(response, "teaville.gov") diff --git a/src/registrar/views/domain_request.py b/src/registrar/views/domain_request.py index bdb125c0a..f7a784b51 100644 --- a/src/registrar/views/domain_request.py +++ b/src/registrar/views/domain_request.py @@ -74,8 +74,8 @@ class DomainRequestWizard(DomainRequestWizardPermissionView, TemplateView): # NB: this is included here for reference. Do not change it without # also changing the many places it is hardcoded in the HTML templates URL_NAMESPACE = "domain_request" - # name for accessing /application//edit - EDIT_URL_NAME = "edit-application" + # name for accessing /domain-request//edit + EDIT_URL_NAME = "edit-domain-request" NEW_URL_NAME = "/request/" # We need to pass our human-readable step titles as context to the templates. TITLES = { @@ -118,7 +118,7 @@ class DomainRequestWizard(DomainRequestWizardPermissionView, TemplateView): def prefix(self): """Namespace the wizard to avoid clashes in session variable names.""" # this is a string literal but can be made dynamic if we'd like - # users to have multiple applications open for editing simultaneously + # users to have multiple domain requests open for editing simultaneously return "wizard_domain_request" @property @@ -148,7 +148,7 @@ class DomainRequestWizard(DomainRequestWizardPermissionView, TemplateView): ) return self._domain_request except DomainRequest.DoesNotExist: - logger.debug("Application id %s did not have a DomainRequest" % id) + logger.debug("DomainRequest id %s did not have a DomainRequest" % id) self._domain_request = DomainRequest.objects.create(creator=self.request.user) @@ -181,7 +181,7 @@ class DomainRequestWizard(DomainRequestWizardPermissionView, TemplateView): """Called when the user clicks the submit button, if all forms are valid.""" self.domain_request.submit() # change the status to submitted self.domain_request.save() - logger.debug("Application object saved: %s", self.domain_request.id) + logger.debug("Domain Request object saved: %s", self.domain_request.id) return redirect(reverse(f"{self.URL_NAMESPACE}:finished")) def from_model(self, attribute: str, default, *args, **kwargs): @@ -210,7 +210,7 @@ class DomainRequestWizard(DomainRequestWizardPermissionView, TemplateView): current_url = resolve(request.path_info).url_name # if user visited via an "edit" url, associate the id of the - # application they are trying to edit to this wizard instance + # domain request they are trying to edit to this wizard instance # and remove any prior wizard data from their session if current_url == self.EDIT_URL_NAME and "id" in kwargs: del self.storage @@ -309,7 +309,7 @@ class DomainRequestWizard(DomainRequestWizardPermissionView, TemplateView): return self.pending_domain_requests() def approved_domain_requests_exist(self): - """Checks if user is creator of applications with DomainRequestStatus.APPROVED status""" + """Checks if user is creator of domain requests with DomainRequestStatus.APPROVED status""" approved_domain_request_count = DomainRequest.objects.filter( creator=self.request.user, status=DomainRequest.DomainRequestStatus.APPROVED ).count() @@ -323,9 +323,9 @@ class DomainRequestWizard(DomainRequestWizardPermissionView, TemplateView): return self.request.user.permissions.count() > 0 def pending_domain_requests(self): - """Returns a List of user's applications with one of the following states: + """Returns a List of user's domain requests with one of the following states: DomainRequestStatus.SUBMITTED, DomainRequestStatus.IN_REVIEW, DomainRequestStatus.ACTION_NEEDED""" - # if the current application has DomainRequestStatus.ACTION_NEEDED status, this check should not be performed + # if the current domain request has DomainRequestStatus.ACTION_NEEDED status, this check should not be performed if self.domain_request.status == DomainRequest.DomainRequestStatus.ACTION_NEEDED: return [] check_statuses = [ @@ -639,7 +639,7 @@ class DomainRequestStatus(DomainRequestPermissionView): template_name = "domain_request_status.html" -class ApplicationWithdrawConfirmation(DomainRequestPermissionWithdrawView): +class DomainRequestWithdrawConfirmation(DomainRequestPermissionWithdrawView): """This page will ask user to confirm if they want to withdraw The DomainRequestPermissionView restricts access so that only the @@ -649,7 +649,7 @@ class ApplicationWithdrawConfirmation(DomainRequestPermissionWithdrawView): template_name = "domain_request_withdraw_confirmation.html" -class ApplicationWithdrawn(DomainRequestPermissionWithdrawView): +class DomainRequestWithdrawn(DomainRequestPermissionWithdrawView): # this view renders no template template_name = "" @@ -689,8 +689,8 @@ class DomainRequestDeleteView(DomainRequestPermissionDeleteView): def post(self, request, *args, **kwargs): # Grab all orphaned contacts - application: DomainRequest = self.get_object() - contacts_to_delete, duplicates = self._get_orphaned_contacts(application) + domain_request: DomainRequest = self.get_object() + contacts_to_delete, duplicates = self._get_orphaned_contacts(domain_request) # Delete the DomainRequest response = super().post(request, *args, **kwargs) @@ -716,7 +716,7 @@ class DomainRequestDeleteView(DomainRequestPermissionDeleteView): and any other contacts linked to the domain_request. Parameters: - application (DomainRequest): The DomainRequest object for which to find orphaned contacts. + domain_request (DomainRequest): The DomainRequest object for which to find orphaned contacts. check_db (bool, optional): A flag indicating whether to check the database for the existence of the contacts. Defaults to False. diff --git a/src/registrar/views/index.py b/src/registrar/views/index.py index 1306b4cef..cb170078a 100644 --- a/src/registrar/views/index.py +++ b/src/registrar/views/index.py @@ -8,25 +8,25 @@ def index(request): context = {} if request.user.is_authenticated: # Get all domain requests the user has access to - applications, deletable_domain_requests = _get_domain_requests(request) + domain_requests, deletable_domain_requests = _get_domain_requests(request) - context["domain_requests"] = applications + context["domain_requests"] = domain_requests # Get all domains the user has access to domains = _get_domains(request) context["domains"] = domains - # Determine if the user will see applications that they can delete + # Determine if the user will see domain requests that they can delete has_deletable_domain_requests = deletable_domain_requests.exists() context["has_deletable_domain_requests"] = has_deletable_domain_requests - # If they can delete applications, add the delete button to the context + # If they can delete domain requests, add the delete button to the context if has_deletable_domain_requests: # Add the delete modal button to the context modal_button = ( '' + 'name="delete-domain-request">Yes, delete request' ) context["modal_button"] = modal_button @@ -37,20 +37,20 @@ def _get_domain_requests(request): """Given the current request, get all DomainRequests that are associated with the UserDomainRole object. - Returns a tuple of all applications, and those that are deletable by the user. + Returns a tuple of all domain requests, and those that are deletable by the user. """ - # Let's exclude the approved applications since our + # Let's exclude the approved domain requests since our # domain_requests context will be used to populate - # the active applications table - applications = DomainRequest.objects.filter(creator=request.user).exclude( + # the active domain requests table + domain_requests = DomainRequest.objects.filter(creator=request.user).exclude( status=DomainRequest.DomainRequestStatus.APPROVED ) # Create a placeholder DraftDomain for each incomplete draft valid_statuses = [DomainRequest.DomainRequestStatus.STARTED, DomainRequest.DomainRequestStatus.WITHDRAWN] - deletable_domain_requests = applications.filter(status__in=valid_statuses) + deletable_domain_requests = domain_requests.filter(status__in=valid_statuses) - return (applications, deletable_domain_requests) + return (domain_requests, deletable_domain_requests) def _get_domains(request): diff --git a/src/registrar/views/utility/mixins.py b/src/registrar/views/utility/mixins.py index 400c6df53..aa0c9cd6b 100644 --- a/src/registrar/views/utility/mixins.py +++ b/src/registrar/views/utility/mixins.py @@ -244,9 +244,9 @@ class DomainPermission(PermissionsLoginMixin): if DomainInformation.objects.filter(id=pk).exists(): requested_domain = DomainInformation.objects.get(id=pk) - # if no domain information or application exist, the user + # if no domain information or domain request exist, the user # should be able to manage the domain; however, if domain information - # and domain request exist, and application is not in valid status, + # and domain request exist, and domain request is not in valid status, # user should not be able to manage domain if ( requested_domain From 732766da0e503b390acbe5bee80f27020f8b4066 Mon Sep 17 00:00:00 2001 From: CocoByte Date: Thu, 29 Feb 2024 20:35:02 -0700 Subject: [PATCH 041/103] linted and fixed urls --- src/registrar/admin.py | 4 +--- src/registrar/config/urls.py | 4 ++-- src/registrar/views/domain_request.py | 3 ++- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index 28f17186a..c9eea460d 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -1081,9 +1081,7 @@ class DomainRequestAdmin(ListHeaderAdmin): ) elif ( - obj - and obj.status == models.DomainRequest.DomainRequestStatus.REJECTED - and not obj.rejection_reason + obj and obj.status == models.DomainRequest.DomainRequestStatus.REJECTED and not obj.rejection_reason ): # This condition should never be triggered. # The opposite of this condition is acceptable (rejected -> other status and rejection_reason) diff --git a/src/registrar/config/urls.py b/src/registrar/config/urls.py index 216a54c6a..9049d718c 100644 --- a/src/registrar/config/urls.py +++ b/src/registrar/config/urls.py @@ -66,12 +66,12 @@ urlpatterns = [ ), path( "domain-request//withdraw", - views.domain-requestWithdrawConfirmation.as_view(), + views.DomainRequestWithdrawConfirmation.as_view(), name="domain-request-withdraw-confirmation", ), path( "domain-request//withdrawconfirmed", - views.domain-requestWithdrawn.as_view(), + views.DomainRequestWithdrawn.as_view(), name="domain-request-withdrawn", ), path("health", views.health, name="health"), diff --git a/src/registrar/views/domain_request.py b/src/registrar/views/domain_request.py index f7a784b51..aff723ac3 100644 --- a/src/registrar/views/domain_request.py +++ b/src/registrar/views/domain_request.py @@ -362,7 +362,8 @@ class DomainRequestWizard(DomainRequestWizardPermissionView, TemplateView): "purpose": self.domain_request.purpose is not None, "your_contact": self.domain_request.submitter is not None, "other_contacts": ( - self.domain_request.other_contacts.exists() or self.domain_request.no_other_contacts_rationale is not None + self.domain_request.other_contacts.exists() + or self.domain_request.no_other_contacts_rationale is not None ), "anything_else": ( self.domain_request.anything_else is not None or self.domain_request.is_policy_acknowledged is not None From a73f2ed03435e643653b8b37d6cf09a73bfd5ce2 Mon Sep 17 00:00:00 2001 From: CocoByte Date: Thu, 29 Feb 2024 20:48:26 -0700 Subject: [PATCH 042/103] Restored old migrations --- src/registrar/migrations/0001_initial.py | 2 +- ..._domain_host_nameserver_hostip_and_more.py | 4 ++-- ...napplication_is_election_board_and_more.py | 22 +++++++++---------- .../0004_domainapplication_federal_agency.py | 4 ++-- .../0005_domainapplication_city_and_more.py | 8 +++---- .../migrations/0006_alter_contact_phone.py | 2 +- ..._more_organization_information_and_more.py | 22 +++++++++---------- ..._remove_userprofile_created_at_and_more.py | 2 +- ...ion_federally_recognized_tribe_and_more.py | 6 ++--- ...application_no_other_contacts_rationale.py | 4 ++-- ...remove_domainapplication_security_email.py | 4 ++-- .../migrations/0012_delete_userprofile.py | 2 +- ...alter_domainapplication_status_and_more.py | 2 +- .../migrations/0018_domaininformation.py | 10 ++++----- ...ter_domainapplication_organization_type.py | 2 +- ...remove_domaininformation_security_email.py | 2 +- ...ainapplication_approved_domain_and_more.py | 8 +++---- ...t_name_alter_contact_last_name_and_more.py | 2 +- ...omainapplication_address_line2_and_more.py | 2 +- ...omaininformation_address_line1_and_more.py | 2 +- .../0028_alter_domainapplication_status.py | 2 +- ...r_status_alter_domainapplication_status.py | 4 ++-- .../migrations/0030_alter_user_status.py | 2 +- .../0031_transitiondomain_and_more.py | 10 ++++----- ...napplication_organization_type_and_more.py | 2 +- .../migrations/0042_create_groups_v03.py | 2 +- ...inapplication_current_websites_and_more.py | 4 ++-- ...0050_alter_contact_middle_name_and_more.py | 4 ++-- ...domainapplication_urbanization_and_more.py | 2 +- ...omainapplication_anything_else_and_more.py | 4 ++-- .../migrations/0053_create_groups_v05.py | 2 +- ...mainapplication_federal_agency_and_more.py | 4 ++-- .../0055_transitiondomain_processed.py | 2 +- ...alter_domainapplication_status_and_more.py | 2 +- .../0057_domainapplication_submission_date.py | 4 ++-- .../0058_alter_domaininformation_options.py | 2 +- ...omainapplication_address_line1_and_more.py | 4 ++-- .../migrations/0065_create_groups_v06.py | 2 +- ...plication_notes_domaininformation_notes.py | 2 +- ...email_alter_contact_first_name_and_more.py | 2 +- ...0070_domainapplication_rejection_reason.py | 2 +- ...t_name_alter_contact_last_name_and_more.py | 16 +++++++------- 42 files changed, 96 insertions(+), 96 deletions(-) diff --git a/src/registrar/migrations/0001_initial.py b/src/registrar/migrations/0001_initial.py index 70bcde188..8c50c750d 100644 --- a/src/registrar/migrations/0001_initial.py +++ b/src/registrar/migrations/0001_initial.py @@ -168,7 +168,7 @@ class Migration(migrations.Migration): ], ), migrations.CreateModel( - name="DomainRequest", + name="DomainApplication", fields=[ ( "id", diff --git a/src/registrar/migrations/0002_domain_host_nameserver_hostip_and_more.py b/src/registrar/migrations/0002_domain_host_nameserver_hostip_and_more.py index d4a4a3918..f1049c252 100644 --- a/src/registrar/migrations/0002_domain_host_nameserver_hostip_and_more.py +++ b/src/registrar/migrations/0002_domain_host_nameserver_hostip_and_more.py @@ -142,14 +142,14 @@ class Migration(migrations.Migration): }, ), migrations.AlterField( - model_name="DomainRequest", + model_name="domainapplication", name="requested_domain", field=models.OneToOneField( blank=True, help_text="The requested domain", null=True, on_delete=django.db.models.deletion.PROTECT, - related_name="domain_request", + related_name="domain_application", to="registrar.domain", ), ), diff --git a/src/registrar/migrations/0003_rename_is_election_office_domainapplication_is_election_board_and_more.py b/src/registrar/migrations/0003_rename_is_election_office_domainapplication_is_election_board_and_more.py index 587747ea8..a6844bfaf 100644 --- a/src/registrar/migrations/0003_rename_is_election_office_domainapplication_is_election_board_and_more.py +++ b/src/registrar/migrations/0003_rename_is_election_office_domainapplication_is_election_board_and_more.py @@ -10,48 +10,48 @@ class Migration(migrations.Migration): operations = [ migrations.RenameField( - model_name="DomainRequest", + model_name="domainapplication", old_name="is_election_office", new_name="is_election_board", ), migrations.RenameField( - model_name="DomainRequest", + model_name="domainapplication", old_name="acknowledged_policy", new_name="is_policy_acknowledged", ), migrations.RenameField( - model_name="DomainRequest", + model_name="domainapplication", old_name="zip_code", new_name="zipcode", ), migrations.RemoveField( - model_name="DomainRequest", + model_name="domainapplication", name="federal_branch", ), migrations.RemoveField( - model_name="DomainRequest", + model_name="domainapplication", name="street_address", ), migrations.RemoveField( - model_name="DomainRequest", + model_name="domainapplication", name="unit_number", ), migrations.RemoveField( - model_name="DomainRequest", + model_name="domainapplication", name="unit_type", ), migrations.AddField( - model_name="DomainRequest", + model_name="domainapplication", name="address_line1", field=models.TextField(blank=True, help_text="Address line 1", null=True), ), migrations.AddField( - model_name="DomainRequest", + model_name="domainapplication", name="address_line2", field=models.CharField(blank=True, help_text="Address line 2", max_length=15, null=True), ), migrations.AddField( - model_name="DomainRequest", + model_name="domainapplication", name="federal_type", field=models.CharField( blank=True, @@ -66,7 +66,7 @@ class Migration(migrations.Migration): ), ), migrations.AlterField( - model_name="DomainRequest", + model_name="domainapplication", name="organization_type", field=models.CharField( blank=True, diff --git a/src/registrar/migrations/0004_domainapplication_federal_agency.py b/src/registrar/migrations/0004_domainapplication_federal_agency.py index cffe5a864..a00d46ac2 100644 --- a/src/registrar/migrations/0004_domainapplication_federal_agency.py +++ b/src/registrar/migrations/0004_domainapplication_federal_agency.py @@ -7,13 +7,13 @@ class Migration(migrations.Migration): dependencies = [ ( "registrar", - "0003_rename_is_election_office_DomainRequest_is_election_board_and_more", + "0003_rename_is_election_office_domainapplication_is_election_board_and_more", ), ] operations = [ migrations.AddField( - model_name="DomainRequest", + model_name="domainapplication", name="federal_agency", field=models.TextField(help_text="Top level federal agency", null=True), ), diff --git a/src/registrar/migrations/0005_domainapplication_city_and_more.py b/src/registrar/migrations/0005_domainapplication_city_and_more.py index 4f933ceb2..bd4683b8c 100644 --- a/src/registrar/migrations/0005_domainapplication_city_and_more.py +++ b/src/registrar/migrations/0005_domainapplication_city_and_more.py @@ -5,22 +5,22 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ("registrar", "0004_DomainRequest_federal_agency"), + ("registrar", "0004_domainapplication_federal_agency"), ] operations = [ migrations.AddField( - model_name="DomainRequest", + model_name="domainapplication", name="city", field=models.TextField(blank=True, help_text="City", null=True), ), migrations.AddField( - model_name="DomainRequest", + model_name="domainapplication", name="urbanization", field=models.TextField(blank=True, help_text="Urbanization", null=True), ), migrations.AlterField( - model_name="DomainRequest", + model_name="domainapplication", name="federal_agency", field=models.TextField(blank=True, help_text="Top level federal agency", null=True), ), diff --git a/src/registrar/migrations/0006_alter_contact_phone.py b/src/registrar/migrations/0006_alter_contact_phone.py index 09bcc1fbb..1e055694f 100644 --- a/src/registrar/migrations/0006_alter_contact_phone.py +++ b/src/registrar/migrations/0006_alter_contact_phone.py @@ -6,7 +6,7 @@ import phonenumber_field.modelfields # type: ignore class Migration(migrations.Migration): dependencies = [ - ("registrar", "0005_DomainRequest_city_and_more"), + ("registrar", "0005_domainapplication_city_and_more"), ] operations = [ diff --git a/src/registrar/migrations/0007_domainapplication_more_organization_information_and_more.py b/src/registrar/migrations/0007_domainapplication_more_organization_information_and_more.py index e6199ea86..49df16fbb 100644 --- a/src/registrar/migrations/0007_domainapplication_more_organization_information_and_more.py +++ b/src/registrar/migrations/0007_domainapplication_more_organization_information_and_more.py @@ -10,7 +10,7 @@ class Migration(migrations.Migration): operations = [ migrations.AddField( - model_name="DomainRequest", + model_name="domainapplication", name="more_organization_information", field=models.TextField( blank=True, @@ -19,27 +19,27 @@ class Migration(migrations.Migration): ), ), migrations.AddField( - model_name="DomainRequest", + model_name="domainapplication", name="type_of_work", field=models.TextField(blank=True, help_text="Type of work of the organization", null=True), ), migrations.AlterField( - model_name="DomainRequest", + model_name="domainapplication", name="address_line1", field=models.TextField(blank=True, help_text="Street address", null=True), ), migrations.AlterField( - model_name="DomainRequest", + model_name="domainapplication", name="address_line2", field=models.CharField(blank=True, help_text="Street address line 2", max_length=15, null=True), ), migrations.AlterField( - model_name="DomainRequest", + model_name="domainapplication", name="federal_agency", field=models.TextField(blank=True, help_text="Federal agency", null=True), ), migrations.AlterField( - model_name="DomainRequest", + model_name="domainapplication", name="federal_type", field=models.CharField( blank=True, @@ -54,7 +54,7 @@ class Migration(migrations.Migration): ), ), migrations.AlterField( - model_name="DomainRequest", + model_name="domainapplication", name="organization_type", field=models.CharField( blank=True, @@ -89,12 +89,12 @@ class Migration(migrations.Migration): ), ), migrations.AlterField( - model_name="DomainRequest", + model_name="domainapplication", name="purpose", field=models.TextField(blank=True, help_text="Purpose of your domain", null=True), ), migrations.AlterField( - model_name="DomainRequest", + model_name="domainapplication", name="state_territory", field=models.CharField( blank=True, @@ -104,12 +104,12 @@ class Migration(migrations.Migration): ), ), migrations.AlterField( - model_name="DomainRequest", + model_name="domainapplication", name="urbanization", field=models.TextField(blank=True, help_text="Urbanization (Puerto Rico only)", null=True), ), migrations.AlterField( - model_name="DomainRequest", + model_name="domainapplication", name="zipcode", field=models.CharField( blank=True, diff --git a/src/registrar/migrations/0008_remove_userprofile_created_at_and_more.py b/src/registrar/migrations/0008_remove_userprofile_created_at_and_more.py index 045e83f49..2e2dbed6c 100644 --- a/src/registrar/migrations/0008_remove_userprofile_created_at_and_more.py +++ b/src/registrar/migrations/0008_remove_userprofile_created_at_and_more.py @@ -6,7 +6,7 @@ import django.utils.timezone class Migration(migrations.Migration): dependencies = [ - ("registrar", "0007_DomainRequest_more_organization_information_and_more"), + ("registrar", "0007_domainapplication_more_organization_information_and_more"), ] operations = [ diff --git a/src/registrar/migrations/0009_domainapplication_federally_recognized_tribe_and_more.py b/src/registrar/migrations/0009_domainapplication_federally_recognized_tribe_and_more.py index 2c9c26888..7fce25b9e 100644 --- a/src/registrar/migrations/0009_domainapplication_federally_recognized_tribe_and_more.py +++ b/src/registrar/migrations/0009_domainapplication_federally_recognized_tribe_and_more.py @@ -10,17 +10,17 @@ class Migration(migrations.Migration): operations = [ migrations.AddField( - model_name="DomainRequest", + model_name="domainapplication", name="federally_recognized_tribe", field=models.BooleanField(help_text="Is the tribe federally recognized", null=True), ), migrations.AddField( - model_name="DomainRequest", + model_name="domainapplication", name="state_recognized_tribe", field=models.BooleanField(help_text="Is the tribe recognized by a state", null=True), ), migrations.AddField( - model_name="DomainRequest", + model_name="domainapplication", name="tribe_name", field=models.TextField(blank=True, help_text="Name of tribe", null=True), ), diff --git a/src/registrar/migrations/0010_domainapplication_no_other_contacts_rationale.py b/src/registrar/migrations/0010_domainapplication_no_other_contacts_rationale.py index 412fcc6db..bf8d83d60 100644 --- a/src/registrar/migrations/0010_domainapplication_no_other_contacts_rationale.py +++ b/src/registrar/migrations/0010_domainapplication_no_other_contacts_rationale.py @@ -5,12 +5,12 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ("registrar", "0009_DomainRequest_federally_recognized_tribe_and_more"), + ("registrar", "0009_domainapplication_federally_recognized_tribe_and_more"), ] operations = [ migrations.AddField( - model_name="DomainRequest", + model_name="domainapplication", name="no_other_contacts_rationale", field=models.TextField( blank=True, diff --git a/src/registrar/migrations/0011_remove_domainapplication_security_email.py b/src/registrar/migrations/0011_remove_domainapplication_security_email.py index 5d5c278ac..c717408da 100644 --- a/src/registrar/migrations/0011_remove_domainapplication_security_email.py +++ b/src/registrar/migrations/0011_remove_domainapplication_security_email.py @@ -5,12 +5,12 @@ from django.db import migrations class Migration(migrations.Migration): dependencies = [ - ("registrar", "0010_DomainRequest_no_other_contacts_rationale"), + ("registrar", "0010_domainapplication_no_other_contacts_rationale"), ] operations = [ migrations.RemoveField( - model_name="DomainRequest", + model_name="domainapplication", name="security_email", ), ] diff --git a/src/registrar/migrations/0012_delete_userprofile.py b/src/registrar/migrations/0012_delete_userprofile.py index 29305d519..b5bcebb95 100644 --- a/src/registrar/migrations/0012_delete_userprofile.py +++ b/src/registrar/migrations/0012_delete_userprofile.py @@ -7,7 +7,7 @@ import django.db.models.deletion class Migration(migrations.Migration): dependencies = [ - ("registrar", "0011_remove_DomainRequest_security_email"), + ("registrar", "0011_remove_domainapplication_security_email"), ] operations = [ diff --git a/src/registrar/migrations/0017_alter_domainapplication_status_and_more.py b/src/registrar/migrations/0017_alter_domainapplication_status_and_more.py index 341c83994..5d20551d7 100644 --- a/src/registrar/migrations/0017_alter_domainapplication_status_and_more.py +++ b/src/registrar/migrations/0017_alter_domainapplication_status_and_more.py @@ -11,7 +11,7 @@ class Migration(migrations.Migration): operations = [ migrations.AlterField( - model_name="DomainRequest", + model_name="domainapplication", name="status", field=django_fsm.FSMField( choices=[ diff --git a/src/registrar/migrations/0018_domaininformation.py b/src/registrar/migrations/0018_domaininformation.py index 38a24f7d8..582a6e244 100644 --- a/src/registrar/migrations/0018_domaininformation.py +++ b/src/registrar/migrations/0018_domaininformation.py @@ -7,7 +7,7 @@ import django.db.models.deletion class Migration(migrations.Migration): dependencies = [ - ("registrar", "0017_alter_DomainRequest_status_and_more"), + ("registrar", "0017_alter_domainapplication_status_and_more"), ] operations = [ @@ -229,14 +229,14 @@ class Migration(migrations.Migration): ), ), ( - "domain_request", + "domain_application", models.OneToOneField( blank=True, - help_text="Associated domain request", + help_text="Associated domain application", null=True, on_delete=django.db.models.deletion.PROTECT, - related_name="DomainRequest_info", - to="registrar.DomainRequest", + related_name="domainapplication_info", + to="registrar.domainapplication", ), ), ( diff --git a/src/registrar/migrations/0019_alter_domainapplication_organization_type.py b/src/registrar/migrations/0019_alter_domainapplication_organization_type.py index 60273e854..1a7397255 100644 --- a/src/registrar/migrations/0019_alter_domainapplication_organization_type.py +++ b/src/registrar/migrations/0019_alter_domainapplication_organization_type.py @@ -10,7 +10,7 @@ class Migration(migrations.Migration): operations = [ migrations.AlterField( - model_name="DomainRequest", + model_name="domainapplication", name="organization_type", field=models.CharField( blank=True, diff --git a/src/registrar/migrations/0020_remove_domaininformation_security_email.py b/src/registrar/migrations/0020_remove_domaininformation_security_email.py index b48133ade..9742c294a 100644 --- a/src/registrar/migrations/0020_remove_domaininformation_security_email.py +++ b/src/registrar/migrations/0020_remove_domaininformation_security_email.py @@ -5,7 +5,7 @@ from django.db import migrations class Migration(migrations.Migration): dependencies = [ - ("registrar", "0019_alter_DomainRequest_organization_type"), + ("registrar", "0019_alter_domainapplication_organization_type"), ] operations = [ diff --git a/src/registrar/migrations/0022_draftdomain_domainapplication_approved_domain_and_more.py b/src/registrar/migrations/0022_draftdomain_domainapplication_approved_domain_and_more.py index 6a44c93d9..fb89e0eb2 100644 --- a/src/registrar/migrations/0022_draftdomain_domainapplication_approved_domain_and_more.py +++ b/src/registrar/migrations/0022_draftdomain_domainapplication_approved_domain_and_more.py @@ -40,26 +40,26 @@ class Migration(migrations.Migration): bases=(models.Model, registrar.models.utility.domain_helper.DomainHelper), # type: ignore ), migrations.AddField( - model_name="DomainRequest", + model_name="domainapplication", name="approved_domain", field=models.OneToOneField( blank=True, help_text="The approved domain", null=True, on_delete=django.db.models.deletion.PROTECT, - related_name="domain_request", + related_name="domain_application", to="registrar.domain", ), ), migrations.AlterField( - model_name="DomainRequest", + model_name="domainapplication", name="requested_domain", field=models.OneToOneField( blank=True, help_text="The requested domain", null=True, on_delete=django.db.models.deletion.PROTECT, - related_name="domain_request", + related_name="domain_application", to="registrar.draftdomain", ), ), diff --git a/src/registrar/migrations/0023_alter_contact_first_name_alter_contact_last_name_and_more.py b/src/registrar/migrations/0023_alter_contact_first_name_alter_contact_last_name_and_more.py index 85ba6268b..b2259f650 100644 --- a/src/registrar/migrations/0023_alter_contact_first_name_alter_contact_last_name_and_more.py +++ b/src/registrar/migrations/0023_alter_contact_first_name_alter_contact_last_name_and_more.py @@ -5,7 +5,7 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ("registrar", "0022_draftdomain_DomainRequest_approved_domain_and_more"), + ("registrar", "0022_draftdomain_domainapplication_approved_domain_and_more"), ] operations = [ diff --git a/src/registrar/migrations/0026_alter_domainapplication_address_line2_and_more.py b/src/registrar/migrations/0026_alter_domainapplication_address_line2_and_more.py index 5ec43af43..77da9e79c 100644 --- a/src/registrar/migrations/0026_alter_domainapplication_address_line2_and_more.py +++ b/src/registrar/migrations/0026_alter_domainapplication_address_line2_and_more.py @@ -10,7 +10,7 @@ class Migration(migrations.Migration): operations = [ migrations.AlterField( - model_name="DomainRequest", + model_name="domainapplication", name="address_line2", field=models.TextField(blank=True, help_text="Street address line 2", null=True), ), diff --git a/src/registrar/migrations/0027_alter_domaininformation_address_line1_and_more.py b/src/registrar/migrations/0027_alter_domaininformation_address_line1_and_more.py index 0d25ec506..9f362c956 100644 --- a/src/registrar/migrations/0027_alter_domaininformation_address_line1_and_more.py +++ b/src/registrar/migrations/0027_alter_domaininformation_address_line1_and_more.py @@ -5,7 +5,7 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ("registrar", "0026_alter_DomainRequest_address_line2_and_more"), + ("registrar", "0026_alter_domainapplication_address_line2_and_more"), ] operations = [ diff --git a/src/registrar/migrations/0028_alter_domainapplication_status.py b/src/registrar/migrations/0028_alter_domainapplication_status.py index ed2544779..61b1c0505 100644 --- a/src/registrar/migrations/0028_alter_domainapplication_status.py +++ b/src/registrar/migrations/0028_alter_domainapplication_status.py @@ -13,7 +13,7 @@ class Migration(migrations.Migration): operations = [ migrations.AlterField( - model_name="DomainRequest", + model_name="domainapplication", name="status", field=django_fsm.FSMField( choices=[ diff --git a/src/registrar/migrations/0029_user_status_alter_domainapplication_status.py b/src/registrar/migrations/0029_user_status_alter_domainapplication_status.py index f3c9bea83..504358665 100644 --- a/src/registrar/migrations/0029_user_status_alter_domainapplication_status.py +++ b/src/registrar/migrations/0029_user_status_alter_domainapplication_status.py @@ -6,7 +6,7 @@ import django_fsm class Migration(migrations.Migration): dependencies = [ - ("registrar", "0028_alter_DomainRequest_status"), + ("registrar", "0028_alter_domainapplication_status"), ] operations = [ @@ -22,7 +22,7 @@ class Migration(migrations.Migration): ), ), migrations.AlterField( - model_name="DomainRequest", + model_name="domainapplication", name="status", field=django_fsm.FSMField( choices=[ diff --git a/src/registrar/migrations/0030_alter_user_status.py b/src/registrar/migrations/0030_alter_user_status.py index a1055017b..7dd27bfa4 100644 --- a/src/registrar/migrations/0030_alter_user_status.py +++ b/src/registrar/migrations/0030_alter_user_status.py @@ -5,7 +5,7 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ("registrar", "0029_user_status_alter_DomainRequest_status"), + ("registrar", "0029_user_status_alter_domainapplication_status"), ] operations = [ diff --git a/src/registrar/migrations/0031_transitiondomain_and_more.py b/src/registrar/migrations/0031_transitiondomain_and_more.py index a3982fd6a..9d1153764 100644 --- a/src/registrar/migrations/0031_transitiondomain_and_more.py +++ b/src/registrar/migrations/0031_transitiondomain_and_more.py @@ -77,11 +77,11 @@ class Migration(migrations.Migration): }, ), migrations.RemoveField( - model_name="DomainRequest", + model_name="domainapplication", name="more_organization_information", ), migrations.RemoveField( - model_name="DomainRequest", + model_name="domainapplication", name="type_of_work", ), migrations.RemoveField( @@ -93,7 +93,7 @@ class Migration(migrations.Migration): name="type_of_work", ), migrations.AddField( - model_name="DomainRequest", + model_name="domainapplication", name="about_your_organization", field=models.TextField(blank=True, help_text="Information about your organization", null=True), ), @@ -103,14 +103,14 @@ class Migration(migrations.Migration): field=models.TextField(blank=True, help_text="Information about your organization", null=True), ), migrations.AlterField( - model_name="DomainRequest", + model_name="domainapplication", name="approved_domain", field=models.OneToOneField( blank=True, help_text="The approved domain", null=True, on_delete=django.db.models.deletion.SET_NULL, - related_name="domain_request", + related_name="domain_application", to="registrar.domain", ), ), diff --git a/src/registrar/migrations/0041_alter_domainapplication_organization_type_and_more.py b/src/registrar/migrations/0041_alter_domainapplication_organization_type_and_more.py index 57201c1bf..07cfe0e77 100644 --- a/src/registrar/migrations/0041_alter_domainapplication_organization_type_and_more.py +++ b/src/registrar/migrations/0041_alter_domainapplication_organization_type_and_more.py @@ -10,7 +10,7 @@ class Migration(migrations.Migration): operations = [ migrations.AlterField( - model_name="DomainRequest", + model_name="domainapplication", name="organization_type", field=models.CharField( blank=True, diff --git a/src/registrar/migrations/0042_create_groups_v03.py b/src/registrar/migrations/0042_create_groups_v03.py index 2d23d870f..01b7985bf 100644 --- a/src/registrar/migrations/0042_create_groups_v03.py +++ b/src/registrar/migrations/0042_create_groups_v03.py @@ -25,7 +25,7 @@ def create_groups(apps, schema_editor) -> Any: class Migration(migrations.Migration): dependencies = [ - ("registrar", "0041_alter_DomainRequest_organization_type_and_more"), + ("registrar", "0041_alter_domainapplication_organization_type_and_more"), ] operations = [ diff --git a/src/registrar/migrations/0049_alter_domainapplication_current_websites_and_more.py b/src/registrar/migrations/0049_alter_domainapplication_current_websites_and_more.py index 49516deb7..4341bdad6 100644 --- a/src/registrar/migrations/0049_alter_domainapplication_current_websites_and_more.py +++ b/src/registrar/migrations/0049_alter_domainapplication_current_websites_and_more.py @@ -10,14 +10,14 @@ class Migration(migrations.Migration): operations = [ migrations.AlterField( - model_name="DomainRequest", + model_name="domainapplication", name="current_websites", field=models.ManyToManyField( blank=True, related_name="current+", to="registrar.website", verbose_name="websites" ), ), migrations.AlterField( - model_name="DomainRequest", + model_name="domainapplication", name="other_contacts", field=models.ManyToManyField( blank=True, related_name="contact_applications", to="registrar.contact", verbose_name="contacts" diff --git a/src/registrar/migrations/0050_alter_contact_middle_name_and_more.py b/src/registrar/migrations/0050_alter_contact_middle_name_and_more.py index 67ad4e1c6..4009d17d9 100644 --- a/src/registrar/migrations/0050_alter_contact_middle_name_and_more.py +++ b/src/registrar/migrations/0050_alter_contact_middle_name_and_more.py @@ -5,7 +5,7 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ("registrar", "0049_alter_DomainRequest_current_websites_and_more"), + ("registrar", "0049_alter_domainapplication_current_websites_and_more"), ] operations = [ @@ -15,7 +15,7 @@ class Migration(migrations.Migration): field=models.TextField(blank=True, help_text="Middle name (optional)", null=True), ), migrations.AlterField( - model_name="DomainRequest", + model_name="domainapplication", name="address_line2", field=models.TextField(blank=True, help_text="Street address line 2 (optional)", null=True), ), diff --git a/src/registrar/migrations/0051_alter_domainapplication_urbanization_and_more.py b/src/registrar/migrations/0051_alter_domainapplication_urbanization_and_more.py index 93865b021..9b012042d 100644 --- a/src/registrar/migrations/0051_alter_domainapplication_urbanization_and_more.py +++ b/src/registrar/migrations/0051_alter_domainapplication_urbanization_and_more.py @@ -10,7 +10,7 @@ class Migration(migrations.Migration): operations = [ migrations.AlterField( - model_name="DomainRequest", + model_name="domainapplication", name="urbanization", field=models.TextField(blank=True, help_text="Urbanization (required for Puerto Rico only)", null=True), ), diff --git a/src/registrar/migrations/0052_alter_domainapplication_anything_else_and_more.py b/src/registrar/migrations/0052_alter_domainapplication_anything_else_and_more.py index c4d8d8807..1d5607aad 100644 --- a/src/registrar/migrations/0052_alter_domainapplication_anything_else_and_more.py +++ b/src/registrar/migrations/0052_alter_domainapplication_anything_else_and_more.py @@ -5,12 +5,12 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ("registrar", "0051_alter_DomainRequest_urbanization_and_more"), + ("registrar", "0051_alter_domainapplication_urbanization_and_more"), ] operations = [ migrations.AlterField( - model_name="DomainRequest", + model_name="domainapplication", name="anything_else", field=models.TextField(blank=True, help_text="Anything else?", null=True), ), diff --git a/src/registrar/migrations/0053_create_groups_v05.py b/src/registrar/migrations/0053_create_groups_v05.py index 3df23d152..aaf74a9db 100644 --- a/src/registrar/migrations/0053_create_groups_v05.py +++ b/src/registrar/migrations/0053_create_groups_v05.py @@ -25,7 +25,7 @@ def create_groups(apps, schema_editor) -> Any: class Migration(migrations.Migration): dependencies = [ - ("registrar", "0052_alter_DomainRequest_anything_else_and_more"), + ("registrar", "0052_alter_domainapplication_anything_else_and_more"), ] operations = [ diff --git a/src/registrar/migrations/0054_alter_domainapplication_federal_agency_and_more.py b/src/registrar/migrations/0054_alter_domainapplication_federal_agency_and_more.py index 2f00c1958..d16c9befd 100644 --- a/src/registrar/migrations/0054_alter_domainapplication_federal_agency_and_more.py +++ b/src/registrar/migrations/0054_alter_domainapplication_federal_agency_and_more.py @@ -10,7 +10,7 @@ class Migration(migrations.Migration): operations = [ migrations.AlterField( - model_name="DomainRequest", + model_name="domainapplication", name="federal_agency", field=models.TextField( blank=True, @@ -317,7 +317,7 @@ class Migration(migrations.Migration): ), ), migrations.AlterField( - model_name="DomainRequest", + model_name="domainapplication", name="state_territory", field=models.CharField( blank=True, diff --git a/src/registrar/migrations/0055_transitiondomain_processed.py b/src/registrar/migrations/0055_transitiondomain_processed.py index 1261fb451..a2fb78edd 100644 --- a/src/registrar/migrations/0055_transitiondomain_processed.py +++ b/src/registrar/migrations/0055_transitiondomain_processed.py @@ -5,7 +5,7 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ("registrar", "0054_alter_DomainRequest_federal_agency_and_more"), + ("registrar", "0054_alter_domainapplication_federal_agency_and_more"), ] operations = [ diff --git a/src/registrar/migrations/0056_alter_domain_state_alter_domainapplication_status_and_more.py b/src/registrar/migrations/0056_alter_domain_state_alter_domainapplication_status_and_more.py index 7ee51b73e..097cddf8a 100644 --- a/src/registrar/migrations/0056_alter_domain_state_alter_domainapplication_status_and_more.py +++ b/src/registrar/migrations/0056_alter_domain_state_alter_domainapplication_status_and_more.py @@ -28,7 +28,7 @@ class Migration(migrations.Migration): ), ), migrations.AlterField( - model_name="DomainRequest", + model_name="domainapplication", name="status", field=django_fsm.FSMField( choices=[ diff --git a/src/registrar/migrations/0057_domainapplication_submission_date.py b/src/registrar/migrations/0057_domainapplication_submission_date.py index 7e914e8f1..a2a170888 100644 --- a/src/registrar/migrations/0057_domainapplication_submission_date.py +++ b/src/registrar/migrations/0057_domainapplication_submission_date.py @@ -5,12 +5,12 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ("registrar", "0056_alter_domain_state_alter_DomainRequest_status_and_more"), + ("registrar", "0056_alter_domain_state_alter_domainapplication_status_and_more"), ] operations = [ migrations.AddField( - model_name="DomainRequest", + model_name="domainapplication", name="submission_date", field=models.DateField(blank=True, default=None, help_text="Date submitted", null=True), ), diff --git a/src/registrar/migrations/0058_alter_domaininformation_options.py b/src/registrar/migrations/0058_alter_domaininformation_options.py index db6e7b24f..2e128cbda 100644 --- a/src/registrar/migrations/0058_alter_domaininformation_options.py +++ b/src/registrar/migrations/0058_alter_domaininformation_options.py @@ -5,7 +5,7 @@ from django.db import migrations class Migration(migrations.Migration): dependencies = [ - ("registrar", "0057_DomainRequest_submission_date"), + ("registrar", "0057_domainapplication_submission_date"), ] operations = [ diff --git a/src/registrar/migrations/0064_alter_domainapplication_address_line1_and_more.py b/src/registrar/migrations/0064_alter_domainapplication_address_line1_and_more.py index 238f084f3..7241c7164 100644 --- a/src/registrar/migrations/0064_alter_domainapplication_address_line1_and_more.py +++ b/src/registrar/migrations/0064_alter_domainapplication_address_line1_and_more.py @@ -10,12 +10,12 @@ class Migration(migrations.Migration): operations = [ migrations.AlterField( - model_name="DomainRequest", + model_name="domainapplication", name="address_line1", field=models.TextField(blank=True, help_text="Street address", null=True, verbose_name="Address line 1"), ), migrations.AlterField( - model_name="DomainRequest", + model_name="domainapplication", name="address_line2", field=models.TextField( blank=True, help_text="Street address line 2 (optional)", null=True, verbose_name="Address line 2" diff --git a/src/registrar/migrations/0065_create_groups_v06.py b/src/registrar/migrations/0065_create_groups_v06.py index aa943c174..d2cb32cee 100644 --- a/src/registrar/migrations/0065_create_groups_v06.py +++ b/src/registrar/migrations/0065_create_groups_v06.py @@ -25,7 +25,7 @@ def create_groups(apps, schema_editor) -> Any: class Migration(migrations.Migration): dependencies = [ - ("registrar", "0064_alter_DomainRequest_address_line1_and_more"), + ("registrar", "0064_alter_domainapplication_address_line1_and_more"), ] operations = [ diff --git a/src/registrar/migrations/0068_domainapplication_notes_domaininformation_notes.py b/src/registrar/migrations/0068_domainapplication_notes_domaininformation_notes.py index ddf3dc914..ea94be77e 100644 --- a/src/registrar/migrations/0068_domainapplication_notes_domaininformation_notes.py +++ b/src/registrar/migrations/0068_domainapplication_notes_domaininformation_notes.py @@ -10,7 +10,7 @@ class Migration(migrations.Migration): operations = [ migrations.AddField( - model_name="DomainRequest", + model_name="domainapplication", name="notes", field=models.TextField(blank=True, help_text="Notes about this request", null=True), ), diff --git a/src/registrar/migrations/0069_alter_contact_email_alter_contact_first_name_and_more.py b/src/registrar/migrations/0069_alter_contact_email_alter_contact_first_name_and_more.py index b6b546d67..5869e6fae 100644 --- a/src/registrar/migrations/0069_alter_contact_email_alter_contact_first_name_and_more.py +++ b/src/registrar/migrations/0069_alter_contact_email_alter_contact_first_name_and_more.py @@ -6,7 +6,7 @@ import phonenumber_field.modelfields class Migration(migrations.Migration): dependencies = [ - ("registrar", "0068_DomainRequest_notes_domaininformation_notes"), + ("registrar", "0068_domainapplication_notes_domaininformation_notes"), ] operations = [ diff --git a/src/registrar/migrations/0070_domainapplication_rejection_reason.py b/src/registrar/migrations/0070_domainapplication_rejection_reason.py index 4ce7aa83f..d559973e2 100644 --- a/src/registrar/migrations/0070_domainapplication_rejection_reason.py +++ b/src/registrar/migrations/0070_domainapplication_rejection_reason.py @@ -10,7 +10,7 @@ class Migration(migrations.Migration): operations = [ migrations.AddField( - model_name="DomainRequest", + model_name="domainapplication", name="rejection_reason", field=models.TextField( blank=True, diff --git a/src/registrar/migrations/0071_alter_contact_first_name_alter_contact_last_name_and_more.py b/src/registrar/migrations/0071_alter_contact_first_name_alter_contact_last_name_and_more.py index af28dbf56..bc594138e 100644 --- a/src/registrar/migrations/0071_alter_contact_first_name_alter_contact_last_name_and_more.py +++ b/src/registrar/migrations/0071_alter_contact_first_name_alter_contact_last_name_and_more.py @@ -7,7 +7,7 @@ import phonenumber_field.modelfields class Migration(migrations.Migration): dependencies = [ - ("registrar", "0070_DomainRequest_rejection_reason"), + ("registrar", "0070_domainapplication_rejection_reason"), ] operations = [ @@ -32,24 +32,24 @@ class Migration(migrations.Migration): field=models.CharField(blank=True, null=True, verbose_name="title or role in your organization"), ), migrations.AlterField( - model_name="DomainRequest", + model_name="domainapplication", name="address_line1", field=models.CharField(blank=True, help_text="Street address", null=True, verbose_name="Address line 1"), ), migrations.AlterField( - model_name="DomainRequest", + model_name="domainapplication", name="address_line2", field=models.CharField( blank=True, help_text="Street address line 2 (optional)", null=True, verbose_name="Address line 2" ), ), migrations.AlterField( - model_name="DomainRequest", + model_name="domainapplication", name="city", field=models.CharField(blank=True, help_text="City", null=True), ), migrations.AlterField( - model_name="DomainRequest", + model_name="domainapplication", name="federal_agency", field=models.CharField( blank=True, @@ -356,17 +356,17 @@ class Migration(migrations.Migration): ), ), migrations.AlterField( - model_name="DomainRequest", + model_name="domainapplication", name="organization_name", field=models.CharField(blank=True, db_index=True, help_text="Organization name", null=True), ), migrations.AlterField( - model_name="DomainRequest", + model_name="domainapplication", name="tribe_name", field=models.CharField(blank=True, help_text="Name of tribe", null=True), ), migrations.AlterField( - model_name="DomainRequest", + model_name="domainapplication", name="urbanization", field=models.CharField(blank=True, help_text="Urbanization (required for Puerto Rico only)", null=True), ), From d8fcc9f41a66b676c2f8eed0db90bc50a863052b Mon Sep 17 00:00:00 2001 From: CocoByte Date: Thu, 29 Feb 2024 20:53:37 -0700 Subject: [PATCH 043/103] Added Migration --- .../migrations/0072_domainrequest_and_more.py | 685 ++++++++++++++++++ 1 file changed, 685 insertions(+) create mode 100644 src/registrar/migrations/0072_domainrequest_and_more.py diff --git a/src/registrar/migrations/0072_domainrequest_and_more.py b/src/registrar/migrations/0072_domainrequest_and_more.py new file mode 100644 index 000000000..03d624834 --- /dev/null +++ b/src/registrar/migrations/0072_domainrequest_and_more.py @@ -0,0 +1,685 @@ +# Generated by Django 4.2.10 on 2024-03-01 03:52 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import django_fsm + + +class Migration(migrations.Migration): + + dependencies = [ + ("registrar", "0071_alter_contact_first_name_alter_contact_last_name_and_more"), + ] + + operations = [ + migrations.CreateModel( + name="DomainRequest", + fields=[ + ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ("created_at", models.DateTimeField(auto_now_add=True)), + ("updated_at", models.DateTimeField(auto_now=True)), + ( + "status", + django_fsm.FSMField( + choices=[ + ("started", "Started"), + ("submitted", "Submitted"), + ("in review", "In review"), + ("action needed", "Action needed"), + ("approved", "Approved"), + ("withdrawn", "Withdrawn"), + ("rejected", "Rejected"), + ("ineligible", "Ineligible"), + ], + default="started", + max_length=50, + ), + ), + ( + "rejection_reason", + models.TextField( + blank=True, + choices=[ + ("purpose_not_met", "Purpose requirements not met"), + ("requestor_not_eligible", "Requestor not eligible to make request"), + ("org_has_domain", "Org already has a .gov domain"), + ("contacts_not_verified", "Org contacts couldn't be verified"), + ("org_not_eligible", "Org not eligible for a .gov domain"), + ("naming_not_met", "Naming requirements not met"), + ("other", "Other/Unspecified"), + ], + null=True, + ), + ), + ( + "organization_type", + models.CharField( + blank=True, + choices=[ + ("federal", "Federal"), + ("interstate", "Interstate"), + ("state_or_territory", "State or territory"), + ("tribal", "Tribal"), + ("county", "County"), + ("city", "City"), + ("special_district", "Special district"), + ("school_district", "School district"), + ], + help_text="Type of organization", + max_length=255, + null=True, + ), + ), + ( + "federally_recognized_tribe", + models.BooleanField(help_text="Is the tribe federally recognized", null=True), + ), + ( + "state_recognized_tribe", + models.BooleanField(help_text="Is the tribe recognized by a state", null=True), + ), + ("tribe_name", models.CharField(blank=True, help_text="Name of tribe", null=True)), + ( + "federal_agency", + models.CharField( + blank=True, + choices=[ + ( + "Administrative Conference of the United States", + "Administrative Conference of the United States", + ), + ("Advisory Council on Historic Preservation", "Advisory Council on Historic Preservation"), + ("American Battle Monuments Commission", "American Battle Monuments Commission"), + ("AMTRAK", "AMTRAK"), + ("Appalachian Regional Commission", "Appalachian Regional Commission"), + ( + "Appraisal Subcommittee of the Federal Financial Institutions Examination Council", + "Appraisal Subcommittee of the Federal Financial Institutions Examination Council", + ), + ("Appraisal Subcommittee", "Appraisal Subcommittee"), + ("Architect of the Capitol", "Architect of the Capitol"), + ("Armed Forces Retirement Home", "Armed Forces Retirement Home"), + ( + "Barry Goldwater Scholarship and Excellence in Education Foundation", + "Barry Goldwater Scholarship and Excellence in Education Foundation", + ), + ( + "Barry Goldwater Scholarship and Excellence in Education Program", + "Barry Goldwater Scholarship and Excellence in Education Program", + ), + ("Central Intelligence Agency", "Central Intelligence Agency"), + ("Chemical Safety Board", "Chemical Safety Board"), + ( + "Christopher Columbus Fellowship Foundation", + "Christopher Columbus Fellowship Foundation", + ), + ( + "Civil Rights Cold Case Records Review Board", + "Civil Rights Cold Case Records Review Board", + ), + ( + "Commission for the Preservation of America's Heritage Abroad", + "Commission for the Preservation of America's Heritage Abroad", + ), + ("Commission of Fine Arts", "Commission of Fine Arts"), + ( + "Committee for Purchase From People Who Are Blind or Severely Disabled", + "Committee for Purchase From People Who Are Blind or Severely Disabled", + ), + ("Commodity Futures Trading Commission", "Commodity Futures Trading Commission"), + ("Congressional Budget Office", "Congressional Budget Office"), + ("Consumer Financial Protection Bureau", "Consumer Financial Protection Bureau"), + ("Consumer Product Safety Commission", "Consumer Product Safety Commission"), + ( + "Corporation for National & Community Service", + "Corporation for National & Community Service", + ), + ( + "Corporation for National and Community Service", + "Corporation for National and Community Service", + ), + ( + "Council of Inspectors General on Integrity and Efficiency", + "Council of Inspectors General on Integrity and Efficiency", + ), + ("Court Services and Offender Supervision", "Court Services and Offender Supervision"), + ("Cyberspace Solarium Commission", "Cyberspace Solarium Commission"), + ( + "DC Court Services and Offender Supervision Agency", + "DC Court Services and Offender Supervision Agency", + ), + ("DC Pre-trial Services", "DC Pre-trial Services"), + ("Defense Nuclear Facilities Safety Board", "Defense Nuclear Facilities Safety Board"), + ("Delta Regional Authority", "Delta Regional Authority"), + ("Denali Commission", "Denali Commission"), + ("Department of Agriculture", "Department of Agriculture"), + ("Department of Commerce", "Department of Commerce"), + ("Department of Defense", "Department of Defense"), + ("Department of Education", "Department of Education"), + ("Department of Energy", "Department of Energy"), + ("Department of Health and Human Services", "Department of Health and Human Services"), + ("Department of Homeland Security", "Department of Homeland Security"), + ( + "Department of Housing and Urban Development", + "Department of Housing and Urban Development", + ), + ("Department of Justice", "Department of Justice"), + ("Department of Labor", "Department of Labor"), + ("Department of State", "Department of State"), + ("Department of the Interior", "Department of the Interior"), + ("Department of the Treasury", "Department of the Treasury"), + ("Department of Transportation", "Department of Transportation"), + ("Department of Veterans Affairs", "Department of Veterans Affairs"), + ("Director of National Intelligence", "Director of National Intelligence"), + ("Dwight D. Eisenhower Memorial Commission", "Dwight D. Eisenhower Memorial Commission"), + ("Election Assistance Commission", "Election Assistance Commission"), + ("Environmental Protection Agency", "Environmental Protection Agency"), + ("Equal Employment Opportunity Commission", "Equal Employment Opportunity Commission"), + ("Executive Office of the President", "Executive Office of the President"), + ("Export-Import Bank of the United States", "Export-Import Bank of the United States"), + ("Export/Import Bank of the U.S.", "Export/Import Bank of the U.S."), + ("Farm Credit Administration", "Farm Credit Administration"), + ("Farm Credit System Insurance Corporation", "Farm Credit System Insurance Corporation"), + ("Federal Communications Commission", "Federal Communications Commission"), + ("Federal Deposit Insurance Corporation", "Federal Deposit Insurance Corporation"), + ("Federal Election Commission", "Federal Election Commission"), + ("Federal Energy Regulatory Commission", "Federal Energy Regulatory Commission"), + ( + "Federal Financial Institutions Examination Council", + "Federal Financial Institutions Examination Council", + ), + ("Federal Housing Finance Agency", "Federal Housing Finance Agency"), + ("Federal Judiciary", "Federal Judiciary"), + ("Federal Labor Relations Authority", "Federal Labor Relations Authority"), + ("Federal Maritime Commission", "Federal Maritime Commission"), + ( + "Federal Mediation and Conciliation Service", + "Federal Mediation and Conciliation Service", + ), + ( + "Federal Mine Safety and Health Review Commission", + "Federal Mine Safety and Health Review Commission", + ), + ( + "Federal Permitting Improvement Steering Council", + "Federal Permitting Improvement Steering Council", + ), + ("Federal Reserve Board of Governors", "Federal Reserve Board of Governors"), + ("Federal Reserve System", "Federal Reserve System"), + ("Federal Trade Commission", "Federal Trade Commission"), + ("General Services Administration", "General Services Administration"), + ("gov Administration", "gov Administration"), + ("Government Accountability Office", "Government Accountability Office"), + ("Government Publishing Office", "Government Publishing Office"), + ("Gulf Coast Ecosystem Restoration Council", "Gulf Coast Ecosystem Restoration Council"), + ("Harry S Truman Scholarship Foundation", "Harry S Truman Scholarship Foundation"), + ("Harry S. Truman Scholarship Foundation", "Harry S. Truman Scholarship Foundation"), + ("Institute of Museum and Library Services", "Institute of Museum and Library Services"), + ("Institute of Peace", "Institute of Peace"), + ("Inter-American Foundation", "Inter-American Foundation"), + ( + "International Boundary and Water Commission: United States and Mexico", + "International Boundary and Water Commission: United States and Mexico", + ), + ( + "International Boundary Commission: United States and Canada", + "International Boundary Commission: United States and Canada", + ), + ( + "International Joint Commission: United States and Canada", + "International Joint Commission: United States and Canada", + ), + ( + "James Madison Memorial Fellowship Foundation", + "James Madison Memorial Fellowship Foundation", + ), + ("Japan-United States Friendship Commission", "Japan-United States Friendship Commission"), + ("Japan-US Friendship Commission", "Japan-US Friendship Commission"), + ( + "John F. Kennedy Center for Performing Arts", + "John F. Kennedy Center for Performing Arts", + ), + ( + "John F. Kennedy Center for the Performing Arts", + "John F. Kennedy Center for the Performing Arts", + ), + ("Legal Services Corporation", "Legal Services Corporation"), + ("Legislative Branch", "Legislative Branch"), + ("Library of Congress", "Library of Congress"), + ("Marine Mammal Commission", "Marine Mammal Commission"), + ( + "Medicaid and CHIP Payment and Access Commission", + "Medicaid and CHIP Payment and Access Commission", + ), + ("Medical Payment Advisory Commission", "Medical Payment Advisory Commission"), + ("Medicare Payment Advisory Commission", "Medicare Payment Advisory Commission"), + ("Merit Systems Protection Board", "Merit Systems Protection Board"), + ("Millennium Challenge Corporation", "Millennium Challenge Corporation"), + ( + "Morris K. Udall and Stewart L. Udall Foundation", + "Morris K. Udall and Stewart L. Udall Foundation", + ), + ( + "National Aeronautics and Space Administration", + "National Aeronautics and Space Administration", + ), + ( + "National Archives and Records Administration", + "National Archives and Records Administration", + ), + ("National Capital Planning Commission", "National Capital Planning Commission"), + ("National Council on Disability", "National Council on Disability"), + ("National Credit Union Administration", "National Credit Union Administration"), + ("National Endowment for the Arts", "National Endowment for the Arts"), + ("National Endowment for the Humanities", "National Endowment for the Humanities"), + ( + "National Foundation on the Arts and the Humanities", + "National Foundation on the Arts and the Humanities", + ), + ("National Gallery of Art", "National Gallery of Art"), + ("National Indian Gaming Commission", "National Indian Gaming Commission"), + ("National Labor Relations Board", "National Labor Relations Board"), + ("National Mediation Board", "National Mediation Board"), + ("National Science Foundation", "National Science Foundation"), + ( + "National Security Commission on Artificial Intelligence", + "National Security Commission on Artificial Intelligence", + ), + ("National Transportation Safety Board", "National Transportation Safety Board"), + ( + "Networking Information Technology Research and Development", + "Networking Information Technology Research and Development", + ), + ("Non-Federal Agency", "Non-Federal Agency"), + ("Northern Border Regional Commission", "Northern Border Regional Commission"), + ("Nuclear Regulatory Commission", "Nuclear Regulatory Commission"), + ("Nuclear Safety Oversight Committee", "Nuclear Safety Oversight Committee"), + ("Nuclear Waste Technical Review Board", "Nuclear Waste Technical Review Board"), + ( + "Occupational Safety & Health Review Commission", + "Occupational Safety & Health Review Commission", + ), + ( + "Occupational Safety and Health Review Commission", + "Occupational Safety and Health Review Commission", + ), + ("Office of Compliance", "Office of Compliance"), + ("Office of Congressional Workplace Rights", "Office of Congressional Workplace Rights"), + ("Office of Government Ethics", "Office of Government Ethics"), + ( + "Office of Navajo and Hopi Indian Relocation", + "Office of Navajo and Hopi Indian Relocation", + ), + ("Office of Personnel Management", "Office of Personnel Management"), + ("Open World Leadership Center", "Open World Leadership Center"), + ("Overseas Private Investment Corporation", "Overseas Private Investment Corporation"), + ("Peace Corps", "Peace Corps"), + ("Pension Benefit Guaranty Corporation", "Pension Benefit Guaranty Corporation"), + ("Postal Regulatory Commission", "Postal Regulatory Commission"), + ("Presidio Trust", "Presidio Trust"), + ( + "Privacy and Civil Liberties Oversight Board", + "Privacy and Civil Liberties Oversight Board", + ), + ("Public Buildings Reform Board", "Public Buildings Reform Board"), + ( + "Public Defender Service for the District of Columbia", + "Public Defender Service for the District of Columbia", + ), + ("Railroad Retirement Board", "Railroad Retirement Board"), + ("Securities and Exchange Commission", "Securities and Exchange Commission"), + ("Selective Service System", "Selective Service System"), + ("Small Business Administration", "Small Business Administration"), + ("Smithsonian Institution", "Smithsonian Institution"), + ("Social Security Administration", "Social Security Administration"), + ("Social Security Advisory Board", "Social Security Advisory Board"), + ("Southeast Crescent Regional Commission", "Southeast Crescent Regional Commission"), + ("Southwest Border Regional Commission", "Southwest Border Regional Commission"), + ("State Justice Institute", "State Justice Institute"), + ("State, Local, and Tribal Government", "State, Local, and Tribal Government"), + ("Stennis Center for Public Service", "Stennis Center for Public Service"), + ("Surface Transportation Board", "Surface Transportation Board"), + ("Tennessee Valley Authority", "Tennessee Valley Authority"), + ("The Executive Office of the President", "The Executive Office of the President"), + ("The Intelligence Community", "The Intelligence Community"), + ("The Legislative Branch", "The Legislative Branch"), + ("The Supreme Court", "The Supreme Court"), + ( + "The United States World War One Centennial Commission", + "The United States World War One Centennial Commission", + ), + ("U.S. Access Board", "U.S. Access Board"), + ("U.S. Agency for Global Media", "U.S. Agency for Global Media"), + ("U.S. Agency for International Development", "U.S. Agency for International Development"), + ("U.S. Capitol Police", "U.S. Capitol Police"), + ("U.S. Chemical Safety Board", "U.S. Chemical Safety Board"), + ( + "U.S. China Economic and Security Review Commission", + "U.S. China Economic and Security Review Commission", + ), + ( + "U.S. Commission for the Preservation of Americas Heritage Abroad", + "U.S. Commission for the Preservation of Americas Heritage Abroad", + ), + ("U.S. Commission of Fine Arts", "U.S. Commission of Fine Arts"), + ("U.S. Commission on Civil Rights", "U.S. Commission on Civil Rights"), + ( + "U.S. Commission on International Religious Freedom", + "U.S. Commission on International Religious Freedom", + ), + ("U.S. Courts", "U.S. Courts"), + ("U.S. Department of Agriculture", "U.S. Department of Agriculture"), + ("U.S. Interagency Council on Homelessness", "U.S. Interagency Council on Homelessness"), + ("U.S. International Trade Commission", "U.S. International Trade Commission"), + ("U.S. Nuclear Waste Technical Review Board", "U.S. Nuclear Waste Technical Review Board"), + ("U.S. Office of Special Counsel", "U.S. Office of Special Counsel"), + ("U.S. Peace Corps", "U.S. Peace Corps"), + ("U.S. Postal Service", "U.S. Postal Service"), + ("U.S. Semiquincentennial Commission", "U.S. Semiquincentennial Commission"), + ("U.S. Trade and Development Agency", "U.S. Trade and Development Agency"), + ( + "U.S.-China Economic and Security Review Commission", + "U.S.-China Economic and Security Review Commission", + ), + ("Udall Foundation", "Udall Foundation"), + ("United States AbilityOne", "United States AbilityOne"), + ("United States Access Board", "United States Access Board"), + ( + "United States African Development Foundation", + "United States African Development Foundation", + ), + ("United States Agency for Global Media", "United States Agency for Global Media"), + ("United States Arctic Research Commission", "United States Arctic Research Commission"), + ( + "United States Global Change Research Program", + "United States Global Change Research Program", + ), + ("United States Holocaust Memorial Museum", "United States Holocaust Memorial Museum"), + ("United States Institute of Peace", "United States Institute of Peace"), + ( + "United States Interagency Council on Homelessness", + "United States Interagency Council on Homelessness", + ), + ( + "United States International Development Finance Corporation", + "United States International Development Finance Corporation", + ), + ( + "United States International Trade Commission", + "United States International Trade Commission", + ), + ("United States Postal Service", "United States Postal Service"), + ("United States Senate", "United States Senate"), + ( + "United States Trade and Development Agency", + "United States Trade and Development Agency", + ), + ( + "Utah Reclamation Mitigation and Conservation Commission", + "Utah Reclamation Mitigation and Conservation Commission", + ), + ("Vietnam Education Foundation", "Vietnam Education Foundation"), + ("Western Hemisphere Drug Policy Commission", "Western Hemisphere Drug Policy Commission"), + ( + "Woodrow Wilson International Center for Scholars", + "Woodrow Wilson International Center for Scholars", + ), + ("World War I Centennial Commission", "World War I Centennial Commission"), + ], + help_text="Federal agency", + null=True, + ), + ), + ( + "federal_type", + models.CharField( + blank=True, + choices=[("executive", "Executive"), ("judicial", "Judicial"), ("legislative", "Legislative")], + help_text="Federal government branch", + max_length=50, + null=True, + ), + ), + ( + "is_election_board", + models.BooleanField(blank=True, help_text="Is your organization an election office?", null=True), + ), + ( + "organization_name", + models.CharField(blank=True, db_index=True, help_text="Organization name", null=True), + ), + ( + "address_line1", + models.CharField(blank=True, help_text="Street address", null=True, verbose_name="Address line 1"), + ), + ( + "address_line2", + models.CharField( + blank=True, + help_text="Street address line 2 (optional)", + null=True, + verbose_name="Address line 2", + ), + ), + ("city", models.CharField(blank=True, help_text="City", null=True)), + ( + "state_territory", + models.CharField( + blank=True, + choices=[ + ("AL", "Alabama (AL)"), + ("AK", "Alaska (AK)"), + ("AS", "American Samoa (AS)"), + ("AZ", "Arizona (AZ)"), + ("AR", "Arkansas (AR)"), + ("CA", "California (CA)"), + ("CO", "Colorado (CO)"), + ("CT", "Connecticut (CT)"), + ("DE", "Delaware (DE)"), + ("DC", "District of Columbia (DC)"), + ("FL", "Florida (FL)"), + ("GA", "Georgia (GA)"), + ("GU", "Guam (GU)"), + ("HI", "Hawaii (HI)"), + ("ID", "Idaho (ID)"), + ("IL", "Illinois (IL)"), + ("IN", "Indiana (IN)"), + ("IA", "Iowa (IA)"), + ("KS", "Kansas (KS)"), + ("KY", "Kentucky (KY)"), + ("LA", "Louisiana (LA)"), + ("ME", "Maine (ME)"), + ("MD", "Maryland (MD)"), + ("MA", "Massachusetts (MA)"), + ("MI", "Michigan (MI)"), + ("MN", "Minnesota (MN)"), + ("MS", "Mississippi (MS)"), + ("MO", "Missouri (MO)"), + ("MT", "Montana (MT)"), + ("NE", "Nebraska (NE)"), + ("NV", "Nevada (NV)"), + ("NH", "New Hampshire (NH)"), + ("NJ", "New Jersey (NJ)"), + ("NM", "New Mexico (NM)"), + ("NY", "New York (NY)"), + ("NC", "North Carolina (NC)"), + ("ND", "North Dakota (ND)"), + ("MP", "Northern Mariana Islands (MP)"), + ("OH", "Ohio (OH)"), + ("OK", "Oklahoma (OK)"), + ("OR", "Oregon (OR)"), + ("PA", "Pennsylvania (PA)"), + ("PR", "Puerto Rico (PR)"), + ("RI", "Rhode Island (RI)"), + ("SC", "South Carolina (SC)"), + ("SD", "South Dakota (SD)"), + ("TN", "Tennessee (TN)"), + ("TX", "Texas (TX)"), + ("UM", "United States Minor Outlying Islands (UM)"), + ("UT", "Utah (UT)"), + ("VT", "Vermont (VT)"), + ("VI", "Virgin Islands (VI)"), + ("VA", "Virginia (VA)"), + ("WA", "Washington (WA)"), + ("WV", "West Virginia (WV)"), + ("WI", "Wisconsin (WI)"), + ("WY", "Wyoming (WY)"), + ("AA", "Armed Forces Americas (AA)"), + ("AE", "Armed Forces Africa, Canada, Europe, Middle East (AE)"), + ("AP", "Armed Forces Pacific (AP)"), + ], + help_text="State, territory, or military post", + max_length=2, + null=True, + ), + ), + ( + "zipcode", + models.CharField(blank=True, db_index=True, help_text="Zip code", max_length=10, null=True), + ), + ( + "urbanization", + models.CharField(blank=True, help_text="Urbanization (required for Puerto Rico only)", null=True), + ), + ( + "about_your_organization", + models.TextField(blank=True, help_text="Information about your organization", null=True), + ), + ("purpose", models.TextField(blank=True, help_text="Purpose of your domain", null=True)), + ( + "no_other_contacts_rationale", + models.TextField(blank=True, help_text="Reason for listing no additional contacts", null=True), + ), + ("anything_else", models.TextField(blank=True, help_text="Anything else?", null=True)), + ( + "is_policy_acknowledged", + models.BooleanField(blank=True, help_text="Acknowledged .gov acceptable use policy", null=True), + ), + ("submission_date", models.DateField(blank=True, default=None, help_text="Date submitted", null=True)), + ("notes", models.TextField(blank=True, help_text="Notes about this request", null=True)), + ( + "alternative_domains", + models.ManyToManyField(blank=True, related_name="alternatives+", to="registrar.website"), + ), + ( + "approved_domain", + models.OneToOneField( + blank=True, + help_text="The approved domain", + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="domain_request", + to="registrar.domain", + ), + ), + ( + "authorizing_official", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name="authorizing_official", + to="registrar.contact", + ), + ), + ( + "creator", + models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + related_name="domain_requests_created", + to=settings.AUTH_USER_MODEL, + ), + ), + ( + "current_websites", + models.ManyToManyField( + blank=True, related_name="current+", to="registrar.website", verbose_name="websites" + ), + ), + ( + "investigator", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="domain_requests_investigating", + to=settings.AUTH_USER_MODEL, + ), + ), + ( + "other_contacts", + models.ManyToManyField( + blank=True, + related_name="contact_domain_requests", + to="registrar.contact", + verbose_name="contacts", + ), + ), + ( + "requested_domain", + models.OneToOneField( + blank=True, + help_text="The requested domain", + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name="domain_request", + to="registrar.draftdomain", + ), + ), + ( + "submitter", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name="submitted_domain_requests", + to="registrar.contact", + ), + ), + ], + options={ + "abstract": False, + }, + ), + migrations.RemoveField( + model_name="domaininformation", + name="domain_application", + ), + migrations.AlterField( + model_name="domaininformation", + name="other_contacts", + field=models.ManyToManyField( + blank=True, + related_name="contact_domain_requests_information", + to="registrar.contact", + verbose_name="contacts", + ), + ), + migrations.AlterField( + model_name="domaininformation", + name="submitter", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name="submitted_domain_requests_information", + to="registrar.contact", + ), + ), + migrations.DeleteModel( + name="DomainApplication", + ), + migrations.AddField( + model_name="domaininformation", + name="domain_request", + field=models.OneToOneField( + blank=True, + help_text="Associated domain request", + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name="DomainRequest_info", + to="registrar.domainrequest", + ), + ), + ] From 74f203448771cfbda77afce2279bd9f9b704a195 Mon Sep 17 00:00:00 2001 From: Rebecca Hsieh Date: Thu, 29 Feb 2024 22:17:48 -0800 Subject: [PATCH 044/103] Email business logic --- .../runbooks/update_python_dependencies.md | 6 +- .../generate_current_metadata_report.py | 20 ++-- src/registrar/utility/email.py | 110 ++++++++---------- 3 files changed, 64 insertions(+), 72 deletions(-) diff --git a/docs/operations/runbooks/update_python_dependencies.md b/docs/operations/runbooks/update_python_dependencies.md index 04fb936c6..468270d09 100644 --- a/docs/operations/runbooks/update_python_dependencies.md +++ b/docs/operations/runbooks/update_python_dependencies.md @@ -3,7 +3,7 @@ 1. Check the [Pipfile](../../../src/Pipfile) for pinned dependencies and manually adjust the version numbers 2. Run `docker-compose stop` to spin down the current containers and images so we can start afresh -2. Run +3. Run cd src docker-compose run app bash -c "pipenv lock && pipenv requirements > requirements.txt" @@ -13,9 +13,9 @@ It is necessary to use `bash -c` because `run pipenv requirements` will not recognize that it is running non-interactively and will include garbage formatting characters. The requirements.txt is used by Cloud.gov. It is needed to work around a bug in the CloudFoundry buildpack version of Pipenv that breaks on installing from a git repository. -3. Change geventconnpool back to what it was originally within the Pipfile.lock and requirements.txt. +4. Change geventconnpool back to what it was originally within the Pipfile.lock and requirements.txt. This is done by either saving what it was originally or opening a PR and using that as a reference to undo changes to any mention of geventconnpool. Geventconnpool, when set as a requirement without the reference portion, is defaulting to get a commit from 2014 which then breaks the code, as we want the newest version from them. -4. Run `docker-compose build` to build a new image for local development with the updated dependencies. +5. Run `docker-compose build` to build a new image for local development with the updated dependencies. The reason for de-coupling the `build` and `lock` steps is to increase consistency between builds--a run of `build` will always get exactly the dependencies listed in `Pipfile.lock`, nothing more, nothing less. \ No newline at end of file diff --git a/src/registrar/management/commands/generate_current_metadata_report.py b/src/registrar/management/commands/generate_current_metadata_report.py index a27199cdb..1a33c2791 100644 --- a/src/registrar/management/commands/generate_current_metadata_report.py +++ b/src/registrar/management/commands/generate_current_metadata_report.py @@ -71,17 +71,23 @@ class Command(BaseCommand): # Secret is encrypted into getgov-credentials # TODO: Update secret in getgov-credentials via cloud.gov and my own .env when ready - # encrypted_metadata is the encrypted output + # Encrypt the metadata + # TODO: UPDATE SECRET_ENCRYPT_METADATA pw getgov-credentials on stable encrypted_metadata = self._encrypt_metadata(s3_client.get_file(file_name), encrypted_metadata_output, str.encode(settings.SECRET_ENCRYPT_METADATA)) print("encrypted_metadata is:", encrypted_metadata) - + print("the type is: ", type(encrypted_metadata)) # Send the metadata file that is zipped - # Q: Would we set the vars I set in email.py here to pass in to the helper function or best way to invoke - # send_templated_email(encrypted_metadata, attachment=True) - + # TODO: Make new .txt files + send_templated_email( + "emails/metadata_body.txt", + "emails/metadata_subject.txt", + to_address="rebecca.hsieh@truss.works", # TODO: Update to settings.DEFAULT_FROM_EMAIL once tested + file=encrypted_metadata, + ) + def _encrypt_metadata(self, input_file, output_file, password): - # Using ZIP_DEFLATED bc it's a more common compression method supported by most zip utilities - # Could also use compression=pyzipper.ZIP_LZMA? + # Using ZIP_DEFLATED bc it's a more common compression method supported by most zip utilities and faster + # We could also use compression=pyzipper.ZIP_LZMA if we are looking for smaller file size with pyzipper.AESZipFile(output_file, 'w', compression=pyzipper.ZIP_DEFLATED, encryption=pyzipper.WZ_AES) as f_out: f_out.setpassword(password) f_out.writestr('encrypted_metadata.txt', input_file) diff --git a/src/registrar/utility/email.py b/src/registrar/utility/email.py index 199a6c304..5f3e42eb5 100644 --- a/src/registrar/utility/email.py +++ b/src/registrar/utility/email.py @@ -4,6 +4,10 @@ import boto3 import logging from django.conf import settings from django.template.loader import get_template +from email.mime.base import MIMEBase +from email.mime.application import MIMEApplication +from email.mime.multipart import MIMEMultipart +from email.mime.text import MIMEText logger = logging.getLogger(__name__) @@ -15,7 +19,7 @@ class EmailSendingError(RuntimeError): pass -def send_templated_email(template_name: str, subject_template_name: str, to_address: str, context={}): +def send_templated_email(template_name: str, subject_template_name: str, to_address: str, context={}, file: str=None): """Send an email built from a template to one email address. template_name and subject_template_name are relative to the same template @@ -40,74 +44,56 @@ def send_templated_email(template_name: str, subject_template_name: str, to_addr except Exception as exc: raise EmailSendingError("Could not access the SES client.") from exc - # Are we okay with passing in "attachment" var in as boolean parameter - # If so, TODO: add attachment boolean to other functions try: - #if not attachment: - ses_client.send_email( - FromEmailAddress=settings.DEFAULT_FROM_EMAIL, - Destination={"ToAddresses": [to_address]}, - Content={ - "Simple": { - "Subject": {"Data": subject}, - "Body": {"Text": {"Data": email_body}}, + if file is None: + ses_client.send_email( + FromEmailAddress=settings.DEFAULT_FROM_EMAIL, + Destination={"ToAddresses": [to_address]}, + Content={ + "Simple": { + "Subject": {"Data": subject}, + "Body": {"Text": {"Data": email_body}}, + }, }, - }, - ) - # else: # has attachment - # same as above but figure out how to attach a file - # via boto3 "boto3 SES file attachment" - # we also want this to only send to the help email - - # from email.mime.multipart import MIMEMultipart - # from email.mime.text import MIMEText - # from email.mime.application import MIMEApplication + ) + if file is not None: + # TODO: Update sender email when we figure out + ses_client = boto3.client( + "ses", + region_name=settings.AWS_REGION, + aws_access_key_id=settings.AWS_ACCESS_KEY_ID, + aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY, + config=settings.BOTO_CONFIG, + ) - # sender_email = 'sender@example.com' - # recipient_email = 'help@get.gov' - # subject = 'DOTGOV-Full Domain Metadata' - # body = 'Domain metadata email, should have an attachment included change here later.' - # attachment_path = 'path/to/attachment/file.pdf' - # aws_region = 'sesv2' - - # response = send_email_with_attachment(sender_email, recipient_email, subject, body, attachment_path, aws_region) - # print(response) + #TODO: Update sender to settings.DEFAULT_FROM_EMAIL + response = send_email_with_attachment(settings.DEFAULT_FROM_EMAIL, to_address, subject, email_body, file, ses_client) + print("Response from send_email_with_attachment_is:", response) except Exception as exc: raise EmailSendingError("Could not send SES email.") from exc +def send_email_with_attachment(sender, recipient, subject, body, attachment_file, ses_client): + # Create a multipart/mixed parent container + msg = MIMEMultipart('mixed') + msg['Subject'] = subject + msg['From'] = sender + msg['To'] = recipient -# def send_email_with_attachment(sender, recipient, subject, body, attachment_path, aws_region): - # # Create a multipart/mixed parent container - # msg = MIMEMultipart('mixed') - # msg['Subject'] = subject - # msg['From'] = sender_email - # msg['To'] = recipient_email + # Add the text part + text_part = MIMEText(body, 'plain') + msg.attach(text_part) - # # Add the text part - # text_part = MIMEText(body, 'plain') - # msg.attach(text_part) + # Add the attachment part - # # Add the attachment part - # with open(attachment_path, 'rb') as attachment_file: - # attachment_data = attachment_file.read() - # attachment_part = MIMEApplication(attachment_data) - # attachment_part.add_header('Content-Disposition', f'attachment; filename="{attachment_path}"') - # msg.attach(attachment_part) + # set it into this "type" + attachment_part = MIMEApplication(attachment_file) + # Adding attachment header + filename that the attachment will be called + attachment_part.add_header('Content-Disposition', f'attachment; filename="encrypted_metadata.zip"') + msg.attach(attachment_part) - # # Send the email - # response = ses_client.send_raw_email( - # Source=sender, - # Destinations=[recipient], - # RawMessage={'Data': msg.as_string()} - # ) - - # ses_client.send_email( - # FromEmailAddress=settings.DEFAULT_FROM_EMAIL, - # Destination={"ToAddresses": [to_address]}, - # Content={ - # "Simple": { - # "Subject": {"Data": subject}, - # "Body": {"Text": {"Data": email_body}}, - # }, - # }, - # ) \ No newline at end of file + response = ses_client.send_raw_email( + Source=sender, + Destinations=[recipient], + RawMessage={"Data": msg.as_string()} + ) + return response From 912169377431c5f07bf9b9e924a31c96794ed685 Mon Sep 17 00:00:00 2001 From: CocoByte Date: Fri, 1 Mar 2024 11:39:14 -0700 Subject: [PATCH 045/103] Fixing broken urls & missed file re-namings --- .../templates/domain_request_form.html | 2 +- .../templates/domain_request_review.html | 28 +++++++++---------- .../templates/domain_request_sidebar.html | 2 +- ...summary.txt => domain_request_summary.txt} | 0 ...n_application.html => domain_request.html} | 0 src/registrar/views/domain_request.py | 2 +- 6 files changed, 17 insertions(+), 17 deletions(-) rename src/registrar/templates/emails/includes/{application_summary.txt => domain_request_summary.txt} (100%) rename src/registrar/templates/includes/{domain_application.html => domain_request.html} (100%) diff --git a/src/registrar/templates/domain_request_form.html b/src/registrar/templates/domain_request_form.html index db436aeb3..cde12ad80 100644 --- a/src/registrar/templates/domain_request_form.html +++ b/src/registrar/templates/domain_request_form.html @@ -11,7 +11,7 @@
{% if steps.prev %} - + Previous step diff --git a/src/registrar/templates/domain_request_review.html b/src/registrar/templates/domain_request_review.html index d7dab21f8..71aec8d0a 100644 --- a/src/registrar/templates/domain_request_review.html +++ b/src/registrar/templates/domain_request_review.html @@ -23,7 +23,7 @@
{% if step == Step.ORGANIZATION_TYPE %} - {% namespaced_url 'domain_request' step as domain_request_url %} + {% namespaced_url 'domain-request' step as domain_request_url %} {% if domain_request.organization_type is not None %} {% with title=form_titles|get_item:step value=domain_request.get_organization_type_display|default:"Incomplete" %} {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=domain_request_url %} @@ -36,7 +36,7 @@ {% endif %} {% if step == Step.TRIBAL_GOVERNMENT %} - {% namespaced_url 'domain_request' step as domain_request_url %} + {% namespaced_url 'domain-request' step as domain_request_url %} {% with title=form_titles|get_item:step value=domain_request.tribe_name|default:"Incomplete" %} {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=domain_request_url %} {% endwith %} @@ -46,21 +46,21 @@ {% if step == Step.ORGANIZATION_FEDERAL %} - {% namespaced_url 'domain_request' step as domain_request_url %} + {% namespaced_url 'domain-request' step as domain_request_url %} {% with title=form_titles|get_item:step value=domain_request.get_federal_type_display|default:"Incomplete" %} {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=domain_request_url %} {% endwith %} {% endif %} {% if step == Step.ORGANIZATION_ELECTION %} - {% namespaced_url 'domain_request' step as domain_request_url %} + {% namespaced_url 'domain-request' step as domain_request_url %} {% with title=form_titles|get_item:step value=domain_request.is_election_board|yesno:"Yes,No,Incomplete" %} {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=domain_request_url %} {% endwith %} {% endif %} {% if step == Step.ORGANIZATION_CONTACT %} - {% namespaced_url 'domain_request' step as domain_request_url %} + {% namespaced_url 'domain-request' step as domain_request_url %} {% if domain_request.organization_name %} {% with title=form_titles|get_item:step value=domain_request %} {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=domain_request_url address='true' %} @@ -73,14 +73,14 @@ {% endif %} {% if step == Step.ABOUT_YOUR_ORGANIZATION %} - {% namespaced_url 'domain_request' step as domain_request_url %} + {% namespaced_url 'domain-request' step as domain_request_url %} {% with title=form_titles|get_item:step value=domain_request.about_your_organization|default:"Incomplete" %} {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=domain_request_url %} {% endwith %} {% endif %} {% if step == Step.AUTHORIZING_OFFICIAL %} - {% namespaced_url 'domain_request' step as domain_request_url %} + {% namespaced_url 'domain-request' step as domain_request_url %} {% if domain_request.authorizing_official is not None %} {% with title=form_titles|get_item:step value=domain_request.authorizing_official %} {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=domain_request_url contact='true' %} @@ -93,7 +93,7 @@ {% endif %} {% if step == Step.CURRENT_SITES %} - {% namespaced_url 'domain_request' step as domain_request_url %} + {% namespaced_url 'domain-request' step as domain_request_url %} {% if domain_request.current_websites.all %} {% with title=form_titles|get_item:step value=domain_request.current_websites.all %} {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=domain_request_url list='true' %} @@ -106,7 +106,7 @@ {% endif %} {% if step == Step.DOTGOV_DOMAIN %} - {% namespaced_url 'domain_request' step as domain_request_url %} + {% namespaced_url 'domain-request' step as domain_request_url %} {% with title=form_titles|get_item:step value=domain_request.requested_domain.name|default:"Incomplete" %} {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=domain_request_url %} {% endwith %} @@ -122,14 +122,14 @@ {% endif %} {% if step == Step.PURPOSE %} - {% namespaced_url 'domain_request' step as domain_request_url %} + {% namespaced_url 'domain-request' step as domain_request_url %} {% with title=form_titles|get_item:step value=domain_request.purpose|default:"Incomplete" %} {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=domain_request_url %} {% endwith %} {% endif %} {% if step == Step.YOUR_CONTACT %} - {% namespaced_url 'domain_request' step as domain_request_url %} + {% namespaced_url 'domain-request' step as domain_request_url %} {% if domain_request.submitter is not None %} {% with title=form_titles|get_item:step value=domain_request.submitter %} {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=domain_request_url contact='true' %} @@ -142,7 +142,7 @@ {% endif %} {% if step == Step.OTHER_CONTACTS %} - {% namespaced_url 'domain_request' step as domain_request_url %} + {% namespaced_url 'domain-request' step as domain_request_url %} {% if domain_request.other_contacts.all %} {% with title=form_titles|get_item:step value=domain_request.other_contacts.all %} {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=domain_request_url contact='true' list='true' %} @@ -156,7 +156,7 @@ {% if step == Step.ANYTHING_ELSE %} - {% namespaced_url 'domain_request' step as domain_request_url %} + {% namespaced_url 'domain-request' step as domain_request_url %} {% with title=form_titles|get_item:step value=domain_request.anything_else|default:"No" %} {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=domain_request_url %} {% endwith %} @@ -164,7 +164,7 @@ {% if step == Step.REQUIREMENTS %} - {% namespaced_url 'domain_request' step as domain_request_url %} + {% namespaced_url 'domain-request' step as domain_request_url %} {% with title=form_titles|get_item:step value=domain_request.is_policy_acknowledged|yesno:"I agree.,I do not agree.,I do not agree." %} {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=domain_request_url %} {% endwith %} diff --git a/src/registrar/templates/domain_request_sidebar.html b/src/registrar/templates/domain_request_sidebar.html index d18864c2e..f9ca5397d 100644 --- a/src/registrar/templates/domain_request_sidebar.html +++ b/src/registrar/templates/domain_request_sidebar.html @@ -15,7 +15,7 @@ {% endif %} {% endif %} - /edit EDIT_URL_NAME = "edit-domain-request" NEW_URL_NAME = "/request/" From a0fba816c237d25224735ec89cd0763b5c07a6b7 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 1 Mar 2024 13:31:01 -0700 Subject: [PATCH 046/103] PR suggestions --- src/registrar/assets/sass/_theme/_admin.scss | 5 ----- src/registrar/utility/errors.py | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/registrar/assets/sass/_theme/_admin.scss b/src/registrar/assets/sass/_theme/_admin.scss index b57c6a015..7f332efd2 100644 --- a/src/registrar/assets/sass/_theme/_admin.scss +++ b/src/registrar/assets/sass/_theme/_admin.scss @@ -275,11 +275,6 @@ h1, h2, h3, } } -// Hides the "clear" button on autocomplete, as we already have one to use -.select2-selection__clear { - display: none; -} - // Fixes a display issue where the list was entirely white, or had too much whitespace .select2-dropdown { display: inline-grid !important; diff --git a/src/registrar/utility/errors.py b/src/registrar/utility/errors.py index f5804ac2f..00c65ce57 100644 --- a/src/registrar/utility/errors.py +++ b/src/registrar/utility/errors.py @@ -94,7 +94,7 @@ class FSMApplicationError(Exception): _error_mapping = { FSMErrorCodes.APPROVE_DOMAIN_IN_USE: ("Cannot approve. Requested domain is already in use."), - FSMErrorCodes.NO_INVESTIGATOR: ("No investigator was assigned."), + FSMErrorCodes.NO_INVESTIGATOR: ("Investigator is required for this status."), FSMErrorCodes.INVESTIGATOR_NOT_STAFF: ("Investigator is not a staff user."), FSMErrorCodes.INVESTIGATOR_NOT_SUBMITTER: ("Only the assigned investigator can make this change."), } From f042bb72f55b99204011cf5ac5a2c4028ac1414e Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 1 Mar 2024 15:01:21 -0700 Subject: [PATCH 047/103] Remove check for only status changes --- src/registrar/admin.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index 6dc6cd94d..0d9045920 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -134,9 +134,6 @@ class DomainApplicationAdminForm(forms.ModelForm): status = cleaned_data.get("status") investigator = cleaned_data.get("investigator") - # Get the old status - initial_status = self.initial.get("status", None) - # We only care about investigator when in these statuses checked_statuses = [ DomainApplication.ApplicationStatus.APPROVED, @@ -147,7 +144,7 @@ class DomainApplicationAdminForm(forms.ModelForm): ] # If a status change occured, check for validity - if status != initial_status and status in checked_statuses: + if status in checked_statuses: # Checks the "investigators" field for validity. # That field must obey certain conditions when an application is approved. # Will call "add_error" if any issues are found. From e420c406a3f7859378d06efa3417ed1786fec486 Mon Sep 17 00:00:00 2001 From: CocoByte Date: Fri, 1 Mar 2024 15:22:15 -0700 Subject: [PATCH 048/103] minor changes --- src/registrar/models/domain_request.py | 2 +- src/registrar/tests/common.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/registrar/models/domain_request.py b/src/registrar/models/domain_request.py index 417713197..5283ce0e3 100644 --- a/src/registrar/models/domain_request.py +++ b/src/registrar/models/domain_request.py @@ -907,7 +907,7 @@ class DomainRequest(TimeStampedModel): def has_rationale(self) -> bool: """Does this domain request have no_other_contacts_rationale?""" return bool(self.no_other_contacts_rationale) - +1 def has_other_contacts(self) -> bool: """Does this domain request have other contacts listed?""" return self.other_contacts.exists() diff --git a/src/registrar/tests/common.py b/src/registrar/tests/common.py index 3993af8f3..42f882c39 100644 --- a/src/registrar/tests/common.py +++ b/src/registrar/tests/common.py @@ -405,11 +405,11 @@ class AuditedAdminMockData: status=status, ) case self.INFORMATION: - domain_app = self.create_full_dummy_domain_request(item_name) + domain_req = self.create_full_dummy_domain_request(item_name) full_arg_dict = dict( **common_args, domain=self.dummy_domain(item_name, True), - domain_request=domain_app, + domain_request=domain_req, ) case self.INVITATION: full_arg_dict = dict( From f427076598e42c27b9f4bb65fb9b6181dbb88f60 Mon Sep 17 00:00:00 2001 From: Rebecca Hsieh Date: Mon, 4 Mar 2024 16:45:05 -0800 Subject: [PATCH 049/103] Fix emailing functionality and update subject and body and file names --- .../generate_current_metadata_report.py | 59 +++++++++++-------- .../templates/emails/metadata_body.txt | 1 + .../templates/emails/metadata_subject.txt | 2 + src/registrar/utility/email.py | 37 ++++++------ 4 files changed, 55 insertions(+), 44 deletions(-) create mode 100644 src/registrar/templates/emails/metadata_body.txt create mode 100644 src/registrar/templates/emails/metadata_subject.txt diff --git a/src/registrar/management/commands/generate_current_metadata_report.py b/src/registrar/management/commands/generate_current_metadata_report.py index 1a33c2791..023a19f10 100644 --- a/src/registrar/management/commands/generate_current_metadata_report.py +++ b/src/registrar/management/commands/generate_current_metadata_report.py @@ -4,6 +4,8 @@ import logging import os import pyzipper +from datetime import datetime + from django.core.management import BaseCommand from django.conf import settings from registrar.utility import csv_export @@ -13,9 +15,11 @@ from ...utility.email import send_templated_email, EmailSendingError logger = logging.getLogger(__name__) + class Command(BaseCommand): help = ( - "Generates and uploads a current-metadata.csv file to our S3 bucket " "which is based off of all existing Domains." + "Generates and uploads a current-metadata.csv file to our S3 bucket " + "which is based off of all existing Domains." ) def add_arguments(self, parser): @@ -26,7 +30,7 @@ class Command(BaseCommand): default=True, help="Flag that determines if we do a check for os.path.exists. Used for test cases", ) - + def handle(self, **options): """Grabs the directory then creates current-metadata.csv in that directory""" file_name = "current-metadata.csv" @@ -58,38 +62,43 @@ class Command(BaseCommand): # Upload this generated file for our S3 instance s3_client.upload_file(file_path, file_name) - """ - We want to make sure to upload to s3 for back up - And now we also want to get the file and encrypt it so we can send it in an email - """ - # Encrypt metadata into a zip file + # Set zip file name + current_date = datetime.now().strftime("%m%d%Y") + current_filename = f"domain-metadata-{current_date}.zip" + # Pre-set zip file name + encrypted_metadata_output = current_filename - # pre-setting zip file name - encrypted_metadata_output = 'encrypted_metadata.zip' + # Set context for the subject + current_date_str = datetime.now().strftime("%Y-%m-%d") - # Secret is encrypted into getgov-credentials # TODO: Update secret in getgov-credentials via cloud.gov and my own .env when ready - - # Encrypt the metadata - # TODO: UPDATE SECRET_ENCRYPT_METADATA pw getgov-credentials on stable - encrypted_metadata = self._encrypt_metadata(s3_client.get_file(file_name), encrypted_metadata_output, str.encode(settings.SECRET_ENCRYPT_METADATA)) - print("encrypted_metadata is:", encrypted_metadata) - print("the type is: ", type(encrypted_metadata)) + + # Encrypt the metadata + encrypted_metadata_in_bytes = self._encrypt_metadata( + s3_client.get_file(file_name), encrypted_metadata_output, str.encode(settings.SECRET_ENCRYPT_METADATA) + ) + # Send the metadata file that is zipped - # TODO: Make new .txt files send_templated_email( - "emails/metadata_body.txt", - "emails/metadata_subject.txt", - to_address="rebecca.hsieh@truss.works", # TODO: Update to settings.DEFAULT_FROM_EMAIL once tested - file=encrypted_metadata, + template_name="emails/metadata_body.txt", + subject_template_name="emails/metadata_subject.txt", + to_address=settings.DEFAULT_FROM_EMAIL, + # to_address="rebecca.hsieh@truss.works ", # TODO: Update to settings.DEFAULT_FROM_EMAIL once tested + context={"current_date_str": current_date_str}, + file=encrypted_metadata_in_bytes, ) def _encrypt_metadata(self, input_file, output_file, password): + current_date = datetime.now().strftime("%m%d%Y") + current_filename = f"domain-metadata-{current_date}.txt" # Using ZIP_DEFLATED bc it's a more common compression method supported by most zip utilities and faster # We could also use compression=pyzipper.ZIP_LZMA if we are looking for smaller file size - with pyzipper.AESZipFile(output_file, 'w', compression=pyzipper.ZIP_DEFLATED, encryption=pyzipper.WZ_AES) as f_out: + with pyzipper.AESZipFile( + output_file, "w", compression=pyzipper.ZIP_DEFLATED, encryption=pyzipper.WZ_AES + ) as f_out: f_out.setpassword(password) - f_out.writestr('encrypted_metadata.txt', input_file) - return output_file - + f_out.writestr(current_filename, input_file) + with open(output_file, "rb") as file_data: + attachment_in_bytes = file_data.read() + return attachment_in_bytes diff --git a/src/registrar/templates/emails/metadata_body.txt b/src/registrar/templates/emails/metadata_body.txt new file mode 100644 index 000000000..adf0a186c --- /dev/null +++ b/src/registrar/templates/emails/metadata_body.txt @@ -0,0 +1 @@ +An export of all .gov metadata. diff --git a/src/registrar/templates/emails/metadata_subject.txt b/src/registrar/templates/emails/metadata_subject.txt new file mode 100644 index 000000000..5fdece7ef --- /dev/null +++ b/src/registrar/templates/emails/metadata_subject.txt @@ -0,0 +1,2 @@ +Domain metadata - {{current_date_str}} + diff --git a/src/registrar/utility/email.py b/src/registrar/utility/email.py index 5f3e42eb5..a81a41716 100644 --- a/src/registrar/utility/email.py +++ b/src/registrar/utility/email.py @@ -2,6 +2,7 @@ import boto3 import logging +from datetime import datetime from django.conf import settings from django.template.loader import get_template from email.mime.base import MIMEBase @@ -19,7 +20,7 @@ class EmailSendingError(RuntimeError): pass -def send_templated_email(template_name: str, subject_template_name: str, to_address: str, context={}, file: str=None): +def send_templated_email(template_name: str, subject_template_name: str, to_address: str, context={}, file: str = None): """Send an email built from a template to one email address. template_name and subject_template_name are relative to the same template @@ -56,8 +57,7 @@ def send_templated_email(template_name: str, subject_template_name: str, to_addr }, }, ) - if file is not None: - # TODO: Update sender email when we figure out + else: ses_client = boto3.client( "ses", region_name=settings.AWS_REGION, @@ -65,35 +65,34 @@ def send_templated_email(template_name: str, subject_template_name: str, to_addr aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY, config=settings.BOTO_CONFIG, ) - - #TODO: Update sender to settings.DEFAULT_FROM_EMAIL - response = send_email_with_attachment(settings.DEFAULT_FROM_EMAIL, to_address, subject, email_body, file, ses_client) + # Define the subject line with the current date + response = send_email_with_attachment( + settings.DEFAULT_FROM_EMAIL, to_address, subject, email_body, file, ses_client + ) + # TODO: Remove this print statement print("Response from send_email_with_attachment_is:", response) except Exception as exc: raise EmailSendingError("Could not send SES email.") from exc + def send_email_with_attachment(sender, recipient, subject, body, attachment_file, ses_client): # Create a multipart/mixed parent container - msg = MIMEMultipart('mixed') - msg['Subject'] = subject - msg['From'] = sender - msg['To'] = recipient + msg = MIMEMultipart("mixed") + msg["Subject"] = subject + msg["From"] = sender + msg["To"] = recipient # Add the text part - text_part = MIMEText(body, 'plain') + text_part = MIMEText(body, "plain") msg.attach(text_part) # Add the attachment part - - # set it into this "type" attachment_part = MIMEApplication(attachment_file) # Adding attachment header + filename that the attachment will be called - attachment_part.add_header('Content-Disposition', f'attachment; filename="encrypted_metadata.zip"') + current_date = datetime.now().strftime("%m%d%Y") + current_filename = f"domain-metadata-{current_date}.zip" + attachment_part.add_header("Content-Disposition", f'attachment; filename="{current_filename}"') msg.attach(attachment_part) - response = ses_client.send_raw_email( - Source=sender, - Destinations=[recipient], - RawMessage={"Data": msg.as_string()} - ) + response = ses_client.send_raw_email(Source=sender, Destinations=[recipient], RawMessage={"Data": msg.as_string()}) return response From f28705daff7e3d83ebf540b72aa05aff981544ca Mon Sep 17 00:00:00 2001 From: CocoByte Date: Mon, 4 Mar 2024 19:31:25 -0700 Subject: [PATCH 050/103] another fix... --- src/registrar/models/domain_request.py | 2 +- src/registrar/tests/test_admin.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/registrar/models/domain_request.py b/src/registrar/models/domain_request.py index 5283ce0e3..417713197 100644 --- a/src/registrar/models/domain_request.py +++ b/src/registrar/models/domain_request.py @@ -907,7 +907,7 @@ class DomainRequest(TimeStampedModel): def has_rationale(self) -> bool: """Does this domain request have no_other_contacts_rationale?""" return bool(self.no_other_contacts_rationale) -1 + def has_other_contacts(self) -> bool: """Does this domain request have other contacts listed?""" return self.other_contacts.exists() diff --git a/src/registrar/tests/test_admin.py b/src/registrar/tests/test_admin.py index c0fb210c0..fb5c566c2 100644 --- a/src/registrar/tests/test_admin.py +++ b/src/registrar/tests/test_admin.py @@ -585,7 +585,7 @@ class TestDomainRequestAdmin(MockEppLib): with less_console_noise(): self.client.force_login(self.superuser) completed_domain_request() - response = self.client.get("/admin/registrar/DomainRequest/") + response = self.client.get("/admin/registrar/domainrequest/") # There are 4 template references to Federal (4) plus two references in the table # for our actual domain request self.assertContains(response, "Federal", count=6) From cea667aae448e57cb3689e54c46ee56b1d6cdf03 Mon Sep 17 00:00:00 2001 From: CocoByte Date: Tue, 5 Mar 2024 00:07:51 -0700 Subject: [PATCH 051/103] Finally fixed remaining unit tests (after a long fight with our test outputs) --- src/registrar/models/user_group.py | 4 +-- src/registrar/tests/test_admin.py | 48 +++++++++++++------------- src/registrar/tests/test_migrations.py | 2 +- 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/registrar/models/user_group.py b/src/registrar/models/user_group.py index 8cf52cc6d..a84da798a 100644 --- a/src/registrar/models/user_group.py +++ b/src/registrar/models/user_group.py @@ -33,8 +33,8 @@ class UserGroup(Group): }, { "app_label": "registrar", - "model": "DomainRequest", - "permissions": ["change_DomainRequest"], + "model": "domainrequest", + "permissions": ["change_domainrequest"], }, { "app_label": "registrar", diff --git a/src/registrar/tests/test_admin.py b/src/registrar/tests/test_admin.py index fb5c566c2..504cbfb32 100644 --- a/src/registrar/tests/test_admin.py +++ b/src/registrar/tests/test_admin.py @@ -293,7 +293,7 @@ class TestDomainAdmin(MockEppLib, WebTest): Scenario: Domain deletion is unsuccessful When the domain is deleted Then a user-friendly success message is returned for displaying on the web - And `state` is et to `DELETED` + And `state` is set to `DELETED` """ with less_console_noise(): domain = create_ready_domain() @@ -498,7 +498,7 @@ class TestDomainRequestAdmin(MockEppLib): factory=self.factory, user=self.superuser, admin=self.admin, - url="/admin/registrar/DomainRequest/", + url="/admin/registrar/domainrequest/", model=DomainRequest, ) self.mock_client = MockSESClient() @@ -600,7 +600,7 @@ class TestDomainRequestAdmin(MockEppLib): with boto3_mocking.clients.handler_for("sesv2", self.mock_client): with less_console_noise(): # Create a mock request - request = self.factory.post("/admin/registrar/DomainRequest/{}/change/".format(domain_request.pk)) + request = self.factory.post("/admin/registrar/domainrequest/{}/change/".format(domain_request.pk)) # Modify the domain request's properties domain_request.status = status @@ -998,7 +998,7 @@ class TestDomainRequestAdmin(MockEppLib): domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.APPROVED) # Create a request object with a superuser - request = self.factory.post("/admin/registrar/DomainRequest/{}/change/".format(domain_request.pk)) + request = self.factory.post("/admin/registrar/domainrequest/{}/change/".format(domain_request.pk)) request.user = self.superuser with ExitStack() as stack: @@ -1026,7 +1026,7 @@ class TestDomainRequestAdmin(MockEppLib): domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.APPROVED) # Create a request object with a superuser - request = self.factory.post("/admin/registrar/DomainRequest/{}/change/".format(domain_request.pk)) + request = self.factory.post("/admin/registrar/domainrequest/{}/change/".format(domain_request.pk)) request.user = self.superuser with ExitStack() as stack: @@ -1079,7 +1079,7 @@ class TestDomainRequestAdmin(MockEppLib): domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.IN_REVIEW) # Create a mock request - request = self.factory.post("/admin/registrar/DomainRequest/{}/change/".format(domain_request.pk)) + request = self.factory.post("/admin/registrar/domainrequest/{}/change/".format(domain_request.pk)) with boto3_mocking.clients.handler_for("sesv2", self.mock_client): # Modify the domain request's property @@ -1101,7 +1101,7 @@ class TestDomainRequestAdmin(MockEppLib): domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.IN_REVIEW) # Create a mock request - request = self.factory.post("/admin/registrar/DomainRequest/{}/change/".format(domain_request.pk)) + request = self.factory.post("/admin/registrar/domainrequest/{}/change/".format(domain_request.pk)) with boto3_mocking.clients.handler_for("sesv2", self.mock_client): # Modify the domain request's property @@ -1233,7 +1233,7 @@ class TestDomainRequestAdmin(MockEppLib): with patch("django.contrib.messages.warning") as mock_warning: # Create a request object with a superuser - request = self.factory.get("/admin/your_app/DomainRequest/{}/change/".format(domain_request.pk)) + request = self.factory.get("/admin/your_app/domainrequest/{}/change/".format(domain_request.pk)) request.user = self.superuser self.admin.display_restricted_warning(request, domain_request) @@ -1260,7 +1260,7 @@ class TestDomainRequestAdmin(MockEppLib): domain_request.save() # Create a request object with a superuser - request = self.factory.post("/admin/registrar/DomainRequest/{}/change/".format(domain_request.pk)) + request = self.factory.post("/admin/registrar/domainrequest/{}/change/".format(domain_request.pk)) request.user = self.superuser # Define a custom implementation for is_active @@ -1403,7 +1403,7 @@ class TestDomainRequestAdmin(MockEppLib): p = "userpass" self.client.login(username="staffuser", password=p) response = self.client.get( - "/admin/registrar/DomainRequest/", + "/admin/registrar/domainrequest/", { "investigator__id__exact": investigator_user.id, }, @@ -1454,7 +1454,7 @@ class TestDomainRequestAdmin(MockEppLib): p = "userpass" self.client.login(username="staffuser", password=p) - request = self.factory.post("/admin/registrar/DomainRequest/{}/change/".format(domain_request.pk)) + request = self.factory.post("/admin/registrar/domainrequest/{}/change/".format(domain_request.pk)) # Get the actual field from the model's meta information investigator_field = DomainRequest._meta.get_field("investigator") @@ -1824,7 +1824,7 @@ class ListHeaderAdminTest(TestCase): # which handles CSRF # Follow=True handles the redirect response = self.client.get( - "/admin/registrar/DomainRequest/", + "/admin/registrar/domainrequest/", { "status__exact": "started", "investigator__id__exact": user.id, @@ -1909,7 +1909,7 @@ class MyUserAdminTest(TestCase): self.assertEqual(fieldsets, expected_fieldsets) def test_get_fieldsets_cisa_analyst(self): - with less_console_noise(): + if True: request = self.client.request().wsgi_request request.user = create_user() fieldsets = self.admin.get_fieldsets(request) @@ -1951,7 +1951,7 @@ class AuditedAdminTest(TestCase): # Create a mock request domain_request_request = self.factory.post( - "/admin/registrar/DomainRequest/{}/change/".format(domain_requests[0].pk) + "/admin/registrar/domainrequest/{}/change/".format(domain_requests[0].pk) ) # Get the formfield data from the domain request page @@ -1992,7 +1992,7 @@ class AuditedAdminTest(TestCase): domain_requests = multiple_unalphabetical_domain_objects("domain_request") # Create a mock request - request = self.factory.post("/admin/registrar/DomainRequest/{}/change/".format(domain_requests[0].pk)) + request = self.factory.post("/admin/registrar/domainrequest/{}/change/".format(domain_requests[0].pk)) model_admin = AuditedAdmin(DomainRequest, self.site) @@ -2343,13 +2343,13 @@ class ContactAdminTest(TestCase): response.wsgi_request, "
    " "
  • Joined to DomainRequest: city1.gov
  • " + f"domainrequest/{domain_request1.pk}/change/'>city1.gov" "
  • Joined to DomainRequest: city2.gov
  • " + f"domainrequest/{domain_request2.pk}/change/'>city2.gov" "
  • Joined to DomainRequest: city3.gov
  • " + f"domainrequest/{domain_request3.pk}/change/'>city3.gov" "
  • Joined to DomainRequest: city4.gov
  • " + f"domainrequest/{domain_request4.pk}/change/'>city4.gov" "
  • Joined to User: staff@example.com
  • " "
", @@ -2378,15 +2378,15 @@ class ContactAdminTest(TestCase): response.wsgi_request, "
    " "
  • Joined to DomainRequest: city1.gov
  • " + f"domainrequest/{domain_request1.pk}/change/'>city1.gov" "
  • Joined to DomainRequest: city2.gov
  • " + f"domainrequest/{domain_request2.pk}/change/'>city2.gov" "
  • Joined to DomainRequest: city3.gov
  • " + f"domainrequest/{domain_request3.pk}/change/'>city3.gov" "
  • Joined to DomainRequest: city4.gov
  • " + f"domainrequest/{domain_request4.pk}/change/'>city4.gov" "
  • Joined to DomainRequest: city5.gov
  • " + f"domainrequest/{domain_request5.pk}/change/'>city5.gov" "
" "

And 1 more...

", ) diff --git a/src/registrar/tests/test_migrations.py b/src/registrar/tests/test_migrations.py index 4dcfd89bb..50861d97f 100644 --- a/src/registrar/tests/test_migrations.py +++ b/src/registrar/tests/test_migrations.py @@ -34,10 +34,10 @@ class TestGroups(TestCase): "view_logentry", "change_contact", "view_domain", - "change_DomainRequest", "change_domaininformation", "add_domaininvitation", "view_domaininvitation", + "change_domainrequest", "change_draftdomain", "analyst_access_permission", "change_user", From 9ca8322510c185006dc1d43f3468420204fd456a Mon Sep 17 00:00:00 2001 From: Rebecca Hsieh Date: Tue, 5 Mar 2024 11:52:48 -0800 Subject: [PATCH 052/103] Update docs, csv set up, and add unit test --- .../runbooks/rotate_application_secrets.md | 6 ++++ .../generate_current_metadata_report.py | 8 ++--- src/registrar/tests/test_emails.py | 33 ++++++++++++++++++- src/registrar/utility/email.py | 4 +-- 4 files changed, 44 insertions(+), 7 deletions(-) diff --git a/docs/operations/runbooks/rotate_application_secrets.md b/docs/operations/runbooks/rotate_application_secrets.md index a776e60b8..f7a5004ef 100644 --- a/docs/operations/runbooks/rotate_application_secrets.md +++ b/docs/operations/runbooks/rotate_application_secrets.md @@ -117,3 +117,9 @@ You'll need to give the new certificate to the registry vendor _before_ rotating ## REGISTRY_HOSTNAME This is the hostname at which the registry can be found. + +## SECRET_METADATA_KEY + +This is in reference to the key for the metadata email that is sent daily. Reach out to product team members or leads with access to security passwords if the passcode is needed. + +To change the password, use a password generator to generate a password, then update the user credentials per the above instructions. Be sure to update the `KDBX` file in Google Drive with this password change. diff --git a/src/registrar/management/commands/generate_current_metadata_report.py b/src/registrar/management/commands/generate_current_metadata_report.py index 023a19f10..2478f9e6b 100644 --- a/src/registrar/management/commands/generate_current_metadata_report.py +++ b/src/registrar/management/commands/generate_current_metadata_report.py @@ -72,7 +72,7 @@ class Command(BaseCommand): # Set context for the subject current_date_str = datetime.now().strftime("%Y-%m-%d") - # TODO: Update secret in getgov-credentials via cloud.gov and my own .env when ready + # TODO: Update secret in getgov-credentials via cloud.gov and my own .env when merging # Encrypt the metadata encrypted_metadata_in_bytes = self._encrypt_metadata( @@ -83,15 +83,15 @@ class Command(BaseCommand): send_templated_email( template_name="emails/metadata_body.txt", subject_template_name="emails/metadata_subject.txt", - to_address=settings.DEFAULT_FROM_EMAIL, - # to_address="rebecca.hsieh@truss.works ", # TODO: Update to settings.DEFAULT_FROM_EMAIL once tested + # to_address=settings.DEFAULT_FROM_EMAIL, # TODO: Uncomment this when ready to merge + to_address="rebecca.hsieh@truss.works ", context={"current_date_str": current_date_str}, file=encrypted_metadata_in_bytes, ) def _encrypt_metadata(self, input_file, output_file, password): current_date = datetime.now().strftime("%m%d%Y") - current_filename = f"domain-metadata-{current_date}.txt" + current_filename = f"domain-metadata-{current_date}.csv" # Using ZIP_DEFLATED bc it's a more common compression method supported by most zip utilities and faster # We could also use compression=pyzipper.ZIP_LZMA if we are looking for smaller file size with pyzipper.AESZipFile( diff --git a/src/registrar/tests/test_emails.py b/src/registrar/tests/test_emails.py index f2a94a186..292fe5b1c 100644 --- a/src/registrar/tests/test_emails.py +++ b/src/registrar/tests/test_emails.py @@ -5,7 +5,8 @@ from unittest.mock import MagicMock from django.test import TestCase from .common import completed_application, less_console_noise - +from datetime import datetime +from registrar.utility import email import boto3_mocking # type: ignore @@ -182,3 +183,33 @@ class TestEmails(TestCase): self.assertNotIn("Anything else", body) # spacing should be right between adjacent elements self.assertRegex(body, r"5557\n\n----") + + @boto3_mocking.patching + def test_send_email_with_attachment(self): + with boto3_mocking.clients.handler_for("ses", self.mock_client_class): + sender_email = "sender@example.com" + recipient_email = "recipient@example.com" + subject = "Test Subject" + body = "Test Body" + attachment_file = b"Attachment file content" + current_date = datetime.now().strftime("%m%d%Y") + current_filename = f"domain-metadata-{current_date}.zip" + + response = email.send_email_with_attachment( + sender_email, recipient_email, subject, body, attachment_file, self.mock_client + ) + print("response is", response) + # Assert that the `send_raw_email` method of the mocked SES client was called with the expected params + self.mock_client.send_raw_email.assert_called_once() + + # Get the args passed to the `send_raw_email` method + call_args = self.mock_client.send_raw_email.call_args[1] + print("call_args is", call_args) + + # Assert that the attachment filename is correct + self.assertEqual(call_args["RawMessage"]["Data"].count(f'filename="{current_filename}"'), 1) + + # Assert that the attachment content is encrypted + self.assertIn("Content-Type: application/octet-stream", call_args["RawMessage"]["Data"]) + self.assertIn("Content-Transfer-Encoding: base64", call_args["RawMessage"]["Data"]) + self.assertIn("Content-Disposition: attachment;", call_args["RawMessage"]["Data"]) diff --git a/src/registrar/utility/email.py b/src/registrar/utility/email.py index a81a41716..ddd211041 100644 --- a/src/registrar/utility/email.py +++ b/src/registrar/utility/email.py @@ -65,11 +65,11 @@ def send_templated_email(template_name: str, subject_template_name: str, to_addr aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY, config=settings.BOTO_CONFIG, ) - # Define the subject line with the current date response = send_email_with_attachment( settings.DEFAULT_FROM_EMAIL, to_address, subject, email_body, file, ses_client ) - # TODO: Remove this print statement + # TODO: Remove this print statement when ready to merge, + # leaving rn for getting error codes in case print("Response from send_email_with_attachment_is:", response) except Exception as exc: raise EmailSendingError("Could not send SES email.") from exc From cf97531102df74ec00655f61e6d87a5216086b1b Mon Sep 17 00:00:00 2001 From: Rebecca Hsieh Date: Tue, 5 Mar 2024 11:56:20 -0800 Subject: [PATCH 053/103] Fix missing brackets --- src/registrar/utility/email.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/registrar/utility/email.py b/src/registrar/utility/email.py index 8960be001..72bbbabc7 100644 --- a/src/registrar/utility/email.py +++ b/src/registrar/utility/email.py @@ -59,7 +59,8 @@ def send_templated_email(template_name: str, subject_template_name: str, to_addr "Simple": { "Subject": {"Data": subject}, "Body": {"Text": {"Data": email_body}}, - }, + }, + } ) else: ses_client = boto3.client( From d61e17a4adcb70ce38b7b8145325027540cbc38c Mon Sep 17 00:00:00 2001 From: Rebecca Hsieh Date: Tue, 5 Mar 2024 12:03:11 -0800 Subject: [PATCH 054/103] Fix conflicts and linting --- .../commands/generate_current_metadata_report.py | 2 +- src/registrar/tests/test_emails.py | 2 -- src/registrar/utility/email.py | 7 ++++--- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/registrar/management/commands/generate_current_metadata_report.py b/src/registrar/management/commands/generate_current_metadata_report.py index 2478f9e6b..a3c7f70e1 100644 --- a/src/registrar/management/commands/generate_current_metadata_report.py +++ b/src/registrar/management/commands/generate_current_metadata_report.py @@ -10,7 +10,7 @@ from django.core.management import BaseCommand from django.conf import settings from registrar.utility import csv_export from registrar.utility.s3_bucket import S3ClientHelper -from ...utility.email import send_templated_email, EmailSendingError +from ...utility.email import send_templated_email logger = logging.getLogger(__name__) diff --git a/src/registrar/tests/test_emails.py b/src/registrar/tests/test_emails.py index 292fe5b1c..2c480cec2 100644 --- a/src/registrar/tests/test_emails.py +++ b/src/registrar/tests/test_emails.py @@ -198,13 +198,11 @@ class TestEmails(TestCase): response = email.send_email_with_attachment( sender_email, recipient_email, subject, body, attachment_file, self.mock_client ) - print("response is", response) # Assert that the `send_raw_email` method of the mocked SES client was called with the expected params self.mock_client.send_raw_email.assert_called_once() # Get the args passed to the `send_raw_email` method call_args = self.mock_client.send_raw_email.call_args[1] - print("call_args is", call_args) # Assert that the attachment filename is correct self.assertEqual(call_args["RawMessage"]["Data"].count(f'filename="{current_filename}"'), 1) diff --git a/src/registrar/utility/email.py b/src/registrar/utility/email.py index 72bbbabc7..2fb08d10c 100644 --- a/src/registrar/utility/email.py +++ b/src/registrar/utility/email.py @@ -5,7 +5,6 @@ import logging from datetime import datetime from django.conf import settings from django.template.loader import get_template -from email.mime.base import MIMEBase from email.mime.application import MIMEApplication from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText @@ -20,7 +19,9 @@ class EmailSendingError(RuntimeError): pass -def send_templated_email(template_name: str, subject_template_name: str, to_address: str, bcc_address="", context={}, file: str = None): +def send_templated_email( + template_name: str, subject_template_name: str, to_address: str, bcc_address="", context={}, file: str = None +): """Send an email built from a template to one email address. template_name and subject_template_name are relative to the same template @@ -60,7 +61,7 @@ def send_templated_email(template_name: str, subject_template_name: str, to_addr "Subject": {"Data": subject}, "Body": {"Text": {"Data": email_body}}, }, - } + }, ) else: ses_client = boto3.client( From c5f83b937d5e9d4f8c48edf848b0ea148a5e90d3 Mon Sep 17 00:00:00 2001 From: Rebecca Hsieh Date: Tue, 5 Mar 2024 12:21:41 -0800 Subject: [PATCH 055/103] Fix test --- src/registrar/tests/test_emails.py | 2 +- src/registrar/utility/email.py | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/registrar/tests/test_emails.py b/src/registrar/tests/test_emails.py index 2c480cec2..99db0d644 100644 --- a/src/registrar/tests/test_emails.py +++ b/src/registrar/tests/test_emails.py @@ -195,7 +195,7 @@ class TestEmails(TestCase): current_date = datetime.now().strftime("%m%d%Y") current_filename = f"domain-metadata-{current_date}.zip" - response = email.send_email_with_attachment( + email.send_email_with_attachment( sender_email, recipient_email, subject, body, attachment_file, self.mock_client ) # Assert that the `send_raw_email` method of the mocked SES client was called with the expected params diff --git a/src/registrar/utility/email.py b/src/registrar/utility/email.py index 2fb08d10c..35a4ecf03 100644 --- a/src/registrar/utility/email.py +++ b/src/registrar/utility/email.py @@ -51,11 +51,10 @@ def send_templated_email( destination["BccAddresses"] = [bcc_address] try: - if file is None: ses_client.send_email( FromEmailAddress=settings.DEFAULT_FROM_EMAIL, - Destination={"ToAddresses": [to_address]}, + Destination=destination, Content={ "Simple": { "Subject": {"Data": subject}, From 2ba38848a67b78537f35da13277e430e520d34ef Mon Sep 17 00:00:00 2001 From: Rebecca Hsieh Date: Tue, 5 Mar 2024 15:15:38 -0800 Subject: [PATCH 056/103] Update comment on why we're uploading to S3 instance --- .../commands/generate_current_metadata_report.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/registrar/management/commands/generate_current_metadata_report.py b/src/registrar/management/commands/generate_current_metadata_report.py index a3c7f70e1..209ed5cd5 100644 --- a/src/registrar/management/commands/generate_current_metadata_report.py +++ b/src/registrar/management/commands/generate_current_metadata_report.py @@ -48,8 +48,11 @@ class Command(BaseCommand): logger.info(f"Success! Created {file_name}") def generate_current_metadata_report(self, directory, file_name, check_path): - """Creates a current-full.csv file under the specified directory, - then uploads it to a AWS S3 bucket""" + """Creates a current-metadata.csv file under the specified directory, + then uploads it to a AWS S3 bucket. This is done for resiliency + reasons in the event our application goes down and/or the email + cannot send -- we'll still be able to grab info from the S3 + instance""" s3_client = S3ClientHelper() file_path = os.path.join(directory, file_name) @@ -60,7 +63,6 @@ class Command(BaseCommand): if check_path and not os.path.exists(file_path): raise FileNotFoundError(f"Could not find newly created file at '{file_path}'") - # Upload this generated file for our S3 instance s3_client.upload_file(file_path, file_name) # Set zip file name From d1a1992ced7f6c998a2f101f4aab773f10d7b8de Mon Sep 17 00:00:00 2001 From: David Kennedy Date: Wed, 6 Mar 2024 07:07:00 -0500 Subject: [PATCH 057/103] dbcache and multiple gunicorn workers --- src/registrar/config/settings.py | 11 ++++++----- src/run.sh | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/registrar/config/settings.py b/src/registrar/config/settings.py index 3107661b9..18b680e0d 100644 --- a/src/registrar/config/settings.py +++ b/src/registrar/config/settings.py @@ -192,11 +192,12 @@ WSGI_APPLICATION = "registrar.config.wsgi.application" # For a low to medium traffic site, caching causes more # problems than it solves. Should caching be desired, # a reasonable start might be: -# CACHES = { -# "default": { -# "BACKEND": "django.core.cache.backends.db.DatabaseCache", -# } -# } +CACHES = { + "default": { + "BACKEND": "django.core.cache.backends.db.DatabaseCache", + "LOCATION": "cache_table", + } +} # Absolute path to the directory where `collectstatic` # will place static files for deployment. diff --git a/src/run.sh b/src/run.sh index 1d35cd617..0228f143f 100755 --- a/src/run.sh +++ b/src/run.sh @@ -6,4 +6,4 @@ set -o pipefail # Make sure that django's `collectstatic` has been run locally before pushing up to any environment, # so that the styles and static assets to show up correctly on any environment. -gunicorn --worker-class=gevent registrar.config.wsgi -t 60 +gunicorn --workers=3 --worker-class=gevent registrar.config.wsgi -t 60 From e3e8c2646b68ef4448af02ceafa88546713bd258 Mon Sep 17 00:00:00 2001 From: David Kennedy Date: Wed, 6 Mar 2024 11:54:34 -0500 Subject: [PATCH 058/103] added createcachetable to docker-compose --- src/docker-compose.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/docker-compose.yml b/src/docker-compose.yml index fdf069f56..2e4ecaae5 100644 --- a/src/docker-compose.yml +++ b/src/docker-compose.yml @@ -66,6 +66,7 @@ services: command: > bash -c " python manage.py migrate && python manage.py load && + python manage.py createcachetable && python manage.py runserver 0.0.0.0:8080" db: From b33d71ee541d35c0d1905542c235e1947a686291 Mon Sep 17 00:00:00 2001 From: David Kennedy Date: Wed, 6 Mar 2024 12:13:18 -0500 Subject: [PATCH 059/103] new createcachetable.yaml script, updated create_dev_sandbox.sh --- .github/workflows/createcachetable.yaml | 46 +++++++++++++++++++++++++ ops/scripts/create_dev_sandbox.sh | 3 ++ 2 files changed, 49 insertions(+) create mode 100644 .github/workflows/createcachetable.yaml diff --git a/.github/workflows/createcachetable.yaml b/.github/workflows/createcachetable.yaml new file mode 100644 index 000000000..8fa4d76c8 --- /dev/null +++ b/.github/workflows/createcachetable.yaml @@ -0,0 +1,46 @@ +# This workflow can be run from the CLI for any environment +# gh workflow run createcachetable.yaml -f environment=ENVIRONMENT +# OR +# cf run-task getgov-ENVIRONMENT --command 'python manage.py createcachetable' --name createcachetable + +name: Create cache table +run-name: Create cache table for ${{ github.event.inputs.environment }} + +on: + workflow_dispatch: + inputs: + environment: + type: choice + description: Which environment should we create cache table for? + options: + - stable + - staging + - development + - backup + - ky + - es + - nl + - rh + - za + - gd + - rb + - ko + - ab + - rjm + - dk + +jobs: + createcachetable: + runs-on: ubuntu-latest + env: + CF_USERNAME: CF_${{ github.event.inputs.environment }}_USERNAME + CF_PASSWORD: CF_${{ github.event.inputs.environment }}_PASSWORD + steps: + - name: Create cache table for ${{ github.event.inputs.environment }} + uses: cloud-gov/cg-cli-tools@main + with: + cf_username: ${{ secrets[env.CF_USERNAME] }} + cf_password: ${{ secrets[env.CF_PASSWORD] }} + cf_org: cisa-dotgov + cf_space: ${{ github.event.inputs.environment }} + cf_command: "run-task getgov-${{ github.event.inputs.environment }} --command 'python manage.py createcachetable' --name createcachetable" diff --git a/ops/scripts/create_dev_sandbox.sh b/ops/scripts/create_dev_sandbox.sh index c9c55ae29..676fcf7ae 100755 --- a/ops/scripts/create_dev_sandbox.sh +++ b/ops/scripts/create_dev_sandbox.sh @@ -90,6 +90,9 @@ cd src/ cd .. cf push getgov-$1 -f ops/manifests/manifest-$1.yaml +echo "Creating cache table..." +cf run-task getgov-$1 --command 'python manage.py createcachetable' --name createcachetable + read -p "Please provide the email of the space developer: " -r cf set-space-role $REPLY cisa-dotgov $1 SpaceDeveloper From ce98272b4841d8186cd53e089827e02bc69f041c Mon Sep 17 00:00:00 2001 From: Rebecca Hsieh Date: Wed, 6 Mar 2024 11:45:50 -0800 Subject: [PATCH 060/103] Update pipfile --- src/Pipfile | 1 - src/Pipfile.lock | 12 ++++-------- src/requirements.txt | 1 - 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/src/Pipfile b/src/Pipfile index b40a8c3ea..b9c5d72d4 100644 --- a/src/Pipfile +++ b/src/Pipfile @@ -29,7 +29,6 @@ django-login-required-middleware = "*" greenlet = "*" gevent = "*" fred-epplib = {git = "https://github.com/cisagov/epplib.git", ref = "master"} -geventconnpool = {git = "https://github.com/rasky/geventconnpool.git", ref = "1bbb93a714a331a069adf27265fe582d9ba7ecd4"} pyzipper="*" tblib = "*" diff --git a/src/Pipfile.lock b/src/Pipfile.lock index 789422c5b..4eb2c0fb3 100644 --- a/src/Pipfile.lock +++ b/src/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "8094a1c9461f860e928b51542adf891c0f6f6c4c62bd1bd8ac3bba55a67f918d" + "sha256": "082a951f15bb26a28f2dca7e0840fdf61518b3d90c42d77a310f982344cbd1dc" }, "pipfile-spec": 6, "requires": {}, @@ -458,10 +458,6 @@ "markers": "python_version >= '3.8'", "version": "==24.2.1" }, - "geventconnpool": { - "git": "https://github.com/rasky/geventconnpool.git", - "ref": "1bbb93a714a331a069adf27265fe582d9ba7ecd4" - }, "greenlet": { "hashes": [ "sha256:01bc7ea167cf943b4c802068e178bbf70ae2e8c080467070d01bfa02f337ee67", @@ -1217,12 +1213,12 @@ }, "boto3-stubs": { "hashes": [ - "sha256:5ee40bdfba94fcdba26f36869339c849e918827ed1fb2f8e470474e6b1e923ff", - "sha256:cbbae1b811b97e4e1f1d00eba237ff987678e652502226b87e6276f7963935b4" + "sha256:627f8eca69d832581ee1676d39df099a2a2e3a86d6b3ebd21c81c5f11ed6a6fa", + "sha256:a87e7ecbab6235ec371b4363027e57483bca349a9cd5c891f40db81dadfa273e" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==1.34.55" + "version": "==1.34.56" }, "botocore": { "hashes": [ diff --git a/src/requirements.txt b/src/requirements.txt index b24e3575a..1db089f5a 100644 --- a/src/requirements.txt +++ b/src/requirements.txt @@ -28,7 +28,6 @@ fred-epplib@ git+https://github.com/cisagov/epplib.git@d56d183f1664f34c40ca9716a furl==2.1.3 future==1.0.0; python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3' gevent==24.2.1; python_version >= '3.8' -geventconnpool@ git+https://github.com/rasky/geventconnpool.git@1bbb93a714a331a069adf27265fe582d9ba7ecd4 greenlet==3.0.3; python_version >= '3.7' gunicorn==21.2.0; python_version >= '3.5' idna==3.6; python_version >= '3.5' From bac44a98149d1a446895374a4a1932223061d9a5 Mon Sep 17 00:00:00 2001 From: Rebecca Hsieh Date: Wed, 6 Mar 2024 15:54:05 -0800 Subject: [PATCH 061/103] Address variable and wording feedback --- .github/workflows/daily-csv-upload.yaml | 4 ++-- .../operations/runbooks/rotate_application_secrets.md | 6 ++++-- src/Pipfile | 3 +-- src/registrar/config/settings.py | 1 + .../commands/generate_current_metadata_report.py | 4 +++- src/registrar/tests/test_emails.py | 1 + src/registrar/utility/email.py | 11 ++++++++--- 7 files changed, 20 insertions(+), 10 deletions(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 84881398e..2a57c2083 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -31,12 +31,12 @@ jobs: cf_space: ${{ secrets.CF_REPORT_ENV }} cf_command: "run-task getgov-${{ secrets.CF_REPORT_ENV }} --command 'python manage.py generate_current_full_report' --name full" - - name: Generate current-metadata.csv + - name: Generate and email domain-metadata-.csv uses: cloud-gov/cg-cli-tools@main with: cf_username: ${{ secrets[env.CF_USERNAME] }} cf_password: ${{ secrets[env.CF_PASSWORD] }} cf_org: cisa-dotgov cf_space: ${{ secrets.CF_REPORT_ENV }} - cf_command: "run-task getgov-${{ secrets.CF_REPORT_ENV }} --command 'python manage.py generate_current_metadata_report' --name metadata" + cf_command: "run-task getgov-${{ secrets.CF_REPORT_ENV }} --command 'python manage.py email_current_metadata_report' --name metadata" diff --git a/docs/operations/runbooks/rotate_application_secrets.md b/docs/operations/runbooks/rotate_application_secrets.md index f7a5004ef..1094b4ff7 100644 --- a/docs/operations/runbooks/rotate_application_secrets.md +++ b/docs/operations/runbooks/rotate_application_secrets.md @@ -120,6 +120,8 @@ This is the hostname at which the registry can be found. ## SECRET_METADATA_KEY -This is in reference to the key for the metadata email that is sent daily. Reach out to product team members or leads with access to security passwords if the passcode is needed. +This is the passphrase for the zipped and encrypted metadata email that is sent out daily. Reach out to product team members or leads with access to security passwords if the passcode is needed. + +To change the password, use a password generator to generate a password, then update the user credentials per the above instructions. Be sure to update the [KBDX](https://docs.google.com/document/d/1_BbJmjYZNYLNh4jJPPnUEG9tFCzJrOc0nMrZrnSKKyw) file in Google Drive with this password change. + -To change the password, use a password generator to generate a password, then update the user credentials per the above instructions. Be sure to update the `KDBX` file in Google Drive with this password change. diff --git a/src/Pipfile b/src/Pipfile index b9c5d72d4..9208fada5 100644 --- a/src/Pipfile +++ b/src/Pipfile @@ -45,5 +45,4 @@ django-webtest = "*" types-cachetools = "*" boto3-mocking = "*" boto3-stubs = "*" -django-model2puml = "*" - +django-model2puml = "*" \ No newline at end of file diff --git a/src/registrar/config/settings.py b/src/registrar/config/settings.py index 65b372fac..e5b97748a 100644 --- a/src/registrar/config/settings.py +++ b/src/registrar/config/settings.py @@ -74,6 +74,7 @@ secret_aws_s3_key_id = secret("access_key_id", None) or secret("AWS_S3_ACCESS_KE secret_aws_s3_key = secret("secret_access_key", None) or secret("AWS_S3_SECRET_ACCESS_KEY", None) secret_aws_s3_bucket_name = secret("bucket", None) or secret("AWS_S3_BUCKET_NAME", None) +# Passphrase for the encrypted metadata email secret_encrypt_metadata = secret("SECRET_ENCRYPT_METADATA", None) secret_registry_cl_id = secret("REGISTRY_CL_ID") diff --git a/src/registrar/management/commands/generate_current_metadata_report.py b/src/registrar/management/commands/generate_current_metadata_report.py index 209ed5cd5..103ce0dab 100644 --- a/src/registrar/management/commands/generate_current_metadata_report.py +++ b/src/registrar/management/commands/generate_current_metadata_report.py @@ -45,7 +45,7 @@ class Command(BaseCommand): # TODO - #1317: Notify operations when auto report generation fails raise err else: - logger.info(f"Success! Created {file_name}") + logger.info(f"Success! Created {file_name} and successfully sent out an email!") def generate_current_metadata_report(self, directory, file_name, check_path): """Creates a current-metadata.csv file under the specified directory, @@ -68,6 +68,7 @@ class Command(BaseCommand): # Set zip file name current_date = datetime.now().strftime("%m%d%Y") current_filename = f"domain-metadata-{current_date}.zip" + # Pre-set zip file name encrypted_metadata_output = current_filename @@ -92,6 +93,7 @@ class Command(BaseCommand): ) def _encrypt_metadata(self, input_file, output_file, password): + """Helper function for encrypting the attachment file""" current_date = datetime.now().strftime("%m%d%Y") current_filename = f"domain-metadata-{current_date}.csv" # Using ZIP_DEFLATED bc it's a more common compression method supported by most zip utilities and faster diff --git a/src/registrar/tests/test_emails.py b/src/registrar/tests/test_emails.py index 99db0d644..b11f21da6 100644 --- a/src/registrar/tests/test_emails.py +++ b/src/registrar/tests/test_emails.py @@ -211,3 +211,4 @@ class TestEmails(TestCase): self.assertIn("Content-Type: application/octet-stream", call_args["RawMessage"]["Data"]) self.assertIn("Content-Transfer-Encoding: base64", call_args["RawMessage"]["Data"]) self.assertIn("Content-Disposition: attachment;", call_args["RawMessage"]["Data"]) + self.assertNotIn("Attachment file content", call_args["RawMessage"]["Data"]) diff --git a/src/registrar/utility/email.py b/src/registrar/utility/email.py index 35a4ecf03..91d55f361 100644 --- a/src/registrar/utility/email.py +++ b/src/registrar/utility/email.py @@ -20,7 +20,12 @@ class EmailSendingError(RuntimeError): def send_templated_email( - template_name: str, subject_template_name: str, to_address: str, bcc_address="", context={}, file: str = None + template_name: str, + subject_template_name: str, + to_address: str, + bcc_address="", + context={}, + attachment_file: str = None, ): """Send an email built from a template to one email address. @@ -51,7 +56,7 @@ def send_templated_email( destination["BccAddresses"] = [bcc_address] try: - if file is None: + if attachment_file is None: ses_client.send_email( FromEmailAddress=settings.DEFAULT_FROM_EMAIL, Destination=destination, @@ -71,7 +76,7 @@ def send_templated_email( config=settings.BOTO_CONFIG, ) response = send_email_with_attachment( - settings.DEFAULT_FROM_EMAIL, to_address, subject, email_body, file, ses_client + settings.DEFAULT_FROM_EMAIL, to_address, subject, email_body, attachment_file, ses_client ) # TODO: Remove this print statement when ready to merge, # leaving rn for getting error codes in case From 370b2ddda068bf77971f7eccbfa40ec4e0a0be7a Mon Sep 17 00:00:00 2001 From: Rebecca Hsieh Date: Wed, 6 Mar 2024 16:05:41 -0800 Subject: [PATCH 062/103] Fix variable name --- .../management/commands/generate_current_metadata_report.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/registrar/management/commands/generate_current_metadata_report.py b/src/registrar/management/commands/generate_current_metadata_report.py index 103ce0dab..da5aafb91 100644 --- a/src/registrar/management/commands/generate_current_metadata_report.py +++ b/src/registrar/management/commands/generate_current_metadata_report.py @@ -89,7 +89,7 @@ class Command(BaseCommand): # to_address=settings.DEFAULT_FROM_EMAIL, # TODO: Uncomment this when ready to merge to_address="rebecca.hsieh@truss.works ", context={"current_date_str": current_date_str}, - file=encrypted_metadata_in_bytes, + attachment_file=encrypted_metadata_in_bytes, ) def _encrypt_metadata(self, input_file, output_file, password): From 83800b6a65e2005b795048aca954b01c1a841234 Mon Sep 17 00:00:00 2001 From: David Kennedy Date: Thu, 7 Mar 2024 08:51:43 -0500 Subject: [PATCH 063/103] updated comments in settings.py --- src/registrar/config/settings.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/registrar/config/settings.py b/src/registrar/config/settings.py index 18b680e0d..15799f91b 100644 --- a/src/registrar/config/settings.py +++ b/src/registrar/config/settings.py @@ -188,10 +188,6 @@ WSGI_APPLICATION = "registrar.config.wsgi.application" # https://docs.djangoproject.com/en/4.0/howto/static-files/ -# Caching is disabled by default. -# For a low to medium traffic site, caching causes more -# problems than it solves. Should caching be desired, -# a reasonable start might be: CACHES = { "default": { "BACKEND": "django.core.cache.backends.db.DatabaseCache", From 52f299d06e304cca79026037facee6794d5f1bb7 Mon Sep 17 00:00:00 2001 From: David Kennedy Date: Thu, 7 Mar 2024 12:35:10 -0500 Subject: [PATCH 064/103] initial form changes - wip --- src/registrar/admin.py | 58 +++++++--------------- src/registrar/models/domain_application.py | 4 +- src/registrar/models/domain_information.py | 2 +- 3 files changed, 21 insertions(+), 43 deletions(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index 92e477667..0ea791181 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -777,18 +777,21 @@ class DomainInformationAdmin(ListHeaderAdmin): search_help_text = "Search by domain." fieldsets = [ - (None, {"fields": ["creator", "domain_application", "notes"]}), + (None, {"fields": ["creator", "submitter", "domain_application", "notes"]}), + (".gov domain", {"fields": ["domain"]}), + ("Contacts", {"fields": ["authorizing_official", "other_contacts", "no_other_contacts_rationale"]}), + ("Background info", {"fields": ["anything_else"]}), ( "Type of organization", { "fields": [ "organization_type", + "is_election_board", + "federal_type", + "federal_agency", + "tribe_name", "federally_recognized_tribe", "state_recognized_tribe", - "tribe_name", - "federal_agency", - "federal_type", - "is_election_board", "about_your_organization", ] }, @@ -798,28 +801,15 @@ class DomainInformationAdmin(ListHeaderAdmin): { "fields": [ "organization_name", + "state_territory", "address_line1", "address_line2", "city", - "state_territory", "zipcode", "urbanization", ] }, ), - ("Authorizing official", {"fields": ["authorizing_official"]}), - (".gov domain", {"fields": ["domain"]}), - ("Your contact information", {"fields": ["submitter"]}), - ("Other employees from your organization?", {"fields": ["other_contacts"]}), - ( - "No other employees from your organization?", - {"fields": ["no_other_contacts_rationale"]}, - ), - ("Anything else?", {"fields": ["anything_else"]}), - ( - "Requirements for operating a .gov domain", - {"fields": ["is_policy_acknowledged"]}, - ), ] # Read only that we'll leverage for CISA Analysts @@ -979,18 +969,21 @@ class DomainApplicationAdmin(ListHeaderAdmin): search_help_text = "Search by domain or submitter." fieldsets = [ - (None, {"fields": ["status", "rejection_reason", "investigator", "creator", "approved_domain", "notes"]}), + (None, {"fields": ["status", "rejection_reason", "investigator", "creator", "submitter", "approved_domain", "notes"]}), + (".gov domain", {"fields": ["requested_domain", "alternative_domains"]}), + ("Contacts", {"fields": ["authorizing_official", "other_contacts", "no_other_contacts_rationale"]}), + ("Background info", {"fields": ["purpose", "anything_else", "current_websites"]}), ( "Type of organization", { "fields": [ "organization_type", + "is_election_board", + "federal_type", + "federal_agency", + "tribe_name", "federally_recognized_tribe", "state_recognized_tribe", - "tribe_name", - "federal_agency", - "federal_type", - "is_election_board", "about_your_organization", ] }, @@ -1000,30 +993,15 @@ class DomainApplicationAdmin(ListHeaderAdmin): { "fields": [ "organization_name", + "state_territory", "address_line1", "address_line2", "city", - "state_territory", "zipcode", "urbanization", ] }, ), - ("Authorizing official", {"fields": ["authorizing_official"]}), - ("Current websites", {"fields": ["current_websites"]}), - (".gov domain", {"fields": ["requested_domain", "alternative_domains"]}), - ("Purpose of your domain", {"fields": ["purpose"]}), - ("Your contact information", {"fields": ["submitter"]}), - ("Other employees from your organization?", {"fields": ["other_contacts"]}), - ( - "No other employees from your organization?", - {"fields": ["no_other_contacts_rationale"]}, - ), - ("Anything else?", {"fields": ["anything_else"]}), - ( - "Requirements for operating a .gov domain", - {"fields": ["is_policy_acknowledged"]}, - ), ] # Read only that we'll leverage for CISA Analysts diff --git a/src/registrar/models/domain_application.py b/src/registrar/models/domain_application.py index 8c417b51a..90627a63b 100644 --- a/src/registrar/models/domain_application.py +++ b/src/registrar/models/domain_application.py @@ -504,7 +504,7 @@ class DomainApplication(TimeStampedModel): "registrar.Website", blank=True, related_name="current+", - verbose_name="websites", + verbose_name="Current websites", ) approved_domain = models.OneToOneField( @@ -550,7 +550,7 @@ class DomainApplication(TimeStampedModel): "registrar.Contact", blank=True, related_name="contact_applications", - verbose_name="contacts", + verbose_name="Other employees", ) no_other_contacts_rationale = models.TextField( diff --git a/src/registrar/models/domain_information.py b/src/registrar/models/domain_information.py index 861171c5c..5e17cfd2c 100644 --- a/src/registrar/models/domain_information.py +++ b/src/registrar/models/domain_information.py @@ -183,7 +183,7 @@ class DomainInformation(TimeStampedModel): "registrar.Contact", blank=True, related_name="contact_applications_information", - verbose_name="contacts", + verbose_name="Other employees", ) no_other_contacts_rationale = models.TextField( From 9dec0753f28cfd40b3df60214edd0d645fb8d50c Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Thu, 7 Mar 2024 10:42:30 -0700 Subject: [PATCH 065/103] Revert change where only status change is forbidden --- src/registrar/admin.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index 0d9045920..6dc6cd94d 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -134,6 +134,9 @@ class DomainApplicationAdminForm(forms.ModelForm): status = cleaned_data.get("status") investigator = cleaned_data.get("investigator") + # Get the old status + initial_status = self.initial.get("status", None) + # We only care about investigator when in these statuses checked_statuses = [ DomainApplication.ApplicationStatus.APPROVED, @@ -144,7 +147,7 @@ class DomainApplicationAdminForm(forms.ModelForm): ] # If a status change occured, check for validity - if status in checked_statuses: + if status != initial_status and status in checked_statuses: # Checks the "investigators" field for validity. # That field must obey certain conditions when an application is approved. # Will call "add_error" if any issues are found. From aa26f782d039920f4937c3b818962a2d1b5d2490 Mon Sep 17 00:00:00 2001 From: David Kennedy Date: Thu, 7 Mar 2024 12:43:40 -0500 Subject: [PATCH 066/103] lint and migrations --- src/registrar/admin.py | 15 +++++++- ...inapplication_current_websites_and_more.py | 37 +++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 src/registrar/migrations/0073_alter_domainapplication_current_websites_and_more.py diff --git a/src/registrar/admin.py b/src/registrar/admin.py index 0ea791181..f03fe6713 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -969,7 +969,20 @@ class DomainApplicationAdmin(ListHeaderAdmin): search_help_text = "Search by domain or submitter." fieldsets = [ - (None, {"fields": ["status", "rejection_reason", "investigator", "creator", "submitter", "approved_domain", "notes"]}), + ( + None, + { + "fields": [ + "status", + "rejection_reason", + "investigator", + "creator", + "submitter", + "approved_domain", + "notes", + ] + }, + ), (".gov domain", {"fields": ["requested_domain", "alternative_domains"]}), ("Contacts", {"fields": ["authorizing_official", "other_contacts", "no_other_contacts_rationale"]}), ("Background info", {"fields": ["purpose", "anything_else", "current_websites"]}), diff --git a/src/registrar/migrations/0073_alter_domainapplication_current_websites_and_more.py b/src/registrar/migrations/0073_alter_domainapplication_current_websites_and_more.py new file mode 100644 index 000000000..cefaba27c --- /dev/null +++ b/src/registrar/migrations/0073_alter_domainapplication_current_websites_and_more.py @@ -0,0 +1,37 @@ +# Generated by Django 4.2.10 on 2024-03-07 17:42 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("registrar", "0072_alter_publiccontact_fax_alter_publiccontact_voice"), + ] + + operations = [ + migrations.AlterField( + model_name="domainapplication", + name="current_websites", + field=models.ManyToManyField( + blank=True, related_name="current+", to="registrar.website", verbose_name="Current websites" + ), + ), + migrations.AlterField( + model_name="domainapplication", + name="other_contacts", + field=models.ManyToManyField( + blank=True, related_name="contact_applications", to="registrar.contact", verbose_name="Other employees" + ), + ), + migrations.AlterField( + model_name="domaininformation", + name="other_contacts", + field=models.ManyToManyField( + blank=True, + related_name="contact_applications_information", + to="registrar.contact", + verbose_name="Other employees", + ), + ), + ] From 1e90c3121ba0e493938345c6667a93688c4b9383 Mon Sep 17 00:00:00 2001 From: David Kennedy Date: Thu, 7 Mar 2024 14:17:41 -0500 Subject: [PATCH 067/103] changed font size of h2 --- src/registrar/assets/sass/_theme/_admin.scss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/registrar/assets/sass/_theme/_admin.scss b/src/registrar/assets/sass/_theme/_admin.scss index b57c6a015..e53dc8b4b 100644 --- a/src/registrar/assets/sass/_theme/_admin.scss +++ b/src/registrar/assets/sass/_theme/_admin.scss @@ -141,6 +141,10 @@ h1, h2, h3, font-weight: font-weight('bold'); } +#content h2 { + font-size: 1.3rem; +} + .module h3 { padding: 0; color: var(--link-fg); From 2340b6c800619acf6698f3353c6ba9b21e729d26 Mon Sep 17 00:00:00 2001 From: CocoByte Date: Thu, 7 Mar 2024 14:19:15 -0700 Subject: [PATCH 068/103] Revert some mis-renamed instances of "application" + other minor fixes --- src/registrar/assets/sass/_theme/_admin.scss | 9 +++++++++ src/registrar/models/utility/generic_helper.py | 2 +- .../templates/django/admin/domain_change_form.html | 2 +- src/registrar/tests/test_admin.py | 2 +- 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/registrar/assets/sass/_theme/_admin.scss b/src/registrar/assets/sass/_theme/_admin.scss index b57c6a015..78c76f090 100644 --- a/src/registrar/assets/sass/_theme/_admin.scss +++ b/src/registrar/assets/sass/_theme/_admin.scss @@ -135,12 +135,21 @@ html[data-theme="dark"] { color: var(--primary-fg); } + + #branding h1, h1, h2, h3, .module h2 { font-weight: font-weight('bold'); } +#content h2 +{ + color:red; + font-size: 1rem; +} + + .module h3 { padding: 0; color: var(--link-fg); diff --git a/src/registrar/models/utility/generic_helper.py b/src/registrar/models/utility/generic_helper.py index dca56f13c..01d4e6b33 100644 --- a/src/registrar/models/utility/generic_helper.py +++ b/src/registrar/models/utility/generic_helper.py @@ -16,7 +16,7 @@ class Timer: Note that this class does not account for general randomness as more robust libraries do, so there is some tiny amount of latency involved - in using this, but it is minimal enough that for most domain requests it is not + in using this, but it is minimal enough that for most applications it is not noticable. Usage: diff --git a/src/registrar/templates/django/admin/domain_change_form.html b/src/registrar/templates/django/admin/domain_change_form.html index 65cbd1db0..67c5ac291 100644 --- a/src/registrar/templates/django/admin/domain_change_form.html +++ b/src/registrar/templates/django/admin/domain_change_form.html @@ -50,7 +50,7 @@ This is controlled by the class `dja-form-placeholder` on the button. In addition, the modal element MUST be placed low in the DOM. The script loads slower on DJA than on other portions - of the domain_request, so this means that it will briefly "populate", causing unintended visual effects. + of the application, so this means that it will briefly "populate", causing unintended visual effects. {% endcomment %}
Date: Thu, 7 Mar 2024 13:21:52 -0800 Subject: [PATCH 069/103] Fix script name --- .../management/commands/generate_current_metadata_report.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/registrar/management/commands/generate_current_metadata_report.py b/src/registrar/management/commands/generate_current_metadata_report.py index da5aafb91..cdda32002 100644 --- a/src/registrar/management/commands/generate_current_metadata_report.py +++ b/src/registrar/management/commands/generate_current_metadata_report.py @@ -40,14 +40,14 @@ class Command(BaseCommand): logger.info("Generating report...") try: - self.generate_current_metadata_report(directory, file_name, check_path) + self.email_current_metadata_report(directory, file_name, check_path) except Exception as err: # TODO - #1317: Notify operations when auto report generation fails raise err else: logger.info(f"Success! Created {file_name} and successfully sent out an email!") - def generate_current_metadata_report(self, directory, file_name, check_path): + def email_current_metadata_report(self, directory, file_name, check_path): """Creates a current-metadata.csv file under the specified directory, then uploads it to a AWS S3 bucket. This is done for resiliency reasons in the event our application goes down and/or the email From 7e6cf54781aa89568d4374830b9f9055e187d4f2 Mon Sep 17 00:00:00 2001 From: Rebecca Hsieh Date: Thu, 7 Mar 2024 13:34:40 -0800 Subject: [PATCH 070/103] Fix renaming for yaml upload --- .github/workflows/daily-csv-upload.yaml | 2 +- ..._metadata_report.py => email_current_metadata_report.py} | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) rename src/registrar/management/commands/{generate_current_metadata_report.py => email_current_metadata_report.py} (95%) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 2a57c2083..9cacfc3bf 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -31,7 +31,7 @@ jobs: cf_space: ${{ secrets.CF_REPORT_ENV }} cf_command: "run-task getgov-${{ secrets.CF_REPORT_ENV }} --command 'python manage.py generate_current_full_report' --name full" - - name: Generate and email domain-metadata-.csv + - name: Generate and email domain-metadata.csv uses: cloud-gov/cg-cli-tools@main with: cf_username: ${{ secrets[env.CF_USERNAME] }} diff --git a/src/registrar/management/commands/generate_current_metadata_report.py b/src/registrar/management/commands/email_current_metadata_report.py similarity index 95% rename from src/registrar/management/commands/generate_current_metadata_report.py rename to src/registrar/management/commands/email_current_metadata_report.py index cdda32002..4300bf227 100644 --- a/src/registrar/management/commands/generate_current_metadata_report.py +++ b/src/registrar/management/commands/email_current_metadata_report.py @@ -18,7 +18,7 @@ logger = logging.getLogger(__name__) class Command(BaseCommand): help = ( - "Generates and uploads a current-metadata.csv file to our S3 bucket " + "Generates and uploads a domain-metadata.csv file to our S3 bucket " "which is based off of all existing Domains." ) @@ -32,8 +32,8 @@ class Command(BaseCommand): ) def handle(self, **options): - """Grabs the directory then creates current-metadata.csv in that directory""" - file_name = "current-metadata.csv" + """Grabs the directory then creates domain-metadata.csv in that directory""" + file_name = "domain-metadata.csv" # Ensures a slash is added directory = os.path.join(options.get("directory"), "") check_path = options.get("checkpath") From a71c48a27d41476f3d8816f63bade3e00c8587f1 Mon Sep 17 00:00:00 2001 From: CocoByte Date: Thu, 7 Mar 2024 14:52:58 -0700 Subject: [PATCH 071/103] fixed migrations --- ...mainrequest_and_more.py => 0073_domainrequest_and_more.py} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename src/registrar/migrations/{0072_domainrequest_and_more.py => 0073_domainrequest_and_more.py} (99%) diff --git a/src/registrar/migrations/0072_domainrequest_and_more.py b/src/registrar/migrations/0073_domainrequest_and_more.py similarity index 99% rename from src/registrar/migrations/0072_domainrequest_and_more.py rename to src/registrar/migrations/0073_domainrequest_and_more.py index 03d624834..88608b03a 100644 --- a/src/registrar/migrations/0072_domainrequest_and_more.py +++ b/src/registrar/migrations/0073_domainrequest_and_more.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.10 on 2024-03-01 03:52 +# Generated by Django 4.2.10 on 2024-03-07 21:52 from django.conf import settings from django.db import migrations, models @@ -9,7 +9,7 @@ import django_fsm class Migration(migrations.Migration): dependencies = [ - ("registrar", "0071_alter_contact_first_name_alter_contact_last_name_and_more"), + ("registrar", "0072_alter_publiccontact_fax_alter_publiccontact_voice"), ] operations = [ From 84c221bac65f4197bfaf429350559da82b40ae15 Mon Sep 17 00:00:00 2001 From: CocoByte Date: Thu, 7 Mar 2024 15:06:34 -0700 Subject: [PATCH 072/103] camel-case correction for targeted models --- src/registrar/admin.py | 2 +- src/registrar/tests/test_admin.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index c9eea460d..c9107969a 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -486,7 +486,7 @@ class MyUserAdmin(BaseUserAdmin): field_name = request_get.get("field_name", None) # Make sure we're only modifying requests from these models. - models_to_target = {"DomainRequest"} + models_to_target = {"domain_request"} if model_name in models_to_target: # Define rules per field match field_name: diff --git a/src/registrar/tests/test_admin.py b/src/registrar/tests/test_admin.py index 013000fb2..ec9c1e7d3 100644 --- a/src/registrar/tests/test_admin.py +++ b/src/registrar/tests/test_admin.py @@ -1466,7 +1466,7 @@ class TestDomainRequestAdmin(MockEppLib): # Grab the current dropdown. We do an API call to autocomplete to get this info. domain_request_queryset = self.admin.formfield_for_foreignkey(investigator_field, request).queryset user_request = self.factory.post( - "/admin/autocomplete/?app_label=registrar&model_name=DomainRequest&field_name=investigator" + "/admin/autocomplete/?app_label=registrar&model_name=domain_request&field_name=investigator" ) user_admin = MyUserAdmin(User, self.site) user_queryset = user_admin.get_search_results(user_request, domain_request_queryset, None)[0] From 97eca957862de0de41b8596dbee27688ea5bbba0 Mon Sep 17 00:00:00 2001 From: Alysia Broddrick Date: Thu, 7 Mar 2024 14:22:24 -0800 Subject: [PATCH 073/103] increase isntances on development to allow for zero downtime --- ops/manifests/manifest-development.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ops/manifests/manifest-development.yaml b/ops/manifests/manifest-development.yaml index 08244cf08..23558ba4c 100644 --- a/ops/manifests/manifest-development.yaml +++ b/ops/manifests/manifest-development.yaml @@ -4,7 +4,7 @@ applications: buildpacks: - python_buildpack path: ../../src - instances: 1 + instances: 2 memory: 512M stack: cflinuxfs4 timeout: 180 From 19fb8a0c04ec9364eedd68368aa18c8b2a50cedf Mon Sep 17 00:00:00 2001 From: CocoByte Date: Thu, 7 Mar 2024 15:24:00 -0700 Subject: [PATCH 074/103] remove css experiment & revert camel-case change --- src/registrar/admin.py | 2 +- src/registrar/assets/sass/_theme/_admin.scss | 7 ------- src/registrar/tests/test_admin.py | 2 +- 3 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index c9107969a..c9eea460d 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -486,7 +486,7 @@ class MyUserAdmin(BaseUserAdmin): field_name = request_get.get("field_name", None) # Make sure we're only modifying requests from these models. - models_to_target = {"domain_request"} + models_to_target = {"DomainRequest"} if model_name in models_to_target: # Define rules per field match field_name: diff --git a/src/registrar/assets/sass/_theme/_admin.scss b/src/registrar/assets/sass/_theme/_admin.scss index 78c76f090..9c0d7517c 100644 --- a/src/registrar/assets/sass/_theme/_admin.scss +++ b/src/registrar/assets/sass/_theme/_admin.scss @@ -143,13 +143,6 @@ h1, h2, h3, font-weight: font-weight('bold'); } -#content h2 -{ - color:red; - font-size: 1rem; -} - - .module h3 { padding: 0; color: var(--link-fg); diff --git a/src/registrar/tests/test_admin.py b/src/registrar/tests/test_admin.py index ec9c1e7d3..013000fb2 100644 --- a/src/registrar/tests/test_admin.py +++ b/src/registrar/tests/test_admin.py @@ -1466,7 +1466,7 @@ class TestDomainRequestAdmin(MockEppLib): # Grab the current dropdown. We do an API call to autocomplete to get this info. domain_request_queryset = self.admin.formfield_for_foreignkey(investigator_field, request).queryset user_request = self.factory.post( - "/admin/autocomplete/?app_label=registrar&model_name=domain_request&field_name=investigator" + "/admin/autocomplete/?app_label=registrar&model_name=DomainRequest&field_name=investigator" ) user_admin = MyUserAdmin(User, self.site) user_queryset = user_admin.get_search_results(user_request, domain_request_queryset, None)[0] From a5ecb010b8750fb6aadd5647c77135cf03a6e6f0 Mon Sep 17 00:00:00 2001 From: CocoByte Date: Thu, 7 Mar 2024 15:31:14 -0700 Subject: [PATCH 075/103] another go at camel-case correction --- src/registrar/admin.py | 2 +- src/registrar/tests/test_admin.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index c9eea460d..50801b79b 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -486,7 +486,7 @@ class MyUserAdmin(BaseUserAdmin): field_name = request_get.get("field_name", None) # Make sure we're only modifying requests from these models. - models_to_target = {"DomainRequest"} + models_to_target = {"domainrequest"} if model_name in models_to_target: # Define rules per field match field_name: diff --git a/src/registrar/tests/test_admin.py b/src/registrar/tests/test_admin.py index 013000fb2..2b85627ca 100644 --- a/src/registrar/tests/test_admin.py +++ b/src/registrar/tests/test_admin.py @@ -1466,7 +1466,7 @@ class TestDomainRequestAdmin(MockEppLib): # Grab the current dropdown. We do an API call to autocomplete to get this info. domain_request_queryset = self.admin.formfield_for_foreignkey(investigator_field, request).queryset user_request = self.factory.post( - "/admin/autocomplete/?app_label=registrar&model_name=DomainRequest&field_name=investigator" + "/admin/autocomplete/?app_label=registrar&model_name=domainrequest&field_name=investigator" ) user_admin = MyUserAdmin(User, self.site) user_queryset = user_admin.get_search_results(user_request, domain_request_queryset, None)[0] @@ -1962,7 +1962,7 @@ class AuditedAdminTest(TestCase): domain_request_queryset = domain_request_admin.formfield_for_foreignkey(field, domain_request_request).queryset request = self.factory.post( - "/admin/autocomplete/?app_label=registrar&model_name=DomainRequest&field_name=investigator" + "/admin/autocomplete/?app_label=registrar&model_name=domainrequest&field_name=investigator" ) sorted_fields = ["first_name", "last_name", "email"] From 8fb16364fec3c1cce56f886be94158f497be7d7b Mon Sep 17 00:00:00 2001 From: Alysia Broddrick Date: Thu, 7 Mar 2024 14:51:22 -0800 Subject: [PATCH 076/103] Added test workflow to see if this results in zero downtime --- .github/workflows/test-deploy.yaml | 41 ++++++++++++++++++++++++++++++ ops/manifests/manifest-ab.yaml | 2 +- 2 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/test-deploy.yaml diff --git a/.github/workflows/test-deploy.yaml b/.github/workflows/test-deploy.yaml new file mode 100644 index 000000000..1c6cc95fc --- /dev/null +++ b/.github/workflows/test-deploy.yaml @@ -0,0 +1,41 @@ +# This workflow is to for testing a change to our deploy structure and will be deleted when testing finishes + +name: Deploy Main +run-name: Run deploy for ${{ github.event.inputs.environment }} + +on: + workflow_dispatch: + inputs: + environment: + type: choice + description: Which environment should we run deploy for? + options: + - development + - backup + - ky + - es + - nl + - rh + - za + - gd + - rb + - ko + - ab + - rjm + - dk + +jobs: + deploy: + runs-on: ubuntu-latest + env: + CF_USERNAME: CF_${{ github.event.inputs.environment }}_USERNAME + CF_PASSWORD: CF_${{ github.event.inputs.environment }}_PASSWORD + steps: + - name: Deploy to cloud.gov sandbox + uses: cloud-gov/cg-cli-tools@main + with: + cf_username: ${{ secrets[env.CF_USERNAME] }} + cf_password: ${{ secrets[env.CF_PASSWORD] }} + cf_org: cisa-dotgov + cf_space: ${{ env.ENVIRONMENT }} + cf_command: "cf push -f ops/manifests/manifest-${{ env.ENVIRONMENT }}.yaml --strategy rolling" \ No newline at end of file diff --git a/ops/manifests/manifest-ab.yaml b/ops/manifests/manifest-ab.yaml index 3ca800392..a78de338e 100644 --- a/ops/manifests/manifest-ab.yaml +++ b/ops/manifests/manifest-ab.yaml @@ -4,7 +4,7 @@ applications: buildpacks: - python_buildpack path: ../../src - instances: 1 + instances: 2 memory: 512M stack: cflinuxfs4 timeout: 180 From 5114ef4ccd7e47eff024aab6562a26653f6c64de Mon Sep 17 00:00:00 2001 From: Alysia Broddrick Date: Thu, 7 Mar 2024 16:18:41 -0800 Subject: [PATCH 077/103] fixed typo --- .github/workflows/test-deploy.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-deploy.yaml b/.github/workflows/test-deploy.yaml index 1c6cc95fc..1f3992280 100644 --- a/.github/workflows/test-deploy.yaml +++ b/.github/workflows/test-deploy.yaml @@ -38,4 +38,4 @@ jobs: cf_password: ${{ secrets[env.CF_PASSWORD] }} cf_org: cisa-dotgov cf_space: ${{ env.ENVIRONMENT }} - cf_command: "cf push -f ops/manifests/manifest-${{ env.ENVIRONMENT }}.yaml --strategy rolling" \ No newline at end of file + cf_command: "push -f ops/manifests/manifest-${{ env.ENVIRONMENT }}.yaml --strategy rolling" \ No newline at end of file From 5f60134d1dbb1f14028537b2d1a5e936a8991efc Mon Sep 17 00:00:00 2001 From: David Kennedy Date: Thu, 7 Mar 2024 19:20:08 -0500 Subject: [PATCH 078/103] updated style on h2 --- src/registrar/assets/sass/_theme/_admin.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/registrar/assets/sass/_theme/_admin.scss b/src/registrar/assets/sass/_theme/_admin.scss index e53dc8b4b..fa3efb9a2 100644 --- a/src/registrar/assets/sass/_theme/_admin.scss +++ b/src/registrar/assets/sass/_theme/_admin.scss @@ -141,7 +141,7 @@ h1, h2, h3, font-weight: font-weight('bold'); } -#content h2 { +div#content > h2 { font-size: 1.3rem; } From d52c254c15e0430323389d1bdd74492fcb806677 Mon Sep 17 00:00:00 2001 From: Alysia Broddrick Date: Thu, 7 Mar 2024 16:33:41 -0800 Subject: [PATCH 079/103] updated workflow --- .github/workflows/test-deploy.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test-deploy.yaml b/.github/workflows/test-deploy.yaml index 1f3992280..310a5ba0a 100644 --- a/.github/workflows/test-deploy.yaml +++ b/.github/workflows/test-deploy.yaml @@ -28,6 +28,7 @@ jobs: deploy: runs-on: ubuntu-latest env: + ENVIRONMENT: ${{ needs.variables.outputs.environment }} CF_USERNAME: CF_${{ github.event.inputs.environment }}_USERNAME CF_PASSWORD: CF_${{ github.event.inputs.environment }}_PASSWORD steps: From 7d891f0d991ef9c9b07422f5a9b443a0dda351c6 Mon Sep 17 00:00:00 2001 From: Alysia Broddrick Date: Thu, 7 Mar 2024 16:45:12 -0800 Subject: [PATCH 080/103] added env --- .github/workflows/test-deploy.yaml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test-deploy.yaml b/.github/workflows/test-deploy.yaml index 310a5ba0a..af429738f 100644 --- a/.github/workflows/test-deploy.yaml +++ b/.github/workflows/test-deploy.yaml @@ -28,7 +28,6 @@ jobs: deploy: runs-on: ubuntu-latest env: - ENVIRONMENT: ${{ needs.variables.outputs.environment }} CF_USERNAME: CF_${{ github.event.inputs.environment }}_USERNAME CF_PASSWORD: CF_${{ github.event.inputs.environment }}_PASSWORD steps: @@ -38,5 +37,5 @@ jobs: cf_username: ${{ secrets[env.CF_USERNAME] }} cf_password: ${{ secrets[env.CF_PASSWORD] }} cf_org: cisa-dotgov - cf_space: ${{ env.ENVIRONMENT }} - cf_command: "push -f ops/manifests/manifest-${{ env.ENVIRONMENT }}.yaml --strategy rolling" \ No newline at end of file + cf_space: ${{ github.event.inputs.environment }} + cf_command: "push -f ops/manifests/manifest-${{ github.event.inputs.environment }}.yaml --strategy rolling" \ No newline at end of file From 47147abf72ddf3c9b6ca915d9898eb3c95b330d6 Mon Sep 17 00:00:00 2001 From: Rebecca Hsieh Date: Fri, 8 Mar 2024 10:55:40 -0800 Subject: [PATCH 081/103] Update from created at to submission date --- src/registrar/admin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index 92e477667..4b85b3f3a 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -942,7 +942,7 @@ class DomainApplicationAdmin(ListHeaderAdmin): "custom_election_board", "city", "state_territory", - "created_at", + "submission_date", #this is the right change "submitter", "investigator", ] From 139e7f11830f4a6b1fc8ee6be861cde205bb0b82 Mon Sep 17 00:00:00 2001 From: David Kennedy Date: Fri, 8 Mar 2024 14:45:02 -0500 Subject: [PATCH 082/103] remove .gov domain from domain form --- src/registrar/admin.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index f03fe6713..fb2ad50af 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -1,5 +1,6 @@ from datetime import date import logging +import copy from django import forms from django.db.models.functions import Concat, Coalesce @@ -1185,7 +1186,13 @@ class DomainInformationInline(admin.StackedInline): model = models.DomainInformation - fieldsets = DomainInformationAdmin.fieldsets + fieldsets = copy.deepcopy(DomainInformationAdmin.fieldsets) + # remove .gov domain from fieldset + for index, (title, _) in enumerate(fieldsets): + if title == ".gov domain": + del fieldsets[index] + break + analyst_readonly_fields = DomainInformationAdmin.analyst_readonly_fields # For each filter_horizontal, init in admin js extendFilterHorizontalWidgets # to activate the edit/delete/view buttons From feafc74d05aebc0969676cc4a6bc0a37703ec1bb Mon Sep 17 00:00:00 2001 From: Rebecca Hsieh Date: Fri, 8 Mar 2024 11:49:52 -0800 Subject: [PATCH 083/103] Remove comment --- src/registrar/admin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index 4b85b3f3a..5c24aaf79 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -942,7 +942,7 @@ class DomainApplicationAdmin(ListHeaderAdmin): "custom_election_board", "city", "state_territory", - "submission_date", #this is the right change + "submission_date", "submitter", "investigator", ] From 29e3275a87a18eac20449565672fbbae0c358f56 Mon Sep 17 00:00:00 2001 From: David Kennedy Date: Fri, 8 Mar 2024 14:52:01 -0500 Subject: [PATCH 084/103] satisfied linter --- src/registrar/admin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index fb2ad50af..eb88473f8 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -1188,7 +1188,7 @@ class DomainInformationInline(admin.StackedInline): fieldsets = copy.deepcopy(DomainInformationAdmin.fieldsets) # remove .gov domain from fieldset - for index, (title, _) in enumerate(fieldsets): + for index, (title, f) in enumerate(fieldsets): if title == ".gov domain": del fieldsets[index] break From d189fffa840451c924889ce4acb2da01869da195 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 8 Mar 2024 14:36:46 -0700 Subject: [PATCH 085/103] Add create group --- .../migrations/0074_create_groups_v08.py | 37 +++++++++++++++++++ .../views/utility/permission_views.py | 4 +- 2 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 src/registrar/migrations/0074_create_groups_v08.py diff --git a/src/registrar/migrations/0074_create_groups_v08.py b/src/registrar/migrations/0074_create_groups_v08.py new file mode 100644 index 000000000..0c28cee52 --- /dev/null +++ b/src/registrar/migrations/0074_create_groups_v08.py @@ -0,0 +1,37 @@ +# This migration creates the create_full_access_group and create_cisa_analyst_group groups +# It is dependent on 0035 (which populates ContentType and Permissions) +# If permissions on the groups need changing, edit CISA_ANALYST_GROUP_PERMISSIONS +# in the user_group model then: +# [NOT RECOMMENDED] +# step 1: docker-compose exec app ./manage.py migrate --fake registrar 0035_contenttypes_permissions +# step 2: docker-compose exec app ./manage.py migrate registrar 0036_create_groups +# step 3: fake run the latest migration in the migrations list +# [RECOMMENDED] +# Alternatively: +# step 1: duplicate the migration that loads data +# step 2: docker-compose exec app ./manage.py migrate + +from django.db import migrations +from registrar.models import UserGroup +from typing import Any + + +# For linting: RunPython expects a function reference, +# so let's give it one +def create_groups(apps, schema_editor) -> Any: + UserGroup.create_cisa_analyst_group(apps, schema_editor) + UserGroup.create_full_access_group(apps, schema_editor) + + +class Migration(migrations.Migration): + dependencies = [ + ("registrar", "0073_domainrequest_and_more"), + ] + + operations = [ + migrations.RunPython( + create_groups, + reverse_code=migrations.RunPython.noop, + atomic=True, + ), + ] diff --git a/src/registrar/views/utility/permission_views.py b/src/registrar/views/utility/permission_views.py index f2752c3b5..a30962e8f 100644 --- a/src/registrar/views/utility/permission_views.py +++ b/src/registrar/views/utility/permission_views.py @@ -66,7 +66,7 @@ class DomainRequestPermissionView(DomainRequestPermission, DetailView, abc.ABC): # DetailView property for what model this is viewing model = DomainRequest # variable name in template context for the model object - context_object_name = "DomainRequest" + context_object_name = "domainrequest" # Abstract property enforces NotImplementedError on an attribute. @property @@ -85,7 +85,7 @@ class DomainRequestPermissionWithdrawView(DomainRequestPermissionWithdraw, Detai # DetailView property for what model this is viewing model = DomainRequest # variable name in template context for the model object - context_object_name = "DomainRequest" + context_object_name = "domainrequest" # Abstract property enforces NotImplementedError on an attribute. @property From 9628c42dd61900493991f3a3bb4d54206965d736 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 8 Mar 2024 14:41:21 -0700 Subject: [PATCH 086/103] reversion --- src/registrar/views/utility/permission_views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/registrar/views/utility/permission_views.py b/src/registrar/views/utility/permission_views.py index a30962e8f..f2752c3b5 100644 --- a/src/registrar/views/utility/permission_views.py +++ b/src/registrar/views/utility/permission_views.py @@ -66,7 +66,7 @@ class DomainRequestPermissionView(DomainRequestPermission, DetailView, abc.ABC): # DetailView property for what model this is viewing model = DomainRequest # variable name in template context for the model object - context_object_name = "domainrequest" + context_object_name = "DomainRequest" # Abstract property enforces NotImplementedError on an attribute. @property @@ -85,7 +85,7 @@ class DomainRequestPermissionWithdrawView(DomainRequestPermissionWithdraw, Detai # DetailView property for what model this is viewing model = DomainRequest # variable name in template context for the model object - context_object_name = "domainrequest" + context_object_name = "DomainRequest" # Abstract property enforces NotImplementedError on an attribute. @property From d75cbf50e3268d4a69ec57ddc95b1c8b19bafd54 Mon Sep 17 00:00:00 2001 From: David Kennedy Date: Sat, 9 Mar 2024 06:41:10 -0500 Subject: [PATCH 087/103] merge changes --- src/registrar/admin.py | 2 +- src/registrar/assets/sass/_theme/_admin.scss | 4 ++ ...maininformation_other_contacts_and_more.py | 40 +++++++++++++++++++ 3 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 src/registrar/migrations/0075_alter_domaininformation_other_contacts_and_more.py diff --git a/src/registrar/admin.py b/src/registrar/admin.py index e877d8ef8..6e4e7f50f 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -777,7 +777,7 @@ class DomainInformationAdmin(ListHeaderAdmin): search_help_text = "Search by domain." fieldsets = [ - (None, {"fields": ["creator", "submitter", "domain_application", "notes"]}), + (None, {"fields": ["creator", "submitter", "domain_request", "notes"]}), (".gov domain", {"fields": ["domain"]}), ("Contacts", {"fields": ["authorizing_official", "other_contacts", "no_other_contacts_rationale"]}), ("Background info", {"fields": ["anything_else"]}), diff --git a/src/registrar/assets/sass/_theme/_admin.scss b/src/registrar/assets/sass/_theme/_admin.scss index 9c0d7517c..aba2ad9a3 100644 --- a/src/registrar/assets/sass/_theme/_admin.scss +++ b/src/registrar/assets/sass/_theme/_admin.scss @@ -143,6 +143,10 @@ h1, h2, h3, font-weight: font-weight('bold'); } +div#content > h2 { + font-size: 1.3rem; +} + .module h3 { padding: 0; color: var(--link-fg); diff --git a/src/registrar/migrations/0075_alter_domaininformation_other_contacts_and_more.py b/src/registrar/migrations/0075_alter_domaininformation_other_contacts_and_more.py new file mode 100644 index 000000000..53ad96ca4 --- /dev/null +++ b/src/registrar/migrations/0075_alter_domaininformation_other_contacts_and_more.py @@ -0,0 +1,40 @@ +# Generated by Django 4.2.10 on 2024-03-09 11:32 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("registrar", "0074_create_groups_v08"), + ] + + operations = [ + migrations.AlterField( + model_name="domaininformation", + name="other_contacts", + field=models.ManyToManyField( + blank=True, + related_name="contact_domain_requests_information", + to="registrar.contact", + verbose_name="Other employees", + ), + ), + migrations.AlterField( + model_name="domainrequest", + name="current_websites", + field=models.ManyToManyField( + blank=True, related_name="current+", to="registrar.website", verbose_name="Current websites" + ), + ), + migrations.AlterField( + model_name="domainrequest", + name="other_contacts", + field=models.ManyToManyField( + blank=True, + related_name="contact_domain_requests", + to="registrar.contact", + verbose_name="Other employees", + ), + ), + ] From b27318e9755990f48ccef75273200467e48753e6 Mon Sep 17 00:00:00 2001 From: David Kennedy Date: Sat, 9 Mar 2024 06:45:30 -0500 Subject: [PATCH 088/103] merge migrations --- ...inapplication_current_websites_and_more.py | 37 ------------------- 1 file changed, 37 deletions(-) delete mode 100644 src/registrar/migrations/0073_alter_domainapplication_current_websites_and_more.py diff --git a/src/registrar/migrations/0073_alter_domainapplication_current_websites_and_more.py b/src/registrar/migrations/0073_alter_domainapplication_current_websites_and_more.py deleted file mode 100644 index cefaba27c..000000000 --- a/src/registrar/migrations/0073_alter_domainapplication_current_websites_and_more.py +++ /dev/null @@ -1,37 +0,0 @@ -# Generated by Django 4.2.10 on 2024-03-07 17:42 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("registrar", "0072_alter_publiccontact_fax_alter_publiccontact_voice"), - ] - - operations = [ - migrations.AlterField( - model_name="domainapplication", - name="current_websites", - field=models.ManyToManyField( - blank=True, related_name="current+", to="registrar.website", verbose_name="Current websites" - ), - ), - migrations.AlterField( - model_name="domainapplication", - name="other_contacts", - field=models.ManyToManyField( - blank=True, related_name="contact_applications", to="registrar.contact", verbose_name="Other employees" - ), - ), - migrations.AlterField( - model_name="domaininformation", - name="other_contacts", - field=models.ManyToManyField( - blank=True, - related_name="contact_applications_information", - to="registrar.contact", - verbose_name="Other employees", - ), - ), - ] From a4822a069ec03951f58f86cf5b97d911026285fc Mon Sep 17 00:00:00 2001 From: Katherine-Osos <119689946+Katherine-Osos@users.noreply.github.com> Date: Mon, 11 Mar 2024 12:26:05 -0500 Subject: [PATCH 089/103] Update language around processing time --- src/registrar/templates/domain_request_done.html | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/registrar/templates/domain_request_done.html b/src/registrar/templates/domain_request_done.html index 6d7bf6f43..f45b507c3 100644 --- a/src/registrar/templates/domain_request_done.html +++ b/src/registrar/templates/domain_request_done.html @@ -19,15 +19,16 @@

Next steps in this process

-

We’ll review your request. This usually takes 20 business days. During - this review we’ll verify that:

+

We’ll review your request. This review period can take 30 business days. Due to the volume of requests, the wait time is longer than usual. We appreciate your patience.

+ +

During our review we’ll verify that:

  • Your organization is eligible for a .gov domain.
  • You work at the organization and/or can make requests on its behalf.
  • Your requested domain meets our naming requirements.
-

We’ll email you if we have questions and when we complete our review. You can check the status +

We’ll email you if we have questions. We’ll also email you as soon as we complete our review. You can check the status of your request at any time on the registrar homepage.

Contact us if you need help during this process.

From aea63d08ee3f4f35f625eef17a71f11952e7b236 Mon Sep 17 00:00:00 2001 From: Katherine-Osos <119689946+Katherine-Osos@users.noreply.github.com> Date: Mon, 11 Mar 2024 12:45:06 -0500 Subject: [PATCH 090/103] Update email language --- src/registrar/templates/emails/submission_confirmation.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/registrar/templates/emails/submission_confirmation.txt b/src/registrar/templates/emails/submission_confirmation.txt index 248d27d81..1009efc02 100644 --- a/src/registrar/templates/emails/submission_confirmation.txt +++ b/src/registrar/templates/emails/submission_confirmation.txt @@ -10,12 +10,14 @@ STATUS: Submitted ---------------------------------------------------------------- NEXT STEPS -We’ll review your request. This usually takes 20 business days. During this review we’ll verify that: +We’ll review your request. This review period can take 30 business days. Due to the volume of requests, the wait time is longer than usual. We appreciate your patience. + +During our review we’ll verify that: - Your organization is eligible for a .gov domain - You work at the organization and/or can make requests on its behalf - Your requested domain meets our naming requirements -We’ll email you if we have questions and when we complete our review. You can check the status of your request at any time on the registrar homepage. +We’ll email you if we have questions. We’ll also email you as soon as we complete our review. You can check the status of your request at any time on the registrar homepage. NEED TO MAKE CHANGES? From d83bd361cba26b8ddb81bd08c29b4b960005f4cd Mon Sep 17 00:00:00 2001 From: CocoByte Date: Mon, 11 Mar 2024 13:16:27 -0600 Subject: [PATCH 091/103] Fix migrations (rename domainApplication model instead of delete/create) --- .../migrations/0073_domainrequest_and_more.py | 685 ------------------ .../0073_rename_domainapplication.py | 16 + ...information_domain_application_and_more.py | 114 +++ ...roups_v08.py => 0075_create_groups_v08.py} | 2 +- 4 files changed, 131 insertions(+), 686 deletions(-) delete mode 100644 src/registrar/migrations/0073_domainrequest_and_more.py create mode 100644 src/registrar/migrations/0073_rename_domainapplication.py create mode 100644 src/registrar/migrations/0074_remove_domaininformation_domain_application_and_more.py rename src/registrar/migrations/{0074_create_groups_v08.py => 0075_create_groups_v08.py} (93%) diff --git a/src/registrar/migrations/0073_domainrequest_and_more.py b/src/registrar/migrations/0073_domainrequest_and_more.py deleted file mode 100644 index 88608b03a..000000000 --- a/src/registrar/migrations/0073_domainrequest_and_more.py +++ /dev/null @@ -1,685 +0,0 @@ -# Generated by Django 4.2.10 on 2024-03-07 21:52 - -from django.conf import settings -from django.db import migrations, models -import django.db.models.deletion -import django_fsm - - -class Migration(migrations.Migration): - - dependencies = [ - ("registrar", "0072_alter_publiccontact_fax_alter_publiccontact_voice"), - ] - - operations = [ - migrations.CreateModel( - name="DomainRequest", - fields=[ - ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), - ("created_at", models.DateTimeField(auto_now_add=True)), - ("updated_at", models.DateTimeField(auto_now=True)), - ( - "status", - django_fsm.FSMField( - choices=[ - ("started", "Started"), - ("submitted", "Submitted"), - ("in review", "In review"), - ("action needed", "Action needed"), - ("approved", "Approved"), - ("withdrawn", "Withdrawn"), - ("rejected", "Rejected"), - ("ineligible", "Ineligible"), - ], - default="started", - max_length=50, - ), - ), - ( - "rejection_reason", - models.TextField( - blank=True, - choices=[ - ("purpose_not_met", "Purpose requirements not met"), - ("requestor_not_eligible", "Requestor not eligible to make request"), - ("org_has_domain", "Org already has a .gov domain"), - ("contacts_not_verified", "Org contacts couldn't be verified"), - ("org_not_eligible", "Org not eligible for a .gov domain"), - ("naming_not_met", "Naming requirements not met"), - ("other", "Other/Unspecified"), - ], - null=True, - ), - ), - ( - "organization_type", - models.CharField( - blank=True, - choices=[ - ("federal", "Federal"), - ("interstate", "Interstate"), - ("state_or_territory", "State or territory"), - ("tribal", "Tribal"), - ("county", "County"), - ("city", "City"), - ("special_district", "Special district"), - ("school_district", "School district"), - ], - help_text="Type of organization", - max_length=255, - null=True, - ), - ), - ( - "federally_recognized_tribe", - models.BooleanField(help_text="Is the tribe federally recognized", null=True), - ), - ( - "state_recognized_tribe", - models.BooleanField(help_text="Is the tribe recognized by a state", null=True), - ), - ("tribe_name", models.CharField(blank=True, help_text="Name of tribe", null=True)), - ( - "federal_agency", - models.CharField( - blank=True, - choices=[ - ( - "Administrative Conference of the United States", - "Administrative Conference of the United States", - ), - ("Advisory Council on Historic Preservation", "Advisory Council on Historic Preservation"), - ("American Battle Monuments Commission", "American Battle Monuments Commission"), - ("AMTRAK", "AMTRAK"), - ("Appalachian Regional Commission", "Appalachian Regional Commission"), - ( - "Appraisal Subcommittee of the Federal Financial Institutions Examination Council", - "Appraisal Subcommittee of the Federal Financial Institutions Examination Council", - ), - ("Appraisal Subcommittee", "Appraisal Subcommittee"), - ("Architect of the Capitol", "Architect of the Capitol"), - ("Armed Forces Retirement Home", "Armed Forces Retirement Home"), - ( - "Barry Goldwater Scholarship and Excellence in Education Foundation", - "Barry Goldwater Scholarship and Excellence in Education Foundation", - ), - ( - "Barry Goldwater Scholarship and Excellence in Education Program", - "Barry Goldwater Scholarship and Excellence in Education Program", - ), - ("Central Intelligence Agency", "Central Intelligence Agency"), - ("Chemical Safety Board", "Chemical Safety Board"), - ( - "Christopher Columbus Fellowship Foundation", - "Christopher Columbus Fellowship Foundation", - ), - ( - "Civil Rights Cold Case Records Review Board", - "Civil Rights Cold Case Records Review Board", - ), - ( - "Commission for the Preservation of America's Heritage Abroad", - "Commission for the Preservation of America's Heritage Abroad", - ), - ("Commission of Fine Arts", "Commission of Fine Arts"), - ( - "Committee for Purchase From People Who Are Blind or Severely Disabled", - "Committee for Purchase From People Who Are Blind or Severely Disabled", - ), - ("Commodity Futures Trading Commission", "Commodity Futures Trading Commission"), - ("Congressional Budget Office", "Congressional Budget Office"), - ("Consumer Financial Protection Bureau", "Consumer Financial Protection Bureau"), - ("Consumer Product Safety Commission", "Consumer Product Safety Commission"), - ( - "Corporation for National & Community Service", - "Corporation for National & Community Service", - ), - ( - "Corporation for National and Community Service", - "Corporation for National and Community Service", - ), - ( - "Council of Inspectors General on Integrity and Efficiency", - "Council of Inspectors General on Integrity and Efficiency", - ), - ("Court Services and Offender Supervision", "Court Services and Offender Supervision"), - ("Cyberspace Solarium Commission", "Cyberspace Solarium Commission"), - ( - "DC Court Services and Offender Supervision Agency", - "DC Court Services and Offender Supervision Agency", - ), - ("DC Pre-trial Services", "DC Pre-trial Services"), - ("Defense Nuclear Facilities Safety Board", "Defense Nuclear Facilities Safety Board"), - ("Delta Regional Authority", "Delta Regional Authority"), - ("Denali Commission", "Denali Commission"), - ("Department of Agriculture", "Department of Agriculture"), - ("Department of Commerce", "Department of Commerce"), - ("Department of Defense", "Department of Defense"), - ("Department of Education", "Department of Education"), - ("Department of Energy", "Department of Energy"), - ("Department of Health and Human Services", "Department of Health and Human Services"), - ("Department of Homeland Security", "Department of Homeland Security"), - ( - "Department of Housing and Urban Development", - "Department of Housing and Urban Development", - ), - ("Department of Justice", "Department of Justice"), - ("Department of Labor", "Department of Labor"), - ("Department of State", "Department of State"), - ("Department of the Interior", "Department of the Interior"), - ("Department of the Treasury", "Department of the Treasury"), - ("Department of Transportation", "Department of Transportation"), - ("Department of Veterans Affairs", "Department of Veterans Affairs"), - ("Director of National Intelligence", "Director of National Intelligence"), - ("Dwight D. Eisenhower Memorial Commission", "Dwight D. Eisenhower Memorial Commission"), - ("Election Assistance Commission", "Election Assistance Commission"), - ("Environmental Protection Agency", "Environmental Protection Agency"), - ("Equal Employment Opportunity Commission", "Equal Employment Opportunity Commission"), - ("Executive Office of the President", "Executive Office of the President"), - ("Export-Import Bank of the United States", "Export-Import Bank of the United States"), - ("Export/Import Bank of the U.S.", "Export/Import Bank of the U.S."), - ("Farm Credit Administration", "Farm Credit Administration"), - ("Farm Credit System Insurance Corporation", "Farm Credit System Insurance Corporation"), - ("Federal Communications Commission", "Federal Communications Commission"), - ("Federal Deposit Insurance Corporation", "Federal Deposit Insurance Corporation"), - ("Federal Election Commission", "Federal Election Commission"), - ("Federal Energy Regulatory Commission", "Federal Energy Regulatory Commission"), - ( - "Federal Financial Institutions Examination Council", - "Federal Financial Institutions Examination Council", - ), - ("Federal Housing Finance Agency", "Federal Housing Finance Agency"), - ("Federal Judiciary", "Federal Judiciary"), - ("Federal Labor Relations Authority", "Federal Labor Relations Authority"), - ("Federal Maritime Commission", "Federal Maritime Commission"), - ( - "Federal Mediation and Conciliation Service", - "Federal Mediation and Conciliation Service", - ), - ( - "Federal Mine Safety and Health Review Commission", - "Federal Mine Safety and Health Review Commission", - ), - ( - "Federal Permitting Improvement Steering Council", - "Federal Permitting Improvement Steering Council", - ), - ("Federal Reserve Board of Governors", "Federal Reserve Board of Governors"), - ("Federal Reserve System", "Federal Reserve System"), - ("Federal Trade Commission", "Federal Trade Commission"), - ("General Services Administration", "General Services Administration"), - ("gov Administration", "gov Administration"), - ("Government Accountability Office", "Government Accountability Office"), - ("Government Publishing Office", "Government Publishing Office"), - ("Gulf Coast Ecosystem Restoration Council", "Gulf Coast Ecosystem Restoration Council"), - ("Harry S Truman Scholarship Foundation", "Harry S Truman Scholarship Foundation"), - ("Harry S. Truman Scholarship Foundation", "Harry S. Truman Scholarship Foundation"), - ("Institute of Museum and Library Services", "Institute of Museum and Library Services"), - ("Institute of Peace", "Institute of Peace"), - ("Inter-American Foundation", "Inter-American Foundation"), - ( - "International Boundary and Water Commission: United States and Mexico", - "International Boundary and Water Commission: United States and Mexico", - ), - ( - "International Boundary Commission: United States and Canada", - "International Boundary Commission: United States and Canada", - ), - ( - "International Joint Commission: United States and Canada", - "International Joint Commission: United States and Canada", - ), - ( - "James Madison Memorial Fellowship Foundation", - "James Madison Memorial Fellowship Foundation", - ), - ("Japan-United States Friendship Commission", "Japan-United States Friendship Commission"), - ("Japan-US Friendship Commission", "Japan-US Friendship Commission"), - ( - "John F. Kennedy Center for Performing Arts", - "John F. Kennedy Center for Performing Arts", - ), - ( - "John F. Kennedy Center for the Performing Arts", - "John F. Kennedy Center for the Performing Arts", - ), - ("Legal Services Corporation", "Legal Services Corporation"), - ("Legislative Branch", "Legislative Branch"), - ("Library of Congress", "Library of Congress"), - ("Marine Mammal Commission", "Marine Mammal Commission"), - ( - "Medicaid and CHIP Payment and Access Commission", - "Medicaid and CHIP Payment and Access Commission", - ), - ("Medical Payment Advisory Commission", "Medical Payment Advisory Commission"), - ("Medicare Payment Advisory Commission", "Medicare Payment Advisory Commission"), - ("Merit Systems Protection Board", "Merit Systems Protection Board"), - ("Millennium Challenge Corporation", "Millennium Challenge Corporation"), - ( - "Morris K. Udall and Stewart L. Udall Foundation", - "Morris K. Udall and Stewart L. Udall Foundation", - ), - ( - "National Aeronautics and Space Administration", - "National Aeronautics and Space Administration", - ), - ( - "National Archives and Records Administration", - "National Archives and Records Administration", - ), - ("National Capital Planning Commission", "National Capital Planning Commission"), - ("National Council on Disability", "National Council on Disability"), - ("National Credit Union Administration", "National Credit Union Administration"), - ("National Endowment for the Arts", "National Endowment for the Arts"), - ("National Endowment for the Humanities", "National Endowment for the Humanities"), - ( - "National Foundation on the Arts and the Humanities", - "National Foundation on the Arts and the Humanities", - ), - ("National Gallery of Art", "National Gallery of Art"), - ("National Indian Gaming Commission", "National Indian Gaming Commission"), - ("National Labor Relations Board", "National Labor Relations Board"), - ("National Mediation Board", "National Mediation Board"), - ("National Science Foundation", "National Science Foundation"), - ( - "National Security Commission on Artificial Intelligence", - "National Security Commission on Artificial Intelligence", - ), - ("National Transportation Safety Board", "National Transportation Safety Board"), - ( - "Networking Information Technology Research and Development", - "Networking Information Technology Research and Development", - ), - ("Non-Federal Agency", "Non-Federal Agency"), - ("Northern Border Regional Commission", "Northern Border Regional Commission"), - ("Nuclear Regulatory Commission", "Nuclear Regulatory Commission"), - ("Nuclear Safety Oversight Committee", "Nuclear Safety Oversight Committee"), - ("Nuclear Waste Technical Review Board", "Nuclear Waste Technical Review Board"), - ( - "Occupational Safety & Health Review Commission", - "Occupational Safety & Health Review Commission", - ), - ( - "Occupational Safety and Health Review Commission", - "Occupational Safety and Health Review Commission", - ), - ("Office of Compliance", "Office of Compliance"), - ("Office of Congressional Workplace Rights", "Office of Congressional Workplace Rights"), - ("Office of Government Ethics", "Office of Government Ethics"), - ( - "Office of Navajo and Hopi Indian Relocation", - "Office of Navajo and Hopi Indian Relocation", - ), - ("Office of Personnel Management", "Office of Personnel Management"), - ("Open World Leadership Center", "Open World Leadership Center"), - ("Overseas Private Investment Corporation", "Overseas Private Investment Corporation"), - ("Peace Corps", "Peace Corps"), - ("Pension Benefit Guaranty Corporation", "Pension Benefit Guaranty Corporation"), - ("Postal Regulatory Commission", "Postal Regulatory Commission"), - ("Presidio Trust", "Presidio Trust"), - ( - "Privacy and Civil Liberties Oversight Board", - "Privacy and Civil Liberties Oversight Board", - ), - ("Public Buildings Reform Board", "Public Buildings Reform Board"), - ( - "Public Defender Service for the District of Columbia", - "Public Defender Service for the District of Columbia", - ), - ("Railroad Retirement Board", "Railroad Retirement Board"), - ("Securities and Exchange Commission", "Securities and Exchange Commission"), - ("Selective Service System", "Selective Service System"), - ("Small Business Administration", "Small Business Administration"), - ("Smithsonian Institution", "Smithsonian Institution"), - ("Social Security Administration", "Social Security Administration"), - ("Social Security Advisory Board", "Social Security Advisory Board"), - ("Southeast Crescent Regional Commission", "Southeast Crescent Regional Commission"), - ("Southwest Border Regional Commission", "Southwest Border Regional Commission"), - ("State Justice Institute", "State Justice Institute"), - ("State, Local, and Tribal Government", "State, Local, and Tribal Government"), - ("Stennis Center for Public Service", "Stennis Center for Public Service"), - ("Surface Transportation Board", "Surface Transportation Board"), - ("Tennessee Valley Authority", "Tennessee Valley Authority"), - ("The Executive Office of the President", "The Executive Office of the President"), - ("The Intelligence Community", "The Intelligence Community"), - ("The Legislative Branch", "The Legislative Branch"), - ("The Supreme Court", "The Supreme Court"), - ( - "The United States World War One Centennial Commission", - "The United States World War One Centennial Commission", - ), - ("U.S. Access Board", "U.S. Access Board"), - ("U.S. Agency for Global Media", "U.S. Agency for Global Media"), - ("U.S. Agency for International Development", "U.S. Agency for International Development"), - ("U.S. Capitol Police", "U.S. Capitol Police"), - ("U.S. Chemical Safety Board", "U.S. Chemical Safety Board"), - ( - "U.S. China Economic and Security Review Commission", - "U.S. China Economic and Security Review Commission", - ), - ( - "U.S. Commission for the Preservation of Americas Heritage Abroad", - "U.S. Commission for the Preservation of Americas Heritage Abroad", - ), - ("U.S. Commission of Fine Arts", "U.S. Commission of Fine Arts"), - ("U.S. Commission on Civil Rights", "U.S. Commission on Civil Rights"), - ( - "U.S. Commission on International Religious Freedom", - "U.S. Commission on International Religious Freedom", - ), - ("U.S. Courts", "U.S. Courts"), - ("U.S. Department of Agriculture", "U.S. Department of Agriculture"), - ("U.S. Interagency Council on Homelessness", "U.S. Interagency Council on Homelessness"), - ("U.S. International Trade Commission", "U.S. International Trade Commission"), - ("U.S. Nuclear Waste Technical Review Board", "U.S. Nuclear Waste Technical Review Board"), - ("U.S. Office of Special Counsel", "U.S. Office of Special Counsel"), - ("U.S. Peace Corps", "U.S. Peace Corps"), - ("U.S. Postal Service", "U.S. Postal Service"), - ("U.S. Semiquincentennial Commission", "U.S. Semiquincentennial Commission"), - ("U.S. Trade and Development Agency", "U.S. Trade and Development Agency"), - ( - "U.S.-China Economic and Security Review Commission", - "U.S.-China Economic and Security Review Commission", - ), - ("Udall Foundation", "Udall Foundation"), - ("United States AbilityOne", "United States AbilityOne"), - ("United States Access Board", "United States Access Board"), - ( - "United States African Development Foundation", - "United States African Development Foundation", - ), - ("United States Agency for Global Media", "United States Agency for Global Media"), - ("United States Arctic Research Commission", "United States Arctic Research Commission"), - ( - "United States Global Change Research Program", - "United States Global Change Research Program", - ), - ("United States Holocaust Memorial Museum", "United States Holocaust Memorial Museum"), - ("United States Institute of Peace", "United States Institute of Peace"), - ( - "United States Interagency Council on Homelessness", - "United States Interagency Council on Homelessness", - ), - ( - "United States International Development Finance Corporation", - "United States International Development Finance Corporation", - ), - ( - "United States International Trade Commission", - "United States International Trade Commission", - ), - ("United States Postal Service", "United States Postal Service"), - ("United States Senate", "United States Senate"), - ( - "United States Trade and Development Agency", - "United States Trade and Development Agency", - ), - ( - "Utah Reclamation Mitigation and Conservation Commission", - "Utah Reclamation Mitigation and Conservation Commission", - ), - ("Vietnam Education Foundation", "Vietnam Education Foundation"), - ("Western Hemisphere Drug Policy Commission", "Western Hemisphere Drug Policy Commission"), - ( - "Woodrow Wilson International Center for Scholars", - "Woodrow Wilson International Center for Scholars", - ), - ("World War I Centennial Commission", "World War I Centennial Commission"), - ], - help_text="Federal agency", - null=True, - ), - ), - ( - "federal_type", - models.CharField( - blank=True, - choices=[("executive", "Executive"), ("judicial", "Judicial"), ("legislative", "Legislative")], - help_text="Federal government branch", - max_length=50, - null=True, - ), - ), - ( - "is_election_board", - models.BooleanField(blank=True, help_text="Is your organization an election office?", null=True), - ), - ( - "organization_name", - models.CharField(blank=True, db_index=True, help_text="Organization name", null=True), - ), - ( - "address_line1", - models.CharField(blank=True, help_text="Street address", null=True, verbose_name="Address line 1"), - ), - ( - "address_line2", - models.CharField( - blank=True, - help_text="Street address line 2 (optional)", - null=True, - verbose_name="Address line 2", - ), - ), - ("city", models.CharField(blank=True, help_text="City", null=True)), - ( - "state_territory", - models.CharField( - blank=True, - choices=[ - ("AL", "Alabama (AL)"), - ("AK", "Alaska (AK)"), - ("AS", "American Samoa (AS)"), - ("AZ", "Arizona (AZ)"), - ("AR", "Arkansas (AR)"), - ("CA", "California (CA)"), - ("CO", "Colorado (CO)"), - ("CT", "Connecticut (CT)"), - ("DE", "Delaware (DE)"), - ("DC", "District of Columbia (DC)"), - ("FL", "Florida (FL)"), - ("GA", "Georgia (GA)"), - ("GU", "Guam (GU)"), - ("HI", "Hawaii (HI)"), - ("ID", "Idaho (ID)"), - ("IL", "Illinois (IL)"), - ("IN", "Indiana (IN)"), - ("IA", "Iowa (IA)"), - ("KS", "Kansas (KS)"), - ("KY", "Kentucky (KY)"), - ("LA", "Louisiana (LA)"), - ("ME", "Maine (ME)"), - ("MD", "Maryland (MD)"), - ("MA", "Massachusetts (MA)"), - ("MI", "Michigan (MI)"), - ("MN", "Minnesota (MN)"), - ("MS", "Mississippi (MS)"), - ("MO", "Missouri (MO)"), - ("MT", "Montana (MT)"), - ("NE", "Nebraska (NE)"), - ("NV", "Nevada (NV)"), - ("NH", "New Hampshire (NH)"), - ("NJ", "New Jersey (NJ)"), - ("NM", "New Mexico (NM)"), - ("NY", "New York (NY)"), - ("NC", "North Carolina (NC)"), - ("ND", "North Dakota (ND)"), - ("MP", "Northern Mariana Islands (MP)"), - ("OH", "Ohio (OH)"), - ("OK", "Oklahoma (OK)"), - ("OR", "Oregon (OR)"), - ("PA", "Pennsylvania (PA)"), - ("PR", "Puerto Rico (PR)"), - ("RI", "Rhode Island (RI)"), - ("SC", "South Carolina (SC)"), - ("SD", "South Dakota (SD)"), - ("TN", "Tennessee (TN)"), - ("TX", "Texas (TX)"), - ("UM", "United States Minor Outlying Islands (UM)"), - ("UT", "Utah (UT)"), - ("VT", "Vermont (VT)"), - ("VI", "Virgin Islands (VI)"), - ("VA", "Virginia (VA)"), - ("WA", "Washington (WA)"), - ("WV", "West Virginia (WV)"), - ("WI", "Wisconsin (WI)"), - ("WY", "Wyoming (WY)"), - ("AA", "Armed Forces Americas (AA)"), - ("AE", "Armed Forces Africa, Canada, Europe, Middle East (AE)"), - ("AP", "Armed Forces Pacific (AP)"), - ], - help_text="State, territory, or military post", - max_length=2, - null=True, - ), - ), - ( - "zipcode", - models.CharField(blank=True, db_index=True, help_text="Zip code", max_length=10, null=True), - ), - ( - "urbanization", - models.CharField(blank=True, help_text="Urbanization (required for Puerto Rico only)", null=True), - ), - ( - "about_your_organization", - models.TextField(blank=True, help_text="Information about your organization", null=True), - ), - ("purpose", models.TextField(blank=True, help_text="Purpose of your domain", null=True)), - ( - "no_other_contacts_rationale", - models.TextField(blank=True, help_text="Reason for listing no additional contacts", null=True), - ), - ("anything_else", models.TextField(blank=True, help_text="Anything else?", null=True)), - ( - "is_policy_acknowledged", - models.BooleanField(blank=True, help_text="Acknowledged .gov acceptable use policy", null=True), - ), - ("submission_date", models.DateField(blank=True, default=None, help_text="Date submitted", null=True)), - ("notes", models.TextField(blank=True, help_text="Notes about this request", null=True)), - ( - "alternative_domains", - models.ManyToManyField(blank=True, related_name="alternatives+", to="registrar.website"), - ), - ( - "approved_domain", - models.OneToOneField( - blank=True, - help_text="The approved domain", - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="domain_request", - to="registrar.domain", - ), - ), - ( - "authorizing_official", - models.ForeignKey( - blank=True, - null=True, - on_delete=django.db.models.deletion.PROTECT, - related_name="authorizing_official", - to="registrar.contact", - ), - ), - ( - "creator", - models.ForeignKey( - on_delete=django.db.models.deletion.PROTECT, - related_name="domain_requests_created", - to=settings.AUTH_USER_MODEL, - ), - ), - ( - "current_websites", - models.ManyToManyField( - blank=True, related_name="current+", to="registrar.website", verbose_name="websites" - ), - ), - ( - "investigator", - models.ForeignKey( - blank=True, - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="domain_requests_investigating", - to=settings.AUTH_USER_MODEL, - ), - ), - ( - "other_contacts", - models.ManyToManyField( - blank=True, - related_name="contact_domain_requests", - to="registrar.contact", - verbose_name="contacts", - ), - ), - ( - "requested_domain", - models.OneToOneField( - blank=True, - help_text="The requested domain", - null=True, - on_delete=django.db.models.deletion.PROTECT, - related_name="domain_request", - to="registrar.draftdomain", - ), - ), - ( - "submitter", - models.ForeignKey( - blank=True, - null=True, - on_delete=django.db.models.deletion.PROTECT, - related_name="submitted_domain_requests", - to="registrar.contact", - ), - ), - ], - options={ - "abstract": False, - }, - ), - migrations.RemoveField( - model_name="domaininformation", - name="domain_application", - ), - migrations.AlterField( - model_name="domaininformation", - name="other_contacts", - field=models.ManyToManyField( - blank=True, - related_name="contact_domain_requests_information", - to="registrar.contact", - verbose_name="contacts", - ), - ), - migrations.AlterField( - model_name="domaininformation", - name="submitter", - field=models.ForeignKey( - blank=True, - null=True, - on_delete=django.db.models.deletion.PROTECT, - related_name="submitted_domain_requests_information", - to="registrar.contact", - ), - ), - migrations.DeleteModel( - name="DomainApplication", - ), - migrations.AddField( - model_name="domaininformation", - name="domain_request", - field=models.OneToOneField( - blank=True, - help_text="Associated domain request", - null=True, - on_delete=django.db.models.deletion.PROTECT, - related_name="DomainRequest_info", - to="registrar.domainrequest", - ), - ), - ] diff --git a/src/registrar/migrations/0073_rename_domainapplication.py b/src/registrar/migrations/0073_rename_domainapplication.py new file mode 100644 index 000000000..488111fab --- /dev/null +++ b/src/registrar/migrations/0073_rename_domainapplication.py @@ -0,0 +1,16 @@ +# Generated by Django 4.2.7 on 2024-01-29 22:21 + +from django.db import migrations + + +class Migration(migrations.Migration): + dependencies = [ + ("registrar", "0072_alter_publiccontact_fax_alter_publiccontact_voice"), + ] + + operations = [ + migrations.RenameModel( + old_name="DomainApplication", + new_name="DomainRequest", + ) + ] diff --git a/src/registrar/migrations/0074_remove_domaininformation_domain_application_and_more.py b/src/registrar/migrations/0074_remove_domaininformation_domain_application_and_more.py new file mode 100644 index 000000000..d654b0d1b --- /dev/null +++ b/src/registrar/migrations/0074_remove_domaininformation_domain_application_and_more.py @@ -0,0 +1,114 @@ +# Generated by Django 4.2.10 on 2024-03-11 19:12 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ("registrar", "0073_rename_domainapplication"), + ] + + operations = [ + migrations.RemoveField( + model_name="domaininformation", + name="domain_application", + ), + migrations.AddField( + model_name="domaininformation", + name="domain_request", + field=models.OneToOneField( + blank=True, + help_text="Associated domain request", + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name="DomainRequest_info", + to="registrar.domainrequest", + ), + ), + migrations.AlterField( + model_name="domaininformation", + name="other_contacts", + field=models.ManyToManyField( + blank=True, + related_name="contact_domain_requests_information", + to="registrar.contact", + verbose_name="contacts", + ), + ), + migrations.AlterField( + model_name="domaininformation", + name="submitter", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name="submitted_domain_requests_information", + to="registrar.contact", + ), + ), + migrations.AlterField( + model_name="domainrequest", + name="approved_domain", + field=models.OneToOneField( + blank=True, + help_text="The approved domain", + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="domain_request", + to="registrar.domain", + ), + ), + migrations.AlterField( + model_name="domainrequest", + name="creator", + field=models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + related_name="domain_requests_created", + to=settings.AUTH_USER_MODEL, + ), + ), + migrations.AlterField( + model_name="domainrequest", + name="investigator", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="domain_requests_investigating", + to=settings.AUTH_USER_MODEL, + ), + ), + migrations.AlterField( + model_name="domainrequest", + name="other_contacts", + field=models.ManyToManyField( + blank=True, related_name="contact_domain_requests", to="registrar.contact", verbose_name="contacts" + ), + ), + migrations.AlterField( + model_name="domainrequest", + name="requested_domain", + field=models.OneToOneField( + blank=True, + help_text="The requested domain", + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name="domain_request", + to="registrar.draftdomain", + ), + ), + migrations.AlterField( + model_name="domainrequest", + name="submitter", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name="submitted_domain_requests", + to="registrar.contact", + ), + ), + ] diff --git a/src/registrar/migrations/0074_create_groups_v08.py b/src/registrar/migrations/0075_create_groups_v08.py similarity index 93% rename from src/registrar/migrations/0074_create_groups_v08.py rename to src/registrar/migrations/0075_create_groups_v08.py index 0c28cee52..a8e70b88a 100644 --- a/src/registrar/migrations/0074_create_groups_v08.py +++ b/src/registrar/migrations/0075_create_groups_v08.py @@ -25,7 +25,7 @@ def create_groups(apps, schema_editor) -> Any: class Migration(migrations.Migration): dependencies = [ - ("registrar", "0073_domainrequest_and_more"), + ("registrar", "0074_remove_domaininformation_domain_application_and_more"), ] operations = [ From 5d41eae80178d5ab914de354640a7607a3f00b0e Mon Sep 17 00:00:00 2001 From: CocoByte Date: Tue, 12 Mar 2024 00:24:04 -0600 Subject: [PATCH 092/103] more fixes (works locally) --- ...ename_domaininformation_domain_application_and_more.py} | 7 ++++--- src/registrar/migrations/0075_create_groups_v08.py | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) rename src/registrar/migrations/{0074_remove_domaininformation_domain_application_and_more.py => 0074_rename_domaininformation_domain_application_and_more.py} (96%) diff --git a/src/registrar/migrations/0074_remove_domaininformation_domain_application_and_more.py b/src/registrar/migrations/0074_rename_domaininformation_domain_application_and_more.py similarity index 96% rename from src/registrar/migrations/0074_remove_domaininformation_domain_application_and_more.py rename to src/registrar/migrations/0074_rename_domaininformation_domain_application_and_more.py index d654b0d1b..b0309bfd9 100644 --- a/src/registrar/migrations/0074_remove_domaininformation_domain_application_and_more.py +++ b/src/registrar/migrations/0074_rename_domaininformation_domain_application_and_more.py @@ -12,11 +12,12 @@ class Migration(migrations.Migration): ] operations = [ - migrations.RemoveField( + migrations.RenameField( model_name="domaininformation", - name="domain_application", + old_name="domain_application", + new_name="domain_request", ), - migrations.AddField( + migrations.AlterField( model_name="domaininformation", name="domain_request", field=models.OneToOneField( diff --git a/src/registrar/migrations/0075_create_groups_v08.py b/src/registrar/migrations/0075_create_groups_v08.py index a8e70b88a..db07ffe78 100644 --- a/src/registrar/migrations/0075_create_groups_v08.py +++ b/src/registrar/migrations/0075_create_groups_v08.py @@ -25,7 +25,7 @@ def create_groups(apps, schema_editor) -> Any: class Migration(migrations.Migration): dependencies = [ - ("registrar", "0074_remove_domaininformation_domain_application_and_more"), + ("registrar", "0074_rename_domaininformation_domain_application_and_more"), ] operations = [ From d4ddd6bb38fac8d09b8d1008af8505de234ea0bc Mon Sep 17 00:00:00 2001 From: CocoByte Date: Tue, 12 Mar 2024 12:37:31 -0600 Subject: [PATCH 093/103] more fixes --- ...inapplication_approved_domain_and_more.py} | 135 +++++++++--------- .../0073_rename_domainapplication.py | 16 --- ...omainapplication_domainrequest_and_more.py | 22 +++ .../migrations/0075_create_groups_v08.py | 2 +- 4 files changed, 88 insertions(+), 87 deletions(-) rename src/registrar/migrations/{0074_rename_domaininformation_domain_application_and_more.py => 0073_alter_domainapplication_approved_domain_and_more.py} (84%) delete mode 100644 src/registrar/migrations/0073_rename_domainapplication.py create mode 100644 src/registrar/migrations/0074_rename_domainapplication_domainrequest_and_more.py diff --git a/src/registrar/migrations/0074_rename_domaininformation_domain_application_and_more.py b/src/registrar/migrations/0073_alter_domainapplication_approved_domain_and_more.py similarity index 84% rename from src/registrar/migrations/0074_rename_domaininformation_domain_application_and_more.py rename to src/registrar/migrations/0073_alter_domainapplication_approved_domain_and_more.py index b0309bfd9..1eacf0e56 100644 --- a/src/registrar/migrations/0074_rename_domaininformation_domain_application_and_more.py +++ b/src/registrar/migrations/0073_alter_domainapplication_approved_domain_and_more.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.10 on 2024-03-11 19:12 +# Generated by Django 4.2.10 on 2024-03-12 16:50 from django.conf import settings from django.db import migrations, models @@ -8,25 +8,82 @@ import django.db.models.deletion class Migration(migrations.Migration): dependencies = [ - ("registrar", "0073_rename_domainapplication"), + ("registrar", "0072_alter_publiccontact_fax_alter_publiccontact_voice"), ] operations = [ - migrations.RenameField( - model_name="domaininformation", - old_name="domain_application", - new_name="domain_request", + migrations.AlterField( + model_name="domainapplication", + name="approved_domain", + field=models.OneToOneField( + blank=True, + help_text="The approved domain", + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="domain_request", + to="registrar.domain", + ), + ), + migrations.AlterField( + model_name="domainapplication", + name="creator", + field=models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, + related_name="domain_requests_created", + to=settings.AUTH_USER_MODEL, + ), + ), + migrations.AlterField( + model_name="domainapplication", + name="investigator", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="domain_requests_investigating", + to=settings.AUTH_USER_MODEL, + ), + ), + migrations.AlterField( + model_name="domainapplication", + name="other_contacts", + field=models.ManyToManyField( + blank=True, related_name="contact_domain_requests", to="registrar.contact", verbose_name="contacts" + ), + ), + migrations.AlterField( + model_name="domainapplication", + name="requested_domain", + field=models.OneToOneField( + blank=True, + help_text="The requested domain", + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name="domain_request", + to="registrar.draftdomain", + ), + ), + migrations.AlterField( + model_name="domainapplication", + name="submitter", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.PROTECT, + related_name="submitted_domain_requests", + to="registrar.contact", + ), ), migrations.AlterField( model_name="domaininformation", - name="domain_request", + name="domain_application", field=models.OneToOneField( blank=True, help_text="Associated domain request", null=True, on_delete=django.db.models.deletion.PROTECT, related_name="DomainRequest_info", - to="registrar.domainrequest", + to="registrar.domainapplication", ), ), migrations.AlterField( @@ -50,66 +107,4 @@ class Migration(migrations.Migration): to="registrar.contact", ), ), - migrations.AlterField( - model_name="domainrequest", - name="approved_domain", - field=models.OneToOneField( - blank=True, - help_text="The approved domain", - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="domain_request", - to="registrar.domain", - ), - ), - migrations.AlterField( - model_name="domainrequest", - name="creator", - field=models.ForeignKey( - on_delete=django.db.models.deletion.PROTECT, - related_name="domain_requests_created", - to=settings.AUTH_USER_MODEL, - ), - ), - migrations.AlterField( - model_name="domainrequest", - name="investigator", - field=models.ForeignKey( - blank=True, - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="domain_requests_investigating", - to=settings.AUTH_USER_MODEL, - ), - ), - migrations.AlterField( - model_name="domainrequest", - name="other_contacts", - field=models.ManyToManyField( - blank=True, related_name="contact_domain_requests", to="registrar.contact", verbose_name="contacts" - ), - ), - migrations.AlterField( - model_name="domainrequest", - name="requested_domain", - field=models.OneToOneField( - blank=True, - help_text="The requested domain", - null=True, - on_delete=django.db.models.deletion.PROTECT, - related_name="domain_request", - to="registrar.draftdomain", - ), - ), - migrations.AlterField( - model_name="domainrequest", - name="submitter", - field=models.ForeignKey( - blank=True, - null=True, - on_delete=django.db.models.deletion.PROTECT, - related_name="submitted_domain_requests", - to="registrar.contact", - ), - ), ] diff --git a/src/registrar/migrations/0073_rename_domainapplication.py b/src/registrar/migrations/0073_rename_domainapplication.py deleted file mode 100644 index 488111fab..000000000 --- a/src/registrar/migrations/0073_rename_domainapplication.py +++ /dev/null @@ -1,16 +0,0 @@ -# Generated by Django 4.2.7 on 2024-01-29 22:21 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("registrar", "0072_alter_publiccontact_fax_alter_publiccontact_voice"), - ] - - operations = [ - migrations.RenameModel( - old_name="DomainApplication", - new_name="DomainRequest", - ) - ] diff --git a/src/registrar/migrations/0074_rename_domainapplication_domainrequest_and_more.py b/src/registrar/migrations/0074_rename_domainapplication_domainrequest_and_more.py new file mode 100644 index 000000000..2dae12340 --- /dev/null +++ b/src/registrar/migrations/0074_rename_domainapplication_domainrequest_and_more.py @@ -0,0 +1,22 @@ +# Generated by Django 4.2.10 on 2024-03-12 16:53 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("registrar", "0073_alter_domainapplication_approved_domain_and_more"), + ] + + operations = [ + migrations.RenameModel( + old_name="DomainApplication", + new_name="DomainRequest", + ), + migrations.RenameField( + model_name="domaininformation", + old_name="domain_application", + new_name="domain_request", + ), + ] diff --git a/src/registrar/migrations/0075_create_groups_v08.py b/src/registrar/migrations/0075_create_groups_v08.py index db07ffe78..b0b2ed740 100644 --- a/src/registrar/migrations/0075_create_groups_v08.py +++ b/src/registrar/migrations/0075_create_groups_v08.py @@ -25,7 +25,7 @@ def create_groups(apps, schema_editor) -> Any: class Migration(migrations.Migration): dependencies = [ - ("registrar", "0074_rename_domaininformation_domain_application_and_more"), + ("registrar", "0074_rename_domainapplication_domainrequest_and_more"), ] operations = [ From ca1a79a97f2c1f858ae4b1f49ecfe094bc531ec1 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 12 Mar 2024 15:35:39 -0600 Subject: [PATCH 094/103] Update fixtures_domain_requests.py --- src/registrar/fixtures_domain_requests.py | 27 ++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/src/registrar/fixtures_domain_requests.py b/src/registrar/fixtures_domain_requests.py index a78bdd1ab..a37e29d6b 100644 --- a/src/registrar/fixtures_domain_requests.py +++ b/src/registrar/fixtures_domain_requests.py @@ -1,6 +1,7 @@ import logging import random from faker import Faker +from django.db import transaction from registrar.models import ( User, @@ -184,6 +185,14 @@ class DomainRequestFixture: logger.warning(e) return + # Lumped under .atomic to ensure we don't make redundant DB calls. + # This bundles them all together, and then saves it in a single call. + with transaction.atomic(): + cls._create_domain_requests(users) + + @classmethod + def _create_domain_requests(cls, users): + """Creates DomainRequests given a list of users""" for user in users: logger.debug("Loading domain requests for %s" % user) for app in cls.DA: @@ -211,8 +220,16 @@ class DomainFixture(DomainRequestFixture): logger.warning(e) return + # Lumped under .atomic to ensure we don't make redundant DB calls. + # This bundles them all together, and then saves it in a single call. + with transaction.atomic(): + # approve each user associated with `in review` status domains + DomainFixture._approve_domain_requests(users) + + @staticmethod + def _approve_domain_requests(users): + """Approves all provided domain requests if they are in the state in_review""" for user in users: - # approve one of each users in review status domains domain_request = DomainRequest.objects.filter( creator=user, status=DomainRequest.DomainRequestStatus.IN_REVIEW ).last() @@ -220,5 +237,13 @@ class DomainFixture(DomainRequestFixture): # We don't want fixtures sending out real emails to # fake email addresses, so we just skip that and log it instead + + # All approvals require an investigator, so if there is none, + # assign one. + if domain_request.investigator is None: + # All "users" in fixtures have admin perms per prior config. + # No need to check for that. + domain_request.investigator = random.choice(users) # nosec + domain_request.approve(send_email=False) domain_request.save() From a5a3c13653905ae19e9f788229876c4bf311cf49 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 12 Mar 2024 15:47:30 -0600 Subject: [PATCH 095/103] Merge conflictts pt 1 --- src/registrar/admin.py | 22 +++++------ src/registrar/models/domain_request.py | 54 +++++++++++++------------- src/registrar/tests/common.py | 8 ++-- src/registrar/tests/test_models.py | 32 +++++++-------- 4 files changed, 58 insertions(+), 58 deletions(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index a7871d5c6..7dc13df17 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -139,17 +139,17 @@ class DomainRequestAdminForm(forms.ModelForm): # We only care about investigator when in these statuses checked_statuses = [ - DomainApplication.ApplicationStatus.APPROVED, - DomainApplication.ApplicationStatus.IN_REVIEW, - DomainApplication.ApplicationStatus.ACTION_NEEDED, - DomainApplication.ApplicationStatus.REJECTED, - DomainApplication.ApplicationStatus.INELIGIBLE, + DomainRequest.DomainRequestStatus.APPROVED, + DomainRequest.DomainRequestStatus.IN_REVIEW, + DomainRequest.DomainRequestStatus.ACTION_NEEDED, + DomainRequest.DomainRequestStatus.REJECTED, + DomainRequest.DomainRequestStatus.INELIGIBLE, ] # If a status change occured, check for validity if status != initial_status and status in checked_statuses: # Checks the "investigators" field for validity. - # That field must obey certain conditions when an application is approved. + # That field must obey certain conditions when an domain_request is approved. # Will call "add_error" if any issues are found. self._check_for_valid_investigator(investigator) @@ -1163,7 +1163,7 @@ class DomainRequestAdmin(ListHeaderAdmin): # == Handle non-status changes == # - # Get the original application from the database. + # Get the original domain_request from the database. original_obj = models.DomainRequest.objects.get(pk=obj.pk) if obj.status == original_obj.status: # If the status hasn't changed, let the base function take care of it @@ -1203,9 +1203,9 @@ class DomainRequestAdmin(ListHeaderAdmin): should_proceed = False return should_proceed - application_is_not_approved = obj.status != models.DomainRequest.DomainRequestStatus.APPROVED - if application_is_not_approved and not obj.domain_is_not_active(): - # If an admin tried to set an approved application to + request_is_not_approved = obj.status != models.DomainRequest.DomainRequestStatus.APPROVED + if request_is_not_approved and not obj.domain_is_not_active(): + # If an admin tried to set an approved domain_request to # another status and the related domain is already # active, shortcut the action and throw a friendly # error message. This action would still not go through @@ -1248,7 +1248,7 @@ class DomainRequestAdmin(ListHeaderAdmin): return (obj, should_proceed) def get_status_method_mapping(self, domain_request): - """Returns what method should be ran given an application object""" + """Returns what method should be ran given an DomainRequest object""" # Define a per-object mapping status_method_mapping = { models.DomainRequest.DomainRequestStatus.STARTED: None, diff --git a/src/registrar/models/domain_request.py b/src/registrar/models/domain_request.py index 4a20514a7..4f7e79c39 100644 --- a/src/registrar/models/domain_request.py +++ b/src/registrar/models/domain_request.py @@ -9,7 +9,7 @@ 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 registrar.utility.errors import FSMdomain_requestError, FSMErrorCodes +from registrar.utility.errors import FSMApplicationError, FSMErrorCodes from .utility.time_stamped_model import TimeStampedModel from ..utility.email import send_templated_email, EmailSendingError @@ -19,7 +19,7 @@ logger = logging.getLogger(__name__) class DomainRequest(TimeStampedModel): - """A registrant's request for a new domain.""" + """A registrant's domain request for a new domain.""" # Constants for choice fields class DomainRequestStatus(models.TextChoices): @@ -116,7 +116,7 @@ class DomainRequest(TimeStampedModel): class OrganizationChoicesVerbose(models.TextChoices): """ Secondary organization choices - For use in the domain_request form and on the templates + For use in the domain request form and on the templates Keys need to match OrganizationChoices """ @@ -367,7 +367,7 @@ class DomainRequest(TimeStampedModel): NAMING_REQUIREMENTS = "naming_not_met", "Naming requirements not met" OTHER = "other", "Other/Unspecified" - # #### Internal fields about the domain_request ##### + # #### Internal fields about the domain request ##### status = FSMField( choices=DomainRequestStatus.choices, # possible states as an array of constants default=DomainRequestStatus.STARTED, # sensible default @@ -380,7 +380,7 @@ class DomainRequest(TimeStampedModel): blank=True, ) - # This is the domain_request user who created this domain_request. The contact + # This is the domain request user who created this domain request. The contact # information that they gave is in the `submitter` field creator = models.ForeignKey( "registrar.User", @@ -500,7 +500,7 @@ class DomainRequest(TimeStampedModel): on_delete=models.PROTECT, ) - # "+" means no reverse relation to lookup domain_requests from Website + # "+" means no reverse relation to lookup domain requests from Website current_websites = models.ManyToManyField( "registrar.Website", blank=True, @@ -513,7 +513,7 @@ class DomainRequest(TimeStampedModel): null=True, blank=True, help_text="The approved domain", - related_name="domain_domain_request", + related_name="domain_request", on_delete=models.SET_NULL, ) @@ -522,7 +522,7 @@ class DomainRequest(TimeStampedModel): null=True, blank=True, help_text="The requested domain", - related_name="domain_domain_request", + related_name="domain_request", on_delete=models.PROTECT, ) alternative_domains = models.ManyToManyField( @@ -531,8 +531,8 @@ class DomainRequest(TimeStampedModel): related_name="alternatives+", ) - # This is the contact information provided by the applicant. The - # domain_request user who created it is in the `creator` field. + # This is the contact information provided by the domain requestor. The + # user who created the domain request is in the `creator` field. submitter = models.ForeignKey( "registrar.Contact", null=True, @@ -572,7 +572,7 @@ class DomainRequest(TimeStampedModel): help_text="Acknowledged .gov acceptable use policy", ) - # submission date records when domain_request is submitted + # submission date records when domain request is submitted submission_date = models.DateField( null=True, blank=True, @@ -591,7 +591,7 @@ class DomainRequest(TimeStampedModel): if self.requested_domain and self.requested_domain.name: return self.requested_domain.name else: - return f"{self.status} domain_request created by {self.creator}" + return f"{self.status} domain request created by {self.creator}" except Exception: return "" @@ -665,7 +665,7 @@ class DomainRequest(TimeStampedModel): target=DomainRequestStatus.SUBMITTED, ) def submit(self): - """Submit an domain_request that is started. + """Submit an domain request that is started. As a side effect, an email notification is sent.""" @@ -713,7 +713,7 @@ class DomainRequest(TimeStampedModel): conditions=[domain_is_not_active, investigator_exists_and_is_staff], ) def in_review(self): - """Investigate an domain_request that has been submitted. + """Investigate an domain request that has been submitted. This action is logged. @@ -745,7 +745,7 @@ class DomainRequest(TimeStampedModel): conditions=[domain_is_not_active, investigator_exists_and_is_staff], ) def action_needed(self): - """Send back an domain_request that is under investigation or rejected. + """Send back an domain request that is under investigation or rejected. This action is logged. @@ -783,7 +783,7 @@ class DomainRequest(TimeStampedModel): This has substantial side-effects because it creates another database object for the approved Domain and makes the user who created the - domain_request into an admin on that domain. It also triggers an email + domain request into an admin on that domain. It also triggers an email notification.""" # create the domain @@ -791,7 +791,7 @@ class DomainRequest(TimeStampedModel): # == Check that the domain_request is valid == # if Domain.objects.filter(name=self.requested_domain.name).exists(): - raise FSMdomain_requestError(code=FSMErrorCodes.APPROVE_DOMAIN_IN_USE) + raise FSMApplicationError(code=FSMErrorCodes.APPROVE_DOMAIN_IN_USE) # == Create the domain and related components == # created_domain = Domain.objects.create(name=self.requested_domain.name) @@ -799,7 +799,7 @@ class DomainRequest(TimeStampedModel): # copy the information from DomainRequest into domaininformation DomainInformation = apps.get_model("registrar.DomainInformation") - DomainInformation.create_from_da(domain_domain_request=self, domain=created_domain) + DomainInformation.create_from_da(domain_request=self, domain=created_domain) # create the permission for the user UserDomainRole = apps.get_model("registrar.UserDomainRole") @@ -812,7 +812,7 @@ class DomainRequest(TimeStampedModel): # == Send out an email == # self._send_status_update_email( - "domain_request approved", + "domain request approved", "emails/status_change_approved.txt", "emails/status_change_approved_subject.txt", send_email, @@ -824,7 +824,7 @@ class DomainRequest(TimeStampedModel): target=DomainRequestStatus.WITHDRAWN, ) def withdraw(self): - """Withdraw an domain_request that has been submitted.""" + """Withdraw an domain request that has been submitted.""" self._send_status_update_email( "withdraw", @@ -839,7 +839,7 @@ class DomainRequest(TimeStampedModel): conditions=[domain_is_not_active, investigator_exists_and_is_staff], ) def reject(self): - """Reject an domain_request that has been submitted. + """Reject an domain request that has been submitted. As side effects this will delete the domain and domain_information (will cascade), and send an email notification.""" @@ -868,7 +868,7 @@ class DomainRequest(TimeStampedModel): """The applicant is a bad actor, reject with prejudice. No email As a side effect, but we block the applicant from editing - any existing domains/domain_requests and from submitting new aplications. + any existing domains/domain requests and from submitting new aplications. We do this by setting an ineligible status on the user, which the permissions classes test against. This will also delete the domain and domain_information (will cascade) when they exist.""" @@ -881,7 +881,7 @@ class DomainRequest(TimeStampedModel): # ## Form policies ### # # These methods control what questions need to be answered by applicants - # during the domain_request flow. They are policies about the domain_request so + # during the domain request flow. They are policies about the domain request so # they appear here. def show_organization_federal(self) -> bool: @@ -917,15 +917,15 @@ class DomainRequest(TimeStampedModel): ] def has_rationale(self) -> bool: - """Does this domain_request have no_other_contacts_rationale?""" + """Does this domain request have no_other_contacts_rationale?""" return bool(self.no_other_contacts_rationale) def has_other_contacts(self) -> bool: - """Does this domain_request have other contacts listed?""" + """Does this domain request have other contacts listed?""" return self.other_contacts.exists() def is_federal(self) -> Union[bool, None]: - """Is this domain_request for a federal agency? + """Is this domain request for a federal agency? organization_type can be both null and blank, """ @@ -957,4 +957,4 @@ class DomainRequest(TimeStampedModel): data[field.name] = field.value_from_object(self) for field in opts.many_to_many: data[field.name] = field.value_from_object(self) - return data \ No newline at end of file + return data diff --git a/src/registrar/tests/common.py b/src/registrar/tests/common.py index 13f15a6d0..587935d54 100644 --- a/src/registrar/tests/common.py +++ b/src/registrar/tests/common.py @@ -599,11 +599,11 @@ def completed_domain_request( return domain_request -def set_domain_request_investigators(application_list: list[DomainRequest], investigator_user: User): +def set_domain_request_investigators(domain_request_list: list[DomainRequest], investigator_user: User): """Helper method that sets the investigator field of all provided domain_requests""" - for application in application_list: - application.investigator = investigator_user - application.save() + for request in domain_request_list: + request.investigator = investigator_user + request.save() def multiple_unalphabetical_domain_objects( diff --git a/src/registrar/tests/test_models.py b/src/registrar/tests/test_models.py index b46676e26..7956b5dc0 100644 --- a/src/registrar/tests/test_models.py +++ b/src/registrar/tests/test_models.py @@ -52,8 +52,8 @@ class TestDomainRequest(TestCase): status=DomainRequest.DomainRequestStatus.INELIGIBLE, name="ineligible.gov" ) - # Store all application statuses in a variable for ease of use - self.all_applications = [ + # Store all domain request statuses in a variable for ease of use + self.all_domain_requests = [ self.started_domain_request, self.submitted_domain_request, self.in_review_domain_request, @@ -269,7 +269,7 @@ class TestDomainRequest(TestCase): ] # Set all investigators to none - set_domain_request_investigators(self.all_applications, None) + set_domain_request_investigators(self.all_domain_requests, None) self.assert_fsm_transition_does_not_raise_error(test_cases, "submit") @@ -286,7 +286,7 @@ class TestDomainRequest(TestCase): # Set all investigators to a user with no staff privs user, _ = User.objects.get_or_create(username="pancakesyrup", is_staff=False) - set_domain_request_investigators(self.all_applications, user) + set_domain_request_investigators(self.all_domain_requests, user) self.assert_fsm_transition_does_not_raise_error(test_cases, "submit") @@ -363,7 +363,7 @@ class TestDomainRequest(TestCase): ] # Set all investigators to none - set_domain_request_investigators(self.all_applications, None) + set_domain_request_investigators(self.all_domain_requests, None) self.assert_fsm_transition_raises_error(test_cases, "in_review") @@ -382,7 +382,7 @@ class TestDomainRequest(TestCase): # Set all investigators to a user with no staff privs user, _ = User.objects.get_or_create(username="pancakesyrup", is_staff=False) - set_applications_investigators(self.all_applications, user) + set_applications_investigators(self.all_domain_requests, user) self.assert_fsm_transition_raises_error(test_cases, "in_review") @@ -424,7 +424,7 @@ class TestDomainRequest(TestCase): ] # Set all investigators to none - set_domain_request_investigators(self.all_applications, None) + set_domain_request_investigators(self.all_domain_requests, None) self.assert_fsm_transition_raises_error(test_cases, "action_needed") @@ -442,7 +442,7 @@ class TestDomainRequest(TestCase): # Set all investigators to a user with no staff privs user, _ = User.objects.get_or_create(username="pancakesyrup", is_staff=False) - set_applications_investigators(self.all_applications, user) + set_applications_investigators(self.all_domain_requests, user) self.assert_fsm_transition_raises_error(test_cases, "action_needed") @@ -484,7 +484,7 @@ class TestDomainRequest(TestCase): ] # Set all investigators to none - set_domain_request_investigators(self.all_applications, None) + set_domain_request_investigators(self.all_domain_requests, None) self.assert_fsm_transition_raises_error(test_cases, "approve") @@ -501,7 +501,7 @@ class TestDomainRequest(TestCase): # Set all investigators to a user with no staff privs user, _ = User.objects.get_or_create(username="pancakesyrup", is_staff=False) - set_applications_investigators(self.all_applications, user) + set_applications_investigators(self.all_domain_requests, user) self.assert_fsm_transition_raises_error(test_cases, "approve") @@ -555,7 +555,7 @@ class TestDomainRequest(TestCase): ] # Set all investigators to none - set_domain_request_investigators(self.all_applications, None) + set_domain_request_investigators(self.all_domain_requests, None) self.assert_fsm_transition_does_not_raise_error(test_cases, "withdraw") @@ -573,7 +573,7 @@ class TestDomainRequest(TestCase): # Set all investigators to a user with no staff privs user, _ = User.objects.get_or_create(username="pancakesyrup", is_staff=False) - set_applications_investigators(self.all_applications, user) + set_applications_investigators(self.all_domain_requests, user) self.assert_fsm_transition_does_not_raise_error(test_cases, "withdraw") @@ -615,7 +615,7 @@ class TestDomainRequest(TestCase): ] # Set all investigators to none - set_domain_request_investigators(self.all_applications, None) + set_domain_request_investigators(self.all_domain_requests, None) self.assert_fsm_transition_raises_error(test_cases, "reject") @@ -632,7 +632,7 @@ class TestDomainRequest(TestCase): # Set all investigators to a user with no staff privs user, _ = User.objects.get_or_create(username="pancakesyrup", is_staff=False) - set_applications_investigators(self.all_applications, user) + set_applications_investigators(self.all_domain_requests, user) self.assert_fsm_transition_raises_error(test_cases, "reject") @@ -676,7 +676,7 @@ class TestDomainRequest(TestCase): ] # Set all investigators to none - set_domain_request_investigators(self.all_applications, None) + set_domain_request_investigators(self.all_domain_requests, None) self.assert_fsm_transition_raises_error(test_cases, "reject_with_prejudice") @@ -694,7 +694,7 @@ class TestDomainRequest(TestCase): # Set all investigators to a user with no staff privs user, _ = User.objects.get_or_create(username="pancakesyrup", is_staff=False) - set_applications_investigators(self.all_applications, user) + set_applications_investigators(self.all_domain_requests, user) self.assert_fsm_transition_raises_error(test_cases, "reject_with_prejudice") From 5661174a2dc6b6bff916d35e93247d349e4695e6 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 12 Mar 2024 15:48:46 -0600 Subject: [PATCH 096/103] Update admin.py --- src/registrar/admin.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index 7dc13df17..b321b9107 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -149,7 +149,7 @@ class DomainRequestAdminForm(forms.ModelForm): # If a status change occured, check for validity if status != initial_status and status in checked_statuses: # Checks the "investigators" field for validity. - # That field must obey certain conditions when an domain_request is approved. + # That field must obey certain conditions when an domain request is approved. # Will call "add_error" if any issues are found. self._check_for_valid_investigator(investigator) @@ -1163,7 +1163,7 @@ class DomainRequestAdmin(ListHeaderAdmin): # == Handle non-status changes == # - # Get the original domain_request from the database. + # Get the original domain request from the database. original_obj = models.DomainRequest.objects.get(pk=obj.pk) if obj.status == original_obj.status: # If the status hasn't changed, let the base function take care of it @@ -1205,7 +1205,7 @@ class DomainRequestAdmin(ListHeaderAdmin): request_is_not_approved = obj.status != models.DomainRequest.DomainRequestStatus.APPROVED if request_is_not_approved and not obj.domain_is_not_active(): - # If an admin tried to set an approved domain_request to + # If an admin tried to set an approved domain request to # another status and the related domain is already # active, shortcut the action and throw a friendly # error message. This action would still not go through @@ -1248,7 +1248,7 @@ class DomainRequestAdmin(ListHeaderAdmin): return (obj, should_proceed) def get_status_method_mapping(self, domain_request): - """Returns what method should be ran given an DomainRequest object""" + """Returns what method should be ran given an domain request object""" # Define a per-object mapping status_method_mapping = { models.DomainRequest.DomainRequestStatus.STARTED: None, From 0f0ce6be53d488568e6b2070127791de55777016 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 12 Mar 2024 15:54:03 -0600 Subject: [PATCH 097/103] Additional merge conflicts --- src/registrar/models/domain_request.py | 2 +- src/registrar/tests/common.py | 2 +- src/registrar/tests/test_models.py | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/registrar/models/domain_request.py b/src/registrar/models/domain_request.py index 4f7e79c39..2282af726 100644 --- a/src/registrar/models/domain_request.py +++ b/src/registrar/models/domain_request.py @@ -777,7 +777,7 @@ class DomainRequest(TimeStampedModel): conditions=[investigator_exists_and_is_staff], ) def approve(self, send_email=True): - """Approve an domain_request that has been submitted. + """Approve an domain request that has been submitted. This action cleans up the rejection status if moving away from rejected. diff --git a/src/registrar/tests/common.py b/src/registrar/tests/common.py index 587935d54..f5ba815f4 100644 --- a/src/registrar/tests/common.py +++ b/src/registrar/tests/common.py @@ -600,7 +600,7 @@ def completed_domain_request( return domain_request def set_domain_request_investigators(domain_request_list: list[DomainRequest], investigator_user: User): - """Helper method that sets the investigator field of all provided domain_requests""" + """Helper method that sets the investigator field of all provided domain requests""" for request in domain_request_list: request.investigator = investigator_user request.save() diff --git a/src/registrar/tests/test_models.py b/src/registrar/tests/test_models.py index 7956b5dc0..de6d021d9 100644 --- a/src/registrar/tests/test_models.py +++ b/src/registrar/tests/test_models.py @@ -245,11 +245,11 @@ class TestDomainRequest(TestCase): def assert_fsm_transition_does_not_raise_error(self, test_cases, method_to_run): """Given a list of test cases, ensure that none of them throw transition errors""" with boto3_mocking.clients.handler_for("sesv2", self.mock_client), less_console_noise(): - for application, exception_type in test_cases: - with self.subTest(application=application, exception_type=exception_type): + for domain_request, exception_type in test_cases: + with self.subTest(domain_request=domain_request, exception_type=exception_type): try: # Retrieve the method by name from the application object and call it - method = getattr(application, method_to_run) + method = getattr(domain_request, method_to_run) # Call the method method() except exception_type: @@ -920,7 +920,7 @@ class TestDomainInformation(TestCase): self.maxDiff = None draft_domain, _ = DraftDomain.objects.get_or_create(name="igorville.gov") user, _ = User.objects.get_or_create() - domain_request = DomainApplication.objects.create(creator=user, requested_domain=draft_domain, notes="test notes") + domain_request = DomainRequest.objects.create(creator=user, requested_domain=draft_domain, notes="test notes") with boto3_mocking.clients.handler_for("sesv2", self.mock_client): with less_console_noise(): From 7f5bfa07a6c0d01f4f00fbbaed89264b5eb8a469 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 12 Mar 2024 15:58:35 -0600 Subject: [PATCH 098/103] Additional --- src/registrar/tests/common.py | 1 + src/registrar/tests/test_models.py | 56 +++++++++++++++--------------- 2 files changed, 29 insertions(+), 28 deletions(-) diff --git a/src/registrar/tests/common.py b/src/registrar/tests/common.py index f5ba815f4..24151261f 100644 --- a/src/registrar/tests/common.py +++ b/src/registrar/tests/common.py @@ -599,6 +599,7 @@ def completed_domain_request( return domain_request + def set_domain_request_investigators(domain_request_list: list[DomainRequest], investigator_user: User): """Helper method that sets the investigator field of all provided domain requests""" for request in domain_request_list: diff --git a/src/registrar/tests/test_models.py b/src/registrar/tests/test_models.py index de6d021d9..c7564b77b 100644 --- a/src/registrar/tests/test_models.py +++ b/src/registrar/tests/test_models.py @@ -248,7 +248,7 @@ class TestDomainRequest(TestCase): for domain_request, exception_type in test_cases: with self.subTest(domain_request=domain_request, exception_type=exception_type): try: - # Retrieve the method by name from the application object and call it + # Retrieve the method by name from the DomainRequest object and call it method = getattr(domain_request, method_to_run) # Call the method method() @@ -374,15 +374,15 @@ class TestDomainRequest(TestCase): """ test_cases = [ - (self.action_needed_application, TransitionNotAllowed), - (self.approved_application, TransitionNotAllowed), - (self.rejected_application, TransitionNotAllowed), - (self.ineligible_application, TransitionNotAllowed), + (self.action_needed_domain_request, TransitionNotAllowed), + (self.approved_domain_request, TransitionNotAllowed), + (self.rejected_domain_request, TransitionNotAllowed), + (self.ineligible_domain_request, TransitionNotAllowed), ] # Set all investigators to a user with no staff privs user, _ = User.objects.get_or_create(username="pancakesyrup", is_staff=False) - set_applications_investigators(self.all_domain_requests, user) + set_domain_request_investigators(self.all_domain_requests, user) self.assert_fsm_transition_raises_error(test_cases, "in_review") @@ -434,15 +434,15 @@ class TestDomainRequest(TestCase): """ test_cases = [ - (self.in_review_application, TransitionNotAllowed), - (self.approved_application, TransitionNotAllowed), - (self.rejected_application, TransitionNotAllowed), - (self.ineligible_application, TransitionNotAllowed), + (self.in_review_domain_request, TransitionNotAllowed), + (self.approved_domain_request, TransitionNotAllowed), + (self.rejected_domain_request, TransitionNotAllowed), + (self.ineligible_domain_request, TransitionNotAllowed), ] # Set all investigators to a user with no staff privs user, _ = User.objects.get_or_create(username="pancakesyrup", is_staff=False) - set_applications_investigators(self.all_domain_requests, user) + set_domain_request_investigators(self.all_domain_requests, user) self.assert_fsm_transition_raises_error(test_cases, "action_needed") @@ -494,14 +494,14 @@ class TestDomainRequest(TestCase): """ test_cases = [ - (self.in_review_application, TransitionNotAllowed), - (self.action_needed_application, TransitionNotAllowed), - (self.rejected_application, TransitionNotAllowed), + (self.in_review_domain_request, TransitionNotAllowed), + (self.action_needed_domain_request, TransitionNotAllowed), + (self.rejected_domain_request, TransitionNotAllowed), ] # Set all investigators to a user with no staff privs user, _ = User.objects.get_or_create(username="pancakesyrup", is_staff=False) - set_applications_investigators(self.all_domain_requests, user) + set_domain_request_investigators(self.all_domain_requests, user) self.assert_fsm_transition_raises_error(test_cases, "approve") @@ -566,14 +566,14 @@ class TestDomainRequest(TestCase): """ test_cases = [ - (self.submitted_application, TransitionNotAllowed), - (self.in_review_application, TransitionNotAllowed), - (self.action_needed_application, TransitionNotAllowed), + (self.submitted_domain_request, TransitionNotAllowed), + (self.in_review_domain_request, TransitionNotAllowed), + (self.action_needed_domain_request, TransitionNotAllowed), ] # Set all investigators to a user with no staff privs user, _ = User.objects.get_or_create(username="pancakesyrup", is_staff=False) - set_applications_investigators(self.all_domain_requests, user) + set_domain_request_investigators(self.all_domain_requests, user) self.assert_fsm_transition_does_not_raise_error(test_cases, "withdraw") @@ -625,14 +625,14 @@ class TestDomainRequest(TestCase): """ test_cases = [ - (self.in_review_application, TransitionNotAllowed), - (self.action_needed_application, TransitionNotAllowed), - (self.approved_application, TransitionNotAllowed), + (self.in_review_domain_request, TransitionNotAllowed), + (self.action_needed_domain_request, TransitionNotAllowed), + (self.approved_domain_request, TransitionNotAllowed), ] # Set all investigators to a user with no staff privs user, _ = User.objects.get_or_create(username="pancakesyrup", is_staff=False) - set_applications_investigators(self.all_domain_requests, user) + set_domain_request_investigators(self.all_domain_requests, user) self.assert_fsm_transition_raises_error(test_cases, "reject") @@ -686,15 +686,15 @@ class TestDomainRequest(TestCase): """ test_cases = [ - (self.in_review_application, TransitionNotAllowed), - (self.action_needed_application, TransitionNotAllowed), - (self.approved_application, TransitionNotAllowed), - (self.rejected_application, TransitionNotAllowed), + (self.in_review_domain_request, TransitionNotAllowed), + (self.action_needed_domain_request, TransitionNotAllowed), + (self.approved_domain_request, TransitionNotAllowed), + (self.rejected_domain_request, TransitionNotAllowed), ] # Set all investigators to a user with no staff privs user, _ = User.objects.get_or_create(username="pancakesyrup", is_staff=False) - set_applications_investigators(self.all_domain_requests, user) + set_domain_request_investigators(self.all_domain_requests, user) self.assert_fsm_transition_raises_error(test_cases, "reject_with_prejudice") From 26dabb3ab0b9d49526a8f9fe6dc958b345f8efd4 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 12 Mar 2024 16:10:19 -0600 Subject: [PATCH 099/103] Update test_models.py --- src/registrar/tests/test_models.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/registrar/tests/test_models.py b/src/registrar/tests/test_models.py index c7564b77b..4d5315b80 100644 --- a/src/registrar/tests/test_models.py +++ b/src/registrar/tests/test_models.py @@ -917,10 +917,12 @@ class TestDomainInformation(TestCase): @boto3_mocking.patching def test_approval_creates_info(self): - self.maxDiff = None draft_domain, _ = DraftDomain.objects.get_or_create(name="igorville.gov") user, _ = User.objects.get_or_create() - domain_request = DomainRequest.objects.create(creator=user, requested_domain=draft_domain, notes="test notes") + investigator, _ = User.objects.get_or_create(username="frenchtoast", is_staff=True) + domain_request = DomainRequest.objects.create( + creator=user, requested_domain=draft_domain, notes="test notes", investigator=investigator + ) with boto3_mocking.clients.handler_for("sesv2", self.mock_client): with less_console_noise(): From f0b510f09d68c6d714b4cb26304660211abf4bc6 Mon Sep 17 00:00:00 2001 From: Rebecca Hsieh Date: Wed, 13 Mar 2024 08:48:25 -0700 Subject: [PATCH 100/103] Remove extraneous TODOs except for 1 --- .../management/commands/email_current_metadata_report.py | 4 +--- src/registrar/utility/email.py | 5 +---- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/registrar/management/commands/email_current_metadata_report.py b/src/registrar/management/commands/email_current_metadata_report.py index 4300bf227..7e3016842 100644 --- a/src/registrar/management/commands/email_current_metadata_report.py +++ b/src/registrar/management/commands/email_current_metadata_report.py @@ -75,8 +75,6 @@ class Command(BaseCommand): # Set context for the subject current_date_str = datetime.now().strftime("%Y-%m-%d") - # TODO: Update secret in getgov-credentials via cloud.gov and my own .env when merging - # Encrypt the metadata encrypted_metadata_in_bytes = self._encrypt_metadata( s3_client.get_file(file_name), encrypted_metadata_output, str.encode(settings.SECRET_ENCRYPT_METADATA) @@ -86,7 +84,7 @@ class Command(BaseCommand): send_templated_email( template_name="emails/metadata_body.txt", subject_template_name="emails/metadata_subject.txt", - # to_address=settings.DEFAULT_FROM_EMAIL, # TODO: Uncomment this when ready to merge + # to_address=settings.DEFAULT_FROM_EMAIL, to_address="rebecca.hsieh@truss.works ", context={"current_date_str": current_date_str}, attachment_file=encrypted_metadata_in_bytes, diff --git a/src/registrar/utility/email.py b/src/registrar/utility/email.py index 91d55f361..5f61181c7 100644 --- a/src/registrar/utility/email.py +++ b/src/registrar/utility/email.py @@ -75,12 +75,9 @@ def send_templated_email( aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY, config=settings.BOTO_CONFIG, ) - response = send_email_with_attachment( + send_email_with_attachment( settings.DEFAULT_FROM_EMAIL, to_address, subject, email_body, attachment_file, ses_client ) - # TODO: Remove this print statement when ready to merge, - # leaving rn for getting error codes in case - print("Response from send_email_with_attachment_is:", response) except Exception as exc: raise EmailSendingError("Could not send SES email.") from exc From 6dacc18956b114cb08a5d26af2f4906a0f62cd29 Mon Sep 17 00:00:00 2001 From: Rebecca Hsieh Date: Wed, 13 Mar 2024 08:55:54 -0700 Subject: [PATCH 101/103] Update final to email --- .../management/commands/email_current_metadata_report.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/registrar/management/commands/email_current_metadata_report.py b/src/registrar/management/commands/email_current_metadata_report.py index 7e3016842..dcaf47b06 100644 --- a/src/registrar/management/commands/email_current_metadata_report.py +++ b/src/registrar/management/commands/email_current_metadata_report.py @@ -84,8 +84,7 @@ class Command(BaseCommand): send_templated_email( template_name="emails/metadata_body.txt", subject_template_name="emails/metadata_subject.txt", - # to_address=settings.DEFAULT_FROM_EMAIL, - to_address="rebecca.hsieh@truss.works ", + to_address=settings.DEFAULT_FROM_EMAIL, context={"current_date_str": current_date_str}, attachment_file=encrypted_metadata_in_bytes, ) From d356e4879db755f84505c8077dde08d091d6dd28 Mon Sep 17 00:00:00 2001 From: Alysia Broddrick Date: Wed, 13 Mar 2024 14:08:58 -0700 Subject: [PATCH 102/103] updated migration with merge conflict --- ...ter_domainrequest_current_websites_and_more.py} | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) rename src/registrar/migrations/{0075_alter_domaininformation_other_contacts_and_more.py => 0076_alter_domainrequest_current_websites_and_more.py} (62%) diff --git a/src/registrar/migrations/0075_alter_domaininformation_other_contacts_and_more.py b/src/registrar/migrations/0076_alter_domainrequest_current_websites_and_more.py similarity index 62% rename from src/registrar/migrations/0075_alter_domaininformation_other_contacts_and_more.py rename to src/registrar/migrations/0076_alter_domainrequest_current_websites_and_more.py index 53ad96ca4..ae1f3dac0 100644 --- a/src/registrar/migrations/0075_alter_domaininformation_other_contacts_and_more.py +++ b/src/registrar/migrations/0076_alter_domainrequest_current_websites_and_more.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.10 on 2024-03-09 11:32 +# Generated by Django 4.2.10 on 2024-03-13 21:07 from django.db import migrations, models @@ -6,20 +6,10 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ("registrar", "0074_create_groups_v08"), + ("registrar", "0075_create_groups_v08"), ] operations = [ - migrations.AlterField( - model_name="domaininformation", - name="other_contacts", - field=models.ManyToManyField( - blank=True, - related_name="contact_domain_requests_information", - to="registrar.contact", - verbose_name="Other employees", - ), - ), migrations.AlterField( model_name="domainrequest", name="current_websites", From 7ce096b28e4e0f3d9e0223d72959c38b5b0abc77 Mon Sep 17 00:00:00 2001 From: Alysia Broddrick Date: Wed, 13 Mar 2024 15:50:21 -0700 Subject: [PATCH 103/103] migration updated with missing value --- ...76_alter_domainrequest_current_websites_and_more.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/registrar/migrations/0076_alter_domainrequest_current_websites_and_more.py b/src/registrar/migrations/0076_alter_domainrequest_current_websites_and_more.py index ae1f3dac0..b536f87c1 100644 --- a/src/registrar/migrations/0076_alter_domainrequest_current_websites_and_more.py +++ b/src/registrar/migrations/0076_alter_domainrequest_current_websites_and_more.py @@ -27,4 +27,14 @@ class Migration(migrations.Migration): verbose_name="Other employees", ), ), + migrations.AlterField( + model_name="domaininformation", + name="other_contacts", + field=models.ManyToManyField( + blank=True, + related_name="contact_domain_requests_information", + to="registrar.contact", + verbose_name="Other employees", + ), + ), ]
Your domain requests
{% if application.requested_domain is None %} diff --git a/src/registrar/templatetags/custom_filters.py b/src/registrar/templatetags/custom_filters.py index de2051989..ff7a6258c 100644 --- a/src/registrar/templatetags/custom_filters.py +++ b/src/registrar/templatetags/custom_filters.py @@ -1,7 +1,7 @@ import logging from django import template import re -from registrar.models.domain_application import DomainApplication +from registrar.models.domain_request import DomainRequest register = template.Library() logger = logging.getLogger(__name__) @@ -55,7 +55,7 @@ def contains_checkbox(html_list): @register.filter def get_organization_long_name(organization_type): - organization_choices_dict = dict(DomainApplication.OrganizationChoicesVerbose.choices) + organization_choices_dict = dict(DomainRequest.OrganizationChoicesVerbose.choices) long_form_type = organization_choices_dict[organization_type] if long_form_type is None: logger.error("Organization type error, triggered by a template's custom filter") diff --git a/src/registrar/tests/common.py b/src/registrar/tests/common.py index ee1ab8b68..184ed9132 100644 --- a/src/registrar/tests/common.py +++ b/src/registrar/tests/common.py @@ -18,7 +18,7 @@ from registrar.models import ( Contact, DraftDomain, Website, - DomainApplication, + DomainRequest, DomainInvitation, User, UserGroup, @@ -365,13 +365,13 @@ class AuditedAdminMockData: self, domain_type, item_name, - status=DomainApplication.ApplicationStatus.STARTED, + status=DomainRequest.ApplicationStatus.STARTED, org_type="federal", federal_type="executive", purpose="Purpose of the site", ): """ - Returns a prebuilt kwarg dictionary for DomainApplication, + Returns a prebuilt kwarg dictionary for DomainRequest, DomainInformation, or DomainInvitation. Args: domain_type (str): is either 'application', 'information', @@ -381,8 +381,8 @@ class AuditedAdminMockData: organization_name, address_line1, address_line2, title, email, and username. - status (str - optional): Defines the status for DomainApplication, - e.g. DomainApplication.ApplicationStatus.STARTED + status (str - optional): Defines the status for DomainRequest, + e.g. DomainRequest.ApplicationStatus.STARTED org_type (str - optional): Sets a domains org_type @@ -391,7 +391,7 @@ class AuditedAdminMockData: purpose (str - optional): Sets a domains purpose Returns: dict: Returns a dictionary structurally consistent with the expected input - of either DomainApplication, DomainInvitation, or DomainInformation + of either DomainRequest, DomainInvitation, or DomainInformation based on the 'domain_type' field. """ # noqa common_args = self.get_common_domain_arg_dictionary(item_name, org_type, federal_type, purpose) @@ -405,11 +405,11 @@ class AuditedAdminMockData: status=status, ) case self.INFORMATION: - domain_app = self.create_full_dummy_domain_application(item_name) + domain_app = self.create_full_dummy_domain_request(item_name) full_arg_dict = dict( **common_args, domain=self.dummy_domain(item_name, True), - domain_application=domain_app, + domain_request=domain_app, ) case self.INVITATION: full_arg_dict = dict( @@ -419,22 +419,22 @@ class AuditedAdminMockData: ) return full_arg_dict - def create_full_dummy_domain_application(self, item_name, status=DomainApplication.ApplicationStatus.STARTED): - """Creates a dummy domain application object""" - domain_application_kwargs = self.dummy_kwarg_boilerplate(self.APPLICATION, item_name, status) - application = DomainApplication.objects.get_or_create(**domain_application_kwargs)[0] + def create_full_dummy_domain_request(self, item_name, status=DomainRequest.ApplicationStatus.STARTED): + """Creates a dummy domain request object""" + domain_request_kwargs = self.dummy_kwarg_boilerplate(self.APPLICATION, item_name, status) + application = DomainRequest.objects.get_or_create(**domain_request_kwargs)[0] return application - def create_full_dummy_domain_information(self, item_name, status=DomainApplication.ApplicationStatus.STARTED): + def create_full_dummy_domain_information(self, item_name, status=DomainRequest.ApplicationStatus.STARTED): """Creates a dummy domain information object""" - domain_application_kwargs = self.dummy_kwarg_boilerplate(self.INFORMATION, item_name, status) - application = DomainInformation.objects.get_or_create(**domain_application_kwargs)[0] + domain_request_kwargs = self.dummy_kwarg_boilerplate(self.INFORMATION, item_name, status) + application = DomainInformation.objects.get_or_create(**domain_request_kwargs)[0] return application - def create_full_dummy_domain_invitation(self, item_name, status=DomainApplication.ApplicationStatus.STARTED): + def create_full_dummy_domain_invitation(self, item_name, status=DomainRequest.ApplicationStatus.STARTED): """Creates a dummy domain invitation object""" - domain_application_kwargs = self.dummy_kwarg_boilerplate(self.INVITATION, item_name, status) - application = DomainInvitation.objects.get_or_create(**domain_application_kwargs)[0] + domain_request_kwargs = self.dummy_kwarg_boilerplate(self.INVITATION, item_name, status) + application = DomainInvitation.objects.get_or_create(**domain_request_kwargs)[0] return application @@ -445,13 +445,13 @@ class AuditedAdminMockData: has_other_contacts=True, has_current_website=True, has_alternative_gov_domain=True, - status=DomainApplication.ApplicationStatus.STARTED, + status=DomainRequest.ApplicationStatus.STARTED, ): - """A helper to create a dummy domain application object""" + """A helper to create a dummy domain request object""" application = None match domain_type: case self.APPLICATION: - application = self.create_full_dummy_domain_application(item_name, status) + application = self.create_full_dummy_domain_request(item_name, status) case self.INVITATION: application = self.create_full_dummy_domain_invitation(item_name, status) case self.INFORMATION: @@ -526,12 +526,12 @@ def completed_application( has_alternative_gov_domain=True, has_about_your_organization=True, has_anything_else=True, - status=DomainApplication.ApplicationStatus.STARTED, + status=DomainRequest.ApplicationStatus.STARTED, user=False, submitter=False, name="city.gov", ): - """A completed domain application.""" + """A completed domain request.""" if not user: user = get_user_model().objects.create(username="username" + str(uuid.uuid4())[:8]) ao, _ = Contact.objects.get_or_create( @@ -559,7 +559,7 @@ def completed_application( email="testy2@town.com", phone="(555) 555 5557", ) - domain_application_kwargs = dict( + domain_request_kwargs = dict( organization_type="federal", federal_type="executive", purpose="Purpose of the site", @@ -576,11 +576,11 @@ def completed_application( status=status, ) if has_about_your_organization: - domain_application_kwargs["about_your_organization"] = "e-Government" + domain_request_kwargs["about_your_organization"] = "e-Government" if has_anything_else: - domain_application_kwargs["anything_else"] = "There is more" + domain_request_kwargs["anything_else"] = "There is more" - application, _ = DomainApplication.objects.get_or_create(**domain_application_kwargs) + application, _ = DomainRequest.objects.get_or_create(**domain_request_kwargs) if has_other_contacts: application.other_contacts.add(other) diff --git a/src/registrar/tests/test_admin.py b/src/registrar/tests/test_admin.py index d76f12f35..d9eef5cd2 100644 --- a/src/registrar/tests/test_admin.py +++ b/src/registrar/tests/test_admin.py @@ -7,8 +7,8 @@ from django.contrib import messages from django.urls import reverse from registrar.admin import ( DomainAdmin, - DomainApplicationAdmin, - DomainApplicationAdminForm, + DomainRequestAdmin, + DomainRequestAdminForm, DomainInvitationAdmin, ListHeaderAdmin, MyUserAdmin, @@ -18,7 +18,7 @@ from registrar.admin import ( UserDomainRoleAdmin, VerifiedByStaffAdmin, ) -from registrar.models import Domain, DomainApplication, DomainInformation, User, DomainInvitation, Contact, Website +from registrar.models import Domain, DomainRequest, DomainInformation, User, DomainInvitation, Contact, Website from registrar.models.user_domain_role import UserDomainRole from registrar.models.verified_by_staff import VerifiedByStaff from .common import ( @@ -236,7 +236,7 @@ class TestDomainAdmin(MockEppLib, WebTest): """ with less_console_noise(): self.client.force_login(self.superuser) - application = completed_application(status=DomainApplication.ApplicationStatus.IN_REVIEW) + application = completed_application(status=DomainRequest.ApplicationStatus.IN_REVIEW) mock_client = MockSESClient() with boto3_mocking.clients.handler_for("sesv2", mock_client): application.approve() @@ -435,11 +435,11 @@ class TestDomainAdmin(MockEppLib, WebTest): super().tearDown() Domain.objects.all().delete() DomainInformation.objects.all().delete() - DomainApplication.objects.all().delete() + DomainRequest.objects.all().delete() User.objects.all().delete() -class TestDomainApplicationAdminForm(TestCase): +class TestDomainRequestAdminForm(TestCase): def setUp(self): # Create a test application with an initial state of started self.application = completed_application() @@ -447,7 +447,7 @@ class TestDomainApplicationAdminForm(TestCase): def test_form_choices(self): with less_console_noise(): # Create a form instance with the test application - form = DomainApplicationAdminForm(instance=self.application) + form = DomainRequestAdminForm(instance=self.application) # Verify that the form choices match the available transitions for started expected_choices = [("started", "Started"), ("submitted", "Submitted")] @@ -456,41 +456,41 @@ class TestDomainApplicationAdminForm(TestCase): def test_form_choices_when_no_instance(self): with less_console_noise(): # Create a form instance without an instance - form = DomainApplicationAdminForm() + form = DomainRequestAdminForm() # Verify that the form choices show all choices when no instance is provided; # this is necessary to show all choices when creating a new domain # application in django admin; - # note that FSM ensures that no domain application exists with invalid status, + # note that FSM ensures that no domain request exists with invalid status, # so don't need to test for invalid status self.assertEqual( form.fields["status"].widget.choices, - DomainApplication._meta.get_field("status").choices, + DomainRequest._meta.get_field("status").choices, ) def test_form_choices_when_ineligible(self): with less_console_noise(): - # Create a form instance with a domain application with ineligible status - ineligible_application = DomainApplication(status="ineligible") + # Create a form instance with a domain request with ineligible status + ineligible_application = DomainRequest(status="ineligible") # Attempt to create a form with the ineligible application # The form should not raise an error, but choices should be the # full list of possible choices - form = DomainApplicationAdminForm(instance=ineligible_application) + form = DomainRequestAdminForm(instance=ineligible_application) self.assertEqual( form.fields["status"].widget.choices, - DomainApplication._meta.get_field("status").choices, + DomainRequest._meta.get_field("status").choices, ) @boto3_mocking.patching -class TestDomainApplicationAdmin(MockEppLib): +class TestDomainRequestAdmin(MockEppLib): def setUp(self): super().setUp() self.site = AdminSite() self.factory = RequestFactory() - self.admin = DomainApplicationAdmin(model=DomainApplication, admin_site=self.site) + self.admin = DomainRequestAdmin(model=DomainRequest, admin_site=self.site) self.superuser = create_superuser() self.staffuser = create_user() self.client = Client(HTTP_HOST="localhost:8080") @@ -498,13 +498,13 @@ class TestDomainApplicationAdmin(MockEppLib): factory=self.factory, user=self.superuser, admin=self.admin, - url="/admin/registrar/DomainApplication/", - model=DomainApplication, + url="/admin/registrar/DomainRequest/", + model=DomainRequest, ) self.mock_client = MockSESClient() def test_domain_sortable(self): - """Tests if the DomainApplication sorts by domain correctly""" + """Tests if the DomainRequest sorts by domain correctly""" with less_console_noise(): p = "adminpass" self.client.login(username="superuser", password=p) @@ -518,7 +518,7 @@ class TestDomainApplicationAdmin(MockEppLib): self.test_helper.assert_table_sorted("-1", ("-requested_domain__name",)) def test_submitter_sortable(self): - """Tests if the DomainApplication sorts by domain correctly""" + """Tests if the DomainRequest sorts by domain correctly""" with less_console_noise(): p = "adminpass" self.client.login(username="superuser", password=p) @@ -549,7 +549,7 @@ class TestDomainApplicationAdmin(MockEppLib): ) def test_investigator_sortable(self): - """Tests if the DomainApplication sorts by domain correctly""" + """Tests if the DomainRequest sorts by domain correctly""" with less_console_noise(): p = "adminpass" self.client.login(username="superuser", password=p) @@ -585,7 +585,7 @@ class TestDomainApplicationAdmin(MockEppLib): with less_console_noise(): self.client.force_login(self.superuser) completed_application() - response = self.client.get("/admin/registrar/domainapplication/") + response = self.client.get("/admin/registrar/DomainRequest/") # There are 4 template references to Federal (4) plus two references in the table # for our actual application self.assertContains(response, "Federal", count=6) @@ -600,7 +600,7 @@ class TestDomainApplicationAdmin(MockEppLib): with boto3_mocking.clients.handler_for("sesv2", self.mock_client): with less_console_noise(): # Create a mock request - request = self.factory.post("/admin/registrar/domainapplication/{}/change/".format(application.pk)) + request = self.factory.post("/admin/registrar/DomainRequest/{}/change/".format(application.pk)) # Modify the application's properties application.status = status @@ -661,39 +661,39 @@ class TestDomainApplicationAdmin(MockEppLib): application = completed_application() # Test Submitted Status from started - self.transition_state_and_send_email(application, DomainApplication.ApplicationStatus.SUBMITTED) + self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.SUBMITTED) self.assert_email_is_accurate("We received your .gov domain request.", 0, EMAIL, True) self.assertEqual(len(self.mock_client.EMAILS_SENT), 1) # Test Withdrawn Status - self.transition_state_and_send_email(application, DomainApplication.ApplicationStatus.WITHDRAWN) + self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.WITHDRAWN) self.assert_email_is_accurate( "Your .gov domain request has been withdrawn and will not be reviewed by our team.", 1, EMAIL, True ) self.assertEqual(len(self.mock_client.EMAILS_SENT), 2) # Test Submitted Status Again (from withdrawn) - self.transition_state_and_send_email(application, DomainApplication.ApplicationStatus.SUBMITTED) + self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.SUBMITTED) self.assertEqual(len(self.mock_client.EMAILS_SENT), 3) # Move it to IN_REVIEW - self.transition_state_and_send_email(application, DomainApplication.ApplicationStatus.IN_REVIEW) + self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.IN_REVIEW) self.assertEqual(len(self.mock_client.EMAILS_SENT), 3) # Test Submitted Status Again from in IN_REVIEW, no new email should be sent - self.transition_state_and_send_email(application, DomainApplication.ApplicationStatus.SUBMITTED) + self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.SUBMITTED) self.assertEqual(len(self.mock_client.EMAILS_SENT), 3) # Move it to IN_REVIEW - self.transition_state_and_send_email(application, DomainApplication.ApplicationStatus.IN_REVIEW) + self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.IN_REVIEW) self.assertEqual(len(self.mock_client.EMAILS_SENT), 3) # Move it to ACTION_NEEDED - self.transition_state_and_send_email(application, DomainApplication.ApplicationStatus.ACTION_NEEDED) + self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.ACTION_NEEDED) self.assertEqual(len(self.mock_client.EMAILS_SENT), 3) # Test Submitted Status Again from in ACTION_NEEDED, no new email should be sent - self.transition_state_and_send_email(application, DomainApplication.ApplicationStatus.SUBMITTED) + self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.SUBMITTED) self.assertEqual(len(self.mock_client.EMAILS_SENT), 3) @override_settings(IS_PRODUCTION=True) @@ -718,40 +718,40 @@ class TestDomainApplicationAdmin(MockEppLib): application = completed_application() # Test Submitted Status from started - self.transition_state_and_send_email(application, DomainApplication.ApplicationStatus.SUBMITTED) + self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.SUBMITTED) self.assert_email_is_accurate("We received your .gov domain request.", 0, EMAIL, False, BCC_EMAIL) self.assertEqual(len(self.mock_client.EMAILS_SENT), 1) # Test Withdrawn Status - self.transition_state_and_send_email(application, DomainApplication.ApplicationStatus.WITHDRAWN) + self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.WITHDRAWN) self.assert_email_is_accurate( "Your .gov domain request has been withdrawn and will not be reviewed by our team.", 1, EMAIL ) self.assertEqual(len(self.mock_client.EMAILS_SENT), 2) # Test Submitted Status Again (from withdrawn) - self.transition_state_and_send_email(application, DomainApplication.ApplicationStatus.SUBMITTED) + self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.SUBMITTED) self.assert_email_is_accurate("We received your .gov domain request.", 0, EMAIL, False, BCC_EMAIL) self.assertEqual(len(self.mock_client.EMAILS_SENT), 3) # Move it to IN_REVIEW - self.transition_state_and_send_email(application, DomainApplication.ApplicationStatus.IN_REVIEW) + self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.IN_REVIEW) self.assertEqual(len(self.mock_client.EMAILS_SENT), 3) # Test Submitted Status Again from in IN_REVIEW, no new email should be sent - self.transition_state_and_send_email(application, DomainApplication.ApplicationStatus.SUBMITTED) + self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.SUBMITTED) self.assertEqual(len(self.mock_client.EMAILS_SENT), 3) # Move it to IN_REVIEW - self.transition_state_and_send_email(application, DomainApplication.ApplicationStatus.IN_REVIEW) + self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.IN_REVIEW) self.assertEqual(len(self.mock_client.EMAILS_SENT), 3) # Move it to ACTION_NEEDED - self.transition_state_and_send_email(application, DomainApplication.ApplicationStatus.ACTION_NEEDED) + self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.ACTION_NEEDED) self.assertEqual(len(self.mock_client.EMAILS_SENT), 3) # Test Submitted Status Again from in ACTION_NEEDED, no new email should be sent - self.transition_state_and_send_email(application, DomainApplication.ApplicationStatus.SUBMITTED) + self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.SUBMITTED) self.assertEqual(len(self.mock_client.EMAILS_SENT), 3) def test_save_model_sends_approved_email(self): @@ -764,24 +764,24 @@ class TestDomainApplicationAdmin(MockEppLib): User.objects.filter(email=EMAIL).delete() # Create a sample application - application = completed_application(status=DomainApplication.ApplicationStatus.IN_REVIEW) + application = completed_application(status=DomainRequest.ApplicationStatus.IN_REVIEW) # Test Submitted Status - self.transition_state_and_send_email(application, DomainApplication.ApplicationStatus.APPROVED) + self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.APPROVED) self.assert_email_is_accurate("Congratulations! Your .gov domain request has been approved.", 0, EMAIL) self.assertEqual(len(self.mock_client.EMAILS_SENT), 1) # Test Withdrawn Status self.transition_state_and_send_email( application, - DomainApplication.ApplicationStatus.REJECTED, - DomainApplication.RejectionReasons.DOMAIN_PURPOSE, + DomainRequest.ApplicationStatus.REJECTED, + DomainRequest.RejectionReasons.DOMAIN_PURPOSE, ) self.assert_email_is_accurate("Your .gov domain request has been rejected.", 1, EMAIL) self.assertEqual(len(self.mock_client.EMAILS_SENT), 2) # Test Submitted Status Again (No new email should be sent) - self.transition_state_and_send_email(application, DomainApplication.ApplicationStatus.APPROVED) + self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.APPROVED) self.assertEqual(len(self.mock_client.EMAILS_SENT), 3) def test_save_model_sends_rejected_email_purpose_not_met(self): @@ -794,13 +794,13 @@ class TestDomainApplicationAdmin(MockEppLib): User.objects.filter(email=EMAIL).delete() # Create a sample application - application = completed_application(status=DomainApplication.ApplicationStatus.IN_REVIEW) + application = completed_application(status=DomainRequest.ApplicationStatus.IN_REVIEW) # Reject for reason DOMAIN_PURPOSE and test email self.transition_state_and_send_email( application, - DomainApplication.ApplicationStatus.REJECTED, - DomainApplication.RejectionReasons.DOMAIN_PURPOSE, + DomainRequest.ApplicationStatus.REJECTED, + DomainRequest.RejectionReasons.DOMAIN_PURPOSE, ) self.assert_email_is_accurate( "Your domain request was rejected because the purpose you provided did not meet our \nrequirements.", @@ -810,7 +810,7 @@ class TestDomainApplicationAdmin(MockEppLib): self.assertEqual(len(self.mock_client.EMAILS_SENT), 1) # Approve - self.transition_state_and_send_email(application, DomainApplication.ApplicationStatus.APPROVED) + self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.APPROVED) self.assert_email_is_accurate("Congratulations! Your .gov domain request has been approved.", 1, EMAIL) self.assertEqual(len(self.mock_client.EMAILS_SENT), 2) @@ -824,11 +824,11 @@ class TestDomainApplicationAdmin(MockEppLib): User.objects.filter(email=EMAIL).delete() # Create a sample application - application = completed_application(status=DomainApplication.ApplicationStatus.IN_REVIEW) + application = completed_application(status=DomainRequest.ApplicationStatus.IN_REVIEW) # Reject for reason REQUESTOR and test email including dynamic organization name self.transition_state_and_send_email( - application, DomainApplication.ApplicationStatus.REJECTED, DomainApplication.RejectionReasons.REQUESTOR + application, DomainRequest.ApplicationStatus.REJECTED, DomainRequest.RejectionReasons.REQUESTOR ) self.assert_email_is_accurate( "Your domain request was rejected because we don’t believe you’re eligible to request a \n.gov " @@ -839,7 +839,7 @@ class TestDomainApplicationAdmin(MockEppLib): self.assertEqual(len(self.mock_client.EMAILS_SENT), 1) # Approve - self.transition_state_and_send_email(application, DomainApplication.ApplicationStatus.APPROVED) + self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.APPROVED) self.assert_email_is_accurate("Congratulations! Your .gov domain request has been approved.", 1, EMAIL) self.assertEqual(len(self.mock_client.EMAILS_SENT), 2) @@ -853,13 +853,13 @@ class TestDomainApplicationAdmin(MockEppLib): User.objects.filter(email=EMAIL).delete() # Create a sample application - application = completed_application(status=DomainApplication.ApplicationStatus.IN_REVIEW) + application = completed_application(status=DomainRequest.ApplicationStatus.IN_REVIEW) # Reject for reason SECOND_DOMAIN_REASONING and test email including dynamic organization name self.transition_state_and_send_email( application, - DomainApplication.ApplicationStatus.REJECTED, - DomainApplication.RejectionReasons.SECOND_DOMAIN_REASONING, + DomainRequest.ApplicationStatus.REJECTED, + DomainRequest.RejectionReasons.SECOND_DOMAIN_REASONING, ) self.assert_email_is_accurate( "Your domain request was rejected because Testorg has a .gov domain.", 0, EMAIL @@ -867,7 +867,7 @@ class TestDomainApplicationAdmin(MockEppLib): self.assertEqual(len(self.mock_client.EMAILS_SENT), 1) # Approve - self.transition_state_and_send_email(application, DomainApplication.ApplicationStatus.APPROVED) + self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.APPROVED) self.assert_email_is_accurate("Congratulations! Your .gov domain request has been approved.", 1, EMAIL) self.assertEqual(len(self.mock_client.EMAILS_SENT), 2) @@ -881,13 +881,13 @@ class TestDomainApplicationAdmin(MockEppLib): User.objects.filter(email=EMAIL).delete() # Create a sample application - application = completed_application(status=DomainApplication.ApplicationStatus.IN_REVIEW) + application = completed_application(status=DomainRequest.ApplicationStatus.IN_REVIEW) # Reject for reason CONTACTS_OR_ORGANIZATION_LEGITIMACY and test email including dynamic organization name self.transition_state_and_send_email( application, - DomainApplication.ApplicationStatus.REJECTED, - DomainApplication.RejectionReasons.CONTACTS_OR_ORGANIZATION_LEGITIMACY, + DomainRequest.ApplicationStatus.REJECTED, + DomainRequest.RejectionReasons.CONTACTS_OR_ORGANIZATION_LEGITIMACY, ) self.assert_email_is_accurate( "Your domain request was rejected because we could not verify the organizational \n" @@ -898,7 +898,7 @@ class TestDomainApplicationAdmin(MockEppLib): self.assertEqual(len(self.mock_client.EMAILS_SENT), 1) # Approve - self.transition_state_and_send_email(application, DomainApplication.ApplicationStatus.APPROVED) + self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.APPROVED) self.assert_email_is_accurate("Congratulations! Your .gov domain request has been approved.", 1, EMAIL) self.assertEqual(len(self.mock_client.EMAILS_SENT), 2) @@ -912,13 +912,13 @@ class TestDomainApplicationAdmin(MockEppLib): User.objects.filter(email=EMAIL).delete() # Create a sample application - application = completed_application(status=DomainApplication.ApplicationStatus.IN_REVIEW) + application = completed_application(status=DomainRequest.ApplicationStatus.IN_REVIEW) # Reject for reason ORGANIZATION_ELIGIBILITY and test email including dynamic organization name self.transition_state_and_send_email( application, - DomainApplication.ApplicationStatus.REJECTED, - DomainApplication.RejectionReasons.ORGANIZATION_ELIGIBILITY, + DomainRequest.ApplicationStatus.REJECTED, + DomainRequest.RejectionReasons.ORGANIZATION_ELIGIBILITY, ) self.assert_email_is_accurate( "Your domain request was rejected because we determined that Testorg is not \neligible for " @@ -929,7 +929,7 @@ class TestDomainApplicationAdmin(MockEppLib): self.assertEqual(len(self.mock_client.EMAILS_SENT), 1) # Approve - self.transition_state_and_send_email(application, DomainApplication.ApplicationStatus.APPROVED) + self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.APPROVED) self.assert_email_is_accurate("Congratulations! Your .gov domain request has been approved.", 1, EMAIL) self.assertEqual(len(self.mock_client.EMAILS_SENT), 2) @@ -943,13 +943,13 @@ class TestDomainApplicationAdmin(MockEppLib): User.objects.filter(email=EMAIL).delete() # Create a sample application - application = completed_application(status=DomainApplication.ApplicationStatus.IN_REVIEW) + application = completed_application(status=DomainRequest.ApplicationStatus.IN_REVIEW) # Reject for reason NAMING_REQUIREMENTS and test email including dynamic organization name self.transition_state_and_send_email( application, - DomainApplication.ApplicationStatus.REJECTED, - DomainApplication.RejectionReasons.NAMING_REQUIREMENTS, + DomainRequest.ApplicationStatus.REJECTED, + DomainRequest.RejectionReasons.NAMING_REQUIREMENTS, ) self.assert_email_is_accurate( "Your domain request was rejected because it does not meet our naming requirements.", 0, EMAIL @@ -957,7 +957,7 @@ class TestDomainApplicationAdmin(MockEppLib): self.assertEqual(len(self.mock_client.EMAILS_SENT), 1) # Approve - self.transition_state_and_send_email(application, DomainApplication.ApplicationStatus.APPROVED) + self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.APPROVED) self.assert_email_is_accurate("Congratulations! Your .gov domain request has been approved.", 1, EMAIL) self.assertEqual(len(self.mock_client.EMAILS_SENT), 2) @@ -971,19 +971,19 @@ class TestDomainApplicationAdmin(MockEppLib): User.objects.filter(email=EMAIL).delete() # Create a sample application - application = completed_application(status=DomainApplication.ApplicationStatus.IN_REVIEW) + application = completed_application(status=DomainRequest.ApplicationStatus.IN_REVIEW) # Reject for reason NAMING_REQUIREMENTS and test email including dynamic organization name self.transition_state_and_send_email( application, - DomainApplication.ApplicationStatus.REJECTED, - DomainApplication.RejectionReasons.OTHER, + DomainRequest.ApplicationStatus.REJECTED, + DomainRequest.RejectionReasons.OTHER, ) self.assert_email_is_accurate("Choosing a .gov domain name", 0, EMAIL) self.assertEqual(len(self.mock_client.EMAILS_SENT), 1) # Approve - self.transition_state_and_send_email(application, DomainApplication.ApplicationStatus.APPROVED) + self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.APPROVED) self.assert_email_is_accurate("Congratulations! Your .gov domain request has been approved.", 1, EMAIL) self.assertEqual(len(self.mock_client.EMAILS_SENT), 2) @@ -995,15 +995,15 @@ class TestDomainApplicationAdmin(MockEppLib): """ with less_console_noise(): - application = completed_application(status=DomainApplication.ApplicationStatus.APPROVED) + application = completed_application(status=DomainRequest.ApplicationStatus.APPROVED) # Create a request object with a superuser - request = self.factory.post("/admin/registrar/domainapplication/{}/change/".format(application.pk)) + request = self.factory.post("/admin/registrar/DomainRequest/{}/change/".format(application.pk)) request.user = self.superuser with ExitStack() as stack: stack.enter_context(patch.object(messages, "error")) - application.status = DomainApplication.ApplicationStatus.REJECTED + application.status = DomainRequest.ApplicationStatus.REJECTED self.admin.save_model(request, application, None, True) @@ -1013,7 +1013,7 @@ class TestDomainApplicationAdmin(MockEppLib): ) application.refresh_from_db() - self.assertEqual(application.status, DomainApplication.ApplicationStatus.APPROVED) + self.assertEqual(application.status, DomainRequest.ApplicationStatus.APPROVED) def test_transition_to_rejected_with_rejection_reason_does_not_trigger_error(self): """ @@ -1023,23 +1023,23 @@ class TestDomainApplicationAdmin(MockEppLib): """ with less_console_noise(): - application = completed_application(status=DomainApplication.ApplicationStatus.APPROVED) + application = completed_application(status=DomainRequest.ApplicationStatus.APPROVED) # Create a request object with a superuser - request = self.factory.post("/admin/registrar/domainapplication/{}/change/".format(application.pk)) + request = self.factory.post("/admin/registrar/DomainRequest/{}/change/".format(application.pk)) request.user = self.superuser with ExitStack() as stack: stack.enter_context(patch.object(messages, "error")) - application.status = DomainApplication.ApplicationStatus.REJECTED - application.rejection_reason = DomainApplication.RejectionReasons.CONTACTS_OR_ORGANIZATION_LEGITIMACY + application.status = DomainRequest.ApplicationStatus.REJECTED + application.rejection_reason = DomainRequest.RejectionReasons.CONTACTS_OR_ORGANIZATION_LEGITIMACY self.admin.save_model(request, application, None, True) messages.error.assert_not_called() application.refresh_from_db() - self.assertEqual(application.status, DomainApplication.ApplicationStatus.REJECTED) + self.assertEqual(application.status, DomainRequest.ApplicationStatus.REJECTED) def test_save_model_sends_withdrawn_email(self): """When transitioning to withdrawn on a domain request, @@ -1051,22 +1051,22 @@ class TestDomainApplicationAdmin(MockEppLib): User.objects.filter(email=EMAIL).delete() # Create a sample application - application = completed_application(status=DomainApplication.ApplicationStatus.IN_REVIEW) + application = completed_application(status=DomainRequest.ApplicationStatus.IN_REVIEW) # Test Submitted Status - self.transition_state_and_send_email(application, DomainApplication.ApplicationStatus.WITHDRAWN) + self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.WITHDRAWN) self.assert_email_is_accurate( "Your .gov domain request has been withdrawn and will not be reviewed by our team.", 0, EMAIL ) self.assertEqual(len(self.mock_client.EMAILS_SENT), 1) # Test Withdrawn Status - self.transition_state_and_send_email(application, DomainApplication.ApplicationStatus.SUBMITTED) + self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.SUBMITTED) self.assert_email_is_accurate("We received your .gov domain request.", 1, EMAIL) self.assertEqual(len(self.mock_client.EMAILS_SENT), 2) # Test Submitted Status Again (No new email should be sent) - self.transition_state_and_send_email(application, DomainApplication.ApplicationStatus.WITHDRAWN) + self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.WITHDRAWN) self.assertEqual(len(self.mock_client.EMAILS_SENT), 3) def test_save_model_sets_approved_domain(self): @@ -1076,14 +1076,14 @@ class TestDomainApplicationAdmin(MockEppLib): User.objects.filter(email=EMAIL).delete() # Create a sample application - application = completed_application(status=DomainApplication.ApplicationStatus.IN_REVIEW) + application = completed_application(status=DomainRequest.ApplicationStatus.IN_REVIEW) # Create a mock request - request = self.factory.post("/admin/registrar/domainapplication/{}/change/".format(application.pk)) + request = self.factory.post("/admin/registrar/DomainRequest/{}/change/".format(application.pk)) with boto3_mocking.clients.handler_for("sesv2", self.mock_client): # Modify the application's property - application.status = DomainApplication.ApplicationStatus.APPROVED + application.status = DomainRequest.ApplicationStatus.APPROVED # Use the model admin's save_model method self.admin.save_model(request, application, form=None, change=True) @@ -1098,14 +1098,14 @@ class TestDomainApplicationAdmin(MockEppLib): User.objects.filter(email=EMAIL).delete() # Create a sample application - application = completed_application(status=DomainApplication.ApplicationStatus.IN_REVIEW) + application = completed_application(status=DomainRequest.ApplicationStatus.IN_REVIEW) # Create a mock request - request = self.factory.post("/admin/registrar/domainapplication/{}/change/".format(application.pk)) + request = self.factory.post("/admin/registrar/DomainRequest/{}/change/".format(application.pk)) with boto3_mocking.clients.handler_for("sesv2", self.mock_client): # Modify the application's property - application.status = DomainApplication.ApplicationStatus.INELIGIBLE + application.status = DomainRequest.ApplicationStatus.INELIGIBLE # Use the model admin's save_model method self.admin.save_model(request, application, form=None, change=True) @@ -1115,7 +1115,7 @@ class TestDomainApplicationAdmin(MockEppLib): def test_readonly_when_restricted_creator(self): with less_console_noise(): - application = completed_application(status=DomainApplication.ApplicationStatus.IN_REVIEW) + application = completed_application(status=DomainRequest.ApplicationStatus.IN_REVIEW) with boto3_mocking.clients.handler_for("sesv2", self.mock_client): application.creator.status = User.RESTRICTED application.creator.save() @@ -1201,7 +1201,7 @@ class TestDomainApplicationAdmin(MockEppLib): def test_saving_when_restricted_creator(self): with less_console_noise(): # Create an instance of the model - application = completed_application(status=DomainApplication.ApplicationStatus.IN_REVIEW) + application = completed_application(status=DomainRequest.ApplicationStatus.IN_REVIEW) with boto3_mocking.clients.handler_for("sesv2", self.mock_client): application.creator.status = User.RESTRICTED application.creator.save() @@ -1221,19 +1221,19 @@ class TestDomainApplicationAdmin(MockEppLib): ) # Assert that the status has not changed - self.assertEqual(application.status, DomainApplication.ApplicationStatus.IN_REVIEW) + self.assertEqual(application.status, DomainRequest.ApplicationStatus.IN_REVIEW) def test_change_view_with_restricted_creator(self): with less_console_noise(): # Create an instance of the model - application = completed_application(status=DomainApplication.ApplicationStatus.IN_REVIEW) + application = completed_application(status=DomainRequest.ApplicationStatus.IN_REVIEW) with boto3_mocking.clients.handler_for("sesv2", self.mock_client): application.creator.status = User.RESTRICTED application.creator.save() with patch("django.contrib.messages.warning") as mock_warning: # Create a request object with a superuser - request = self.factory.get("/admin/your_app/domainapplication/{}/change/".format(application.pk)) + request = self.factory.get("/admin/your_app/DomainRequest/{}/change/".format(application.pk)) request.user = self.superuser self.admin.display_restricted_warning(request, application) @@ -1253,14 +1253,14 @@ class TestDomainApplicationAdmin(MockEppLib): with less_console_noise(): # Create an instance of the model - application = completed_application(status=DomainApplication.ApplicationStatus.APPROVED) + application = completed_application(status=DomainRequest.ApplicationStatus.APPROVED) domain = Domain.objects.create(name=application.requested_domain.name) domain_information = DomainInformation.objects.create(creator=self.superuser, domain=domain) application.approved_domain = domain application.save() # Create a request object with a superuser - request = self.factory.post("/admin/registrar/domainapplication/{}/change/".format(application.pk)) + request = self.factory.post("/admin/registrar/DomainRequest/{}/change/".format(application.pk)) request.user = self.superuser # Define a custom implementation for is_active @@ -1299,38 +1299,38 @@ class TestDomainApplicationAdmin(MockEppLib): domain_information.refresh_from_db() def test_error_when_saving_approved_to_in_review_and_domain_is_active(self): - self.trigger_saving_approved_to_another_state(True, DomainApplication.ApplicationStatus.IN_REVIEW) + self.trigger_saving_approved_to_another_state(True, DomainRequest.ApplicationStatus.IN_REVIEW) def test_error_when_saving_approved_to_action_needed_and_domain_is_active(self): - self.trigger_saving_approved_to_another_state(True, DomainApplication.ApplicationStatus.ACTION_NEEDED) + self.trigger_saving_approved_to_another_state(True, DomainRequest.ApplicationStatus.ACTION_NEEDED) def test_error_when_saving_approved_to_rejected_and_domain_is_active(self): - self.trigger_saving_approved_to_another_state(True, DomainApplication.ApplicationStatus.REJECTED) + self.trigger_saving_approved_to_another_state(True, DomainRequest.ApplicationStatus.REJECTED) def test_error_when_saving_approved_to_ineligible_and_domain_is_active(self): - self.trigger_saving_approved_to_another_state(True, DomainApplication.ApplicationStatus.INELIGIBLE) + self.trigger_saving_approved_to_another_state(True, DomainRequest.ApplicationStatus.INELIGIBLE) def test_side_effects_when_saving_approved_to_in_review(self): - self.trigger_saving_approved_to_another_state(False, DomainApplication.ApplicationStatus.IN_REVIEW) + self.trigger_saving_approved_to_another_state(False, DomainRequest.ApplicationStatus.IN_REVIEW) def test_side_effects_when_saving_approved_to_action_needed(self): - self.trigger_saving_approved_to_another_state(False, DomainApplication.ApplicationStatus.ACTION_NEEDED) + self.trigger_saving_approved_to_another_state(False, DomainRequest.ApplicationStatus.ACTION_NEEDED) def test_side_effects_when_saving_approved_to_rejected(self): self.trigger_saving_approved_to_another_state( False, - DomainApplication.ApplicationStatus.REJECTED, - DomainApplication.RejectionReasons.CONTACTS_OR_ORGANIZATION_LEGITIMACY, + DomainRequest.ApplicationStatus.REJECTED, + DomainRequest.RejectionReasons.CONTACTS_OR_ORGANIZATION_LEGITIMACY, ) def test_side_effects_when_saving_approved_to_ineligible(self): - self.trigger_saving_approved_to_another_state(False, DomainApplication.ApplicationStatus.INELIGIBLE) + self.trigger_saving_approved_to_another_state(False, DomainRequest.ApplicationStatus.INELIGIBLE) def test_has_correct_filters(self): """ - This test verifies that DomainApplicationAdmin has the correct filters set up. + This test verifies that DomainRequestAdmin has the correct filters set up. - It retrieves the current list of filters from DomainApplicationAdmin + It retrieves the current list of filters from DomainRequestAdmin and checks that it matches the expected list of filters. """ with less_console_noise(): @@ -1343,32 +1343,32 @@ class TestDomainApplicationAdmin(MockEppLib): "status", "organization_type", "federal_type", - DomainApplicationAdmin.ElectionOfficeFilter, + DomainRequestAdmin.ElectionOfficeFilter, "rejection_reason", - DomainApplicationAdmin.InvestigatorFilter, + DomainRequestAdmin.InvestigatorFilter, ) self.assertEqual(readonly_fields, expected_fields) def test_table_sorted_alphabetically(self): """ - This test verifies that the DomainApplicationAdmin table is sorted alphabetically + This test verifies that the DomainRequestAdmin table is sorted alphabetically by the 'requested_domain__name' field. - It creates a list of DomainApplication instances in a non-alphabetical order, - then retrieves the queryset from the DomainApplicationAdmin and checks + It creates a list of DomainRequest instances in a non-alphabetical order, + then retrieves the queryset from the DomainRequestAdmin and checks that it matches the expected queryset, which is sorted alphabetically by the 'requested_domain__name' field. """ with less_console_noise(): - # Creates a list of DomainApplications in scrambled order + # Creates a list of DomainRequests in scrambled order multiple_unalphabetical_domain_objects("application") request = self.factory.get("/") request.user = self.superuser - # Get the expected list of alphabetically sorted DomainApplications - expected_order = DomainApplication.objects.order_by("requested_domain__name") + # Get the expected list of alphabetically sorted DomainRequests + expected_order = DomainRequest.objects.order_by("requested_domain__name") # Get the returned queryset queryset = self.admin.get_queryset(request) @@ -1382,11 +1382,11 @@ class TestDomainApplicationAdmin(MockEppLib): def test_displays_investigator_filter(self): """ This test verifies that the investigator filter in the admin interface for - the DomainApplication model displays correctly. + the DomainRequest model displays correctly. - It creates two DomainApplication instances, each with a different investigator. + It creates two DomainRequest instances, each with a different investigator. It then simulates a staff user logging in and applying the investigator filter - on the DomainApplication admin page. + on the DomainRequest admin page. We then test if the page displays the filter we expect, but we do not test if we get back the correct response in the table. This is to isolate if @@ -1394,8 +1394,8 @@ class TestDomainApplicationAdmin(MockEppLib): """ with less_console_noise(): - # Create a mock DomainApplication object, with a fake investigator - application: DomainApplication = generic_domain_object("application", "SomeGuy") + # Create a mock DomainRequest object, with a fake investigator + application: DomainRequest = generic_domain_object("application", "SomeGuy") investigator_user = User.objects.filter(username=application.investigator.username).get() investigator_user.is_staff = True investigator_user.save() @@ -1403,7 +1403,7 @@ class TestDomainApplicationAdmin(MockEppLib): p = "userpass" self.client.login(username="staffuser", password=p) response = self.client.get( - "/admin/registrar/domainapplication/", + "/admin/registrar/DomainRequest/", { "investigator__id__exact": investigator_user.id, }, @@ -1428,25 +1428,25 @@ class TestDomainApplicationAdmin(MockEppLib): def test_investigator_dropdown_displays_only_staff(self): """ - This test verifies that the dropdown for the 'investigator' field in the DomainApplicationAdmin + This test verifies that the dropdown for the 'investigator' field in the DomainRequestAdmin interface only displays users who are marked as staff. - It creates two DomainApplication instances, one with an investigator + It creates two DomainRequest instances, one with an investigator who is a staff user and another with an investigator who is not a staff user. - It then retrieves the queryset for the 'investigator' dropdown from DomainApplicationAdmin + It then retrieves the queryset for the 'investigator' dropdown from DomainRequestAdmin and checks that it matches the expected queryset, which only includes staff users. """ with less_console_noise(): - # Create a mock DomainApplication object, with a fake investigator - application: DomainApplication = generic_domain_object("application", "SomeGuy") + # Create a mock DomainRequest object, with a fake investigator + application: DomainRequest = generic_domain_object("application", "SomeGuy") investigator_user = User.objects.filter(username=application.investigator.username).get() investigator_user.is_staff = True investigator_user.save() - # Create a mock DomainApplication object, with a user that is not staff - application_2: DomainApplication = generic_domain_object("application", "SomeOtherGuy") + # Create a mock DomainRequest object, with a user that is not staff + application_2: DomainRequest = generic_domain_object("application", "SomeOtherGuy") investigator_user_2 = User.objects.filter(username=application_2.investigator.username).get() investigator_user_2.is_staff = False investigator_user_2.save() @@ -1454,10 +1454,10 @@ class TestDomainApplicationAdmin(MockEppLib): p = "userpass" self.client.login(username="staffuser", password=p) - request = self.factory.post("/admin/registrar/domainapplication/{}/change/".format(application.pk)) + request = self.factory.post("/admin/registrar/DomainRequest/{}/change/".format(application.pk)) # Get the actual field from the model's meta information - investigator_field = DomainApplication._meta.get_field("investigator") + investigator_field = DomainRequest._meta.get_field("investigator") # We should only be displaying staff users, in alphabetical order sorted_fields = ["first_name", "last_name", "email"] @@ -1466,7 +1466,7 @@ class TestDomainApplicationAdmin(MockEppLib): # Grab the current dropdown. We do an API call to autocomplete to get this info. application_queryset = self.admin.formfield_for_foreignkey(investigator_field, request).queryset user_request = self.factory.post( - "/admin/autocomplete/?app_label=registrar&model_name=domainapplication&field_name=investigator" + "/admin/autocomplete/?app_label=registrar&model_name=DomainRequest&field_name=investigator" ) user_admin = MyUserAdmin(User, self.site) user_queryset = user_admin.get_search_results(user_request, application_queryset, None)[0] @@ -1483,19 +1483,19 @@ class TestDomainApplicationAdmin(MockEppLib): is displayed alphabetically """ with less_console_noise(): - # Create a mock DomainApplication object, with a fake investigator - application: DomainApplication = generic_domain_object("application", "SomeGuy") + # Create a mock DomainRequest object, with a fake investigator + application: DomainRequest = generic_domain_object("application", "SomeGuy") investigator_user = User.objects.filter(username=application.investigator.username).get() investigator_user.is_staff = True investigator_user.save() - application_2: DomainApplication = generic_domain_object("application", "AGuy") + application_2: DomainRequest = generic_domain_object("application", "AGuy") investigator_user_2 = User.objects.filter(username=application_2.investigator.username).get() investigator_user_2.first_name = "AGuy" investigator_user_2.is_staff = True investigator_user_2.save() - application_3: DomainApplication = generic_domain_object("application", "FinalGuy") + application_3: DomainRequest = generic_domain_object("application", "FinalGuy") investigator_user_3 = User.objects.filter(username=application_3.investigator.username).get() investigator_user_3.first_name = "FinalGuy" investigator_user_3.is_staff = True @@ -1522,7 +1522,7 @@ class TestDomainApplicationAdmin(MockEppLib): super().tearDown() Domain.objects.all().delete() DomainInformation.objects.all().delete() - DomainApplication.objects.all().delete() + DomainRequest.objects.all().delete() User.objects.all().delete() Contact.objects.all().delete() Website.objects.all().delete() @@ -1617,7 +1617,7 @@ class TestDomainInformationAdmin(TestCase): def tearDown(self): """Delete all Users, Domains, and UserDomainRoles""" DomainInformation.objects.all().delete() - DomainApplication.objects.all().delete() + DomainRequest.objects.all().delete() Domain.objects.all().delete() Contact.objects.all().delete() User.objects.all().delete() @@ -1635,7 +1635,7 @@ class TestDomainInformationAdmin(TestCase): "type_of_work", "more_organization_information", "domain", - "domain_application", + "domain_request", "submitter", "no_other_contacts_rationale", "anything_else", @@ -1809,7 +1809,7 @@ class ListHeaderAdminTest(TestCase): def setUp(self): self.site = AdminSite() self.factory = RequestFactory() - self.admin = ListHeaderAdmin(model=DomainApplication, admin_site=None) + self.admin = ListHeaderAdmin(model=DomainRequest, admin_site=None) self.client = Client(HTTP_HOST="localhost:8080") self.superuser = create_superuser() @@ -1824,7 +1824,7 @@ class ListHeaderAdminTest(TestCase): # which handles CSRF # Follow=True handles the redirect response = self.client.get( - "/admin/registrar/domainapplication/", + "/admin/registrar/DomainRequest/", { "status__exact": "started", "investigator__id__exact": user.id, @@ -1874,7 +1874,7 @@ class ListHeaderAdminTest(TestCase): def tearDown(self): # delete any applications too DomainInformation.objects.all().delete() - DomainApplication.objects.all().delete() + DomainRequest.objects.all().delete() User.objects.all().delete() @@ -1943,7 +1943,7 @@ class AuditedAdminTest(TestCase): return ordered_list - def test_alphabetically_sorted_domain_application_investigator(self): + def test_alphabetically_sorted_domain_request_investigator(self): """Tests if the investigator field is alphabetically sorted by mimicking the call event flow""" # Creates multiple domain applications - review status does not matter @@ -1951,16 +1951,16 @@ class AuditedAdminTest(TestCase): # Create a mock request application_request = self.factory.post( - "/admin/registrar/domainapplication/{}/change/".format(applications[0].pk) + "/admin/registrar/DomainRequest/{}/change/".format(applications[0].pk) ) # Get the formfield data from the application page - application_admin = AuditedAdmin(DomainApplication, self.site) - field = DomainApplication.investigator.field + application_admin = AuditedAdmin(DomainRequest, self.site) + field = DomainRequest.investigator.field application_queryset = application_admin.formfield_for_foreignkey(field, application_request).queryset request = self.factory.post( - "/admin/autocomplete/?app_label=registrar&model_name=domainapplication&field_name=investigator" + "/admin/autocomplete/?app_label=registrar&model_name=DomainRequest&field_name=investigator" ) sorted_fields = ["first_name", "last_name", "email"] @@ -1978,23 +1978,23 @@ class AuditedAdminTest(TestCase): ) # This test case should be refactored in general, as it is too overly specific and engineered - def test_alphabetically_sorted_fk_fields_domain_application(self): + def test_alphabetically_sorted_fk_fields_domain_request(self): with less_console_noise(): tested_fields = [ - DomainApplication.authorizing_official.field, - DomainApplication.submitter.field, - # DomainApplication.investigator.field, - DomainApplication.creator.field, - DomainApplication.requested_domain.field, + DomainRequest.authorizing_official.field, + DomainRequest.submitter.field, + # DomainRequest.investigator.field, + DomainRequest.creator.field, + DomainRequest.requested_domain.field, ] # Creates multiple domain applications - review status does not matter applications = multiple_unalphabetical_domain_objects("application") # Create a mock request - request = self.factory.post("/admin/registrar/domainapplication/{}/change/".format(applications[0].pk)) + request = self.factory.post("/admin/registrar/DomainRequest/{}/change/".format(applications[0].pk)) - model_admin = AuditedAdmin(DomainApplication, self.site) + model_admin = AuditedAdmin(DomainRequest, self.site) sorted_fields = [] # Typically we wouldn't want two nested for fields, @@ -2002,7 +2002,7 @@ class AuditedAdminTest(TestCase): # For test case purposes, this should be performant. for field in tested_fields: with self.subTest(field=field): - isNamefield: bool = field == DomainApplication.requested_domain.field + isNamefield: bool = field == DomainRequest.requested_domain.field if isNamefield: sorted_fields = ["name"] else: @@ -2043,7 +2043,7 @@ class AuditedAdminTest(TestCase): DomainInformation.submitter.field, # DomainInformation.creator.field, (DomainInformation.domain.field, ["name"]), - (DomainInformation.domain_application.field, ["requested_domain__name"]), + (DomainInformation.domain_request.field, ["requested_domain__name"]), ] # Creates multiple domain applications - review status does not matter applications = multiple_unalphabetical_domain_objects("information") @@ -2083,7 +2083,7 @@ class AuditedAdminTest(TestCase): last = obj.last_name elif field_obj == DomainInformation.domain.field: first = obj.name - elif field_obj == DomainInformation.domain_application.field: + elif field_obj == DomainInformation.domain_request.field: first = obj.requested_domain.name name_tuple = self.coerced_fk_field_helper(first, last, field_obj.name, ":") @@ -2156,7 +2156,7 @@ class AuditedAdminTest(TestCase): def tearDown(self): DomainInformation.objects.all().delete() - DomainApplication.objects.all().delete() + DomainRequest.objects.all().delete() DomainInvitation.objects.all().delete() @@ -2342,14 +2342,14 @@ class ContactAdminTest(TestCase): mock_warning.assert_called_once_with( response.wsgi_request, "", @@ -2377,22 +2377,22 @@ class ContactAdminTest(TestCase): mock_warning.assert_called_once_with( response.wsgi_request, "" "

And 1 more...

", ) def tearDown(self): - DomainApplication.objects.all().delete() + DomainRequest.objects.all().delete() Contact.objects.all().delete() User.objects.all().delete() diff --git a/src/registrar/tests/test_migrations.py b/src/registrar/tests/test_migrations.py index 773a885c1..4dcfd89bb 100644 --- a/src/registrar/tests/test_migrations.py +++ b/src/registrar/tests/test_migrations.py @@ -34,7 +34,7 @@ class TestGroups(TestCase): "view_logentry", "change_contact", "view_domain", - "change_domainapplication", + "change_DomainRequest", "change_domaininformation", "add_domaininvitation", "view_domaininvitation", diff --git a/src/registrar/tests/test_models.py b/src/registrar/tests/test_models.py index f243956ff..90a3d924a 100644 --- a/src/registrar/tests/test_models.py +++ b/src/registrar/tests/test_models.py @@ -4,7 +4,7 @@ from unittest.mock import patch from registrar.models import ( Contact, - DomainApplication, + DomainRequest, DomainInformation, User, Website, @@ -22,34 +22,34 @@ from django_fsm import TransitionNotAllowed # Test comment for push -- will remove -# The DomainApplication submit method has a side effect of sending an email +# The DomainRequest submit method has a side effect of sending an email # with AWS SES, so mock that out in all of these test cases @boto3_mocking.patching -class TestDomainApplication(TestCase): +class TestDomainRequest(TestCase): def setUp(self): self.started_application = completed_application( - status=DomainApplication.ApplicationStatus.STARTED, name="started.gov" + status=DomainRequest.ApplicationStatus.STARTED, name="started.gov" ) self.submitted_application = completed_application( - status=DomainApplication.ApplicationStatus.SUBMITTED, name="submitted.gov" + status=DomainRequest.ApplicationStatus.SUBMITTED, name="submitted.gov" ) self.in_review_application = completed_application( - status=DomainApplication.ApplicationStatus.IN_REVIEW, name="in-review.gov" + status=DomainRequest.ApplicationStatus.IN_REVIEW, name="in-review.gov" ) self.action_needed_application = completed_application( - status=DomainApplication.ApplicationStatus.ACTION_NEEDED, name="action-needed.gov" + status=DomainRequest.ApplicationStatus.ACTION_NEEDED, name="action-needed.gov" ) self.approved_application = completed_application( - status=DomainApplication.ApplicationStatus.APPROVED, name="approved.gov" + status=DomainRequest.ApplicationStatus.APPROVED, name="approved.gov" ) self.withdrawn_application = completed_application( - status=DomainApplication.ApplicationStatus.WITHDRAWN, name="withdrawn.gov" + status=DomainRequest.ApplicationStatus.WITHDRAWN, name="withdrawn.gov" ) self.rejected_application = completed_application( - status=DomainApplication.ApplicationStatus.REJECTED, name="rejected.gov" + status=DomainRequest.ApplicationStatus.REJECTED, name="rejected.gov" ) self.ineligible_application = completed_application( - status=DomainApplication.ApplicationStatus.INELIGIBLE, name="ineligible.gov" + status=DomainRequest.ApplicationStatus.INELIGIBLE, name="ineligible.gov" ) self.mock_client = MockSESClient() @@ -64,19 +64,19 @@ class TestDomainApplication(TestCase): return self.assertRaises(Exception, None, exception_type) def test_empty_create_fails(self): - """Can't create a completely empty domain application. + """Can't create a completely empty domain request. NOTE: something about theexception this test raises messes up with the atomic block in a custom tearDown method for the parent test class.""" with less_console_noise(): with self.assertRaisesRegex(IntegrityError, "creator"): - DomainApplication.objects.create() + DomainRequest.objects.create() def test_minimal_create(self): """Can create with just a creator.""" with less_console_noise(): user, _ = User.objects.get_or_create(username="testy") - application = DomainApplication.objects.create(creator=user) - self.assertEqual(application.status, DomainApplication.ApplicationStatus.STARTED) + application = DomainRequest.objects.create(creator=user) + self.assertEqual(application.status, DomainRequest.ApplicationStatus.STARTED) def test_full_create(self): """Can create with all fields.""" @@ -86,11 +86,11 @@ class TestDomainApplication(TestCase): com_website, _ = Website.objects.get_or_create(website="igorville.com") gov_website, _ = Website.objects.get_or_create(website="igorville.gov") domain, _ = DraftDomain.objects.get_or_create(name="igorville.gov") - application = DomainApplication.objects.create( + application = DomainRequest.objects.create( creator=user, investigator=user, - organization_type=DomainApplication.OrganizationChoices.FEDERAL, - federal_type=DomainApplication.BranchChoices.EXECUTIVE, + organization_type=DomainRequest.OrganizationChoices.FEDERAL, + federal_type=DomainRequest.BranchChoices.EXECUTIVE, is_election_board=False, organization_name="Test", address_line1="100 Main St.", @@ -140,7 +140,7 @@ class TestDomainApplication(TestCase): def test_status_fsm_submit_fail(self): with less_console_noise(): user, _ = User.objects.get_or_create(username="testy") - application = DomainApplication.objects.create(creator=user) + application = DomainRequest.objects.create(creator=user) with boto3_mocking.clients.handler_for("sesv2", self.mock_client): with less_console_noise(): @@ -152,7 +152,7 @@ class TestDomainApplication(TestCase): with less_console_noise(): user, _ = User.objects.get_or_create(username="testy") site = DraftDomain.objects.create(name="igorville.gov") - application = DomainApplication.objects.create(creator=user, requested_domain=site) + application = DomainRequest.objects.create(creator=user, requested_domain=site) # no submitter email so this emits a log warning @@ -186,37 +186,37 @@ class TestDomainApplication(TestCase): def test_submit_from_withdrawn_sends_email(self): msg = "Create a withdrawn application and submit it and see if email was sent." - application = completed_application(status=DomainApplication.ApplicationStatus.WITHDRAWN) + application = completed_application(status=DomainRequest.ApplicationStatus.WITHDRAWN) self.check_email_sent(application, msg, "submit", 1) def test_submit_from_action_needed_does_not_send_email(self): msg = "Create an application with ACTION_NEEDED status and submit it, check if email was not sent." - application = completed_application(status=DomainApplication.ApplicationStatus.ACTION_NEEDED) + application = completed_application(status=DomainRequest.ApplicationStatus.ACTION_NEEDED) self.check_email_sent(application, msg, "submit", 0) def test_submit_from_in_review_does_not_send_email(self): msg = "Create a withdrawn application and submit it and see if email was sent." - application = completed_application(status=DomainApplication.ApplicationStatus.IN_REVIEW) + application = completed_application(status=DomainRequest.ApplicationStatus.IN_REVIEW) self.check_email_sent(application, msg, "submit", 0) def test_approve_sends_email(self): msg = "Create an application and approve it and see if email was sent." - application = completed_application(status=DomainApplication.ApplicationStatus.IN_REVIEW) + application = completed_application(status=DomainRequest.ApplicationStatus.IN_REVIEW) self.check_email_sent(application, msg, "approve", 1) def test_withdraw_sends_email(self): msg = "Create an application and withdraw it and see if email was sent." - application = completed_application(status=DomainApplication.ApplicationStatus.IN_REVIEW) + application = completed_application(status=DomainRequest.ApplicationStatus.IN_REVIEW) self.check_email_sent(application, msg, "withdraw", 1) def test_reject_sends_email(self): msg = "Create an application and reject it and see if email was sent." - application = completed_application(status=DomainApplication.ApplicationStatus.APPROVED) + application = completed_application(status=DomainRequest.ApplicationStatus.APPROVED) self.check_email_sent(application, msg, "reject", 1) def test_reject_with_prejudice_does_not_send_email(self): msg = "Create an application and reject it with prejudice and see if email was sent." - application = completed_application(status=DomainApplication.ApplicationStatus.APPROVED) + application = completed_application(status=DomainRequest.ApplicationStatus.APPROVED) self.check_email_sent(application, msg, "reject_with_prejudice", 0) def test_submit_transition_allowed(self): @@ -580,14 +580,14 @@ class TestDomainApplication(TestCase): with less_console_noise(): # Create a sample application - application = completed_application(status=DomainApplication.ApplicationStatus.REJECTED) - application.rejection_reason = DomainApplication.RejectionReasons.DOMAIN_PURPOSE + application = completed_application(status=DomainRequest.ApplicationStatus.REJECTED) + application.rejection_reason = DomainRequest.RejectionReasons.DOMAIN_PURPOSE # Approve with boto3_mocking.clients.handler_for("sesv2", self.mock_client): application.approve() - self.assertEqual(application.status, DomainApplication.ApplicationStatus.APPROVED) + self.assertEqual(application.status, DomainRequest.ApplicationStatus.APPROVED) self.assertEqual(application.rejection_reason, None) def test_in_review_from_rejected_clears_rejection_reason(self): @@ -596,15 +596,15 @@ class TestDomainApplication(TestCase): with less_console_noise(): # Create a sample application - application = completed_application(status=DomainApplication.ApplicationStatus.REJECTED) + application = completed_application(status=DomainRequest.ApplicationStatus.REJECTED) application.domain_is_not_active = True - application.rejection_reason = DomainApplication.RejectionReasons.DOMAIN_PURPOSE + application.rejection_reason = DomainRequest.RejectionReasons.DOMAIN_PURPOSE # Approve with boto3_mocking.clients.handler_for("sesv2", self.mock_client): application.in_review() - self.assertEqual(application.status, DomainApplication.ApplicationStatus.IN_REVIEW) + self.assertEqual(application.status, DomainRequest.ApplicationStatus.IN_REVIEW) self.assertEqual(application.rejection_reason, None) def test_action_needed_from_rejected_clears_rejection_reason(self): @@ -613,15 +613,15 @@ class TestDomainApplication(TestCase): with less_console_noise(): # Create a sample application - application = completed_application(status=DomainApplication.ApplicationStatus.REJECTED) + application = completed_application(status=DomainRequest.ApplicationStatus.REJECTED) application.domain_is_not_active = True - application.rejection_reason = DomainApplication.RejectionReasons.DOMAIN_PURPOSE + application.rejection_reason = DomainRequest.RejectionReasons.DOMAIN_PURPOSE # Approve with boto3_mocking.clients.handler_for("sesv2", self.mock_client): application.action_needed() - self.assertEqual(application.status, DomainApplication.ApplicationStatus.ACTION_NEEDED) + self.assertEqual(application.status, DomainRequest.ApplicationStatus.ACTION_NEEDED) self.assertEqual(application.rejection_reason, None) def test_has_rationale_returns_true(self): @@ -646,7 +646,7 @@ class TestDomainApplication(TestCase): """has_other_contacts() returns false when an application has no other_contacts""" with less_console_noise(): application = completed_application( - status=DomainApplication.ApplicationStatus.STARTED, name="no-others.gov", has_other_contacts=False + status=DomainRequest.ApplicationStatus.STARTED, name="no-others.gov", has_other_contacts=False ) self.assertEquals(application.has_other_contacts(), False) @@ -666,12 +666,12 @@ class TestPermissions(TestCase): def test_approval_creates_role(self): draft_domain, _ = DraftDomain.objects.get_or_create(name="igorville.gov") user, _ = User.objects.get_or_create() - application = DomainApplication.objects.create(creator=user, requested_domain=draft_domain) + application = DomainRequest.objects.create(creator=user, requested_domain=draft_domain) with boto3_mocking.clients.handler_for("sesv2", self.mock_client): with less_console_noise(): # skip using the submit method - application.status = DomainApplication.ApplicationStatus.SUBMITTED + application.status = DomainRequest.ApplicationStatus.SUBMITTED application.approve() # should be a role for this user @@ -691,7 +691,7 @@ class TestDomainInformation(TestCase): self.mock_client.EMAILS_SENT.clear() Domain.objects.all().delete() DomainInformation.objects.all().delete() - DomainApplication.objects.all().delete() + DomainRequest.objects.all().delete() User.objects.all().delete() DraftDomain.objects.all().delete() @@ -700,12 +700,12 @@ class TestDomainInformation(TestCase): self.maxDiff = None draft_domain, _ = DraftDomain.objects.get_or_create(name="igorville.gov") user, _ = User.objects.get_or_create() - application = DomainApplication.objects.create(creator=user, requested_domain=draft_domain, notes="test notes") + application = DomainRequest.objects.create(creator=user, requested_domain=draft_domain, notes="test notes") with boto3_mocking.clients.handler_for("sesv2", self.mock_client): with less_console_noise(): # skip using the submit method - application.status = DomainApplication.ApplicationStatus.SUBMITTED + application.status = DomainRequest.ApplicationStatus.SUBMITTED application.approve() # should be an information present for this domain @@ -719,7 +719,7 @@ class TestDomainInformation(TestCase): creator=user, domain=domain, notes="test notes", - domain_application=application, + domain_request=application, ).__dict__ # Test the two records for consistency @@ -852,11 +852,11 @@ class TestContact(TestCase): self.contact, _ = Contact.objects.get_or_create(user=self.user) self.contact_as_ao, _ = Contact.objects.get_or_create(email="newguy@igorville.gov") - self.application = DomainApplication.objects.create(creator=self.user, authorizing_official=self.contact_as_ao) + self.application = DomainRequest.objects.create(creator=self.user, authorizing_official=self.contact_as_ao) def tearDown(self): super().tearDown() - DomainApplication.objects.all().delete() + DomainRequest.objects.all().delete() Contact.objects.all().delete() User.objects.all().delete() diff --git a/src/registrar/tests/test_models_domain.py b/src/registrar/tests/test_models_domain.py index d99eaa25c..65b1e2504 100644 --- a/src/registrar/tests/test_models_domain.py +++ b/src/registrar/tests/test_models_domain.py @@ -12,7 +12,7 @@ from django.utils.timezone import make_aware from registrar.models import Domain, Host, HostIP from unittest import skip -from registrar.models.domain_application import DomainApplication +from registrar.models.domain_request import DomainRequest from registrar.models.domain_information import DomainInformation from registrar.models.draft_domain import DraftDomain from registrar.models.public_contact import PublicContact @@ -311,25 +311,25 @@ class TestDomainCache(MockEppLib): class TestDomainCreation(MockEppLib): - """Rule: An approved domain application must result in a domain""" + """Rule: An approved domain request must result in a domain""" @boto3_mocking.patching def test_approved_application_creates_domain_locally(self): """ - Scenario: Analyst approves a domain application - When the DomainApplication transitions to approved + Scenario: Analyst approves a domain request + When the DomainRequest transitions to approved Then a Domain exists in the database with the same `name` But a domain object does not exist in the registry """ with less_console_noise(): draft_domain, _ = DraftDomain.objects.get_or_create(name="igorville.gov") user, _ = User.objects.get_or_create() - application = DomainApplication.objects.create(creator=user, requested_domain=draft_domain) + application = DomainRequest.objects.create(creator=user, requested_domain=draft_domain) mock_client = MockSESClient() with boto3_mocking.clients.handler_for("sesv2", mock_client): # skip using the submit method - application.status = DomainApplication.ApplicationStatus.SUBMITTED + application.status = DomainRequest.ApplicationStatus.SUBMITTED # transition to approve state application.approve() # should have information present for this domain @@ -395,7 +395,7 @@ class TestDomainCreation(MockEppLib): def tearDown(self) -> None: DomainInformation.objects.all().delete() - DomainApplication.objects.all().delete() + DomainRequest.objects.all().delete() PublicContact.objects.all().delete() Domain.objects.all().delete() User.objects.all().delete() diff --git a/src/registrar/tests/test_views.py b/src/registrar/tests/test_views.py index 8f9a8e4fc..655cece4a 100644 --- a/src/registrar/tests/test_views.py +++ b/src/registrar/tests/test_views.py @@ -5,7 +5,7 @@ from .common import MockEppLib # type: ignore from registrar.models import ( - DomainApplication, + DomainRequest, DomainInformation, ) import logging @@ -47,7 +47,7 @@ class TestWithUser(MockEppLib): def tearDown(self): # delete any applications too super().tearDown() - DomainApplication.objects.all().delete() + DomainRequest.objects.all().delete() DomainInformation.objects.all().delete() self.user.delete() diff --git a/src/registrar/tests/test_views_application.py b/src/registrar/tests/test_views_application.py index 7da906a8f..f19c6c41d 100644 --- a/src/registrar/tests/test_views_application.py +++ b/src/registrar/tests/test_views_application.py @@ -10,7 +10,7 @@ from django_webtest import WebTest # type: ignore import boto3_mocking # type: ignore from registrar.models import ( - DomainApplication, + DomainRequest, DraftDomain, Domain, DomainInformation, @@ -29,8 +29,8 @@ import logging logger = logging.getLogger(__name__) -class DomainApplicationTests(TestWithUser, WebTest): - """Webtests for domain application to test filling and submitting.""" +class DomainRequestTests(TestWithUser, WebTest): + """Webtests for domain request to test filling and submitting.""" # Doesn't work with CSRF checking # hypothesis is that CSRF_USE_SESSIONS is incompatible with WebTest @@ -48,7 +48,7 @@ class DomainApplicationTests(TestWithUser, WebTest): def test_application_form_intro_is_skipped_when_edit_access(self): """Tests that user is NOT presented with intro acknowledgement page when accessed through 'edit'""" - completed_application(status=DomainApplication.ApplicationStatus.STARTED, user=self.user) + completed_application(status=DomainRequest.ApplicationStatus.STARTED, user=self.user) home_page = self.app.get("/") self.assertContains(home_page, "city.gov") # click the "Edit" link @@ -146,7 +146,7 @@ class DomainApplicationTests(TestWithUser, WebTest): self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) type_result = type_form.submit() # should see results in db - application = DomainApplication.objects.get() # there's only one + application = DomainRequest.objects.get() # there's only one self.assertEqual(application.organization_type, "federal") # the post request should return a redirect to the next form in # the application @@ -166,7 +166,7 @@ class DomainApplicationTests(TestWithUser, WebTest): self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) federal_result = federal_form.submit() # validate that data from this step are being saved - application = DomainApplication.objects.get() # there's only one + application = DomainRequest.objects.get() # there's only one self.assertEqual(application.federal_type, "executive") # the post request should return a redirect to the next form in # the application @@ -193,7 +193,7 @@ class DomainApplicationTests(TestWithUser, WebTest): self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) org_contact_result = org_contact_form.submit() # validate that data from this step are being saved - application = DomainApplication.objects.get() # there's only one + application = DomainRequest.objects.get() # there's only one self.assertEqual(application.organization_name, "Testorg") self.assertEqual(application.address_line1, "address 1") self.assertEqual(application.address_line2, "address 2") @@ -221,7 +221,7 @@ class DomainApplicationTests(TestWithUser, WebTest): self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) ao_result = ao_form.submit() # validate that data from this step are being saved - application = DomainApplication.objects.get() # there's only one + application = DomainRequest.objects.get() # there's only one self.assertEqual(application.authorizing_official.first_name, "Testy ATO") self.assertEqual(application.authorizing_official.last_name, "Tester ATO") self.assertEqual(application.authorizing_official.title, "Chief Tester") @@ -243,7 +243,7 @@ class DomainApplicationTests(TestWithUser, WebTest): self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) current_sites_result = current_sites_form.submit() # validate that data from this step are being saved - application = DomainApplication.objects.get() # there's only one + application = DomainRequest.objects.get() # there's only one self.assertEqual( application.current_websites.filter(website="http://www.city.com").count(), 1, @@ -265,7 +265,7 @@ class DomainApplicationTests(TestWithUser, WebTest): self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) dotgov_result = dotgov_form.submit() # validate that data from this step are being saved - application = DomainApplication.objects.get() # there's only one + application = DomainRequest.objects.get() # there's only one self.assertEqual(application.requested_domain.name, "city.gov") self.assertEqual(application.alternative_domains.filter(website="city1.gov").count(), 1) # the post request should return a redirect to the next form in @@ -285,7 +285,7 @@ class DomainApplicationTests(TestWithUser, WebTest): self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) purpose_result = purpose_form.submit() # validate that data from this step are being saved - application = DomainApplication.objects.get() # there's only one + application = DomainRequest.objects.get() # there's only one self.assertEqual(application.purpose, "For all kinds of things.") # the post request should return a redirect to the next form in # the application @@ -309,7 +309,7 @@ class DomainApplicationTests(TestWithUser, WebTest): self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) your_contact_result = your_contact_form.submit() # validate that data from this step are being saved - application = DomainApplication.objects.get() # there's only one + application = DomainRequest.objects.get() # there's only one self.assertEqual(application.submitter.first_name, "Testy you") self.assertEqual(application.submitter.last_name, "Tester you") self.assertEqual(application.submitter.title, "Admin Tester") @@ -342,7 +342,7 @@ class DomainApplicationTests(TestWithUser, WebTest): self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) other_contacts_result = other_contacts_form.submit() # validate that data from this step are being saved - application = DomainApplication.objects.get() # there's only one + application = DomainRequest.objects.get() # there's only one self.assertEqual( application.other_contacts.filter( first_name="Testy2", @@ -371,7 +371,7 @@ class DomainApplicationTests(TestWithUser, WebTest): self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) anything_else_result = anything_else_form.submit() # validate that data from this step are being saved - application = DomainApplication.objects.get() # there's only one + application = DomainRequest.objects.get() # there's only one self.assertEqual(application.anything_else, "Nothing else.") # the post request should return a redirect to the next form in # the application @@ -391,7 +391,7 @@ class DomainApplicationTests(TestWithUser, WebTest): self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) requirements_result = requirements_form.submit() # validate that data from this step are being saved - application = DomainApplication.objects.get() # there's only one + application = DomainRequest.objects.get() # there's only one self.assertEqual(application.is_policy_acknowledged, True) # the post request should return a redirect to the next form in # the application @@ -663,7 +663,7 @@ class DomainApplicationTests(TestWithUser, WebTest): session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] type_form = type_page.forms[0] - type_form["organization_type-organization_type"] = DomainApplication.OrganizationChoices.INTERSTATE + type_form["organization_type-organization_type"] = DomainRequest.OrganizationChoices.INTERSTATE self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) type_result = type_form.submit() @@ -708,7 +708,7 @@ class DomainApplicationTests(TestWithUser, WebTest): session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] type_form = type_page.forms[0] - type_form["organization_type-organization_type"] = DomainApplication.OrganizationChoices.SPECIAL_DISTRICT + type_form["organization_type-organization_type"] = DomainRequest.OrganizationChoices.SPECIAL_DISTRICT self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) type_result = type_page.forms[0].submit() # follow first redirect @@ -803,7 +803,7 @@ class DomainApplicationTests(TestWithUser, WebTest): self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) # Verify that the no_other_contacts_rationale we saved earlier has been removed from the database - application = DomainApplication.objects.get() + application = DomainRequest.objects.get() self.assertEqual( application.other_contacts.count(), 1, @@ -845,7 +845,7 @@ class DomainApplicationTests(TestWithUser, WebTest): self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) # Verify that the no_other_contacts_rationale we saved earlier has been removed from the database - application = DomainApplication.objects.get() + application = DomainRequest.objects.get() self.assertEqual( application.other_contacts.count(), 0, @@ -859,7 +859,7 @@ class DomainApplicationTests(TestWithUser, WebTest): def test_submitting_no_other_contacts_rationale_removes_reference_other_contacts_when_joined(self): """When a user submits the Other Contacts form with no other contacts selected, the application's other contacts references get removed for other contacts that exist and are joined to other objects""" - # Populate the database with a domain application that + # Populate the database with a domain request that # has 1 "other contact" assigned to it # We'll do it from scratch so we can reuse the other contact ao, _ = Contact.objects.get_or_create( @@ -883,7 +883,7 @@ class DomainApplicationTests(TestWithUser, WebTest): email="testy2@town.com", phone="(555) 555 5557", ) - application, _ = DomainApplication.objects.get_or_create( + application, _ = DomainRequest.objects.get_or_create( organization_type="federal", federal_type="executive", purpose="Purpose of the site", @@ -929,7 +929,7 @@ class DomainApplicationTests(TestWithUser, WebTest): self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) # Verify that the no_other_contacts_rationale we saved earlier is no longer associated with the application - application = DomainApplication.objects.get() + application = DomainRequest.objects.get() self.assertEqual( application.other_contacts.count(), 0, @@ -986,7 +986,7 @@ class DomainApplicationTests(TestWithUser, WebTest): This formset uses the DJANGO DELETE widget. We'll test that by setting 2 contacts on an application, loading the form and marking one contact up for deletion.""" - # Populate the database with a domain application that + # Populate the database with a domain request that # has 2 "other contact" assigned to it # We'll do it from scratch so we can reuse the other contact ao, _ = Contact.objects.get_or_create( @@ -1017,7 +1017,7 @@ class DomainApplicationTests(TestWithUser, WebTest): email="testy3@town.com", phone="(201) 555 5557", ) - application, _ = DomainApplication.objects.get_or_create( + application, _ = DomainRequest.objects.get_or_create( organization_type="federal", federal_type="executive", purpose="Purpose of the site", @@ -1061,13 +1061,13 @@ class DomainApplicationTests(TestWithUser, WebTest): self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) # Verify that the first dude was deleted - application = DomainApplication.objects.get() + application = DomainRequest.objects.get() self.assertEqual(application.other_contacts.count(), 1) self.assertEqual(application.other_contacts.first().first_name, "Testy3") def test_delete_other_contact_does_not_allow_zero_contacts(self): """Delete Other Contact does not allow submission with zero contacts.""" - # Populate the database with a domain application that + # Populate the database with a domain request that # has 1 "other contact" assigned to it # We'll do it from scratch so we can reuse the other contact ao, _ = Contact.objects.get_or_create( @@ -1091,7 +1091,7 @@ class DomainApplicationTests(TestWithUser, WebTest): email="testy2@town.com", phone="(201) 555 5557", ) - application, _ = DomainApplication.objects.get_or_create( + application, _ = DomainRequest.objects.get_or_create( organization_type="federal", federal_type="executive", purpose="Purpose of the site", @@ -1133,7 +1133,7 @@ class DomainApplicationTests(TestWithUser, WebTest): self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) # Verify that the contact was not deleted - application = DomainApplication.objects.get() + application = DomainRequest.objects.get() self.assertEqual(application.other_contacts.count(), 1) self.assertEqual(application.other_contacts.first().first_name, "Testy2") @@ -1144,7 +1144,7 @@ class DomainApplicationTests(TestWithUser, WebTest): 3. then submit, The forms on page reload shows all the required fields and their errors.""" - # Populate the database with a domain application that + # Populate the database with a domain request that # has 1 "other contact" assigned to it # We'll do it from scratch so we can reuse the other contact ao, _ = Contact.objects.get_or_create( @@ -1168,7 +1168,7 @@ class DomainApplicationTests(TestWithUser, WebTest): email="testy2@town.com", phone="(201) 555 5557", ) - application, _ = DomainApplication.objects.get_or_create( + application, _ = DomainRequest.objects.get_or_create( organization_type="federal", federal_type="executive", purpose="Purpose of the site", @@ -1220,7 +1220,7 @@ class DomainApplicationTests(TestWithUser, WebTest): 2. then submit, The application is linked to the existing contact, and the existing contact updated.""" - # Populate the database with a domain application that + # Populate the database with a domain request that # has 1 "other contact" assigned to it # We'll do it from scratch ao, _ = Contact.objects.get_or_create( @@ -1244,7 +1244,7 @@ class DomainApplicationTests(TestWithUser, WebTest): email="testy2@town.com", phone="(201) 555 5557", ) - application, _ = DomainApplication.objects.get_or_create( + application, _ = DomainRequest.objects.get_or_create( organization_type="federal", federal_type="executive", purpose="Purpose of the site", @@ -1301,7 +1301,7 @@ class DomainApplicationTests(TestWithUser, WebTest): 2. then submit, The application is linked to a new contact, and the new contact is updated.""" - # Populate the database with a domain application that + # Populate the database with a domain request that # has 1 "other contact" assigned to it, the other contact is also # the authorizing official initially # We'll do it from scratch @@ -1319,7 +1319,7 @@ class DomainApplicationTests(TestWithUser, WebTest): email="testy-admin@town.com", phone="(201) 555 5556", ) - application, _ = DomainApplication.objects.get_or_create( + application, _ = DomainRequest.objects.get_or_create( organization_type="federal", federal_type="executive", purpose="Purpose of the site", @@ -1381,7 +1381,7 @@ class DomainApplicationTests(TestWithUser, WebTest): 2. then submit, The application is linked to the existing ao, and the ao updated.""" - # Populate the database with a domain application that + # Populate the database with a domain request that # has an authorizing_official (ao) # We'll do it from scratch ao, _ = Contact.objects.get_or_create( @@ -1391,7 +1391,7 @@ class DomainApplicationTests(TestWithUser, WebTest): email="testy@town.com", phone="(201) 555 5555", ) - application, _ = DomainApplication.objects.get_or_create( + application, _ = DomainRequest.objects.get_or_create( organization_type="federal", federal_type="executive", purpose="Purpose of the site", @@ -1446,7 +1446,7 @@ class DomainApplicationTests(TestWithUser, WebTest): 2. then submit, The application is linked to a new Contact, and the new Contact is updated.""" - # Populate the database with a domain application that + # Populate the database with a domain request that # has authorizing official assigned to it, the authorizing offical is also # an other contact initially # We'll do it from scratch @@ -1457,7 +1457,7 @@ class DomainApplicationTests(TestWithUser, WebTest): email="testy@town.com", phone="(201) 555 5555", ) - application, _ = DomainApplication.objects.get_or_create( + application, _ = DomainRequest.objects.get_or_create( organization_type="federal", federal_type="executive", purpose="Purpose of the site", @@ -1518,7 +1518,7 @@ class DomainApplicationTests(TestWithUser, WebTest): 2. then submit, The application is linked to the existing submitter, and the submitter updated.""" - # Populate the database with a domain application that + # Populate the database with a domain request that # has a submitter # We'll do it from scratch you, _ = Contact.objects.get_or_create( @@ -1528,7 +1528,7 @@ class DomainApplicationTests(TestWithUser, WebTest): email="testy@town.com", phone="(201) 555 5555", ) - application, _ = DomainApplication.objects.get_or_create( + application, _ = DomainRequest.objects.get_or_create( organization_type="federal", federal_type="executive", purpose="Purpose of the site", @@ -1582,7 +1582,7 @@ class DomainApplicationTests(TestWithUser, WebTest): 2. then submit, The application is linked to a new Contact, and the new Contact is updated.""" - # Populate the database with a domain application that + # Populate the database with a domain request that # has submitter assigned to it, the submitter is also # an other contact initially # We'll do it from scratch @@ -1593,7 +1593,7 @@ class DomainApplicationTests(TestWithUser, WebTest): email="testy@town.com", phone="(201) 555 5555", ) - application, _ = DomainApplication.objects.get_or_create( + application, _ = DomainRequest.objects.get_or_create( organization_type="federal", federal_type="executive", purpose="Purpose of the site", @@ -1667,7 +1667,7 @@ class DomainApplicationTests(TestWithUser, WebTest): session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] type_form = type_page.forms[0] - type_form["organization_type-organization_type"] = DomainApplication.OrganizationChoices.INTERSTATE + type_form["organization_type-organization_type"] = DomainRequest.OrganizationChoices.INTERSTATE self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) type_result = type_form.submit() # follow first redirect @@ -1695,7 +1695,7 @@ class DomainApplicationTests(TestWithUser, WebTest): session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] type_form = type_page.forms[0] - type_form["organization_type-organization_type"] = DomainApplication.OrganizationChoices.TRIBAL + type_form["organization_type-organization_type"] = DomainRequest.OrganizationChoices.TRIBAL self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) type_result = type_form.submit() # the tribal government page comes immediately afterwards @@ -1900,7 +1900,7 @@ class DomainApplicationTests(TestWithUser, WebTest): self.assertEqual(value, "https://example.com") self.assertIn("current_sites-1-website", current_sites_form.fields) # and it is correctly referenced in the ManyToOne relationship - application = DomainApplication.objects.get() # there's only one + application = DomainRequest.objects.get() # there's only one self.assertEqual( application.current_websites.filter(website="https://example.com").count(), 1, @@ -1935,7 +1935,7 @@ class DomainApplicationTests(TestWithUser, WebTest): email="testy2@town.com", phone="(555) 555 5557", ) - application, _ = DomainApplication.objects.get_or_create( + application, _ = DomainRequest.objects.get_or_create( organization_type="federal", federal_type="executive", purpose="Purpose of the site", @@ -2068,7 +2068,7 @@ class DomainApplicationTests(TestWithUser, WebTest): self.assertContains(review_page, "You are about to submit an incomplete request") -class DomainApplicationTestDifferentStatuses(TestWithUser, WebTest): +class DomainRequestTestDifferentStatuses(TestWithUser, WebTest): def setUp(self): super().setUp() self.app.set_user(self.user.username) @@ -2076,7 +2076,7 @@ class DomainApplicationTestDifferentStatuses(TestWithUser, WebTest): def test_application_status(self): """Checking application status page""" - application = completed_application(status=DomainApplication.ApplicationStatus.SUBMITTED, user=self.user) + application = completed_application(status=DomainRequest.ApplicationStatus.SUBMITTED, user=self.user) application.save() home_page = self.app.get("/") @@ -2096,7 +2096,7 @@ class DomainApplicationTestDifferentStatuses(TestWithUser, WebTest): self.user.status = "ineligible" self.user.save() - application = completed_application(status=DomainApplication.ApplicationStatus.SUBMITTED, user=self.user) + application = completed_application(status=DomainRequest.ApplicationStatus.SUBMITTED, user=self.user) application.save() home_page = self.app.get("/") @@ -2111,7 +2111,7 @@ class DomainApplicationTestDifferentStatuses(TestWithUser, WebTest): def test_application_withdraw(self): """Checking application status page""" - application = completed_application(status=DomainApplication.ApplicationStatus.SUBMITTED, user=self.user) + application = completed_application(status=DomainRequest.ApplicationStatus.SUBMITTED, user=self.user) application.save() home_page = self.app.get("/") @@ -2146,7 +2146,7 @@ class DomainApplicationTestDifferentStatuses(TestWithUser, WebTest): """Can't withdraw applications as a restricted user.""" self.user.status = User.RESTRICTED self.user.save() - application = completed_application(status=DomainApplication.ApplicationStatus.SUBMITTED, user=self.user) + application = completed_application(status=DomainRequest.ApplicationStatus.SUBMITTED, user=self.user) application.save() home_page = self.app.get("/") @@ -2171,7 +2171,7 @@ class DomainApplicationTestDifferentStatuses(TestWithUser, WebTest): def test_application_status_no_permissions(self): """Can't access applications without being the creator.""" - application = completed_application(status=DomainApplication.ApplicationStatus.SUBMITTED, user=self.user) + application = completed_application(status=DomainRequest.ApplicationStatus.SUBMITTED, user=self.user) other_user = User() other_user.save() application.creator = other_user @@ -2191,7 +2191,7 @@ class DomainApplicationTestDifferentStatuses(TestWithUser, WebTest): def test_approved_application_not_in_active_requests(self): """An approved application is not shown in the Active Requests table on home.html.""" - application = completed_application(status=DomainApplication.ApplicationStatus.APPROVED, user=self.user) + application = completed_application(status=DomainRequest.ApplicationStatus.APPROVED, user=self.user) application.save() home_page = self.app.get("/") @@ -2222,7 +2222,7 @@ class TestWizardUnlockingSteps(TestWithUser, WebTest): def test_unlocked_steps_full_application(self): """Test when all fields in the application are filled.""" - completed_application(status=DomainApplication.ApplicationStatus.STARTED, user=self.user) + completed_application(status=DomainRequest.ApplicationStatus.STARTED, user=self.user) # Make a request to the home page home_page = self.app.get("/") # django-webtest does not handle cookie-based sessions well because it keeps @@ -2280,10 +2280,10 @@ class TestWizardUnlockingSteps(TestWithUser, WebTest): contact_user, _ = Contact.objects.get_or_create(user=self.user) site = DraftDomain.objects.create(name="igorville.gov") - application = DomainApplication.objects.create( + application = DomainRequest.objects.create( creator=self.user, requested_domain=site, - status=DomainApplication.ApplicationStatus.WITHDRAWN, + status=DomainRequest.ApplicationStatus.WITHDRAWN, authorizing_official=contact, submitter=contact_user, ) @@ -2341,11 +2341,11 @@ class HomeTests(TestWithUser): super().tearDown() Contact.objects.all().delete() - def test_home_lists_domain_applications(self): + def test_home_lists_domain_requests(self): response = self.client.get("/") self.assertNotContains(response, "igorville.gov") site = DraftDomain.objects.create(name="igorville.gov") - application = DomainApplication.objects.create(creator=self.user, requested_domain=site) + application = DomainRequest.objects.create(creator=self.user, requested_domain=site) response = self.client.get("/") # count = 7 because of screenreader content @@ -2464,12 +2464,12 @@ class HomeTests(TestWithUser): # Check that we have the right text content. self.assertContains(response, unknown_text, count=1) - def test_home_deletes_withdrawn_domain_application(self): - """Tests if the user can delete a DomainApplication in the 'withdrawn' status""" + def test_home_deletes_withdrawn_domain_request(self): + """Tests if the user can delete a DomainRequest in the 'withdrawn' status""" site = DraftDomain.objects.create(name="igorville.gov") - application = DomainApplication.objects.create( - creator=self.user, requested_domain=site, status=DomainApplication.ApplicationStatus.WITHDRAWN + application = DomainRequest.objects.create( + creator=self.user, requested_domain=site, status=DomainRequest.ApplicationStatus.WITHDRAWN ) # Ensure that igorville.gov exists on the page @@ -2488,12 +2488,12 @@ class HomeTests(TestWithUser): # clean up application.delete() - def test_home_deletes_started_domain_application(self): - """Tests if the user can delete a DomainApplication in the 'started' status""" + def test_home_deletes_started_domain_request(self): + """Tests if the user can delete a DomainRequest in the 'started' status""" site = DraftDomain.objects.create(name="igorville.gov") - application = DomainApplication.objects.create( - creator=self.user, requested_domain=site, status=DomainApplication.ApplicationStatus.STARTED + application = DomainRequest.objects.create( + creator=self.user, requested_domain=site, status=DomainRequest.ApplicationStatus.STARTED ) # Ensure that igorville.gov exists on the page @@ -2512,20 +2512,20 @@ class HomeTests(TestWithUser): # clean up application.delete() - def test_home_doesnt_delete_other_domain_applications(self): + def test_home_doesnt_delete_other_domain_requests(self): """Tests to ensure the user can't delete Applications not in the status of STARTED or WITHDRAWN""" # Given that we are including a subset of items that can be deleted while excluding the rest, # subTest is appropriate here as otherwise we would need many duplicate tests for the same reason. with less_console_noise(): draft_domain = DraftDomain.objects.create(name="igorville.gov") - for status in DomainApplication.ApplicationStatus: + for status in DomainRequest.ApplicationStatus: if status not in [ - DomainApplication.ApplicationStatus.STARTED, - DomainApplication.ApplicationStatus.WITHDRAWN, + DomainRequest.ApplicationStatus.STARTED, + DomainRequest.ApplicationStatus.WITHDRAWN, ]: with self.subTest(status=status): - application = DomainApplication.objects.create( + application = DomainRequest.objects.create( creator=self.user, requested_domain=draft_domain, status=status ) @@ -2537,16 +2537,16 @@ class HomeTests(TestWithUser): # Check for a 403 error - the end user should not be allowed to do this self.assertEqual(response.status_code, 403) - desired_application = DomainApplication.objects.filter(requested_domain=draft_domain) + desired_application = DomainRequest.objects.filter(requested_domain=draft_domain) - # Make sure the DomainApplication wasn't deleted + # Make sure the DomainRequest wasn't deleted self.assertEqual(desired_application.count(), 1) # clean up application.delete() - def test_home_deletes_domain_application_and_orphans(self): - """Tests if delete for DomainApplication deletes orphaned Contact objects""" + def test_home_deletes_domain_request_and_orphans(self): + """Tests if delete for DomainRequest deletes orphaned Contact objects""" # Create the site and contacts to delete (orphaned) contact = Contact.objects.create( @@ -2568,10 +2568,10 @@ class HomeTests(TestWithUser): contact_user, _ = Contact.objects.get_or_create(user=self.user) site = DraftDomain.objects.create(name="igorville.gov") - application = DomainApplication.objects.create( + application = DomainRequest.objects.create( creator=self.user, requested_domain=site, - status=DomainApplication.ApplicationStatus.WITHDRAWN, + status=DomainRequest.ApplicationStatus.WITHDRAWN, authorizing_official=contact, submitter=contact_user, ) @@ -2579,10 +2579,10 @@ class HomeTests(TestWithUser): # Create a second application to attach contacts to site_2 = DraftDomain.objects.create(name="teaville.gov") - application_2 = DomainApplication.objects.create( + application_2 = DomainRequest.objects.create( creator=self.user, requested_domain=site_2, - status=DomainApplication.ApplicationStatus.STARTED, + status=DomainRequest.ApplicationStatus.STARTED, authorizing_official=contact_2, submitter=contact_shared, ) @@ -2616,7 +2616,7 @@ class HomeTests(TestWithUser): self.assertEqual(edge_case, contact_2) - def test_home_deletes_domain_application_and_shared_orphans(self): + def test_home_deletes_domain_request_and_shared_orphans(self): """Test the edge case for an object that will become orphaned after a delete (but is not an orphan at the time of deletion)""" @@ -2640,10 +2640,10 @@ class HomeTests(TestWithUser): contact_user, _ = Contact.objects.get_or_create(user=self.user) site = DraftDomain.objects.create(name="igorville.gov") - application = DomainApplication.objects.create( + application = DomainRequest.objects.create( creator=self.user, requested_domain=site, - status=DomainApplication.ApplicationStatus.WITHDRAWN, + status=DomainRequest.ApplicationStatus.WITHDRAWN, authorizing_official=contact, submitter=contact_user, ) @@ -2651,10 +2651,10 @@ class HomeTests(TestWithUser): # Create a second application to attach contacts to site_2 = DraftDomain.objects.create(name="teaville.gov") - application_2 = DomainApplication.objects.create( + application_2 = DomainRequest.objects.create( creator=self.user, requested_domain=site_2, - status=DomainApplication.ApplicationStatus.STARTED, + status=DomainRequest.ApplicationStatus.STARTED, authorizing_official=contact_2, submitter=contact_shared, ) @@ -2679,7 +2679,7 @@ class HomeTests(TestWithUser): "You’re about to start your .gov domain request.", ) - def test_domain_application_form_with_ineligible_user(self): + def test_domain_request_form_with_ineligible_user(self): """Application form not accessible for an ineligible user. This test should be solid enough since all application wizard views share the same permissions class""" diff --git a/src/registrar/tests/test_views_domain.py b/src/registrar/tests/test_views_domain.py index 59b5faaa9..90b987020 100644 --- a/src/registrar/tests/test_views_domain.py +++ b/src/registrar/tests/test_views_domain.py @@ -21,7 +21,7 @@ from registrar.utility.errors import ( ) from registrar.models import ( - DomainApplication, + DomainRequest, Domain, DomainInformation, DomainInvitation, @@ -120,7 +120,7 @@ class TestWithDomainPermissions(TestWithUser): UserDomainRole.objects.all().delete() if hasattr(self.domain, "contacts"): self.domain.contacts.all().delete() - DomainApplication.objects.all().delete() + DomainRequest.objects.all().delete() DomainInformation.objects.all().delete() PublicContact.objects.all().delete() HostIP.objects.all().delete() @@ -311,7 +311,7 @@ class TestDomainDetail(TestDomainOverview): def test_domain_detail_with_no_information_or_application(self): """Test that domain management page returns 200 and displays error - when no domain information or domain application exist""" + when no domain information or domain request exist""" with less_console_noise(): # have to use staff user for this test staff_user = create_user() diff --git a/src/registrar/views/application.py b/src/registrar/views/application.py index b71018d81..4c3ffe306 100644 --- a/src/registrar/views/application.py +++ b/src/registrar/views/application.py @@ -9,16 +9,16 @@ from django.views.generic import TemplateView from django.contrib import messages from registrar.forms import application_wizard as forms -from registrar.models import DomainApplication +from registrar.models import DomainRequest from registrar.models.contact import Contact from registrar.models.user import User from registrar.utility import StrEnum from registrar.views.utility import StepsHelper -from registrar.views.utility.permission_views import DomainApplicationPermissionDeleteView +from registrar.views.utility.permission_views import DomainRequestPermissionDeleteView from .utility import ( - DomainApplicationPermissionView, - DomainApplicationPermissionWithdrawView, + DomainRequestPermissionView, + DomainRequestPermissionWithdrawView, ApplicationWizardPermissionView, ) @@ -54,7 +54,7 @@ class ApplicationWizard(ApplicationWizardPermissionView, TemplateView): """ A common set of methods and configuration. - The registrar's domain application is several pages of "steps". + The registrar's domain request is several pages of "steps". Together, these steps constitute a "wizard". This base class sets up a shared state (stored in the user's session) @@ -111,7 +111,7 @@ class ApplicationWizard(ApplicationWizardPermissionView, TemplateView): self._application = None # for caching def has_pk(self): - """Does this wizard know about a DomainApplication database record?""" + """Does this wizard know about a DomainRequest database record?""" return "application_id" in self.storage @property @@ -122,9 +122,9 @@ class ApplicationWizard(ApplicationWizardPermissionView, TemplateView): return "wizard_application" @property - def application(self) -> DomainApplication: + def application(self) -> DomainRequest: """ - Attempt to match the current wizard with a DomainApplication. + Attempt to match the current wizard with a DomainRequest. Will create an application if none exists. """ @@ -142,15 +142,15 @@ class ApplicationWizard(ApplicationWizardPermissionView, TemplateView): if self.has_pk(): id = self.storage["application_id"] try: - self._application = DomainApplication.objects.get( + self._application = DomainRequest.objects.get( creator=creator, pk=id, ) return self._application - except DomainApplication.DoesNotExist: - logger.debug("Application id %s did not have a DomainApplication" % id) + except DomainRequest.DoesNotExist: + logger.debug("Application id %s did not have a DomainRequest" % id) - self._application = DomainApplication.objects.create(creator=self.request.user) + self._application = DomainRequest.objects.create(creator=self.request.user) self.storage["application_id"] = self._application.id return self._application @@ -236,7 +236,7 @@ class ApplicationWizard(ApplicationWizardPermissionView, TemplateView): context["forms"] = self.get_forms() # if pending requests exist and user does not have approved domains, - # present message that domain application cannot be submitted + # present message that domain request cannot be submitted pending_requests = self.pending_requests() if len(pending_requests) > 0: message_header = "You cannot submit this request yet" @@ -310,8 +310,8 @@ class ApplicationWizard(ApplicationWizardPermissionView, TemplateView): def approved_applications_exist(self): """Checks if user is creator of applications with ApplicationStatus.APPROVED status""" - approved_application_count = DomainApplication.objects.filter( - creator=self.request.user, status=DomainApplication.ApplicationStatus.APPROVED + approved_application_count = DomainRequest.objects.filter( + creator=self.request.user, status=DomainRequest.ApplicationStatus.APPROVED ).count() return approved_application_count > 0 @@ -326,14 +326,14 @@ class ApplicationWizard(ApplicationWizardPermissionView, TemplateView): """Returns a List of user's applications with one of the following states: ApplicationStatus.SUBMITTED, ApplicationStatus.IN_REVIEW, ApplicationStatus.ACTION_NEEDED""" # if the current application has ApplicationStatus.ACTION_NEEDED status, this check should not be performed - if self.application.status == DomainApplication.ApplicationStatus.ACTION_NEEDED: + if self.application.status == DomainRequest.ApplicationStatus.ACTION_NEEDED: return [] check_statuses = [ - DomainApplication.ApplicationStatus.SUBMITTED, - DomainApplication.ApplicationStatus.IN_REVIEW, - DomainApplication.ApplicationStatus.ACTION_NEEDED, + DomainRequest.ApplicationStatus.SUBMITTED, + DomainRequest.ApplicationStatus.IN_REVIEW, + DomainRequest.ApplicationStatus.ACTION_NEEDED, ] - return DomainApplication.objects.filter(creator=self.request.user, status__in=check_statuses) + return DomainRequest.objects.filter(creator=self.request.user, status__in=check_statuses) def db_check_for_unlocking_steps(self): """Helper for get_context_data @@ -635,21 +635,21 @@ class Finished(ApplicationWizard): return render(self.request, self.template_name, context) -class ApplicationStatus(DomainApplicationPermissionView): +class ApplicationStatus(DomainRequestPermissionView): template_name = "application_status.html" -class ApplicationWithdrawConfirmation(DomainApplicationPermissionWithdrawView): +class ApplicationWithdrawConfirmation(DomainRequestPermissionWithdrawView): """This page will ask user to confirm if they want to withdraw - The DomainApplicationPermissionView restricts access so that only the + The DomainRequestPermissionView restricts access so that only the `creator` of the application may withdraw it. """ template_name = "application_withdraw_confirmation.html" -class ApplicationWithdrawn(DomainApplicationPermissionWithdrawView): +class ApplicationWithdrawn(DomainRequestPermissionWithdrawView): # this view renders no template template_name = "" @@ -659,16 +659,16 @@ class ApplicationWithdrawn(DomainApplicationPermissionWithdrawView): If user click on withdraw confirm button, this view updates the status to withdraw and send back to homepage. """ - application = DomainApplication.objects.get(id=self.kwargs["pk"]) + application = DomainRequest.objects.get(id=self.kwargs["pk"]) application.withdraw() application.save() return HttpResponseRedirect(reverse("home")) -class DomainApplicationDeleteView(DomainApplicationPermissionDeleteView): - """Delete view for home that allows the end user to delete DomainApplications""" +class DomainRequestDeleteView(DomainRequestPermissionDeleteView): + """Delete view for home that allows the end user to delete DomainRequests""" - object: DomainApplication # workaround for type mismatch in DeleteView + object: DomainRequest # workaround for type mismatch in DeleteView def has_permission(self): """Custom override for has_permission to exclude all statuses, except WITHDRAWN and STARTED""" @@ -677,7 +677,7 @@ class DomainApplicationDeleteView(DomainApplicationPermissionDeleteView): return False status = self.get_object().status - valid_statuses = [DomainApplication.ApplicationStatus.WITHDRAWN, DomainApplication.ApplicationStatus.STARTED] + valid_statuses = [DomainRequest.ApplicationStatus.WITHDRAWN, DomainRequest.ApplicationStatus.STARTED] if status not in valid_statuses: return False @@ -689,10 +689,10 @@ class DomainApplicationDeleteView(DomainApplicationPermissionDeleteView): def post(self, request, *args, **kwargs): # Grab all orphaned contacts - application: DomainApplication = self.get_object() + application: DomainRequest = self.get_object() contacts_to_delete, duplicates = self._get_orphaned_contacts(application) - # Delete the DomainApplication + # Delete the DomainRequest response = super().post(request, *args, **kwargs) # Delete orphaned contacts - but only for if they are not associated with a user @@ -707,16 +707,16 @@ class DomainApplicationDeleteView(DomainApplicationPermissionDeleteView): return response - def _get_orphaned_contacts(self, application: DomainApplication, check_db=False): + def _get_orphaned_contacts(self, application: DomainRequest, check_db=False): """ - Collects all orphaned contacts associated with a given DomainApplication object. + Collects all orphaned contacts associated with a given DomainRequest object. An orphaned contact is defined as a contact that is associated with the application, but not with any other application. This includes the authorizing official, the submitter, and any other contacts linked to the application. Parameters: - application (DomainApplication): The DomainApplication object for which to find orphaned contacts. + application (DomainRequest): The DomainRequest object for which to find orphaned contacts. check_db (bool, optional): A flag indicating whether to check the database for the existence of the contacts. Defaults to False. @@ -726,7 +726,7 @@ class DomainApplicationDeleteView(DomainApplicationPermissionDeleteView): """ contacts_to_delete = [] - # Get each contact object on the DomainApplication object + # Get each contact object on the DomainRequest object ao = application.authorizing_official submitter = application.submitter other_contacts = list(application.other_contacts.all()) diff --git a/src/registrar/views/index.py b/src/registrar/views/index.py index 367e5c315..c14341109 100644 --- a/src/registrar/views/index.py +++ b/src/registrar/views/index.py @@ -1,6 +1,6 @@ from django.shortcuts import render -from registrar.models import DomainApplication, Domain, UserDomainRole +from registrar.models import DomainRequest, Domain, UserDomainRole def index(request): @@ -10,7 +10,7 @@ def index(request): # Get all domain applications the user has access to applications, deletable_applications = _get_applications(request) - context["domain_applications"] = applications + context["domain_requests"] = applications # Get all domains the user has access to domains = _get_domains(request) @@ -35,19 +35,19 @@ def index(request): def _get_applications(request): """Given the current request, - get all DomainApplications that are associated with the UserDomainRole object. + get all DomainRequests that are associated with the UserDomainRole object. Returns a tuple of all applications, and those that are deletable by the user. """ # Let's exclude the approved applications since our - # domain_applications context will be used to populate + # domain_requests context will be used to populate # the active applications table - applications = DomainApplication.objects.filter(creator=request.user).exclude( - status=DomainApplication.ApplicationStatus.APPROVED + applications = DomainRequest.objects.filter(creator=request.user).exclude( + status=DomainRequest.ApplicationStatus.APPROVED ) # Create a placeholder DraftDomain for each incomplete draft - valid_statuses = [DomainApplication.ApplicationStatus.STARTED, DomainApplication.ApplicationStatus.WITHDRAWN] + valid_statuses = [DomainRequest.ApplicationStatus.STARTED, DomainRequest.ApplicationStatus.WITHDRAWN] deletable_applications = applications.filter(status__in=valid_statuses) return (applications, deletable_applications) diff --git a/src/registrar/views/utility/__init__.py b/src/registrar/views/utility/__init__.py index 3d1a64628..b5d910a98 100644 --- a/src/registrar/views/utility/__init__.py +++ b/src/registrar/views/utility/__init__.py @@ -3,8 +3,8 @@ from .always_404 import always_404 from .permission_views import ( DomainPermissionView, - DomainApplicationPermissionView, - DomainApplicationPermissionWithdrawView, + DomainRequestPermissionView, + DomainRequestPermissionWithdrawView, DomainInvitationPermissionDeleteView, ApplicationWizardPermissionView, ) diff --git a/src/registrar/views/utility/mixins.py b/src/registrar/views/utility/mixins.py index 8de75e151..51dadc439 100644 --- a/src/registrar/views/utility/mixins.py +++ b/src/registrar/views/utility/mixins.py @@ -4,7 +4,7 @@ from django.contrib.auth.mixins import PermissionRequiredMixin from registrar.models import ( Domain, - DomainApplication, + DomainRequest, DomainInvitation, DomainInformation, UserDomainRole, @@ -230,10 +230,10 @@ class DomainPermission(PermissionsLoginMixin): # Analysts may manage domains, when they are in these statuses: valid_domain_statuses = [ - DomainApplication.ApplicationStatus.APPROVED, - DomainApplication.ApplicationStatus.IN_REVIEW, - DomainApplication.ApplicationStatus.REJECTED, - DomainApplication.ApplicationStatus.ACTION_NEEDED, + DomainRequest.ApplicationStatus.APPROVED, + DomainRequest.ApplicationStatus.IN_REVIEW, + DomainRequest.ApplicationStatus.REJECTED, + DomainRequest.ApplicationStatus.ACTION_NEEDED, # Edge case - some domains do not have # a status or DomainInformation... aka a status of 'None'. # It is necessary to access those to correct errors. @@ -246,12 +246,12 @@ class DomainPermission(PermissionsLoginMixin): # if no domain information or application exist, the user # should be able to manage the domain; however, if domain information - # and domain application exist, and application is not in valid status, + # and domain request exist, and application is not in valid status, # user should not be able to manage domain if ( requested_domain - and requested_domain.domain_application - and requested_domain.domain_application.status not in valid_domain_statuses + and requested_domain.domain_request + and requested_domain.domain_request.status not in valid_domain_statuses ): return False @@ -261,12 +261,12 @@ class DomainPermission(PermissionsLoginMixin): return True -class DomainApplicationPermission(PermissionsLoginMixin): - """Permission mixin that redirects to domain application if user +class DomainRequestPermission(PermissionsLoginMixin): + """Permission mixin that redirects to domain request if user has access, otherwise 403""" def has_permission(self): - """Check if this user has access to this domain application. + """Check if this user has access to this domain request. The user is in self.request.user and the domain needs to be looked up from the domain's primary key in self.kwargs["pk"] @@ -275,9 +275,9 @@ class DomainApplicationPermission(PermissionsLoginMixin): return False # user needs to be the creator of the application - # this query is empty if there isn't a domain application with this + # this query is empty if there isn't a domain request with this # id and this user as creator - if not DomainApplication.objects.filter(creator=self.request.user, id=self.kwargs["pk"]).exists(): + if not DomainRequest.objects.filter(creator=self.request.user, id=self.kwargs["pk"]).exists(): return False return True @@ -288,7 +288,7 @@ class UserDeleteDomainRolePermission(PermissionsLoginMixin): has access, otherwise 403""" def has_permission(self): - """Check if this user has access to this domain application. + """Check if this user has access to this domain request. The user is in self.request.user and the domain needs to be looked up from the domain's primary key in self.kwargs["pk"] @@ -319,19 +319,19 @@ class UserDeleteDomainRolePermission(PermissionsLoginMixin): return True -class DomainApplicationPermissionWithdraw(PermissionsLoginMixin): - """Permission mixin that redirects to withdraw action on domain application +class DomainRequestPermissionWithdraw(PermissionsLoginMixin): + """Permission mixin that redirects to withdraw action on domain request if user has access, otherwise 403""" def has_permission(self): - """Check if this user has access to withdraw this domain application.""" + """Check if this user has access to withdraw this domain request.""" if not self.request.user.is_authenticated: return False # user needs to be the creator of the application - # this query is empty if there isn't a domain application with this + # this query is empty if there isn't a domain request with this # id and this user as creator - if not DomainApplication.objects.filter(creator=self.request.user, id=self.kwargs["pk"]).exists(): + if not DomainRequest.objects.filter(creator=self.request.user, id=self.kwargs["pk"]).exists(): return False # Restricted users should not be able to withdraw domain requests @@ -342,7 +342,7 @@ class DomainApplicationPermissionWithdraw(PermissionsLoginMixin): class ApplicationWizardPermission(PermissionsLoginMixin): - """Permission mixin that redirects to start or edit domain application if + """Permission mixin that redirects to start or edit domain request if user has access, otherwise 403""" def has_permission(self): diff --git a/src/registrar/views/utility/permission_views.py b/src/registrar/views/utility/permission_views.py index 02d3db96d..4cfab714c 100644 --- a/src/registrar/views/utility/permission_views.py +++ b/src/registrar/views/utility/permission_views.py @@ -3,13 +3,13 @@ import abc # abstract base class from django.views.generic import DetailView, DeleteView, TemplateView -from registrar.models import Domain, DomainApplication, DomainInvitation +from registrar.models import Domain, DomainRequest, DomainInvitation from registrar.models.user_domain_role import UserDomainRole from .mixins import ( DomainPermission, - DomainApplicationPermission, - DomainApplicationPermissionWithdraw, + DomainRequestPermission, + DomainRequestPermissionWithdraw, DomainInvitationPermission, ApplicationWizardPermission, UserDeleteDomainRolePermission, @@ -56,7 +56,7 @@ class DomainPermissionView(DomainPermission, DetailView, abc.ABC): raise NotImplementedError -class DomainApplicationPermissionView(DomainApplicationPermission, DetailView, abc.ABC): +class DomainRequestPermissionView(DomainRequestPermission, DetailView, abc.ABC): """Abstract base view for domain applications that enforces permissions This abstract view cannot be instantiated. Actual views must specify @@ -64,9 +64,9 @@ class DomainApplicationPermissionView(DomainApplicationPermission, DetailView, a """ # DetailView property for what model this is viewing - model = DomainApplication + model = DomainRequest # variable name in template context for the model object - context_object_name = "domainapplication" + context_object_name = "DomainRequest" # Abstract property enforces NotImplementedError on an attribute. @property @@ -75,17 +75,17 @@ class DomainApplicationPermissionView(DomainApplicationPermission, DetailView, a raise NotImplementedError -class DomainApplicationPermissionWithdrawView(DomainApplicationPermissionWithdraw, DetailView, abc.ABC): - """Abstract base view for domain application withdraw function +class DomainRequestPermissionWithdrawView(DomainRequestPermissionWithdraw, DetailView, abc.ABC): + """Abstract base view for domain request withdraw function This abstract view cannot be instantiated. Actual views must specify `template_name`. """ # DetailView property for what model this is viewing - model = DomainApplication + model = DomainRequest # variable name in template context for the model object - context_object_name = "domainapplication" + context_object_name = "DomainRequest" # Abstract property enforces NotImplementedError on an attribute. @property @@ -121,11 +121,11 @@ class DomainInvitationPermissionDeleteView(DomainInvitationPermission, DeleteVie object: DomainInvitation # workaround for type mismatch in DeleteView -class DomainApplicationPermissionDeleteView(DomainApplicationPermission, DeleteView, abc.ABC): - """Abstract view for deleting a DomainApplication.""" +class DomainRequestPermissionDeleteView(DomainRequestPermission, DeleteView, abc.ABC): + """Abstract view for deleting a DomainRequest.""" - model = DomainApplication - object: DomainApplication + model = DomainRequest + object: DomainRequest class UserDomainRolePermissionDeleteView(UserDeleteDomainRolePermission, DeleteView, abc.ABC): From 0eafad3fb6055c56d46e1ea3141c217287c22174 Mon Sep 17 00:00:00 2001 From: CocoByte Date: Thu, 29 Feb 2024 15:29:00 -0700 Subject: [PATCH 037/103] Renaming files, lots and lots of find-replace (with manual, step-through inspections where needed). Still IN PROGRESS and I'm sure there are breakages that need repair at this stage... --- .github/ISSUE_TEMPLATE/bug.yml | 4 +- .../decisions/0015-use-django-fsm.md | 4 +- .../decisions/0016-django-form-wizard.md | 6 +- docs/architecture/decisions/0017-ses-email.md | 2 +- .../decisions/0021-django-admin.md | 3 +- .../0022-submit-domain-request-user-flow.md | 4 +- docs/architecture/diagrams/model_timeline.md | 2 +- docs/developer/README.md | 8 +- docs/developer/generating-emails-guide.md | 8 +- docs/operations/README.md | 2 +- src/registrar/admin.py | 38 +- src/registrar/config/urls.py | 20 +- ...cations.py => fixtures_domain_requests.py} | 30 +- src/registrar/forms/__init__.py | 2 +- ...ion_wizard.py => domain_request_wizard.py} | 32 +- src/registrar/management/commands/load.py | 2 +- src/registrar/models/domain_information.py | 8 +- ...omain_application.py => domain_request.py} | 118 ++--- ...main_request_about_your_organization.html} | 2 +- ...html => domain_request_anything_else.html} | 2 +- ... domain_request_authorizing_official.html} | 2 +- ...html => domain_request_current_sites.html} | 2 +- ...ion_done.html => domain_request_done.html} | 0 ...html => domain_request_dotgov_domain.html} | 2 +- ...ion_form.html => domain_request_form.html} | 4 +- ...n_intro.html => domain_request_intro.html} | 0 ...t.html => domain_request_org_contact.html} | 2 +- ....html => domain_request_org_election.html} | 2 +- ...l.html => domain_request_org_federal.html} | 2 +- ...type.html => domain_request_org_type.html} | 2 +- ...tml => domain_request_other_contacts.html} | 2 +- ...rpose.html => domain_request_purpose.html} | 2 +- ....html => domain_request_requirements.html} | 2 +- ...review.html => domain_request_review.html} | 118 ++--- ...debar.html => domain_request_sidebar.html} | 2 +- ...status.html => domain_request_status.html} | 0 ... => domain_request_tribal_government.html} | 2 +- ...domain_request_withdraw_confirmation.html} | 0 ....html => domain_request_your_contact.html} | 2 +- .../emails/domain_request_withdrawn.txt | 6 +- .../domain_request_withdrawn_subject.txt | 2 +- .../emails/includes/application_summary.txt | 58 +-- .../emails/status_change_approved.txt | 6 +- .../emails/status_change_approved_subject.txt | 2 +- .../emails/status_change_rejected.txt | 28 +- .../emails/status_change_rejected_subject.txt | 2 +- .../emails/submission_confirmation.txt | 8 +- .../submission_confirmation_subject.txt | 2 +- src/registrar/templates/home.html | 50 +- src/registrar/tests/common.py | 64 +-- src/registrar/tests/test_admin.py | 326 +++++++------- src/registrar/tests/test_emails.py | 46 +- src/registrar/tests/test_forms.py | 2 +- src/registrar/tests/test_models.py | 350 +++++++------- src/registrar/tests/test_models_domain.py | 8 +- .../test_transition_domain_migrations.py | 2 +- src/registrar/tests/test_views.py | 4 +- src/registrar/tests/test_views_application.py | 426 +++++++++--------- src/registrar/tests/test_views_domain.py | 2 +- src/registrar/views/__init__.py | 2 +- .../{application.py => domain_request.py} | 252 +++++------ src/registrar/views/index.py | 20 +- src/registrar/views/utility/__init__.py | 2 +- src/registrar/views/utility/mixins.py | 16 +- .../views/utility/permission_views.py | 8 +- 65 files changed, 1069 insertions(+), 1070 deletions(-) rename src/registrar/{fixtures_applications.py => fixtures_domain_requests.py} (89%) rename src/registrar/forms/{application_wizard.py => domain_request_wizard.py} (97%) rename src/registrar/models/{domain_application.py => domain_request.py} (90%) rename src/registrar/templates/{application_about_your_organization.html => domain_request_about_your_organization.html} (95%) rename src/registrar/templates/{application_anything_else.html => domain_request_anything_else.html} (92%) rename src/registrar/templates/{application_authorizing_official.html => domain_request_authorizing_official.html} (96%) rename src/registrar/templates/{application_current_sites.html => domain_request_current_sites.html} (96%) rename src/registrar/templates/{application_done.html => domain_request_done.html} (100%) rename src/registrar/templates/{application_dotgov_domain.html => domain_request_dotgov_domain.html} (98%) rename src/registrar/templates/{application_form.html => domain_request_form.html} (96%) rename src/registrar/templates/{application_intro.html => domain_request_intro.html} (100%) rename src/registrar/templates/{application_org_contact.html => domain_request_org_contact.html} (96%) rename src/registrar/templates/{application_org_election.html => domain_request_org_election.html} (94%) rename src/registrar/templates/{application_org_federal.html => domain_request_org_federal.html} (91%) rename src/registrar/templates/{application_org_type.html => domain_request_org_type.html} (92%) rename src/registrar/templates/{application_other_contacts.html => domain_request_other_contacts.html} (99%) rename src/registrar/templates/{application_purpose.html => domain_request_purpose.html} (95%) rename src/registrar/templates/{application_requirements.html => domain_request_requirements.html} (98%) rename src/registrar/templates/{application_review.html => domain_request_review.html} (58%) rename src/registrar/templates/{application_sidebar.html => domain_request_sidebar.html} (95%) rename src/registrar/templates/{application_status.html => domain_request_status.html} (100%) rename src/registrar/templates/{application_tribal_government.html => domain_request_tribal_government.html} (96%) rename src/registrar/templates/{application_withdraw_confirmation.html => domain_request_withdraw_confirmation.html} (100%) rename src/registrar/templates/{application_your_contact.html => domain_request_your_contact.html} (95%) rename src/registrar/views/{application.py => domain_request.py} (75%) diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml index d4d3497ac..559be3fca 100644 --- a/.github/ISSUE_TEMPLATE/bug.yml +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -33,8 +33,8 @@ body: How can the issue be reliably reproduced? Feel free to include screenshots or other supporting artifacts Example: - 1. In the test environment, fill out the application for a new domain - 2. Click the button to trigger a save/submit on the final page and complete the application + 1. In the test environment, fill out the domain request for a new domain + 2. Click the button to trigger a save/submit on the final page and complete the domain request 3. See the error value: | 1. diff --git a/docs/architecture/decisions/0015-use-django-fsm.md b/docs/architecture/decisions/0015-use-django-fsm.md index c291f509f..4c4aa7e36 100644 --- a/docs/architecture/decisions/0015-use-django-fsm.md +++ b/docs/architecture/decisions/0015-use-django-fsm.md @@ -15,7 +15,7 @@ rules in the application code that control what changes are permitted to the statuses are called “domain logic”. In a large piece of software, domain logic often spreads around the code base -because while handling a single request like “mark this application as +because while handling a single request like “mark this domain request as approved”, requirements can be enforced at many different points during the process. @@ -28,7 +28,7 @@ states and can change states (or “transition”) according to fixed rules. We will use the django-fsm library to represent the status of our domain registration applications as a finite state machine. The library allows us to list what statuses are possible and describe which state transitions are -possible (e.g. Can an approved application ever be marked as “in-process”?). +possible (e.g. Can an approved domain request ever be marked as “in-process”?). ## Consequences diff --git a/docs/architecture/decisions/0016-django-form-wizard.md b/docs/architecture/decisions/0016-django-form-wizard.md index 1d0bf0852..afbfb7edf 100644 --- a/docs/architecture/decisions/0016-django-form-wizard.md +++ b/docs/architecture/decisions/0016-django-form-wizard.md @@ -8,11 +8,11 @@ Accepted ## Context -The application form by which registrants apply for a .gov domain is presented over many pages. +The domain request form by which registrants apply for a .gov domain is presented over many pages. -Because we use server-side rendering, each page of the application is a unique HTML page with form fields surrounded by a form tag. +Because we use server-side rendering, each page of the domain request is a unique HTML page with form fields surrounded by a form tag. -Needing a way to coordinate state between the pages as a user fills in their application, we initially used the Form wizard from [django-formtools](https://django-formtools.readthedocs.io/en/latest/wizard.html). This eventually proved unworkable due to the lack of native ability to have more than one Django form object displayed on a single HTML page. +Needing a way to coordinate state between the pages as a user fills in their domain request, we initially used the Form wizard from [django-formtools](https://django-formtools.readthedocs.io/en/latest/wizard.html). This eventually proved unworkable due to the lack of native ability to have more than one Django form object displayed on a single HTML page. However, a significant portion of the user workflow had already been coded, so it seemed prudent to port some of the formtools logic into our codebase. diff --git a/docs/architecture/decisions/0017-ses-email.md b/docs/architecture/decisions/0017-ses-email.md index 6559cbb4e..d39a4aa68 100644 --- a/docs/architecture/decisions/0017-ses-email.md +++ b/docs/architecture/decisions/0017-ses-email.md @@ -9,7 +9,7 @@ Approved ## Context Our application needs to be able to send email to applicants for various -purposes including notifying them that their application has been submitted. +purposes including notifying them that their domain request has been submitted. We need infrastructure for programmatically sending email. Amazon Web Services (AWS) provides the Simple Email Service (SES) that can do that. CISA can provide access to AWS SES for our application. diff --git a/docs/architecture/decisions/0021-django-admin.md b/docs/architecture/decisions/0021-django-admin.md index add6992cd..31715a9cf 100644 --- a/docs/architecture/decisions/0021-django-admin.md +++ b/docs/architecture/decisions/0021-django-admin.md @@ -8,8 +8,7 @@ Accepted ## Context -CISA needs a way to perform administrative actions to manage the new get.gov application as well as the .gov domain -application requests submitted. Analysts need to be able to view, review, and approve domain applications. Other +CISA needs a way to perform administrative actions to manage the new get.gov application as well as the .gov domain requests submitted. Analysts need to be able to view, review, and approve domain requests. Other dashboard views, reports, searches (with filters and sorting) are also highly desired. ## Decision diff --git a/docs/architecture/decisions/0022-submit-domain-request-user-flow.md b/docs/architecture/decisions/0022-submit-domain-request-user-flow.md index e0e94fc16..c28579113 100644 --- a/docs/architecture/decisions/0022-submit-domain-request-user-flow.md +++ b/docs/architecture/decisions/0022-submit-domain-request-user-flow.md @@ -12,9 +12,9 @@ Historically, the .gov vendor managed initial identity verification and organiza ## Considered Options -**Option 1:** Users will not be able to submit any new applications if they have 0 prior approved applications OR prior registered .gov domains. We would add a page alert informing the user that they cannot submit their application because they have an application in one of these "3" statuses (Submitted, In Review or Action Needed). They would still be able to create and edit new applications, just not submit them. The benefits of this option are that it would allow users to have multiple applications essentially in "draft mode" that are queued up and ready for submission after they are permitted to submit. +**Option 1:** Users will not be able to submit any new applications if they have 0 prior approved applications OR prior registered .gov domains. We would add a page alert informing the user that they cannot submit their application because they have a domain request in one of these "3" statuses (Submitted, In Review or Action Needed). They would still be able to create and edit new applications, just not submit them. The benefits of this option are that it would allow users to have multiple applications essentially in "draft mode" that are queued up and ready for submission after they are permitted to submit. -**Option 2:** Users will not be able to submit any new applications if they have 0 prior approved applications OR prior registered .gov domains. Additionally, we would remove the ability to edit any application with the started/withdrawn/rejected status, or start a new application. The benefit of this option is that a user would not be able to begin an action (submitting an application) that they are not allowed to complete. +**Option 2:** Users will not be able to submit any new applications if they have 0 prior approved applications OR prior registered .gov domains. Additionally, we would remove the ability to edit any application with the started/withdrawn/rejected status, or start a new application. The benefit of this option is that a user would not be able to begin an action (submitting a domain request) that they are not allowed to complete. ## Decision diff --git a/docs/architecture/diagrams/model_timeline.md b/docs/architecture/diagrams/model_timeline.md index 47e449162..42aad16e1 100644 --- a/docs/architecture/diagrams/model_timeline.md +++ b/docs/architecture/diagrams/model_timeline.md @@ -5,7 +5,7 @@ This diagram connects the data models along with various workflow stages. 1. The applicant starts the process at `/request` interacting with the `DomainRequest` object. -2. The analyst approves the application using the `DomainRequest`'s +2. The analyst approves the domain request using the `DomainRequest`'s `approve()` method which creates many related objects: `UserDomainRole`, `Domain`, and `DomainInformation`. diff --git a/docs/developer/README.md b/docs/developer/README.md index dc4c9ddd2..e28c57378 100644 --- a/docs/developer/README.md +++ b/docs/developer/README.md @@ -78,7 +78,7 @@ Get the secrets from Cloud.gov by running `cf env getgov-YOURSANDBOX`. More info The endpoint /admin can be used to view and manage site content, including but not limited to user information and the list of current applications in the database. To be able to view and use /admin locally: 1. Login via login.gov -2. Go to the home page and make sure you can see the part where you can submit an application +2. Go to the home page and make sure you can see the part where you can submit a domain request 3. Go to /admin and it will tell you that UUID is not authorized, copy that UUID for use in 4 4. in src/registrar/fixtures_users.py add to the `ADMINS` list in that file by adding your UUID as your username along with your first and last name. See below: @@ -93,14 +93,14 @@ The endpoint /admin can be used to view and manage site content, including but n ] ``` -5. In the browser, navigate to /admin. To verify that all is working correctly, under "domain applications" you should see fake domains with various fake statuses. +5. In the browser, navigate to /admin. To verify that all is working correctly, under "domain requests" you should see fake domains with various fake statuses. 6. Add an optional email key/value pair ### Adding an Analyst to /admin Analysts are a variant of the admin role with limited permissions. The process for adding an Analyst is much the same as adding an admin: 1. Login via login.gov (if you already exist as an admin, you will need to create a separate login.gov account for this: i.e. first.last+1@email.com) -2. Go to the home page and make sure you can see the part where you can submit an application +2. Go to the home page and make sure you can see the part where you can submit a domain request 3. Go to /admin and it will tell you that UUID is not authorized, copy that UUID for use in 4 (this will be a different UUID than the one obtained from creating an admin) 4. in src/registrar/fixtures_users.py add to the `STAFF` list in that file by adding your UUID as your username along with your first and last name. See below: @@ -145,7 +145,7 @@ You can change the logging verbosity, if needed. Do a web search for "django log ## Mock data -[load.py](../../src/registrar/management/commands/load.py) called from docker-compose (locally) and reset-db.yml (upper) loads the fixtures from [fixtures_user.py](../../src/registrar/fixtures_users.py) and [fixtures_applications.py](../../src/registrar/fixtures_applications.py), giving you some test data to play with while developing. +[load.py](../../src/registrar/management/commands/load.py) called from docker-compose (locally) and reset-db.yml (upper) loads the fixtures from [fixtures_user.py](../../src/registrar/fixtures_users.py) and [fixtures_domain_requests.py](../../src/registrar/fixtures_domain_requests.py), giving you some test data to play with while developing. See the [database-access README](./database-access.md) for information on how to pull data to update these fixtures. diff --git a/docs/developer/generating-emails-guide.md b/docs/developer/generating-emails-guide.md index 0a97a8bc6..dd0a55e64 100644 --- a/docs/developer/generating-emails-guide.md +++ b/docs/developer/generating-emails-guide.md @@ -24,8 +24,8 @@ ## Status Change Approved - Starting Location: Django Admin - Workflow: Analyst Admin -- Workflow Step: Click "Domain applications" -> Click an application in a status of "submitted", "In review", "rejected", or "ineligible" -> Click status dropdown -> (select "approved") -> click "Save" -- Notes: Note that this will send an email to the submitter (email listed on Your Contact Information). To test this with your own email, you need to create an application, then set the status to "approved". This will send you an email. +- Workflow Step: Click "domain requests" -> Click a domain request in a status of "submitted", "In review", "rejected", or "ineligible" -> Click status dropdown -> (select "approved") -> click "Save" +- Notes: Note that this will send an email to the submitter (email listed on Your Contact Information). To test this with your own email, you need to create a domain request, then set the status to "approved". This will send you an email. - [Email Content](https://github.com/cisagov/manage.get.gov/blob/main/src/registrar/templates/emails/status_change_approved.txt) ### Status Change Approved Subject @@ -35,8 +35,8 @@ ## Status Change Rejected - Starting Location: Django Admin - Workflow: Analyst Admin -- Workflow Step: Click "Domain applications" -> Click an application in a status of "In review", or "approved" -> Click status dropdown -> (select "rejected") -> click "Save" -- Notes: Note that this will send an email to the submitter (email listed on Your Contact Information). To test this with your own email, you need to create an application, then set the status to "in review" (and click save). Then, go back to the same application and set the status to "rejected". This will send you an email. +- Workflow Step: Click "domain requests" -> Click a domain request in a status of "In review", or "approved" -> Click status dropdown -> (select "rejected") -> click "Save" +- Notes: Note that this will send an email to the submitter (email listed on Your Contact Information). To test this with your own email, you need to create a domain request, then set the status to "in review" (and click save). Then, go back to the same application and set the status to "rejected". This will send you an email. - [Email Content](https://github.com/cisagov/manage.get.gov/blob/main/src/registrar/templates/emails/status_change_rejected.txt) ### Status Change Rejected Subject diff --git a/docs/operations/README.md b/docs/operations/README.md index 0bd55ab51..9aaee4c86 100644 --- a/docs/operations/README.md +++ b/docs/operations/README.md @@ -114,7 +114,7 @@ that can be used for specific tasks. ## Cloud.gov dashboard At there is a list for all of the -applications that a Cloud.gov user has access to. Clicking on an application +applications that a Cloud.gov user has access to. Clicking on a domain request goes to a screen for that individual application, e.g. . On that page is a left-hand link for "Log Stream" e.g. diff --git a/src/registrar/admin.py b/src/registrar/admin.py index a985a971e..3d2d194b3 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -85,15 +85,15 @@ class DomainRequestAdminForm(forms.ModelForm): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - application = kwargs.get("instance") - if application and application.pk: - current_state = application.status + domain_request = kwargs.get("instance") + if domain_request and domain_request.pk: + current_state = domain_request.status # first option in status transitions is current state - available_transitions = [(current_state, application.get_status_display())] + available_transitions = [(current_state, domain_request.get_status_display())] transitions = get_available_FIELD_transitions( - application, models.DomainRequest._meta.get_field("status") + domain_request, models.DomainRequest._meta.get_field("status") ) for transition in transitions: @@ -102,7 +102,7 @@ class DomainRequestAdminForm(forms.ModelForm): # only set the available transitions if the user is not restricted # from editing the domain request; otherwise, the form will be # readonly and the status field will not have a widget - if not application.creator.is_restricted(): + if not domain_request.creator.is_restricted(): self.fields["status"].widget.choices = available_transitions @@ -867,7 +867,7 @@ class DomainInformationAdmin(ListHeaderAdmin): class DomainRequestAdmin(ListHeaderAdmin): - """Custom domain applications admin class.""" + """Custom domain requests admin class.""" form = DomainRequestAdminForm @@ -1061,8 +1061,8 @@ class DomainRequestAdmin(ListHeaderAdmin): if ( obj - and original_obj.status == models.DomainRequest.ApplicationStatus.APPROVED - and obj.status != models.DomainRequest.ApplicationStatus.APPROVED + and original_obj.status == models.DomainRequest.DomainRequestStatus.APPROVED + and obj.status != models.DomainRequest.DomainRequestStatus.APPROVED and not obj.domain_is_not_active() ): # If an admin tried to set an approved application to @@ -1082,7 +1082,7 @@ class DomainRequestAdmin(ListHeaderAdmin): elif ( obj - and obj.status == models.DomainRequest.ApplicationStatus.REJECTED + and obj.status == models.DomainRequest.DomainRequestStatus.REJECTED and not obj.rejection_reason ): # This condition should never be triggered. @@ -1100,14 +1100,14 @@ class DomainRequestAdmin(ListHeaderAdmin): else: if obj.status != original_obj.status: status_method_mapping = { - models.DomainRequest.ApplicationStatus.STARTED: None, - models.DomainRequest.ApplicationStatus.SUBMITTED: obj.submit, - models.DomainRequest.ApplicationStatus.IN_REVIEW: obj.in_review, - models.DomainRequest.ApplicationStatus.ACTION_NEEDED: obj.action_needed, - models.DomainRequest.ApplicationStatus.APPROVED: obj.approve, - models.DomainRequest.ApplicationStatus.WITHDRAWN: obj.withdraw, - models.DomainRequest.ApplicationStatus.REJECTED: obj.reject, - models.DomainRequest.ApplicationStatus.INELIGIBLE: (obj.reject_with_prejudice), + models.DomainRequest.DomainRequestStatus.STARTED: None, + models.DomainRequest.DomainRequestStatus.SUBMITTED: obj.submit, + models.DomainRequest.DomainRequestStatus.IN_REVIEW: obj.in_review, + models.DomainRequest.DomainRequestStatus.ACTION_NEEDED: obj.action_needed, + models.DomainRequest.DomainRequestStatus.APPROVED: obj.approve, + models.DomainRequest.DomainRequestStatus.WITHDRAWN: obj.withdraw, + models.DomainRequest.DomainRequestStatus.REJECTED: obj.reject, + models.DomainRequest.DomainRequestStatus.INELIGIBLE: (obj.reject_with_prejudice), } selected_method = status_method_mapping.get(obj.status) if selected_method is None: @@ -1158,7 +1158,7 @@ class DomainRequestAdmin(ListHeaderAdmin): if obj and obj.creator.status == models.User.RESTRICTED: messages.warning( request, - "Cannot edit an application with a restricted creator.", + "Cannot edit a domain request with a restricted creator.", ) def change_view(self, request, object_id, form_url="", extra_context=None): diff --git a/src/registrar/config/urls.py b/src/registrar/config/urls.py index 153c3448f..f23dcf53f 100644 --- a/src/registrar/config/urls.py +++ b/src/registrar/config/urls.py @@ -13,18 +13,18 @@ from registrar import views from registrar.views.admin_views import ExportData -from registrar.views.application import Step +from registrar.views.domain_request import Step from registrar.views.utility import always_404 from api.views import available, get_current_federal, get_current_full -APPLICATION_NAMESPACE = views.ApplicationWizard.URL_NAMESPACE -application_urls = [ - path("", views.ApplicationWizard.as_view(), name=""), +DOMAIN_REQUEST_NAMESPACE = views.DomainRequestWizard.URL_NAMESPACE +domain_request_urls = [ + path("", views.DomainRequestWizard.as_view(), name=""), path("finished/", views.Finished.as_view(), name="finished"), ] -# dynamically generate the other application_urls +# dynamically generate the other domain_request_urls for step, view in [ # add/remove steps here (Step.ORGANIZATION_TYPE, views.OrganizationType), @@ -43,7 +43,7 @@ for step, view in [ (Step.REQUIREMENTS, views.Requirements), (Step.REVIEW, views.Review), ]: - application_urls.append(path(f"{step}/", view.as_view(), name=step)) + domain_request_urls.append(path(f"{step}/", view.as_view(), name=step)) urlpatterns = [ @@ -56,12 +56,12 @@ urlpatterns = [ path("admin/", admin.site.urls), path( "application//edit/", - views.ApplicationWizard.as_view(), - name=views.ApplicationWizard.EDIT_URL_NAME, + views.DomainRequestWizard.as_view(), + name=views.DomainRequestWizard.EDIT_URL_NAME, ), path( "application/", - views.ApplicationStatus.as_view(), + views.DomainRequestStatus.as_view(), name="application-status", ), path( @@ -76,7 +76,7 @@ urlpatterns = [ ), path("health", views.health, name="health"), path("openid/", include("djangooidc.urls")), - path("request/", include((application_urls, APPLICATION_NAMESPACE))), + path("request/", include((domain_request_urls, DOMAIN_REQUEST_NAMESPACE))), path("api/v1/available/", available, name="available"), path("api/v1/get-report/current-federal", get_current_federal, name="get-current-federal"), path("api/v1/get-report/current-full", get_current_full, name="get-current-full"), diff --git a/src/registrar/fixtures_applications.py b/src/registrar/fixtures_domain_requests.py similarity index 89% rename from src/registrar/fixtures_applications.py rename to src/registrar/fixtures_domain_requests.py index cfba61fa9..a78bdd1ab 100644 --- a/src/registrar/fixtures_applications.py +++ b/src/registrar/fixtures_domain_requests.py @@ -16,7 +16,7 @@ logger = logging.getLogger(__name__) class DomainRequestFixture: """ - Load domain applications into the database. + Load domain requests into the database. Make sure this class' `load` method is called from `handle` in management/commands/load.py, then use `./manage.py load` @@ -49,27 +49,27 @@ class DomainRequestFixture: # }, DA = [ { - "status": DomainRequest.ApplicationStatus.STARTED, + "status": DomainRequest.DomainRequestStatus.STARTED, "organization_name": "Example - Finished but not submitted", }, { - "status": DomainRequest.ApplicationStatus.SUBMITTED, + "status": DomainRequest.DomainRequestStatus.SUBMITTED, "organization_name": "Example - Submitted but pending investigation", }, { - "status": DomainRequest.ApplicationStatus.IN_REVIEW, + "status": DomainRequest.DomainRequestStatus.IN_REVIEW, "organization_name": "Example - In investigation", }, { - "status": DomainRequest.ApplicationStatus.IN_REVIEW, + "status": DomainRequest.DomainRequestStatus.IN_REVIEW, "organization_name": "Example - Approved", }, { - "status": DomainRequest.ApplicationStatus.WITHDRAWN, + "status": DomainRequest.DomainRequestStatus.WITHDRAWN, "organization_name": "Example - Withdrawn", }, { - "status": DomainRequest.ApplicationStatus.ACTION_NEEDED, + "status": DomainRequest.DomainRequestStatus.ACTION_NEEDED, "organization_name": "Example - Action needed", }, { @@ -176,8 +176,8 @@ class DomainRequestFixture: @classmethod def load(cls): - """Creates domain applications for each user in the database.""" - logger.info("Going to load %s domain applications" % len(cls.DA)) + """Creates domain requests for each user in the database.""" + logger.info("Going to load %s domain requests" % len(cls.DA)) try: users = list(User.objects.all()) # force evaluation to catch db errors except Exception as e: @@ -185,7 +185,7 @@ class DomainRequestFixture: return for user in users: - logger.debug("Loading domain applications for %s" % user) + logger.debug("Loading domain requests for %s" % user) for app in cls.DA: try: da, _ = DomainRequest.objects.get_or_create( @@ -213,12 +213,12 @@ class DomainFixture(DomainRequestFixture): for user in users: # approve one of each users in review status domains - application = DomainRequest.objects.filter( - creator=user, status=DomainRequest.ApplicationStatus.IN_REVIEW + domain_request = DomainRequest.objects.filter( + creator=user, status=DomainRequest.DomainRequestStatus.IN_REVIEW ).last() - logger.debug(f"Approving {application} for {user}") + logger.debug(f"Approving {domain_request} for {user}") # We don't want fixtures sending out real emails to # fake email addresses, so we just skip that and log it instead - application.approve(send_email=False) - application.save() + domain_request.approve(send_email=False) + domain_request.save() diff --git a/src/registrar/forms/__init__.py b/src/registrar/forms/__init__.py index 914db375c..be3b634f6 100644 --- a/src/registrar/forms/__init__.py +++ b/src/registrar/forms/__init__.py @@ -1,4 +1,4 @@ -from .application_wizard import * +from .domain_request_wizard import * from .domain import ( DomainAddUserForm, NameserverFormset, diff --git a/src/registrar/forms/application_wizard.py b/src/registrar/forms/domain_request_wizard.py similarity index 97% rename from src/registrar/forms/application_wizard.py rename to src/registrar/forms/domain_request_wizard.py index ed81bf8a9..c9e90d935 100644 --- a/src/registrar/forms/application_wizard.py +++ b/src/registrar/forms/domain_request_wizard.py @@ -29,8 +29,8 @@ class RegistrarForm(forms.Form): def __init__(self, *args, **kwargs): kwargs.setdefault("label_suffix", "") - # save a reference to an application object - self.application = kwargs.pop("application", None) + # save a reference to a domain request object + self.domain_request = kwargs.pop("domain_request", None) super(RegistrarForm, self).__init__(*args, **kwargs) def to_database(self, obj: DomainRequest | Contact): @@ -61,8 +61,8 @@ class RegistrarFormSet(forms.BaseFormSet): """ def __init__(self, *args, **kwargs): - # save a reference to an application object - self.application = kwargs.pop("application", None) + # save a reference to an domain_request object + self.domain_request = kwargs.pop("domain_request", None) super(RegistrarFormSet, self).__init__(*args, **kwargs) # quick workaround to ensure that the HTML `required` # attribute shows up on required fields for any forms @@ -137,14 +137,14 @@ class RegistrarFormSet(forms.BaseFormSet): if should_delete(cleaned): if hasattr(db_obj, "has_more_than_one_join") and db_obj.has_more_than_one_join(related_name): # Remove the specific relationship without deleting the object - getattr(db_obj, related_name).remove(self.application) + getattr(db_obj, related_name).remove(self.domain_request) else: # If there are no other relationships, delete the object db_obj.delete() else: if hasattr(db_obj, "has_more_than_one_join") and db_obj.has_more_than_one_join(related_name): # create a new db_obj and disconnect existing one - getattr(db_obj, related_name).remove(self.application) + getattr(db_obj, related_name).remove(self.domain_request) kwargs = pre_create(db_obj, cleaned) getattr(obj, join).create(**kwargs) else: @@ -170,7 +170,7 @@ class RegistrarFormSet(forms.BaseFormSet): class OrganizationTypeForm(RegistrarForm): organization_type = forms.ChoiceField( - # use the long names in the application form + # use the long names in the domain request form choices=DomainRequest.OrganizationChoicesVerbose.choices, widget=forms.RadioSelect, error_messages={"required": "Select the type of organization you represent."}, @@ -201,7 +201,7 @@ class TribalGovernmentForm(RegistrarForm): # into a link. There should be no user-facing input in the # HTML indicated here. mark_safe( # nosec - "You can’t complete this application yet. " + "You can’t complete this domain request yet. " "Only tribes recognized by the U.S. federal government " "or by a U.S. state government are eligible for .gov " 'domains. Use our contact form to ' @@ -294,8 +294,8 @@ class OrganizationContactForm(RegistrarForm): def clean_federal_agency(self): """Require something to be selected when this is a federal agency.""" federal_agency = self.cleaned_data.get("federal_agency", None) - # need the application object to know if this is federal - if self.application is None: + # need the domain request object to know if this is federal + if self.domain_request is None: # hmm, no saved application object?, default require the agency if not federal_agency: # no answer was selected @@ -303,7 +303,7 @@ class OrganizationContactForm(RegistrarForm): "Select the federal agency your organization is in.", code="required", ) - if self.application.is_federal(): + if self.domain_request.is_federal(): if not federal_agency: # no answer was selected raise forms.ValidationError( @@ -530,7 +530,7 @@ class YourContactForm(RegistrarForm): if not self.is_valid(): return contact = getattr(obj, "submitter", None) - if contact is not None and not contact.has_more_than_one_join("submitted_applications"): + if contact is not None and not contact.has_more_than_one_join("submitted_domain_requests"): # if contact exists in the database and is not joined to other entities super().to_database(contact) else: @@ -579,9 +579,9 @@ class OtherContactsYesNoForm(RegistrarForm): """Extend the initialization of the form from RegistrarForm __init__""" super().__init__(*args, **kwargs) # set the initial value based on attributes of application - if self.application and self.application.has_other_contacts(): + if self.domain_request and self.domain_request.has_other_contacts(): initial_value = True - elif self.application and self.application.has_rationale(): + elif self.domain_request and self.domain_request.has_rationale(): initial_value = False else: # No pre-selection for new applications @@ -687,7 +687,7 @@ class BaseOtherContactsFormSet(RegistrarFormSet): this case, all forms in formset are marked for deletion. Both of these conditions must co-exist. Also, other_contacts have db relationships to multiple db objects. When attempting - to delete an other_contact from an application, those db relationships must be + to delete an other_contact from a domain request, those db relationships must be tested and handled. """ @@ -701,7 +701,7 @@ class BaseOtherContactsFormSet(RegistrarFormSet): Override __init__ for RegistrarFormSet. """ self.formset_data_marked_for_deletion = False - self.application = kwargs.pop("application", None) + self.domain_request = kwargs.pop("domain_request", None) super(RegistrarFormSet, self).__init__(*args, **kwargs) # quick workaround to ensure that the HTML `required` # attribute shows up on required fields for the first form diff --git a/src/registrar/management/commands/load.py b/src/registrar/management/commands/load.py index 369e9d5ba..aac5eade1 100644 --- a/src/registrar/management/commands/load.py +++ b/src/registrar/management/commands/load.py @@ -5,7 +5,7 @@ from auditlog.context import disable_auditlog # type: ignore from registrar.fixtures_users import UserFixture -from registrar.fixtures_applications import DomainRequestFixture, DomainFixture +from registrar.fixtures_domain_requests import DomainRequestFixture, DomainFixture logger = logging.getLogger(__name__) diff --git a/src/registrar/models/domain_information.py b/src/registrar/models/domain_information.py index 3d8f76a5d..f757c7d61 100644 --- a/src/registrar/models/domain_information.py +++ b/src/registrar/models/domain_information.py @@ -18,7 +18,7 @@ class DomainInformation(TimeStampedModel): DomainRequest. We use these field from DomainRequest with few exceptions which are 'removed' via pop at the bottom of this file. Most of design for domain management's user information are based on application, but we cannot change - the application once approved, so copying them that way we can make changes + the domain request once approved, so copying them that way we can make changes after its approved. Most fields here are copied from Application.""" StateTerritoryChoices = DomainRequest.StateTerritoryChoices @@ -30,7 +30,7 @@ class DomainInformation(TimeStampedModel): AGENCY_CHOICES = DomainRequest.AGENCY_CHOICES - # This is the application user who created this application. The contact + # This is the domain request user who created this domain request. The contact # information that they gave is in the `submitter` field creator = models.ForeignKey( "registrar.User", @@ -169,7 +169,7 @@ class DomainInformation(TimeStampedModel): "registrar.Contact", null=True, blank=True, - related_name="submitted_applications_information", + related_name="submitted_domain_requests_information", on_delete=models.PROTECT, ) @@ -182,7 +182,7 @@ class DomainInformation(TimeStampedModel): other_contacts = models.ManyToManyField( "registrar.Contact", blank=True, - related_name="contact_applications_information", + related_name="contact_domain_requests_information", verbose_name="contacts", ) diff --git a/src/registrar/models/domain_application.py b/src/registrar/models/domain_request.py similarity index 90% rename from src/registrar/models/domain_application.py rename to src/registrar/models/domain_request.py index 5a1865b3a..4e141107f 100644 --- a/src/registrar/models/domain_application.py +++ b/src/registrar/models/domain_request.py @@ -21,7 +21,7 @@ class DomainRequest(TimeStampedModel): """A registrant's application for a new domain.""" # Constants for choice fields - class ApplicationStatus(models.TextChoices): + class DomainRequestStatus(models.TextChoices): STARTED = "started", "Started" SUBMITTED = "submitted", "Submitted" IN_REVIEW = "in review", "In review" @@ -115,7 +115,7 @@ class DomainRequest(TimeStampedModel): class OrganizationChoicesVerbose(models.TextChoices): """ Secondary organization choices - For use in the application form and on the templates + For use in the domain request form and on the templates Keys need to match OrganizationChoices """ @@ -366,10 +366,10 @@ class DomainRequest(TimeStampedModel): NAMING_REQUIREMENTS = "naming_not_met", "Naming requirements not met" OTHER = "other", "Other/Unspecified" - # #### Internal fields about the application ##### + # #### Internal fields about the domain request ##### status = FSMField( - choices=ApplicationStatus.choices, # possible states as an array of constants - default=ApplicationStatus.STARTED, # sensible default + choices=DomainRequestStatus.choices, # possible states as an array of constants + default=DomainRequestStatus.STARTED, # sensible default protected=False, # can change state directly, particularly in Django admin ) @@ -379,7 +379,7 @@ class DomainRequest(TimeStampedModel): blank=True, ) - # This is the application user who created this application. The contact + # This is the domain request user who created this domain request. The contact # information that they gave is in the `submitter` field creator = models.ForeignKey( "registrar.User", @@ -536,7 +536,7 @@ class DomainRequest(TimeStampedModel): "registrar.Contact", null=True, blank=True, - related_name="submitted_applications", + related_name="submitted_domain_requests", on_delete=models.PROTECT, ) @@ -549,7 +549,7 @@ class DomainRequest(TimeStampedModel): other_contacts = models.ManyToManyField( "registrar.Contact", blank=True, - related_name="contact_applications", + related_name="contact_domain_requests", verbose_name="contacts", ) @@ -638,7 +638,7 @@ class DomainRequest(TimeStampedModel): email_template, email_template_subject, self.submitter.email, - context={"application": self}, + context={"domain_request": self}, bcc_address=bcc_address, ) logger.info(f"The {new_status} email sent to: {self.submitter.email}") @@ -648,15 +648,15 @@ class DomainRequest(TimeStampedModel): @transition( field="status", source=[ - ApplicationStatus.STARTED, - ApplicationStatus.IN_REVIEW, - ApplicationStatus.ACTION_NEEDED, - ApplicationStatus.WITHDRAWN, + DomainRequestStatus.STARTED, + DomainRequestStatus.IN_REVIEW, + DomainRequestStatus.ACTION_NEEDED, + DomainRequestStatus.WITHDRAWN, ], - target=ApplicationStatus.SUBMITTED, + target=DomainRequestStatus.SUBMITTED, ) def submit(self): - """Submit an application that is started. + """Submit a domain request that is started. As a side effect, an email notification is sent.""" @@ -679,7 +679,7 @@ class DomainRequest(TimeStampedModel): self.save() # Limit email notifications to transitions from Started and Withdrawn - limited_statuses = [self.ApplicationStatus.STARTED, self.ApplicationStatus.WITHDRAWN] + limited_statuses = [self.DomainRequestStatus.STARTED, self.DomainRequestStatus.WITHDRAWN] bcc_address = "" if settings.IS_PRODUCTION: @@ -697,17 +697,17 @@ class DomainRequest(TimeStampedModel): @transition( field="status", source=[ - ApplicationStatus.SUBMITTED, - ApplicationStatus.ACTION_NEEDED, - ApplicationStatus.APPROVED, - ApplicationStatus.REJECTED, - ApplicationStatus.INELIGIBLE, + DomainRequestStatus.SUBMITTED, + DomainRequestStatus.ACTION_NEEDED, + DomainRequestStatus.APPROVED, + DomainRequestStatus.REJECTED, + DomainRequestStatus.INELIGIBLE, ], - target=ApplicationStatus.IN_REVIEW, + target=DomainRequestStatus.IN_REVIEW, conditions=[domain_is_not_active], ) def in_review(self): - """Investigate an application that has been submitted. + """Investigate a domain request that has been submitted. This action is logged. @@ -716,13 +716,13 @@ class DomainRequest(TimeStampedModel): As side effects this will delete the domain and domain_information (will cascade) when they exist.""" - if self.status == self.ApplicationStatus.APPROVED: + if self.status == self.DomainRequestStatus.APPROVED: self.delete_and_clean_up_domain("in_review") - if self.status == self.ApplicationStatus.REJECTED: + if self.status == self.DomainRequestStatus.REJECTED: self.rejection_reason = None - literal = DomainRequest.ApplicationStatus.IN_REVIEW + literal = DomainRequest.DomainRequestStatus.IN_REVIEW # Check if the tuple exists, then grab its value in_review = literal if literal is not None else "In Review" logger.info(f"A status change occurred. {self} was changed to '{in_review}'") @@ -730,16 +730,16 @@ class DomainRequest(TimeStampedModel): @transition( field="status", source=[ - ApplicationStatus.IN_REVIEW, - ApplicationStatus.APPROVED, - ApplicationStatus.REJECTED, - ApplicationStatus.INELIGIBLE, + DomainRequestStatus.IN_REVIEW, + DomainRequestStatus.APPROVED, + DomainRequestStatus.REJECTED, + DomainRequestStatus.INELIGIBLE, ], - target=ApplicationStatus.ACTION_NEEDED, + target=DomainRequestStatus.ACTION_NEEDED, conditions=[domain_is_not_active], ) def action_needed(self): - """Send back an application that is under investigation or rejected. + """Send back a domain request that is under investigation or rejected. This action is logged. @@ -748,13 +748,13 @@ class DomainRequest(TimeStampedModel): As side effects this will delete the domain and domain_information (will cascade) when they exist.""" - if self.status == self.ApplicationStatus.APPROVED: + if self.status == self.DomainRequestStatus.APPROVED: self.delete_and_clean_up_domain("reject_with_prejudice") - if self.status == self.ApplicationStatus.REJECTED: + if self.status == self.DomainRequestStatus.REJECTED: self.rejection_reason = None - literal = DomainRequest.ApplicationStatus.ACTION_NEEDED + literal = DomainRequest.DomainRequestStatus.ACTION_NEEDED # Check if the tuple is setup correctly, then grab its value action_needed = literal if literal is not None else "Action Needed" logger.info(f"A status change occurred. {self} was changed to '{action_needed}'") @@ -762,15 +762,15 @@ class DomainRequest(TimeStampedModel): @transition( field="status", source=[ - ApplicationStatus.SUBMITTED, - ApplicationStatus.IN_REVIEW, - ApplicationStatus.ACTION_NEEDED, - ApplicationStatus.REJECTED, + DomainRequestStatus.SUBMITTED, + DomainRequestStatus.IN_REVIEW, + DomainRequestStatus.ACTION_NEEDED, + DomainRequestStatus.REJECTED, ], - target=ApplicationStatus.APPROVED, + target=DomainRequestStatus.APPROVED, ) def approve(self, send_email=True): - """Approve an application that has been submitted. + """Approve a domain request that has been submitted. This action cleans up the rejection status if moving away from rejected. @@ -796,7 +796,7 @@ class DomainRequest(TimeStampedModel): user=self.creator, domain=created_domain, role=UserDomainRole.Roles.MANAGER ) - if self.status == self.ApplicationStatus.REJECTED: + if self.status == self.DomainRequestStatus.REJECTED: self.rejection_reason = None self._send_status_update_email( @@ -808,11 +808,11 @@ class DomainRequest(TimeStampedModel): @transition( field="status", - source=[ApplicationStatus.SUBMITTED, ApplicationStatus.IN_REVIEW, ApplicationStatus.ACTION_NEEDED], - target=ApplicationStatus.WITHDRAWN, + source=[DomainRequestStatus.SUBMITTED, DomainRequestStatus.IN_REVIEW, DomainRequestStatus.ACTION_NEEDED], + target=DomainRequestStatus.WITHDRAWN, ) def withdraw(self): - """Withdraw an application that has been submitted.""" + """Withdraw a domain request that has been submitted.""" self._send_status_update_email( "withdraw", @@ -822,17 +822,17 @@ class DomainRequest(TimeStampedModel): @transition( field="status", - source=[ApplicationStatus.IN_REVIEW, ApplicationStatus.ACTION_NEEDED, ApplicationStatus.APPROVED], - target=ApplicationStatus.REJECTED, + source=[DomainRequestStatus.IN_REVIEW, DomainRequestStatus.ACTION_NEEDED, DomainRequestStatus.APPROVED], + target=DomainRequestStatus.REJECTED, conditions=[domain_is_not_active], ) def reject(self): - """Reject an application that has been submitted. + """Reject a domain request that has been submitted. As side effects this will delete the domain and domain_information (will cascade), and send an email notification.""" - if self.status == self.ApplicationStatus.APPROVED: + if self.status == self.DomainRequestStatus.APPROVED: self.delete_and_clean_up_domain("reject") self._send_status_update_email( @@ -844,12 +844,12 @@ class DomainRequest(TimeStampedModel): @transition( field="status", source=[ - ApplicationStatus.IN_REVIEW, - ApplicationStatus.ACTION_NEEDED, - ApplicationStatus.APPROVED, - ApplicationStatus.REJECTED, + DomainRequestStatus.IN_REVIEW, + DomainRequestStatus.ACTION_NEEDED, + DomainRequestStatus.APPROVED, + DomainRequestStatus.REJECTED, ], - target=ApplicationStatus.INELIGIBLE, + target=DomainRequestStatus.INELIGIBLE, conditions=[domain_is_not_active], ) def reject_with_prejudice(self): @@ -861,7 +861,7 @@ class DomainRequest(TimeStampedModel): permissions classes test against. This will also delete the domain and domain_information (will cascade) when they exist.""" - if self.status == self.ApplicationStatus.APPROVED: + if self.status == self.DomainRequestStatus.APPROVED: self.delete_and_clean_up_domain("reject_with_prejudice") self.creator.restrict_user() @@ -869,7 +869,7 @@ class DomainRequest(TimeStampedModel): # ## Form policies ### # # These methods control what questions need to be answered by applicants - # during the application flow. They are policies about the application so + # during the domain request flow. They are policies about the domain request so # they appear here. def show_organization_federal(self) -> bool: @@ -905,15 +905,15 @@ class DomainRequest(TimeStampedModel): ] def has_rationale(self) -> bool: - """Does this application have no_other_contacts_rationale?""" + """Does this domain request have no_other_contacts_rationale?""" return bool(self.no_other_contacts_rationale) def has_other_contacts(self) -> bool: - """Does this application have other contacts listed?""" + """Does this domain request have other contacts listed?""" return self.other_contacts.exists() def is_federal(self) -> Union[bool, None]: - """Is this application for a federal agency? + """Is this domain request for a federal agency? organization_type can be both null and blank, """ diff --git a/src/registrar/templates/application_about_your_organization.html b/src/registrar/templates/domain_request_about_your_organization.html similarity index 95% rename from src/registrar/templates/application_about_your_organization.html rename to src/registrar/templates/domain_request_about_your_organization.html index 02e2e2c4f..9be8626aa 100644 --- a/src/registrar/templates/application_about_your_organization.html +++ b/src/registrar/templates/domain_request_about_your_organization.html @@ -1,4 +1,4 @@ -{% extends 'application_form.html' %} +{% extends 'domain_request_form.html' %} {% load field_helpers %} {% block form_instructions %} diff --git a/src/registrar/templates/application_anything_else.html b/src/registrar/templates/domain_request_anything_else.html similarity index 92% rename from src/registrar/templates/application_anything_else.html rename to src/registrar/templates/domain_request_anything_else.html index c1ecf94a9..326f9a5cf 100644 --- a/src/registrar/templates/application_anything_else.html +++ b/src/registrar/templates/domain_request_anything_else.html @@ -1,4 +1,4 @@ -{% extends 'application_form.html' %} +{% extends 'domain_request_form.html' %} {% load field_helpers %} {% block form_instructions %} diff --git a/src/registrar/templates/application_authorizing_official.html b/src/registrar/templates/domain_request_authorizing_official.html similarity index 96% rename from src/registrar/templates/application_authorizing_official.html rename to src/registrar/templates/domain_request_authorizing_official.html index 068457373..df4931ba7 100644 --- a/src/registrar/templates/application_authorizing_official.html +++ b/src/registrar/templates/domain_request_authorizing_official.html @@ -1,4 +1,4 @@ -{% extends 'application_form.html' %} +{% extends 'domain_request_form.html' %} {% load field_helpers url_helpers %} {% block form_instructions %} diff --git a/src/registrar/templates/application_current_sites.html b/src/registrar/templates/domain_request_current_sites.html similarity index 96% rename from src/registrar/templates/application_current_sites.html rename to src/registrar/templates/domain_request_current_sites.html index debadcfe2..2a2ac6885 100644 --- a/src/registrar/templates/application_current_sites.html +++ b/src/registrar/templates/domain_request_current_sites.html @@ -1,4 +1,4 @@ -{% extends 'application_form.html' %} +{% extends 'domain_request_form.html' %} {% load static field_helpers %} {% block form_instructions %} diff --git a/src/registrar/templates/application_done.html b/src/registrar/templates/domain_request_done.html similarity index 100% rename from src/registrar/templates/application_done.html rename to src/registrar/templates/domain_request_done.html diff --git a/src/registrar/templates/application_dotgov_domain.html b/src/registrar/templates/domain_request_dotgov_domain.html similarity index 98% rename from src/registrar/templates/application_dotgov_domain.html rename to src/registrar/templates/domain_request_dotgov_domain.html index 155fdbeb4..60220e014 100644 --- a/src/registrar/templates/application_dotgov_domain.html +++ b/src/registrar/templates/domain_request_dotgov_domain.html @@ -1,4 +1,4 @@ -{% extends 'application_form.html' %} +{% extends 'domain_request_form.html' %} {% load static field_helpers url_helpers %} {% block form_instructions %} diff --git a/src/registrar/templates/application_form.html b/src/registrar/templates/domain_request_form.html similarity index 96% rename from src/registrar/templates/application_form.html rename to src/registrar/templates/domain_request_form.html index 965967072..db436aeb3 100644 --- a/src/registrar/templates/application_form.html +++ b/src/registrar/templates/domain_request_form.html @@ -6,12 +6,12 @@
- {% include 'application_sidebar.html' %} + {% include 'domain_request_sidebar.html' %}
{% if steps.prev %} - + Previous step diff --git a/src/registrar/templates/application_intro.html b/src/registrar/templates/domain_request_intro.html similarity index 100% rename from src/registrar/templates/application_intro.html rename to src/registrar/templates/domain_request_intro.html diff --git a/src/registrar/templates/application_org_contact.html b/src/registrar/templates/domain_request_org_contact.html similarity index 96% rename from src/registrar/templates/application_org_contact.html rename to src/registrar/templates/domain_request_org_contact.html index e8e8f50bf..21cf19306 100644 --- a/src/registrar/templates/application_org_contact.html +++ b/src/registrar/templates/domain_request_org_contact.html @@ -1,4 +1,4 @@ -{% extends 'application_form.html' %} +{% extends 'domain_request_form.html' %} {% load field_helpers url_helpers %} {% block form_instructions %} diff --git a/src/registrar/templates/application_org_election.html b/src/registrar/templates/domain_request_org_election.html similarity index 94% rename from src/registrar/templates/application_org_election.html rename to src/registrar/templates/domain_request_org_election.html index b2ef462b5..182234bc3 100644 --- a/src/registrar/templates/application_org_election.html +++ b/src/registrar/templates/domain_request_org_election.html @@ -1,4 +1,4 @@ -{% extends 'application_form.html' %} +{% extends 'domain_request_form.html' %} {% load field_helpers %} {% block form_instructions %} diff --git a/src/registrar/templates/application_org_federal.html b/src/registrar/templates/domain_request_org_federal.html similarity index 91% rename from src/registrar/templates/application_org_federal.html rename to src/registrar/templates/domain_request_org_federal.html index 8a5a574b0..834298f24 100644 --- a/src/registrar/templates/application_org_federal.html +++ b/src/registrar/templates/domain_request_org_federal.html @@ -1,4 +1,4 @@ -{% extends 'application_form.html' %} +{% extends 'domain_request_form.html' %} {% load field_helpers %} {% block form_instructions %} diff --git a/src/registrar/templates/application_org_type.html b/src/registrar/templates/domain_request_org_type.html similarity index 92% rename from src/registrar/templates/application_org_type.html rename to src/registrar/templates/domain_request_org_type.html index ef3fb82f7..eab61e0bc 100644 --- a/src/registrar/templates/application_org_type.html +++ b/src/registrar/templates/domain_request_org_type.html @@ -1,4 +1,4 @@ -{% extends 'application_form.html' %} +{% extends 'domain_request_form.html' %} {% load field_helpers %} {% block form_instructions %} diff --git a/src/registrar/templates/application_other_contacts.html b/src/registrar/templates/domain_request_other_contacts.html similarity index 99% rename from src/registrar/templates/application_other_contacts.html rename to src/registrar/templates/domain_request_other_contacts.html index 4e13f705b..4189e8c73 100644 --- a/src/registrar/templates/application_other_contacts.html +++ b/src/registrar/templates/domain_request_other_contacts.html @@ -1,4 +1,4 @@ -{% extends 'application_form.html' %} +{% extends 'domain_request_form.html' %} {% load static field_helpers %} {% block form_instructions %} diff --git a/src/registrar/templates/application_purpose.html b/src/registrar/templates/domain_request_purpose.html similarity index 95% rename from src/registrar/templates/application_purpose.html rename to src/registrar/templates/domain_request_purpose.html index d71d068de..f79bf46e2 100644 --- a/src/registrar/templates/application_purpose.html +++ b/src/registrar/templates/domain_request_purpose.html @@ -1,4 +1,4 @@ -{% extends 'application_form.html' %} +{% extends 'domain_request_form.html' %} {% load field_helpers url_helpers %} {% block form_instructions %} diff --git a/src/registrar/templates/application_requirements.html b/src/registrar/templates/domain_request_requirements.html similarity index 98% rename from src/registrar/templates/application_requirements.html rename to src/registrar/templates/domain_request_requirements.html index ef0bf00f2..d0da7818b 100644 --- a/src/registrar/templates/application_requirements.html +++ b/src/registrar/templates/domain_request_requirements.html @@ -1,4 +1,4 @@ -{% extends 'application_form.html' %} +{% extends 'domain_request_form.html' %} {% load field_helpers %} {% block form_instructions %} diff --git a/src/registrar/templates/application_review.html b/src/registrar/templates/domain_request_review.html similarity index 58% rename from src/registrar/templates/application_review.html rename to src/registrar/templates/domain_request_review.html index 4af6b758f..f92aa858c 100644 --- a/src/registrar/templates/application_review.html +++ b/src/registrar/templates/domain_request_review.html @@ -1,4 +1,4 @@ -{% extends 'application_form.html' %} +{% extends 'domain_request_form.html' %} {% load static url_helpers %} {% load custom_filters %} @@ -23,98 +23,98 @@
{% if step == Step.ORGANIZATION_TYPE %} - {% namespaced_url 'application' step as application_url %} - {% if application.organization_type is not None %} - {% with title=form_titles|get_item:step value=application.get_organization_type_display|default:"Incomplete" %} - {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=application_url %} + {% namespaced_url 'domain_request' step as domain_request_url %} + {% if domain_request.organization_type is not None %} + {% with title=form_titles|get_item:step value=domain_request.get_organization_type_display|default:"Incomplete" %} + {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=domain_request_url %} {% endwith %} {% else %} {% with title=form_titles|get_item:step value="Incomplete" %} - {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=application_url %} + {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=domain_request_url %} {% endwith %} {% endif %} {% endif %} {% if step == Step.TRIBAL_GOVERNMENT %} - {% namespaced_url 'application' step as application_url %} - {% with title=form_titles|get_item:step value=application.tribe_name|default:"Incomplete" %} - {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=application_url %} + {% namespaced_url 'domain_request' step as domain_request_url %} + {% with title=form_titles|get_item:step value=domain_request.tribe_name|default:"Incomplete" %} + {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=domain_request_url %} {% endwith %} - {% if application.federally_recognized_tribe %}

Federally-recognized tribe

{% endif %} - {% if application.state_recognized_tribe %}

State-recognized tribe

{% endif %} + {% if domain_request.federally_recognized_tribe %}

Federally-recognized tribe

{% endif %} + {% if domain_request.state_recognized_tribe %}

State-recognized tribe

{% endif %} {% endif %} {% if step == Step.ORGANIZATION_FEDERAL %} - {% namespaced_url 'application' step as application_url %} - {% with title=form_titles|get_item:step value=application.get_federal_type_display|default:"Incomplete" %} - {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=application_url %} + {% namespaced_url 'domain_request' step as domain_request_url %} + {% with title=form_titles|get_item:step value=domain_request.get_federal_type_display|default:"Incomplete" %} + {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=domain_request_url %} {% endwith %} {% endif %} {% if step == Step.ORGANIZATION_ELECTION %} - {% namespaced_url 'application' step as application_url %} - {% with title=form_titles|get_item:step value=application.is_election_board|yesno:"Yes,No,Incomplete" %} - {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=application_url %} + {% namespaced_url 'domain_request' step as domain_request_url %} + {% with title=form_titles|get_item:step value=domain_request.is_election_board|yesno:"Yes,No,Incomplete" %} + {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=domain_request_url %} {% endwith %} {% endif %} {% if step == Step.ORGANIZATION_CONTACT %} - {% namespaced_url 'application' step as application_url %} - {% if application.organization_name %} + {% namespaced_url 'domain_request' step as domain_request_url %} + {% if domain_request.organization_name %} {% with title=form_titles|get_item:step value=application %} - {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=application_url address='true' %} + {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=domain_request_url address='true' %} {% endwith %} {% else %} {% with title=form_titles|get_item:step value='Incomplete' %} - {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=application_url %} + {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=domain_request_url %} {% endwith %} {% endif %} {% endif %} {% if step == Step.ABOUT_YOUR_ORGANIZATION %} - {% namespaced_url 'application' step as application_url %} - {% with title=form_titles|get_item:step value=application.about_your_organization|default:"Incomplete" %} - {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=application_url %} + {% namespaced_url 'domain_request' step as domain_request_url %} + {% with title=form_titles|get_item:step value=domain_request.about_your_organization|default:"Incomplete" %} + {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=domain_request_url %} {% endwith %} {% endif %} {% if step == Step.AUTHORIZING_OFFICIAL %} - {% namespaced_url 'application' step as application_url %} - {% if application.authorizing_official is not None %} - {% with title=form_titles|get_item:step value=application.authorizing_official %} - {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=application_url contact='true' %} + {% namespaced_url 'domain_request' step as domain_request_url %} + {% if domain_request.authorizing_official is not None %} + {% with title=form_titles|get_item:step value=domain_request.authorizing_official %} + {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=domain_request_url contact='true' %} {% endwith %} {% else %} {% with title=form_titles|get_item:step value="Incomplete" %} - {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=application_url %} + {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=domain_request_url %} {% endwith %} {% endif %} {% endif %} {% if step == Step.CURRENT_SITES %} - {% namespaced_url 'application' step as application_url %} - {% if application.current_websites.all %} - {% with title=form_titles|get_item:step value=application.current_websites.all %} - {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=application_url list='true' %} + {% namespaced_url 'domain_request' step as domain_request_url %} + {% if domain_request.current_websites.all %} + {% with title=form_titles|get_item:step value=domain_request.current_websites.all %} + {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=domain_request_url list='true' %} {% endwith %} {% else %} {% with title=form_titles|get_item:step value='None' %} - {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=application_url %} + {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=domain_request_url %} {% endwith %} {% endif %} {% endif %} {% if step == Step.DOTGOV_DOMAIN %} - {% namespaced_url 'application' step as application_url %} - {% with title=form_titles|get_item:step value=application.requested_domain.name|default:"Incomplete" %} - {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=application_url %} + {% namespaced_url 'domain_request' step as domain_request_url %} + {% with title=form_titles|get_item:step value=domain_request.requested_domain.name|default:"Incomplete" %} + {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=domain_request_url %} {% endwith %} - {% if application.alternative_domains.all %} + {% if domain_request.alternative_domains.all %}

Alternative domains

    - {% for site in application.alternative_domains.all %} + {% for site in domain_request.alternative_domains.all %}
  • {{ site.website }}
  • {% endfor %}
@@ -122,51 +122,51 @@ {% endif %} {% if step == Step.PURPOSE %} - {% namespaced_url 'application' step as application_url %} - {% with title=form_titles|get_item:step value=application.purpose|default:"Incomplete" %} - {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=application_url %} + {% namespaced_url 'domain_request' step as domain_request_url %} + {% with title=form_titles|get_item:step value=domain_request.purpose|default:"Incomplete" %} + {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=domain_request_url %} {% endwith %} {% endif %} {% if step == Step.YOUR_CONTACT %} - {% namespaced_url 'application' step as application_url %} - {% if application.submitter is not None %} - {% with title=form_titles|get_item:step value=application.submitter %} - {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=application_url contact='true' %} + {% namespaced_url 'domain_request' step as domain_request_url %} + {% if domain_request.submitter is not None %} + {% with title=form_titles|get_item:step value=domain_request.submitter %} + {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=domain_request_url contact='true' %} {% endwith %} {% else %} {% with title=form_titles|get_item:step value="Incomplete" %} - {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=application_url %} + {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=domain_request_url %} {% endwith %} {% endif %} {% endif %} {% if step == Step.OTHER_CONTACTS %} - {% namespaced_url 'application' step as application_url %} - {% if application.other_contacts.all %} - {% with title=form_titles|get_item:step value=application.other_contacts.all %} - {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=application_url contact='true' list='true' %} + {% namespaced_url 'domain_request' step as domain_request_url %} + {% if domain_request.other_contacts.all %} + {% with title=form_titles|get_item:step value=domain_request.other_contacts.all %} + {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=domain_request_url contact='true' list='true' %} {% endwith %} {% else %} - {% with title=form_titles|get_item:step value=application.no_other_contacts_rationale|default:"Incomplete" %} - {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=application_url %} + {% with title=form_titles|get_item:step value=domain_request.no_other_contacts_rationale|default:"Incomplete" %} + {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=domain_request_url %} {% endwith %} {% endif %} {% endif %} {% if step == Step.ANYTHING_ELSE %} - {% namespaced_url 'application' step as application_url %} - {% with title=form_titles|get_item:step value=application.anything_else|default:"No" %} - {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=application_url %} + {% namespaced_url 'domain_request' step as domain_request_url %} + {% with title=form_titles|get_item:step value=domain_request.anything_else|default:"No" %} + {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=domain_request_url %} {% endwith %} {% endif %} {% if step == Step.REQUIREMENTS %} - {% namespaced_url 'application' step as application_url %} - {% with title=form_titles|get_item:step value=application.is_policy_acknowledged|yesno:"I agree.,I do not agree.,I do not agree." %} - {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=application_url %} + {% namespaced_url 'domain_request' step as domain_request_url %} + {% with title=form_titles|get_item:step value=domain_request.is_policy_acknowledged|yesno:"I agree.,I do not agree.,I do not agree." %} + {% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=domain_request_url %} {% endwith %} {% endif %} diff --git a/src/registrar/templates/application_sidebar.html b/src/registrar/templates/domain_request_sidebar.html similarity index 95% rename from src/registrar/templates/application_sidebar.html rename to src/registrar/templates/domain_request_sidebar.html index e0e51dd45..d18864c2e 100644 --- a/src/registrar/templates/application_sidebar.html +++ b/src/registrar/templates/domain_request_sidebar.html @@ -15,7 +15,7 @@ {% endif %} {% endif %} -
. diff --git a/src/registrar/templates/emails/status_change_approved_subject.txt b/src/registrar/templates/emails/status_change_approved_subject.txt index 5ceaa29af..51b2c745a 100644 --- a/src/registrar/templates/emails/status_change_approved_subject.txt +++ b/src/registrar/templates/emails/status_change_approved_subject.txt @@ -1 +1 @@ -Update on your .gov request: {{ application.requested_domain.name }} +Update on your .gov request: {{ domain_request.requested_domain.name }} diff --git a/src/registrar/templates/emails/status_change_rejected.txt b/src/registrar/templates/emails/status_change_rejected.txt index 0ece4b8ed..4573bc137 100644 --- a/src/registrar/templates/emails/status_change_rejected.txt +++ b/src/registrar/templates/emails/status_change_rejected.txt @@ -1,15 +1,15 @@ {% autoescape off %}{# In a text file, we don't want to have HTML entities escaped #} -Hi, {{ application.submitter.first_name }}. +Hi, {{ domain_request.submitter.first_name }}. Your .gov domain request has been rejected. -DOMAIN REQUESTED: {{ application.requested_domain.name }} -REQUEST RECEIVED ON: {{ application.submission_date|date }} +DOMAIN REQUESTED: {{ domain_request.requested_domain.name }} +REQUEST RECEIVED ON: {{ domain_request.submission_date|date }} STATUS: Rejected ---------------------------------------------------------------- -{% if application.rejection_reason != 'other' %} -REJECTION REASON{% endif %}{% if application.rejection_reason == 'purpose_not_met' %} +{% if domain_request.rejection_reason != 'other' %} +REJECTION REASON{% endif %}{% if domain_request.rejection_reason == 'purpose_not_met' %} Your domain request was rejected because the purpose you provided did not meet our requirements. You didn’t provide enough information about how you intend to use the domain. @@ -18,16 +18,16 @@ Learn more about: - Eligibility for a .gov domain - What you can and can’t do with .gov domains -If you have questions or comments, reply to this email.{% elif application.rejection_reason == 'requestor_not_eligible' %} +If you have questions or comments, reply to this email.{% elif domain_request.rejection_reason == 'requestor_not_eligible' %} Your domain request was rejected because we don’t believe you’re eligible to request a -.gov domain on behalf of {{ application.organization_name }}. You must be a government employee, or be +.gov domain on behalf of {{ domain_request.organization_name }}. You must be a government employee, or be working on behalf of a government organization, to request a .gov domain. DEMONSTRATE ELIGIBILITY If you can provide more information that demonstrates your eligibility, or you want to -discuss further, reply to this email.{% elif application.rejection_reason == 'org_has_domain' %} -Your domain request was rejected because {{ application.organization_name }} has a .gov domain. Our +discuss further, reply to this email.{% elif domain_request.rejection_reason == 'org_has_domain' %} +Your domain request was rejected because {{ domain_request.organization_name }} has a .gov domain. Our practice is to approve one domain per online service per government organization. We evaluate additional requests on a case-by-case basis. You did not provide sufficient justification for an additional domain. @@ -35,10 +35,10 @@ justification for an additional domain. Read more about our practice of approving one domain per online service . -If you have questions or comments, reply to this email.{% elif application.rejection_reason == 'contacts_not_verified' %} +If you have questions or comments, reply to this email.{% elif domain_request.rejection_reason == 'contacts_not_verified' %} Your domain request was rejected because we could not verify the organizational -contacts you provided. If you have questions or comments, reply to this email.{% elif application.rejection_reason == 'org_not_eligible' %} -Your domain request was rejected because we determined that {{ application.organization_name }} is not +contacts you provided. If you have questions or comments, reply to this email.{% elif domain_request.rejection_reason == 'org_not_eligible' %} +Your domain request was rejected because we determined that {{ domain_request.organization_name }} is not eligible for a .gov domain. .Gov domains are only available to official U.S.-based government organizations. @@ -48,7 +48,7 @@ If you can provide documentation that demonstrates your eligibility, reply to th This can include links to (or copies of) your authorizing legislation, your founding charter or bylaws, or other similar documentation. Without this, we can’t approve a .gov domain for your organization. Learn more about eligibility for .gov domains -.{% elif application.rejection_reason == 'naming_not_met' %} +.{% elif domain_request.rejection_reason == 'naming_not_met' %} Your domain request was rejected because it does not meet our naming requirements. Domains should uniquely identify a government organization and be clear to the general public. Learn more about naming requirements for your type of organization @@ -57,7 +57,7 @@ general public. Learn more about naming requirements for your type of organizati YOU CAN SUBMIT A NEW REQUEST We encourage you to request a domain that meets our requirements. If you have -questions or want to discuss potential domain names, reply to this email.{% elif application.rejection_reason == 'other' %} +questions or want to discuss potential domain names, reply to this email.{% elif domain_request.rejection_reason == 'other' %} YOU CAN SUBMIT A NEW REQUEST If your organization is eligible for a .gov domain and you meet our other requirements, you can submit a new request. diff --git a/src/registrar/templates/emails/status_change_rejected_subject.txt b/src/registrar/templates/emails/status_change_rejected_subject.txt index 5ceaa29af..51b2c745a 100644 --- a/src/registrar/templates/emails/status_change_rejected_subject.txt +++ b/src/registrar/templates/emails/status_change_rejected_subject.txt @@ -1 +1 @@ -Update on your .gov request: {{ application.requested_domain.name }} +Update on your .gov request: {{ domain_request.requested_domain.name }} diff --git a/src/registrar/templates/emails/submission_confirmation.txt b/src/registrar/templates/emails/submission_confirmation.txt index 16a951ac1..248d27d81 100644 --- a/src/registrar/templates/emails/submission_confirmation.txt +++ b/src/registrar/templates/emails/submission_confirmation.txt @@ -1,10 +1,10 @@ {% autoescape off %}{# In a text file, we don't want to have HTML entities escaped #} -Hi, {{ application.submitter.first_name }}. +Hi, {{ domain_request.submitter.first_name }}. We received your .gov domain request. -DOMAIN REQUESTED: {{ application.requested_domain.name }} -REQUEST RECEIVED ON: {{ application.submission_date|date }} +DOMAIN REQUESTED: {{ domain_request.requested_domain.name }} +REQUEST RECEIVED ON: {{ domain_request.submission_date|date }} STATUS: Submitted ---------------------------------------------------------------- @@ -29,7 +29,7 @@ THANK YOU ---------------------------------------------------------------- -{% include 'emails/includes/application_summary.txt' %} +{% include 'emails/includes/domain_request_summary.txt' %} ---------------------------------------------------------------- The .gov team diff --git a/src/registrar/templates/emails/submission_confirmation_subject.txt b/src/registrar/templates/emails/submission_confirmation_subject.txt index 5ceaa29af..51b2c745a 100644 --- a/src/registrar/templates/emails/submission_confirmation_subject.txt +++ b/src/registrar/templates/emails/submission_confirmation_subject.txt @@ -1 +1 @@ -Update on your .gov request: {{ application.requested_domain.name }} +Update on your .gov request: {{ domain_request.requested_domain.name }} diff --git a/src/registrar/templates/home.html b/src/registrar/templates/home.html index c33c5153c..b488cb958 100644 --- a/src/registrar/templates/home.html +++ b/src/registrar/templates/home.html @@ -112,7 +112,7 @@
Date submitted Status ActionDelete Action
- {% if application.requested_domain is None %} + {% if domain_request.requested_domain is None %} New domain request {# Add a breakpoint #} - ({{ application.created_at }} UTC) + ({{ domain_request.created_at }} UTC) {% else %} - {{ application.requested_domain.name }} + {{ domain_request.requested_domain.name }} {% endif %} - {% if application.submission_date %} - {{ application.submission_date|date }} + + {% if domain_request.submission_date %} + {{ domain_request.submission_date|date }} {% else %} Not submitted {% endif %} {{ application.get_status_display }}{{ domain_request.get_status_display }} {% with prefix="New domain request ("%} - {% with date=application.created_at|date:"DATETIME_FORMAT"%} + {% with date=domain_request.created_at|date:"DATETIME_FORMAT"%} {% with name_default=prefix|add:date|add:" UTC)"%} - {% if application.status == application.ApplicationStatus.STARTED or application.status == application.ApplicationStatus.ACTION_NEEDED or application.status == application.ApplicationStatus.WITHDRAWN %} - + {% if domain_request.status == domain_request.DomainRequestStatus.STARTED or domain_request.status == domain_request.DomainRequestStatus.ACTION_NEEDED or domain_request.status == domain_request.DomainRequestStatus.WITHDRAWN %} + - {% if application.requested_domain is not None%} - Edit {{ application.requested_domain.name }} + {% if domain_request.requested_domain is not None%} + Edit {{ domain_request.requested_domain.name }} {% else %} Edit {{ name_default }} {% endif %} {% else %} - + - Manage {{ application.requested_domain.name|default:name_default }} + Manage {{ domain_request.requested_domain.name|default:name_default }} {% endif %} {% endwith %} {% endwith %} {% endwith %} - {% if application.status == "started" or application.status == "withdrawn" %} + {% if domain_request.status == "started" or domain_request.status == "withdrawn" %} {% with prefix="New domain request ("%} - {% with date=application.created_at|date:"DATETIME_FORMAT"%} + {% with date=domain_request.created_at|date:"DATETIME_FORMAT"%} {% with name_default=prefix|add:date|add:" UTC)"%} - {% if application.requested_domain is not None %} - Delete {{ application.requested_domain.name }} + {% if domain_request.requested_domain is not None %} + Delete {{ domain_request.requested_domain.name }} {% else %} Delete {{ name_default }} {% endif %} @@ -198,11 +198,11 @@ aria-describedby="Domain will be removed" data-force-action > -
- {% if application.requested_domain is None %} - {% if application.created_at %} + + {% if domain_request.requested_domain is None %} + {% if domain_request.created_at %} {% with prefix="(created " %} - {% with formatted_date=application.created_at|date:"DATETIME_FORMAT" %} + {% with formatted_date=domain_request.created_at|date:"DATETIME_FORMAT" %} {% with modal_content=prefix|add:formatted_date|add:" UTC)" %} {% include 'includes/modal.html' with modal_heading="Are you sure you want to delete this domain request?" modal_description="This will remove the domain request "|add:modal_content|add:" from the .gov registrar. This action cannot be undone." modal_button=modal_button|safe %} {% endwith %} @@ -212,7 +212,7 @@ {% include 'includes/modal.html' with modal_heading="Are you sure you want to delete New domain request?" modal_description="This will remove the domain request from the .gov registrar. This action cannot be undone." modal_button=modal_button|safe %} {% endif %} {% else %} - {% with modal_heading_value=application.requested_domain.name|add:"?" %} + {% with modal_heading_value=domain_request.requested_domain.name|add:"?" %} {% include 'includes/modal.html' with modal_heading="Are you sure you want to delete" heading_value=modal_heading_value modal_description="This will remove the domain request from the .gov registrar. This action cannot be undone." modal_button=modal_button|safe %} {% endwith %} {% endif %} diff --git a/src/registrar/tests/common.py b/src/registrar/tests/common.py index 184ed9132..3e5d7136d 100644 --- a/src/registrar/tests/common.py +++ b/src/registrar/tests/common.py @@ -221,7 +221,7 @@ class AuditedAdminMockData: # Constants for different domain object types INFORMATION = "information" - APPLICATION = "application" + DOMAIN_REQUEST = "domain_request" INVITATION = "invitation" def dummy_user(self, item_name, short_hand): @@ -365,7 +365,7 @@ class AuditedAdminMockData: self, domain_type, item_name, - status=DomainRequest.ApplicationStatus.STARTED, + status=DomainRequest.DomainRequestStatus.STARTED, org_type="federal", federal_type="executive", purpose="Purpose of the site", @@ -374,7 +374,7 @@ class AuditedAdminMockData: Returns a prebuilt kwarg dictionary for DomainRequest, DomainInformation, or DomainInvitation. Args: - domain_type (str): is either 'application', 'information', + domain_type (str): is either 'domain_request', 'information', or 'invitation'. item_name (str): A shared str value appended to first_name, last_name, @@ -382,7 +382,7 @@ class AuditedAdminMockData: title, email, and username. status (str - optional): Defines the status for DomainRequest, - e.g. DomainRequest.ApplicationStatus.STARTED + e.g. DomainRequest.DomainRequestStatus.STARTED org_type (str - optional): Sets a domains org_type @@ -397,7 +397,7 @@ class AuditedAdminMockData: common_args = self.get_common_domain_arg_dictionary(item_name, org_type, federal_type, purpose) full_arg_dict = None match domain_type: - case self.APPLICATION: + case self.DOMAIN_REQUEST: full_arg_dict = dict( **common_args, requested_domain=self.dummy_draft_domain(item_name), @@ -419,22 +419,22 @@ class AuditedAdminMockData: ) return full_arg_dict - def create_full_dummy_domain_request(self, item_name, status=DomainRequest.ApplicationStatus.STARTED): + def create_full_dummy_domain_request(self, item_name, status=DomainRequest.DomainRequestStatus.STARTED): """Creates a dummy domain request object""" - domain_request_kwargs = self.dummy_kwarg_boilerplate(self.APPLICATION, item_name, status) - application = DomainRequest.objects.get_or_create(**domain_request_kwargs)[0] + domain_request_kwargs = self.dummy_kwarg_boilerplate(self.DOMAIN_REQUEST, item_name, status) + domain_request = DomainRequest.objects.get_or_create(**domain_request_kwargs)[0] return application - def create_full_dummy_domain_information(self, item_name, status=DomainRequest.ApplicationStatus.STARTED): + def create_full_dummy_domain_information(self, item_name, status=DomainRequest.DomainRequestStatus.STARTED): """Creates a dummy domain information object""" domain_request_kwargs = self.dummy_kwarg_boilerplate(self.INFORMATION, item_name, status) - application = DomainInformation.objects.get_or_create(**domain_request_kwargs)[0] + domain_request = DomainInformation.objects.get_or_create(**domain_request_kwargs)[0] return application - def create_full_dummy_domain_invitation(self, item_name, status=DomainRequest.ApplicationStatus.STARTED): + def create_full_dummy_domain_invitation(self, item_name, status=DomainRequest.DomainRequestStatus.STARTED): """Creates a dummy domain invitation object""" domain_request_kwargs = self.dummy_kwarg_boilerplate(self.INVITATION, item_name, status) - application = DomainInvitation.objects.get_or_create(**domain_request_kwargs)[0] + domain_request = DomainInvitation.objects.get_or_create(**domain_request_kwargs)[0] return application @@ -445,29 +445,29 @@ class AuditedAdminMockData: has_other_contacts=True, has_current_website=True, has_alternative_gov_domain=True, - status=DomainRequest.ApplicationStatus.STARTED, + status=DomainRequest.DomainRequestStatus.STARTED, ): """A helper to create a dummy domain request object""" - application = None + domain_request = None match domain_type: - case self.APPLICATION: - application = self.create_full_dummy_domain_request(item_name, status) + case self.DOMAIN_REQUEST: + domain_request = self.create_full_dummy_domain_request(item_name, status) case self.INVITATION: - application = self.create_full_dummy_domain_invitation(item_name, status) + domain_request = self.create_full_dummy_domain_invitation(item_name, status) case self.INFORMATION: - application = self.create_full_dummy_domain_information(item_name, status) + domain_request = self.create_full_dummy_domain_information(item_name, status) case _: raise ValueError("Invalid domain_type, must conform to given constants") if has_other_contacts and domain_type != self.INVITATION: other = self.dummy_contact(item_name, "other") - application.other_contacts.add(other) - if has_current_website and domain_type == self.APPLICATION: + domain_request.other_contacts.add(other) + if has_current_website and domain_type == self.DOMAIN_REQUEST: current = self.dummy_current(item_name) - application.current_websites.add(current) - if has_alternative_gov_domain and domain_type == self.APPLICATION: + domain_request.current_websites.add(current) + if has_alternative_gov_domain and domain_type == self.DOMAIN_REQUEST: alt = self.dummy_alt(item_name) - application.alternative_domains.add(alt) + domain_request.alternative_domains.add(alt) return application @@ -520,13 +520,13 @@ def create_ready_domain(): return domain -def completed_application( +def completed_domain_request( has_other_contacts=True, has_current_website=True, has_alternative_gov_domain=True, has_about_your_organization=True, has_anything_else=True, - status=DomainRequest.ApplicationStatus.STARTED, + status=DomainRequest.DomainRequestStatus.STARTED, user=False, submitter=False, name="city.gov", @@ -583,17 +583,17 @@ def completed_application( application, _ = DomainRequest.objects.get_or_create(**domain_request_kwargs) if has_other_contacts: - application.other_contacts.add(other) + domain_request.other_contacts.add(other) if has_current_website: - application.current_websites.add(current) + domain_request.current_websites.add(current) if has_alternative_gov_domain: - application.alternative_domains.add(alt) + domain_request.alternative_domains.add(alt) return application def multiple_unalphabetical_domain_objects( - domain_type=AuditedAdminMockData.APPLICATION, + domain_type=AuditedAdminMockData.DOMAIN_REQUEST, ): """Returns a list of generic domain objects for testing purposes""" applications = [] @@ -602,16 +602,16 @@ def multiple_unalphabetical_domain_objects( mock = AuditedAdminMockData() for object_name in list_of_letters: - application = mock.create_full_dummy_domain_object(domain_type, object_name) + domain_request = mock.create_full_dummy_domain_object(domain_type, object_name) applications.append(application) return applications def generic_domain_object(domain_type, object_name): """Returns a generic domain object of - domain_type 'application', 'information', or 'invitation'""" + domain_type 'domain_request', 'information', or 'invitation'""" mock = AuditedAdminMockData() - application = mock.create_full_dummy_domain_object(domain_type, object_name) + domain_request = mock.create_full_dummy_domain_object(domain_type, object_name) return application diff --git a/src/registrar/tests/test_admin.py b/src/registrar/tests/test_admin.py index d9eef5cd2..7fb72e8ec 100644 --- a/src/registrar/tests/test_admin.py +++ b/src/registrar/tests/test_admin.py @@ -24,7 +24,7 @@ from registrar.models.verified_by_staff import VerifiedByStaff from .common import ( MockSESClient, AuditedAdminMockData, - completed_application, + completed_domain_request, generic_domain_object, less_console_noise, mock_user, @@ -236,10 +236,10 @@ class TestDomainAdmin(MockEppLib, WebTest): """ with less_console_noise(): self.client.force_login(self.superuser) - application = completed_application(status=DomainRequest.ApplicationStatus.IN_REVIEW) + domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.IN_REVIEW) mock_client = MockSESClient() with boto3_mocking.clients.handler_for("sesv2", mock_client): - application.approve() + domain_request.approve() response = self.client.get("/admin/registrar/domain/") @@ -442,12 +442,12 @@ class TestDomainAdmin(MockEppLib, WebTest): class TestDomainRequestAdminForm(TestCase): def setUp(self): # Create a test application with an initial state of started - self.application = completed_application() + self.domain_request = completed_domain_request() def test_form_choices(self): with less_console_noise(): # Create a form instance with the test application - form = DomainRequestAdminForm(instance=self.application) + form = DomainRequestAdminForm(instance=self.domain_request) # Verify that the form choices match the available transitions for started expected_choices = [("started", "Started"), ("submitted", "Submitted")] @@ -471,12 +471,12 @@ class TestDomainRequestAdminForm(TestCase): def test_form_choices_when_ineligible(self): with less_console_noise(): # Create a form instance with a domain request with ineligible status - ineligible_application = DomainRequest(status="ineligible") + ineligible_domain_request = DomainRequest(status="ineligible") # Attempt to create a form with the ineligible application # The form should not raise an error, but choices should be the # full list of possible choices - form = DomainRequestAdminForm(instance=ineligible_application) + form = DomainRequestAdminForm(instance=ineligible_domain_request) self.assertEqual( form.fields["status"].widget.choices, @@ -509,7 +509,7 @@ class TestDomainRequestAdmin(MockEppLib): p = "adminpass" self.client.login(username="superuser", password=p) - multiple_unalphabetical_domain_objects("application") + multiple_unalphabetical_domain_objects("domain_request") # Assert that our sort works correctly self.test_helper.assert_table_sorted("1", ("requested_domain__name",)) @@ -523,10 +523,10 @@ class TestDomainRequestAdmin(MockEppLib): p = "adminpass" self.client.login(username="superuser", password=p) - multiple_unalphabetical_domain_objects("application") + multiple_unalphabetical_domain_objects("domain_request") - additional_application = generic_domain_object("application", "Xylophone") - new_user = User.objects.filter(username=additional_application.investigator.username).get() + additional_domain_request = generic_domain_object("domain_request", "Xylophone") + new_user = User.objects.filter(username=additional_domain_request.investigator.username).get() new_user.first_name = "Xylophonic" new_user.save() @@ -554,9 +554,9 @@ class TestDomainRequestAdmin(MockEppLib): p = "adminpass" self.client.login(username="superuser", password=p) - multiple_unalphabetical_domain_objects("application") - additional_application = generic_domain_object("application", "Xylophone") - new_user = User.objects.filter(username=additional_application.investigator.username).get() + multiple_unalphabetical_domain_objects("domain_request") + additional_domain_request = generic_domain_object("domain_request", "Xylophone") + new_user = User.objects.filter(username=additional_domain_request.investigator.username).get() new_user.first_name = "Xylophonic" new_user.save() @@ -578,13 +578,13 @@ class TestDomainRequestAdmin(MockEppLib): ), ) - def test_short_org_name_in_applications_list(self): + def test_short_org_name_in_domain_requests_list(self): """ Make sure the short name is displaying in admin on the list page """ with less_console_noise(): self.client.force_login(self.superuser) - completed_application() + completed_domain_request() response = self.client.get("/admin/registrar/DomainRequest/") # There are 4 template references to Federal (4) plus two references in the table # for our actual application @@ -594,20 +594,20 @@ class TestDomainRequestAdmin(MockEppLib): # Now let's make sure the long description does not exist self.assertNotContains(response, "Federal: an agency of the U.S. government") - def transition_state_and_send_email(self, application, status, rejection_reason=None): + def transition_state_and_send_email(self, domain_request, status, rejection_reason=None): """Helper method for the email test cases.""" with boto3_mocking.clients.handler_for("sesv2", self.mock_client): with less_console_noise(): # Create a mock request - request = self.factory.post("/admin/registrar/DomainRequest/{}/change/".format(application.pk)) + request = self.factory.post("/admin/registrar/DomainRequest/{}/change/".format(domain_request.pk)) - # Modify the application's properties - application.status = status - application.rejection_reason = rejection_reason + # Modify the domain request's properties + domain_request.status = status + domain_request.rejection_reason = rejection_reason # Use the model admin's save_model method - self.admin.save_model(request, application, form=None, change=True) + self.admin.save_model(request, domain_request, form=None, change=True) def assert_email_is_accurate( self, expected_string, email_index, email_address, test_that_no_bcc=False, bcc_email_address="" @@ -658,42 +658,42 @@ class TestDomainRequestAdmin(MockEppLib): User.objects.filter(email=EMAIL).delete() # Create a sample application - application = completed_application() + domain_request = completed_domain_request() # Test Submitted Status from started - self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.SUBMITTED) + self.transition_state_and_send_email(application, DomainRequest.DomainRequestStatus.SUBMITTED) self.assert_email_is_accurate("We received your .gov domain request.", 0, EMAIL, True) self.assertEqual(len(self.mock_client.EMAILS_SENT), 1) # Test Withdrawn Status - self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.WITHDRAWN) + self.transition_state_and_send_email(application, DomainRequest.DomainRequestStatus.WITHDRAWN) self.assert_email_is_accurate( "Your .gov domain request has been withdrawn and will not be reviewed by our team.", 1, EMAIL, True ) self.assertEqual(len(self.mock_client.EMAILS_SENT), 2) # Test Submitted Status Again (from withdrawn) - self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.SUBMITTED) + self.transition_state_and_send_email(application, DomainRequest.DomainRequestStatus.SUBMITTED) self.assertEqual(len(self.mock_client.EMAILS_SENT), 3) # Move it to IN_REVIEW - self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.IN_REVIEW) + self.transition_state_and_send_email(application, DomainRequest.DomainRequestStatus.IN_REVIEW) self.assertEqual(len(self.mock_client.EMAILS_SENT), 3) # Test Submitted Status Again from in IN_REVIEW, no new email should be sent - self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.SUBMITTED) + self.transition_state_and_send_email(application, DomainRequest.DomainRequestStatus.SUBMITTED) self.assertEqual(len(self.mock_client.EMAILS_SENT), 3) # Move it to IN_REVIEW - self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.IN_REVIEW) + self.transition_state_and_send_email(application, DomainRequest.DomainRequestStatus.IN_REVIEW) self.assertEqual(len(self.mock_client.EMAILS_SENT), 3) # Move it to ACTION_NEEDED - self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.ACTION_NEEDED) + self.transition_state_and_send_email(application, DomainRequest.DomainRequestStatus.ACTION_NEEDED) self.assertEqual(len(self.mock_client.EMAILS_SENT), 3) # Test Submitted Status Again from in ACTION_NEEDED, no new email should be sent - self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.SUBMITTED) + self.transition_state_and_send_email(application, DomainRequest.DomainRequestStatus.SUBMITTED) self.assertEqual(len(self.mock_client.EMAILS_SENT), 3) @override_settings(IS_PRODUCTION=True) @@ -715,43 +715,43 @@ class TestDomainRequestAdmin(MockEppLib): BCC_EMAIL = settings.DEFAULT_FROM_EMAIL # Create a sample application - application = completed_application() + domain_request = completed_domain_request() # Test Submitted Status from started - self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.SUBMITTED) + self.transition_state_and_send_email(application, DomainRequest.DomainRequestStatus.SUBMITTED) self.assert_email_is_accurate("We received your .gov domain request.", 0, EMAIL, False, BCC_EMAIL) self.assertEqual(len(self.mock_client.EMAILS_SENT), 1) # Test Withdrawn Status - self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.WITHDRAWN) + self.transition_state_and_send_email(application, DomainRequest.DomainRequestStatus.WITHDRAWN) self.assert_email_is_accurate( "Your .gov domain request has been withdrawn and will not be reviewed by our team.", 1, EMAIL ) self.assertEqual(len(self.mock_client.EMAILS_SENT), 2) # Test Submitted Status Again (from withdrawn) - self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.SUBMITTED) + self.transition_state_and_send_email(application, DomainRequest.DomainRequestStatus.SUBMITTED) self.assert_email_is_accurate("We received your .gov domain request.", 0, EMAIL, False, BCC_EMAIL) self.assertEqual(len(self.mock_client.EMAILS_SENT), 3) # Move it to IN_REVIEW - self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.IN_REVIEW) + self.transition_state_and_send_email(application, DomainRequest.DomainRequestStatus.IN_REVIEW) self.assertEqual(len(self.mock_client.EMAILS_SENT), 3) # Test Submitted Status Again from in IN_REVIEW, no new email should be sent - self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.SUBMITTED) + self.transition_state_and_send_email(application, DomainRequest.DomainRequestStatus.SUBMITTED) self.assertEqual(len(self.mock_client.EMAILS_SENT), 3) # Move it to IN_REVIEW - self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.IN_REVIEW) + self.transition_state_and_send_email(application, DomainRequest.DomainRequestStatus.IN_REVIEW) self.assertEqual(len(self.mock_client.EMAILS_SENT), 3) # Move it to ACTION_NEEDED - self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.ACTION_NEEDED) + self.transition_state_and_send_email(application, DomainRequest.DomainRequestStatus.ACTION_NEEDED) self.assertEqual(len(self.mock_client.EMAILS_SENT), 3) # Test Submitted Status Again from in ACTION_NEEDED, no new email should be sent - self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.SUBMITTED) + self.transition_state_and_send_email(application, DomainRequest.DomainRequestStatus.SUBMITTED) self.assertEqual(len(self.mock_client.EMAILS_SENT), 3) def test_save_model_sends_approved_email(self): @@ -764,24 +764,24 @@ class TestDomainRequestAdmin(MockEppLib): User.objects.filter(email=EMAIL).delete() # Create a sample application - application = completed_application(status=DomainRequest.ApplicationStatus.IN_REVIEW) + domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.IN_REVIEW) # Test Submitted Status - self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.APPROVED) + self.transition_state_and_send_email(application, DomainRequest.DomainRequestStatus.APPROVED) self.assert_email_is_accurate("Congratulations! Your .gov domain request has been approved.", 0, EMAIL) self.assertEqual(len(self.mock_client.EMAILS_SENT), 1) # Test Withdrawn Status self.transition_state_and_send_email( application, - DomainRequest.ApplicationStatus.REJECTED, + DomainRequest.DomainRequestStatus.REJECTED, DomainRequest.RejectionReasons.DOMAIN_PURPOSE, ) self.assert_email_is_accurate("Your .gov domain request has been rejected.", 1, EMAIL) self.assertEqual(len(self.mock_client.EMAILS_SENT), 2) # Test Submitted Status Again (No new email should be sent) - self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.APPROVED) + self.transition_state_and_send_email(application, DomainRequest.DomainRequestStatus.APPROVED) self.assertEqual(len(self.mock_client.EMAILS_SENT), 3) def test_save_model_sends_rejected_email_purpose_not_met(self): @@ -794,12 +794,12 @@ class TestDomainRequestAdmin(MockEppLib): User.objects.filter(email=EMAIL).delete() # Create a sample application - application = completed_application(status=DomainRequest.ApplicationStatus.IN_REVIEW) + domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.IN_REVIEW) # Reject for reason DOMAIN_PURPOSE and test email self.transition_state_and_send_email( application, - DomainRequest.ApplicationStatus.REJECTED, + DomainRequest.DomainRequestStatus.REJECTED, DomainRequest.RejectionReasons.DOMAIN_PURPOSE, ) self.assert_email_is_accurate( @@ -810,7 +810,7 @@ class TestDomainRequestAdmin(MockEppLib): self.assertEqual(len(self.mock_client.EMAILS_SENT), 1) # Approve - self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.APPROVED) + self.transition_state_and_send_email(application, DomainRequest.DomainRequestStatus.APPROVED) self.assert_email_is_accurate("Congratulations! Your .gov domain request has been approved.", 1, EMAIL) self.assertEqual(len(self.mock_client.EMAILS_SENT), 2) @@ -824,11 +824,11 @@ class TestDomainRequestAdmin(MockEppLib): User.objects.filter(email=EMAIL).delete() # Create a sample application - application = completed_application(status=DomainRequest.ApplicationStatus.IN_REVIEW) + domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.IN_REVIEW) # Reject for reason REQUESTOR and test email including dynamic organization name self.transition_state_and_send_email( - application, DomainRequest.ApplicationStatus.REJECTED, DomainRequest.RejectionReasons.REQUESTOR + application, DomainRequest.DomainRequestStatus.REJECTED, DomainRequest.RejectionReasons.REQUESTOR ) self.assert_email_is_accurate( "Your domain request was rejected because we don’t believe you’re eligible to request a \n.gov " @@ -839,7 +839,7 @@ class TestDomainRequestAdmin(MockEppLib): self.assertEqual(len(self.mock_client.EMAILS_SENT), 1) # Approve - self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.APPROVED) + self.transition_state_and_send_email(application, DomainRequest.DomainRequestStatus.APPROVED) self.assert_email_is_accurate("Congratulations! Your .gov domain request has been approved.", 1, EMAIL) self.assertEqual(len(self.mock_client.EMAILS_SENT), 2) @@ -853,12 +853,12 @@ class TestDomainRequestAdmin(MockEppLib): User.objects.filter(email=EMAIL).delete() # Create a sample application - application = completed_application(status=DomainRequest.ApplicationStatus.IN_REVIEW) + domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.IN_REVIEW) # Reject for reason SECOND_DOMAIN_REASONING and test email including dynamic organization name self.transition_state_and_send_email( application, - DomainRequest.ApplicationStatus.REJECTED, + DomainRequest.DomainRequestStatus.REJECTED, DomainRequest.RejectionReasons.SECOND_DOMAIN_REASONING, ) self.assert_email_is_accurate( @@ -867,7 +867,7 @@ class TestDomainRequestAdmin(MockEppLib): self.assertEqual(len(self.mock_client.EMAILS_SENT), 1) # Approve - self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.APPROVED) + self.transition_state_and_send_email(application, DomainRequest.DomainRequestStatus.APPROVED) self.assert_email_is_accurate("Congratulations! Your .gov domain request has been approved.", 1, EMAIL) self.assertEqual(len(self.mock_client.EMAILS_SENT), 2) @@ -881,12 +881,12 @@ class TestDomainRequestAdmin(MockEppLib): User.objects.filter(email=EMAIL).delete() # Create a sample application - application = completed_application(status=DomainRequest.ApplicationStatus.IN_REVIEW) + domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.IN_REVIEW) # Reject for reason CONTACTS_OR_ORGANIZATION_LEGITIMACY and test email including dynamic organization name self.transition_state_and_send_email( application, - DomainRequest.ApplicationStatus.REJECTED, + DomainRequest.DomainRequestStatus.REJECTED, DomainRequest.RejectionReasons.CONTACTS_OR_ORGANIZATION_LEGITIMACY, ) self.assert_email_is_accurate( @@ -898,7 +898,7 @@ class TestDomainRequestAdmin(MockEppLib): self.assertEqual(len(self.mock_client.EMAILS_SENT), 1) # Approve - self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.APPROVED) + self.transition_state_and_send_email(application, DomainRequest.DomainRequestStatus.APPROVED) self.assert_email_is_accurate("Congratulations! Your .gov domain request has been approved.", 1, EMAIL) self.assertEqual(len(self.mock_client.EMAILS_SENT), 2) @@ -912,12 +912,12 @@ class TestDomainRequestAdmin(MockEppLib): User.objects.filter(email=EMAIL).delete() # Create a sample application - application = completed_application(status=DomainRequest.ApplicationStatus.IN_REVIEW) + domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.IN_REVIEW) # Reject for reason ORGANIZATION_ELIGIBILITY and test email including dynamic organization name self.transition_state_and_send_email( application, - DomainRequest.ApplicationStatus.REJECTED, + DomainRequest.DomainRequestStatus.REJECTED, DomainRequest.RejectionReasons.ORGANIZATION_ELIGIBILITY, ) self.assert_email_is_accurate( @@ -929,7 +929,7 @@ class TestDomainRequestAdmin(MockEppLib): self.assertEqual(len(self.mock_client.EMAILS_SENT), 1) # Approve - self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.APPROVED) + self.transition_state_and_send_email(application, DomainRequest.DomainRequestStatus.APPROVED) self.assert_email_is_accurate("Congratulations! Your .gov domain request has been approved.", 1, EMAIL) self.assertEqual(len(self.mock_client.EMAILS_SENT), 2) @@ -943,12 +943,12 @@ class TestDomainRequestAdmin(MockEppLib): User.objects.filter(email=EMAIL).delete() # Create a sample application - application = completed_application(status=DomainRequest.ApplicationStatus.IN_REVIEW) + domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.IN_REVIEW) # Reject for reason NAMING_REQUIREMENTS and test email including dynamic organization name self.transition_state_and_send_email( application, - DomainRequest.ApplicationStatus.REJECTED, + DomainRequest.DomainRequestStatus.REJECTED, DomainRequest.RejectionReasons.NAMING_REQUIREMENTS, ) self.assert_email_is_accurate( @@ -957,7 +957,7 @@ class TestDomainRequestAdmin(MockEppLib): self.assertEqual(len(self.mock_client.EMAILS_SENT), 1) # Approve - self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.APPROVED) + self.transition_state_and_send_email(application, DomainRequest.DomainRequestStatus.APPROVED) self.assert_email_is_accurate("Congratulations! Your .gov domain request has been approved.", 1, EMAIL) self.assertEqual(len(self.mock_client.EMAILS_SENT), 2) @@ -971,19 +971,19 @@ class TestDomainRequestAdmin(MockEppLib): User.objects.filter(email=EMAIL).delete() # Create a sample application - application = completed_application(status=DomainRequest.ApplicationStatus.IN_REVIEW) + domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.IN_REVIEW) # Reject for reason NAMING_REQUIREMENTS and test email including dynamic organization name self.transition_state_and_send_email( application, - DomainRequest.ApplicationStatus.REJECTED, + DomainRequest.DomainRequestStatus.REJECTED, DomainRequest.RejectionReasons.OTHER, ) self.assert_email_is_accurate("Choosing a .gov domain name", 0, EMAIL) self.assertEqual(len(self.mock_client.EMAILS_SENT), 1) # Approve - self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.APPROVED) + self.transition_state_and_send_email(application, DomainRequest.DomainRequestStatus.APPROVED) self.assert_email_is_accurate("Congratulations! Your .gov domain request has been approved.", 1, EMAIL) self.assertEqual(len(self.mock_client.EMAILS_SENT), 2) @@ -995,25 +995,25 @@ class TestDomainRequestAdmin(MockEppLib): """ with less_console_noise(): - application = completed_application(status=DomainRequest.ApplicationStatus.APPROVED) + domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.APPROVED) # Create a request object with a superuser - request = self.factory.post("/admin/registrar/DomainRequest/{}/change/".format(application.pk)) + request = self.factory.post("/admin/registrar/DomainRequest/{}/change/".format(domain_request.pk)) request.user = self.superuser with ExitStack() as stack: stack.enter_context(patch.object(messages, "error")) - application.status = DomainRequest.ApplicationStatus.REJECTED + domain_request.status = DomainRequest.DomainRequestStatus.REJECTED - self.admin.save_model(request, application, None, True) + self.admin.save_model(request, domain_request, None, True) messages.error.assert_called_once_with( request, "A rejection reason is required.", ) - application.refresh_from_db() - self.assertEqual(application.status, DomainRequest.ApplicationStatus.APPROVED) + domain_request.refresh_from_db() + self.assertEqual(domain_request.status, DomainRequest.DomainRequestStatus.APPROVED) def test_transition_to_rejected_with_rejection_reason_does_not_trigger_error(self): """ @@ -1023,23 +1023,23 @@ class TestDomainRequestAdmin(MockEppLib): """ with less_console_noise(): - application = completed_application(status=DomainRequest.ApplicationStatus.APPROVED) + domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.APPROVED) # Create a request object with a superuser - request = self.factory.post("/admin/registrar/DomainRequest/{}/change/".format(application.pk)) + request = self.factory.post("/admin/registrar/DomainRequest/{}/change/".format(domain_request.pk)) request.user = self.superuser with ExitStack() as stack: stack.enter_context(patch.object(messages, "error")) - application.status = DomainRequest.ApplicationStatus.REJECTED - application.rejection_reason = DomainRequest.RejectionReasons.CONTACTS_OR_ORGANIZATION_LEGITIMACY + domain_request.status = DomainRequest.DomainRequestStatus.REJECTED + domain_request.rejection_reason = DomainRequest.RejectionReasons.CONTACTS_OR_ORGANIZATION_LEGITIMACY - self.admin.save_model(request, application, None, True) + self.admin.save_model(request, domain_request, None, True) messages.error.assert_not_called() - application.refresh_from_db() - self.assertEqual(application.status, DomainRequest.ApplicationStatus.REJECTED) + domain_request.refresh_from_db() + self.assertEqual(domain_request.status, DomainRequest.DomainRequestStatus.REJECTED) def test_save_model_sends_withdrawn_email(self): """When transitioning to withdrawn on a domain request, @@ -1051,22 +1051,22 @@ class TestDomainRequestAdmin(MockEppLib): User.objects.filter(email=EMAIL).delete() # Create a sample application - application = completed_application(status=DomainRequest.ApplicationStatus.IN_REVIEW) + domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.IN_REVIEW) # Test Submitted Status - self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.WITHDRAWN) + self.transition_state_and_send_email(application, DomainRequest.DomainRequestStatus.WITHDRAWN) self.assert_email_is_accurate( "Your .gov domain request has been withdrawn and will not be reviewed by our team.", 0, EMAIL ) self.assertEqual(len(self.mock_client.EMAILS_SENT), 1) # Test Withdrawn Status - self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.SUBMITTED) + self.transition_state_and_send_email(application, DomainRequest.DomainRequestStatus.SUBMITTED) self.assert_email_is_accurate("We received your .gov domain request.", 1, EMAIL) self.assertEqual(len(self.mock_client.EMAILS_SENT), 2) # Test Submitted Status Again (No new email should be sent) - self.transition_state_and_send_email(application, DomainRequest.ApplicationStatus.WITHDRAWN) + self.transition_state_and_send_email(application, DomainRequest.DomainRequestStatus.WITHDRAWN) self.assertEqual(len(self.mock_client.EMAILS_SENT), 3) def test_save_model_sets_approved_domain(self): @@ -1076,20 +1076,20 @@ class TestDomainRequestAdmin(MockEppLib): User.objects.filter(email=EMAIL).delete() # Create a sample application - application = completed_application(status=DomainRequest.ApplicationStatus.IN_REVIEW) + domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.IN_REVIEW) # Create a mock request - request = self.factory.post("/admin/registrar/DomainRequest/{}/change/".format(application.pk)) + request = self.factory.post("/admin/registrar/DomainRequest/{}/change/".format(domain_request.pk)) with boto3_mocking.clients.handler_for("sesv2", self.mock_client): - # Modify the application's property - application.status = DomainRequest.ApplicationStatus.APPROVED + # Modify the domain request's property + domain_request.status = DomainRequest.DomainRequestStatus.APPROVED # Use the model admin's save_model method - self.admin.save_model(request, application, form=None, change=True) + self.admin.save_model(request, domain_request, form=None, change=True) # Test that approved domain exists and equals requested domain - self.assertEqual(application.requested_domain.name, application.approved_domain.name) + self.assertEqual(domain_request.requested_domain.name, domain_request.approved_domain.name) def test_save_model_sets_restricted_status_on_user(self): with less_console_noise(): @@ -1098,32 +1098,32 @@ class TestDomainRequestAdmin(MockEppLib): User.objects.filter(email=EMAIL).delete() # Create a sample application - application = completed_application(status=DomainRequest.ApplicationStatus.IN_REVIEW) + domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.IN_REVIEW) # Create a mock request - request = self.factory.post("/admin/registrar/DomainRequest/{}/change/".format(application.pk)) + request = self.factory.post("/admin/registrar/DomainRequest/{}/change/".format(domain_request.pk)) with boto3_mocking.clients.handler_for("sesv2", self.mock_client): - # Modify the application's property - application.status = DomainRequest.ApplicationStatus.INELIGIBLE + # Modify the domain request's property + domain_request.status = DomainRequest.DomainRequestStatus.INELIGIBLE # Use the model admin's save_model method - self.admin.save_model(request, application, form=None, change=True) + self.admin.save_model(request, domain_request, form=None, change=True) # Test that approved domain exists and equals requested domain - self.assertEqual(application.creator.status, "restricted") + self.assertEqual(domain_request.creator.status, "restricted") def test_readonly_when_restricted_creator(self): with less_console_noise(): - application = completed_application(status=DomainRequest.ApplicationStatus.IN_REVIEW) + domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.IN_REVIEW) with boto3_mocking.clients.handler_for("sesv2", self.mock_client): - application.creator.status = User.RESTRICTED - application.creator.save() + domain_request.creator.status = User.RESTRICTED + domain_request.creator.save() request = self.factory.get("/") request.user = self.superuser - readonly_fields = self.admin.get_readonly_fields(request, application) + readonly_fields = self.admin.get_readonly_fields(request, domain_request) expected_fields = [ "id", @@ -1201,10 +1201,10 @@ class TestDomainRequestAdmin(MockEppLib): def test_saving_when_restricted_creator(self): with less_console_noise(): # Create an instance of the model - application = completed_application(status=DomainRequest.ApplicationStatus.IN_REVIEW) + domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.IN_REVIEW) with boto3_mocking.clients.handler_for("sesv2", self.mock_client): - application.creator.status = User.RESTRICTED - application.creator.save() + domain_request.creator.status = User.RESTRICTED + domain_request.creator.save() # Create a request object with a superuser request = self.factory.get("/") @@ -1212,7 +1212,7 @@ class TestDomainRequestAdmin(MockEppLib): with patch("django.contrib.messages.error") as mock_error: # Simulate saving the model - self.admin.save_model(request, application, None, False) + self.admin.save_model(request, domain_request, None, False) # Assert that the error message was called with the correct argument mock_error.assert_called_once_with( @@ -1221,27 +1221,27 @@ class TestDomainRequestAdmin(MockEppLib): ) # Assert that the status has not changed - self.assertEqual(application.status, DomainRequest.ApplicationStatus.IN_REVIEW) + self.assertEqual(domain_request.status, DomainRequest.DomainRequestStatus.IN_REVIEW) def test_change_view_with_restricted_creator(self): with less_console_noise(): # Create an instance of the model - application = completed_application(status=DomainRequest.ApplicationStatus.IN_REVIEW) + domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.IN_REVIEW) with boto3_mocking.clients.handler_for("sesv2", self.mock_client): - application.creator.status = User.RESTRICTED - application.creator.save() + domain_request.creator.status = User.RESTRICTED + domain_request.creator.save() with patch("django.contrib.messages.warning") as mock_warning: # Create a request object with a superuser - request = self.factory.get("/admin/your_app/DomainRequest/{}/change/".format(application.pk)) + request = self.factory.get("/admin/your_app/DomainRequest/{}/change/".format(domain_request.pk)) request.user = self.superuser - self.admin.display_restricted_warning(request, application) + self.admin.display_restricted_warning(request, domain_request) # Assert that the error message was called with the correct argument mock_warning.assert_called_once_with( request, - "Cannot edit an application with a restricted creator.", + "Cannot edit a domain request with a restricted creator.", ) def trigger_saving_approved_to_another_state(self, domain_is_active, another_state, rejection_reason=None): @@ -1253,14 +1253,14 @@ class TestDomainRequestAdmin(MockEppLib): with less_console_noise(): # Create an instance of the model - application = completed_application(status=DomainRequest.ApplicationStatus.APPROVED) - domain = Domain.objects.create(name=application.requested_domain.name) + domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.APPROVED) + domain = Domain.objects.create(name=domain_request.requested_domain.name) domain_information = DomainInformation.objects.create(creator=self.superuser, domain=domain) - application.approved_domain = domain - application.save() + domain_request.approved_domain = domain + domain_request.save() # Create a request object with a superuser - request = self.factory.post("/admin/registrar/DomainRequest/{}/change/".format(application.pk)) + request = self.factory.post("/admin/registrar/DomainRequest/{}/change/".format(domain_request.pk)) request.user = self.superuser # Define a custom implementation for is_active @@ -1273,10 +1273,10 @@ class TestDomainRequestAdmin(MockEppLib): stack.enter_context(patch.object(Domain, "is_active", custom_is_active)) stack.enter_context(patch.object(messages, "error")) - application.status = another_state - application.rejection_reason = rejection_reason + domain_request.status = another_state + domain_request.rejection_reason = rejection_reason - self.admin.save_model(request, application, None, True) + self.admin.save_model(request, domain_request, None, True) # Assert that the error message was called with the correct argument if domain_is_active: @@ -1288,7 +1288,7 @@ class TestDomainRequestAdmin(MockEppLib): # Assert that the error message was never called messages.error.assert_not_called() - self.assertEqual(application.approved_domain, None) + self.assertEqual(domain_request.approved_domain, None) # Assert that Domain got Deleted with self.assertRaises(Domain.DoesNotExist): @@ -1299,32 +1299,32 @@ class TestDomainRequestAdmin(MockEppLib): domain_information.refresh_from_db() def test_error_when_saving_approved_to_in_review_and_domain_is_active(self): - self.trigger_saving_approved_to_another_state(True, DomainRequest.ApplicationStatus.IN_REVIEW) + self.trigger_saving_approved_to_another_state(True, DomainRequest.DomainRequestStatus.IN_REVIEW) def test_error_when_saving_approved_to_action_needed_and_domain_is_active(self): - self.trigger_saving_approved_to_another_state(True, DomainRequest.ApplicationStatus.ACTION_NEEDED) + self.trigger_saving_approved_to_another_state(True, DomainRequest.DomainRequestStatus.ACTION_NEEDED) def test_error_when_saving_approved_to_rejected_and_domain_is_active(self): - self.trigger_saving_approved_to_another_state(True, DomainRequest.ApplicationStatus.REJECTED) + self.trigger_saving_approved_to_another_state(True, DomainRequest.DomainRequestStatus.REJECTED) def test_error_when_saving_approved_to_ineligible_and_domain_is_active(self): - self.trigger_saving_approved_to_another_state(True, DomainRequest.ApplicationStatus.INELIGIBLE) + self.trigger_saving_approved_to_another_state(True, DomainRequest.DomainRequestStatus.INELIGIBLE) def test_side_effects_when_saving_approved_to_in_review(self): - self.trigger_saving_approved_to_another_state(False, DomainRequest.ApplicationStatus.IN_REVIEW) + self.trigger_saving_approved_to_another_state(False, DomainRequest.DomainRequestStatus.IN_REVIEW) def test_side_effects_when_saving_approved_to_action_needed(self): - self.trigger_saving_approved_to_another_state(False, DomainRequest.ApplicationStatus.ACTION_NEEDED) + self.trigger_saving_approved_to_another_state(False, DomainRequest.DomainRequestStatus.ACTION_NEEDED) def test_side_effects_when_saving_approved_to_rejected(self): self.trigger_saving_approved_to_another_state( False, - DomainRequest.ApplicationStatus.REJECTED, + DomainRequest.DomainRequestStatus.REJECTED, DomainRequest.RejectionReasons.CONTACTS_OR_ORGANIZATION_LEGITIMACY, ) def test_side_effects_when_saving_approved_to_ineligible(self): - self.trigger_saving_approved_to_another_state(False, DomainRequest.ApplicationStatus.INELIGIBLE) + self.trigger_saving_approved_to_another_state(False, DomainRequest.DomainRequestStatus.INELIGIBLE) def test_has_correct_filters(self): """ @@ -1362,7 +1362,7 @@ class TestDomainRequestAdmin(MockEppLib): """ with less_console_noise(): # Creates a list of DomainRequests in scrambled order - multiple_unalphabetical_domain_objects("application") + multiple_unalphabetical_domain_objects("domain_request") request = self.factory.get("/") request.user = self.superuser @@ -1395,8 +1395,8 @@ class TestDomainRequestAdmin(MockEppLib): with less_console_noise(): # Create a mock DomainRequest object, with a fake investigator - application: DomainRequest = generic_domain_object("application", "SomeGuy") - investigator_user = User.objects.filter(username=application.investigator.username).get() + application: DomainRequest = generic_domain_object("domain_request", "SomeGuy") + investigator_user = User.objects.filter(username=domain_request.investigator.username).get() investigator_user.is_staff = True investigator_user.save() @@ -1440,21 +1440,21 @@ class TestDomainRequestAdmin(MockEppLib): with less_console_noise(): # Create a mock DomainRequest object, with a fake investigator - application: DomainRequest = generic_domain_object("application", "SomeGuy") - investigator_user = User.objects.filter(username=application.investigator.username).get() + application: DomainRequest = generic_domain_object("domain_request", "SomeGuy") + investigator_user = User.objects.filter(username=domain_request.investigator.username).get() investigator_user.is_staff = True investigator_user.save() # Create a mock DomainRequest object, with a user that is not staff - application_2: DomainRequest = generic_domain_object("application", "SomeOtherGuy") - investigator_user_2 = User.objects.filter(username=application_2.investigator.username).get() + domain_request_2: DomainRequest = generic_domain_object("domain_request", "SomeOtherGuy") + investigator_user_2 = User.objects.filter(username=domain_request_2.investigator.username).get() investigator_user_2.is_staff = False investigator_user_2.save() p = "userpass" self.client.login(username="staffuser", password=p) - request = self.factory.post("/admin/registrar/DomainRequest/{}/change/".format(application.pk)) + request = self.factory.post("/admin/registrar/DomainRequest/{}/change/".format(domain_request.pk)) # Get the actual field from the model's meta information investigator_field = DomainRequest._meta.get_field("investigator") @@ -1464,18 +1464,18 @@ class TestDomainRequestAdmin(MockEppLib): expected_dropdown = list(User.objects.filter(is_staff=True).order_by(*sorted_fields)) # Grab the current dropdown. We do an API call to autocomplete to get this info. - application_queryset = self.admin.formfield_for_foreignkey(investigator_field, request).queryset + domain_request_queryset = self.admin.formfield_for_foreignkey(investigator_field, request).queryset user_request = self.factory.post( "/admin/autocomplete/?app_label=registrar&model_name=DomainRequest&field_name=investigator" ) user_admin = MyUserAdmin(User, self.site) - user_queryset = user_admin.get_search_results(user_request, application_queryset, None)[0] + user_queryset = user_admin.get_search_results(user_request, domain_request_queryset, None)[0] current_dropdown = list(user_queryset) self.assertEqual(expected_dropdown, current_dropdown) # Non staff users should not be in the list - self.assertNotIn(application_2, current_dropdown) + self.assertNotIn(domain_request_2, current_dropdown) def test_investigator_list_is_alphabetically_sorted(self): """ @@ -1484,19 +1484,19 @@ class TestDomainRequestAdmin(MockEppLib): """ with less_console_noise(): # Create a mock DomainRequest object, with a fake investigator - application: DomainRequest = generic_domain_object("application", "SomeGuy") - investigator_user = User.objects.filter(username=application.investigator.username).get() + application: DomainRequest = generic_domain_object("domain_request", "SomeGuy") + investigator_user = User.objects.filter(username=domain_request.investigator.username).get() investigator_user.is_staff = True investigator_user.save() - application_2: DomainRequest = generic_domain_object("application", "AGuy") - investigator_user_2 = User.objects.filter(username=application_2.investigator.username).get() + domain_request_2: DomainRequest = generic_domain_object("domain_request", "AGuy") + investigator_user_2 = User.objects.filter(username=domain_request_2.investigator.username).get() investigator_user_2.first_name = "AGuy" investigator_user_2.is_staff = True investigator_user_2.save() - application_3: DomainRequest = generic_domain_object("application", "FinalGuy") - investigator_user_3 = User.objects.filter(username=application_3.investigator.username).get() + domain_request_3: DomainRequest = generic_domain_object("domain_request", "FinalGuy") + investigator_user_3 = User.objects.filter(username=domain_request_3.investigator.username).get() investigator_user_3.first_name = "FinalGuy" investigator_user_3.is_staff = True investigator_user_3.save() @@ -1946,18 +1946,18 @@ class AuditedAdminTest(TestCase): def test_alphabetically_sorted_domain_request_investigator(self): """Tests if the investigator field is alphabetically sorted by mimicking the call event flow""" - # Creates multiple domain applications - review status does not matter - applications = multiple_unalphabetical_domain_objects("application") + # Creates multiple domain requests - review status does not matter + applications = multiple_unalphabetical_domain_objects("domain_request") # Create a mock request - application_request = self.factory.post( + domain_request_request = self.factory.post( "/admin/registrar/DomainRequest/{}/change/".format(applications[0].pk) ) - # Get the formfield data from the application page - application_admin = AuditedAdmin(DomainRequest, self.site) + # Get the formfield data from the domain request page + domain_request_admin = AuditedAdmin(DomainRequest, self.site) field = DomainRequest.investigator.field - application_queryset = application_admin.formfield_for_foreignkey(field, application_request).queryset + domain_request_queryset = domain_request_admin.formfield_for_foreignkey(field, domain_request_request).queryset request = self.factory.post( "/admin/autocomplete/?app_label=registrar&model_name=DomainRequest&field_name=investigator" @@ -1968,7 +1968,7 @@ class AuditedAdminTest(TestCase): # Grab the data returned from get search results admin = MyUserAdmin(User, self.site) - search_queryset = admin.get_search_results(request, application_queryset, None)[0] + search_queryset = admin.get_search_results(request, domain_request_queryset, None)[0] current_sort_order = list(search_queryset) self.assertEqual( @@ -1988,8 +1988,8 @@ class AuditedAdminTest(TestCase): DomainRequest.requested_domain.field, ] - # Creates multiple domain applications - review status does not matter - applications = multiple_unalphabetical_domain_objects("application") + # Creates multiple domain requests - review status does not matter + applications = multiple_unalphabetical_domain_objects("domain_request") # Create a mock request request = self.factory.post("/admin/registrar/DomainRequest/{}/change/".format(applications[0].pk)) @@ -2045,7 +2045,7 @@ class AuditedAdminTest(TestCase): (DomainInformation.domain.field, ["name"]), (DomainInformation.domain_request.field, ["requested_domain__name"]), ] - # Creates multiple domain applications - review status does not matter + # Creates multiple domain requests - review status does not matter applications = multiple_unalphabetical_domain_objects("information") # Create a mock request @@ -2100,7 +2100,7 @@ class AuditedAdminTest(TestCase): with less_console_noise(): tested_fields = [DomainInvitation.domain.field] - # Creates multiple domain applications - review status does not matter + # Creates multiple domain requests - review status does not matter applications = multiple_unalphabetical_domain_objects("invitation") # Create a mock request @@ -2328,10 +2328,10 @@ class ContactAdminTest(TestCase): contact, _ = Contact.objects.get_or_create(user=self.staffuser) # join it to 4 domain requests. The 5th join will be a user. - application1 = completed_application(submitter=contact, name="city1.gov") - application2 = completed_application(submitter=contact, name="city2.gov") - application3 = completed_application(submitter=contact, name="city3.gov") - application4 = completed_application(submitter=contact, name="city4.gov") + application1 = completed_domain_request(submitter=contact, name="city1.gov") + application2 = completed_domain_request(submitter=contact, name="city2.gov") + application3 = completed_domain_request(submitter=contact, name="city3.gov") + application4 = completed_domain_request(submitter=contact, name="city4.gov") with patch("django.contrib.messages.warning") as mock_warning: # Use the test client to simulate the request @@ -2363,11 +2363,11 @@ class ContactAdminTest(TestCase): # Create an instance of the model # join it to 5 domain requests. The 6th join will be a user. contact, _ = Contact.objects.get_or_create(user=self.staffuser) - application1 = completed_application(submitter=contact, name="city1.gov") - application2 = completed_application(submitter=contact, name="city2.gov") - application3 = completed_application(submitter=contact, name="city3.gov") - application4 = completed_application(submitter=contact, name="city4.gov") - application5 = completed_application(submitter=contact, name="city5.gov") + application1 = completed_domain_request(submitter=contact, name="city1.gov") + application2 = completed_domain_request(submitter=contact, name="city2.gov") + application3 = completed_domain_request(submitter=contact, name="city3.gov") + application4 = completed_domain_request(submitter=contact, name="city4.gov") + application5 = completed_domain_request(submitter=contact, name="city5.gov") with patch("django.contrib.messages.warning") as mock_warning: # Use the test client to simulate the request response = self.client.get(reverse("admin:registrar_contact_change", args=[contact.pk])) diff --git a/src/registrar/tests/test_emails.py b/src/registrar/tests/test_emails.py index f2a94a186..a4807545b 100644 --- a/src/registrar/tests/test_emails.py +++ b/src/registrar/tests/test_emails.py @@ -3,7 +3,7 @@ from unittest.mock import MagicMock from django.test import TestCase -from .common import completed_application, less_console_noise +from .common import completed_domain_request, less_console_noise import boto3_mocking # type: ignore @@ -17,11 +17,11 @@ class TestEmails(TestCase): @boto3_mocking.patching def test_submission_confirmation(self): """Submission confirmation email works.""" - application = completed_application() + domain_request = completed_domain_request() with boto3_mocking.clients.handler_for("sesv2", self.mock_client_class): with less_console_noise(): - application.submit() + domain_request.submit() # check that an email was sent self.assertTrue(self.mock_client.send_email.called) @@ -55,10 +55,10 @@ class TestEmails(TestCase): @boto3_mocking.patching def test_submission_confirmation_no_current_website_spacing(self): """Test line spacing without current_website.""" - application = completed_application(has_current_website=False) + domain_request = completed_domain_request(has_current_website=False) with boto3_mocking.clients.handler_for("sesv2", self.mock_client_class): with less_console_noise(): - application.submit() + domain_request.submit() _, kwargs = self.mock_client.send_email.call_args body = kwargs["Content"]["Simple"]["Body"]["Text"]["Data"] self.assertNotIn("Current websites:", body) @@ -68,10 +68,10 @@ class TestEmails(TestCase): @boto3_mocking.patching def test_submission_confirmation_current_website_spacing(self): """Test line spacing with current_website.""" - application = completed_application(has_current_website=True) + domain_request = completed_domain_request(has_current_website=True) with boto3_mocking.clients.handler_for("sesv2", self.mock_client_class): with less_console_noise(): - application.submit() + domain_request.submit() _, kwargs = self.mock_client.send_email.call_args body = kwargs["Content"]["Simple"]["Body"]["Text"]["Data"] self.assertIn("Current websites:", body) @@ -82,10 +82,10 @@ class TestEmails(TestCase): @boto3_mocking.patching def test_submission_confirmation_other_contacts_spacing(self): """Test line spacing with other contacts.""" - application = completed_application(has_other_contacts=True) + domain_request = completed_domain_request(has_other_contacts=True) with boto3_mocking.clients.handler_for("sesv2", self.mock_client_class): with less_console_noise(): - application.submit() + domain_request.submit() _, kwargs = self.mock_client.send_email.call_args body = kwargs["Content"]["Simple"]["Body"]["Text"]["Data"] self.assertIn("Other employees from your organization:", body) @@ -96,10 +96,10 @@ class TestEmails(TestCase): @boto3_mocking.patching def test_submission_confirmation_no_other_contacts_spacing(self): """Test line spacing without other contacts.""" - application = completed_application(has_other_contacts=False) + domain_request = completed_domain_request(has_other_contacts=False) with boto3_mocking.clients.handler_for("sesv2", self.mock_client_class): with less_console_noise(): - application.submit() + domain_request.submit() _, kwargs = self.mock_client.send_email.call_args body = kwargs["Content"]["Simple"]["Body"]["Text"]["Data"] # spacing should be right between adjacent elements @@ -109,10 +109,10 @@ class TestEmails(TestCase): @boto3_mocking.patching def test_submission_confirmation_alternative_govdomain_spacing(self): """Test line spacing with alternative .gov domain.""" - application = completed_application(has_alternative_gov_domain=True) + domain_request = completed_domain_request(has_alternative_gov_domain=True) with boto3_mocking.clients.handler_for("sesv2", self.mock_client_class): with less_console_noise(): - application.submit() + domain_request.submit() _, kwargs = self.mock_client.send_email.call_args body = kwargs["Content"]["Simple"]["Body"]["Text"]["Data"] self.assertIn("city1.gov", body) @@ -122,10 +122,10 @@ class TestEmails(TestCase): @boto3_mocking.patching def test_submission_confirmation_no_alternative_govdomain_spacing(self): """Test line spacing without alternative .gov domain.""" - application = completed_application(has_alternative_gov_domain=False) + domain_request = completed_domain_request(has_alternative_gov_domain=False) with boto3_mocking.clients.handler_for("sesv2", self.mock_client_class): with less_console_noise(): - application.submit() + domain_request.submit() _, kwargs = self.mock_client.send_email.call_args body = kwargs["Content"]["Simple"]["Body"]["Text"]["Data"] self.assertNotIn("city1.gov", body) @@ -135,10 +135,10 @@ class TestEmails(TestCase): @boto3_mocking.patching def test_submission_confirmation_about_your_organization_spacing(self): """Test line spacing with about your organization.""" - application = completed_application(has_about_your_organization=True) + domain_request = completed_domain_request(has_about_your_organization=True) with boto3_mocking.clients.handler_for("sesv2", self.mock_client_class): with less_console_noise(): - application.submit() + domain_request.submit() _, kwargs = self.mock_client.send_email.call_args body = kwargs["Content"]["Simple"]["Body"]["Text"]["Data"] self.assertIn("About your organization:", body) @@ -148,10 +148,10 @@ class TestEmails(TestCase): @boto3_mocking.patching def test_submission_confirmation_no_about_your_organization_spacing(self): """Test line spacing without about your organization.""" - application = completed_application(has_about_your_organization=False) + domain_request = completed_domain_request(has_about_your_organization=False) with boto3_mocking.clients.handler_for("sesv2", self.mock_client_class): with less_console_noise(): - application.submit() + domain_request.submit() _, kwargs = self.mock_client.send_email.call_args body = kwargs["Content"]["Simple"]["Body"]["Text"]["Data"] self.assertNotIn("About your organization:", body) @@ -161,10 +161,10 @@ class TestEmails(TestCase): @boto3_mocking.patching def test_submission_confirmation_anything_else_spacing(self): """Test line spacing with anything else.""" - application = completed_application(has_anything_else=True) + domain_request = completed_domain_request(has_anything_else=True) with boto3_mocking.clients.handler_for("sesv2", self.mock_client_class): with less_console_noise(): - application.submit() + domain_request.submit() _, kwargs = self.mock_client.send_email.call_args body = kwargs["Content"]["Simple"]["Body"]["Text"]["Data"] # spacing should be right between adjacent elements @@ -173,10 +173,10 @@ class TestEmails(TestCase): @boto3_mocking.patching def test_submission_confirmation_no_anything_else_spacing(self): """Test line spacing without anything else.""" - application = completed_application(has_anything_else=False) + domain_request = completed_domain_request(has_anything_else=False) with boto3_mocking.clients.handler_for("sesv2", self.mock_client_class): with less_console_noise(): - application.submit() + domain_request.submit() _, kwargs = self.mock_client.send_email.call_args body = kwargs["Content"]["Simple"]["Body"]["Text"]["Data"] self.assertNotIn("Anything else", body) diff --git a/src/registrar/tests/test_forms.py b/src/registrar/tests/test_forms.py index c9dd3c4f0..8f85631a9 100644 --- a/src/registrar/tests/test_forms.py +++ b/src/registrar/tests/test_forms.py @@ -4,7 +4,7 @@ import json from django.test import TestCase, RequestFactory from api.views import available -from registrar.forms.application_wizard import ( +from registrar.forms.domain_request_wizard import ( AlternativeDomainForm, CurrentSitesForm, DotGovDomainForm, diff --git a/src/registrar/tests/test_models.py b/src/registrar/tests/test_models.py index 90a3d924a..5b151768f 100644 --- a/src/registrar/tests/test_models.py +++ b/src/registrar/tests/test_models.py @@ -17,7 +17,7 @@ from registrar.models import ( import boto3_mocking from registrar.models.transition_domain import TransitionDomain from registrar.models.verified_by_staff import VerifiedByStaff # type: ignore -from .common import MockSESClient, less_console_noise, completed_application +from .common import MockSESClient, less_console_noise, completed_domain_request from django_fsm import TransitionNotAllowed @@ -27,29 +27,29 @@ from django_fsm import TransitionNotAllowed @boto3_mocking.patching class TestDomainRequest(TestCase): def setUp(self): - self.started_application = completed_application( - status=DomainRequest.ApplicationStatus.STARTED, name="started.gov" + self.started_domain_request = completed_domain_request( + status=DomainRequest.DomainRequestStatus.STARTED, name="started.gov" ) - self.submitted_application = completed_application( - status=DomainRequest.ApplicationStatus.SUBMITTED, name="submitted.gov" + self.submitted_domain_request = completed_domain_request( + status=DomainRequest.DomainRequestStatus.SUBMITTED, name="submitted.gov" ) - self.in_review_application = completed_application( - status=DomainRequest.ApplicationStatus.IN_REVIEW, name="in-review.gov" + self.in_review_domain_request = completed_domain_request( + status=DomainRequest.DomainRequestStatus.IN_REVIEW, name="in-review.gov" ) - self.action_needed_application = completed_application( - status=DomainRequest.ApplicationStatus.ACTION_NEEDED, name="action-needed.gov" + self.action_needed_domain_request = completed_domain_request( + status=DomainRequest.DomainRequestStatus.ACTION_NEEDED, name="action-needed.gov" ) - self.approved_application = completed_application( - status=DomainRequest.ApplicationStatus.APPROVED, name="approved.gov" + self.approved_domain_request = completed_domain_request( + status=DomainRequest.DomainRequestStatus.APPROVED, name="approved.gov" ) - self.withdrawn_application = completed_application( - status=DomainRequest.ApplicationStatus.WITHDRAWN, name="withdrawn.gov" + self.withdrawn_domain_request = completed_domain_request( + status=DomainRequest.DomainRequestStatus.WITHDRAWN, name="withdrawn.gov" ) - self.rejected_application = completed_application( - status=DomainRequest.ApplicationStatus.REJECTED, name="rejected.gov" + self.rejected_domain_request = completed_domain_request( + status=DomainRequest.DomainRequestStatus.REJECTED, name="rejected.gov" ) - self.ineligible_application = completed_application( - status=DomainRequest.ApplicationStatus.INELIGIBLE, name="ineligible.gov" + self.ineligible_domain_request = completed_domain_request( + status=DomainRequest.DomainRequestStatus.INELIGIBLE, name="ineligible.gov" ) self.mock_client = MockSESClient() @@ -75,8 +75,8 @@ class TestDomainRequest(TestCase): """Can create with just a creator.""" with less_console_noise(): user, _ = User.objects.get_or_create(username="testy") - application = DomainRequest.objects.create(creator=user) - self.assertEqual(application.status, DomainRequest.ApplicationStatus.STARTED) + domain_request = DomainRequest.objects.create(creator=user) + self.assertEqual(domain_request.status, DomainRequest.DomainRequestStatus.STARTED) def test_full_create(self): """Can create with all fields.""" @@ -86,7 +86,7 @@ class TestDomainRequest(TestCase): com_website, _ = Website.objects.get_or_create(website="igorville.com") gov_website, _ = Website.objects.get_or_create(website="igorville.gov") domain, _ = DraftDomain.objects.get_or_create(name="igorville.gov") - application = DomainRequest.objects.create( + domain_request = DomainRequest.objects.create( creator=user, investigator=user, organization_type=DomainRequest.OrganizationChoices.FEDERAL, @@ -104,10 +104,10 @@ class TestDomainRequest(TestCase): anything_else="All of Igorville loves the dotgov program.", is_policy_acknowledged=True, ) - application.current_websites.add(com_website) - application.alternative_domains.add(gov_website) - application.other_contacts.add(contact) - application.save() + domain_request.current_websites.add(com_website) + domain_request.alternative_domains.add(gov_website) + domain_request.other_contacts.add(contact) + domain_request.save() def test_domain_info(self): """Can create domain info with all fields.""" @@ -140,28 +140,28 @@ class TestDomainRequest(TestCase): def test_status_fsm_submit_fail(self): with less_console_noise(): user, _ = User.objects.get_or_create(username="testy") - application = DomainRequest.objects.create(creator=user) + domain_request = DomainRequest.objects.create(creator=user) with boto3_mocking.clients.handler_for("sesv2", self.mock_client): with less_console_noise(): with self.assertRaises(ValueError): - # can't submit an application with a null domain name - application.submit() + # can't submit a domain request with a null domain name + domain_request.submit() def test_status_fsm_submit_succeed(self): with less_console_noise(): user, _ = User.objects.get_or_create(username="testy") site = DraftDomain.objects.create(name="igorville.gov") - application = DomainRequest.objects.create(creator=user, requested_domain=site) + domain_request = DomainRequest.objects.create(creator=user, requested_domain=site) # no submitter email so this emits a log warning with boto3_mocking.clients.handler_for("sesv2", self.mock_client): with less_console_noise(): - application.submit() - self.assertEqual(application.status, application.ApplicationStatus.SUBMITTED) + domain_request.submit() + self.assertEqual(domain_request.status, domain_request.DomainRequestStatus.SUBMITTED) - def check_email_sent(self, application, msg, action, expected_count): + def check_email_sent(self, domain_request, msg, action, expected_count): """Check if an email was sent after performing an action.""" with self.subTest(msg=msg, action=action): @@ -180,43 +180,43 @@ class TestDomainRequest(TestCase): self.assertEqual(len(sent_emails), expected_count) def test_submit_from_started_sends_email(self): - msg = "Create an application and submit it and see if email was sent." - application = completed_application() + msg = "Create a domain request and submit it and see if email was sent." + domain_request = completed_domain_request() self.check_email_sent(application, msg, "submit", 1) def test_submit_from_withdrawn_sends_email(self): msg = "Create a withdrawn application and submit it and see if email was sent." - application = completed_application(status=DomainRequest.ApplicationStatus.WITHDRAWN) + domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.WITHDRAWN) self.check_email_sent(application, msg, "submit", 1) def test_submit_from_action_needed_does_not_send_email(self): - msg = "Create an application with ACTION_NEEDED status and submit it, check if email was not sent." - application = completed_application(status=DomainRequest.ApplicationStatus.ACTION_NEEDED) + msg = "Create a domain request with ACTION_NEEDED status and submit it, check if email was not sent." + domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.ACTION_NEEDED) self.check_email_sent(application, msg, "submit", 0) def test_submit_from_in_review_does_not_send_email(self): msg = "Create a withdrawn application and submit it and see if email was sent." - application = completed_application(status=DomainRequest.ApplicationStatus.IN_REVIEW) + domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.IN_REVIEW) self.check_email_sent(application, msg, "submit", 0) def test_approve_sends_email(self): - msg = "Create an application and approve it and see if email was sent." - application = completed_application(status=DomainRequest.ApplicationStatus.IN_REVIEW) + msg = "Create a domain request and approve it and see if email was sent." + domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.IN_REVIEW) self.check_email_sent(application, msg, "approve", 1) def test_withdraw_sends_email(self): - msg = "Create an application and withdraw it and see if email was sent." - application = completed_application(status=DomainRequest.ApplicationStatus.IN_REVIEW) + msg = "Create a domain request and withdraw it and see if email was sent." + domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.IN_REVIEW) self.check_email_sent(application, msg, "withdraw", 1) def test_reject_sends_email(self): - msg = "Create an application and reject it and see if email was sent." - application = completed_application(status=DomainRequest.ApplicationStatus.APPROVED) + msg = "Create a domain request and reject it and see if email was sent." + domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.APPROVED) self.check_email_sent(application, msg, "reject", 1) def test_reject_with_prejudice_does_not_send_email(self): - msg = "Create an application and reject it with prejudice and see if email was sent." - application = completed_application(status=DomainRequest.ApplicationStatus.APPROVED) + msg = "Create a domain request and reject it with prejudice and see if email was sent." + domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.APPROVED) self.check_email_sent(application, msg, "reject_with_prejudice", 0) def test_submit_transition_allowed(self): @@ -224,10 +224,10 @@ class TestDomainRequest(TestCase): Test that calling submit from allowable statuses does raises TransitionNotAllowed. """ test_cases = [ - (self.started_application, TransitionNotAllowed), - (self.in_review_application, TransitionNotAllowed), - (self.action_needed_application, TransitionNotAllowed), - (self.withdrawn_application, TransitionNotAllowed), + (self.started_domain_request, TransitionNotAllowed), + (self.in_review_domain_request, TransitionNotAllowed), + (self.action_needed_domain_request, TransitionNotAllowed), + (self.withdrawn_domain_request, TransitionNotAllowed), ] with boto3_mocking.clients.handler_for("sesv2", self.mock_client): @@ -235,7 +235,7 @@ class TestDomainRequest(TestCase): for application, exception_type in test_cases: with self.subTest(application=application, exception_type=exception_type): try: - application.submit() + domain_request.submit() except TransitionNotAllowed: self.fail("TransitionNotAllowed was raised, but it was not expected.") @@ -244,10 +244,10 @@ class TestDomainRequest(TestCase): Test that calling submit against transition rules raises TransitionNotAllowed. """ test_cases = [ - (self.submitted_application, TransitionNotAllowed), - (self.approved_application, TransitionNotAllowed), - (self.rejected_application, TransitionNotAllowed), - (self.ineligible_application, TransitionNotAllowed), + (self.submitted_domain_request, TransitionNotAllowed), + (self.approved_domain_request, TransitionNotAllowed), + (self.rejected_domain_request, TransitionNotAllowed), + (self.ineligible_domain_request, TransitionNotAllowed), ] with boto3_mocking.clients.handler_for("sesv2", self.mock_client): @@ -255,18 +255,18 @@ class TestDomainRequest(TestCase): for application, exception_type in test_cases: with self.subTest(application=application, exception_type=exception_type): with self.assertRaises(exception_type): - application.submit() + domain_request.submit() def test_in_review_transition_allowed(self): """ Test that calling in_review from allowable statuses does raises TransitionNotAllowed. """ test_cases = [ - (self.submitted_application, TransitionNotAllowed), - (self.action_needed_application, TransitionNotAllowed), - (self.approved_application, TransitionNotAllowed), - (self.rejected_application, TransitionNotAllowed), - (self.ineligible_application, TransitionNotAllowed), + (self.submitted_domain_request, TransitionNotAllowed), + (self.action_needed_domain_request, TransitionNotAllowed), + (self.approved_domain_request, TransitionNotAllowed), + (self.rejected_domain_request, TransitionNotAllowed), + (self.ineligible_domain_request, TransitionNotAllowed), ] with boto3_mocking.clients.handler_for("sesv2", self.mock_client): @@ -274,7 +274,7 @@ class TestDomainRequest(TestCase): for application, exception_type in test_cases: with self.subTest(application=application, exception_type=exception_type): try: - application.in_review() + domain_request.in_review() except TransitionNotAllowed: self.fail("TransitionNotAllowed was raised, but it was not expected.") @@ -283,9 +283,9 @@ class TestDomainRequest(TestCase): Test that calling in_review against transition rules raises TransitionNotAllowed. """ test_cases = [ - (self.started_application, TransitionNotAllowed), - (self.in_review_application, TransitionNotAllowed), - (self.withdrawn_application, TransitionNotAllowed), + (self.started_domain_request, TransitionNotAllowed), + (self.in_review_domain_request, TransitionNotAllowed), + (self.withdrawn_domain_request, TransitionNotAllowed), ] with boto3_mocking.clients.handler_for("sesv2", self.mock_client): @@ -293,23 +293,23 @@ class TestDomainRequest(TestCase): for application, exception_type in test_cases: with self.subTest(application=application, exception_type=exception_type): with self.assertRaises(exception_type): - application.in_review() + domain_request.in_review() def test_action_needed_transition_allowed(self): """ Test that calling action_needed from allowable statuses does raises TransitionNotAllowed. """ test_cases = [ - (self.in_review_application, TransitionNotAllowed), - (self.approved_application, TransitionNotAllowed), - (self.rejected_application, TransitionNotAllowed), - (self.ineligible_application, TransitionNotAllowed), + (self.in_review_domain_request, TransitionNotAllowed), + (self.approved_domain_request, TransitionNotAllowed), + (self.rejected_domain_request, TransitionNotAllowed), + (self.ineligible_domain_request, TransitionNotAllowed), ] with less_console_noise(): for application, exception_type in test_cases: with self.subTest(application=application, exception_type=exception_type): try: - application.action_needed() + domain_request.action_needed() except TransitionNotAllowed: self.fail("TransitionNotAllowed was raised, but it was not expected.") @@ -318,26 +318,26 @@ class TestDomainRequest(TestCase): Test that calling action_needed against transition rules raises TransitionNotAllowed. """ test_cases = [ - (self.started_application, TransitionNotAllowed), - (self.submitted_application, TransitionNotAllowed), - (self.action_needed_application, TransitionNotAllowed), - (self.withdrawn_application, TransitionNotAllowed), + (self.started_domain_request, TransitionNotAllowed), + (self.submitted_domain_request, TransitionNotAllowed), + (self.action_needed_domain_request, TransitionNotAllowed), + (self.withdrawn_domain_request, TransitionNotAllowed), ] with less_console_noise(): for application, exception_type in test_cases: with self.subTest(application=application, exception_type=exception_type): with self.assertRaises(exception_type): - application.action_needed() + domain_request.action_needed() def test_approved_transition_allowed(self): """ Test that calling action_needed from allowable statuses does raises TransitionNotAllowed. """ test_cases = [ - (self.submitted_application, TransitionNotAllowed), - (self.in_review_application, TransitionNotAllowed), - (self.action_needed_application, TransitionNotAllowed), - (self.rejected_application, TransitionNotAllowed), + (self.submitted_domain_request, TransitionNotAllowed), + (self.in_review_domain_request, TransitionNotAllowed), + (self.action_needed_domain_request, TransitionNotAllowed), + (self.rejected_domain_request, TransitionNotAllowed), ] with boto3_mocking.clients.handler_for("sesv2", self.mock_client): @@ -345,7 +345,7 @@ class TestDomainRequest(TestCase): for application, exception_type in test_cases: with self.subTest(application=application, exception_type=exception_type): try: - application.approve() + domain_request.approve() except TransitionNotAllowed: self.fail("TransitionNotAllowed was raised, but it was not expected.") @@ -357,7 +357,7 @@ class TestDomainRequest(TestCase): with boto3_mocking.clients.handler_for("sesv2", self.mock_client): with less_console_noise(): - self.submitted_application.approve(send_email=False) + self.submitted_domain_request.approve(send_email=False) # Assert that no emails were sent self.assertEqual(len(self.mock_client.EMAILS_SENT), 0) @@ -367,10 +367,10 @@ class TestDomainRequest(TestCase): Test that calling action_needed against transition rules raises TransitionNotAllowed. """ test_cases = [ - (self.started_application, TransitionNotAllowed), - (self.approved_application, TransitionNotAllowed), - (self.withdrawn_application, TransitionNotAllowed), - (self.ineligible_application, TransitionNotAllowed), + (self.started_domain_request, TransitionNotAllowed), + (self.approved_domain_request, TransitionNotAllowed), + (self.withdrawn_domain_request, TransitionNotAllowed), + (self.ineligible_domain_request, TransitionNotAllowed), ] with boto3_mocking.clients.handler_for("sesv2", self.mock_client): @@ -378,16 +378,16 @@ class TestDomainRequest(TestCase): for application, exception_type in test_cases: with self.subTest(application=application, exception_type=exception_type): with self.assertRaises(exception_type): - application.approve() + domain_request.approve() def test_withdraw_transition_allowed(self): """ Test that calling action_needed from allowable statuses does raises TransitionNotAllowed. """ test_cases = [ - (self.submitted_application, TransitionNotAllowed), - (self.in_review_application, TransitionNotAllowed), - (self.action_needed_application, TransitionNotAllowed), + (self.submitted_domain_request, TransitionNotAllowed), + (self.in_review_domain_request, TransitionNotAllowed), + (self.action_needed_domain_request, TransitionNotAllowed), ] with boto3_mocking.clients.handler_for("sesv2", self.mock_client): @@ -395,7 +395,7 @@ class TestDomainRequest(TestCase): for application, exception_type in test_cases: with self.subTest(application=application, exception_type=exception_type): try: - application.withdraw() + domain_request.withdraw() except TransitionNotAllowed: self.fail("TransitionNotAllowed was raised, but it was not expected.") @@ -404,11 +404,11 @@ class TestDomainRequest(TestCase): Test that calling action_needed against transition rules raises TransitionNotAllowed. """ test_cases = [ - (self.started_application, TransitionNotAllowed), - (self.approved_application, TransitionNotAllowed), - (self.withdrawn_application, TransitionNotAllowed), - (self.rejected_application, TransitionNotAllowed), - (self.ineligible_application, TransitionNotAllowed), + (self.started_domain_request, TransitionNotAllowed), + (self.approved_domain_request, TransitionNotAllowed), + (self.withdrawn_domain_request, TransitionNotAllowed), + (self.rejected_domain_request, TransitionNotAllowed), + (self.ineligible_domain_request, TransitionNotAllowed), ] with boto3_mocking.clients.handler_for("sesv2", self.mock_client): @@ -416,16 +416,16 @@ class TestDomainRequest(TestCase): for application, exception_type in test_cases: with self.subTest(application=application, exception_type=exception_type): with self.assertRaises(exception_type): - application.withdraw() + domain_request.withdraw() def test_reject_transition_allowed(self): """ Test that calling action_needed from allowable statuses does raises TransitionNotAllowed. """ test_cases = [ - (self.in_review_application, TransitionNotAllowed), - (self.action_needed_application, TransitionNotAllowed), - (self.approved_application, TransitionNotAllowed), + (self.in_review_domain_request, TransitionNotAllowed), + (self.action_needed_domain_request, TransitionNotAllowed), + (self.approved_domain_request, TransitionNotAllowed), ] with boto3_mocking.clients.handler_for("sesv2", self.mock_client): @@ -433,7 +433,7 @@ class TestDomainRequest(TestCase): for application, exception_type in test_cases: with self.subTest(application=application, exception_type=exception_type): try: - application.reject() + domain_request.reject() except TransitionNotAllowed: self.fail("TransitionNotAllowed was raised, but it was not expected.") @@ -442,11 +442,11 @@ class TestDomainRequest(TestCase): Test that calling action_needed against transition rules raises TransitionNotAllowed. """ test_cases = [ - (self.started_application, TransitionNotAllowed), - (self.submitted_application, TransitionNotAllowed), - (self.withdrawn_application, TransitionNotAllowed), - (self.rejected_application, TransitionNotAllowed), - (self.ineligible_application, TransitionNotAllowed), + (self.started_domain_request, TransitionNotAllowed), + (self.submitted_domain_request, TransitionNotAllowed), + (self.withdrawn_domain_request, TransitionNotAllowed), + (self.rejected_domain_request, TransitionNotAllowed), + (self.ineligible_domain_request, TransitionNotAllowed), ] with boto3_mocking.clients.handler_for("sesv2", self.mock_client): @@ -454,17 +454,17 @@ class TestDomainRequest(TestCase): for application, exception_type in test_cases: with self.subTest(application=application, exception_type=exception_type): with self.assertRaises(exception_type): - application.reject() + domain_request.reject() def test_reject_with_prejudice_transition_allowed(self): """ Test that calling action_needed from allowable statuses does raises TransitionNotAllowed. """ test_cases = [ - (self.in_review_application, TransitionNotAllowed), - (self.action_needed_application, TransitionNotAllowed), - (self.approved_application, TransitionNotAllowed), - (self.rejected_application, TransitionNotAllowed), + (self.in_review_domain_request, TransitionNotAllowed), + (self.action_needed_domain_request, TransitionNotAllowed), + (self.approved_domain_request, TransitionNotAllowed), + (self.rejected_domain_request, TransitionNotAllowed), ] with boto3_mocking.clients.handler_for("sesv2", self.mock_client): @@ -472,7 +472,7 @@ class TestDomainRequest(TestCase): for application, exception_type in test_cases: with self.subTest(application=application, exception_type=exception_type): try: - application.reject_with_prejudice() + domain_request.reject_with_prejudice() except TransitionNotAllowed: self.fail("TransitionNotAllowed was raised, but it was not expected.") @@ -481,10 +481,10 @@ class TestDomainRequest(TestCase): Test that calling action_needed against transition rules raises TransitionNotAllowed. """ test_cases = [ - (self.started_application, TransitionNotAllowed), - (self.submitted_application, TransitionNotAllowed), - (self.withdrawn_application, TransitionNotAllowed), - (self.ineligible_application, TransitionNotAllowed), + (self.started_domain_request, TransitionNotAllowed), + (self.submitted_domain_request, TransitionNotAllowed), + (self.withdrawn_domain_request, TransitionNotAllowed), + (self.ineligible_domain_request, TransitionNotAllowed), ] with boto3_mocking.clients.handler_for("sesv2", self.mock_client): @@ -492,15 +492,15 @@ class TestDomainRequest(TestCase): for application, exception_type in test_cases: with self.subTest(application=application, exception_type=exception_type): with self.assertRaises(exception_type): - application.reject_with_prejudice() + domain_request.reject_with_prejudice() def test_transition_not_allowed_approved_in_review_when_domain_is_active(self): - """Create an application with status approved, create a matching domain that + """Create a domain request with status approved, create a matching domain that is active, and call in_review against transition rules""" - domain = Domain.objects.create(name=self.approved_application.requested_domain.name) - self.approved_application.approved_domain = domain - self.approved_application.save() + domain = Domain.objects.create(name=self.approved_domain_request.requested_domain.name) + self.approved_domain_request.approved_domain = domain + self.approved_domain_request.save() # Define a custom implementation for is_active def custom_is_active(self): @@ -512,15 +512,15 @@ class TestDomainRequest(TestCase): with patch.object(Domain, "is_active", custom_is_active): # Now, when you call is_active on Domain, it will return True with self.assertRaises(TransitionNotAllowed): - self.approved_application.in_review() + self.approved_domain_request.in_review() def test_transition_not_allowed_approved_action_needed_when_domain_is_active(self): - """Create an application with status approved, create a matching domain that + """Create a domain request with status approved, create a matching domain that is active, and call action_needed against transition rules""" - domain = Domain.objects.create(name=self.approved_application.requested_domain.name) - self.approved_application.approved_domain = domain - self.approved_application.save() + domain = Domain.objects.create(name=self.approved_domain_request.requested_domain.name) + self.approved_domain_request.approved_domain = domain + self.approved_domain_request.save() # Define a custom implementation for is_active def custom_is_active(self): @@ -532,15 +532,15 @@ class TestDomainRequest(TestCase): with patch.object(Domain, "is_active", custom_is_active): # Now, when you call is_active on Domain, it will return True with self.assertRaises(TransitionNotAllowed): - self.approved_application.action_needed() + self.approved_domain_request.action_needed() def test_transition_not_allowed_approved_rejected_when_domain_is_active(self): - """Create an application with status approved, create a matching domain that + """Create a domain request with status approved, create a matching domain that is active, and call reject against transition rules""" - domain = Domain.objects.create(name=self.approved_application.requested_domain.name) - self.approved_application.approved_domain = domain - self.approved_application.save() + domain = Domain.objects.create(name=self.approved_domain_request.requested_domain.name) + self.approved_domain_request.approved_domain = domain + self.approved_domain_request.save() # Define a custom implementation for is_active def custom_is_active(self): @@ -552,15 +552,15 @@ class TestDomainRequest(TestCase): with patch.object(Domain, "is_active", custom_is_active): # Now, when you call is_active on Domain, it will return True with self.assertRaises(TransitionNotAllowed): - self.approved_application.reject() + self.approved_domain_request.reject() def test_transition_not_allowed_approved_ineligible_when_domain_is_active(self): - """Create an application with status approved, create a matching domain that + """Create a domain request with status approved, create a matching domain that is active, and call reject_with_prejudice against transition rules""" - domain = Domain.objects.create(name=self.approved_application.requested_domain.name) - self.approved_application.approved_domain = domain - self.approved_application.save() + domain = Domain.objects.create(name=self.approved_domain_request.requested_domain.name) + self.approved_domain_request.approved_domain = domain + self.approved_domain_request.save() # Define a custom implementation for is_active def custom_is_active(self): @@ -572,7 +572,7 @@ class TestDomainRequest(TestCase): with patch.object(Domain, "is_active", custom_is_active): # Now, when you call is_active on Domain, it will return True with self.assertRaises(TransitionNotAllowed): - self.approved_application.reject_with_prejudice() + self.approved_domain_request.reject_with_prejudice() def test_approve_from_rejected_clears_rejection_reason(self): """When transitioning from rejected to approved on a domain request, @@ -580,15 +580,15 @@ class TestDomainRequest(TestCase): with less_console_noise(): # Create a sample application - application = completed_application(status=DomainRequest.ApplicationStatus.REJECTED) - application.rejection_reason = DomainRequest.RejectionReasons.DOMAIN_PURPOSE + domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.REJECTED) + domain_request.rejection_reason = DomainRequest.RejectionReasons.DOMAIN_PURPOSE # Approve with boto3_mocking.clients.handler_for("sesv2", self.mock_client): - application.approve() + domain_request.approve() - self.assertEqual(application.status, DomainRequest.ApplicationStatus.APPROVED) - self.assertEqual(application.rejection_reason, None) + self.assertEqual(domain_request.status, DomainRequest.DomainRequestStatus.APPROVED) + self.assertEqual(domain_request.rejection_reason, None) def test_in_review_from_rejected_clears_rejection_reason(self): """When transitioning from rejected to in_review on a domain request, @@ -596,16 +596,16 @@ class TestDomainRequest(TestCase): with less_console_noise(): # Create a sample application - application = completed_application(status=DomainRequest.ApplicationStatus.REJECTED) - application.domain_is_not_active = True - application.rejection_reason = DomainRequest.RejectionReasons.DOMAIN_PURPOSE + domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.REJECTED) + domain_request.domain_is_not_active = True + domain_request.rejection_reason = DomainRequest.RejectionReasons.DOMAIN_PURPOSE # Approve with boto3_mocking.clients.handler_for("sesv2", self.mock_client): - application.in_review() + domain_request.in_review() - self.assertEqual(application.status, DomainRequest.ApplicationStatus.IN_REVIEW) - self.assertEqual(application.rejection_reason, None) + self.assertEqual(domain_request.status, DomainRequest.DomainRequestStatus.IN_REVIEW) + self.assertEqual(domain_request.rejection_reason, None) def test_action_needed_from_rejected_clears_rejection_reason(self): """When transitioning from rejected to action_needed on a domain request, @@ -613,42 +613,42 @@ class TestDomainRequest(TestCase): with less_console_noise(): # Create a sample application - application = completed_application(status=DomainRequest.ApplicationStatus.REJECTED) - application.domain_is_not_active = True - application.rejection_reason = DomainRequest.RejectionReasons.DOMAIN_PURPOSE + domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.REJECTED) + domain_request.domain_is_not_active = True + domain_request.rejection_reason = DomainRequest.RejectionReasons.DOMAIN_PURPOSE # Approve with boto3_mocking.clients.handler_for("sesv2", self.mock_client): - application.action_needed() + domain_request.action_needed() - self.assertEqual(application.status, DomainRequest.ApplicationStatus.ACTION_NEEDED) - self.assertEqual(application.rejection_reason, None) + self.assertEqual(domain_request.status, DomainRequest.DomainRequestStatus.ACTION_NEEDED) + self.assertEqual(domain_request.rejection_reason, None) def test_has_rationale_returns_true(self): - """has_rationale() returns true when an application has no_other_contacts_rationale""" + """has_rationale() returns true when a domain request has no_other_contacts_rationale""" with less_console_noise(): - self.started_application.no_other_contacts_rationale = "You talkin' to me?" - self.started_application.save() - self.assertEquals(self.started_application.has_rationale(), True) + self.started_domain_request.no_other_contacts_rationale = "You talkin' to me?" + self.started_domain_request.save() + self.assertEquals(self.started_domain_request.has_rationale(), True) def test_has_rationale_returns_false(self): - """has_rationale() returns false when an application has no no_other_contacts_rationale""" + """has_rationale() returns false when a domain request has no no_other_contacts_rationale""" with less_console_noise(): - self.assertEquals(self.started_application.has_rationale(), False) + self.assertEquals(self.started_domain_request.has_rationale(), False) def test_has_other_contacts_returns_true(self): - """has_other_contacts() returns true when an application has other_contacts""" + """has_other_contacts() returns true when a domain request has other_contacts""" with less_console_noise(): - # completed_application has other contacts by default - self.assertEquals(self.started_application.has_other_contacts(), True) + # completed_domain_request has other contacts by default + self.assertEquals(self.started_domain_request.has_other_contacts(), True) def test_has_other_contacts_returns_false(self): - """has_other_contacts() returns false when an application has no other_contacts""" + """has_other_contacts() returns false when a domain request has no other_contacts""" with less_console_noise(): - application = completed_application( - status=DomainRequest.ApplicationStatus.STARTED, name="no-others.gov", has_other_contacts=False + domain_request = completed_domain_request( + status=DomainRequest.DomainRequestStatus.STARTED, name="no-others.gov", has_other_contacts=False ) - self.assertEquals(application.has_other_contacts(), False) + self.assertEquals(domain_request.has_other_contacts(), False) class TestPermissions(TestCase): @@ -666,13 +666,13 @@ class TestPermissions(TestCase): def test_approval_creates_role(self): draft_domain, _ = DraftDomain.objects.get_or_create(name="igorville.gov") user, _ = User.objects.get_or_create() - application = DomainRequest.objects.create(creator=user, requested_domain=draft_domain) + domain_request = DomainRequest.objects.create(creator=user, requested_domain=draft_domain) with boto3_mocking.clients.handler_for("sesv2", self.mock_client): with less_console_noise(): # skip using the submit method - application.status = DomainRequest.ApplicationStatus.SUBMITTED - application.approve() + domain_request.status = DomainRequest.DomainRequestStatus.SUBMITTED + domain_request.approve() # should be a role for this user domain = Domain.objects.get(name="igorville.gov") @@ -700,13 +700,13 @@ class TestDomainInformation(TestCase): self.maxDiff = None draft_domain, _ = DraftDomain.objects.get_or_create(name="igorville.gov") user, _ = User.objects.get_or_create() - application = DomainRequest.objects.create(creator=user, requested_domain=draft_domain, notes="test notes") + domain_request = DomainRequest.objects.create(creator=user, requested_domain=draft_domain, notes="test notes") with boto3_mocking.clients.handler_for("sesv2", self.mock_client): with less_console_noise(): # skip using the submit method - application.status = DomainRequest.ApplicationStatus.SUBMITTED - application.approve() + domain_request.status = DomainRequest.DomainRequestStatus.SUBMITTED + domain_request.approve() # should be an information present for this domain domain = Domain.objects.get(name="igorville.gov") @@ -852,7 +852,7 @@ class TestContact(TestCase): self.contact, _ = Contact.objects.get_or_create(user=self.user) self.contact_as_ao, _ = Contact.objects.get_or_create(email="newguy@igorville.gov") - self.application = DomainRequest.objects.create(creator=self.user, authorizing_official=self.contact_as_ao) + self.domain_request = DomainRequest.objects.create(creator=self.user, authorizing_official=self.contact_as_ao) def tearDown(self): super().tearDown() @@ -936,6 +936,6 @@ class TestContact(TestCase): # test for a contact which has one user defined self.assertFalse(self.contact.has_more_than_one_join("user")) self.assertTrue(self.contact.has_more_than_one_join("authorizing_official")) - # test for a contact which is assigned as an authorizing official on an application + # test for a contact which is assigned as an authorizing official on a domain request self.assertFalse(self.contact_as_ao.has_more_than_one_join("authorizing_official")) - self.assertTrue(self.contact_as_ao.has_more_than_one_join("submitted_applications")) + self.assertTrue(self.contact_as_ao.has_more_than_one_join("submitted_domain_requests")) diff --git a/src/registrar/tests/test_models_domain.py b/src/registrar/tests/test_models_domain.py index 65b1e2504..fd47d907f 100644 --- a/src/registrar/tests/test_models_domain.py +++ b/src/registrar/tests/test_models_domain.py @@ -314,7 +314,7 @@ class TestDomainCreation(MockEppLib): """Rule: An approved domain request must result in a domain""" @boto3_mocking.patching - def test_approved_application_creates_domain_locally(self): + def test_approved_domain_request_creates_domain_locally(self): """ Scenario: Analyst approves a domain request When the DomainRequest transitions to approved @@ -324,14 +324,14 @@ class TestDomainCreation(MockEppLib): with less_console_noise(): draft_domain, _ = DraftDomain.objects.get_or_create(name="igorville.gov") user, _ = User.objects.get_or_create() - application = DomainRequest.objects.create(creator=user, requested_domain=draft_domain) + domain_request = DomainRequest.objects.create(creator=user, requested_domain=draft_domain) mock_client = MockSESClient() with boto3_mocking.clients.handler_for("sesv2", mock_client): # skip using the submit method - application.status = DomainRequest.ApplicationStatus.SUBMITTED + domain_request.status = DomainRequest.DomainRequestStatus.SUBMITTED # transition to approve state - application.approve() + domain_request.approve() # should have information present for this domain domain = Domain.objects.get(name="igorville.gov") self.assertTrue(domain) diff --git a/src/registrar/tests/test_transition_domain_migrations.py b/src/registrar/tests/test_transition_domain_migrations.py index e9453bd03..9008a4f94 100644 --- a/src/registrar/tests/test_transition_domain_migrations.py +++ b/src/registrar/tests/test_transition_domain_migrations.py @@ -27,7 +27,7 @@ logger = logging.getLogger(__name__) class TestProcessedMigrations(TestCase): """This test case class is designed to verify the idempotency of migrations - related to domain transitions in the application.""" + related to domain transitions in the domain_request.""" def setUp(self): """Defines the file name of migration_json and the folder its contained in""" diff --git a/src/registrar/tests/test_views.py b/src/registrar/tests/test_views.py index 655cece4a..b4ec1288a 100644 --- a/src/registrar/tests/test_views.py +++ b/src/registrar/tests/test_views.py @@ -26,8 +26,8 @@ class TestViews(TestCase): response = self.client.get("/") self.assertEqual(response.status_code, 302) - def test_application_form_not_logged_in(self): - """Application form not accessible without a logged-in user.""" + def test_domain_request_form_not_logged_in(self): + """Domain request form not accessible without a logged-in user.""" response = self.client.get("/request/") self.assertEqual(response.status_code, 302) self.assertIn("/login?next=/request/", response.headers["Location"]) diff --git a/src/registrar/tests/test_views_application.py b/src/registrar/tests/test_views_application.py index f19c6c41d..b08c0a913 100644 --- a/src/registrar/tests/test_views_application.py +++ b/src/registrar/tests/test_views_application.py @@ -5,7 +5,7 @@ from django.conf import settings from django.urls import reverse from datetime import date -from .common import MockSESClient, completed_application # type: ignore +from .common import MockSESClient, completed_domain_request # type: ignore from django_webtest import WebTest # type: ignore import boto3_mocking # type: ignore @@ -19,7 +19,7 @@ from registrar.models import ( Website, UserDomainRole, ) -from registrar.views.application import ApplicationWizard, Step +from registrar.views.domain_request import DomainRequestWizard, Step from .common import less_console_noise from .test_views import TestWithUser @@ -39,16 +39,16 @@ class DomainRequestTests(TestWithUser, WebTest): def setUp(self): super().setUp() self.app.set_user(self.user.username) - self.TITLES = ApplicationWizard.TITLES + self.TITLES = DomainRequestWizard.TITLES - def test_application_form_intro_acknowledgement(self): + def test_domain_request_form_intro_acknowledgement(self): """Tests that user is presented with intro acknowledgement page""" intro_page = self.app.get(reverse("application:")) self.assertContains(intro_page, "You’re about to start your .gov domain request") - def test_application_form_intro_is_skipped_when_edit_access(self): + def test_domain_request_form_intro_is_skipped_when_edit_access(self): """Tests that user is NOT presented with intro acknowledgement page when accessed through 'edit'""" - completed_application(status=DomainRequest.ApplicationStatus.STARTED, user=self.user) + completed_domain_request(status=DomainRequest.DomainRequestStatus.STARTED, user=self.user) home_page = self.app.get("/") self.assertContains(home_page, "city.gov") # click the "Edit" link @@ -59,7 +59,7 @@ class DomainRequestTests(TestWithUser, WebTest): redirect_url = detail_page.url self.assertEqual(redirect_url, "/request/organization_type/") - def test_application_form_empty_submit(self): + def test_domain_request_form_empty_submit(self): """Tests empty submit on the first page after the acknowledgement page""" intro_page = self.app.get(reverse("application:")) # django-webtest does not handle cookie-based sessions well because it keeps @@ -81,15 +81,15 @@ class DomainRequestTests(TestWithUser, WebTest): result = type_page.forms[0].submit() self.assertIn("What kind of U.S.-based government organization do you represent?", result) - def test_application_multiple_applications_exist(self): + def test_domain_request_multiple_domain_requests_exist(self): """Test that an info message appears when user has multiple applications already""" - # create and submit an application - application = completed_application(user=self.user) + # create and submit a domain request + domain_request = completed_domain_request(user=self.user) mock_client = MockSESClient() with boto3_mocking.clients.handler_for("sesv2", mock_client): with less_console_noise(): - application.submit() - application.save() + domain_request.submit() + domain_request.save() # now, attempt to create another one with less_console_noise(): @@ -107,7 +107,7 @@ class DomainRequestTests(TestWithUser, WebTest): self.assertContains(type_page, "You cannot submit this request yet") @boto3_mocking.patching - def test_application_form_submission(self): + def test_domain_request_form_submission(self): """ Can fill out the entire form and submit. As we add additional form pages, we need to include them here to make @@ -146,10 +146,10 @@ class DomainRequestTests(TestWithUser, WebTest): self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) type_result = type_form.submit() # should see results in db - application = DomainRequest.objects.get() # there's only one - self.assertEqual(application.organization_type, "federal") + domain_request = DomainRequest.objects.get() # there's only one + self.assertEqual(domain_request.organization_type, "federal") # the post request should return a redirect to the next form in - # the application + # the domain request page self.assertEqual(type_result.status_code, 302) self.assertEqual(type_result["Location"], "/request/organization_federal/") num_pages_tested += 1 @@ -166,10 +166,10 @@ class DomainRequestTests(TestWithUser, WebTest): self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) federal_result = federal_form.submit() # validate that data from this step are being saved - application = DomainRequest.objects.get() # there's only one - self.assertEqual(application.federal_type, "executive") + domain_request = DomainRequest.objects.get() # there's only one + self.assertEqual(domain_request.federal_type, "executive") # the post request should return a redirect to the next form in - # the application + # the domain request page self.assertEqual(federal_result.status_code, 302) self.assertEqual(federal_result["Location"], "/request/organization_contact/") num_pages_tested += 1 @@ -193,16 +193,16 @@ class DomainRequestTests(TestWithUser, WebTest): self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) org_contact_result = org_contact_form.submit() # validate that data from this step are being saved - application = DomainRequest.objects.get() # there's only one - self.assertEqual(application.organization_name, "Testorg") - self.assertEqual(application.address_line1, "address 1") - self.assertEqual(application.address_line2, "address 2") - self.assertEqual(application.city, "NYC") - self.assertEqual(application.state_territory, "NY") - self.assertEqual(application.zipcode, "10002") - self.assertEqual(application.urbanization, "URB Royal Oaks") + domain_request = DomainRequest.objects.get() # there's only one + self.assertEqual(domain_request.organization_name, "Testorg") + self.assertEqual(domain_request.address_line1, "address 1") + self.assertEqual(domain_request.address_line2, "address 2") + self.assertEqual(domain_request.city, "NYC") + self.assertEqual(domain_request.state_territory, "NY") + self.assertEqual(domain_request.zipcode, "10002") + self.assertEqual(domain_request.urbanization, "URB Royal Oaks") # the post request should return a redirect to the next form in - # the application + # the domain request page self.assertEqual(org_contact_result.status_code, 302) self.assertEqual(org_contact_result["Location"], "/request/authorizing_official/") num_pages_tested += 1 @@ -221,13 +221,13 @@ class DomainRequestTests(TestWithUser, WebTest): self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) ao_result = ao_form.submit() # validate that data from this step are being saved - application = DomainRequest.objects.get() # there's only one - self.assertEqual(application.authorizing_official.first_name, "Testy ATO") - self.assertEqual(application.authorizing_official.last_name, "Tester ATO") - self.assertEqual(application.authorizing_official.title, "Chief Tester") - self.assertEqual(application.authorizing_official.email, "testy@town.com") + domain_request = DomainRequest.objects.get() # there's only one + self.assertEqual(domain_request.authorizing_official.first_name, "Testy ATO") + self.assertEqual(domain_request.authorizing_official.last_name, "Tester ATO") + self.assertEqual(domain_request.authorizing_official.title, "Chief Tester") + self.assertEqual(domain_request.authorizing_official.email, "testy@town.com") # the post request should return a redirect to the next form in - # the application + # the domain request page self.assertEqual(ao_result.status_code, 302) self.assertEqual(ao_result["Location"], "/request/current_sites/") num_pages_tested += 1 @@ -243,13 +243,13 @@ class DomainRequestTests(TestWithUser, WebTest): self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) current_sites_result = current_sites_form.submit() # validate that data from this step are being saved - application = DomainRequest.objects.get() # there's only one + domain_request = DomainRequest.objects.get() # there's only one self.assertEqual( - application.current_websites.filter(website="http://www.city.com").count(), + domain_request.current_websites.filter(website="http://www.city.com").count(), 1, ) # the post request should return a redirect to the next form in - # the application + # the domain request page self.assertEqual(current_sites_result.status_code, 302) self.assertEqual(current_sites_result["Location"], "/request/dotgov_domain/") num_pages_tested += 1 @@ -265,11 +265,11 @@ class DomainRequestTests(TestWithUser, WebTest): self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) dotgov_result = dotgov_form.submit() # validate that data from this step are being saved - application = DomainRequest.objects.get() # there's only one - self.assertEqual(application.requested_domain.name, "city.gov") - self.assertEqual(application.alternative_domains.filter(website="city1.gov").count(), 1) + domain_request = DomainRequest.objects.get() # there's only one + self.assertEqual(domain_request.requested_domain.name, "city.gov") + self.assertEqual(domain_request.alternative_domains.filter(website="city1.gov").count(), 1) # the post request should return a redirect to the next form in - # the application + # the domain request page self.assertEqual(dotgov_result.status_code, 302) self.assertEqual(dotgov_result["Location"], "/request/purpose/") num_pages_tested += 1 @@ -285,10 +285,10 @@ class DomainRequestTests(TestWithUser, WebTest): self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) purpose_result = purpose_form.submit() # validate that data from this step are being saved - application = DomainRequest.objects.get() # there's only one - self.assertEqual(application.purpose, "For all kinds of things.") + domain_request = DomainRequest.objects.get() # there's only one + self.assertEqual(domain_request.purpose, "For all kinds of things.") # the post request should return a redirect to the next form in - # the application + # the domain request page self.assertEqual(purpose_result.status_code, 302) self.assertEqual(purpose_result["Location"], "/request/your_contact/") num_pages_tested += 1 @@ -309,14 +309,14 @@ class DomainRequestTests(TestWithUser, WebTest): self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) your_contact_result = your_contact_form.submit() # validate that data from this step are being saved - application = DomainRequest.objects.get() # there's only one - self.assertEqual(application.submitter.first_name, "Testy you") - self.assertEqual(application.submitter.last_name, "Tester you") - self.assertEqual(application.submitter.title, "Admin Tester") - self.assertEqual(application.submitter.email, "testy-admin@town.com") - self.assertEqual(application.submitter.phone, "(201) 555 5556") + domain_request = DomainRequest.objects.get() # there's only one + self.assertEqual(domain_request.submitter.first_name, "Testy you") + self.assertEqual(domain_request.submitter.last_name, "Tester you") + self.assertEqual(domain_request.submitter.title, "Admin Tester") + self.assertEqual(domain_request.submitter.email, "testy-admin@town.com") + self.assertEqual(domain_request.submitter.phone, "(201) 555 5556") # the post request should return a redirect to the next form in - # the application + # the domain request page self.assertEqual(your_contact_result.status_code, 302) self.assertEqual(your_contact_result["Location"], "/request/other_contacts/") num_pages_tested += 1 @@ -342,9 +342,9 @@ class DomainRequestTests(TestWithUser, WebTest): self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) other_contacts_result = other_contacts_form.submit() # validate that data from this step are being saved - application = DomainRequest.objects.get() # there's only one + domain_request = DomainRequest.objects.get() # there's only one self.assertEqual( - application.other_contacts.filter( + domain_request.other_contacts.filter( first_name="Testy2", last_name="Tester2", title="Another Tester", @@ -354,7 +354,7 @@ class DomainRequestTests(TestWithUser, WebTest): 1, ) # the post request should return a redirect to the next form in - # the application + # the domain request page self.assertEqual(other_contacts_result.status_code, 302) self.assertEqual(other_contacts_result["Location"], "/request/anything_else/") num_pages_tested += 1 @@ -371,10 +371,10 @@ class DomainRequestTests(TestWithUser, WebTest): self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) anything_else_result = anything_else_form.submit() # validate that data from this step are being saved - application = DomainRequest.objects.get() # there's only one - self.assertEqual(application.anything_else, "Nothing else.") + domain_request = DomainRequest.objects.get() # there's only one + self.assertEqual(domain_request.anything_else, "Nothing else.") # the post request should return a redirect to the next form in - # the application + # the domain request page self.assertEqual(anything_else_result.status_code, 302) self.assertEqual(anything_else_result["Location"], "/request/requirements/") num_pages_tested += 1 @@ -391,10 +391,10 @@ class DomainRequestTests(TestWithUser, WebTest): self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) requirements_result = requirements_form.submit() # validate that data from this step are being saved - application = DomainRequest.objects.get() # there's only one - self.assertEqual(application.is_policy_acknowledged, True) + domain_request = DomainRequest.objects.get() # there's only one + self.assertEqual(domain_request.is_policy_acknowledged, True) # the post request should return a redirect to the next form in - # the application + # the domain request page self.assertEqual(requirements_result.status_code, 302) self.assertEqual(requirements_result["Location"], "/request/review/") num_pages_tested += 1 @@ -441,7 +441,7 @@ class DomainRequestTests(TestWithUser, WebTest): self.assertContains(review_page, "toggle-submit-domain-request") # And the existence of the modal's data parked and ready for the js init. # The next assert also tests for the passed requested domain context from - # the view > application_form > modal + # the view > domain_request_form > modal self.assertContains(review_page, "You are about to submit a domain request for city.gov") # final submission results in a redirect to the "finished" URL @@ -467,15 +467,15 @@ class DomainRequestTests(TestWithUser, WebTest): # does not work and results in errors as noted in: # https://github.com/cisagov/getgov/pull/728 @skip("WIP") - def test_application_form_started_allsteps(self): + def test_domain_request_form_started_allsteps(self): num_pages_tested = 0 # elections, type_of_work, tribal_government SKIPPED_PAGES = 3 DASHBOARD_PAGE = 1 num_pages = len(self.TITLES) - SKIPPED_PAGES + DASHBOARD_PAGE - application = completed_application(user=self.user) - application.save() + domain_request = completed_domain_request(user=self.user) + domain_request.save() home_page = self.app.get("/") self.assertContains(home_page, "city.gov") self.assertContains(home_page, "Started") @@ -487,7 +487,7 @@ class DomainRequestTests(TestWithUser, WebTest): # type_page = home_page.click("Edit") session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] - url = reverse("edit-application", kwargs={"id": application.pk}) + url = reverse("edit-application", kwargs={"id": domain_request.pk}) self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) # TODO: The following line results in a django error on middleware @@ -498,7 +498,7 @@ class DomainRequestTests(TestWithUser, WebTest): self.assertEqual(num_pages, num_pages_tested) - def test_application_form_conditional_federal(self): + def test_domain_request_form_conditional_federal(self): """Federal branch question is shown for federal organizations.""" intro_page = self.app.get(reverse("application:")) # django-webtest does not handle cookie-based sessions well because it keeps @@ -553,7 +553,7 @@ class DomainRequestTests(TestWithUser, WebTest): contact_page = federal_result.follow() self.assertContains(contact_page, "Federal agency") - def test_application_form_conditional_elections(self): + def test_domain_request_form_conditional_elections(self): """Election question is shown for other organizations.""" intro_page = self.app.get(reverse("application:")) # django-webtest does not handle cookie-based sessions well because it keeps @@ -607,7 +607,7 @@ class DomainRequestTests(TestWithUser, WebTest): contact_page = election_result.follow() self.assertNotContains(contact_page, "Federal agency") - def test_application_form_section_skipping(self): + def test_domain_request_form_section_skipping(self): """Can skip forward and back in sections""" intro_page = self.app.get(reverse("application:")) # django-webtest does not handle cookie-based sessions well because it keeps @@ -644,7 +644,7 @@ class DomainRequestTests(TestWithUser, WebTest): 0, ) - def test_application_form_nonfederal(self): + def test_domain_request_form_nonfederal(self): """Non-federal organizations don't have to provide their federal agency.""" intro_page = self.app.get(reverse("application:")) # django-webtest does not handle cookie-based sessions well because it keeps @@ -689,7 +689,7 @@ class DomainRequestTests(TestWithUser, WebTest): self.assertEqual(contact_result.status_code, 302) self.assertEqual(contact_result["Location"], "/request/about_your_organization/") - def test_application_about_your_organization_special(self): + def test_domain_request_about_your_organization_special(self): """Special districts have to answer an additional question.""" intro_page = self.app.get(reverse("application:")) # django-webtest does not handle cookie-based sessions well because it keeps @@ -717,20 +717,20 @@ class DomainRequestTests(TestWithUser, WebTest): self.assertContains(contact_page, self.TITLES[Step.ABOUT_YOUR_ORGANIZATION]) - def test_yes_no_form_inits_blank_for_new_application(self): + def test_yes_no_form_inits_blank_for_new_domain_request(self): """On the Other Contacts page, the yes/no form gets initialized with nothing selected for new applications""" other_contacts_page = self.app.get(reverse("application:other_contacts")) other_contacts_form = other_contacts_page.forms[0] self.assertEquals(other_contacts_form["other_contacts-has_other_contacts"].value, None) - def test_yes_no_form_inits_yes_for_application_with_other_contacts(self): + def test_yes_no_form_inits_yes_for_domain_request_with_other_contacts(self): """On the Other Contacts page, the yes/no form gets initialized with YES selected if the application has other contacts""" # Application has other contacts by default - application = completed_application(user=self.user) + domain_request = completed_domain_request(user=self.user) # prime the form by visiting /edit - self.app.get(reverse("edit-application", kwargs={"id": application.pk})) + self.app.get(reverse("edit-application", kwargs={"id": domain_request.pk})) # django-webtest does not handle cookie-based sessions well because it keeps # resetting the session key on each new request, thus destroying the concept # of a "session". We are going to do it manually, saving the session ID here @@ -744,15 +744,15 @@ class DomainRequestTests(TestWithUser, WebTest): other_contacts_form = other_contacts_page.forms[0] self.assertEquals(other_contacts_form["other_contacts-has_other_contacts"].value, "True") - def test_yes_no_form_inits_no_for_application_with_no_other_contacts_rationale(self): + def test_yes_no_form_inits_no_for_domain_request_with_no_other_contacts_rationale(self): """On the Other Contacts page, the yes/no form gets initialized with NO selected if the application has no other contacts""" # Application has other contacts by default - application = completed_application(user=self.user, has_other_contacts=False) - application.no_other_contacts_rationale = "Hello!" - application.save() + domain_request = completed_domain_request(user=self.user, has_other_contacts=False) + domain_request.no_other_contacts_rationale = "Hello!" + domain_request.save() # prime the form by visiting /edit - self.app.get(reverse("edit-application", kwargs={"id": application.pk})) + self.app.get(reverse("edit-application", kwargs={"id": domain_request.pk})) # django-webtest does not handle cookie-based sessions well because it keeps # resetting the session key on each new request, thus destroying the concept # of a "session". We are going to do it manually, saving the session ID here @@ -770,11 +770,11 @@ class DomainRequestTests(TestWithUser, WebTest): """When a user submits the Other Contacts form with other contacts selected, the application's no other contacts rationale gets deleted""" # Application has other contacts by default - application = completed_application(user=self.user, has_other_contacts=False) - application.no_other_contacts_rationale = "Hello!" - application.save() + domain_request = completed_domain_request(user=self.user, has_other_contacts=False) + domain_request.no_other_contacts_rationale = "Hello!" + domain_request.save() # prime the form by visiting /edit - self.app.get(reverse("edit-application", kwargs={"id": application.pk})) + self.app.get(reverse("edit-application", kwargs={"id": domain_request.pk})) # django-webtest does not handle cookie-based sessions well because it keeps # resetting the session key on each new request, thus destroying the concept # of a "session". We are going to do it manually, saving the session ID here @@ -803,14 +803,14 @@ class DomainRequestTests(TestWithUser, WebTest): self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) # Verify that the no_other_contacts_rationale we saved earlier has been removed from the database - application = DomainRequest.objects.get() + domain_request = DomainRequest.objects.get() self.assertEqual( - application.other_contacts.count(), + domain_request.other_contacts.count(), 1, ) self.assertEquals( - application.no_other_contacts_rationale, + domain_request.no_other_contacts_rationale, None, ) @@ -819,9 +819,9 @@ class DomainRequestTests(TestWithUser, WebTest): other contacts get deleted for other contacts that exist and are not joined to other objects """ # Application has other contacts by default - application = completed_application(user=self.user) + domain_request = completed_domain_request(user=self.user) # prime the form by visiting /edit - self.app.get(reverse("edit-application", kwargs={"id": application.pk})) + self.app.get(reverse("edit-application", kwargs={"id": domain_request.pk})) # django-webtest does not handle cookie-based sessions well because it keeps # resetting the session key on each new request, thus destroying the concept # of a "session". We are going to do it manually, saving the session ID here @@ -845,14 +845,14 @@ class DomainRequestTests(TestWithUser, WebTest): self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) # Verify that the no_other_contacts_rationale we saved earlier has been removed from the database - application = DomainRequest.objects.get() + domain_request = DomainRequest.objects.get() self.assertEqual( - application.other_contacts.count(), + domain_request.other_contacts.count(), 0, ) self.assertEquals( - application.no_other_contacts_rationale, + domain_request.no_other_contacts_rationale, "Hello again!", ) @@ -898,14 +898,14 @@ class DomainRequestTests(TestWithUser, WebTest): creator=self.user, status="started", ) - application.other_contacts.add(other) + domain_request.other_contacts.add(other) # Now let's join the other contact to another object domain_info = DomainInformation.objects.create(creator=self.user) domain_info.other_contacts.set([other]) # prime the form by visiting /edit - self.app.get(reverse("edit-application", kwargs={"id": application.pk})) + self.app.get(reverse("edit-application", kwargs={"id": domain_request.pk})) # django-webtest does not handle cookie-based sessions well because it keeps # resetting the session key on each new request, thus destroying the concept # of a "session". We are going to do it manually, saving the session ID here @@ -929,9 +929,9 @@ class DomainRequestTests(TestWithUser, WebTest): self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) # Verify that the no_other_contacts_rationale we saved earlier is no longer associated with the application - application = DomainRequest.objects.get() + domain_request = DomainRequest.objects.get() self.assertEqual( - application.other_contacts.count(), + domain_request.other_contacts.count(), 0, ) @@ -947,7 +947,7 @@ class DomainRequestTests(TestWithUser, WebTest): ) self.assertEquals( - application.no_other_contacts_rationale, + domain_request.no_other_contacts_rationale, "Hello again!", ) @@ -984,7 +984,7 @@ class DomainRequestTests(TestWithUser, WebTest): def test_delete_other_contact(self): """Other contacts can be deleted after being saved to database. - This formset uses the DJANGO DELETE widget. We'll test that by setting 2 contacts on an application, + This formset uses the DJANGO DELETE widget. We'll test that by setting 2 contacts on a domain request, loading the form and marking one contact up for deletion.""" # Populate the database with a domain request that # has 2 "other contact" assigned to it @@ -1032,11 +1032,11 @@ class DomainRequestTests(TestWithUser, WebTest): creator=self.user, status="started", ) - application.other_contacts.add(other) - application.other_contacts.add(other2) + domain_request.other_contacts.add(other) + domain_request.other_contacts.add(other2) # prime the form by visiting /edit - self.app.get(reverse("edit-application", kwargs={"id": application.pk})) + self.app.get(reverse("edit-application", kwargs={"id": domain_request.pk})) # django-webtest does not handle cookie-based sessions well because it keeps # resetting the session key on each new request, thus destroying the concept # of a "session". We are going to do it manually, saving the session ID here @@ -1061,9 +1061,9 @@ class DomainRequestTests(TestWithUser, WebTest): self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) # Verify that the first dude was deleted - application = DomainRequest.objects.get() - self.assertEqual(application.other_contacts.count(), 1) - self.assertEqual(application.other_contacts.first().first_name, "Testy3") + domain_request = DomainRequest.objects.get() + self.assertEqual(domain_request.other_contacts.count(), 1) + self.assertEqual(domain_request.other_contacts.first().first_name, "Testy3") def test_delete_other_contact_does_not_allow_zero_contacts(self): """Delete Other Contact does not allow submission with zero contacts.""" @@ -1106,10 +1106,10 @@ class DomainRequestTests(TestWithUser, WebTest): creator=self.user, status="started", ) - application.other_contacts.add(other) + domain_request.other_contacts.add(other) # prime the form by visiting /edit - self.app.get(reverse("edit-application", kwargs={"id": application.pk})) + self.app.get(reverse("edit-application", kwargs={"id": domain_request.pk})) # django-webtest does not handle cookie-based sessions well because it keeps # resetting the session key on each new request, thus destroying the concept # of a "session". We are going to do it manually, saving the session ID here @@ -1133,9 +1133,9 @@ class DomainRequestTests(TestWithUser, WebTest): self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id) # Verify that the contact was not deleted - application = DomainRequest.objects.get() - self.assertEqual(application.other_contacts.count(), 1) - self.assertEqual(application.other_contacts.first().first_name, "Testy2") + domain_request = DomainRequest.objects.get() + self.assertEqual(domain_request.other_contacts.count(), 1) + self.assertEqual(domain_request.other_contacts.first().first_name, "Testy2") def test_delete_other_contact_sets_visible_empty_form_as_required_after_failed_submit(self): """When you: @@ -1183,10 +1183,10 @@ class DomainRequestTests(TestWithUser, WebTest): creator=self.user, status="started", ) - application.other_contacts.add(other) + domain_request.other_contacts.add(other) # prime the form by visiting /edit - self.app.get(reverse("edit-application", kwargs={"id": application.pk})) + self.app.get(reverse("edit-application", kwargs={"id": domain_request.pk})) # django-webtest does not handle cookie-based sessions well because it keeps # resetting the session key on each new request, thus destroying the concept # of a "session". We are going to do it manually, saving the session ID here @@ -1259,14 +1259,14 @@ class DomainRequestTests(TestWithUser, WebTest): creator=self.user, status="started", ) - application.other_contacts.add(other) + domain_request.other_contacts.add(other) # other_contact_pk is the initial pk of the other contact. set it before update # to be able to verify after update that the same contact object is in place other_contact_pk = other.id # prime the form by visiting /edit - self.app.get(reverse("edit-application", kwargs={"id": application.pk})) + self.app.get(reverse("edit-application", kwargs={"id": domain_request.pk})) # django-webtest does not handle cookie-based sessions well because it keeps # resetting the session key on each new request, thus destroying the concept # of a "session". We are going to do it manually, saving the session ID here @@ -1288,10 +1288,10 @@ class DomainRequestTests(TestWithUser, WebTest): # Submit the updated form other_contacts_form.submit() - application.refresh_from_db() + domain_request.refresh_from_db() # assert that the Other Contact is updated "in place" - other_contact = application.other_contacts.all()[0] + other_contact = domain_request.other_contacts.all()[0] self.assertEquals(other_contact_pk, other_contact.id) self.assertEquals("Testy3", other_contact.first_name) @@ -1334,7 +1334,7 @@ class DomainRequestTests(TestWithUser, WebTest): creator=self.user, status="started", ) - application.other_contacts.add(ao) + domain_request.other_contacts.add(ao) # other_contact_pk is the initial pk of the other contact. set it before update # to be able to verify after update that the ao contact is still in place @@ -1342,7 +1342,7 @@ class DomainRequestTests(TestWithUser, WebTest): other_contact_pk = ao.id # prime the form by visiting /edit - self.app.get(reverse("edit-application", kwargs={"id": application.pk})) + self.app.get(reverse("edit-application", kwargs={"id": domain_request.pk})) # django-webtest does not handle cookie-based sessions well because it keeps # resetting the session key on each new request, thus destroying the concept # of a "session". We are going to do it manually, saving the session ID here @@ -1364,15 +1364,15 @@ class DomainRequestTests(TestWithUser, WebTest): # Submit the updated form other_contacts_form.submit() - application.refresh_from_db() + domain_request.refresh_from_db() # assert that other contact info is updated, and that a new Contact # is created for the other contact - other_contact = application.other_contacts.all()[0] + other_contact = domain_request.other_contacts.all()[0] self.assertNotEquals(other_contact_pk, other_contact.id) self.assertEquals("Testy2", other_contact.first_name) # assert that the authorizing official is not updated - authorizing_official = application.authorizing_official + authorizing_official = domain_request.authorizing_official self.assertEquals("Testy", authorizing_official.first_name) def test_edit_authorizing_official_in_place(self): @@ -1411,7 +1411,7 @@ class DomainRequestTests(TestWithUser, WebTest): ao_pk = ao.id # prime the form by visiting /edit - self.app.get(reverse("edit-application", kwargs={"id": application.pk})) + self.app.get(reverse("edit-application", kwargs={"id": domain_request.pk})) # django-webtest does not handle cookie-based sessions well because it keeps # resetting the session key on each new request, thus destroying the concept # of a "session". We are going to do it manually, saving the session ID here @@ -1433,10 +1433,10 @@ class DomainRequestTests(TestWithUser, WebTest): # Submit the updated form ao_form.submit() - application.refresh_from_db() + domain_request.refresh_from_db() # assert AO is updated "in place" - updated_ao = application.authorizing_official + updated_ao = domain_request.authorizing_official self.assertEquals(ao_pk, updated_ao.id) self.assertEquals("Testy2", updated_ao.first_name) @@ -1471,7 +1471,7 @@ class DomainRequestTests(TestWithUser, WebTest): creator=self.user, status="started", ) - application.other_contacts.add(ao) + domain_request.other_contacts.add(ao) # ao_pk is the initial pk of the authorizing official. set it before update # to be able to verify after update that the other contact is still in place @@ -1479,7 +1479,7 @@ class DomainRequestTests(TestWithUser, WebTest): ao_pk = ao.id # prime the form by visiting /edit - self.app.get(reverse("edit-application", kwargs={"id": application.pk})) + self.app.get(reverse("edit-application", kwargs={"id": domain_request.pk})) # django-webtest does not handle cookie-based sessions well because it keeps # resetting the session key on each new request, thus destroying the concept # of a "session". We are going to do it manually, saving the session ID here @@ -1501,15 +1501,15 @@ class DomainRequestTests(TestWithUser, WebTest): # Submit the updated form ao_form.submit() - application.refresh_from_db() + domain_request.refresh_from_db() # assert that the other contact is not updated - other_contacts = application.other_contacts.all() + other_contacts = domain_request.other_contacts.all() other_contact = other_contacts[0] self.assertEquals(ao_pk, other_contact.id) self.assertEquals("Testy", other_contact.first_name) # assert that the authorizing official is updated - authorizing_official = application.authorizing_official + authorizing_official = domain_request.authorizing_official self.assertEquals("Testy2", authorizing_official.first_name) def test_edit_submitter_in_place(self): @@ -1548,7 +1548,7 @@ class DomainRequestTests(TestWithUser, WebTest): submitter_pk = you.id # prime the form by visiting /edit - self.app.get(reverse("edit-application", kwargs={"id": application.pk})) + self.app.get(reverse("edit-application", kwargs={"id": domain_request.pk})) # django-webtest does not handle cookie-based sessions well because it keeps # resetting the session key on each new request, thus destroying the concept # of a "session". We are going to do it manually, saving the session ID here @@ -1570,9 +1570,9 @@ class DomainRequestTests(TestWithUser, WebTest): # Submit the updated form your_contact_form.submit() - application.refresh_from_db() + domain_request.refresh_from_db() - updated_submitter = application.submitter + updated_submitter = domain_request.submitter self.assertEquals(submitter_pk, updated_submitter.id) self.assertEquals("Testy2", updated_submitter.first_name) @@ -1607,7 +1607,7 @@ class DomainRequestTests(TestWithUser, WebTest): creator=self.user, status="started", ) - application.other_contacts.add(submitter) + domain_request.other_contacts.add(submitter) # submitter_pk is the initial pk of the your contact. set it before update # to be able to verify after update that the other contact is still in place @@ -1615,7 +1615,7 @@ class DomainRequestTests(TestWithUser, WebTest): submitter_pk = submitter.id # prime the form by visiting /edit - self.app.get(reverse("edit-application", kwargs={"id": application.pk})) + self.app.get(reverse("edit-application", kwargs={"id": domain_request.pk})) # django-webtest does not handle cookie-based sessions well because it keeps # resetting the session key on each new request, thus destroying the concept # of a "session". We are going to do it manually, saving the session ID here @@ -1637,18 +1637,18 @@ class DomainRequestTests(TestWithUser, WebTest): # Submit the updated form your_contact_form.submit() - application.refresh_from_db() + domain_request.refresh_from_db() # assert that the other contact is not updated - other_contacts = application.other_contacts.all() + other_contacts = domain_request.other_contacts.all() other_contact = other_contacts[0] self.assertEquals(submitter_pk, other_contact.id) self.assertEquals("Testy", other_contact.first_name) # assert that the submitter is updated - submitter = application.submitter + submitter = domain_request.submitter self.assertEquals("Testy2", submitter.first_name) - def test_application_about_your_organiztion_interstate(self): + def test_domain_request_about_your_organiztion_interstate(self): """Special districts have to answer an additional question.""" intro_page = self.app.get(reverse("application:")) # django-webtest does not handle cookie-based sessions well because it keeps @@ -1676,7 +1676,7 @@ class DomainRequestTests(TestWithUser, WebTest): self.assertContains(contact_page, self.TITLES[Step.ABOUT_YOUR_ORGANIZATION]) - def test_application_tribal_government(self): + def test_domain_request_tribal_government(self): """Tribal organizations have to answer an additional question.""" intro_page = self.app.get(reverse("application:")) # django-webtest does not handle cookie-based sessions well because it keeps @@ -1707,7 +1707,7 @@ class DomainRequestTests(TestWithUser, WebTest): # and the step is on the sidebar list. self.assertContains(tribal_government_page, self.TITLES[Step.TRIBAL_GOVERNMENT]) - def test_application_ao_dynamic_text(self): + def test_domain_request_ao_dynamic_text(self): intro_page = self.app.get(reverse("application:")) # django-webtest does not handle cookie-based sessions well because it keeps # resetting the session key on each new request, thus destroying the concept @@ -1778,7 +1778,7 @@ class DomainRequestTests(TestWithUser, WebTest): ao_page = election_page.click(str(self.TITLES["authorizing_official"]), index=0) self.assertContains(ao_page, "Domain requests from cities") - def test_application_dotgov_domain_dynamic_text(self): + def test_domain_request_dotgov_domain_dynamic_text(self): intro_page = self.app.get(reverse("application:")) # django-webtest does not handle cookie-based sessions well because it keeps # resetting the session key on each new request, thus destroying the concept @@ -1879,7 +1879,7 @@ class DomainRequestTests(TestWithUser, WebTest): self.assertContains(dotgov_page, "CityofEudoraKS.gov") self.assertNotContains(dotgov_page, "medicare.gov") - def test_application_formsets(self): + def test_domain_request_formsets(self): """Users are able to add more than one of some fields.""" current_sites_page = self.app.get(reverse("application:current_sites")) session_id = self.app.cookies[settings.SESSION_COOKIE_NAME] @@ -1900,14 +1900,14 @@ class DomainRequestTests(TestWithUser, WebTest): self.assertEqual(value, "https://example.com") self.assertIn("current_sites-1-website", current_sites_form.fields) # and it is correctly referenced in the ManyToOne relationship - application = DomainRequest.objects.get() # there's only one + domain_request = DomainRequest.objects.get() # there's only one self.assertEqual( - application.current_websites.filter(website="https://example.com").count(), + domain_request.current_websites.filter(website="https://example.com").count(), 1, ) @skip("WIP") - def test_application_edit_restore(self): + def test_domain_request_edit_restore(self): """ Test that a previously saved application is available at the /edit endpoint. """ @@ -1950,12 +1950,12 @@ class DomainRequestTests(TestWithUser, WebTest): submitter=you, creator=self.user, ) - application.other_contacts.add(other) - application.current_websites.add(current) - application.alternative_domains.add(alt) + domain_request.other_contacts.add(other) + domain_request.current_websites.add(current) + domain_request.alternative_domains.add(alt) # prime the form by visiting /edit - url = reverse("edit-application", kwargs={"id": application.pk}) + url = reverse("edit-application", kwargs={"id": domain_request.pk}) response = self.client.get(url) # TODO: this is a sketch of each page in the wizard which needs to be tested @@ -2033,9 +2033,9 @@ class DomainRequestTests(TestWithUser, WebTest): # page = self.app.get(url) # self.assertNotContains(page, "VALUE") - def test_long_org_name_in_application(self): + def test_long_org_name_in_domain_request(self): """ - Make sure the long name is displaying in the application form, + Make sure the long name is displaying in the domain request form, org step """ intro_page = self.app.get(reverse("application:")) @@ -2074,10 +2074,10 @@ class DomainRequestTestDifferentStatuses(TestWithUser, WebTest): self.app.set_user(self.user.username) self.client.force_login(self.user) - def test_application_status(self): + def test_domain_request_status(self): """Checking application status page""" - application = completed_application(status=DomainRequest.ApplicationStatus.SUBMITTED, user=self.user) - application.save() + domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.SUBMITTED, user=self.user) + domain_request.save() home_page = self.app.get("/") self.assertContains(home_page, "city.gov") @@ -2090,14 +2090,14 @@ class DomainRequestTestDifferentStatuses(TestWithUser, WebTest): self.assertContains(detail_page, "Admin Tester") self.assertContains(detail_page, "Status:") - def test_application_status_with_ineligible_user(self): + def test_domain_request_status_with_ineligible_user(self): """Checking application status page whith a blocked user. The user should still have access to view.""" self.user.status = "ineligible" self.user.save() - application = completed_application(status=DomainRequest.ApplicationStatus.SUBMITTED, user=self.user) - application.save() + domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.SUBMITTED, user=self.user) + domain_request.save() home_page = self.app.get("/") self.assertContains(home_page, "city.gov") @@ -2109,10 +2109,10 @@ class DomainRequestTestDifferentStatuses(TestWithUser, WebTest): self.assertContains(detail_page, "Admin Tester") self.assertContains(detail_page, "Status:") - def test_application_withdraw(self): + def test_domain_request_withdraw(self): """Checking application status page""" - application = completed_application(status=DomainRequest.ApplicationStatus.SUBMITTED, user=self.user) - application.save() + domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.SUBMITTED, user=self.user) + domain_request.save() home_page = self.app.get("/") self.assertContains(home_page, "city.gov") @@ -2142,12 +2142,12 @@ class DomainRequestTestDifferentStatuses(TestWithUser, WebTest): home_page = self.app.get("/") self.assertContains(home_page, "Withdrawn") - def test_application_withdraw_no_permissions(self): + def test_domain_request_withdraw_no_permissions(self): """Can't withdraw applications as a restricted user.""" self.user.status = User.RESTRICTED self.user.save() - application = completed_application(status=DomainRequest.ApplicationStatus.SUBMITTED, user=self.user) - application.save() + domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.SUBMITTED, user=self.user) + domain_request.save() home_page = self.app.get("/") self.assertContains(home_page, "city.gov") @@ -2166,16 +2166,16 @@ class DomainRequestTestDifferentStatuses(TestWithUser, WebTest): "application-withdrawn", ]: with self.subTest(url_name=url_name): - page = self.client.get(reverse(url_name, kwargs={"pk": application.pk})) + page = self.client.get(reverse(url_name, kwargs={"pk": domain_request.pk})) self.assertEqual(page.status_code, 403) - def test_application_status_no_permissions(self): + def test_domain_request_status_no_permissions(self): """Can't access applications without being the creator.""" - application = completed_application(status=DomainRequest.ApplicationStatus.SUBMITTED, user=self.user) + domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.SUBMITTED, user=self.user) other_user = User() other_user.save() - application.creator = other_user - application.save() + domain_request.creator = other_user + domain_request.save() # PermissionDeniedErrors make lots of noise in test output with less_console_noise(): @@ -2185,14 +2185,14 @@ class DomainRequestTestDifferentStatuses(TestWithUser, WebTest): "application-withdrawn", ]: with self.subTest(url_name=url_name): - page = self.client.get(reverse(url_name, kwargs={"pk": application.pk})) + page = self.client.get(reverse(url_name, kwargs={"pk": domain_request.pk})) self.assertEqual(page.status_code, 403) - def test_approved_application_not_in_active_requests(self): + def test_approved_domain_request_not_in_active_requests(self): """An approved application is not shown in the Active Requests table on home.html.""" - application = completed_application(status=DomainRequest.ApplicationStatus.APPROVED, user=self.user) - application.save() + domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.APPROVED, user=self.user) + domain_request.save() home_page = self.app.get("/") # This works in our test environment because creating @@ -2206,23 +2206,23 @@ class TestWizardUnlockingSteps(TestWithUser, WebTest): def setUp(self): super().setUp() self.app.set_user(self.user.username) - self.wizard = ApplicationWizard() + self.wizard = DomainRequestWizard() # Mock the request object, its user, and session attributes appropriately self.wizard.request = Mock(user=self.user, session={}) def tearDown(self): super().tearDown() - def test_unlocked_steps_empty_application(self): + def test_unlocked_steps_empty_domain_request(self): """Test when all fields in the application are empty.""" unlocked_steps = self.wizard.db_check_for_unlocking_steps() expected_dict = [] self.assertEqual(unlocked_steps, expected_dict) - def test_unlocked_steps_full_application(self): + def test_unlocked_steps_full_domain_request(self): """Test when all fields in the application are filled.""" - completed_application(status=DomainRequest.ApplicationStatus.STARTED, user=self.user) + completed_domain_request(status=DomainRequest.DomainRequestStatus.STARTED, user=self.user) # Make a request to the home page home_page = self.app.get("/") # django-webtest does not handle cookie-based sessions well because it keeps @@ -2262,7 +2262,7 @@ class TestWizardUnlockingSteps(TestWithUser, WebTest): else: self.fail(f"Expected a redirect, but got a different response: {response}") - def test_unlocked_steps_partial_application(self): + def test_unlocked_steps_partial_domain_request(self): """Test when some fields in the application are filled.""" # Create the site and contacts to delete (orphaned) @@ -2280,14 +2280,14 @@ class TestWizardUnlockingSteps(TestWithUser, WebTest): contact_user, _ = Contact.objects.get_or_create(user=self.user) site = DraftDomain.objects.create(name="igorville.gov") - application = DomainRequest.objects.create( + domain_request = DomainRequest.objects.create( creator=self.user, requested_domain=site, - status=DomainRequest.ApplicationStatus.WITHDRAWN, + status=DomainRequest.DomainRequestStatus.WITHDRAWN, authorizing_official=contact, submitter=contact_user, ) - application.other_contacts.set([contact_2]) + domain_request.other_contacts.set([contact_2]) # Make a request to the home page home_page = self.app.get("/") @@ -2345,14 +2345,14 @@ class HomeTests(TestWithUser): response = self.client.get("/") self.assertNotContains(response, "igorville.gov") site = DraftDomain.objects.create(name="igorville.gov") - application = DomainRequest.objects.create(creator=self.user, requested_domain=site) + domain_request = DomainRequest.objects.create(creator=self.user, requested_domain=site) response = self.client.get("/") # count = 7 because of screenreader content self.assertContains(response, "igorville.gov", count=7) # clean up - application.delete() + domain_request.delete() def test_state_help_text(self): """Tests if each domain state has help text""" @@ -2468,8 +2468,8 @@ class HomeTests(TestWithUser): """Tests if the user can delete a DomainRequest in the 'withdrawn' status""" site = DraftDomain.objects.create(name="igorville.gov") - application = DomainRequest.objects.create( - creator=self.user, requested_domain=site, status=DomainRequest.ApplicationStatus.WITHDRAWN + domain_request = DomainRequest.objects.create( + creator=self.user, requested_domain=site, status=DomainRequest.DomainRequestStatus.WITHDRAWN ) # Ensure that igorville.gov exists on the page @@ -2481,19 +2481,19 @@ class HomeTests(TestWithUser): self.assertContains(home_page, "button-toggle-delete-domain-alert-1") # Trigger the delete logic - response = self.client.post(reverse("application-delete", kwargs={"pk": application.pk}), follow=True) + response = self.client.post(reverse("application-delete", kwargs={"pk": domain_request.pk}), follow=True) self.assertNotContains(response, "igorville.gov") # clean up - application.delete() + domain_request.delete() def test_home_deletes_started_domain_request(self): """Tests if the user can delete a DomainRequest in the 'started' status""" site = DraftDomain.objects.create(name="igorville.gov") - application = DomainRequest.objects.create( - creator=self.user, requested_domain=site, status=DomainRequest.ApplicationStatus.STARTED + domain_request = DomainRequest.objects.create( + creator=self.user, requested_domain=site, status=DomainRequest.DomainRequestStatus.STARTED ) # Ensure that igorville.gov exists on the page @@ -2505,12 +2505,12 @@ class HomeTests(TestWithUser): self.assertContains(home_page, "button-toggle-delete-domain-alert-1") # Trigger the delete logic - response = self.client.post(reverse("application-delete", kwargs={"pk": application.pk}), follow=True) + response = self.client.post(reverse("application-delete", kwargs={"pk": domain_request.pk}), follow=True) self.assertNotContains(response, "igorville.gov") # clean up - application.delete() + domain_request.delete() def test_home_doesnt_delete_other_domain_requests(self): """Tests to ensure the user can't delete Applications not in the status of STARTED or WITHDRAWN""" @@ -2519,31 +2519,31 @@ class HomeTests(TestWithUser): # subTest is appropriate here as otherwise we would need many duplicate tests for the same reason. with less_console_noise(): draft_domain = DraftDomain.objects.create(name="igorville.gov") - for status in DomainRequest.ApplicationStatus: + for status in DomainRequest.DomainRequestStatus: if status not in [ - DomainRequest.ApplicationStatus.STARTED, - DomainRequest.ApplicationStatus.WITHDRAWN, + DomainRequest.DomainRequestStatus.STARTED, + DomainRequest.DomainRequestStatus.WITHDRAWN, ]: with self.subTest(status=status): - application = DomainRequest.objects.create( + domain_request = DomainRequest.objects.create( creator=self.user, requested_domain=draft_domain, status=status ) # Trigger the delete logic response = self.client.post( - reverse("application-delete", kwargs={"pk": application.pk}), follow=True + reverse("application-delete", kwargs={"pk": domain_request.pk}), follow=True ) # Check for a 403 error - the end user should not be allowed to do this self.assertEqual(response.status_code, 403) - desired_application = DomainRequest.objects.filter(requested_domain=draft_domain) + desired_domain_request = DomainRequest.objects.filter(requested_domain=draft_domain) # Make sure the DomainRequest wasn't deleted - self.assertEqual(desired_application.count(), 1) + self.assertEqual(desired_domain_request.count(), 1) # clean up - application.delete() + domain_request.delete() def test_home_deletes_domain_request_and_orphans(self): """Tests if delete for DomainRequest deletes orphaned Contact objects""" @@ -2568,32 +2568,32 @@ class HomeTests(TestWithUser): contact_user, _ = Contact.objects.get_or_create(user=self.user) site = DraftDomain.objects.create(name="igorville.gov") - application = DomainRequest.objects.create( + domain_request = DomainRequest.objects.create( creator=self.user, requested_domain=site, - status=DomainRequest.ApplicationStatus.WITHDRAWN, + status=DomainRequest.DomainRequestStatus.WITHDRAWN, authorizing_official=contact, submitter=contact_user, ) - application.other_contacts.set([contact_2]) + domain_request.other_contacts.set([contact_2]) # Create a second application to attach contacts to site_2 = DraftDomain.objects.create(name="teaville.gov") - application_2 = DomainRequest.objects.create( + domain_request_2 = DomainRequest.objects.create( creator=self.user, requested_domain=site_2, - status=DomainRequest.ApplicationStatus.STARTED, + status=DomainRequest.DomainRequestStatus.STARTED, authorizing_official=contact_2, submitter=contact_shared, ) - application_2.other_contacts.set([contact_shared]) + domain_request_2.other_contacts.set([contact_shared]) # Ensure that igorville.gov exists on the page home_page = self.client.get("/") self.assertContains(home_page, "igorville.gov") # Trigger the delete logic - response = self.client.post(reverse("application-delete", kwargs={"pk": application.pk}), follow=True) + response = self.client.post(reverse("application-delete", kwargs={"pk": domain_request.pk}), follow=True) # igorville is now deleted self.assertNotContains(response, "igorville.gov") @@ -2640,31 +2640,31 @@ class HomeTests(TestWithUser): contact_user, _ = Contact.objects.get_or_create(user=self.user) site = DraftDomain.objects.create(name="igorville.gov") - application = DomainRequest.objects.create( + domain_request = DomainRequest.objects.create( creator=self.user, requested_domain=site, - status=DomainRequest.ApplicationStatus.WITHDRAWN, + status=DomainRequest.DomainRequestStatus.WITHDRAWN, authorizing_official=contact, submitter=contact_user, ) - application.other_contacts.set([contact_2]) + domain_request.other_contacts.set([contact_2]) # Create a second application to attach contacts to site_2 = DraftDomain.objects.create(name="teaville.gov") - application_2 = DomainRequest.objects.create( + domain_request_2 = DomainRequest.objects.create( creator=self.user, requested_domain=site_2, - status=DomainRequest.ApplicationStatus.STARTED, + status=DomainRequest.DomainRequestStatus.STARTED, authorizing_official=contact_2, submitter=contact_shared, ) - application_2.other_contacts.set([contact_shared]) + domain_request_2.other_contacts.set([contact_shared]) home_page = self.client.get("/") self.assertContains(home_page, "teaville.gov") # Trigger the delete logic - response = self.client.post(reverse("application-delete", kwargs={"pk": application_2.pk}), follow=True) + response = self.client.post(reverse("application-delete", kwargs={"pk": domain_request_2.pk}), follow=True) self.assertNotContains(response, "teaville.gov") @@ -2672,7 +2672,7 @@ class HomeTests(TestWithUser): orphan = Contact.objects.filter(id=contact_shared.id) self.assertFalse(orphan.exists()) - def test_application_form_view(self): + def test_domain_request_form_view(self): response = self.client.get("/request/", follow=True) self.assertContains( response, @@ -2680,8 +2680,8 @@ class HomeTests(TestWithUser): ) def test_domain_request_form_with_ineligible_user(self): - """Application form not accessible for an ineligible user. - This test should be solid enough since all application wizard + """Domain request form not accessible for an ineligible user. + This test should be solid enough since all domain request wizard views share the same permissions class""" self.user.status = User.RESTRICTED self.user.save() diff --git a/src/registrar/tests/test_views_domain.py b/src/registrar/tests/test_views_domain.py index 90b987020..9b71da02e 100644 --- a/src/registrar/tests/test_views_domain.py +++ b/src/registrar/tests/test_views_domain.py @@ -309,7 +309,7 @@ class TestDomainDetail(TestDomainOverview): self.assertContains(detail_page, "(1.2.3.4,") self.assertContains(detail_page, "2.3.4.5)") - def test_domain_detail_with_no_information_or_application(self): + def test_domain_detail_with_no_information_or_domain_request(self): """Test that domain management page returns 200 and displays error when no domain information or domain request exist""" with less_console_noise(): diff --git a/src/registrar/views/__init__.py b/src/registrar/views/__init__.py index 8785c9076..bd15196d4 100644 --- a/src/registrar/views/__init__.py +++ b/src/registrar/views/__init__.py @@ -1,4 +1,4 @@ -from .application import * +from .domain_request import * from .domain import ( DomainView, DomainAuthorizingOfficialView, diff --git a/src/registrar/views/application.py b/src/registrar/views/domain_request.py similarity index 75% rename from src/registrar/views/application.py rename to src/registrar/views/domain_request.py index 4c3ffe306..49869c99e 100644 --- a/src/registrar/views/application.py +++ b/src/registrar/views/domain_request.py @@ -8,7 +8,7 @@ from django.utils.translation import gettext_lazy as _ from django.views.generic import TemplateView from django.contrib import messages -from registrar.forms import application_wizard as forms +from registrar.forms import domain_request_wizard as forms from registrar.models import DomainRequest from registrar.models.contact import Contact from registrar.models.user import User @@ -19,7 +19,7 @@ from registrar.views.utility.permission_views import DomainRequestPermissionDele from .utility import ( DomainRequestPermissionView, DomainRequestPermissionWithdrawView, - ApplicationWizardPermissionView, + DomainRequestWizardPermissionView, ) logger = logging.getLogger(__name__) @@ -27,7 +27,7 @@ logger = logging.getLogger(__name__) class Step(StrEnum): """ - Names for each page of the application wizard. + Names for each page of the domain request wizard. As with Django's own `TextChoices` class, steps will appear in the order they are defined. (Order matters.) @@ -50,7 +50,7 @@ class Step(StrEnum): REVIEW = "review" -class ApplicationWizard(ApplicationWizardPermissionView, TemplateView): +class DomainRequestWizard(DomainRequestWizardPermissionView, TemplateView): """ A common set of methods and configuration. @@ -58,7 +58,7 @@ class ApplicationWizard(ApplicationWizardPermissionView, TemplateView): Together, these steps constitute a "wizard". This base class sets up a shared state (stored in the user's session) - between pages of the application and provides common methods for + between pages of the domain request and provides common methods for processing form data. Views for each step should inherit from this base class. @@ -73,7 +73,7 @@ class ApplicationWizard(ApplicationWizardPermissionView, TemplateView): # (this is not seen _in_ urls, only for Django's internal naming) # NB: this is included here for reference. Do not change it without # also changing the many places it is hardcoded in the HTML templates - URL_NAMESPACE = "application" + URL_NAMESPACE = "domain_request" # name for accessing /application//edit EDIT_URL_NAME = "edit-application" NEW_URL_NAME = "/request/" @@ -108,28 +108,28 @@ class ApplicationWizard(ApplicationWizardPermissionView, TemplateView): def __init__(self): super().__init__() self.steps = StepsHelper(self) - self._application = None # for caching + self._domain_request = None # for caching def has_pk(self): """Does this wizard know about a DomainRequest database record?""" - return "application_id" in self.storage + return "domain_request_id" in self.storage @property def prefix(self): """Namespace the wizard to avoid clashes in session variable names.""" # this is a string literal but can be made dynamic if we'd like # users to have multiple applications open for editing simultaneously - return "wizard_application" + return "wizard_domain_request" @property def application(self) -> DomainRequest: """ Attempt to match the current wizard with a DomainRequest. - Will create an application if none exists. + Will create a domain request if none exists. """ - if self._application: - return self._application + if self._domain_request: + return self._domain_request # For linter. The else block should never be hit, but if it does, # there may be a UI consideration. That will need to be handled in another ticket. @@ -140,20 +140,20 @@ class ApplicationWizard(ApplicationWizardPermissionView, TemplateView): raise ValueError("Invalid value for User") if self.has_pk(): - id = self.storage["application_id"] + id = self.storage["domain_request_id"] try: - self._application = DomainRequest.objects.get( + self._domain_request = DomainRequest.objects.get( creator=creator, pk=id, ) - return self._application + return self._domain_request except DomainRequest.DoesNotExist: logger.debug("Application id %s did not have a DomainRequest" % id) - self._application = DomainRequest.objects.create(creator=self.request.user) + self._domain_request = DomainRequest.objects.create(creator=self.request.user) - self.storage["application_id"] = self._application.id - return self._application + self.storage["domain_request_id"] = self._domain_request.id + return self._domain_request @property def storage(self): @@ -179,9 +179,9 @@ class ApplicationWizard(ApplicationWizardPermissionView, TemplateView): def done(self): """Called when the user clicks the submit button, if all forms are valid.""" - self.application.submit() # change the status to submitted - self.application.save() - logger.debug("Application object saved: %s", self.application.id) + self.domain_request.submit() # change the status to submitted + self.domain_request.save() + logger.debug("Application object saved: %s", self.domain_request.id) return redirect(reverse(f"{self.URL_NAMESPACE}:finished")) def from_model(self, attribute: str, default, *args, **kwargs): @@ -214,20 +214,20 @@ class ApplicationWizard(ApplicationWizardPermissionView, TemplateView): # and remove any prior wizard data from their session if current_url == self.EDIT_URL_NAME and "id" in kwargs: del self.storage - self.storage["application_id"] = kwargs["id"] + self.storage["domain_request_id"] = kwargs["id"] self.storage["step_history"] = self.db_check_for_unlocking_steps() # if accessing this class directly, redirect to the first step - # in other words, if `ApplicationWizard` is called as view + # in other words, if `DomainRequestWizard` is called as view # directly by some redirect or url handler, we'll send users # either to an acknowledgement page or to the first step in # the processes (if an edit rather than a new request); subclasses # will NOT be redirected. The purpose of this is to allow code to - # send users "to the application wizard" without needing to + # send users "to the domain request wizard" without needing to # know which view is first in the list of steps. - if self.__class__ == ApplicationWizard: + if self.__class__ == DomainRequestWizard: if request.path_info == self.NEW_URL_NAME: - return render(request, "application_intro.html") + return render(request, "domain_request_intro.html") else: return self.goto(self.steps.first) @@ -278,7 +278,7 @@ class ApplicationWizard(ApplicationWizardPermissionView, TemplateView): kwargs = { "files": files, "prefix": self.steps.current, - "application": self.application, # this is a property, not an object + "domain_request": self.application, # this is a property, not an object } if step is None: @@ -303,72 +303,72 @@ class ApplicationWizard(ApplicationWizardPermissionView, TemplateView): def pending_requests(self): """return an array of pending requests if user has pending requests and no approved requests""" - if self.approved_applications_exist() or self.approved_domains_exist(): + if self.approved_domain_requests_exist() or self.approved_domains_exist(): return [] else: - return self.pending_applications() + return self.pending_domain_requests() - def approved_applications_exist(self): - """Checks if user is creator of applications with ApplicationStatus.APPROVED status""" - approved_application_count = DomainRequest.objects.filter( - creator=self.request.user, status=DomainRequest.ApplicationStatus.APPROVED + def approved_domain_requests_exist(self): + """Checks if user is creator of applications with DomainRequestStatus.APPROVED status""" + approved_domain_request_count = DomainRequest.objects.filter( + creator=self.request.user, status=DomainRequest.DomainRequestStatus.APPROVED ).count() - return approved_application_count > 0 + return approved_domain_request_count > 0 def approved_domains_exist(self): """Checks if user has permissions on approved domains This additional check is necessary to account for domains which were migrated - and do not have an application""" + and do not have a domain request""" return self.request.user.permissions.count() > 0 - def pending_applications(self): + def pending_domain_requests(self): """Returns a List of user's applications with one of the following states: - ApplicationStatus.SUBMITTED, ApplicationStatus.IN_REVIEW, ApplicationStatus.ACTION_NEEDED""" - # if the current application has ApplicationStatus.ACTION_NEEDED status, this check should not be performed - if self.application.status == DomainRequest.ApplicationStatus.ACTION_NEEDED: + DomainRequestStatus.SUBMITTED, DomainRequestStatus.IN_REVIEW, DomainRequestStatus.ACTION_NEEDED""" + # if the current application has DomainRequestStatus.ACTION_NEEDED status, this check should not be performed + if self.domain_request.status == DomainRequest.DomainRequestStatus.ACTION_NEEDED: return [] check_statuses = [ - DomainRequest.ApplicationStatus.SUBMITTED, - DomainRequest.ApplicationStatus.IN_REVIEW, - DomainRequest.ApplicationStatus.ACTION_NEEDED, + DomainRequest.DomainRequestStatus.SUBMITTED, + DomainRequest.DomainRequestStatus.IN_REVIEW, + DomainRequest.DomainRequestStatus.ACTION_NEEDED, ] return DomainRequest.objects.filter(creator=self.request.user, status__in=check_statuses) def db_check_for_unlocking_steps(self): """Helper for get_context_data - Queries the DB for an application and returns a list of unlocked steps.""" + Queries the DB for a domain request and returns a list of unlocked steps.""" history_dict = { - "organization_type": self.application.organization_type is not None, - "tribal_government": self.application.tribe_name is not None, - "organization_federal": self.application.federal_type is not None, - "organization_election": self.application.is_election_board is not None, + "organization_type": self.domain_request.organization_type is not None, + "tribal_government": self.domain_request.tribe_name is not None, + "organization_federal": self.domain_request.federal_type is not None, + "organization_election": self.domain_request.is_election_board is not None, "organization_contact": ( - self.application.federal_agency is not None - or self.application.organization_name is not None - or self.application.address_line1 is not None - or self.application.city is not None - or self.application.state_territory is not None - or self.application.zipcode is not None - or self.application.urbanization is not None + self.domain_request.federal_agency is not None + or self.domain_request.organization_name is not None + or self.domain_request.address_line1 is not None + or self.domain_request.city is not None + or self.domain_request.state_territory is not None + or self.domain_request.zipcode is not None + or self.domain_request.urbanization is not None ), - "about_your_organization": self.application.about_your_organization is not None, - "authorizing_official": self.application.authorizing_official is not None, + "about_your_organization": self.domain_request.about_your_organization is not None, + "authorizing_official": self.domain_request.authorizing_official is not None, "current_sites": ( - self.application.current_websites.exists() or self.application.requested_domain is not None + self.domain_request.current_websites.exists() or self.domain_request.requested_domain is not None ), - "dotgov_domain": self.application.requested_domain is not None, - "purpose": self.application.purpose is not None, - "your_contact": self.application.submitter is not None, + "dotgov_domain": self.domain_request.requested_domain is not None, + "purpose": self.domain_request.purpose is not None, + "your_contact": self.domain_request.submitter is not None, "other_contacts": ( - self.application.other_contacts.exists() or self.application.no_other_contacts_rationale is not None + self.domain_request.other_contacts.exists() or self.domain_request.no_other_contacts_rationale is not None ), "anything_else": ( - self.application.anything_else is not None or self.application.is_policy_acknowledged is not None + self.domain_request.anything_else is not None or self.domain_request.is_policy_acknowledged is not None ), - "requirements": self.application.is_policy_acknowledged is not None, - "review": self.application.is_policy_acknowledged is not None, + "requirements": self.domain_request.is_policy_acknowledged is not None, + "review": self.domain_request.is_policy_acknowledged is not None, } return [key for key, value in history_dict.items() if value] @@ -377,8 +377,8 @@ class ApplicationWizard(ApplicationWizardPermissionView, TemplateView): # Build the submit button that we'll pass to the modal. modal_button = '" # Concatenate the modal header that we'll pass to the modal. - if self.application.requested_domain: - modal_heading = "You are about to submit a domain request for " + str(self.application.requested_domain) + if self.domain_request.requested_domain: + modal_heading = "You are about to submit a domain request for " + str(self.domain_request.requested_domain) else: modal_heading = "You are about to submit an incomplete request" @@ -387,7 +387,7 @@ class ApplicationWizard(ApplicationWizardPermissionView, TemplateView): "steps": self.steps, # Add information about which steps should be unlocked "visited": self.storage.get("step_history", []), - "is_federal": self.application.is_federal(), + "is_federal": self.domain_request.is_federal(), "modal_button": modal_button, "modal_heading": modal_heading, } @@ -434,7 +434,7 @@ class ApplicationWizard(ApplicationWizardPermissionView, TemplateView): return self.goto(self.steps.first) # if accessing this class directly, redirect to the first step - if self.__class__ == ApplicationWizard: + if self.__class__ == DomainRequestWizard: return self.goto(self.steps.first) forms = self.get_forms(use_post=True) @@ -462,86 +462,86 @@ class ApplicationWizard(ApplicationWizardPermissionView, TemplateView): """ Unpack the form responses onto the model object properties. - Saves the application to the database. + Saves the domain request to the database. """ for form in forms: if form is not None and hasattr(form, "to_database"): form.to_database(self.application) -class OrganizationType(ApplicationWizard): - template_name = "application_org_type.html" +class OrganizationType(DomainRequestWizard): + template_name = "domain_request_org_type.html" forms = [forms.OrganizationTypeForm] -class TribalGovernment(ApplicationWizard): - template_name = "application_tribal_government.html" +class TribalGovernment(DomainRequestWizard): + template_name = "domain_request_tribal_government.html" forms = [forms.TribalGovernmentForm] -class OrganizationFederal(ApplicationWizard): - template_name = "application_org_federal.html" +class OrganizationFederal(DomainRequestWizard): + template_name = "domain_request_org_federal.html" forms = [forms.OrganizationFederalForm] -class OrganizationElection(ApplicationWizard): - template_name = "application_org_election.html" +class OrganizationElection(DomainRequestWizard): + template_name = "domain_request_org_election.html" forms = [forms.OrganizationElectionForm] -class OrganizationContact(ApplicationWizard): - template_name = "application_org_contact.html" +class OrganizationContact(DomainRequestWizard): + template_name = "domain_request_org_contact.html" forms = [forms.OrganizationContactForm] -class AboutYourOrganization(ApplicationWizard): - template_name = "application_about_your_organization.html" +class AboutYourOrganization(DomainRequestWizard): + template_name = "domain_request_about_your_organization.html" forms = [forms.AboutYourOrganizationForm] -class AuthorizingOfficial(ApplicationWizard): - template_name = "application_authorizing_official.html" +class AuthorizingOfficial(DomainRequestWizard): + template_name = "domain_request_authorizing_official.html" forms = [forms.AuthorizingOfficialForm] def get_context_data(self): context = super().get_context_data() - context["organization_type"] = self.application.organization_type - context["federal_type"] = self.application.federal_type + context["organization_type"] = self.domain_request.organization_type + context["federal_type"] = self.domain_request.federal_type return context -class CurrentSites(ApplicationWizard): - template_name = "application_current_sites.html" +class CurrentSites(DomainRequestWizard): + template_name = "domain_request_current_sites.html" forms = [forms.CurrentSitesFormSet] -class DotgovDomain(ApplicationWizard): - template_name = "application_dotgov_domain.html" +class DotgovDomain(DomainRequestWizard): + template_name = "domain_request_dotgov_domain.html" forms = [forms.DotGovDomainForm, forms.AlternativeDomainFormSet] def get_context_data(self): context = super().get_context_data() - context["organization_type"] = self.application.organization_type - context["federal_type"] = self.application.federal_type + context["organization_type"] = self.domain_request.organization_type + context["federal_type"] = self.domain_request.federal_type return context -class Purpose(ApplicationWizard): - template_name = "application_purpose.html" +class Purpose(DomainRequestWizard): + template_name = "domain_request_purpose.html" forms = [forms.PurposeForm] -class YourContact(ApplicationWizard): - template_name = "application_your_contact.html" +class YourContact(DomainRequestWizard): + template_name = "domain_request_your_contact.html" forms = [forms.YourContactForm] -class OtherContacts(ApplicationWizard): - template_name = "application_other_contacts.html" +class OtherContacts(DomainRequestWizard): + template_name = "domain_request_other_contacts.html" forms = [forms.OtherContactsYesNoForm, forms.OtherContactsFormSet, forms.NoOtherContactsForm] def is_valid(self, forms: list) -> bool: - """Overrides default behavior defined in ApplicationWizard. + """Overrides default behavior defined in DomainRequestWizard. Depending on value in other_contacts_yes_no_form, marks forms in other_contacts or no_other_contacts for deletion. Then validates all forms. @@ -580,24 +580,24 @@ class OtherContacts(ApplicationWizard): return all_forms_valid -class AnythingElse(ApplicationWizard): - template_name = "application_anything_else.html" +class AnythingElse(DomainRequestWizard): + template_name = "domain_request_anything_else.html" forms = [forms.AnythingElseForm] -class Requirements(ApplicationWizard): - template_name = "application_requirements.html" +class Requirements(DomainRequestWizard): + template_name = "domain_request_requirements.html" forms = [forms.RequirementsForm] -class Review(ApplicationWizard): - template_name = "application_review.html" +class Review(DomainRequestWizard): + template_name = "domain_request_review.html" forms = [] # type: ignore def get_context_data(self): context = super().get_context_data() context["Step"] = Step.__members__ - context["application"] = self.application + context["domain_request"] = self.application return context def goto_next_step(self): @@ -623,30 +623,30 @@ class Review(ApplicationWizard): # return self.goto(self.steps.current) -class Finished(ApplicationWizard): - template_name = "application_done.html" +class Finished(DomainRequestWizard): + template_name = "domain_request_done.html" forms = [] # type: ignore def get(self, request, *args, **kwargs): context = self.get_context_data() - context["application_id"] = self.application.id + context["domain_request_id"] = self.domain_request.id # clean up this wizard session, because we are done with it del self.storage return render(self.request, self.template_name, context) -class ApplicationStatus(DomainRequestPermissionView): - template_name = "application_status.html" +class DomainRequestStatus(DomainRequestPermissionView): + template_name = "domain_request_status.html" class ApplicationWithdrawConfirmation(DomainRequestPermissionWithdrawView): """This page will ask user to confirm if they want to withdraw The DomainRequestPermissionView restricts access so that only the - `creator` of the application may withdraw it. + `creator` of the domain request may withdraw it. """ - template_name = "application_withdraw_confirmation.html" + template_name = "domain_request_withdraw_confirmation.html" class ApplicationWithdrawn(DomainRequestPermissionWithdrawView): @@ -659,9 +659,9 @@ class ApplicationWithdrawn(DomainRequestPermissionWithdrawView): If user click on withdraw confirm button, this view updates the status to withdraw and send back to homepage. """ - application = DomainRequest.objects.get(id=self.kwargs["pk"]) - application.withdraw() - application.save() + domain_request = DomainRequest.objects.get(id=self.kwargs["pk"]) + domain_request.withdraw() + domain_request.save() return HttpResponseRedirect(reverse("home")) @@ -677,7 +677,7 @@ class DomainRequestDeleteView(DomainRequestPermissionDeleteView): return False status = self.get_object().status - valid_statuses = [DomainRequest.ApplicationStatus.WITHDRAWN, DomainRequest.ApplicationStatus.STARTED] + valid_statuses = [DomainRequest.DomainRequestStatus.WITHDRAWN, DomainRequest.DomainRequestStatus.STARTED] if status not in valid_statuses: return False @@ -707,13 +707,13 @@ class DomainRequestDeleteView(DomainRequestPermissionDeleteView): return response - def _get_orphaned_contacts(self, application: DomainRequest, check_db=False): + def _get_orphaned_contacts(self, domain_request: DomainRequest, check_db=False): """ Collects all orphaned contacts associated with a given DomainRequest object. - An orphaned contact is defined as a contact that is associated with the application, - but not with any other application. This includes the authorizing official, the submitter, - and any other contacts linked to the application. + An orphaned contact is defined as a contact that is associated with the domain request, + but not with any other domain_request. This includes the authorizing official, the submitter, + and any other contacts linked to the domain_request. Parameters: application (DomainRequest): The DomainRequest object for which to find orphaned contacts. @@ -727,10 +727,10 @@ class DomainRequestDeleteView(DomainRequestPermissionDeleteView): contacts_to_delete = [] # Get each contact object on the DomainRequest object - ao = application.authorizing_official - submitter = application.submitter - other_contacts = list(application.other_contacts.all()) - other_contact_ids = application.other_contacts.all().values_list("id", flat=True) + ao = domain_request.authorizing_official + submitter = domain_request.submitter + other_contacts = list(domain_request.other_contacts.all()) + other_contact_ids = domain_request.other_contacts.all().values_list("id", flat=True) # Check if the desired item still exists in the DB if check_db: @@ -739,8 +739,8 @@ class DomainRequestDeleteView(DomainRequestPermissionDeleteView): other_contacts = self._get_contacts_by_id(other_contact_ids) # Pair each contact with its db related name for use in checking if it has joins - checked_contacts = [(ao, "authorizing_official"), (submitter, "submitted_applications")] - checked_contacts.extend((contact, "contact_applications") for contact in other_contacts) + checked_contacts = [(ao, "authorizing_official"), (submitter, "submitted_domain_requests")] + checked_contacts.extend((contact, "contact_domain_requests") for contact in other_contacts) for contact, related_name in checked_contacts: if contact is not None and not contact.has_more_than_one_join(related_name): diff --git a/src/registrar/views/index.py b/src/registrar/views/index.py index c14341109..1306b4cef 100644 --- a/src/registrar/views/index.py +++ b/src/registrar/views/index.py @@ -7,8 +7,8 @@ def index(request): """This page is available to anyone without logging in.""" context = {} if request.user.is_authenticated: - # Get all domain applications the user has access to - applications, deletable_applications = _get_applications(request) + # Get all domain requests the user has access to + applications, deletable_domain_requests = _get_domain_requests(request) context["domain_requests"] = applications @@ -17,11 +17,11 @@ def index(request): context["domains"] = domains # Determine if the user will see applications that they can delete - has_deletable_applications = deletable_applications.exists() - context["has_deletable_applications"] = has_deletable_applications + has_deletable_domain_requests = deletable_domain_requests.exists() + context["has_deletable_domain_requests"] = has_deletable_domain_requests # If they can delete applications, add the delete button to the context - if has_deletable_applications: + if has_deletable_domain_requests: # Add the delete modal button to the context modal_button = ( '
{% if domain_request.requested_domain is None %} @@ -143,7 +143,7 @@ {% with date=domain_request.created_at|date:"DATETIME_FORMAT"%} {% with name_default=prefix|add:date|add:" UTC)"%} {% if domain_request.status == domain_request.DomainRequestStatus.STARTED or domain_request.status == domain_request.DomainRequestStatus.ACTION_NEEDED or domain_request.status == domain_request.DomainRequestStatus.WITHDRAWN %} - + @@ -153,7 +153,7 @@ Edit {{ name_default }} {% endif %} {% else %} - + @@ -198,7 +198,7 @@ aria-describedby="Domain will be removed" data-force-action > - + {% if domain_request.requested_domain is None %} {% if domain_request.created_at %} {% with prefix="(created " %} @@ -231,7 +231,7 @@ > {% else %}

You haven't requested any domains.

- + {% endif %} diff --git a/src/registrar/tests/common.py b/src/registrar/tests/common.py index 4c02aa926..3993af8f3 100644 --- a/src/registrar/tests/common.py +++ b/src/registrar/tests/common.py @@ -423,20 +423,20 @@ class AuditedAdminMockData: """Creates a dummy domain request object""" domain_request_kwargs = self.dummy_kwarg_boilerplate(self.DOMAIN_REQUEST, item_name, status) domain_request = DomainRequest.objects.get_or_create(**domain_request_kwargs)[0] - return application + return domain_request def create_full_dummy_domain_information(self, item_name, status=DomainRequest.DomainRequestStatus.STARTED): """Creates a dummy domain information object""" domain_request_kwargs = self.dummy_kwarg_boilerplate(self.INFORMATION, item_name, status) domain_request = DomainInformation.objects.get_or_create(**domain_request_kwargs)[0] - return application + return domain_request def create_full_dummy_domain_invitation(self, item_name, status=DomainRequest.DomainRequestStatus.STARTED): """Creates a dummy domain invitation object""" domain_request_kwargs = self.dummy_kwarg_boilerplate(self.INVITATION, item_name, status) domain_request = DomainInvitation.objects.get_or_create(**domain_request_kwargs)[0] - return application + return domain_request def create_full_dummy_domain_object( self, @@ -469,7 +469,7 @@ class AuditedAdminMockData: alt = self.dummy_alt(item_name) domain_request.alternative_domains.add(alt) - return application + return domain_request def mock_user(): @@ -589,22 +589,22 @@ def completed_domain_request( if has_alternative_gov_domain: domain_request.alternative_domains.add(alt) - return application + return domain_request def multiple_unalphabetical_domain_objects( domain_type=AuditedAdminMockData.DOMAIN_REQUEST, ): """Returns a list of generic domain objects for testing purposes""" - applications = [] + domain_requests = [] list_of_letters = list(ascii_uppercase) random.shuffle(list_of_letters) mock = AuditedAdminMockData() for object_name in list_of_letters: domain_request = mock.create_full_dummy_domain_object(domain_type, object_name) - applications.append(application) - return applications + domain_requests.append(domain_request) + return domain_requests def generic_domain_object(domain_type, object_name): @@ -612,7 +612,7 @@ def generic_domain_object(domain_type, object_name): domain_type 'domain_request', 'information', or 'invitation'""" mock = AuditedAdminMockData() domain_request = mock.create_full_dummy_domain_object(domain_type, object_name) - return application + return domain_request class MockEppLib(TestCase): diff --git a/src/registrar/tests/test_admin.py b/src/registrar/tests/test_admin.py index b310cff5e..c0fb210c0 100644 --- a/src/registrar/tests/test_admin.py +++ b/src/registrar/tests/test_admin.py @@ -244,7 +244,7 @@ class TestDomainAdmin(MockEppLib, WebTest): response = self.client.get("/admin/registrar/domain/") # There are 4 template references to Federal (4) plus four references in the table - # for our actual application + # for our actual domain_request self.assertContains(response, "Federal", count=8) # This may be a bit more robust self.assertContains(response, '
FederalFederal