mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-05-20 11:29:25 +02:00
Merge MAIN to nl/926-transition-domain-object-creation
Signed-off-by: CocoByte <nicolle.leclair@gmail.com>
This commit is contained in:
commit
b68d66db9e
8 changed files with 161 additions and 33 deletions
|
@ -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
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
return secContact.email
|
||||
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(
|
||||
|
|
|
@ -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}"
|
||||
|
|
|
@ -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 %}
|
||||
|
||||
|
|
|
@ -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 individual’s 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 %}
|
||||
|
||||
|
|
|
@ -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"""
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue