mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-05-15 09:07:02 +02:00
Merge branch 'main' into za/1851-check-how-user-was-verified
This commit is contained in:
commit
cb030cb694
15 changed files with 1623 additions and 81 deletions
|
@ -48,6 +48,34 @@ class MyUserAdminForm(UserChangeForm):
|
|||
"user_permissions": NoAutocompleteFilteredSelectMultiple("user_permissions", False),
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
"""Custom init to modify the user form"""
|
||||
super(MyUserAdminForm, self).__init__(*args, **kwargs)
|
||||
self._override_base_help_texts()
|
||||
|
||||
def _override_base_help_texts(self):
|
||||
"""
|
||||
Used to override pre-existing help texts in AbstractUser.
|
||||
This is done to avoid modifying the base AbstractUser class.
|
||||
"""
|
||||
is_superuser = self.fields.get("is_superuser")
|
||||
is_staff = self.fields.get("is_staff")
|
||||
password = self.fields.get("password")
|
||||
|
||||
if is_superuser is not None:
|
||||
is_superuser.help_text = "For development purposes only; provides superuser access on the database level."
|
||||
|
||||
if is_staff is not None:
|
||||
is_staff.help_text = "Designates whether the user can log in to this admin site."
|
||||
|
||||
if password is not None:
|
||||
# Link is copied from the base implementation of UserChangeForm.
|
||||
link = f"../../{self.instance.pk}/password/"
|
||||
password.help_text = (
|
||||
"Raw passwords are not stored, so they will not display here. "
|
||||
f'You can change the password using <a href="{link}">this form</a>.'
|
||||
)
|
||||
|
||||
|
||||
class DomainInformationAdminForm(forms.ModelForm):
|
||||
"""This form utilizes the custom widget for its class's ManyToMany UIs."""
|
||||
|
@ -535,7 +563,7 @@ class MyUserAdmin(BaseUserAdmin):
|
|||
analyst_fieldsets = (
|
||||
(
|
||||
None,
|
||||
{"fields": ("password", "status", "verification_type")},
|
||||
{"fields": ("status", "verification_type",)},
|
||||
),
|
||||
("Personal Info", {"fields": ("first_name", "last_name", "email")}),
|
||||
(
|
||||
|
@ -561,7 +589,6 @@ class MyUserAdmin(BaseUserAdmin):
|
|||
# NOT all fields are readonly for admin, otherwise we would have
|
||||
# set this at the permissions level. The exception is 'status'
|
||||
analyst_readonly_fields = [
|
||||
"password",
|
||||
"Personal Info",
|
||||
"first_name",
|
||||
"last_name",
|
||||
|
@ -1727,20 +1754,26 @@ class DomainAdmin(ListHeaderAdmin):
|
|||
if domain is not None and hasattr(domain, "domain_info"):
|
||||
extra_context["original_object"] = domain.domain_info
|
||||
|
||||
extra_context["state_help_message"] = Domain.State.get_admin_help_text(domain.state)
|
||||
extra_context["domain_state"] = domain.get_state_display()
|
||||
|
||||
# Pass in what the an extended expiration date would be for the expiration date modal
|
||||
self._set_expiration_date_context(domain, extra_context)
|
||||
|
||||
return super().changeform_view(request, object_id, form_url, extra_context)
|
||||
|
||||
def _set_expiration_date_context(self, domain, extra_context):
|
||||
"""Given a domain, calculate the an extended expiration date
|
||||
from the current registry expiration date."""
|
||||
years_to_extend_by = self._get_calculated_years_for_exp_date(domain)
|
||||
try:
|
||||
curr_exp_date = domain.registry_expiration_date
|
||||
except KeyError:
|
||||
# No expiration date was found. Return none.
|
||||
extra_context["extended_expiration_date"] = None
|
||||
return super().changeform_view(request, object_id, form_url, extra_context)
|
||||
else:
|
||||
new_date = curr_exp_date + relativedelta(years=years_to_extend_by)
|
||||
extra_context["extended_expiration_date"] = new_date
|
||||
else:
|
||||
extra_context["extended_expiration_date"] = None
|
||||
|
||||
return super().changeform_view(request, object_id, form_url, extra_context)
|
||||
|
||||
def response_change(self, request, obj):
|
||||
# Create dictionary of action functions
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -159,6 +159,31 @@ class Domain(TimeStampedModel, DomainHelper):
|
|||
|
||||
return help_texts.get(state, "")
|
||||
|
||||
@classmethod
|
||||
def get_admin_help_text(cls, state):
|
||||
"""Returns a help message for a desired state for /admin. If none is found, an empty string is returned"""
|
||||
admin_help_texts = {
|
||||
cls.UNKNOWN: (
|
||||
"The creator of the associated domain request has not logged in to "
|
||||
"manage the domain since it was approved. "
|
||||
'The state will switch to "DNS needed" after they access the domain in the registrar.'
|
||||
),
|
||||
cls.DNS_NEEDED: (
|
||||
"Before this domain can be used, name server addresses need to be added within the registrar."
|
||||
),
|
||||
cls.READY: "This domain has name servers and is ready for use.",
|
||||
cls.ON_HOLD: (
|
||||
"While on hold, this domain won't resolve in DNS and "
|
||||
"any infrastructure (like websites) will be offline."
|
||||
),
|
||||
cls.DELETED: (
|
||||
"This domain was permanently removed from the registry. "
|
||||
"The domain no longer resolves in DNS and any infrastructure (like websites) is offline."
|
||||
),
|
||||
}
|
||||
|
||||
return admin_help_texts.get(state, "")
|
||||
|
||||
class Cache(property):
|
||||
"""
|
||||
Python descriptor to turn class methods into properties.
|
||||
|
@ -992,22 +1017,25 @@ class Domain(TimeStampedModel, DomainHelper):
|
|||
blank=False,
|
||||
default=None, # prevent saving without a value
|
||||
unique=True,
|
||||
verbose_name="domain",
|
||||
help_text="Fully qualified domain name",
|
||||
verbose_name="domain",
|
||||
)
|
||||
|
||||
state = FSMField(
|
||||
max_length=21,
|
||||
choices=State.choices,
|
||||
default=State.UNKNOWN,
|
||||
protected=True, # cannot change state directly, particularly in Django admin
|
||||
# cannot change state directly, particularly in Django admin
|
||||
protected=True,
|
||||
# This must be defined for custom state help messages,
|
||||
# as otherwise the view will purge the help field as it does not exist.
|
||||
help_text=" ",
|
||||
verbose_name="domain state",
|
||||
help_text="Very basic info about the lifecycle of this domain object",
|
||||
)
|
||||
|
||||
expiration_date = DateField(
|
||||
null=True,
|
||||
help_text=("Duplication of registry's expiration date saved for ease of reporting"),
|
||||
help_text=("Date the domain expires in the registry"),
|
||||
)
|
||||
|
||||
security_contact_registry_id = TextField(
|
||||
|
@ -1019,15 +1047,15 @@ class Domain(TimeStampedModel, DomainHelper):
|
|||
deleted = DateField(
|
||||
null=True,
|
||||
editable=False,
|
||||
help_text='Will appear blank unless the domain is in "deleted" state',
|
||||
verbose_name="deleted on",
|
||||
help_text="Deleted at date",
|
||||
)
|
||||
|
||||
first_ready = DateField(
|
||||
null=True,
|
||||
editable=False,
|
||||
help_text='Date when this domain first moved into "ready" state; date will never change',
|
||||
verbose_name="first ready on",
|
||||
help_text="The last time this domain moved into the READY state",
|
||||
)
|
||||
|
||||
def isActive(self):
|
||||
|
|
|
@ -47,6 +47,7 @@ class DomainInformation(TimeStampedModel):
|
|||
"registrar.User",
|
||||
on_delete=models.PROTECT,
|
||||
related_name="information_created",
|
||||
help_text="Person who submitted the domain request",
|
||||
)
|
||||
|
||||
domain_request = models.OneToOneField(
|
||||
|
@ -55,7 +56,7 @@ class DomainInformation(TimeStampedModel):
|
|||
blank=True,
|
||||
null=True,
|
||||
related_name="DomainRequest_info",
|
||||
help_text="Associated domain request",
|
||||
help_text="Request associated with this domain",
|
||||
unique=True,
|
||||
)
|
||||
|
||||
|
@ -73,7 +74,6 @@ class DomainInformation(TimeStampedModel):
|
|||
null=True,
|
||||
blank=True,
|
||||
verbose_name="election office",
|
||||
help_text="Is your organization an election office?",
|
||||
)
|
||||
|
||||
# TODO - Ticket #1911: stub this data from DomainRequest
|
||||
|
@ -82,30 +82,26 @@ class DomainInformation(TimeStampedModel):
|
|||
choices=DomainRequest.OrgChoicesElectionOffice.choices,
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Type of organization - Election office",
|
||||
help_text='"Election" appears after the org type if it\'s an election office.',
|
||||
)
|
||||
|
||||
federally_recognized_tribe = models.BooleanField(
|
||||
null=True,
|
||||
help_text="Is the tribe federally recognized",
|
||||
)
|
||||
|
||||
state_recognized_tribe = models.BooleanField(
|
||||
null=True,
|
||||
help_text="Is the tribe recognized by a state",
|
||||
)
|
||||
|
||||
tribe_name = models.CharField(
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Name of tribe",
|
||||
)
|
||||
|
||||
federal_agency = models.CharField(
|
||||
choices=AGENCY_CHOICES,
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Federal agency",
|
||||
)
|
||||
|
||||
federal_type = models.CharField(
|
||||
|
@ -113,38 +109,32 @@ class DomainInformation(TimeStampedModel):
|
|||
choices=BranchChoices.choices,
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Federal government branch",
|
||||
)
|
||||
|
||||
is_election_board = models.BooleanField(
|
||||
null=True,
|
||||
blank=True,
|
||||
verbose_name="election office",
|
||||
help_text="Is your organization an election office?",
|
||||
)
|
||||
|
||||
organization_name = models.CharField(
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Organization name",
|
||||
db_index=True,
|
||||
)
|
||||
address_line1 = models.CharField(
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Street address",
|
||||
verbose_name="address line 1",
|
||||
)
|
||||
address_line2 = models.CharField(
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Street address line 2 (optional)",
|
||||
verbose_name="address line 2",
|
||||
)
|
||||
city = models.CharField(
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="City",
|
||||
)
|
||||
state_territory = models.CharField(
|
||||
max_length=2,
|
||||
|
@ -152,27 +142,24 @@ class DomainInformation(TimeStampedModel):
|
|||
null=True,
|
||||
blank=True,
|
||||
verbose_name="state / territory",
|
||||
help_text="State, territory, or military post",
|
||||
)
|
||||
zipcode = models.CharField(
|
||||
max_length=10,
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Zip code",
|
||||
verbose_name="zip code",
|
||||
db_index=True,
|
||||
verbose_name="zip code",
|
||||
)
|
||||
urbanization = models.CharField(
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Urbanization (required for Puerto Rico only)",
|
||||
help_text="Required for Puerto Rico only",
|
||||
verbose_name="urbanization",
|
||||
)
|
||||
|
||||
about_your_organization = models.TextField(
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Information about your organization",
|
||||
)
|
||||
|
||||
authorizing_official = models.ForeignKey(
|
||||
|
@ -190,7 +177,6 @@ class DomainInformation(TimeStampedModel):
|
|||
null=True,
|
||||
# Access this information via Domain as "domain.domain_info"
|
||||
related_name="domain_info",
|
||||
help_text="Domain to which this information belongs",
|
||||
)
|
||||
|
||||
# This is the contact information provided by the domain requestor. The
|
||||
|
@ -201,6 +187,7 @@ class DomainInformation(TimeStampedModel):
|
|||
blank=True,
|
||||
related_name="submitted_domain_requests_information",
|
||||
on_delete=models.PROTECT,
|
||||
help_text='Person listed under "your contact information" in the request form',
|
||||
)
|
||||
|
||||
purpose = models.TextField(
|
||||
|
@ -219,13 +206,12 @@ class DomainInformation(TimeStampedModel):
|
|||
no_other_contacts_rationale = models.TextField(
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Reason for listing no additional contacts",
|
||||
help_text="Required if creator does not list other employees",
|
||||
)
|
||||
|
||||
anything_else = models.TextField(
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Anything else?",
|
||||
)
|
||||
|
||||
is_policy_acknowledged = models.BooleanField(
|
||||
|
@ -237,7 +223,6 @@ class DomainInformation(TimeStampedModel):
|
|||
notes = models.TextField(
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Notes about the request",
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
|
|
|
@ -464,6 +464,7 @@ class DomainRequest(TimeStampedModel):
|
|||
"registrar.User",
|
||||
on_delete=models.PROTECT,
|
||||
related_name="domain_requests_created",
|
||||
help_text="Person who submitted the domain request; will not receive email updates",
|
||||
)
|
||||
|
||||
investigator = models.ForeignKey(
|
||||
|
@ -481,14 +482,12 @@ class DomainRequest(TimeStampedModel):
|
|||
choices=OrganizationChoices.choices,
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Type of organization",
|
||||
)
|
||||
|
||||
is_election_board = models.BooleanField(
|
||||
null=True,
|
||||
blank=True,
|
||||
verbose_name="election office",
|
||||
help_text="Is your organization an election office?",
|
||||
)
|
||||
|
||||
# TODO - Ticket #1911: stub this data from DomainRequest
|
||||
|
@ -497,30 +496,26 @@ class DomainRequest(TimeStampedModel):
|
|||
choices=OrgChoicesElectionOffice.choices,
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Type of organization - Election office",
|
||||
help_text='"Election" appears after the org type if it\'s an election office.',
|
||||
)
|
||||
|
||||
federally_recognized_tribe = models.BooleanField(
|
||||
null=True,
|
||||
help_text="Is the tribe federally recognized",
|
||||
)
|
||||
|
||||
state_recognized_tribe = models.BooleanField(
|
||||
null=True,
|
||||
help_text="Is the tribe recognized by a state",
|
||||
)
|
||||
|
||||
tribe_name = models.CharField(
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Name of tribe",
|
||||
)
|
||||
|
||||
federal_agency = models.CharField(
|
||||
choices=AGENCY_CHOICES,
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Federal agency",
|
||||
)
|
||||
|
||||
federal_type = models.CharField(
|
||||
|
@ -528,32 +523,27 @@ class DomainRequest(TimeStampedModel):
|
|||
choices=BranchChoices.choices,
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Federal government branch",
|
||||
)
|
||||
|
||||
organization_name = models.CharField(
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Organization name",
|
||||
db_index=True,
|
||||
)
|
||||
|
||||
address_line1 = models.CharField(
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Street address",
|
||||
verbose_name="Address line 1",
|
||||
)
|
||||
address_line2 = models.CharField(
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Street address line 2 (optional)",
|
||||
verbose_name="Address line 2",
|
||||
)
|
||||
city = models.CharField(
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="City",
|
||||
)
|
||||
state_territory = models.CharField(
|
||||
max_length=2,
|
||||
|
@ -561,26 +551,23 @@ class DomainRequest(TimeStampedModel):
|
|||
null=True,
|
||||
blank=True,
|
||||
verbose_name="state / territory",
|
||||
help_text="State, territory, or military post",
|
||||
)
|
||||
zipcode = models.CharField(
|
||||
max_length=10,
|
||||
null=True,
|
||||
blank=True,
|
||||
verbose_name="zip code",
|
||||
help_text="Zip code",
|
||||
db_index=True,
|
||||
)
|
||||
urbanization = models.CharField(
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Urbanization (required for Puerto Rico only)",
|
||||
help_text="Required for Puerto Rico only",
|
||||
)
|
||||
|
||||
about_your_organization = models.TextField(
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Information about your organization",
|
||||
)
|
||||
|
||||
authorizing_official = models.ForeignKey(
|
||||
|
@ -603,7 +590,7 @@ class DomainRequest(TimeStampedModel):
|
|||
"Domain",
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="The approved domain",
|
||||
help_text="Domain associated with this request; will be blank until request is approved",
|
||||
related_name="domain_request",
|
||||
on_delete=models.SET_NULL,
|
||||
)
|
||||
|
@ -612,7 +599,6 @@ class DomainRequest(TimeStampedModel):
|
|||
"DraftDomain",
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="The requested domain",
|
||||
related_name="domain_request",
|
||||
on_delete=models.PROTECT,
|
||||
)
|
||||
|
@ -621,6 +607,7 @@ class DomainRequest(TimeStampedModel):
|
|||
"registrar.Website",
|
||||
blank=True,
|
||||
related_name="alternatives+",
|
||||
help_text="Other domain names the creator provided for consideration",
|
||||
)
|
||||
|
||||
# This is the contact information provided by the domain requestor. The
|
||||
|
@ -631,12 +618,12 @@ class DomainRequest(TimeStampedModel):
|
|||
blank=True,
|
||||
related_name="submitted_domain_requests",
|
||||
on_delete=models.PROTECT,
|
||||
help_text='Person listed under "your contact information" in the request form; will receive email updates',
|
||||
)
|
||||
|
||||
purpose = models.TextField(
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Purpose of your domain",
|
||||
)
|
||||
|
||||
other_contacts = models.ManyToManyField(
|
||||
|
@ -649,13 +636,12 @@ class DomainRequest(TimeStampedModel):
|
|||
no_other_contacts_rationale = models.TextField(
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Reason for listing no additional contacts",
|
||||
help_text="Required if creator does not list other employees",
|
||||
)
|
||||
|
||||
anything_else = models.TextField(
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Anything else?",
|
||||
)
|
||||
|
||||
is_policy_acknowledged = models.BooleanField(
|
||||
|
@ -676,7 +662,6 @@ class DomainRequest(TimeStampedModel):
|
|||
notes = models.TextField(
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Notes about this request",
|
||||
)
|
||||
|
||||
def sync_organization_type(self):
|
||||
|
|
|
@ -22,14 +22,13 @@ class Host(TimeStampedModel):
|
|||
default=None, # prevent saving without a value
|
||||
unique=False,
|
||||
verbose_name="host name",
|
||||
help_text="Fully qualified domain name",
|
||||
)
|
||||
|
||||
domain = models.ForeignKey(
|
||||
"registrar.Domain",
|
||||
on_delete=models.PROTECT,
|
||||
related_name="host", # access this Host via the Domain as `domain.host`
|
||||
help_text="Domain to which this host belongs",
|
||||
help_text="Domain associated with this host",
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
|
|
|
@ -21,12 +21,11 @@ class HostIP(TimeStampedModel):
|
|||
default=None, # prevent saving without a value
|
||||
validators=[validate_ipv46_address],
|
||||
verbose_name="IP address",
|
||||
help_text="IP address",
|
||||
)
|
||||
|
||||
host = models.ForeignKey(
|
||||
"registrar.Host",
|
||||
on_delete=models.PROTECT,
|
||||
related_name="ip", # access this HostIP via the Host as `host.ip`
|
||||
help_text="Host to which this IP address belongs",
|
||||
help_text="IP associated with this host",
|
||||
)
|
||||
|
|
|
@ -58,6 +58,7 @@ class User(AbstractUser):
|
|||
null=True, # Allow the field to be null
|
||||
blank=True, # Allow the field to be blank
|
||||
verbose_name="user status",
|
||||
help_text='Users in "restricted" status cannot make updates in the registrar or start a new request.',
|
||||
)
|
||||
|
||||
domains = models.ManyToManyField(
|
||||
|
|
|
@ -164,7 +164,7 @@ class CreateOrUpdateOrganizationTypeHelper:
|
|||
# There is no avenue for this to occur in the UI,
|
||||
# as such - this can only occur if the object is initialized in this way.
|
||||
# Or if there are pre-existing data.
|
||||
logger.warning(
|
||||
logger.debug(
|
||||
"create_or_update_organization_type() -> is_election_board "
|
||||
f"cannot exist for {generic_org_type}. Setting to None."
|
||||
)
|
||||
|
|
|
@ -9,7 +9,6 @@ class VerifiedByStaff(TimeStampedModel):
|
|||
email = models.EmailField(
|
||||
null=False,
|
||||
blank=False,
|
||||
help_text="Email",
|
||||
db_index=True,
|
||||
)
|
||||
|
||||
|
@ -19,12 +18,12 @@ class VerifiedByStaff(TimeStampedModel):
|
|||
blank=True,
|
||||
on_delete=models.SET_NULL,
|
||||
related_name="verifiedby_user",
|
||||
help_text="Person who verified this user",
|
||||
)
|
||||
|
||||
notes = models.TextField(
|
||||
null=False,
|
||||
blank=False,
|
||||
help_text="Notes",
|
||||
)
|
||||
|
||||
class Meta:
|
||||
|
|
|
@ -12,7 +12,7 @@ class Website(TimeStampedModel):
|
|||
website = models.CharField(
|
||||
max_length=255,
|
||||
null=False,
|
||||
help_text="",
|
||||
help_text="An alternative domain or current website listed on a domain request",
|
||||
)
|
||||
|
||||
def __str__(self) -> str:
|
||||
|
|
|
@ -33,7 +33,10 @@
|
|||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{{ block.super }}
|
||||
|
||||
{% for fieldset in adminform %}
|
||||
{% include "django/admin/includes/domain_fieldset.html" with state_help_message=state_help_message %}
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
|
||||
{% block submit_buttons_bottom %}
|
||||
|
|
|
@ -67,9 +67,16 @@ This is using a custom implementation fieldset.html (see admin/fieldset.html)
|
|||
{% endwith %}
|
||||
{% endblock field_readonly %}
|
||||
|
||||
{% block help_text %}
|
||||
<div class="help margin-bottom-1" {% if field.field.id_for_label %} id="{{ field.field.id_for_label }}_helptext"{% endif %}>
|
||||
<div>{{ field.field.help_text|safe }}</div>
|
||||
</div>
|
||||
{% endblock help_text %}
|
||||
|
||||
|
||||
{% block after_help_text %}
|
||||
{% if field.field.name == "creator" %}
|
||||
<div class="flex-container">
|
||||
<div class="flex-container tablet:margin-top-1">
|
||||
<label aria-label="Creator contact details"></label>
|
||||
{% include "django/admin/includes/contact_detail_list.html" with user=original_object.creator no_title_top_padding=field.is_readonly %}
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
{% extends "admin/fieldset.html" %}
|
||||
{% load static url_helpers %}
|
||||
|
||||
|
||||
{% block field_readonly %}
|
||||
{% if field.field.name == "state" %}
|
||||
<div class="readonly">{{ domain_state }}</div>
|
||||
{% else %}
|
||||
<div class="readonly">{{ field.contents }}</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block help_text %}
|
||||
<div class="help margin-bottom-1" {% if field.field.id_for_label %} id="{{ field.field.id_for_label }}_helptext"{% endif %}>
|
||||
{% if field.field.name == "state" %}
|
||||
<div>{{ state_help_message }}</div>
|
||||
{% else %}
|
||||
<div>{{ field.field.help_text|safe }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock help_text %}
|
|
@ -18,6 +18,7 @@ from registrar.admin import (
|
|||
AuditedAdmin,
|
||||
ContactAdmin,
|
||||
DomainInformationAdmin,
|
||||
MyHostAdmin,
|
||||
UserDomainRoleAdmin,
|
||||
VerifiedByStaffAdmin,
|
||||
)
|
||||
|
@ -76,6 +77,13 @@ class TestDomainAdmin(MockEppLib, WebTest):
|
|||
self.app.set_user(self.superuser.username)
|
||||
self.client.force_login(self.superuser)
|
||||
|
||||
# Add domain data
|
||||
self.ready_domain, _ = Domain.objects.get_or_create(name="fakeready.gov", state=Domain.State.READY)
|
||||
self.unknown_domain, _ = Domain.objects.get_or_create(name="fakeunknown.gov", state=Domain.State.UNKNOWN)
|
||||
self.dns_domain, _ = Domain.objects.get_or_create(name="fakedns.gov", state=Domain.State.DNS_NEEDED)
|
||||
self.hold_domain, _ = Domain.objects.get_or_create(name="fakehold.gov", state=Domain.State.ON_HOLD)
|
||||
self.deleted_domain, _ = Domain.objects.get_or_create(name="fakedeleted.gov", state=Domain.State.DELETED)
|
||||
|
||||
# Contains some test tools
|
||||
self.test_helper = GenericTestHelper(
|
||||
factory=self.factory,
|
||||
|
@ -159,6 +167,68 @@ class TestDomainAdmin(MockEppLib, WebTest):
|
|||
# Test for the copy link
|
||||
self.assertContains(response, "usa-button__clipboard")
|
||||
|
||||
@less_console_noise_decorator
|
||||
def test_helper_text(self):
|
||||
"""
|
||||
Tests for the correct helper text on this page
|
||||
"""
|
||||
|
||||
# Create a ready domain with a preset expiration date
|
||||
domain, _ = Domain.objects.get_or_create(name="fake.gov", state=Domain.State.READY)
|
||||
|
||||
p = "adminpass"
|
||||
self.client.login(username="superuser", password=p)
|
||||
response = self.client.get(
|
||||
"/admin/registrar/domain/{}/change/".format(domain.pk),
|
||||
follow=True,
|
||||
)
|
||||
|
||||
# Make sure the page loaded, and that we're on the right page
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertContains(response, domain.name)
|
||||
|
||||
# These should exist in the response
|
||||
expected_values = [
|
||||
("expiration_date", "Date the domain expires in the registry"),
|
||||
("first_ready_at", 'Date when this domain first moved into "ready" state; date will never change'),
|
||||
("deleted_at", 'Will appear blank unless the domain is in "deleted" state'),
|
||||
]
|
||||
self.test_helper.assert_response_contains_distinct_values(response, expected_values)
|
||||
|
||||
@less_console_noise_decorator
|
||||
def test_helper_text_state(self):
|
||||
"""
|
||||
Tests for the correct state helper text on this page
|
||||
"""
|
||||
|
||||
# We don't need to check for all text content, just a portion of it
|
||||
expected_unknown_domain_message = "The creator of the associated domain request has not logged in to"
|
||||
expected_dns_message = "Before this domain can be used, name server addresses need"
|
||||
expected_hold_message = "While on hold, this domain"
|
||||
expected_deleted_message = "This domain was permanently removed from the registry."
|
||||
expected_messages = [
|
||||
(self.ready_domain, "This domain has name servers and is ready for use."),
|
||||
(self.unknown_domain, expected_unknown_domain_message),
|
||||
(self.dns_domain, expected_dns_message),
|
||||
(self.hold_domain, expected_hold_message),
|
||||
(self.deleted_domain, expected_deleted_message),
|
||||
]
|
||||
|
||||
p = "adminpass"
|
||||
self.client.login(username="superuser", password=p)
|
||||
for domain, message in expected_messages:
|
||||
with self.subTest(domain_state=domain.state):
|
||||
response = self.client.get(
|
||||
"/admin/registrar/domain/{}/change/".format(domain.id),
|
||||
)
|
||||
|
||||
# Make sure the page loaded, and that we're on the right page
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertContains(response, domain.name)
|
||||
|
||||
# Check that the right help text exists
|
||||
self.assertContains(response, message)
|
||||
|
||||
@patch("registrar.admin.DomainAdmin._get_current_date", return_value=date(2024, 1, 1))
|
||||
def test_extend_expiration_date_button(self, mock_date_today):
|
||||
"""
|
||||
|
@ -782,6 +852,41 @@ class TestDomainRequestAdmin(MockEppLib):
|
|||
)
|
||||
self.mock_client = MockSESClient()
|
||||
|
||||
@less_console_noise_decorator
|
||||
def test_helper_text(self):
|
||||
"""
|
||||
Tests for the correct helper text on this page
|
||||
"""
|
||||
|
||||
# Create a fake domain request and domain
|
||||
domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.IN_REVIEW)
|
||||
|
||||
p = "adminpass"
|
||||
self.client.login(username="superuser", password=p)
|
||||
response = self.client.get(
|
||||
"/admin/registrar/domainrequest/{}/change/".format(domain_request.pk),
|
||||
follow=True,
|
||||
)
|
||||
|
||||
# Make sure the page loaded, and that we're on the right page
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertContains(response, domain_request.requested_domain.name)
|
||||
|
||||
# These should exist in the response
|
||||
expected_values = [
|
||||
("creator", "Person who submitted the domain request; will not receive email updates"),
|
||||
(
|
||||
"submitter",
|
||||
'Person listed under "your contact information" in the request form; will receive email updates',
|
||||
),
|
||||
("approved_domain", "Domain associated with this request; will be blank until request is approved"),
|
||||
("no_other_contacts_rationale", "Required if creator does not list other employees"),
|
||||
("alternative_domains", "Other domain names the creator provided for consideration"),
|
||||
("no_other_contacts_rationale", "Required if creator does not list other employees"),
|
||||
("Urbanization", "Required for Puerto Rico only"),
|
||||
]
|
||||
self.test_helper.assert_response_contains_distinct_values(response, expected_values)
|
||||
|
||||
@less_console_noise_decorator
|
||||
def test_analyst_can_see_and_edit_alternative_domain(self):
|
||||
"""Tests if an analyst can still see and edit the alternative domain field"""
|
||||
|
@ -2315,6 +2420,54 @@ class DomainInvitationAdminTest(TestCase):
|
|||
self.assertContains(response, retrieved_html, count=1)
|
||||
|
||||
|
||||
class TestHostAdmin(TestCase):
|
||||
def setUp(self):
|
||||
"""Setup environment for a mock admin user"""
|
||||
super().setUp()
|
||||
self.site = AdminSite()
|
||||
self.factory = RequestFactory()
|
||||
self.admin = MyHostAdmin(model=Host, admin_site=self.site)
|
||||
self.client = Client(HTTP_HOST="localhost:8080")
|
||||
self.superuser = create_superuser()
|
||||
self.test_helper = GenericTestHelper(
|
||||
factory=self.factory,
|
||||
user=self.superuser,
|
||||
admin=self.admin,
|
||||
url="/admin/registrar/Host/",
|
||||
model=Host,
|
||||
)
|
||||
|
||||
def tearDown(self):
|
||||
super().tearDown()
|
||||
Host.objects.all().delete()
|
||||
Domain.objects.all().delete()
|
||||
|
||||
@less_console_noise_decorator
|
||||
def test_helper_text(self):
|
||||
"""
|
||||
Tests for the correct helper text on this page
|
||||
"""
|
||||
domain, _ = Domain.objects.get_or_create(name="fake.gov", state=Domain.State.READY)
|
||||
# Create a fake host
|
||||
host, _ = Host.objects.get_or_create(name="ns1.test.gov", domain=domain)
|
||||
|
||||
p = "adminpass"
|
||||
self.client.login(username="superuser", password=p)
|
||||
response = self.client.get(
|
||||
"/admin/registrar/host/{}/change/".format(host.pk),
|
||||
follow=True,
|
||||
)
|
||||
|
||||
# Make sure the page loaded
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
# These should exist in the response
|
||||
expected_values = [
|
||||
("domain", "Domain associated with this host"),
|
||||
]
|
||||
self.test_helper.assert_response_contains_distinct_values(response, expected_values)
|
||||
|
||||
|
||||
class TestDomainInformationAdmin(TestCase):
|
||||
def setUp(self):
|
||||
"""Setup environment for a mock admin user"""
|
||||
|
@ -2367,6 +2520,38 @@ class TestDomainInformationAdmin(TestCase):
|
|||
Contact.objects.all().delete()
|
||||
User.objects.all().delete()
|
||||
|
||||
@less_console_noise_decorator
|
||||
def test_helper_text(self):
|
||||
"""
|
||||
Tests for the correct helper text on this page
|
||||
"""
|
||||
|
||||
# Create a fake domain request and domain
|
||||
domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.IN_REVIEW)
|
||||
domain_request.approve()
|
||||
domain_info = DomainInformation.objects.filter(domain=domain_request.approved_domain).get()
|
||||
|
||||
p = "adminpass"
|
||||
self.client.login(username="superuser", password=p)
|
||||
response = self.client.get(
|
||||
"/admin/registrar/domaininformation/{}/change/".format(domain_info.pk),
|
||||
follow=True,
|
||||
)
|
||||
|
||||
# Make sure the page loaded, and that we're on the right page
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertContains(response, domain_info.domain.name)
|
||||
|
||||
# These should exist in the response
|
||||
expected_values = [
|
||||
("creator", "Person who submitted the domain request"),
|
||||
("submitter", 'Person listed under "your contact information" in the request form'),
|
||||
("domain_request", "Request associated with this domain"),
|
||||
("no_other_contacts_rationale", "Required if creator does not list other employees"),
|
||||
("urbanization", "Required for Puerto Rico only"),
|
||||
]
|
||||
self.test_helper.assert_response_contains_distinct_values(response, expected_values)
|
||||
|
||||
@less_console_noise_decorator
|
||||
def test_other_contacts_has_readonly_link(self):
|
||||
"""Tests if the readonly other_contacts field has links"""
|
||||
|
@ -2711,7 +2896,7 @@ class UserDomainRoleAdminTest(TestCase):
|
|||
self.assertContains(response, "Joe Jones AntarcticPolarBears@example.com</a></th>", count=1)
|
||||
|
||||
|
||||
class ListHeaderAdminTest(TestCase):
|
||||
class TestListHeaderAdmin(TestCase):
|
||||
def setUp(self):
|
||||
self.site = AdminSite()
|
||||
self.factory = RequestFactory()
|
||||
|
@ -2784,10 +2969,43 @@ class ListHeaderAdminTest(TestCase):
|
|||
User.objects.all().delete()
|
||||
|
||||
|
||||
class MyUserAdminTest(TestCase):
|
||||
class TestMyUserAdmin(TestCase):
|
||||
def setUp(self):
|
||||
admin_site = AdminSite()
|
||||
self.admin = MyUserAdmin(model=get_user_model(), admin_site=admin_site)
|
||||
self.client = Client(HTTP_HOST="localhost:8080")
|
||||
self.superuser = create_superuser()
|
||||
self.test_helper = GenericTestHelper(admin=self.admin)
|
||||
|
||||
def tearDown(self):
|
||||
super().tearDown()
|
||||
User.objects.all().delete()
|
||||
|
||||
@less_console_noise_decorator
|
||||
def test_helper_text(self):
|
||||
"""
|
||||
Tests for the correct helper text on this page
|
||||
"""
|
||||
user = create_user()
|
||||
|
||||
p = "adminpass"
|
||||
self.client.login(username="superuser", password=p)
|
||||
response = self.client.get(
|
||||
"/admin/registrar/user/{}/change/".format(user.pk),
|
||||
follow=True,
|
||||
)
|
||||
|
||||
# Make sure the page loaded
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
# These should exist in the response
|
||||
expected_values = [
|
||||
("password", "Raw passwords are not stored, so they will not display here."),
|
||||
("status", 'Users in "restricted" status cannot make updates in the registrar or start a new request.'),
|
||||
("is_staff", "Designates whether the user can log in to this admin site"),
|
||||
("is_superuser", "For development purposes only; provides superuser access on the database level"),
|
||||
]
|
||||
self.test_helper.assert_response_contains_distinct_values(response, expected_values)
|
||||
|
||||
def test_list_display_without_username(self):
|
||||
with less_console_noise():
|
||||
|
@ -2809,8 +3027,9 @@ class MyUserAdminTest(TestCase):
|
|||
def test_get_fieldsets_superuser(self):
|
||||
with less_console_noise():
|
||||
request = self.client.request().wsgi_request
|
||||
request.user = create_superuser()
|
||||
request.user = self.superuser
|
||||
fieldsets = self.admin.get_fieldsets(request)
|
||||
|
||||
expected_fieldsets = super(MyUserAdmin, self.admin).get_fieldsets(request)
|
||||
self.assertEqual(fieldsets, expected_fieldsets)
|
||||
|
||||
|
@ -2820,16 +3039,13 @@ class MyUserAdminTest(TestCase):
|
|||
request.user = create_user()
|
||||
fieldsets = self.admin.get_fieldsets(request)
|
||||
expected_fieldsets = (
|
||||
(None, {"fields": ("password", "status", "verification_type")}),
|
||||
(None, {"fields": ("status", "verification_type",)}),
|
||||
("Personal Info", {"fields": ("first_name", "last_name", "email")}),
|
||||
("Permissions", {"fields": ("is_active", "groups")}),
|
||||
("Important dates", {"fields": ("last_login", "date_joined")}),
|
||||
)
|
||||
self.assertEqual(fieldsets, expected_fieldsets)
|
||||
|
||||
def tearDown(self):
|
||||
User.objects.all().delete()
|
||||
|
||||
|
||||
class AuditedAdminTest(TestCase):
|
||||
def setUp(self):
|
||||
|
@ -3303,10 +3519,43 @@ class ContactAdminTest(TestCase):
|
|||
User.objects.all().delete()
|
||||
|
||||
|
||||
class VerifiedByStaffAdminTestCase(TestCase):
|
||||
class TestVerifiedByStaffAdmin(TestCase):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.site = AdminSite()
|
||||
self.superuser = create_superuser()
|
||||
self.admin = VerifiedByStaffAdmin(model=VerifiedByStaff, admin_site=self.site)
|
||||
self.factory = RequestFactory()
|
||||
self.client = Client(HTTP_HOST="localhost:8080")
|
||||
self.test_helper = GenericTestHelper(admin=self.admin)
|
||||
|
||||
def tearDown(self):
|
||||
super().tearDown()
|
||||
VerifiedByStaff.objects.all().delete()
|
||||
User.objects.all().delete()
|
||||
|
||||
@less_console_noise_decorator
|
||||
def test_helper_text(self):
|
||||
"""
|
||||
Tests for the correct helper text on this page
|
||||
"""
|
||||
vip_instance, _ = VerifiedByStaff.objects.get_or_create(email="test@example.com", notes="Test Notes")
|
||||
|
||||
p = "adminpass"
|
||||
self.client.login(username="superuser", password=p)
|
||||
response = self.client.get(
|
||||
"/admin/registrar/verifiedbystaff/{}/change/".format(vip_instance.pk),
|
||||
follow=True,
|
||||
)
|
||||
|
||||
# Make sure the page loaded
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
# These should exist in the response
|
||||
expected_values = [
|
||||
("requestor", "Person who verified this user"),
|
||||
]
|
||||
self.test_helper.assert_response_contains_distinct_values(response, expected_values)
|
||||
|
||||
def test_save_model_sets_user_field(self):
|
||||
with less_console_noise():
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue