diff --git a/src/registrar/admin.py b/src/registrar/admin.py index 707ea624e..9e218161b 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -2892,46 +2892,21 @@ class DomainRequestAdmin(ListHeaderAdmin, ImportExportModelAdmin): should_proceed = True error_message = None - """ - Let's try this method? - If transition to APPROVED: + print("##### original_obj.status is", original_obj.status) + print("##### obj.status is", obj.status) + domain_name = original_obj.requested_domain.name - Check if: - 1. If the domain request is not approved in previous state (original status) - 2. If the new status that's supposed to be triggered IS approved - 3. That it's a valid domain? Do we need this check or is this extra - - If it is then: - * Go through the domain check like in availabile! - """ - print("***** original_obj.status is", original_obj.status) - print("***** obj.status is", obj.status) - - if ( - original_obj.status != models.DomainRequest.DomainRequestStatus.APPROVED - and obj.status == models.DomainRequest.DomainRequestStatus.APPROVED - and original_obj.requested_domain is not None - ): - domain_name = original_obj.requested_domain.name - print(f"***** Domain_name is {domain_name}") - - try: - # Do same check in available() - info_req = commands.InfoDomain(domain_name) - info_response = registry.send(info_req, cleaned=True) - domain_status_state = [status.state for status in info_response.res_data[0].statuses] - print(f"***** Domain statuses for {domain_name} is: {domain_status_state}") - if "pendingDelete" in domain_status_state: - print("***** In the if pendingDelete check yay!") - error_message = ( - f"The domain '{domain_name}' is still in 'pendingDelete' status " - "in the registry and cannot be approved at this time." - ) - - except Exception as e: - print("In the Exception state") - logger.error(f"Failed to check registry status for {domain_name}: {e}") - error_message = f"Failed to verify domain status in registry. " "Please try again or contact support." + # if ( + # original_obj.status != models.DomainRequest.DomainRequestStatus.APPROVED + # and obj.status == models.DomainRequest.DomainRequestStatus.APPROVED + # and original_obj.requested_domain is not None + # and Domain.objects.filter(name=original_obj.requested_domain.name).exists() + # and Domain.is_pending_delete(domain_name) + # ): + # print(f"##### in the if statement - {domain_name} is not available, yay") + # # raise FSMDomainRequestError(code=FSMErrorCodes.DOMAIN_IS_PENDING_DELETE) + # error_message = FSMDomainRequestError.get_error_message(FSMErrorCodes.DOMAIN_IS_PENDING_DELETE) + # print(f"##### error_message is - {error_message}") # Get the method that should be run given the status selected_method = self.get_status_method_mapping(obj) @@ -2953,6 +2928,16 @@ class DomainRequestAdmin(ListHeaderAdmin, ImportExportModelAdmin): # duplicated in the model and the error is raised from the model. # This avoids an ugly Django error screen. error_message = "This action is not permitted. The domain is already active." + elif ( + original_obj.status != models.DomainRequest.DomainRequestStatus.APPROVED + and obj.status == models.DomainRequest.DomainRequestStatus.APPROVED + and original_obj.requested_domain is not None + and Domain.objects.filter(name=original_obj.requested_domain.name).exists() + and Domain.is_pending_delete(domain_name) + ): + # TODO: Write blurb here + print(f"##### in the elif statement - {domain_name} is not available, yay") + error_message = FSMDomainRequestError.get_error_message(FSMErrorCodes.DOMAIN_IS_PENDING_DELETE) elif ( original_obj.status != models.DomainRequest.DomainRequestStatus.APPROVED and obj.status == models.DomainRequest.DomainRequestStatus.APPROVED @@ -2987,6 +2972,8 @@ class DomainRequestAdmin(ListHeaderAdmin, ImportExportModelAdmin): logger.warning(f"An error encountered when trying to change status: {err}") error_message = err.message + print(f"##### error_message is - {error_message}") + if error_message is not None: # Clear the success message messages.set_level(request, messages.ERROR) diff --git a/src/registrar/models/domain.py b/src/registrar/models/domain.py index 60b531c37..a82d55ec9 100644 --- a/src/registrar/models/domain.py +++ b/src/registrar/models/domain.py @@ -246,24 +246,6 @@ class Domain(TimeStampedModel, DomainHelper): Throws: RegistryError or InvalidDomainError""" - # if not cls.string_could_be_domain(domain): - # logger.warning("Not a valid domain: %s" % str(domain)) - # # throw invalid domain error so that it can be caught in - # # validate_and_handle_errors in domain_helper - # raise errors.InvalidDomainError() - - # domain_name = domain.lower() - # req = commands.CheckDomain([domain_name]) - # return registry.send(req, cleaned=True).res_data[0].avail - - """ - 1. Check for Invalid Domain and then check for availability - 2. If domain is available, return True - 3. If not available -> check for pendingDelete status - 4. If pendingDelete found, return False - 5. Check keyError? - """ - if not cls.string_could_be_domain(domain): logger.warning("Not a valid domain: %s" % str(domain)) # throw invalid domain error so that it can be caught in @@ -280,39 +262,40 @@ class Domain(TimeStampedModel, DomainHelper): if response.res_data[0].avail: return True + @classmethod + def is_pending_delete(cls, domain: str) -> bool: + # TODO: Write blurb here still + domain_name = domain.lower() + + print("***** in is_pending_delete") # If not avail, check registry using InfoDomain - try: - info_req = commands.InfoDomain(domain_name) - info_response = registry.send(info_req, cleaned=True) - print("***** MODELS/DOMAIN.PY IN TRY info_response is:", info_response) - """ - InfoDomainResult(code=1000, msg='Command completed successfully', - res_data=[InfoDomainResultData(roid='DF1364752-GOV', - statuses=[Status(state='serverTransferProhibited', description=None, lang='en')], - cl_id='gov2023-ote', cr_id='gov2023-ote', cr_date=datetime.datetime(2023, 10, 23, 17, 8, 9, tzinfo=tzlocal()), - up_id='gov2023-ote', up_date=datetime.datetime(2023, 10, 28, 17, 8, 9, tzinfo=tzlocal()), - tr_date=None, name='meoward.gov', registrant='sh8013', admins=[], nsset=None, - keyset=None, ex_date=datetime.date(2024, 10, 23), auth_info=DomainAuthInfo(pw='feedabee'))], - cl_tr_id='wup7ad#2025-03-17T22:21:39.298149', sv_tr_id='aOQBDg4fQoSMGemppS5AdQ==-73ca', - extensions=[], msg_q=None) - """ - print("***** MODELS/DOMAIN.PY IN TRY Response info_response.res_data[0]:", info_response.res_data[0]) + info_req = commands.InfoDomain(domain_name) + info_response = registry.send(info_req, cleaned=True) - domain_status_state = [status.state for status in info_response.res_data[0].statuses] + print("***** MODELS/DOMAIN.PY IN TRY info_response is:", info_response) + """ + InfoDomainResult(code=1000, msg='Command completed successfully', + res_data=[InfoDomainResultData(roid='DF1364752-GOV', + statuses=[Status(state='serverTransferProhibited', description=None, lang='en')], + cl_id='gov2023-ote', cr_id='gov2023-ote', cr_date=datetime.datetime(2023, 10, 23, 17, 8, 9, tzinfo=tzlocal()), + up_id='gov2023-ote', up_date=datetime.datetime(2023, 10, 28, 17, 8, 9, tzinfo=tzlocal()), + tr_date=None, name='meoward.gov', registrant='sh8013', admins=[], nsset=None, + keyset=None, ex_date=datetime.date(2024, 10, 23), auth_info=DomainAuthInfo(pw='feedabee'))], + cl_tr_id='wup7ad#2025-03-17T22:21:39.298149', sv_tr_id='aOQBDg4fQoSMGemppS5AdQ==-73ca', + extensions=[], msg_q=None) + """ - # domain_status_state = [status.state for status in response.res_data[0].statuses] + # Ensure res_data exists and is not empty + if info_response and info_response.res_data: + res_data = info_response.res_data[0] + print("***** MODELS/DOMAIN.PY IN IF Response info_response.res_data[0]:", info_response.res_data[0]) + domain_status_state = [status.state for status in res_data.statuses] print(f"***** Domain statuses for {domain_name} is: {domain_status_state}") - # if "serverTransferProhibited" in domain_status_state: - # print("***** Just checking it comes into here!") - if "pendingDelete" in domain_status_state: - logger.info(f"Domain {domain_name} is still in pendingDelete status.") - return False - except KeyError: - logger.info(f"Domain {domain_name} status check encountered a KeyError. It may be fully deleted.") - except Exception as e: - logger.warning(f"Failed to retrieve domain statuses for {domain_name}: {e}") + + # Check for pendingDelete status + return "pendingDelete" not in domain_status_state return False @@ -2065,7 +2048,9 @@ class Domain(TimeStampedModel, DomainHelper): def _extract_data_from_response(self, data_response): """extract data from response from registry""" + data = data_response.res_data[0] + return { "auth_info": getattr(data, "auth_info", ...), "_contacts": getattr(data, "contacts", ...), @@ -2074,11 +2059,34 @@ class Domain(TimeStampedModel, DomainHelper): "_hosts": getattr(data, "hosts", ...), "name": getattr(data, "name", ...), "registrant": getattr(data, "registrant", ...), - "statuses": getattr(data, "statuses", ...), + "statuses": [epp.Status(state="pendingDelete", description="", lang="en")], "tr_date": getattr(data, "tr_date", ...), "up_date": getattr(data, "up_date", ...), } + # Have it return/raise this for checking for Deleted + # epplibwrapper/errors.py -> OBJECT_DOES_NOT_EXIST = 2303 + # raise RegistryError( + # message=f"Domain '{domain_name}' no longer exists in the registry and is DELETED.", + # error_code=2303, + # ) + + ### Original code + # data = data_response.res_data[0] + + # return { + # "auth_info": getattr(data, "auth_info", ...), + # "_contacts": getattr(data, "contacts", ...), + # "cr_date": getattr(data, "cr_date", ...), + # "ex_date": getattr(data, "ex_date", ...), + # "_hosts": getattr(data, "hosts", ...), + # "name": getattr(data, "name", ...), + # "registrant": getattr(data, "registrant", ...), + # "statuses": getattr(data, "statuses", ...), + # "tr_date": getattr(data, "tr_date", ...), + # "up_date": getattr(data, "up_date", ...), + # } + def _clean_cache(self, cache, data_response): """clean up the cache""" # remove null properties (to distinguish between "a value of None" and null) diff --git a/src/registrar/models/domain_request.py b/src/registrar/models/domain_request.py index 5ae51ebc6..52f1d4141 100644 --- a/src/registrar/models/domain_request.py +++ b/src/registrar/models/domain_request.py @@ -1185,10 +1185,28 @@ class DomainRequest(TimeStampedModel): # create the domain Domain = apps.get_model("registrar.Domain") + print("##### BEFORE the Domain.available check") + print( + "##### Domain.is_pending_delete(self.requested_domain.name)", + Domain.is_pending_delete(self.requested_domain.name), + ) + print("##### self.requested_domain.name is", self.requested_domain.name) + # == Check that the domain_request is valid == # + # if Domain.objects.filter(name=self.requested_domain.name).exists(): + # print("##### If it already exists, we do another check") + # if Domain.is_pending_delete(self.requested_domain.name): + # print(f"***** in the if statement - {self.requested_domain.name} is not available, yay") + # raise FSMDomainRequestError(code=FSMErrorCodes.DOMAIN_IS_PENDING_DELETE) + # else: + # print("##### in the else statement") + # raise FSMDomainRequestError(code=FSMErrorCodes.APPROVE_DOMAIN_IN_USE) + if Domain.objects.filter(name=self.requested_domain.name).exists(): raise FSMDomainRequestError(code=FSMErrorCodes.APPROVE_DOMAIN_IN_USE) + print("##### AFTER the Domain.available check") + # == Create the domain and related components == # created_domain = Domain.objects.create(name=self.requested_domain.name) self.approved_domain = created_domain diff --git a/src/registrar/utility/errors.py b/src/registrar/utility/errors.py index 0a6f00c36..85e2f5f8b 100644 --- a/src/registrar/utility/errors.py +++ b/src/registrar/utility/errors.py @@ -136,6 +136,7 @@ class FSMErrorCodes(IntEnum): INVESTIGATOR_NOT_STAFF = 3 NO_REJECTION_REASON = 4 NO_ACTION_NEEDED_REASON = 5 + DOMAIN_IS_PENDING_DELETE = 6 class FSMDomainRequestError(Exception): @@ -150,6 +151,7 @@ class FSMDomainRequestError(Exception): FSMErrorCodes.INVESTIGATOR_NOT_STAFF: ("Investigator is not a staff user."), FSMErrorCodes.NO_REJECTION_REASON: ("A reason is required for this status."), FSMErrorCodes.NO_ACTION_NEEDED_REASON: ("A reason is required for this status."), + FSMErrorCodes.DOMAIN_IS_PENDING_DELETE: ("Domain of same name is currently in pending delete state."), } def __init__(self, *args, code=None, **kwargs):