Merge MAIN to nl/926-transition-domain-object-creation

Signed-off-by: CocoByte <nicolle.leclair@gmail.com>
This commit is contained in:
CocoByte 2023-10-11 16:20:19 -06:00
commit b68d66db9e
No known key found for this signature in database
GPG key ID: BBFAA2526384C97F
8 changed files with 161 additions and 33 deletions

View file

@ -138,24 +138,12 @@ class MyUserAdmin(BaseUserAdmin):
"email",
"first_name",
"last_name",
# Group is a custom property defined within this file,
# rather than in a model like the other properties
"group",
"status",
)
list_filter = (
"is_active",
"groups",
)
# Let's define First group
# (which should in theory be the ONLY group)
def group(self, obj):
if obj.groups.filter(name="full_access_group").exists():
return "Full access"
elif obj.groups.filter(name="cisa_analysts_group").exists():
return "Analyst"
return ""
fieldsets = (
(
None,
@ -222,6 +210,20 @@ class MyUserAdmin(BaseUserAdmin):
"date_joined",
]
list_filter = (
"is_active",
"groups",
)
# Let's define First group
# (which should in theory be the ONLY group)
def group(self, obj):
if obj.groups.filter(name="full_access_group").exists():
return "Full access"
elif obj.groups.filter(name="cisa_analysts_group").exists():
return "Analyst"
return ""
def get_list_display(self, request):
# The full_access_permission perm will load onto the full_access_group
# which is equivalent to superuser. The other group we use to manage

View file

@ -64,7 +64,7 @@ class DomainSecurityEmailForm(forms.Form):
"""Form for adding or editing a security email to a domain."""
security_email = forms.EmailField(label="Security email")
security_email = forms.EmailField(label="Security email", required=False)
class DomainOrgNameAddressForm(forms.ModelForm):

View file

@ -15,7 +15,7 @@ from epplibwrapper import (
RegistryError,
ErrorCode,
)
from registrar.models.utility.contact_error import ContactError
from registrar.models.utility.contact_error import ContactError, ContactErrorCodes
from .utility.domain_field import DomainField
from .utility.domain_helper import DomainHelper
@ -625,7 +625,10 @@ class Domain(TimeStampedModel, DomainHelper):
def get_security_email(self):
logger.info("get_security_email-> getting the contact ")
secContact = self.security_contact
if secContact is not None:
return secContact.email
else:
return None
def clientHoldStatus(self):
return epp.Status(state=self.Status.CLIENT_HOLD, description="", lang="en")
@ -698,10 +701,10 @@ class Domain(TimeStampedModel, DomainHelper):
return None
if contact_type is None:
raise ContactError("contact_type is None")
raise ContactError(code=ContactErrorCodes.CONTACT_TYPE_NONE)
if contact_id is None:
raise ContactError("contact_id is None")
raise ContactError(code=ContactErrorCodes.CONTACT_ID_NONE)
# Since contact_id is registry_id,
# check that its the right length
@ -710,14 +713,11 @@ class Domain(TimeStampedModel, DomainHelper):
contact_id_length > PublicContact.get_max_id_length()
or contact_id_length < 1
):
raise ContactError(
"contact_id is of invalid length. "
"Cannot exceed 16 characters, "
f"got {contact_id} with a length of {contact_id_length}"
)
raise ContactError(code=ContactErrorCodes.CONTACT_ID_INVALID_LENGTH)
if not isinstance(contact, eppInfo.InfoContactResultData):
raise ContactError("Contact must be of type InfoContactResultData")
raise ContactError(code=ContactErrorCodes.CONTACT_INVALID_TYPE)
auth_info = contact.auth_info
postal_info = contact.postal_info
addr = postal_info.addr
@ -880,8 +880,8 @@ class Domain(TimeStampedModel, DomainHelper):
return self._handle_registrant_contact(desired_contact)
_registry_id: str
if contact_type in contacts:
_registry_id: str = ""
if contacts is not None and contact_type in contacts:
_registry_id = contacts.get(contact_type)
desired = PublicContact.objects.filter(

View file

@ -1,2 +1,51 @@
from enum import IntEnum
class ContactErrorCodes(IntEnum):
"""Used in the ContactError class for
error mapping.
Overview of contact error codes:
- 2000 CONTACT_TYPE_NONE
- 2001 CONTACT_ID_NONE
- 2002 CONTACT_ID_INVALID_LENGTH
- 2003 CONTACT_INVALID_TYPE
"""
CONTACT_TYPE_NONE = 2000
CONTACT_ID_NONE = 2001
CONTACT_ID_INVALID_LENGTH = 2002
CONTACT_INVALID_TYPE = 2003
CONTACT_NOT_FOUND = 2004
class ContactError(Exception):
...
"""
Overview of contact error codes:
- 2000 CONTACT_TYPE_NONE
- 2001 CONTACT_ID_NONE
- 2002 CONTACT_ID_INVALID_LENGTH
- 2003 CONTACT_INVALID_TYPE
- 2004 CONTACT_NOT_FOUND
"""
# For linter
_contact_id_error = "contact_id has an invalid length. Cannot exceed 16 characters."
_contact_invalid_error = "Contact must be of type InfoContactResultData"
_contact_not_found_error = "No contact was found in cache or the registry"
_error_mapping = {
ContactErrorCodes.CONTACT_TYPE_NONE: "contact_type is None",
ContactErrorCodes.CONTACT_ID_NONE: "contact_id is None",
ContactErrorCodes.CONTACT_ID_INVALID_LENGTH: _contact_id_error,
ContactErrorCodes.CONTACT_INVALID_TYPE: _contact_invalid_error,
ContactErrorCodes.CONTACT_NOT_FOUND: _contact_not_found_error,
}
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}"

