From 828c47de4528fc7bec86639087f91cfe628e835a Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Mon, 13 Jan 2025 15:06:44 -0700 Subject: [PATCH 1/2] Better table + simplify get_or_create function --- src/registrar/admin.py | 3 ++ src/registrar/models/domain.py | 68 ++++++++++++++-------------------- 2 files changed, 30 insertions(+), 41 deletions(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index 849cb6100..ed0b776ce 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -3835,6 +3835,9 @@ class PublicContactAdmin(ListHeaderAdmin, ImportExportModelAdmin): change_form_template = "django/admin/email_clipboard_change_form.html" autocomplete_fields = ["domain"] + list_display = ("domain", "email", "name", "contact_type", "id") + search_fields = ["email", "name", "id"] + search_help_text = "Search by email, name or id." def changeform_view(self, request, object_id=None, form_url="", extra_context=None): if extra_context is None: diff --git a/src/registrar/models/domain.py b/src/registrar/models/domain.py index 6bd8278a1..cb912cb37 100644 --- a/src/registrar/models/domain.py +++ b/src/registrar/models/domain.py @@ -4,9 +4,9 @@ import re from datetime import date, timedelta from typing import Optional +from django.db import transaction from django_fsm import FSMField, transition, TransitionNotAllowed # type: ignore - -from django.db import models +from django.db import models, IntegrityError from django.utils import timezone from typing import Any from registrar.models.host import Host @@ -2077,49 +2077,35 @@ def _get_hosts(self, hosts): def _get_or_create_public_contact(self, public_contact: PublicContact): """Tries to find a PublicContact object in our DB. If it can't, it'll create it. Returns PublicContact""" - db_contact = PublicContact.objects.filter( - registry_id=public_contact.registry_id, - contact_type=public_contact.contact_type, - domain=self, - ) - - # If we find duplicates, log it and delete the oldest ones. - if db_contact.count() > 1: - logger.warning("_get_or_create_public_contact() -> Duplicate contacts found. Deleting duplicate.") - - newest_duplicate = db_contact.order_by("-created_at").first() - - duplicates_to_delete = db_contact.exclude(id=newest_duplicate.id) # type: ignore - - # Delete all duplicates - duplicates_to_delete.delete() - - # Do a second filter to grab the latest content - db_contact = PublicContact.objects.filter( + try: + with transaction.atomic(): + contact, _ = PublicContact.objects.get_or_create( + registry_id=public_contact.registry_id, + contact_type=public_contact.contact_type, + domain=self, + defaults={ + "email": public_contact.email, + "voice": public_contact.voice, + "fax": public_contact.fax, + "name": public_contact.name, + "org": public_contact.org, + "pw": public_contact.pw, + "city": public_contact.city, + "pc": public_contact.pc, + "cc": public_contact.cc, + "sp": public_contact.sp, + "street1": public_contact.street1, + "street2": public_contact.street2, + "street3": public_contact.street3, + } + ) + except IntegrityError: + contact = PublicContact.objects.get( registry_id=public_contact.registry_id, contact_type=public_contact.contact_type, domain=self, ) - - # Save to DB if it doesn't exist already. - if db_contact.count() == 0: - # Doesn't run custom save logic, just saves to DB - public_contact.save(skip_epp_save=True) - logger.info(f"Created a new PublicContact: {public_contact}") - # Append the item we just created - return public_contact - - existing_contact = db_contact.get() - - # Does the item we're grabbing match what we have in our DB? - if existing_contact.email != public_contact.email or existing_contact.registry_id != public_contact.registry_id: - existing_contact.delete() - public_contact.save() - logger.warning("Requested PublicContact is out of sync " "with DB.") - return public_contact - - # If it already exists, we can assume that the DB instance was updated during set, so we should just use that. - return existing_contact + return contact def _registrant_to_public_contact(self, registry_id: str): """EPPLib returns the registrant as a string, From c0c9817c99459a0ecfef76a59fe12a9ea9483bfa Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 14 Jan 2025 10:33:00 -0700 Subject: [PATCH 2/2] Update admin.py --- src/registrar/admin.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index ed0b776ce..8773f7ef8 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -3835,9 +3835,9 @@ class PublicContactAdmin(ListHeaderAdmin, ImportExportModelAdmin): change_form_template = "django/admin/email_clipboard_change_form.html" autocomplete_fields = ["domain"] - list_display = ("domain", "email", "name", "contact_type", "id") - search_fields = ["email", "name", "id"] - search_help_text = "Search by email, name or id." + list_display = ("name", "contact_type", "email", "domain", "registry_id") + search_fields = ["email", "name", "registry_id"] + search_help_text = "Search by email, name or registry id." def changeform_view(self, request, object_id=None, form_url="", extra_context=None): if extra_context is None: