diff --git a/src/registrar/migrations/0044_create_groups_v04.py b/src/registrar/migrations/0044_create_groups_v04.py
new file mode 100644
index 000000000..ecb48e335
--- /dev/null
+++ b/src/registrar/migrations/0044_create_groups_v04.py
@@ -0,0 +1,37 @@
+# This migration creates the create_full_access_group and create_cisa_analyst_group groups
+# It is dependent on 0035 (which populates ContentType and Permissions)
+# If permissions on the groups need changing, edit CISA_ANALYST_GROUP_PERMISSIONS
+# in the user_group model then:
+# [NOT RECOMMENDED]
+# step 1: docker-compose exec app ./manage.py migrate --fake registrar 0035_contenttypes_permissions
+# step 2: docker-compose exec app ./manage.py migrate registrar 0036_create_groups
+# step 3: fake run the latest migration in the migrations list
+# [RECOMMENDED]
+# Alternatively:
+# step 1: duplicate the migration that loads data
+# step 2: docker-compose exec app ./manage.py migrate
+
+from django.db import migrations
+from registrar.models import UserGroup
+from typing import Any
+
+
+# For linting: RunPython expects a function reference,
+# so let's give it one
+def create_groups(apps, schema_editor) -> Any:
+ UserGroup.create_cisa_analyst_group(apps, schema_editor)
+ UserGroup.create_full_access_group(apps, schema_editor)
+
+
+class Migration(migrations.Migration):
+ dependencies = [
+ ("registrar", "0043_domain_expiration_date"),
+ ]
+
+ operations = [
+ migrations.RunPython(
+ create_groups,
+ reverse_code=migrations.RunPython.noop,
+ atomic=True,
+ ),
+ ]
diff --git a/src/registrar/templates/401.html b/src/registrar/templates/401.html
index a419dab53..21ac9db35 100644
--- a/src/registrar/templates/401.html
+++ b/src/registrar/templates/401.html
@@ -26,7 +26,7 @@
Would you like to try logging in again?
- If you'd like help with this error contact us .
+ If you'd like help with this error contact us.
{% if log_identifier %}
diff --git a/src/registrar/templates/403.html b/src/registrar/templates/403.html
index 93d32f65a..08057dfba 100644
--- a/src/registrar/templates/403.html
+++ b/src/registrar/templates/403.html
@@ -26,7 +26,7 @@
Would you like to try logging in again?
- If you'd like help with this error contact us .
+ If you'd like help with this error contact us.
We typically don’t reach out to the authorizing official, but if contact is necessary, our practice is to coordinate first with you, the requestor. Read more about who can serve as an authorizing official.
+
We typically don’t reach out to the authorizing official, but if contact is necessary, our practice is to coordinate first with you, the requestor. Read more about who can serve as an authorizing official.
diff --git a/src/registrar/templates/application_purpose.html b/src/registrar/templates/application_purpose.html
index ca2ff7287..5135e6678 100644
--- a/src/registrar/templates/application_purpose.html
+++ b/src/registrar/templates/application_purpose.html
@@ -8,7 +8,7 @@ domain name or for mainly internal use.
Describe the reason for your domain request. Explain how you plan to use this domain.
Who is your intended audience? Will you use it for a website and/or email? Are you moving
your website from another top-level domain (like .com or .org)?
-Read about activities that are prohibited on .gov domains.
+Read about activities that are prohibited on .gov domains.
{% endblock %}
diff --git a/src/registrar/templates/application_tribal_government.html b/src/registrar/templates/application_tribal_government.html
index 3c2a8999f..bdca60907 100644
--- a/src/registrar/templates/application_tribal_government.html
+++ b/src/registrar/templates/application_tribal_government.html
@@ -7,7 +7,7 @@
{% with sublabel_text="Please include the entire name of your tribe as recognized by the Bureau of Indian Affairs." %}
{% with link_text="Bureau of Indian Affairs" %}
{% with link_href="https://www.federalregister.gov/documents/2023/01/12/2023-00504/indian-entities-recognized-by-and-eligible-to-receive-services-from-the-united-states-bureau-of" %}
- {% with target_blank="true" %}
+ {% with external_link="true" target_blank="true" %}
{% input_with_errors forms.0.tribe_name %}
{% endwith %}
{% endwith %}
diff --git a/src/registrar/templates/domain_authorizing_official.html b/src/registrar/templates/domain_authorizing_official.html
index c12f1f290..93b4b1b50 100644
--- a/src/registrar/templates/domain_authorizing_official.html
+++ b/src/registrar/templates/domain_authorizing_official.html
@@ -10,7 +10,7 @@
Authorizing official
Your authorizing official is the person within your organization who can
- authorize domain requests. This person must be in a role of significant, executive responsibility within the organization. Read more about who can serve as an authorizing official.
+ authorize domain requests. This person must be in a role of significant, executive responsibility within the organization. Read more about who can serve as an authorizing official.
{% include "includes/required_fields.html" %}
diff --git a/src/registrar/templates/domain_base.html b/src/registrar/templates/domain_base.html
index d2870a82c..b5f70d341 100644
--- a/src/registrar/templates/domain_base.html
+++ b/src/registrar/templates/domain_base.html
@@ -16,49 +16,60 @@
- {% include 'domain_sidebar.html' %}
+ {% if domain.domain_info %}
+ {% include 'domain_sidebar.html' %}
+ {% endif %}
-
- {% if is_analyst_or_superuser and analyst_action == 'edit' and analyst_action_location == domain.pk %}
-
-
-
Attention!
-
- You are making changes to a registrant’s domain. When finished making changes, close this tab and inform the registrant of your updates.
-
-
- {% endif %}
- {# messages block is under the back breadcrumb link #}
- {% if messages %}
- {% for message in messages %}
-
+ {% if not domain.domain_info %}
+
- {{ message }}
+
Domain missing domain information
+
+ You are attempting to manage a domain, {{ domain.name }}, which does not have a domain information object. Please correct this in the admin by editing the domain, and adding domain information, as appropriate.
+
-
- {% endfor %}
+
+ {% else %}
+ {% if is_analyst_or_superuser and analyst_action == 'edit' and analyst_action_location == domain.pk %}
+
+
+
Attention!
+
+ You are making changes to a registrant’s domain. When finished making changes, close this tab and inform the registrant of your updates.
+
We strongly recommend that you provide a security email. This email will allow the public to report observed or suspected security issues on your domain. Security emails are made public and included in the .gov domain data we provide.
+
We strongly recommend that you provide a security email. This email will allow the public to report observed or suspected security issues on your domain. Security emails are made public and included in the .gov domain data we provide.
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.
Domain requests from state legislatures and courts must be authorized by an agency’s Chief Information Officer or highest-ranking executive.
{% elif organization_type == 'tribal' %}
-
Domain requests from federally-recognized tribal governments must be authorized by the leader of the tribe, as recognized by the Bureau of Indian Affairs.
+
Domain requests from federally-recognized tribal governments must be authorized by the leader of the tribe, as recognized by the Bureau of Indian Affairs.
Domain requests from state-recognized tribal governments must be authorized by the leader of the tribe, as determined by the state’s tribal recognition initiative.
Most county .gov domains must include the two-letter state abbreviation or the full state name. County names that aren’t shared by any other city, county, parish, town, borough, village or equivalent in the U.S., at the time a domain is granted, can be requested without referring to the state. Counties can include “county” in their domain to distinguish it from other places with similar names. We use the Census Bureau’s National Places Gazetteer Files to determine if county names are unique.
+
Most county .gov domains must include the two-letter state abbreviation or the full state name. County names that aren’t shared by any other city, county, parish, town, borough, village or equivalent in the U.S., at the time a domain is granted, can be requested without referring to the state. Counties can include “county” in their domain to distinguish it from other places with similar names. We use the Census Bureau’s National Places Gazetteer Files to determine if county names are unique.
Examples:
AdamsCountyMS.gov
@@ -68,7 +68,7 @@
Most city domains must include the two-letter state abbreviation or clearly spell out the state name. Using phrases like “City of” or “Town of” is optional.
Cities that meet one of the criteria below don’t have to refer to their state in the domain name.
-
City names that are not shared by any other U.S. city, town, or village can be requested without referring to the state. We use the Census Bureau’s National Places Gazetteer Files to determine if names are unique.
+
City names that are not shared by any other U.S. city, town, or village can be requested without referring to the state. We use the Census Bureau’s National Places Gazetteer Files to determine if names are unique.
Certain cities are so well-known that they may not require a state reference to communicate location. We use the list of U.S. “dateline cities” in the Associated Press Stylebook to make this determination.
The 50 largest cities, as measured by population according to the Census Bureau, can have .gov domain names that don’t refer to their state.
Domain names must represent your organization or institutional name, not solely the services you provide. It also needs to include your two-letter state abbreviation or clearly spell out the state name unless county or city exceptions apply.
+
Domain names must represent your organization or institutional name, not solely the services you provide. It also needs to include your two-letter state abbreviation or clearly spell out the state name unless county or city exceptions apply.
diff --git a/src/registrar/templates/includes/input_with_errors.html b/src/registrar/templates/includes/input_with_errors.html
index 2adc08984..56bd0b111 100644
--- a/src/registrar/templates/includes/input_with_errors.html
+++ b/src/registrar/templates/includes/input_with_errors.html
@@ -37,7 +37,7 @@ error messages, if necessary.
{% with link_index=sublabel_text|find_index:link_text %}
{{ sublabel_text|slice:link_index }}
{% comment %} HTML will convert a new line into a space, resulting with a space before the fullstop in case link_text is at the end of sublabel_text, hence the unfortunate line below {% endcomment %}
- {{ link_text }}{% with sublabel_part_after=sublabel_text|slice_after:link_text %}{{ sublabel_part_after }}{% endwith %}
+ {{ link_text }}{% with sublabel_part_after=sublabel_text|slice_after:link_text %}{{ sublabel_part_after }}{% endwith %}
{% endwith %}
{% else %}
{{ sublabel_text }}
diff --git a/src/registrar/tests/common.py b/src/registrar/tests/common.py
index ad464bb3e..ed6ea3366 100644
--- a/src/registrar/tests/common.py
+++ b/src/registrar/tests/common.py
@@ -453,7 +453,7 @@ def create_user():
p = "userpass"
user = User.objects.create_user(
username="staffuser",
- email="user@example.com",
+ email="staff@example.com",
is_staff=True,
password=p,
)
diff --git a/src/registrar/tests/test_views.py b/src/registrar/tests/test_views.py
index c30e84248..681f25468 100644
--- a/src/registrar/tests/test_views.py
+++ b/src/registrar/tests/test_views.py
@@ -5,7 +5,7 @@ from django.conf import settings
from django.test import Client, TestCase
from django.urls import reverse
from django.contrib.auth import get_user_model
-from .common import MockEppLib, completed_application # type: ignore
+from .common import MockEppLib, completed_application, create_user # type: ignore
from django_webtest import WebTest # type: ignore
import boto3_mocking # type: ignore
@@ -1105,6 +1105,9 @@ class TestWithDomainPermissions(TestWithUser):
self.domain_just_nameserver, _ = Domain.objects.get_or_create(
name="justnameserver.com"
)
+ self.domain_no_information, _ = Domain.objects.get_or_create(
+ name="noinformation.gov"
+ )
self.domain_dsdata, _ = Domain.objects.get_or_create(name="dnssec-dsdata.gov")
self.domain_multdsdata, _ = Domain.objects.get_or_create(
@@ -1278,6 +1281,29 @@ class TestDomainOverview(TestWithDomainPermissions, WebTest):
self.assertContains(detail_page, "(1.2.3.4,")
self.assertContains(detail_page, "2.3.4.5)")
+ def test_domain_with_no_information_or_application(self):
+ """Test that domain management page returns 200 and displays error
+ when no domain information or domain application exist"""
+ # have to use staff user for this test
+ staff_user = create_user()
+ # staff_user.save()
+ self.client.force_login(staff_user)
+
+ # need to set the analyst_action and analyst_action_location
+ # in the session to emulate user clicking Manage Domain
+ # in the admin interface
+ session = self.client.session
+ session["analyst_action"] = "foo"
+ session["analyst_action_location"] = self.domain_no_information.id
+ session.save()
+
+ detail_page = self.client.get(
+ reverse("domain", kwargs={"pk": self.domain_no_information.id})
+ )
+
+ self.assertContains(detail_page, "noinformation.gov")
+ self.assertContains(detail_page, "Domain missing domain information")
+
class TestDomainManagers(TestDomainOverview):
def test_domain_managers(self):
diff --git a/src/registrar/views/utility/mixins.py b/src/registrar/views/utility/mixins.py
index 02cc25d64..f49359588 100644
--- a/src/registrar/views/utility/mixins.py
+++ b/src/registrar/views/utility/mixins.py
@@ -100,8 +100,15 @@ class DomainPermission(PermissionsLoginMixin):
if DomainInformation.objects.filter(id=pk).exists():
requested_domain = DomainInformation.objects.get(id=pk)
- domain_application = requested_domain.domain_application
- if domain_application.status not in valid_domain_statuses:
+ # if no domain information or application exist, the user
+ # should be able to manage the domain; however, if domain information
+ # and domain application exist, and application is not in valid status,
+ # user should not be able to manage domain
+ if (
+ requested_domain
+ and requested_domain.domain_application
+ and requested_domain.domain_application.status not in valid_domain_statuses
+ ):
return False
# Valid session keys exist,