View file

@ -46,8 +46,11 @@
{% include "includes/summary_item.html" with title='Your contact information' value=request.user.contact contact='true' edit_link=url %}
{% url 'domain-security-email' pk=domain.id as url %}
{% include "includes/summary_item.html" with title='Security email' value=domain.security_email edit_link=url %}
{% if security_email is not None and security_email != default_security_email%}
{% include "includes/summary_item.html" with title='Security email' value=security_email edit_link=url %}
{% else %}
{% include "includes/summary_item.html" with title='Security email' value='None provided' edit_link=url %}
{% endif %}
{% url 'domain-users' pk=domain.id as url %}
{% include "includes/summary_item.html" with title='User management' users='true' list=True value=domain.permissions.all edit_link=url %}

View file

@ -11,8 +11,6 @@
<p>A security contact should be capable of evaluating or triaging security reports for your entire domain. Use a team email address, not an individuals email. We recommend using an alias, like security@domain.gov.</p>
{% include "includes/required_fields.html" %}
<form class="usa-form usa-form--large" method="post" novalidate>
{% csrf_token %}

View file

@ -16,6 +16,7 @@ from registrar.models.domain_information import DomainInformation
from registrar.models.draft_domain import DraftDomain
from registrar.models.public_contact import PublicContact
from registrar.models.user import User
from registrar.models.utility.contact_error import ContactError, ContactErrorCodes
from .common import MockEppLib
from django_fsm import TransitionNotAllowed # type: ignore
from epplibwrapper import (
@ -193,6 +194,56 @@ class TestDomainCache(MockEppLib):
self.assertEqual(cached_contact, in_db.registry_id)
self.assertEqual(domain.security_contact.email, "123test@mail.gov")
def test_errors_map_epp_contact_to_public_contact(self):
"""
Scenario: Registrant gets invalid data from EPPLib
When the `map_epp_contact_to_public_contact` function
gets invalid data from EPPLib
Then the function throws the expected ContactErrors
"""
domain, _ = Domain.objects.get_or_create(name="registry.gov")
fakedEpp = self.fakedEppObject()
invalid_length = fakedEpp.dummyInfoContactResultData(
"Cymaticsisasubsetofmodalvibrationalphenomena", "lengthInvalid@mail.gov"
)
valid_object = fakedEpp.dummyInfoContactResultData("valid", "valid@mail.gov")
desired_error = ContactErrorCodes.CONTACT_ID_INVALID_LENGTH
with self.assertRaises(ContactError) as context:
domain.map_epp_contact_to_public_contact(
invalid_length,
invalid_length.id,
PublicContact.ContactTypeChoices.SECURITY,
)
self.assertEqual(context.exception.code, desired_error)
desired_error = ContactErrorCodes.CONTACT_ID_NONE
with self.assertRaises(ContactError) as context:
domain.map_epp_contact_to_public_contact(
valid_object,
None,
PublicContact.ContactTypeChoices.SECURITY,
)
self.assertEqual(context.exception.code, desired_error)
desired_error = ContactErrorCodes.CONTACT_INVALID_TYPE
with self.assertRaises(ContactError) as context:
domain.map_epp_contact_to_public_contact(
"bad_object",
valid_object.id,
PublicContact.ContactTypeChoices.SECURITY,
)
self.assertEqual(context.exception.code, desired_error)
desired_error = ContactErrorCodes.CONTACT_TYPE_NONE
with self.assertRaises(ContactError) as context:
domain.map_epp_contact_to_public_contact(
valid_object,
valid_object.id,
None,
)
self.assertEqual(context.exception.code, desired_error)
class TestDomainCreation(MockEppLib):
"""Rule: An approved domain application must result in a domain"""

View file

@ -21,6 +21,7 @@ from registrar.models import (
User,
UserDomainRole,
)
from registrar.models.public_contact import PublicContact
from ..forms import (
ContactForm,
@ -42,6 +43,19 @@ class DomainView(DomainPermissionView):
template_name = "domain_detail.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
default_email = Domain().get_default_security_contact().email
context["default_security_email"] = default_email
security_email = self.get_object().get_security_email()
if security_email is None or security_email == default_email:
context["security_email"] = None
return context
context["security_email"] = security_email
return context
class DomainOrgNameAddressView(DomainPermissionView, FormMixin):
"""Organization name and mailing address view"""
@ -284,10 +298,21 @@ class DomainSecurityEmailView(DomainPermissionView, FormMixin):
"""The form is valid, call setter in model."""
# Set the security email from the form
new_email = form.cleaned_data.get("security_email", "")
new_email: str = form.cleaned_data.get("security_email", "")
# If we pass nothing for the sec email, set to the default
if new_email is None or new_email.strip() == "":
new_email = PublicContact.get_default_security().email
domain = self.get_object()
contact = domain.security_contact
# If no default is created for security_contact,
# then we cannot connect to the registry.
if contact is None:
messages.error(self.request, "Update failed. Cannot contact the registry.")
return redirect(self.get_success_url())
contact.email = new_email
contact.save()