mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-08-28 12:03:53 +02:00
Merge branch 'main' into za/2402-design-review
This commit is contained in:
commit
afe498978c
80 changed files with 2896 additions and 1532 deletions
|
@ -9,10 +9,10 @@ We use [django-waffle](https://waffle.readthedocs.io/en/stable/) for our feature
|
||||||
3. Click `Add waffle flag`.
|
3. Click `Add waffle flag`.
|
||||||
4. Add the model as you would normally. Refer to waffle's documentation [regarding attributes](https://waffle.readthedocs.io/en/stable/types/flag.html#flag-attributes) for more information on them.
|
4. Add the model as you would normally. Refer to waffle's documentation [regarding attributes](https://waffle.readthedocs.io/en/stable/types/flag.html#flag-attributes) for more information on them.
|
||||||
|
|
||||||
### Enabling the profile_feature flag
|
### Enabling a feature flag
|
||||||
1. On the app, navigate to `\admin`.
|
1. On the app, navigate to `\admin`.
|
||||||
2. Under models, click `Waffle flags`.
|
2. Under models, click `Waffle flags`.
|
||||||
3. Click the `profile_feature` record. This should exist by default, if not - create one with that name.
|
3. Click the featue flag record. This should exist by default, if not - create one with that name.
|
||||||
4. (Important) Set the field `Everyone` to `Unknown`. This field overrides all other settings when set to anything else.
|
4. (Important) Set the field `Everyone` to `Unknown`. This field overrides all other settings when set to anything else.
|
||||||
5. Configure the settings as you see fit.
|
5. Configure the settings as you see fit.
|
||||||
|
|
||||||
|
|
|
@ -126,7 +126,15 @@ class AvailableAPITest(MockEppLib):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super().setUp()
|
super().setUp()
|
||||||
self.user = get_user_model().objects.create(username="username")
|
username = "test_user"
|
||||||
|
first_name = "First"
|
||||||
|
last_name = "Last"
|
||||||
|
email = "info@example.com"
|
||||||
|
title = "title"
|
||||||
|
phone = "8080102431"
|
||||||
|
self.user = get_user_model().objects.create(
|
||||||
|
username=username, title=title, first_name=first_name, last_name=last_name, email=email, phone=phone
|
||||||
|
)
|
||||||
|
|
||||||
def test_available_get(self):
|
def test_available_get(self):
|
||||||
self.client.force_login(self.user)
|
self.client.force_login(self.user)
|
||||||
|
|
|
@ -1923,11 +1923,7 @@ class DomainRequestAdmin(ListHeaderAdmin, ImportExportModelAdmin):
|
||||||
so we should display that information using this function.
|
so we should display that information using this function.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if hasattr(obj, "creator"):
|
|
||||||
recipient = obj.creator
|
recipient = obj.creator
|
||||||
else:
|
|
||||||
recipient = None
|
|
||||||
|
|
||||||
# Displays a warning in admin when an email cannot be sent
|
# Displays a warning in admin when an email cannot be sent
|
||||||
if recipient and recipient.email:
|
if recipient and recipient.email:
|
||||||
|
@ -2132,7 +2128,6 @@ class DomainRequestAdmin(ListHeaderAdmin, ImportExportModelAdmin):
|
||||||
extra_context["filtered_audit_log_entries"] = filtered_audit_log_entries
|
extra_context["filtered_audit_log_entries"] = filtered_audit_log_entries
|
||||||
emails = self.get_all_action_needed_reason_emails(obj)
|
emails = self.get_all_action_needed_reason_emails(obj)
|
||||||
extra_context["action_needed_reason_emails"] = json.dumps(emails)
|
extra_context["action_needed_reason_emails"] = json.dumps(emails)
|
||||||
extra_context["has_profile_feature_flag"] = flag_is_active(request, "profile_feature")
|
|
||||||
|
|
||||||
# Denote if an action needed email was sent or not
|
# Denote if an action needed email was sent or not
|
||||||
email_sent = request.session.get("action_needed_email_sent", False)
|
email_sent = request.session.get("action_needed_email_sent", False)
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,3 +1,5 @@
|
||||||
|
@use "base" as *;
|
||||||
|
|
||||||
// Fixes some font size disparities with the Figma
|
// Fixes some font size disparities with the Figma
|
||||||
// for usa-alert alert elements
|
// for usa-alert alert elements
|
||||||
.usa-alert {
|
.usa-alert {
|
||||||
|
@ -22,3 +24,8 @@
|
||||||
margin-left: 0.5rem!important;
|
margin-left: 0.5rem!important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE: !important is used because _font.scss overrides this
|
||||||
|
.usa-alert__body--widescreen {
|
||||||
|
max-width: $widescreen-max-width !important;
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
@use "uswds-core" as *;
|
@use "uswds-core" as *;
|
||||||
@use "cisa_colors" as *;
|
@use "cisa_colors" as *;
|
||||||
|
|
||||||
|
$widescreen-max-width: 1920px;
|
||||||
|
|
||||||
/* Styles for making visible to screen reader / AT users only. */
|
/* Styles for making visible to screen reader / AT users only. */
|
||||||
.sr-only {
|
.sr-only {
|
||||||
@include sr-only;
|
@include sr-only;
|
||||||
|
@ -102,6 +104,24 @@ body {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
This is a hack to keep the "Export" button on Domain Requests page inline
|
||||||
|
with the searchbar in widescreen mode.
|
||||||
|
|
||||||
|
EXPLANATION: The existing frontend implementation puts the searchbar and export
|
||||||
|
button in two separate columns in a grid, which creates a solid wrap-around effect
|
||||||
|
for mobile devices. The searchbar had a max-width that exactly equaled the max width
|
||||||
|
of its parent column (for non-widescreens), so there wasn't any issue at this time of
|
||||||
|
implementation.
|
||||||
|
However, during immplementation of widescreen mode this small max-width caused the searchbar to
|
||||||
|
no longer fill its parent grid column for larger screen sizes, creating a visual gap between
|
||||||
|
it and the adjacent export button. To fix this, we will limit the width of the first
|
||||||
|
grid column to the max-width of the searchbar, which was calculated to be 33rem.
|
||||||
|
*/
|
||||||
|
.section-outlined__search--widescreen {
|
||||||
|
max-width: 33rem;
|
||||||
|
}
|
||||||
|
|
||||||
.break-word {
|
.break-word {
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
}
|
}
|
||||||
|
@ -222,6 +242,14 @@ abbr[title] {
|
||||||
left: auto!important;
|
left: auto!important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.usa-banner__inner--widescreen {
|
||||||
|
max-width: $widescreen-max-width;
|
||||||
|
}
|
||||||
|
|
||||||
|
.margin-right-neg-4px {
|
||||||
|
margin-right: -4px;
|
||||||
|
}
|
||||||
|
|
||||||
.break-word {
|
.break-word {
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
@use "uswds-core" as *;
|
@use "uswds-core" as *;
|
||||||
@use "cisa_colors" as *;
|
@use "cisa_colors" as *;
|
||||||
|
|
||||||
/* Make "placeholder" links visually obvious */
|
// Used on: TODO links
|
||||||
|
// Used on: NONE
|
||||||
a[href$="todo"]::after {
|
a[href$="todo"]::after {
|
||||||
background-color: yellow;
|
background-color: yellow;
|
||||||
color: color(blue-80v);
|
color: color(blue-80v);
|
||||||
|
@ -9,10 +10,14 @@ a[href$="todo"]::after {
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Used on: profile
|
||||||
|
// Note: Is this needed?
|
||||||
a.usa-link.usa-link--always-blue {
|
a.usa-link.usa-link--always-blue {
|
||||||
color: #{$dhs-blue};
|
color: #{$dhs-blue};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Used on: breadcrumbs
|
||||||
|
// Note: This could potentially be simplified and use usa-button--with-icon
|
||||||
a.breadcrumb__back {
|
a.breadcrumb__back {
|
||||||
display:flex;
|
display:flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
@ -28,10 +33,18 @@ a.breadcrumb__back {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove anchor buttons' underline
|
||||||
a.usa-button {
|
a.usa-button {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unstyled anchor buttons
|
||||||
|
a.usa-button--unstyled:visited {
|
||||||
|
color: color('primary');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disabled anchor buttons
|
||||||
|
// NOTE: Not used
|
||||||
a.usa-button.disabled-link {
|
a.usa-button.disabled-link {
|
||||||
background-color: #ccc !important;
|
background-color: #ccc !important;
|
||||||
color: #454545 !important
|
color: #454545 !important
|
||||||
|
@ -58,6 +71,8 @@ a.usa-button--unstyled.disabled-link:focus {
|
||||||
text-decoration: none !important;
|
text-decoration: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Disabled buttons
|
||||||
|
// Used on: Domain managers, disabled logo on profile
|
||||||
.usa-button--unstyled.disabled-button,
|
.usa-button--unstyled.disabled-button,
|
||||||
.usa-button--unstyled.disabled-button:hover,
|
.usa-button--unstyled.disabled-button:hover,
|
||||||
.usa-button--unstyled.disabled-button:focus {
|
.usa-button--unstyled.disabled-button:focus {
|
||||||
|
@ -66,6 +81,16 @@ a.usa-button--unstyled.disabled-link:focus {
|
||||||
text-decoration: none !important;
|
text-decoration: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unstyled variant for reverse out?
|
||||||
|
// Used on: NONE
|
||||||
|
.usa-button--unstyled--white,
|
||||||
|
.usa-button--unstyled--white:hover,
|
||||||
|
.usa-button--unstyled--white:focus,
|
||||||
|
.usa-button--unstyled--white:active {
|
||||||
|
color: color('white');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Solid anchor buttons
|
||||||
a.usa-button:not(.usa-button--unstyled, .usa-button--outline) {
|
a.usa-button:not(.usa-button--unstyled, .usa-button--outline) {
|
||||||
color: color('white');
|
color: color('white');
|
||||||
}
|
}
|
||||||
|
@ -77,6 +102,7 @@ a.usa-button:not(.usa-button--unstyled, .usa-button--outline):active {
|
||||||
color: color('white');
|
color: color('white');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Outline anchor buttons
|
||||||
a.usa-button--outline,
|
a.usa-button--outline,
|
||||||
a.usa-button--outline:visited {
|
a.usa-button--outline:visited {
|
||||||
box-shadow: inset 0 0 0 2px color('primary');
|
box-shadow: inset 0 0 0 2px color('primary');
|
||||||
|
@ -94,10 +120,22 @@ a.usa-button--outline:active {
|
||||||
color: color('primary-darker');
|
color: color('primary-darker');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Used on: Domain request withdraw confirmation
|
||||||
a.withdraw {
|
a.withdraw {
|
||||||
background-color: color('error');
|
background-color: color('error');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a.withdraw:hover,
|
||||||
|
a.withdraw:focus {
|
||||||
|
background-color: color('error-dark');
|
||||||
|
}
|
||||||
|
|
||||||
|
a.withdraw:active {
|
||||||
|
background-color: color('error-darker');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used on: Domain request status
|
||||||
|
//NOTE: Revise to BEM convention usa-button--outline-secondary
|
||||||
a.withdraw_outline,
|
a.withdraw_outline,
|
||||||
a.withdraw_outline:visited {
|
a.withdraw_outline:visited {
|
||||||
box-shadow: inset 0 0 0 2px color('error');
|
box-shadow: inset 0 0 0 2px color('error');
|
||||||
|
@ -115,19 +153,8 @@ a.withdraw_outline:active {
|
||||||
color: color('error-darker');
|
color: color('error-darker');
|
||||||
}
|
}
|
||||||
|
|
||||||
a.withdraw:hover,
|
|
||||||
a.withdraw:focus {
|
|
||||||
background-color: color('error-dark');
|
|
||||||
}
|
|
||||||
|
|
||||||
a.withdraw:active {
|
|
||||||
background-color: color('error-darker');
|
|
||||||
}
|
|
||||||
|
|
||||||
a.usa-button--unstyled:visited {
|
|
||||||
color: color('primary');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Used on: Domain request submit
|
||||||
.dotgov-button--green {
|
.dotgov-button--green {
|
||||||
background-color: color('success-dark');
|
background-color: color('success-dark');
|
||||||
|
|
||||||
|
@ -140,15 +167,8 @@ a.usa-button--unstyled:visited {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.usa-button--unstyled--white,
|
// Cancel button
|
||||||
.usa-button--unstyled--white:hover,
|
// Used on: DNSSEC main page
|
||||||
.usa-button--unstyled--white:focus,
|
|
||||||
.usa-button--unstyled--white:active {
|
|
||||||
color: color('white');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cancel button used on the
|
|
||||||
// DNSSEC main page
|
|
||||||
// We want to center this button on mobile
|
// We want to center this button on mobile
|
||||||
// and add some extra left margin on tablet+
|
// and add some extra left margin on tablet+
|
||||||
.usa-button--cancel {
|
.usa-button--cancel {
|
||||||
|
@ -175,6 +195,8 @@ a.usa-button--unstyled:visited {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Used on: Profile page, toggleable fields
|
||||||
|
// Note: Could potentially be cleaned up by using usa-button--with-icon
|
||||||
// We need to deviate from some default USWDS styles here
|
// We need to deviate from some default USWDS styles here
|
||||||
// in this particular case, so we have to override this.
|
// in this particular case, so we have to override this.
|
||||||
.usa-form .usa-button.readonly-edit-button {
|
.usa-form .usa-button.readonly-edit-button {
|
||||||
|
@ -186,6 +208,7 @@ a.usa-button--unstyled:visited {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Used on: Domains and Requests tables
|
||||||
.usa-button--filter {
|
.usa-button--filter {
|
||||||
width: auto;
|
width: auto;
|
||||||
// For mobile stacking
|
// For mobile stacking
|
||||||
|
@ -201,6 +224,8 @@ a.usa-button--unstyled:visited {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Buttons with nested icons
|
||||||
|
// Note: Can be simplified by adding usa-link--icon to anchors in tables
|
||||||
.dotgov-table a,
|
.dotgov-table a,
|
||||||
.usa-link--icon,
|
.usa-link--icon,
|
||||||
.usa-button--with-icon {
|
.usa-button--with-icon {
|
||||||
|
@ -224,6 +249,9 @@ a .usa-icon,
|
||||||
width: 1.5em;
|
width: 1.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Red, for delete buttons
|
||||||
|
// Used on: All delete buttons
|
||||||
|
// Note: Can be simplified by adding text-secondary to delete anchors in tables
|
||||||
button.text-secondary,
|
button.text-secondary,
|
||||||
button.text-secondary:hover,
|
button.text-secondary:hover,
|
||||||
.dotgov-table a.text-secondary {
|
.dotgov-table a.text-secondary {
|
||||||
|
|
8
src/registrar/assets/sass/_theme/_containers.scss
Normal file
8
src/registrar/assets/sass/_theme/_containers.scss
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
@use "uswds-core" as *;
|
||||||
|
@use "base" as *;
|
||||||
|
|
||||||
|
//NOTE: !important is needed because it gets overriden by other .scss for footer nav
|
||||||
|
.grid-container--widescreen,
|
||||||
|
.usa-identifier__container--widescreen {
|
||||||
|
max-width: $widescreen-max-width !important;
|
||||||
|
}
|
|
@ -85,7 +85,7 @@ legend.float-left-tablet + button.float-right-tablet {
|
||||||
|
|
||||||
.read-only-label {
|
.read-only-label {
|
||||||
font-size: size('body', 'sm');
|
font-size: size('body', 'sm');
|
||||||
color: color('primary');
|
color: color('primary-dark');
|
||||||
margin-bottom: units(0.5);
|
margin-bottom: units(0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
@use "uswds-core" as *;
|
@use "uswds-core" as *;
|
||||||
@use "cisa_colors" as *;
|
@use "cisa_colors" as *;
|
||||||
|
@use "base" as *;
|
||||||
|
|
||||||
// Define some styles for the .gov header/logo
|
// Define some styles for the .gov header/logo
|
||||||
.usa-logo button {
|
.usa-logo button {
|
||||||
|
@ -127,3 +128,9 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.usa-nav__inner--widescreen,
|
||||||
|
.usa-navbar--widescreen,
|
||||||
|
.usa-nav-container--widescreen {
|
||||||
|
max-width: $widescreen-max-width !important;
|
||||||
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
@forward "identifier";
|
@forward "identifier";
|
||||||
@forward "header";
|
@forward "header";
|
||||||
@forward "register-form";
|
@forward "register-form";
|
||||||
|
@forward "containers";
|
||||||
|
|
||||||
/*--------------------------------------------------
|
/*--------------------------------------------------
|
||||||
--- Admin ---------------------------------*/
|
--- Admin ---------------------------------*/
|
||||||
|
|
|
@ -245,8 +245,8 @@ TEMPLATES = [
|
||||||
"registrar.context_processors.is_production",
|
"registrar.context_processors.is_production",
|
||||||
"registrar.context_processors.org_user_status",
|
"registrar.context_processors.org_user_status",
|
||||||
"registrar.context_processors.add_path_to_context",
|
"registrar.context_processors.add_path_to_context",
|
||||||
"registrar.context_processors.add_has_profile_feature_flag_to_context",
|
|
||||||
"registrar.context_processors.portfolio_permissions",
|
"registrar.context_processors.portfolio_permissions",
|
||||||
|
"registrar.context_processors.is_widescreen_mode",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -169,6 +169,11 @@ urlpatterns = [
|
||||||
views.DomainRequestStatus.as_view(),
|
views.DomainRequestStatus.as_view(),
|
||||||
name="domain-request-status",
|
name="domain-request-status",
|
||||||
),
|
),
|
||||||
|
path(
|
||||||
|
"domain-request/viewonly/<int:pk>",
|
||||||
|
views.PortfolioDomainRequestStatusViewOnly.as_view(),
|
||||||
|
name="domain-request-status-viewonly",
|
||||||
|
),
|
||||||
path(
|
path(
|
||||||
"domain-request/<int:pk>/withdraw",
|
"domain-request/<int:pk>/withdraw",
|
||||||
views.DomainRequestWithdrawConfirmation.as_view(),
|
views.DomainRequestWithdrawConfirmation.as_view(),
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from waffle.decorators import flag_is_active
|
|
||||||
|
|
||||||
|
|
||||||
def language_code(request):
|
def language_code(request):
|
||||||
|
@ -54,10 +53,6 @@ def add_path_to_context(request):
|
||||||
return {"path": getattr(request, "path", None)}
|
return {"path": getattr(request, "path", None)}
|
||||||
|
|
||||||
|
|
||||||
def add_has_profile_feature_flag_to_context(request):
|
|
||||||
return {"has_profile_feature_flag": flag_is_active(request, "profile_feature")}
|
|
||||||
|
|
||||||
|
|
||||||
def portfolio_permissions(request):
|
def portfolio_permissions(request):
|
||||||
"""Make portfolio permissions for the request user available in global context"""
|
"""Make portfolio permissions for the request user available in global context"""
|
||||||
portfolio_context = {
|
portfolio_context = {
|
||||||
|
@ -99,3 +94,8 @@ def portfolio_permissions(request):
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
# Handles cases where request.user might not exist
|
# Handles cases where request.user might not exist
|
||||||
return portfolio_context
|
return portfolio_context
|
||||||
|
|
||||||
|
|
||||||
|
def is_widescreen_mode(request):
|
||||||
|
widescreen_paths = ["/domains/", "/requests/"]
|
||||||
|
return {"is_widescreen_mode": any(path in request.path for path in widescreen_paths) or request.path == "/"}
|
||||||
|
|
|
@ -4,7 +4,6 @@ from itertools import zip_longest
|
||||||
from typing import Callable
|
from typing import Callable
|
||||||
from django.db.models.fields.related import ForeignObjectRel
|
from django.db.models.fields.related import ForeignObjectRel
|
||||||
from django import forms
|
from django import forms
|
||||||
|
|
||||||
from registrar.models import DomainRequest, Contact
|
from registrar.models import DomainRequest, Contact
|
||||||
|
|
||||||
|
|
||||||
|
@ -278,3 +277,15 @@ class BaseYesNoForm(RegistrarForm):
|
||||||
# No pre-selection for new domain requests
|
# No pre-selection for new domain requests
|
||||||
initial_value = self.form_is_checked if self.domain_request else None
|
initial_value = self.form_is_checked if self.domain_request else None
|
||||||
return initial_value
|
return initial_value
|
||||||
|
|
||||||
|
|
||||||
|
def request_step_list(request_wizard):
|
||||||
|
"""Dynamically generated list of steps in the form wizard."""
|
||||||
|
step_list = []
|
||||||
|
for step in request_wizard.StepEnum:
|
||||||
|
condition = request_wizard.WIZARD_CONDITIONS.get(step, True)
|
||||||
|
if callable(condition):
|
||||||
|
condition = condition(request_wizard)
|
||||||
|
if condition:
|
||||||
|
step_list.append(step)
|
||||||
|
return step_list
|
||||||
|
|
|
@ -0,0 +1,229 @@
|
||||||
|
# Generated by Django 4.2.10 on 2024-09-11 21:00
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("registrar", "0127_remove_domaininformation_submitter_and_more"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="domaininformation",
|
||||||
|
name="state_territory",
|
||||||
|
field=models.CharField(
|
||||||
|
blank=True,
|
||||||
|
choices=[
|
||||||
|
("AL", "Alabama (AL)"),
|
||||||
|
("AK", "Alaska (AK)"),
|
||||||
|
("AS", "American Samoa (AS)"),
|
||||||
|
("AZ", "Arizona (AZ)"),
|
||||||
|
("AR", "Arkansas (AR)"),
|
||||||
|
("CA", "California (CA)"),
|
||||||
|
("CO", "Colorado (CO)"),
|
||||||
|
("CT", "Connecticut (CT)"),
|
||||||
|
("DE", "Delaware (DE)"),
|
||||||
|
("DC", "District of Columbia (DC)"),
|
||||||
|
("FL", "Florida (FL)"),
|
||||||
|
("GA", "Georgia (GA)"),
|
||||||
|
("GU", "Guam (GU)"),
|
||||||
|
("HI", "Hawaii (HI)"),
|
||||||
|
("ID", "Idaho (ID)"),
|
||||||
|
("IL", "Illinois (IL)"),
|
||||||
|
("IN", "Indiana (IN)"),
|
||||||
|
("IA", "Iowa (IA)"),
|
||||||
|
("KS", "Kansas (KS)"),
|
||||||
|
("KY", "Kentucky (KY)"),
|
||||||
|
("LA", "Louisiana (LA)"),
|
||||||
|
("ME", "Maine (ME)"),
|
||||||
|
("MD", "Maryland (MD)"),
|
||||||
|
("MA", "Massachusetts (MA)"),
|
||||||
|
("MI", "Michigan (MI)"),
|
||||||
|
("MN", "Minnesota (MN)"),
|
||||||
|
("MS", "Mississippi (MS)"),
|
||||||
|
("MO", "Missouri (MO)"),
|
||||||
|
("MT", "Montana (MT)"),
|
||||||
|
("NE", "Nebraska (NE)"),
|
||||||
|
("NV", "Nevada (NV)"),
|
||||||
|
("NH", "New Hampshire (NH)"),
|
||||||
|
("NJ", "New Jersey (NJ)"),
|
||||||
|
("NM", "New Mexico (NM)"),
|
||||||
|
("NY", "New York (NY)"),
|
||||||
|
("NC", "North Carolina (NC)"),
|
||||||
|
("ND", "North Dakota (ND)"),
|
||||||
|
("MP", "Northern Mariana Islands (MP)"),
|
||||||
|
("OH", "Ohio (OH)"),
|
||||||
|
("OK", "Oklahoma (OK)"),
|
||||||
|
("OR", "Oregon (OR)"),
|
||||||
|
("PA", "Pennsylvania (PA)"),
|
||||||
|
("PR", "Puerto Rico (PR)"),
|
||||||
|
("RI", "Rhode Island (RI)"),
|
||||||
|
("SC", "South Carolina (SC)"),
|
||||||
|
("SD", "South Dakota (SD)"),
|
||||||
|
("TN", "Tennessee (TN)"),
|
||||||
|
("TX", "Texas (TX)"),
|
||||||
|
("UM", "United States Minor Outlying Islands (UM)"),
|
||||||
|
("UT", "Utah (UT)"),
|
||||||
|
("VT", "Vermont (VT)"),
|
||||||
|
("VI", "Virgin Islands (VI)"),
|
||||||
|
("VA", "Virginia (VA)"),
|
||||||
|
("WA", "Washington (WA)"),
|
||||||
|
("WV", "West Virginia (WV)"),
|
||||||
|
("WI", "Wisconsin (WI)"),
|
||||||
|
("WY", "Wyoming (WY)"),
|
||||||
|
("AA", "Armed Forces Americas (AA)"),
|
||||||
|
("AE", "Armed Forces Africa, Canada, Europe, Middle East (AE)"),
|
||||||
|
("AP", "Armed Forces Pacific (AP)"),
|
||||||
|
],
|
||||||
|
max_length=2,
|
||||||
|
null=True,
|
||||||
|
verbose_name="state, territory, or military post",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="domainrequest",
|
||||||
|
name="state_territory",
|
||||||
|
field=models.CharField(
|
||||||
|
blank=True,
|
||||||
|
choices=[
|
||||||
|
("AL", "Alabama (AL)"),
|
||||||
|
("AK", "Alaska (AK)"),
|
||||||
|
("AS", "American Samoa (AS)"),
|
||||||
|
("AZ", "Arizona (AZ)"),
|
||||||
|
("AR", "Arkansas (AR)"),
|
||||||
|
("CA", "California (CA)"),
|
||||||
|
("CO", "Colorado (CO)"),
|
||||||
|
("CT", "Connecticut (CT)"),
|
||||||
|
("DE", "Delaware (DE)"),
|
||||||
|
("DC", "District of Columbia (DC)"),
|
||||||
|
("FL", "Florida (FL)"),
|
||||||
|
("GA", "Georgia (GA)"),
|
||||||
|
("GU", "Guam (GU)"),
|
||||||
|
("HI", "Hawaii (HI)"),
|
||||||
|
("ID", "Idaho (ID)"),
|
||||||
|
("IL", "Illinois (IL)"),
|
||||||
|
("IN", "Indiana (IN)"),
|
||||||
|
("IA", "Iowa (IA)"),
|
||||||
|
("KS", "Kansas (KS)"),
|
||||||
|
("KY", "Kentucky (KY)"),
|
||||||
|
("LA", "Louisiana (LA)"),
|
||||||
|
("ME", "Maine (ME)"),
|
||||||
|
("MD", "Maryland (MD)"),
|
||||||
|
("MA", "Massachusetts (MA)"),
|
||||||
|
("MI", "Michigan (MI)"),
|
||||||
|
("MN", "Minnesota (MN)"),
|
||||||
|
("MS", "Mississippi (MS)"),
|
||||||
|
("MO", "Missouri (MO)"),
|
||||||
|
("MT", "Montana (MT)"),
|
||||||
|
("NE", "Nebraska (NE)"),
|
||||||
|
("NV", "Nevada (NV)"),
|
||||||
|
("NH", "New Hampshire (NH)"),
|
||||||
|
("NJ", "New Jersey (NJ)"),
|
||||||
|
("NM", "New Mexico (NM)"),
|
||||||
|
("NY", "New York (NY)"),
|
||||||
|
("NC", "North Carolina (NC)"),
|
||||||
|
("ND", "North Dakota (ND)"),
|
||||||
|
("MP", "Northern Mariana Islands (MP)"),
|
||||||
|
("OH", "Ohio (OH)"),
|
||||||
|
("OK", "Oklahoma (OK)"),
|
||||||
|
("OR", "Oregon (OR)"),
|
||||||
|
("PA", "Pennsylvania (PA)"),
|
||||||
|
("PR", "Puerto Rico (PR)"),
|
||||||
|
("RI", "Rhode Island (RI)"),
|
||||||
|
("SC", "South Carolina (SC)"),
|
||||||
|
("SD", "South Dakota (SD)"),
|
||||||
|
("TN", "Tennessee (TN)"),
|
||||||
|
("TX", "Texas (TX)"),
|
||||||
|
("UM", "United States Minor Outlying Islands (UM)"),
|
||||||
|
("UT", "Utah (UT)"),
|
||||||
|
("VT", "Vermont (VT)"),
|
||||||
|
("VI", "Virgin Islands (VI)"),
|
||||||
|
("VA", "Virginia (VA)"),
|
||||||
|
("WA", "Washington (WA)"),
|
||||||
|
("WV", "West Virginia (WV)"),
|
||||||
|
("WI", "Wisconsin (WI)"),
|
||||||
|
("WY", "Wyoming (WY)"),
|
||||||
|
("AA", "Armed Forces Americas (AA)"),
|
||||||
|
("AE", "Armed Forces Africa, Canada, Europe, Middle East (AE)"),
|
||||||
|
("AP", "Armed Forces Pacific (AP)"),
|
||||||
|
],
|
||||||
|
max_length=2,
|
||||||
|
null=True,
|
||||||
|
verbose_name="state, territory, or military post",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="portfolio",
|
||||||
|
name="state_territory",
|
||||||
|
field=models.CharField(
|
||||||
|
blank=True,
|
||||||
|
choices=[
|
||||||
|
("AL", "Alabama (AL)"),
|
||||||
|
("AK", "Alaska (AK)"),
|
||||||
|
("AS", "American Samoa (AS)"),
|
||||||
|
("AZ", "Arizona (AZ)"),
|
||||||
|
("AR", "Arkansas (AR)"),
|
||||||
|
("CA", "California (CA)"),
|
||||||
|
("CO", "Colorado (CO)"),
|
||||||
|
("CT", "Connecticut (CT)"),
|
||||||
|
("DE", "Delaware (DE)"),
|
||||||
|
("DC", "District of Columbia (DC)"),
|
||||||
|
("FL", "Florida (FL)"),
|
||||||
|
("GA", "Georgia (GA)"),
|
||||||
|
("GU", "Guam (GU)"),
|
||||||
|
("HI", "Hawaii (HI)"),
|
||||||
|
("ID", "Idaho (ID)"),
|
||||||
|
("IL", "Illinois (IL)"),
|
||||||
|
("IN", "Indiana (IN)"),
|
||||||
|
("IA", "Iowa (IA)"),
|
||||||
|
("KS", "Kansas (KS)"),
|
||||||
|
("KY", "Kentucky (KY)"),
|
||||||
|
("LA", "Louisiana (LA)"),
|
||||||
|
("ME", "Maine (ME)"),
|
||||||
|
("MD", "Maryland (MD)"),
|
||||||
|
("MA", "Massachusetts (MA)"),
|
||||||
|
("MI", "Michigan (MI)"),
|
||||||
|
("MN", "Minnesota (MN)"),
|
||||||
|
("MS", "Mississippi (MS)"),
|
||||||
|
("MO", "Missouri (MO)"),
|
||||||
|
("MT", "Montana (MT)"),
|
||||||
|
("NE", "Nebraska (NE)"),
|
||||||
|
("NV", "Nevada (NV)"),
|
||||||
|
("NH", "New Hampshire (NH)"),
|
||||||
|
("NJ", "New Jersey (NJ)"),
|
||||||
|
("NM", "New Mexico (NM)"),
|
||||||
|
("NY", "New York (NY)"),
|
||||||
|
("NC", "North Carolina (NC)"),
|
||||||
|
("ND", "North Dakota (ND)"),
|
||||||
|
("MP", "Northern Mariana Islands (MP)"),
|
||||||
|
("OH", "Ohio (OH)"),
|
||||||
|
("OK", "Oklahoma (OK)"),
|
||||||
|
("OR", "Oregon (OR)"),
|
||||||
|
("PA", "Pennsylvania (PA)"),
|
||||||
|
("PR", "Puerto Rico (PR)"),
|
||||||
|
("RI", "Rhode Island (RI)"),
|
||||||
|
("SC", "South Carolina (SC)"),
|
||||||
|
("SD", "South Dakota (SD)"),
|
||||||
|
("TN", "Tennessee (TN)"),
|
||||||
|
("TX", "Texas (TX)"),
|
||||||
|
("UM", "United States Minor Outlying Islands (UM)"),
|
||||||
|
("UT", "Utah (UT)"),
|
||||||
|
("VT", "Vermont (VT)"),
|
||||||
|
("VI", "Virgin Islands (VI)"),
|
||||||
|
("VA", "Virginia (VA)"),
|
||||||
|
("WA", "Washington (WA)"),
|
||||||
|
("WV", "West Virginia (WV)"),
|
||||||
|
("WI", "Wisconsin (WI)"),
|
||||||
|
("WY", "Wyoming (WY)"),
|
||||||
|
("AA", "Armed Forces Americas (AA)"),
|
||||||
|
("AE", "Armed Forces Africa, Canada, Europe, Middle East (AE)"),
|
||||||
|
("AP", "Armed Forces Pacific (AP)"),
|
||||||
|
],
|
||||||
|
max_length=2,
|
||||||
|
null=True,
|
||||||
|
verbose_name="state, territory, or military post",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
|
@ -159,7 +159,7 @@ class DomainInformation(TimeStampedModel):
|
||||||
choices=StateTerritoryChoices.choices,
|
choices=StateTerritoryChoices.choices,
|
||||||
null=True,
|
null=True,
|
||||||
blank=True,
|
blank=True,
|
||||||
verbose_name="state / territory",
|
verbose_name="state, territory, or military post",
|
||||||
)
|
)
|
||||||
zipcode = models.CharField(
|
zipcode = models.CharField(
|
||||||
max_length=10,
|
max_length=10,
|
||||||
|
|
|
@ -11,6 +11,7 @@ from registrar.models.federal_agency import FederalAgency
|
||||||
from registrar.models.utility.generic_helper import CreateOrUpdateOrganizationTypeHelper
|
from registrar.models.utility.generic_helper import CreateOrUpdateOrganizationTypeHelper
|
||||||
from registrar.utility.errors import FSMDomainRequestError, FSMErrorCodes
|
from registrar.utility.errors import FSMDomainRequestError, FSMErrorCodes
|
||||||
from registrar.utility.constants import BranchChoices
|
from registrar.utility.constants import BranchChoices
|
||||||
|
from auditlog.models import LogEntry
|
||||||
|
|
||||||
from .utility.time_stamped_model import TimeStampedModel
|
from .utility.time_stamped_model import TimeStampedModel
|
||||||
from ..utility.email import send_templated_email, EmailSendingError
|
from ..utility.email import send_templated_email, EmailSendingError
|
||||||
|
@ -422,7 +423,7 @@ class DomainRequest(TimeStampedModel):
|
||||||
choices=StateTerritoryChoices.choices,
|
choices=StateTerritoryChoices.choices,
|
||||||
null=True,
|
null=True,
|
||||||
blank=True,
|
blank=True,
|
||||||
verbose_name="state / territory",
|
verbose_name="state, territory, or military post",
|
||||||
)
|
)
|
||||||
zipcode = models.CharField(
|
zipcode = models.CharField(
|
||||||
max_length=10,
|
max_length=10,
|
||||||
|
@ -576,11 +577,29 @@ class DomainRequest(TimeStampedModel):
|
||||||
verbose_name="last updated on",
|
verbose_name="last updated on",
|
||||||
help_text="Date of the last status update",
|
help_text="Date of the last status update",
|
||||||
)
|
)
|
||||||
|
|
||||||
notes = models.TextField(
|
notes = models.TextField(
|
||||||
null=True,
|
null=True,
|
||||||
blank=True,
|
blank=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def is_awaiting_review(self) -> bool:
|
||||||
|
"""Checks if the current status is in submitted or in_review"""
|
||||||
|
return self.status in [self.DomainRequestStatus.SUBMITTED, self.DomainRequestStatus.IN_REVIEW]
|
||||||
|
|
||||||
|
def get_first_status_set_date(self, status):
|
||||||
|
"""Returns the date when the domain request was first set to the given status."""
|
||||||
|
log_entry = (
|
||||||
|
LogEntry.objects.filter(content_type__model="domainrequest", object_pk=self.pk, changes__status__1=status)
|
||||||
|
.order_by("-timestamp")
|
||||||
|
.first()
|
||||||
|
)
|
||||||
|
return log_entry.timestamp.date() if log_entry else None
|
||||||
|
|
||||||
|
def get_first_status_started_date(self):
|
||||||
|
"""Returns the date when the domain request was put into the status "started" for the first time"""
|
||||||
|
return self.get_first_status_set_date(DomainRequest.DomainRequestStatus.STARTED)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_statuses_that_send_emails(cls):
|
def get_statuses_that_send_emails(cls):
|
||||||
"""Returns a list of statuses that send an email to the user"""
|
"""Returns a list of statuses that send an email to the user"""
|
||||||
|
@ -986,6 +1005,17 @@ class DomainRequest(TimeStampedModel):
|
||||||
send_email=send_email,
|
send_email=send_email,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def is_withdrawable(self):
|
||||||
|
"""Helper function that determines if the request can be withdrawn in its current status"""
|
||||||
|
# This list is equivalent to the source field on withdraw. We need a better way to
|
||||||
|
# consolidate these two lists - i.e. some sort of method that keeps these two lists in sync.
|
||||||
|
# django fsm is very picky with what we can define in that field.
|
||||||
|
return self.status in [
|
||||||
|
self.DomainRequestStatus.SUBMITTED,
|
||||||
|
self.DomainRequestStatus.IN_REVIEW,
|
||||||
|
self.DomainRequestStatus.ACTION_NEEDED,
|
||||||
|
]
|
||||||
|
|
||||||
@transition(
|
@transition(
|
||||||
field="status",
|
field="status",
|
||||||
source=[DomainRequestStatus.SUBMITTED, DomainRequestStatus.IN_REVIEW, DomainRequestStatus.ACTION_NEEDED],
|
source=[DomainRequestStatus.SUBMITTED, DomainRequestStatus.IN_REVIEW, DomainRequestStatus.ACTION_NEEDED],
|
||||||
|
@ -1138,6 +1168,11 @@ class DomainRequest(TimeStampedModel):
|
||||||
data[field.name] = field.value_from_object(self)
|
data[field.name] = field.value_from_object(self)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
def get_formatted_cisa_rep_name(self):
|
||||||
|
"""Returns the cisa representatives name in Western order."""
|
||||||
|
names = [n for n in [self.cisa_representative_first_name, self.cisa_representative_last_name] if n]
|
||||||
|
return " ".join(names) if names else "Unknown"
|
||||||
|
|
||||||
def _is_federal_complete(self):
|
def _is_federal_complete(self):
|
||||||
# Federal -> "Federal government branch" page can't be empty + Federal Agency selection can't be None
|
# Federal -> "Federal government branch" page can't be empty + Federal Agency selection can't be None
|
||||||
return not (self.federal_type is None or self.federal_agency is None)
|
return not (self.federal_type is None or self.federal_agency is None)
|
||||||
|
|
|
@ -97,7 +97,7 @@ class Portfolio(TimeStampedModel):
|
||||||
choices=StateTerritoryChoices.choices,
|
choices=StateTerritoryChoices.choices,
|
||||||
null=True,
|
null=True,
|
||||||
blank=True,
|
blank=True,
|
||||||
verbose_name="state / territory",
|
verbose_name="state, territory, or military post",
|
||||||
)
|
)
|
||||||
|
|
||||||
zipcode = models.CharField(
|
zipcode = models.CharField(
|
||||||
|
|
|
@ -3,7 +3,6 @@ import logging
|
||||||
from django.contrib.auth.models import AbstractUser
|
from django.contrib.auth.models import AbstractUser
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from django.http import HttpRequest
|
|
||||||
|
|
||||||
from registrar.models import DomainInformation, UserDomainRole
|
from registrar.models import DomainInformation, UserDomainRole
|
||||||
from registrar.models.utility.portfolio_helper import UserPortfolioPermissionChoices
|
from registrar.models.utility.portfolio_helper import UserPortfolioPermissionChoices
|
||||||
|
@ -14,6 +13,7 @@ from .transition_domain import TransitionDomain
|
||||||
from .verified_by_staff import VerifiedByStaff
|
from .verified_by_staff import VerifiedByStaff
|
||||||
from .domain import Domain
|
from .domain import Domain
|
||||||
from .domain_request import DomainRequest
|
from .domain_request import DomainRequest
|
||||||
|
from registrar.utility.waffle import flag_is_active_for_user
|
||||||
from waffle.decorators import flag_is_active
|
from waffle.decorators import flag_is_active
|
||||||
|
|
||||||
from phonenumber_field.modelfields import PhoneNumberField # type: ignore
|
from phonenumber_field.modelfields import PhoneNumberField # type: ignore
|
||||||
|
@ -204,14 +204,10 @@ class User(AbstractUser):
|
||||||
) or self._has_portfolio_permission(portfolio, UserPortfolioPermissionChoices.VIEW_MANAGED_DOMAINS)
|
) or self._has_portfolio_permission(portfolio, UserPortfolioPermissionChoices.VIEW_MANAGED_DOMAINS)
|
||||||
|
|
||||||
def has_organization_requests_flag(self):
|
def has_organization_requests_flag(self):
|
||||||
request = HttpRequest()
|
return flag_is_active_for_user(self, "organization_requests")
|
||||||
request.user = self
|
|
||||||
return flag_is_active(request, "organization_requests")
|
|
||||||
|
|
||||||
def has_organization_members_flag(self):
|
def has_organization_members_flag(self):
|
||||||
request = HttpRequest()
|
return flag_is_active_for_user(self, "organization_members")
|
||||||
request.user = self
|
|
||||||
return flag_is_active(request, "organization_members")
|
|
||||||
|
|
||||||
def has_view_members_portfolio_permission(self, portfolio):
|
def has_view_members_portfolio_permission(self, portfolio):
|
||||||
# BEGIN
|
# BEGIN
|
||||||
|
@ -422,12 +418,8 @@ class User(AbstractUser):
|
||||||
for invitation in PortfolioInvitation.objects.filter(
|
for invitation in PortfolioInvitation.objects.filter(
|
||||||
email__iexact=self.email, status=PortfolioInvitation.PortfolioInvitationStatus.INVITED
|
email__iexact=self.email, status=PortfolioInvitation.PortfolioInvitationStatus.INVITED
|
||||||
):
|
):
|
||||||
# need to create a bogus request and assign user to it, in order to pass request
|
|
||||||
# to flag_is_active
|
|
||||||
request = HttpRequest()
|
|
||||||
request.user = self
|
|
||||||
only_single_portfolio = (
|
only_single_portfolio = (
|
||||||
not flag_is_active(request, "multiple_portfolios") and self.get_first_portfolio() is None
|
not flag_is_active_for_user(self, "multiple_portfolios") and self.get_first_portfolio() is None
|
||||||
)
|
)
|
||||||
if only_single_portfolio or flag_is_active(None, "multiple_portfolios"):
|
if only_single_portfolio or flag_is_active(None, "multiple_portfolios"):
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.forms import ValidationError
|
from django.forms import ValidationError
|
||||||
from django.http import HttpRequest
|
from registrar.utility.waffle import flag_is_active_for_user
|
||||||
from waffle import flag_is_active
|
|
||||||
from registrar.models.utility.portfolio_helper import UserPortfolioPermissionChoices, UserPortfolioRoleChoices
|
from registrar.models.utility.portfolio_helper import UserPortfolioPermissionChoices, UserPortfolioRoleChoices
|
||||||
from .utility.time_stamped_model import TimeStampedModel
|
from .utility.time_stamped_model import TimeStampedModel
|
||||||
from django.contrib.postgres.fields import ArrayField
|
from django.contrib.postgres.fields import ArrayField
|
||||||
|
@ -101,11 +100,8 @@ class UserPortfolioPermission(TimeStampedModel):
|
||||||
# Check if a user is set without accessing the related object.
|
# Check if a user is set without accessing the related object.
|
||||||
has_user = bool(self.user_id)
|
has_user = bool(self.user_id)
|
||||||
if self.pk is None and has_user:
|
if self.pk is None and has_user:
|
||||||
# Have to create a bogus request to set the user and pass to flag_is_active
|
|
||||||
request = HttpRequest()
|
|
||||||
request.user = self.user
|
|
||||||
existing_permissions = UserPortfolioPermission.objects.filter(user=self.user)
|
existing_permissions = UserPortfolioPermission.objects.filter(user=self.user)
|
||||||
if not flag_is_active(request, "multiple_portfolios") and existing_permissions.exists():
|
if not flag_is_active_for_user(self.user, "multiple_portfolios") and existing_permissions.exists():
|
||||||
raise ValidationError(
|
raise ValidationError(
|
||||||
"Only one portfolio permission is allowed per user when multiple portfolios are disabled."
|
"Only one portfolio permission is allowed per user when multiple portfolios are disabled."
|
||||||
)
|
)
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
import time
|
import time
|
||||||
import logging
|
import logging
|
||||||
from urllib.parse import urlparse, urlunparse, urlencode
|
from urllib.parse import urlparse, urlunparse, urlencode
|
||||||
|
from django.urls import resolve, Resolver404
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -315,3 +316,21 @@ def convert_queryset_to_dict(queryset, is_model=True, key="id"):
|
||||||
request_dict = {value[key]: value for value in queryset}
|
request_dict = {value[key]: value for value in queryset}
|
||||||
|
|
||||||
return request_dict
|
return request_dict
|
||||||
|
|
||||||
|
|
||||||
|
def get_url_name(path):
|
||||||
|
"""
|
||||||
|
Given a URL path, returns the corresponding URL name defined in urls.py.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
path (str): The URL path to resolve.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str or None: The URL name if it exists, otherwise None.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
match = resolve(path)
|
||||||
|
return match.url_name
|
||||||
|
except Resolver404:
|
||||||
|
logger.error(f"No matching URL name found for path: {path}")
|
||||||
|
return None
|
||||||
|
|
|
@ -9,7 +9,7 @@ class WaffleFlag(AbstractUserFlag):
|
||||||
Custom implementation of django-waffles 'Flag' object.
|
Custom implementation of django-waffles 'Flag' object.
|
||||||
Read more here: https://waffle.readthedocs.io/en/stable/types/flag.html
|
Read more here: https://waffle.readthedocs.io/en/stable/types/flag.html
|
||||||
|
|
||||||
Use this class when dealing with feature flags, such as profile_feature.
|
Use this class when dealing with feature flags.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
|
@ -72,12 +72,6 @@ class CheckUserProfileMiddleware:
|
||||||
"""Runs pre-processing logic for each view. Checks for the
|
"""Runs pre-processing logic for each view. Checks for the
|
||||||
finished_setup flag on the current user. If they haven't done so,
|
finished_setup flag on the current user. If they haven't done so,
|
||||||
then we redirect them to the finish setup page."""
|
then we redirect them to the finish setup page."""
|
||||||
# Check that the user is "opted-in" to the profile feature flag
|
|
||||||
has_profile_feature_flag = flag_is_active(request, "profile_feature")
|
|
||||||
|
|
||||||
# If they aren't, skip this check entirely
|
|
||||||
if not has_profile_feature_flag:
|
|
||||||
return None
|
|
||||||
|
|
||||||
if request.user.is_authenticated:
|
if request.user.is_authenticated:
|
||||||
profile_page = self.profile_page
|
profile_page = self.profile_page
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
{% block title %}{% translate "Unauthorized | " %}{% endblock %}
|
{% block title %}{% translate "Unauthorized | " %}{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<main id="main-content" class="grid-container">
|
<main id="main-content" class="grid-container {% if is_widescreen_mode %} grid-container--widescreen {% endif %}">
|
||||||
<div class="grid-row grow-gap">
|
<div class="grid-row grow-gap">
|
||||||
<div class="tablet:grid-col-6 usa-prose margin-bottom-3">
|
<div class="tablet:grid-col-6 usa-prose margin-bottom-3">
|
||||||
<h1>
|
<h1>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
{% block title %}{% translate "Forbidden | " %}{% endblock %}
|
{% block title %}{% translate "Forbidden | " %}{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<main id="main-content" class="grid-container">
|
<main id="main-content" class="grid-container {% if is_widescreen_mode %} grid-container--widescreen {% endif %}">
|
||||||
<div class="grid-row grow-gap">
|
<div class="grid-row grow-gap">
|
||||||
<div class="tablet:grid-col-6 usa-prose margin-bottom-3">
|
<div class="tablet:grid-col-6 usa-prose margin-bottom-3">
|
||||||
<h1>
|
<h1>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
{% block title %}{% translate "Page not found | " %}{% endblock %}
|
{% block title %}{% translate "Page not found | " %}{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<main id="main-content" class="grid-container">
|
<main id="main-content" class="grid-container {% if is_widescreen_mode %} grid-container--widescreen {% endif %}">
|
||||||
<div class="grid-row grid-gap">
|
<div class="grid-row grid-gap">
|
||||||
<div class="tablet:grid-col-6 usa-prose margin-bottom-3">
|
<div class="tablet:grid-col-6 usa-prose margin-bottom-3">
|
||||||
<h1>
|
<h1>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
{% block title %}{% translate "Server error | " %}{% endblock %}
|
{% block title %}{% translate "Server error | " %}{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<main id="main-content" class="grid-container">
|
<main id="main-content" class="grid-container {% if is_widescreen_mode %} grid-container--widescreen {% endif %}">
|
||||||
<div class="grid-row grid-gap">
|
<div class="grid-row grid-gap">
|
||||||
<div class="tablet:grid-col-6 usa-prose margin-bottom-3">
|
<div class="tablet:grid-col-6 usa-prose margin-bottom-3">
|
||||||
<h1>
|
<h1>
|
||||||
|
|
|
@ -78,7 +78,7 @@
|
||||||
<section class="usa-banner" aria-label="Official website of the United States government">
|
<section class="usa-banner" aria-label="Official website of the United States government">
|
||||||
<div class="usa-accordion">
|
<div class="usa-accordion">
|
||||||
<header class="usa-banner__header">
|
<header class="usa-banner__header">
|
||||||
<div class="usa-banner__inner">
|
<div class="usa-banner__inner {% if is_widescreen_mode %} usa-banner__inner--widescreen {% endif %}">
|
||||||
<div class="grid-col-auto">
|
<div class="grid-col-auto">
|
||||||
<img class="usa-banner__header-flag" src="{% static 'img/us_flag_small.png' %}" alt="U.S. flag" />
|
<img class="usa-banner__header-flag" src="{% static 'img/us_flag_small.png' %}" alt="U.S. flag" />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -77,19 +77,12 @@
|
||||||
{% include "includes/summary_item.html" with title='Suborganization' value=domain.domain_info.sub_organization edit_link=url editable=is_editable|and:has_edit_suborganization_portfolio_permission %}
|
{% include "includes/summary_item.html" with title='Suborganization' value=domain.domain_info.sub_organization edit_link=url editable=is_editable|and:has_edit_suborganization_portfolio_permission %}
|
||||||
{% else %}
|
{% else %}
|
||||||
{% url 'domain-org-name-address' pk=domain.id as url %}
|
{% url 'domain-org-name-address' pk=domain.id as url %}
|
||||||
{% include "includes/summary_item.html" with title='Organization name and mailing address' value=domain.domain_info address='true' edit_link=url editable=is_editable %}
|
{% include "includes/summary_item.html" with title='Organization' value=domain.domain_info address='true' edit_link=url editable=is_editable %}
|
||||||
|
|
||||||
{% url 'domain-senior-official' pk=domain.id as url %}
|
{% url 'domain-senior-official' pk=domain.id as url %}
|
||||||
{% include "includes/summary_item.html" with title='Senior official' value=domain.domain_info.senior_official contact='true' edit_link=url editable=is_editable %}
|
{% include "includes/summary_item.html" with title='Senior official' value=domain.domain_info.senior_official contact='true' edit_link=url editable=is_editable %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
{# Conditionally display profile #}
|
|
||||||
{% if not has_profile_feature_flag %}
|
|
||||||
{% url 'domain-your-contact-information' pk=domain.id as url %}
|
|
||||||
{% include "includes/summary_item.html" with title='Your contact information' value=request.user contact='true' edit_link=url editable=is_editable %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% url 'domain-security-email' pk=domain.id as url %}
|
{% url 'domain-security-email' pk=domain.id as url %}
|
||||||
{% if security_email is not None and security_email not in hidden_security_emails%}
|
{% if security_email is not None and security_email not in hidden_security_emails%}
|
||||||
{% include "includes/summary_item.html" with title='Security email' value=security_email edit_link=url editable=is_editable %}
|
{% include "includes/summary_item.html" with title='Security email' value=security_email edit_link=url editable=is_editable %}
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
{# this is right after the messages block in the parent template #}
|
{# this is right after the messages block in the parent template #}
|
||||||
{% include "includes/form_errors.html" with form=form %}
|
{% include "includes/form_errors.html" with form=form %}
|
||||||
|
|
||||||
<h1>Organization name and mailing address </h1>
|
<h1>Organization</h1>
|
||||||
|
|
||||||
<p>The name of your organization will be publicly listed as the domain registrant.</p>
|
<p>The name of your organization will be publicly listed as the domain registrant.</p>
|
||||||
|
|
||||||
|
|
|
@ -16,11 +16,9 @@
|
||||||
<h2>Time to complete the form</h2>
|
<h2>Time to complete the form</h2>
|
||||||
<p>If you have <a href="{% public_site_url 'domains/before/#information-you%E2%80%99ll-need-to-complete-the-domain-request-form' %}" target="_blank" class="usa-link">all the information you need</a>,
|
<p>If you have <a href="{% public_site_url 'domains/before/#information-you%E2%80%99ll-need-to-complete-the-domain-request-form' %}" target="_blank" class="usa-link">all the information you need</a>,
|
||||||
completing your domain request might take around 15 minutes.</p>
|
completing your domain request might take around 15 minutes.</p>
|
||||||
{% if has_profile_feature_flag %}
|
|
||||||
<h2>How we’ll reach you</h2>
|
<h2>How we’ll reach you</h2>
|
||||||
<p>While reviewing your domain request, we may need to reach out with questions. We’ll also email you when we complete our review. If the contact information below is not correct, visit <a href="{% url 'user-profile' %}?redirect=domain-request:" class="usa-link">your profile</a> to make updates.</p>
|
<p>While reviewing your domain request, we may need to reach out with questions. We’ll also email you when we complete our review. If the contact information below is not correct, visit <a href="{% url 'user-profile' %}?redirect=domain-request:" class="usa-link">your profile</a> to make updates.</p>
|
||||||
{% include "includes/profile_information.html" with user=user%}
|
{% include "includes/profile_information.html" with user=user%}
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
|
|
||||||
{% block form_buttons %}
|
{% block form_buttons %}
|
||||||
|
|
|
@ -19,183 +19,5 @@
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block form_fields %}
|
{% block form_fields %}
|
||||||
{% for step in steps.all|slice:":-1" %}
|
{% include "includes/request_review_steps.html" with is_editable=True %}
|
||||||
<section class="summary-item margin-top-3">
|
|
||||||
|
|
||||||
{% if step == Step.ORGANIZATION_TYPE %}
|
|
||||||
{% namespaced_url 'domain-request' step as domain_request_url %}
|
|
||||||
{% if domain_request.generic_org_type is not None %}
|
|
||||||
{% with title=form_titles|get_item:step value=domain_request.get_generic_org_type_display|default:"<span class='text-bold text-secondary-dark'>Incomplete</span>"|safe %}
|
|
||||||
{% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=domain_request_url %}
|
|
||||||
{% endwith %}
|
|
||||||
{% else %}
|
|
||||||
{% with title=form_titles|get_item:step value="<span class='text-bold text-secondary-dark'>Incomplete</span>"|safe %}
|
|
||||||
{% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=domain_request_url %}
|
|
||||||
{% endwith %}
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if step == Step.TRIBAL_GOVERNMENT %}
|
|
||||||
{% namespaced_url 'domain-request' step as domain_request_url %}
|
|
||||||
{% with title=form_titles|get_item:step value=domain_request.tribe_name|default:"<span class='text-bold text-secondary-dark'>Incomplete</span>"|safe %}
|
|
||||||
{% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=domain_request_url %}
|
|
||||||
{% endwith %}
|
|
||||||
{% if domain_request.federally_recognized_tribe %}<p>Federally-recognized tribe</p>{% endif %}
|
|
||||||
{% if domain_request.state_recognized_tribe %}<p>State-recognized tribe</p>{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
|
|
||||||
{% if step == Step.ORGANIZATION_FEDERAL %}
|
|
||||||
{% namespaced_url 'domain-request' step as domain_request_url %}
|
|
||||||
{% with title=form_titles|get_item:step value=domain_request.get_federal_type_display|default:"<span class='text-bold text-secondary-dark'>Incomplete</span>"|safe %}
|
|
||||||
{% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=domain_request_url %}
|
|
||||||
{% endwith %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if step == Step.ORGANIZATION_ELECTION %}
|
|
||||||
{% namespaced_url 'domain-request' step as domain_request_url %}
|
|
||||||
{% with title=form_titles|get_item:step value=domain_request.is_election_board|yesno:"Yes,No,Incomplete" %}
|
|
||||||
{% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=domain_request_url %}
|
|
||||||
{% endwith %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if step == Step.ORGANIZATION_CONTACT %}
|
|
||||||
{% namespaced_url 'domain-request' step as domain_request_url %}
|
|
||||||
{% if domain_request.organization_name %}
|
|
||||||
{% with title=form_titles|get_item:step value=domain_request %}
|
|
||||||
{% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=domain_request_url address='true' %}
|
|
||||||
{% endwith %}
|
|
||||||
{% else %}
|
|
||||||
{% with title=form_titles|get_item:step value="<span class='text-bold text-secondary-dark'>Incomplete</span>"|safe %}
|
|
||||||
{% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=domain_request_url %}
|
|
||||||
{% endwith %}
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if step == Step.ABOUT_YOUR_ORGANIZATION %}
|
|
||||||
{% namespaced_url 'domain-request' step as domain_request_url %}
|
|
||||||
{% with title=form_titles|get_item:step value=domain_request.about_your_organization|default:"<span class='text-bold text-secondary-dark'>Incomplete</span>"|safe %}
|
|
||||||
{% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=domain_request_url %}
|
|
||||||
{% endwith %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if step == Step.SENIOR_OFFICIAL %}
|
|
||||||
{% namespaced_url 'domain-request' step as domain_request_url %}
|
|
||||||
{% if domain_request.senior_official is not None %}
|
|
||||||
{% with title=form_titles|get_item:step value=domain_request.senior_official %}
|
|
||||||
{% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=domain_request_url contact='true' %}
|
|
||||||
{% endwith %}
|
|
||||||
{% else %}
|
|
||||||
{% with title=form_titles|get_item:step value="<span class='text-bold text-secondary-dark'>Incomplete</span>"|safe %}
|
|
||||||
{% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=domain_request_url %}
|
|
||||||
{% endwith %}
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if step == Step.CURRENT_SITES %}
|
|
||||||
{% namespaced_url 'domain-request' step as domain_request_url %}
|
|
||||||
{% if domain_request.current_websites.all %}
|
|
||||||
{% with title=form_titles|get_item:step value=domain_request.current_websites.all %}
|
|
||||||
{% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=domain_request_url list='true' %}
|
|
||||||
{% endwith %}
|
|
||||||
{% else %}
|
|
||||||
{% with title=form_titles|get_item:step value='None' %}
|
|
||||||
{% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=domain_request_url %}
|
|
||||||
{% endwith %}
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if step == Step.DOTGOV_DOMAIN %}
|
|
||||||
{% namespaced_url 'domain-request' step as domain_request_url %}
|
|
||||||
{% with title=form_titles|get_item:step value=domain_request.requested_domain.name|default:"<span class='text-bold text-secondary-dark'>Incomplete</span>"|safe%}
|
|
||||||
{% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=domain_request_url %}
|
|
||||||
{% endwith %}
|
|
||||||
|
|
||||||
{% if domain_request.alternative_domains.all %}
|
|
||||||
<h3 class="register-form-review-header">Alternative domains</h3>
|
|
||||||
<ul class="usa-list usa-list--unstyled margin-top-0">
|
|
||||||
{% for site in domain_request.alternative_domains.all %}
|
|
||||||
<li>{{ site.website }}</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if step == Step.PURPOSE %}
|
|
||||||
{% namespaced_url 'domain-request' step as domain_request_url %}
|
|
||||||
{% with title=form_titles|get_item:step value=domain_request.purpose|default:"<span class='text-bold text-secondary-dark'>Incomplete</span>"|safe %}
|
|
||||||
{% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=domain_request_url %}
|
|
||||||
{% endwith %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if step == Step.YOUR_CONTACT %}
|
|
||||||
{% namespaced_url 'domain-request' step as domain_request_url %}
|
|
||||||
{% if domain_request.creator is not None %}
|
|
||||||
{% with title=form_titles|get_item:step value=domain_request.creator %}
|
|
||||||
{% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=domain_request_url contact='true' %}
|
|
||||||
{% endwith %}
|
|
||||||
{% else %}
|
|
||||||
{% with title=form_titles|get_item:step value="<span class='text-bold text-secondary-dark'>Incomplete</span>"|safe %}
|
|
||||||
{% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=domain_request_url %}
|
|
||||||
{% endwith %}
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if step == Step.OTHER_CONTACTS %}
|
|
||||||
{% namespaced_url 'domain-request' step as domain_request_url %}
|
|
||||||
{% if domain_request.other_contacts.all %}
|
|
||||||
{% with title=form_titles|get_item:step value=domain_request.other_contacts.all %}
|
|
||||||
{% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=domain_request_url contact='true' list='true' %}
|
|
||||||
{% endwith %}
|
|
||||||
{% else %}
|
|
||||||
{% with title=form_titles|get_item:step value=domain_request.no_other_contacts_rationale|default:"<span class='text-bold text-secondary-dark'>Incomplete</span>"|safe %}
|
|
||||||
{% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=domain_request_url %}
|
|
||||||
{% endwith %}
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
|
|
||||||
{% if step == Step.ADDITIONAL_DETAILS %}
|
|
||||||
{% namespaced_url 'domain-request' step as domain_request_url %}
|
|
||||||
{% with title=form_titles|get_item:step %}
|
|
||||||
{% if domain_request.has_additional_details %}
|
|
||||||
{% include "includes/summary_item.html" with title="Additional Details" value=" " heading_level=heading_level editable=True edit_link=domain_request_url %}
|
|
||||||
<h3 class="register-form-review-header">CISA Regional Representative</h3>
|
|
||||||
<ul class="usa-list usa-list--unstyled margin-top-0">
|
|
||||||
{% if domain_request.cisa_representative_first_name %}
|
|
||||||
<li>{{domain_request.cisa_representative_first_name}} {{domain_request.cisa_representative_last_name}}</li>
|
|
||||||
{% if domain_request.cisa_representative_email %}
|
|
||||||
<li>{{domain_request.cisa_representative_email}}</li>
|
|
||||||
{% endif %}
|
|
||||||
{% else %}
|
|
||||||
No
|
|
||||||
{% endif %}
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<h3 class="register-form-review-header">Anything else</h3>
|
|
||||||
<ul class="usa-list usa-list--unstyled margin-top-0">
|
|
||||||
{% if domain_request.anything_else %}
|
|
||||||
{{domain_request.anything_else}}
|
|
||||||
{% else %}
|
|
||||||
No
|
|
||||||
{% endif %}
|
|
||||||
</ul>
|
|
||||||
{% else %}
|
|
||||||
{% include "includes/summary_item.html" with title="Additional Details" value="<span class='text-bold text-secondary-dark'>Incomplete</span>"|safe heading_level=heading_level editable=True edit_link=domain_request_url %}
|
|
||||||
{% endif %}
|
|
||||||
{% endwith %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
|
|
||||||
{% if step == Step.REQUIREMENTS %}
|
|
||||||
{% namespaced_url 'domain-request' step as domain_request_url %}
|
|
||||||
{% with title=form_titles|get_item:step value=domain_request.is_policy_acknowledged|yesno:"I agree.,I do not agree.,I do not agree." %}
|
|
||||||
{% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=True edit_link=domain_request_url %}
|
|
||||||
{% endwith %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</section>
|
|
||||||
{% endfor %}
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -1,164 +1,10 @@
|
||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
{% load custom_filters %}
|
{% load custom_filters %}
|
||||||
|
|
||||||
{% block title %}Domain request status | {{ DomainRequest.requested_domain.name }} | {% endblock %}
|
|
||||||
{% load static url_helpers %}
|
{% load static url_helpers %}
|
||||||
|
|
||||||
|
{% block title %}Domain request status | {{ DomainRequest.requested_domain.name }} | {% endblock %}
|
||||||
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<main id="main-content" class="grid-container">
|
{% include "includes/request_status_manage.html" %}
|
||||||
<div class="grid-col desktop:grid-offset-2 desktop:grid-col-8">
|
|
||||||
{% comment %}
|
|
||||||
TODO: Uncomment in #2596
|
|
||||||
{% if portfolio %}
|
|
||||||
{% url 'domain-requests' as url %}
|
|
||||||
<nav class="usa-breadcrumb padding-top-0" aria-label="Domain request breadcrumb">
|
|
||||||
<ol class="usa-breadcrumb__list">
|
|
||||||
<li class="usa-breadcrumb__list-item">
|
|
||||||
<a href="{{ url }}" class="usa-breadcrumb__link"><span>Domain requests</span></a>
|
|
||||||
</li>
|
|
||||||
<li class="usa-breadcrumb__list-item usa-current" aria-current="page">
|
|
||||||
<span>{{ DomainRequest.requested_domain.name }}</span
|
|
||||||
>
|
|
||||||
</li>
|
|
||||||
</ol>
|
|
||||||
</nav>
|
|
||||||
{% else %}{% endcomment %}
|
|
||||||
{% url 'home' as url %}
|
|
||||||
<a href="{{ url }}" class="breadcrumb__back">
|
|
||||||
<svg class="usa-icon" aria-hidden="true" focusable="false" role="img">
|
|
||||||
<use xlink:href="{% static 'img/sprite.svg' %}#arrow_back"></use>
|
|
||||||
</svg>
|
|
||||||
|
|
||||||
<p class="margin-left-05 margin-top-0 margin-bottom-0 line-height-sans-1">
|
|
||||||
Back to manage your domains
|
|
||||||
</p>
|
|
||||||
</a>
|
|
||||||
{% comment %} {% endif %}{% endcomment %}
|
|
||||||
<h1>Domain request for {{ DomainRequest.requested_domain.name }}</h1>
|
|
||||||
<div
|
|
||||||
class="usa-summary-box dotgov-status-box margin-top-3 padding-left-2"
|
|
||||||
role="region"
|
|
||||||
aria-labelledby="summary-box-key-information"
|
|
||||||
>
|
|
||||||
<div class="usa-summary-box__body">
|
|
||||||
<p class="usa-summary-box__heading font-sans-md margin-bottom-0"
|
|
||||||
id="summary-box-key-information"
|
|
||||||
>
|
|
||||||
<span class="text-bold text-primary-darker">
|
|
||||||
Status:
|
|
||||||
</span>
|
|
||||||
{% if DomainRequest.status == 'approved' %} Approved
|
|
||||||
{% elif DomainRequest.status == 'in review' %} In review
|
|
||||||
{% elif DomainRequest.status == 'rejected' %} Rejected
|
|
||||||
{% elif DomainRequest.status == 'submitted' %} Submitted
|
|
||||||
{% elif DomainRequest.status == 'ineligible' %} Ineligible
|
|
||||||
{% else %}ERROR Please contact technical support/dev
|
|
||||||
{% endif %}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<br>
|
|
||||||
<p><b class="review__step__name">Last updated:</b> {{DomainRequest.updated_at|date:"F j, Y"}}</p>
|
|
||||||
|
|
||||||
{% if DomainRequest.status != 'rejected' %}
|
|
||||||
<p>{% include "includes/domain_request.html" %}</p>
|
|
||||||
<p><a href="{% url 'domain-request-withdraw-confirmation' pk=DomainRequest.id %}" class="usa-button usa-button--outline withdraw_outline">
|
|
||||||
Withdraw request</a>
|
|
||||||
</p>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="grid-col desktop:grid-offset-2 maxw-tablet">
|
|
||||||
<h2 class="text-primary-darker"> Summary of your domain request </h2>
|
|
||||||
{% with heading_level='h3' %}
|
|
||||||
{% with org_type=DomainRequest.get_generic_org_type_display %}
|
|
||||||
{% include "includes/summary_item.html" with title='Type of organization' value=org_type heading_level=heading_level %}
|
|
||||||
{% endwith %}
|
|
||||||
|
|
||||||
{% if DomainRequest.tribe_name %}
|
|
||||||
{% include "includes/summary_item.html" with title='Tribal government' value=DomainRequest.tribe_name heading_level=heading_level %}
|
|
||||||
|
|
||||||
{% if DomainRequest.federally_recognized_tribe %}
|
|
||||||
<p>Federally-recognized tribe</p>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if DomainRequest.state_recognized_tribe %}
|
|
||||||
<p>State-recognized tribe</p>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if DomainRequest.get_federal_type_display %}
|
|
||||||
{% include "includes/summary_item.html" with title='Federal government branch' value=DomainRequest.get_federal_type_display heading_level=heading_level %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if DomainRequest.is_election_board %}
|
|
||||||
{% with value=DomainRequest.is_election_board|yesno:"Yes,No,Incomplete" %}
|
|
||||||
{% include "includes/summary_item.html" with title='Election office' value=value heading_level=heading_level %}
|
|
||||||
{% endwith %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if DomainRequest.organization_name %}
|
|
||||||
{% include "includes/summary_item.html" with title='Organization name and mailing address' value=DomainRequest address='true' heading_level=heading_level %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if DomainRequest.about_your_organization %}
|
|
||||||
{% include "includes/summary_item.html" with title='About your organization' value=DomainRequest.about_your_organization heading_level=heading_level %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if DomainRequest.senior_official %}
|
|
||||||
{% include "includes/summary_item.html" with title='Senior official' value=DomainRequest.senior_official contact='true' heading_level=heading_level %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if DomainRequest.current_websites.all %}
|
|
||||||
{% include "includes/summary_item.html" with title='Current websites' value=DomainRequest.current_websites.all list='true' heading_level=heading_level %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if DomainRequest.requested_domain %}
|
|
||||||
{% include "includes/summary_item.html" with title='.gov domain' value=DomainRequest.requested_domain heading_level=heading_level %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if DomainRequest.alternative_domains.all %}
|
|
||||||
{% include "includes/summary_item.html" with title='Alternative domains' value=DomainRequest.alternative_domains.all list='true' heading_level=heading_level %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if DomainRequest.purpose %}
|
|
||||||
{% include "includes/summary_item.html" with title='Purpose of your domain' value=DomainRequest.purpose heading_level=heading_level %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if DomainRequest.creator %}
|
|
||||||
{% include "includes/summary_item.html" with title='Your contact information' value=DomainRequest.creator contact='true' heading_level=heading_level %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if DomainRequest.other_contacts.all %}
|
|
||||||
{% include "includes/summary_item.html" with title='Other employees from your organization' value=DomainRequest.other_contacts.all contact='true' list='true' heading_level=heading_level %}
|
|
||||||
{% else %}
|
|
||||||
{% include "includes/summary_item.html" with title='Other employees from your organization' value=DomainRequest.no_other_contacts_rationale heading_level=heading_level %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{# We always show this field even if None #}
|
|
||||||
{% if DomainRequest %}
|
|
||||||
<h3 class="register-form-review-header">CISA Regional Representative</h3>
|
|
||||||
<ul class="usa-list usa-list--unstyled margin-top-0">
|
|
||||||
{% if domain_request.cisa_representative_first_name %}
|
|
||||||
{{domain_request.cisa_representative_first_name}} {{domain_request.cisa_representative_last_name}}
|
|
||||||
{% else %}
|
|
||||||
No
|
|
||||||
{% endif %}
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<h3 class="register-form-review-header">Anything else</h3>
|
|
||||||
<ul class="usa-list usa-list--unstyled margin-top-0">
|
|
||||||
{% if DomainRequest.anything_else %}
|
|
||||||
{{DomainRequest.anything_else}}
|
|
||||||
{% else %}
|
|
||||||
No
|
|
||||||
{% endif %}
|
|
||||||
</ul>
|
|
||||||
{% endif %}
|
|
||||||
{% endwith %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
{% if not portfolio %}
|
{% if not portfolio %}
|
||||||
{% with url_name="domain-org-name-address" %}
|
{% with url_name="domain-org-name-address" %}
|
||||||
{% include "includes/domain_sidenav_item.html" with item_text="Organization name and mailing address" %}
|
{% include "includes/domain_sidenav_item.html" with item_text="Organization" %}
|
||||||
{% endwith %}
|
{% endwith %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ State-recognized tribe
|
||||||
Election office:
|
Election office:
|
||||||
{{ domain_request.is_election_board|yesno:"Yes,No,Incomplete" }}
|
{{ domain_request.is_election_board|yesno:"Yes,No,Incomplete" }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
Organization name and mailing address:
|
Organization:
|
||||||
{% spaceless %}{{ domain_request.federal_agency }}
|
{% spaceless %}{{ domain_request.federal_agency }}
|
||||||
{{ domain_request.organization_name }}
|
{{ domain_request.organization_name }}
|
||||||
{{ domain_request.address_line1 }}{% if domain_request.address_line2 %}
|
{{ domain_request.address_line1 }}{% if domain_request.address_line2 %}
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
{% block title %} Home | {% endblock %}
|
{% block title %} Home | {% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<main id="main-content" class="grid-container">
|
<main id="main-content" class="grid-container {% if is_widescreen_mode %} grid-container--widescreen {% endif %}">
|
||||||
{% if user.is_authenticated %}
|
{% if user.is_authenticated %}
|
||||||
{# the entire logged in page goes here #}
|
{# the entire logged in page goes here #}
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,10 @@
|
||||||
</h2>
|
</h2>
|
||||||
<p>We received your .gov domain request. Our next step is to review your request. This usually takes 30 business days. We’ll email you if we have questions and when we complete our review. <a class="usa-link" rel="noopener noreferrer" target="_blank" href="{% public_site_url 'contact' %}">Contact us with any questions</a>.</p>
|
<p>We received your .gov domain request. Our next step is to review your request. This usually takes 30 business days. We’ll email you if we have questions and when we complete our review. <a class="usa-link" rel="noopener noreferrer" target="_blank" href="{% public_site_url 'contact' %}">Contact us with any questions</a>.</p>
|
||||||
|
|
||||||
<h2 class="margin-top-0 margin-bottom-2 text-primary-darker text-semibold">
|
{% if show_withdraw_text %}
|
||||||
|
<h2 class="margin-top-0 margin-bottom-2 text-primary-darker text-semibold">
|
||||||
Need to make changes?
|
Need to make changes?
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<p>If you need to change your request you have to first withdraw it. Once you withdraw the request you can edit it and submit it again. Changing your request might add to the wait time.</p>
|
<p>If you need to change your request you have to first withdraw it. Once you withdraw the request you can edit it and submit it again. Changing your request might add to the wait time.</p>
|
||||||
|
{% endif %}
|
|
@ -0,0 +1,236 @@
|
||||||
|
{% load custom_filters %}
|
||||||
|
{% load static url_helpers %}
|
||||||
|
<main id="main-content" class="grid-container">
|
||||||
|
<div class="grid-col desktop:grid-offset-2 desktop:grid-col-8">
|
||||||
|
{% block breadcrumb %}
|
||||||
|
{% if portfolio %}
|
||||||
|
{% url 'domain-requests' as url %}
|
||||||
|
{% else %}
|
||||||
|
{% url 'home' as url %}
|
||||||
|
{% endif %}
|
||||||
|
<nav class="usa-breadcrumb padding-top-0" aria-label="Domain request breadcrumb">
|
||||||
|
<ol class="usa-breadcrumb__list">
|
||||||
|
<li class="usa-breadcrumb__list-item">
|
||||||
|
{% if portfolio %}
|
||||||
|
<a href="{{ url }}" class="usa-breadcrumb__link"><span>Domain requests</span></a>
|
||||||
|
{% else %}
|
||||||
|
<a href="{{ url }}" class="usa-breadcrumb__link"><span>Manage your domains</span></a>
|
||||||
|
{% endif %}
|
||||||
|
</li>
|
||||||
|
<li class="usa-breadcrumb__list-item usa-current" aria-current="page">
|
||||||
|
{% if not DomainRequest.requested_domain and DomainRequest.status == DomainRequest.DomainRequestStatus.STARTED %}
|
||||||
|
<span>New domain request</span>
|
||||||
|
{% else %}
|
||||||
|
<span>{{ DomainRequest.requested_domain.name }}</span>
|
||||||
|
{% endif %}
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
</nav>
|
||||||
|
{% endblock breadcrumb %}
|
||||||
|
|
||||||
|
{% block header %}
|
||||||
|
{% if not DomainRequest.requested_domain and DomainRequest.status == DomainRequest.DomainRequestStatus.STARTED %}
|
||||||
|
<h1>New domain request</h1>
|
||||||
|
{% else %}
|
||||||
|
<h1>Domain request for {{ DomainRequest.requested_domain.name }}</h1>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock header %}
|
||||||
|
|
||||||
|
{% block status_summary %}
|
||||||
|
<div
|
||||||
|
class="usa-summary-box dotgov-status-box margin-top-3 padding-left-2"
|
||||||
|
role="region"
|
||||||
|
aria-labelledby="summary-box-key-information"
|
||||||
|
>
|
||||||
|
<div class="usa-summary-box__body">
|
||||||
|
<p class="usa-summary-box__heading font-sans-md margin-bottom-0"
|
||||||
|
id="summary-box-key-information"
|
||||||
|
>
|
||||||
|
<span class="text-bold text-primary-darker">
|
||||||
|
Status:
|
||||||
|
</span>
|
||||||
|
{{ DomainRequest.get_status_display|default:"ERROR Please contact technical support/dev" }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
{% endblock status_summary %}
|
||||||
|
|
||||||
|
{% block status_metadata %}
|
||||||
|
|
||||||
|
{% if portfolio %}
|
||||||
|
{% if DomainRequest.creator %}
|
||||||
|
<p class="margin-top-1 margin-bottom-1">
|
||||||
|
<b class="review__step__name">Created by:</b> {{DomainRequest.creator.email|default:DomainRequest.creator.get_formatted_name }}
|
||||||
|
</p>
|
||||||
|
{% else %}
|
||||||
|
<p class="margin-top-1 margin-bottom-1">
|
||||||
|
<b class="review__step__name">No creator found:</b> this is an error, please email <a href="mailto:help@get.gov" class="usa-link">help@get.gov</a>.
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% with statuses=DomainRequest.DomainRequestStatus last_submitted=DomainRequest.last_submitted_date|date:"F j, Y" first_submitted=DomainRequest.first_submitted_date|date:"F j, Y" last_status_update=DomainRequest.last_status_update|date:"F j, Y" %}
|
||||||
|
{% comment %}
|
||||||
|
These are intentionally seperated this way.
|
||||||
|
There is some code repetition, but it gives us more flexibility rather than a dense reduction.
|
||||||
|
Leave it this way until we've solidified our requirements.
|
||||||
|
{% endcomment %}
|
||||||
|
{% if DomainRequest.status == statuses.STARTED %}
|
||||||
|
{% with first_started_date=DomainRequest.get_first_status_started_date|date:"F j, Y" %}
|
||||||
|
<p class="margin-top-1">
|
||||||
|
{% comment %}
|
||||||
|
A newly created domain request will not have a value for last_status update.
|
||||||
|
This is because the status never really updated.
|
||||||
|
However, if this somehow goes back to started we can default to displaying that new date.
|
||||||
|
{% endcomment %}
|
||||||
|
<b class="review__step__name">Started on:</b> {{last_status_update|default:first_started_date}}
|
||||||
|
</p>
|
||||||
|
{% endwith %}
|
||||||
|
{% elif DomainRequest.status == statuses.SUBMITTED %}
|
||||||
|
<p class="margin-top-1 margin-bottom-1">
|
||||||
|
<b class="review__step__name">Submitted on:</b> {{last_submitted|default:first_submitted }}
|
||||||
|
</p>
|
||||||
|
<p class="margin-top-1">
|
||||||
|
<b class="review__step__name">Last updated on:</b> {{DomainRequest.updated_at|date:"F j, Y"}}
|
||||||
|
</p>
|
||||||
|
{% elif DomainRequest.status == statuses.ACTION_NEEDED %}
|
||||||
|
<p class="margin-top-1 margin-bottom-1">
|
||||||
|
<b class="review__step__name">Submitted on:</b> {{last_submitted|default:first_submitted }}
|
||||||
|
</p>
|
||||||
|
<p class="margin-top-1">
|
||||||
|
<b class="review__step__name">Last updated on:</b> {{DomainRequest.updated_at|date:"F j, Y"}}
|
||||||
|
</p>
|
||||||
|
{% elif DomainRequest.status == statuses.REJECTED %}
|
||||||
|
<p class="margin-top-1 margin-bottom-1">
|
||||||
|
<b class="review__step__name">Submitted on:</b> {{last_submitted|default:first_submitted }}
|
||||||
|
</p>
|
||||||
|
<p class="margin-top-1">
|
||||||
|
<b class="review__step__name">Rejected on:</b> {{last_status_update}}
|
||||||
|
</p>
|
||||||
|
{% elif DomainRequest.status == statuses.WITHDRAWN %}
|
||||||
|
<p class="margin-top-1 margin-bottom-1">
|
||||||
|
<b class="review__step__name">Submitted on:</b> {{last_submitted|default:first_submitted }}
|
||||||
|
</p>
|
||||||
|
<p class="margin-top-1">
|
||||||
|
<b class="review__step__name">Withdrawn on:</b> {{last_status_update}}
|
||||||
|
</p>
|
||||||
|
{% else %}
|
||||||
|
{% comment %} Shown for in_review, approved, ineligible {% endcomment %}
|
||||||
|
<p class="margin-top-1">
|
||||||
|
<b class="review__step__name">Last updated on:</b> {{DomainRequest.updated_at|date:"F j, Y"}}
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
{% endwith %}
|
||||||
|
{% endblock status_metadata %}
|
||||||
|
|
||||||
|
{% block status_blurb %}
|
||||||
|
{% if DomainRequest.is_awaiting_review %}
|
||||||
|
<p>{% include "includes/domain_request_awaiting_review.html" with show_withdraw_text=DomainRequest.is_withdrawable %}</p>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock status_blurb %}
|
||||||
|
|
||||||
|
{% block modify_request %}
|
||||||
|
{% if DomainRequest.is_withdrawable %}
|
||||||
|
<p><a href="{% url 'domain-request-withdraw-confirmation' pk=DomainRequest.id %}" class="usa-button usa-button--outline withdraw_outline">
|
||||||
|
Withdraw request</a>
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock modify_request %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid-col desktop:grid-offset-2 maxw-tablet">
|
||||||
|
{% block request_summary_header %}
|
||||||
|
<h2 class="text-primary-darker"> Summary of your domain request </h2>
|
||||||
|
{% endblock request_summary_header%}
|
||||||
|
|
||||||
|
{% block request_summary %}
|
||||||
|
{% with heading_level='h3' %}
|
||||||
|
{% with org_type=DomainRequest.get_generic_org_type_display %}
|
||||||
|
{% include "includes/summary_item.html" with title='Type of organization' value=org_type heading_level=heading_level %}
|
||||||
|
{% endwith %}
|
||||||
|
|
||||||
|
{% if DomainRequest.tribe_name %}
|
||||||
|
{% include "includes/summary_item.html" with title='Tribal government' value=DomainRequest.tribe_name heading_level=heading_level %}
|
||||||
|
|
||||||
|
{% if DomainRequest.federally_recognized_tribe %}
|
||||||
|
<p>Federally-recognized tribe</p>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if DomainRequest.state_recognized_tribe %}
|
||||||
|
<p>State-recognized tribe</p>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if DomainRequest.get_federal_type_display %}
|
||||||
|
{% include "includes/summary_item.html" with title='Federal government branch' value=DomainRequest.get_federal_type_display heading_level=heading_level %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if DomainRequest.is_election_board %}
|
||||||
|
{% with value=DomainRequest.is_election_board|yesno:"Yes,No,Incomplete" %}
|
||||||
|
{% include "includes/summary_item.html" with title='Election office' value=value heading_level=heading_level %}
|
||||||
|
{% endwith %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if DomainRequest.organization_name %}
|
||||||
|
{% include "includes/summary_item.html" with title='Organization' value=DomainRequest address='true' heading_level=heading_level %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if DomainRequest.about_your_organization %}
|
||||||
|
{% include "includes/summary_item.html" with title='About your organization' value=DomainRequest.about_your_organization heading_level=heading_level %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if DomainRequest.senior_official %}
|
||||||
|
{% include "includes/summary_item.html" with title='Senior official' value=DomainRequest.senior_official contact='true' heading_level=heading_level %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if DomainRequest.current_websites.all %}
|
||||||
|
{% include "includes/summary_item.html" with title='Current websites' value=DomainRequest.current_websites.all list='true' heading_level=heading_level %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if DomainRequest.requested_domain %}
|
||||||
|
{% include "includes/summary_item.html" with title='.gov domain' value=DomainRequest.requested_domain heading_level=heading_level %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if DomainRequest.alternative_domains.all %}
|
||||||
|
{% include "includes/summary_item.html" with title='Alternative domains' value=DomainRequest.alternative_domains.all list='true' heading_level=heading_level %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if DomainRequest.purpose %}
|
||||||
|
{% include "includes/summary_item.html" with title='Purpose of your domain' value=DomainRequest.purpose heading_level=heading_level %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if DomainRequest.creator %}
|
||||||
|
{% include "includes/summary_item.html" with title='Your contact information' value=DomainRequest.creator contact='true' heading_level=heading_level %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if DomainRequest.other_contacts.all %}
|
||||||
|
{% include "includes/summary_item.html" with title='Other employees from your organization' value=DomainRequest.other_contacts.all contact='true' list='true' heading_level=heading_level %}
|
||||||
|
{% else %}
|
||||||
|
{% include "includes/summary_item.html" with title='Other employees from your organization' value=DomainRequest.no_other_contacts_rationale heading_level=heading_level %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{# We always show this field even if None #}
|
||||||
|
{% if DomainRequest %}
|
||||||
|
<h3 class="register-form-review-header">CISA Regional Representative</h3>
|
||||||
|
<ul class="usa-list usa-list--unstyled margin-top-0">
|
||||||
|
{% if DomainRequest.cisa_representative_first_name %}
|
||||||
|
{{ DomainRequest.get_formatted_cisa_rep_name }}
|
||||||
|
{% else %}
|
||||||
|
No
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
<h3 class="register-form-review-header">Anything else</h3>
|
||||||
|
<ul class="usa-list usa-list--unstyled margin-top-0">
|
||||||
|
{% if DomainRequest.anything_else %}
|
||||||
|
{{DomainRequest.anything_else}}
|
||||||
|
{% else %}
|
||||||
|
No
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
{% endwith %}
|
||||||
|
{% endblock request_summary%}
|
||||||
|
</div>
|
||||||
|
</main>
|
|
@ -23,13 +23,21 @@
|
||||||
</svg>
|
</svg>
|
||||||
Reset
|
Reset
|
||||||
</button>
|
</button>
|
||||||
|
{% if portfolio %}
|
||||||
|
<label class="usa-sr-only" for="domain-requests__search-field">Search by domain name or creator</label>
|
||||||
|
{% else %}
|
||||||
<label class="usa-sr-only" for="domain-requests__search-field">Search by domain name</label>
|
<label class="usa-sr-only" for="domain-requests__search-field">Search by domain name</label>
|
||||||
|
{% endif %}
|
||||||
<input
|
<input
|
||||||
class="usa-input"
|
class="usa-input"
|
||||||
id="domain-requests__search-field"
|
id="domain-requests__search-field"
|
||||||
type="search"
|
type="search"
|
||||||
name="search"
|
name="search"
|
||||||
|
{% if portfolio %}
|
||||||
|
placeholder="Search by domain name or creator"
|
||||||
|
{% else %}
|
||||||
placeholder="Search by domain name"
|
placeholder="Search by domain name"
|
||||||
|
{% endif %}
|
||||||
/>
|
/>
|
||||||
<button class="usa-button" type="submit" id="domain-requests__search-field-submit">
|
<button class="usa-button" type="submit" id="domain-requests__search-field-submit">
|
||||||
<img
|
<img
|
||||||
|
@ -42,6 +50,125 @@
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% if portfolio %}
|
||||||
|
<div class="display-flex flex-align-center">
|
||||||
|
<span class="margin-right-2 margin-top-neg-1 usa-prose text-base-darker">Filter by</span>
|
||||||
|
<div class="usa-accordion usa-accordion--select margin-right-2">
|
||||||
|
<div class="usa-accordion__heading">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="usa-button usa-button--small padding--8-8-9 usa-button--outline usa-button--filter usa-accordion__button"
|
||||||
|
aria-expanded="false"
|
||||||
|
aria-controls="filter-status"
|
||||||
|
>
|
||||||
|
<span class="filter-indicator text-bold display-none"></span> Status
|
||||||
|
<svg class="usa-icon top-2px" aria-hidden="true" focusable="false" role="img" width="24">
|
||||||
|
<use xlink:href="/public/img/sprite.svg#expand_more"></use>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div id="filter-status" class="usa-accordion__content usa-prose shadow-1">
|
||||||
|
<h2>Status</h2>
|
||||||
|
<fieldset class="usa-fieldset margin-top-0">
|
||||||
|
<legend class="usa-legend">Select to apply <span class="sr-only">status</span> filter</legend>
|
||||||
|
<div class="usa-checkbox">
|
||||||
|
<input
|
||||||
|
class="usa-checkbox__input"
|
||||||
|
id="filter-status-started"
|
||||||
|
type="checkbox"
|
||||||
|
name="filter-status"
|
||||||
|
value="started"
|
||||||
|
/>
|
||||||
|
<label class="usa-checkbox__label" for="filter-status-started"
|
||||||
|
>Started</label
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="usa-checkbox">
|
||||||
|
<input
|
||||||
|
class="usa-checkbox__input"
|
||||||
|
id="filter-status-submitted"
|
||||||
|
type="checkbox"
|
||||||
|
name="filter-status"
|
||||||
|
value="submitted"
|
||||||
|
/>
|
||||||
|
<label class="usa-checkbox__label" for="filter-status-submitted"
|
||||||
|
>Submitted</label
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="usa-checkbox">
|
||||||
|
<input
|
||||||
|
class="usa-checkbox__input"
|
||||||
|
id="filter-status-in-review"
|
||||||
|
type="checkbox"
|
||||||
|
name="filter-status"
|
||||||
|
value="in review"
|
||||||
|
/>
|
||||||
|
<label class="usa-checkbox__label" for="filter-status-in-review"
|
||||||
|
>In review</label
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="usa-checkbox">
|
||||||
|
<input
|
||||||
|
class="usa-checkbox__input"
|
||||||
|
id="filter-status-action-needed"
|
||||||
|
type="checkbox"
|
||||||
|
name="filter-status"
|
||||||
|
value="action needed"
|
||||||
|
/>
|
||||||
|
<label class="usa-checkbox__label" for="filter-status-action-needed"
|
||||||
|
>Action needed</label
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="usa-checkbox">
|
||||||
|
<input
|
||||||
|
class="usa-checkbox__input"
|
||||||
|
id="filter-status-rejected"
|
||||||
|
type="checkbox"
|
||||||
|
name="filter-status"
|
||||||
|
value="rejected"
|
||||||
|
/>
|
||||||
|
<label class="usa-checkbox__label" for="filter-status-rejected"
|
||||||
|
>Rejected</label
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="usa-checkbox">
|
||||||
|
<input
|
||||||
|
class="usa-checkbox__input"
|
||||||
|
id="filter-status-withdrawn"
|
||||||
|
type="checkbox"
|
||||||
|
name="filter-status"
|
||||||
|
value="withdrawn"
|
||||||
|
/>
|
||||||
|
<label class="usa-checkbox__label" for="filter-status-withdrawn"
|
||||||
|
>Withdrawn</label
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="usa-checkbox">
|
||||||
|
<input
|
||||||
|
class="usa-checkbox__input"
|
||||||
|
id="filter-status-ineligible"
|
||||||
|
type="checkbox"
|
||||||
|
name="filter-status"
|
||||||
|
value="ineligible"
|
||||||
|
/>
|
||||||
|
<label class="usa-checkbox__label" for="filter-status-ineligible"
|
||||||
|
>Ineligible</label
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="usa-button usa-button--small padding--8-12-9-12 usa-button--outline usa-button--filter domain-requests__reset-filters display-none"
|
||||||
|
>
|
||||||
|
Clear filters
|
||||||
|
<svg class="usa-icon top-1px" aria-hidden="true" focusable="false" role="img" width="24">
|
||||||
|
<use xlink:href="/public/img/sprite.svg#close"></use>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
<div class="domain-requests__table-wrapper display-none usa-table-container--scrollable margin-top-0" tabindex="0">
|
<div class="domain-requests__table-wrapper display-none usa-table-container--scrollable margin-top-0" tabindex="0">
|
||||||
<table class="usa-table usa-table--borderless usa-table--stacked dotgov-table dotgov-table--stacked domain-requests__table">
|
<table class="usa-table usa-table--borderless usa-table--stacked dotgov-table dotgov-table--stacked domain-requests__table">
|
||||||
<caption class="sr-only">Your domain requests</caption>
|
<caption class="sr-only">Your domain requests</caption>
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
<!-- Embedding the portfolio value in a data attribute -->
|
<!-- Embedding the portfolio value in a data attribute -->
|
||||||
<span id="portfolio-js-value" data-portfolio="{{ portfolio.id }}"></span>
|
<span id="portfolio-js-value" data-portfolio="{{ portfolio.id }}"></span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="section-outlined__search {% if portfolio %} mobile:grid-col-12 desktop:grid-col-6{% endif %}">
|
<div class="section-outlined__search {% if portfolio %} mobile:grid-col-12 desktop:grid-col-6{% endif %} {% if is_widescreen_mode %} section-outlined__search--widescreen {% endif %}">
|
||||||
<section aria-label="Domains search component" class="margin-top-2">
|
<section aria-label="Domains search component" class="margin-top-2">
|
||||||
<form class="usa-search usa-search--small" method="POST" role="search">
|
<form class="usa-search usa-search--small" method="POST" role="search">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
|
@ -44,7 +44,7 @@
|
||||||
{% if user_domain_count and user_domain_count > 0 %}
|
{% if user_domain_count and user_domain_count > 0 %}
|
||||||
<div class="section-outlined__utility-button mobile-lg:padding-right-105 {% if portfolio %} mobile:grid-col-12 desktop:grid-col-6 desktop:padding-left-3{% endif %}">
|
<div class="section-outlined__utility-button mobile-lg:padding-right-105 {% if portfolio %} mobile:grid-col-12 desktop:grid-col-6 desktop:padding-left-3{% endif %}">
|
||||||
<section aria-label="Domains report component" class="margin-top-205">
|
<section aria-label="Domains report component" class="margin-top-205">
|
||||||
<a href="{% url 'export_data_type_user' %}" class="usa-button usa-button--unstyled usa-button--with-icon" role="button">
|
<a href="{% url 'export_data_type_user' %}" class="usa-button usa-button--unstyled usa-button--with-icon usa-button--justify-right" role="button">
|
||||||
<svg class="usa-icon usa-icon--big" aria-hidden="true" focusable="false" role="img" width="24" height="24">
|
<svg class="usa-icon usa-icon--big" aria-hidden="true" focusable="false" role="img" width="24" height="24">
|
||||||
<use xlink:href="{%static 'img/sprite.svg'%}#file_download"></use>
|
<use xlink:href="{%static 'img/sprite.svg'%}#file_download"></use>
|
||||||
</svg>Export as CSV
|
</svg>Export as CSV
|
||||||
|
@ -64,7 +64,7 @@
|
||||||
aria-expanded="false"
|
aria-expanded="false"
|
||||||
aria-controls="filter-status"
|
aria-controls="filter-status"
|
||||||
>
|
>
|
||||||
<span class="domain__filter-indicator text-bold display-none"></span> Status
|
<span class="filter-indicator text-bold display-none"></span> Status
|
||||||
<svg class="usa-icon top-2px" aria-hidden="true" focusable="false" role="img" width="24">
|
<svg class="usa-icon top-2px" aria-hidden="true" focusable="false" role="img" width="24">
|
||||||
<use xlink:href="/public/img/sprite.svg#expand_more"></use>
|
<use xlink:href="/public/img/sprite.svg#expand_more"></use>
|
||||||
</svg>
|
</svg>
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
<footer class="usa-footer">
|
<footer class="usa-footer">
|
||||||
<div class="usa-footer__secondary-section">
|
<div class="usa-footer__secondary-section">
|
||||||
<div class="grid-container">
|
<div class="grid-container {% if is_widescreen_mode %} grid-container--widescreen {% endif %}">
|
||||||
<div class="grid-row grid-gap">
|
<div class="grid-row grid-gap">
|
||||||
<div
|
<div
|
||||||
class="
|
class="
|
||||||
|
@ -51,7 +51,7 @@
|
||||||
class="usa-identifier__section usa-identifier__section--masthead"
|
class="usa-identifier__section usa-identifier__section--masthead"
|
||||||
aria-label="Agency identifier"
|
aria-label="Agency identifier"
|
||||||
>
|
>
|
||||||
<div class="usa-identifier__container">
|
<div class="usa-identifier__container {% if is_widescreen_mode %} usa-identifier__container--widescreen {% endif %}">
|
||||||
<div class="usa-identifier__logos">
|
<div class="usa-identifier__logos">
|
||||||
<a rel="noopener noreferrer" target="_blank" href="https://www.cisa.gov" class="usa-identifier__logo"
|
<a rel="noopener noreferrer" target="_blank" href="https://www.cisa.gov" class="usa-identifier__logo"
|
||||||
><img
|
><img
|
||||||
|
@ -77,7 +77,7 @@
|
||||||
class="usa-identifier__section usa-identifier__section--required-links"
|
class="usa-identifier__section usa-identifier__section--required-links"
|
||||||
aria-label="Important links"
|
aria-label="Important links"
|
||||||
>
|
>
|
||||||
<div class="usa-identifier__container">
|
<div class="usa-identifier__container {% if is_widescreen_mode %} usa-identifier__container--widescreen {% endif %}">
|
||||||
<ul class="usa-identifier__required-links-list">
|
<ul class="usa-identifier__required-links-list">
|
||||||
<li class="usa-identifier__required-links-item">
|
<li class="usa-identifier__required-links-item">
|
||||||
<a rel="noopener noreferrer" target="_blank" href="{% public_site_url 'about/' %}"
|
<a rel="noopener noreferrer" target="_blank" href="{% public_site_url 'about/' %}"
|
||||||
|
@ -119,7 +119,7 @@
|
||||||
class="usa-identifier__section usa-identifier__section--usagov"
|
class="usa-identifier__section usa-identifier__section--usagov"
|
||||||
aria-label="U.S. government information and services"
|
aria-label="U.S. government information and services"
|
||||||
>
|
>
|
||||||
<div class="usa-identifier__container">
|
<div class="usa-identifier__container {% if is_widescreen_mode %} usa-identifier__container--widescreen {% endif %}">
|
||||||
<div class="usa-identifier__usagov-description">
|
<div class="usa-identifier__usagov-description">
|
||||||
Looking for U.S. government information and services?
|
Looking for U.S. government information and services?
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{% load static %}
|
{% load static %}
|
||||||
|
|
||||||
<header class="usa-header usa-header--basic">
|
<header class="usa-header usa-header--basic">
|
||||||
<div class="usa-nav-container">
|
<div class="usa-nav-container {% if is_widescreen_mode %} usa-nav-container--widescreen {% endif %}">
|
||||||
<div class="usa-navbar">
|
<div class="usa-navbar">
|
||||||
{% include "includes/gov_extended_logo.html" with logo_clickable=logo_clickable %}
|
{% include "includes/gov_extended_logo.html" with logo_clickable=logo_clickable %}
|
||||||
<button type="button" class="usa-menu-btn">Menu</button>
|
<button type="button" class="usa-menu-btn">Menu</button>
|
||||||
|
@ -16,7 +16,6 @@
|
||||||
{% if user.is_authenticated %}
|
{% if user.is_authenticated %}
|
||||||
<span class="usa-nav__username ellipsis">{{ user.email }}</span>
|
<span class="usa-nav__username ellipsis">{{ user.email }}</span>
|
||||||
</li>
|
</li>
|
||||||
{% if has_profile_feature_flag %}
|
|
||||||
<li class="usa-nav__primary-item">
|
<li class="usa-nav__primary-item">
|
||||||
{% url 'user-profile' as user_profile_url %}
|
{% url 'user-profile' as user_profile_url %}
|
||||||
{% url 'finish-user-profile-setup' as finish_setup_url %}
|
{% url 'finish-user-profile-setup' as finish_setup_url %}
|
||||||
|
@ -24,7 +23,6 @@
|
||||||
<span class="text-primary">Your profile</span>
|
<span class="text-primary">Your profile</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
|
||||||
<li class="usa-nav__primary-item">
|
<li class="usa-nav__primary-item">
|
||||||
<a href="{% url 'logout' %}"><span class="text-primary">Sign out</span></a>
|
<a href="{% url 'logout' %}"><span class="text-primary">Sign out</span></a>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|
|
@ -2,13 +2,13 @@
|
||||||
{% load custom_filters %}
|
{% load custom_filters %}
|
||||||
|
|
||||||
<header class="usa-header usa-header--extended">
|
<header class="usa-header usa-header--extended">
|
||||||
<div class="usa-navbar">
|
<div class="usa-navbar {% if is_widescreen_mode %} usa-navbar--widescreen {% endif %}">
|
||||||
{% include "includes/gov_extended_logo.html" with logo_clickable=logo_clickable %}
|
{% include "includes/gov_extended_logo.html" with logo_clickable=logo_clickable %}
|
||||||
<button type="button" class="usa-menu-btn">Menu</button>
|
<button type="button" class="usa-menu-btn">Menu</button>
|
||||||
</div>
|
</div>
|
||||||
{% block usa_nav %}
|
{% block usa_nav %}
|
||||||
<nav class="usa-nav" aria-label="Primary navigation">
|
<nav class="usa-nav" aria-label="Primary navigation">
|
||||||
<div class="usa-nav__inner">
|
<div class="usa-nav__inner {% if is_widescreen_mode %} usa-nav__inner--widescreen {% endif %}">
|
||||||
<button type="button" class="usa-nav__close">
|
<button type="button" class="usa-nav__close">
|
||||||
<img src="{%static 'img/usa-icons/close.svg'%}" role="img" alt="Close" />
|
<img src="{%static 'img/usa-icons/close.svg'%}" role="img" alt="Close" />
|
||||||
</button>
|
</button>
|
||||||
|
@ -18,7 +18,6 @@
|
||||||
{% if user.is_authenticated %}
|
{% if user.is_authenticated %}
|
||||||
<span class="ellipsis usa-nav__username">{{ user.email }}</span>
|
<span class="ellipsis usa-nav__username">{{ user.email }}</span>
|
||||||
</li>
|
</li>
|
||||||
{% if has_profile_feature_flag %}
|
|
||||||
<li class="usa-nav__secondary-item">
|
<li class="usa-nav__secondary-item">
|
||||||
{% url 'user-profile' as user_profile_url %}
|
{% url 'user-profile' as user_profile_url %}
|
||||||
{% url 'finish-user-profile-setup' as finish_setup_url %}
|
{% url 'finish-user-profile-setup' as finish_setup_url %}
|
||||||
|
@ -26,7 +25,6 @@
|
||||||
Your profile
|
Your profile
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
|
||||||
<li class="usa-nav__secondary-item">
|
<li class="usa-nav__secondary-item">
|
||||||
<a class="usa-nav-link" href="{% url 'logout' %}">Sign out</a>
|
<a class="usa-nav-link" href="{% url 'logout' %}">Sign out</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
@ -42,7 +40,7 @@
|
||||||
{% else %}
|
{% else %}
|
||||||
{% url 'no-portfolio-domains' as url %}
|
{% url 'no-portfolio-domains' as url %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a href="{{ url }}" class="usa-nav-link{% if 'domain'|in_path:request.path %} usa-current{% endif %}">
|
<a href="{{ url }}" class="usa-nav-link{% if path|is_domain_subpage %} usa-current{% endif %}">
|
||||||
Domains
|
Domains
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
@ -59,7 +57,7 @@
|
||||||
{% url 'domain-requests' as url %}
|
{% url 'domain-requests' as url %}
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="usa-accordion__button usa-nav__link{% if 'request'|in_path:request.path %} usa-current{% endif %}"
|
class="usa-accordion__button usa-nav__link{% if path|is_domain_request_subpage %} usa-current{% endif %}"
|
||||||
aria-expanded="false"
|
aria-expanded="false"
|
||||||
aria-controls="basic-nav-section-two"
|
aria-controls="basic-nav-section-two"
|
||||||
>
|
>
|
||||||
|
@ -80,13 +78,13 @@
|
||||||
<!-- user has view but no edit permissions -->
|
<!-- user has view but no edit permissions -->
|
||||||
{% elif has_any_requests_portfolio_permission %}
|
{% elif has_any_requests_portfolio_permission %}
|
||||||
{% url 'domain-requests' as url %}
|
{% url 'domain-requests' as url %}
|
||||||
<a href="{{ url }}" class="usa-nav-link{% if 'request'|in_path:request.path %} usa-current{% endif %}">
|
<a href="{{ url }}" class="usa-nav-link{% if path|is_domain_request_subpage %} usa-current{% endif %}">
|
||||||
Domain requests
|
Domain requests
|
||||||
</a>
|
</a>
|
||||||
<!-- user does not have permissions -->
|
<!-- user does not have permissions -->
|
||||||
{% else %}
|
{% else %}
|
||||||
{% url 'no-portfolio-requests' as url %}
|
{% url 'no-portfolio-requests' as url %}
|
||||||
<a href="{{ url }}" class="usa-nav-link{% if 'request'|in_path:request.path %} usa-current{% endif %}">
|
<a href="{{ url }}" class="usa-nav-link{% if path|is_domain_request_subpage %} usa-current{% endif %}">
|
||||||
Domain requests
|
Domain requests
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -104,7 +102,7 @@
|
||||||
<li class="usa-nav__primary-item">
|
<li class="usa-nav__primary-item">
|
||||||
{% url 'organization' as url %}
|
{% url 'organization' as url %}
|
||||||
<!-- Move the padding from the a to the span so that the descenders do not get cut off -->
|
<!-- Move the padding from the a to the span so that the descenders do not get cut off -->
|
||||||
<a href="{{ url }}" class="usa-nav-link padding-y-0 {% if request.path == '/organization/' %} usa-current{% endif %}">
|
<a href="{{ url }}" class="usa-nav-link padding-y-0 {% if path|is_portfolio_subpage %} usa-current{% endif %}">
|
||||||
<span class="ellipsis ellipsis--23 ellipsis--desktop-50 padding-y-1 desktop:padding-y-2">
|
<span class="ellipsis ellipsis--23 ellipsis--desktop-50 padding-y-1 desktop:padding-y-2">
|
||||||
{{ portfolio.organization_name }}
|
{{ portfolio.organization_name }}
|
||||||
</span>
|
</span>
|
||||||
|
|
|
@ -1,10 +1,7 @@
|
||||||
<div class="usa-site-alert--emergency margin-y-0 {% if add_class %}{{ add_class }}{% endif %}" aria-label="Site alert">
|
<div class="usa-site-alert--emergency margin-y-0 {% if add_class %}{{ add_class }}{% endif %}" aria-label="Site alert">
|
||||||
<div class="usa-alert">
|
<div class="usa-alert">
|
||||||
<div class="usa-alert__body {% if add_body_class %}{{ add_body_class }}{% endif %}">
|
<div class="usa-alert__body {% if add_body_class %}{{ add_body_class }}{% endif %} {% if is_widescreen_mode %}usa-alert__body--widescreen{% endif %}">
|
||||||
<b>Attention:</b> You are on a test site.
|
<b>Attention:</b> You are on a test site.
|
||||||
{% if has_profile_feature_flag %}
|
|
||||||
The profile_feature flag is active.
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -0,0 +1,92 @@
|
||||||
|
{% load custom_filters %}
|
||||||
|
{% load static url_helpers %}
|
||||||
|
|
||||||
|
{% for step in steps %}
|
||||||
|
<section class="summary-item margin-top-3">
|
||||||
|
{% if is_editable %}
|
||||||
|
{% namespaced_url 'domain-request' step as domain_request_url %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if step == Step.REQUESTING_ENTITY %}
|
||||||
|
|
||||||
|
{% if domain_request.organization_name %}
|
||||||
|
{% with title=form_titles|get_item:step value=domain_request %}
|
||||||
|
{% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=is_editable edit_link=domain_request_url address='true' %}
|
||||||
|
{% endwith %}
|
||||||
|
{% else %}
|
||||||
|
{% with title=form_titles|get_item:step value="<span class='text-bold text-secondary-dark'>Incomplete</span>"|safe %}
|
||||||
|
{% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=is_editable edit_link=domain_request_url %}
|
||||||
|
{% endwith %}
|
||||||
|
{% endif%}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if step == Step.CURRENT_SITES %}
|
||||||
|
{% if domain_request.current_websites.all %}
|
||||||
|
{% with title=form_titles|get_item:step value=domain_request.current_websites.all %}
|
||||||
|
{% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=is_editable edit_link=domain_request_url list='true' %}
|
||||||
|
{% endwith %}
|
||||||
|
{% else %}
|
||||||
|
{% with title=form_titles|get_item:step value='None' %}
|
||||||
|
{% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=is_editable edit_link=domain_request_url %}
|
||||||
|
{% endwith %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if step == Step.DOTGOV_DOMAIN %}
|
||||||
|
{% with title=form_titles|get_item:step value=domain_request.requested_domain.name|default:"<span class='text-bold text-secondary-dark'>Incomplete</span>"|safe%}
|
||||||
|
{% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=is_editable edit_link=domain_request_url %}
|
||||||
|
{% endwith %}
|
||||||
|
|
||||||
|
{% if domain_request.alternative_domains.all %}
|
||||||
|
<h3 class="register-form-review-header">Alternative domains</h3>
|
||||||
|
<ul class="usa-list usa-list--unstyled margin-top-0">
|
||||||
|
{% for site in domain_request.alternative_domains.all %}
|
||||||
|
<li>{{ site.website }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if step == Step.PURPOSE %}
|
||||||
|
{% with title=form_titles|get_item:step value=domain_request.purpose|default:"<span class='text-bold text-secondary-dark'>Incomplete</span>"|safe %}
|
||||||
|
{% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=is_editable edit_link=domain_request_url %}
|
||||||
|
{% endwith %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if step == Step.ADDITIONAL_DETAILS %}
|
||||||
|
{% with title=form_titles|get_item:step %}
|
||||||
|
{% if domain_request.has_additional_details %}
|
||||||
|
{% include "includes/summary_item.html" with title="Additional Details" value=" " heading_level=heading_level editable=is_editable edit_link=domain_request_url %}
|
||||||
|
<h3 class="register-form-review-header">CISA Regional Representative</h3>
|
||||||
|
<ul class="usa-list usa-list--unstyled margin-top-0">
|
||||||
|
{% if domain_request.cisa_representative_first_name %}
|
||||||
|
<li>{{domain_request.cisa_representative_first_name}} {{domain_request.cisa_representative_last_name}}</li>
|
||||||
|
{% if domain_request.cisa_representative_email %}
|
||||||
|
<li>{{domain_request.cisa_representative_email}}</li>
|
||||||
|
{% endif %}
|
||||||
|
{% else %}
|
||||||
|
No
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h3 class="register-form-review-header">Anything else</h3>
|
||||||
|
<ul class="usa-list usa-list--unstyled margin-top-0">
|
||||||
|
{% if domain_request.anything_else %}
|
||||||
|
{{domain_request.anything_else}}
|
||||||
|
{% else %}
|
||||||
|
No
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
{% else %}
|
||||||
|
{% include "includes/summary_item.html" with title="Additional Details" value="<span class='text-bold text-secondary-dark'>Incomplete</span>"|safe heading_level=heading_level editable=is_editable edit_link=domain_request_url %}
|
||||||
|
{% endif %}
|
||||||
|
{% endwith %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if step == Step.REQUIREMENTS %}
|
||||||
|
{% with title=form_titles|get_item:step value=domain_request.is_policy_acknowledged|yesno:"I agree.,I do not agree.,I do not agree." %}
|
||||||
|
{% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=is_editable edit_link=domain_request_url %}
|
||||||
|
{% endwith %}
|
||||||
|
{% endif %}
|
||||||
|
</section>
|
||||||
|
{% endfor %}
|
|
@ -0,0 +1,18 @@
|
||||||
|
{% extends 'includes/request_status_manage.html' %}
|
||||||
|
{% load custom_filters %}
|
||||||
|
{% load static url_helpers %}
|
||||||
|
|
||||||
|
{% comment %} Do not show the withdrawal text in viewonly mode {% endcomment %}
|
||||||
|
{% block status_blurb %}
|
||||||
|
{% if DomainRequest.is_awaiting_review %}
|
||||||
|
<p>{% include "includes/domain_request_awaiting_review.html" with show_withdraw_text=False %}</p>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock status_blurb %}
|
||||||
|
|
||||||
|
{% comment %} Do not show action buttons in viewonly mode {% endcomment %}
|
||||||
|
{% block modify_request %}
|
||||||
|
{% endblock modify_request %}
|
||||||
|
|
||||||
|
{% block request_summary %}
|
||||||
|
{% include "includes/portfolio_request_review_steps.html" with domain_request=DomainRequest is_editable=False %}
|
||||||
|
{% endblock request_summary %}
|
168
src/registrar/templates/includes/request_review_steps.html
Normal file
168
src/registrar/templates/includes/request_review_steps.html
Normal file
|
@ -0,0 +1,168 @@
|
||||||
|
{% load custom_filters %}
|
||||||
|
{% load static url_helpers %}
|
||||||
|
|
||||||
|
{% for step in steps %}
|
||||||
|
<section class="summary-item margin-top-3">
|
||||||
|
{% if is_editable %}
|
||||||
|
{% namespaced_url 'domain-request' step as domain_request_url %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if step == Step.ORGANIZATION_TYPE %}
|
||||||
|
{% if domain_request.generic_org_type is not None %}
|
||||||
|
{% with title=form_titles|get_item:step value=domain_request.get_generic_org_type_display|default:"<span class='text-bold text-secondary-dark'>Incomplete</span>"|safe %}
|
||||||
|
{% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=is_editable edit_link=domain_request_url %}
|
||||||
|
{% endwith %}
|
||||||
|
{% else %}
|
||||||
|
{% with title=form_titles|get_item:step value="<span class='text-bold text-secondary-dark'>Incomplete</span>"|safe %}
|
||||||
|
{% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=is_editable edit_link=domain_request_url %}
|
||||||
|
{% endwith %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if step == Step.TRIBAL_GOVERNMENT %}
|
||||||
|
{% with title=form_titles|get_item:step value=domain_request.tribe_name|default:"<span class='text-bold text-secondary-dark'>Incomplete</span>"|safe %}
|
||||||
|
{% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=is_editable edit_link=domain_request_url %}
|
||||||
|
{% endwith %}
|
||||||
|
{% if domain_request.federally_recognized_tribe %}<p>Federally-recognized tribe</p>{% endif %}
|
||||||
|
{% if domain_request.state_recognized_tribe %}<p>State-recognized tribe</p>{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
|
{% if step == Step.ORGANIZATION_FEDERAL %}
|
||||||
|
{% with title=form_titles|get_item:step value=domain_request.get_federal_type_display|default:"<span class='text-bold text-secondary-dark'>Incomplete</span>"|safe %}
|
||||||
|
{% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=is_editable edit_link=domain_request_url %}
|
||||||
|
{% endwith %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if step == Step.ORGANIZATION_ELECTION %}
|
||||||
|
{% with title=form_titles|get_item:step value=domain_request.is_election_board|yesno:"Yes,No,Incomplete" %}
|
||||||
|
{% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=is_editable edit_link=domain_request_url %}
|
||||||
|
{% endwith %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if step == Step.ORGANIZATION_CONTACT %}
|
||||||
|
{% if domain_request.organization_name %}
|
||||||
|
{% with title=form_titles|get_item:step value=domain_request %}
|
||||||
|
{% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=is_editable edit_link=domain_request_url address='true' %}
|
||||||
|
{% endwith %}
|
||||||
|
{% else %}
|
||||||
|
{% with title=form_titles|get_item:step value="<span class='text-bold text-secondary-dark'>Incomplete</span>"|safe %}
|
||||||
|
{% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=is_editable edit_link=domain_request_url %}
|
||||||
|
{% endwith %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if step == Step.ABOUT_YOUR_ORGANIZATION %}
|
||||||
|
{% with title=form_titles|get_item:step value=domain_request.about_your_organization|default:"<span class='text-bold text-secondary-dark'>Incomplete</span>"|safe %}
|
||||||
|
{% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=is_editable edit_link=domain_request_url %}
|
||||||
|
{% endwith %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if step == Step.SENIOR_OFFICIAL %}
|
||||||
|
{% if domain_request.senior_official is not None %}
|
||||||
|
{% with title=form_titles|get_item:step value=domain_request.senior_official %}
|
||||||
|
{% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=is_editable edit_link=domain_request_url contact='true' %}
|
||||||
|
{% endwith %}
|
||||||
|
{% else %}
|
||||||
|
{% with title=form_titles|get_item:step value="<span class='text-bold text-secondary-dark'>Incomplete</span>"|safe %}
|
||||||
|
{% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=is_editable edit_link=domain_request_url %}
|
||||||
|
{% endwith %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if step == Step.CURRENT_SITES %}
|
||||||
|
{% if domain_request.current_websites.all %}
|
||||||
|
{% with title=form_titles|get_item:step value=domain_request.current_websites.all %}
|
||||||
|
{% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=is_editable edit_link=domain_request_url list='true' %}
|
||||||
|
{% endwith %}
|
||||||
|
{% else %}
|
||||||
|
{% with title=form_titles|get_item:step value='None' %}
|
||||||
|
{% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=is_editable edit_link=domain_request_url %}
|
||||||
|
{% endwith %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if step == Step.DOTGOV_DOMAIN %}
|
||||||
|
{% with title=form_titles|get_item:step value=domain_request.requested_domain.name|default:"<span class='text-bold text-secondary-dark'>Incomplete</span>"|safe%}
|
||||||
|
{% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=is_editable edit_link=domain_request_url %}
|
||||||
|
{% endwith %}
|
||||||
|
|
||||||
|
{% if domain_request.alternative_domains.all %}
|
||||||
|
<h3 class="register-form-review-header">Alternative domains</h3>
|
||||||
|
<ul class="usa-list usa-list--unstyled margin-top-0">
|
||||||
|
{% for site in domain_request.alternative_domains.all %}
|
||||||
|
<li>{{ site.website }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if step == Step.PURPOSE %}
|
||||||
|
{% with title=form_titles|get_item:step value=domain_request.purpose|default:"<span class='text-bold text-secondary-dark'>Incomplete</span>"|safe %}
|
||||||
|
{% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=is_editable edit_link=domain_request_url %}
|
||||||
|
{% endwith %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if step == Step.YOUR_CONTACT %}
|
||||||
|
{% if domain_request.creator is not None %}
|
||||||
|
{% with title=form_titles|get_item:step value=domain_request.creator %}
|
||||||
|
{% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=is_editable edit_link=domain_request_url contact='true' %}
|
||||||
|
{% endwith %}
|
||||||
|
{% else %}
|
||||||
|
{% with title=form_titles|get_item:step value="<span class='text-bold text-secondary-dark'>Incomplete</span>"|safe %}
|
||||||
|
{% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=is_editable edit_link=domain_request_url %}
|
||||||
|
{% endwith %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if step == Step.OTHER_CONTACTS %}
|
||||||
|
{% if domain_request.other_contacts.all %}
|
||||||
|
{% with title=form_titles|get_item:step value=domain_request.other_contacts.all %}
|
||||||
|
{% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=is_editable edit_link=domain_request_url contact='true' list='true' %}
|
||||||
|
{% endwith %}
|
||||||
|
{% else %}
|
||||||
|
{% with title=form_titles|get_item:step value=domain_request.no_other_contacts_rationale|default:"<span class='text-bold text-secondary-dark'>Incomplete</span>"|safe %}
|
||||||
|
{% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=is_editable edit_link=domain_request_url %}
|
||||||
|
{% endwith %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
|
{% if step == Step.ADDITIONAL_DETAILS %}
|
||||||
|
{% with title=form_titles|get_item:step %}
|
||||||
|
{% if domain_request.has_additional_details %}
|
||||||
|
{% include "includes/summary_item.html" with title="Additional Details" value=" " heading_level=heading_level editable=is_editable edit_link=domain_request_url %}
|
||||||
|
<h3 class="register-form-review-header">CISA Regional Representative</h3>
|
||||||
|
<ul class="usa-list usa-list--unstyled margin-top-0">
|
||||||
|
{% if domain_request.cisa_representative_first_name %}
|
||||||
|
<li>{{domain_request.cisa_representative_first_name}} {{domain_request.cisa_representative_last_name}}</li>
|
||||||
|
{% if domain_request.cisa_representative_email %}
|
||||||
|
<li>{{domain_request.cisa_representative_email}}</li>
|
||||||
|
{% endif %}
|
||||||
|
{% else %}
|
||||||
|
No
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h3 class="register-form-review-header">Anything else</h3>
|
||||||
|
<ul class="usa-list usa-list--unstyled margin-top-0">
|
||||||
|
{% if domain_request.anything_else %}
|
||||||
|
{{domain_request.anything_else}}
|
||||||
|
{% else %}
|
||||||
|
No
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
{% else %}
|
||||||
|
{% include "includes/summary_item.html" with title="Additional Details" value="<span class='text-bold text-secondary-dark'>Incomplete</span>"|safe heading_level=heading_level editable=is_editable edit_link=domain_request_url %}
|
||||||
|
{% endif %}
|
||||||
|
{% endwith %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
|
{% if step == Step.REQUIREMENTS %}
|
||||||
|
{% with title=form_titles|get_item:step value=domain_request.is_policy_acknowledged|yesno:"I agree.,I do not agree.,I do not agree." %}
|
||||||
|
{% include "includes/summary_item.html" with title=title value=value heading_level=heading_level editable=is_editable edit_link=domain_request_url %}
|
||||||
|
{% endwith %}
|
||||||
|
{% endif %}
|
||||||
|
</section>
|
||||||
|
{% endfor %}
|
236
src/registrar/templates/includes/request_status_manage.html
Normal file
236
src/registrar/templates/includes/request_status_manage.html
Normal file
|
@ -0,0 +1,236 @@
|
||||||
|
{% load custom_filters %}
|
||||||
|
{% load static url_helpers %}
|
||||||
|
<main id="main-content" class="grid-container">
|
||||||
|
<div class="grid-col desktop:grid-offset-2 desktop:grid-col-8">
|
||||||
|
{% block breadcrumb %}
|
||||||
|
{% if portfolio %}
|
||||||
|
{% url 'domain-requests' as url %}
|
||||||
|
{% else %}
|
||||||
|
{% url 'home' as url %}
|
||||||
|
{% endif %}
|
||||||
|
<nav class="usa-breadcrumb padding-top-0" aria-label="Domain request breadcrumb">
|
||||||
|
<ol class="usa-breadcrumb__list">
|
||||||
|
<li class="usa-breadcrumb__list-item">
|
||||||
|
{% if portfolio %}
|
||||||
|
<a href="{{ url }}" class="usa-breadcrumb__link"><span>Domain requests</span></a>
|
||||||
|
{% else %}
|
||||||
|
<a href="{{ url }}" class="usa-breadcrumb__link"><span>Manage your domains</span></a>
|
||||||
|
{% endif %}
|
||||||
|
</li>
|
||||||
|
<li class="usa-breadcrumb__list-item usa-current" aria-current="page">
|
||||||
|
{% if not DomainRequest.requested_domain and DomainRequest.status == DomainRequest.DomainRequestStatus.STARTED %}
|
||||||
|
<span>New domain request</span>
|
||||||
|
{% else %}
|
||||||
|
<span>{{ DomainRequest.requested_domain.name }}</span>
|
||||||
|
{% endif %}
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
</nav>
|
||||||
|
{% endblock breadcrumb %}
|
||||||
|
|
||||||
|
{% block header %}
|
||||||
|
{% if not DomainRequest.requested_domain and DomainRequest.status == DomainRequest.DomainRequestStatus.STARTED %}
|
||||||
|
<h1>New domain request</h1>
|
||||||
|
{% else %}
|
||||||
|
<h1>Domain request for {{ DomainRequest.requested_domain.name }}</h1>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock header %}
|
||||||
|
|
||||||
|
{% block status_summary %}
|
||||||
|
<div
|
||||||
|
class="usa-summary-box dotgov-status-box margin-top-3 padding-left-2"
|
||||||
|
role="region"
|
||||||
|
aria-labelledby="summary-box-key-information"
|
||||||
|
>
|
||||||
|
<div class="usa-summary-box__body">
|
||||||
|
<p class="usa-summary-box__heading font-sans-md margin-bottom-0"
|
||||||
|
id="summary-box-key-information"
|
||||||
|
>
|
||||||
|
<span class="text-bold text-primary-darker">
|
||||||
|
Status:
|
||||||
|
</span>
|
||||||
|
{{ DomainRequest.get_status_display|default:"ERROR Please contact technical support/dev" }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
{% endblock status_summary %}
|
||||||
|
|
||||||
|
{% block status_metadata %}
|
||||||
|
|
||||||
|
{% if portfolio %}
|
||||||
|
{% if DomainRequest.creator %}
|
||||||
|
<p class="margin-top-1 margin-bottom-1">
|
||||||
|
<b class="review__step__name">Created by:</b> {{DomainRequest.creator.email|default:DomainRequest.creator.get_formatted_name }}
|
||||||
|
</p>
|
||||||
|
{% else %}
|
||||||
|
<p class="margin-top-1 margin-bottom-1">
|
||||||
|
<b class="review__step__name">No creator found:</b> this is an error, please email <a href="mailto:help@get.gov" class="usa-link">help@get.gov</a>.
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% with statuses=DomainRequest.DomainRequestStatus last_submitted=DomainRequest.last_submitted_date|date:"F j, Y" first_submitted=DomainRequest.first_submitted_date|date:"F j, Y" last_status_update=DomainRequest.last_status_update|date:"F j, Y" %}
|
||||||
|
{% comment %}
|
||||||
|
These are intentionally seperated this way.
|
||||||
|
There is some code repetition, but it gives us more flexibility rather than a dense reduction.
|
||||||
|
Leave it this way until we've solidified our requirements.
|
||||||
|
{% endcomment %}
|
||||||
|
{% if DomainRequest.status == statuses.STARTED %}
|
||||||
|
{% with first_started_date=DomainRequest.get_first_status_started_date|date:"F j, Y" %}
|
||||||
|
<p class="margin-top-1">
|
||||||
|
{% comment %}
|
||||||
|
A newly created domain request will not have a value for last_status update.
|
||||||
|
This is because the status never really updated.
|
||||||
|
However, if this somehow goes back to started we can default to displaying that new date.
|
||||||
|
{% endcomment %}
|
||||||
|
<b class="review__step__name">Started on:</b> {{last_status_update|default:first_started_date}}
|
||||||
|
</p>
|
||||||
|
{% endwith %}
|
||||||
|
{% elif DomainRequest.status == statuses.SUBMITTED %}
|
||||||
|
<p class="margin-top-1 margin-bottom-1">
|
||||||
|
<b class="review__step__name">Submitted on:</b> {{last_submitted|default:first_submitted }}
|
||||||
|
</p>
|
||||||
|
<p class="margin-top-1">
|
||||||
|
<b class="review__step__name">Last updated on:</b> {{DomainRequest.updated_at|date:"F j, Y"}}
|
||||||
|
</p>
|
||||||
|
{% elif DomainRequest.status == statuses.ACTION_NEEDED %}
|
||||||
|
<p class="margin-top-1 margin-bottom-1">
|
||||||
|
<b class="review__step__name">Submitted on:</b> {{last_submitted|default:first_submitted }}
|
||||||
|
</p>
|
||||||
|
<p class="margin-top-1">
|
||||||
|
<b class="review__step__name">Last updated on:</b> {{DomainRequest.updated_at|date:"F j, Y"}}
|
||||||
|
</p>
|
||||||
|
{% elif DomainRequest.status == statuses.REJECTED %}
|
||||||
|
<p class="margin-top-1 margin-bottom-1">
|
||||||
|
<b class="review__step__name">Submitted on:</b> {{last_submitted|default:first_submitted }}
|
||||||
|
</p>
|
||||||
|
<p class="margin-top-1">
|
||||||
|
<b class="review__step__name">Rejected on:</b> {{last_status_update}}
|
||||||
|
</p>
|
||||||
|
{% elif DomainRequest.status == statuses.WITHDRAWN %}
|
||||||
|
<p class="margin-top-1 margin-bottom-1">
|
||||||
|
<b class="review__step__name">Submitted on:</b> {{last_submitted|default:first_submitted }}
|
||||||
|
</p>
|
||||||
|
<p class="margin-top-1">
|
||||||
|
<b class="review__step__name">Withdrawn on:</b> {{last_status_update}}
|
||||||
|
</p>
|
||||||
|
{% else %}
|
||||||
|
{% comment %} Shown for in_review, approved, ineligible {% endcomment %}
|
||||||
|
<p class="margin-top-1">
|
||||||
|
<b class="review__step__name">Last updated on:</b> {{DomainRequest.updated_at|date:"F j, Y"}}
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
{% endwith %}
|
||||||
|
{% endblock status_metadata %}
|
||||||
|
|
||||||
|
{% block status_blurb %}
|
||||||
|
{% if DomainRequest.is_awaiting_review %}
|
||||||
|
<p>{% include "includes/domain_request_awaiting_review.html" with show_withdraw_text=DomainRequest.is_withdrawable %}</p>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock status_blurb %}
|
||||||
|
|
||||||
|
{% block modify_request %}
|
||||||
|
{% if DomainRequest.is_withdrawable %}
|
||||||
|
<p><a href="{% url 'domain-request-withdraw-confirmation' pk=DomainRequest.id %}" class="usa-button usa-button--outline withdraw_outline">
|
||||||
|
Withdraw request</a>
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock modify_request %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid-col desktop:grid-offset-2 maxw-tablet">
|
||||||
|
{% block request_summary_header %}
|
||||||
|
<h2 class="text-primary-darker"> Summary of your domain request </h2>
|
||||||
|
{% endblock request_summary_header%}
|
||||||
|
|
||||||
|
{% block request_summary %}
|
||||||
|
{% with heading_level='h3' %}
|
||||||
|
{% with org_type=DomainRequest.get_generic_org_type_display %}
|
||||||
|
{% include "includes/summary_item.html" with title='Type of organization' value=org_type heading_level=heading_level %}
|
||||||
|
{% endwith %}
|
||||||
|
|
||||||
|
{% if DomainRequest.tribe_name %}
|
||||||
|
{% include "includes/summary_item.html" with title='Tribal government' value=DomainRequest.tribe_name heading_level=heading_level %}
|
||||||
|
|
||||||
|
{% if DomainRequest.federally_recognized_tribe %}
|
||||||
|
<p>Federally-recognized tribe</p>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if DomainRequest.state_recognized_tribe %}
|
||||||
|
<p>State-recognized tribe</p>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if DomainRequest.get_federal_type_display %}
|
||||||
|
{% include "includes/summary_item.html" with title='Federal government branch' value=DomainRequest.get_federal_type_display heading_level=heading_level %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if DomainRequest.is_election_board %}
|
||||||
|
{% with value=DomainRequest.is_election_board|yesno:"Yes,No,Incomplete" %}
|
||||||
|
{% include "includes/summary_item.html" with title='Election office' value=value heading_level=heading_level %}
|
||||||
|
{% endwith %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if DomainRequest.organization_name %}
|
||||||
|
{% include "includes/summary_item.html" with title='Organization' value=DomainRequest address='true' heading_level=heading_level %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if DomainRequest.about_your_organization %}
|
||||||
|
{% include "includes/summary_item.html" with title='About your organization' value=DomainRequest.about_your_organization heading_level=heading_level %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if DomainRequest.senior_official %}
|
||||||
|
{% include "includes/summary_item.html" with title='Senior official' value=DomainRequest.senior_official contact='true' heading_level=heading_level %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if DomainRequest.current_websites.all %}
|
||||||
|
{% include "includes/summary_item.html" with title='Current websites' value=DomainRequest.current_websites.all list='true' heading_level=heading_level %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if DomainRequest.requested_domain %}
|
||||||
|
{% include "includes/summary_item.html" with title='.gov domain' value=DomainRequest.requested_domain heading_level=heading_level %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if DomainRequest.alternative_domains.all %}
|
||||||
|
{% include "includes/summary_item.html" with title='Alternative domains' value=DomainRequest.alternative_domains.all list='true' heading_level=heading_level %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if DomainRequest.purpose %}
|
||||||
|
{% include "includes/summary_item.html" with title='Purpose of your domain' value=DomainRequest.purpose heading_level=heading_level %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if DomainRequest.creator %}
|
||||||
|
{% include "includes/summary_item.html" with title='Your contact information' value=DomainRequest.creator contact='true' heading_level=heading_level %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if DomainRequest.other_contacts.all %}
|
||||||
|
{% include "includes/summary_item.html" with title='Other employees from your organization' value=DomainRequest.other_contacts.all contact='true' list='true' heading_level=heading_level %}
|
||||||
|
{% else %}
|
||||||
|
{% include "includes/summary_item.html" with title='Other employees from your organization' value=DomainRequest.no_other_contacts_rationale heading_level=heading_level %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{# We always show this field even if None #}
|
||||||
|
{% if DomainRequest %}
|
||||||
|
<h3 class="register-form-review-header">CISA Regional Representative</h3>
|
||||||
|
<ul class="usa-list usa-list--unstyled margin-top-0">
|
||||||
|
{% if DomainRequest.cisa_representative_first_name %}
|
||||||
|
{{ DomainRequest.get_formatted_cisa_rep_name }}
|
||||||
|
{% else %}
|
||||||
|
No
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
<h3 class="register-form-review-header">Anything else</h3>
|
||||||
|
<ul class="usa-list usa-list--unstyled margin-top-0">
|
||||||
|
{% if DomainRequest.anything_else %}
|
||||||
|
{{DomainRequest.anything_else}}
|
||||||
|
{% else %}
|
||||||
|
No
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
{% endwith %}
|
||||||
|
{% endblock request_summary%}
|
||||||
|
</div>
|
||||||
|
</main>
|
|
@ -16,15 +16,7 @@
|
||||||
|
|
||||||
{% if can_edit %}
|
{% if can_edit %}
|
||||||
{% include "includes/required_fields.html" %}
|
{% include "includes/required_fields.html" %}
|
||||||
{% else %}
|
<form class="usa-form usa-form--large desktop:margin-top-4" method="post" novalidate id="form-container">
|
||||||
<p>
|
|
||||||
The senior official for your organization can’t be updated here.
|
|
||||||
To suggest an update, email <a href="mailto:help@get.gov" class="usa-link">help@get.gov</a>.
|
|
||||||
</p>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if can_edit %}
|
|
||||||
<form class="usa-form usa-form--large" method="post" novalidate id="form-container">
|
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{% input_with_errors form.first_name %}
|
{% input_with_errors form.first_name %}
|
||||||
{% input_with_errors form.last_name %}
|
{% input_with_errors form.last_name %}
|
||||||
|
@ -33,8 +25,16 @@
|
||||||
<button type="submit" class="usa-button">Save</button>
|
<button type="submit" class="usa-button">Save</button>
|
||||||
</form>
|
</form>
|
||||||
{% elif not form.full_name.value and not form.title.value and not form.email.value %}
|
{% elif not form.full_name.value and not form.title.value and not form.email.value %}
|
||||||
<h4>No senior official was found.</h4>
|
<p>
|
||||||
|
Your senior official is a person within your organization who can authorize domain requests.
|
||||||
|
We don't have information about your organization's senior official. To suggest an update, email <a href="mailto:help@get.gov" class="usa-link">help@get.gov</a>.
|
||||||
|
</p>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
<p>
|
||||||
|
The senior official for your organization can’t be updated here.
|
||||||
|
To suggest an update, email <a href="mailto:help@get.gov" class="usa-link">help@get.gov</a>.
|
||||||
|
</p>
|
||||||
|
<div class="desktop:margin-top-4">
|
||||||
{% if form.full_name.value is not None %}
|
{% if form.full_name.value is not None %}
|
||||||
{% include "includes/input_read_only.html" with field=form.full_name %}
|
{% include "includes/input_read_only.html" with field=form.full_name %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -46,4 +46,5 @@
|
||||||
{% if form.email.value is not None %}
|
{% if form.email.value is not None %}
|
||||||
{% include "includes/input_read_only.html" with field=form.email %}
|
{% include "includes/input_read_only.html" with field=form.email %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -35,7 +35,14 @@
|
||||||
<dl class="usa-list usa-list--unstyled margin-top-0">
|
<dl class="usa-list usa-list--unstyled margin-top-0">
|
||||||
{% for item in value %}
|
{% for item in value %}
|
||||||
<dt>
|
<dt>
|
||||||
|
|
||||||
|
<h4 class="summary-item__title
|
||||||
|
font-sans-md
|
||||||
|
text-primary-dark text-semibold
|
||||||
|
margin-bottom-05
|
||||||
|
padding-right-1">
|
||||||
Contact {{forloop.counter}}
|
Contact {{forloop.counter}}
|
||||||
|
</h4>
|
||||||
</dt>
|
</dt>
|
||||||
<dd>
|
<dd>
|
||||||
{% include "includes/contact.html" with contact=item %}
|
{% include "includes/contact.html" with contact=item %}
|
||||||
|
|
|
@ -4,11 +4,11 @@
|
||||||
<div id="wrapper" class="{% block wrapper_class %}dashboard--portfolio{% endblock %}">
|
<div id="wrapper" class="{% block wrapper_class %}dashboard--portfolio{% endblock %}">
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<main class="grid-container">
|
<main class="grid-container {% if is_widescreen_mode %} grid-container--widescreen {% endif %}">
|
||||||
{% if user.is_authenticated %}
|
{% if user.is_authenticated %}
|
||||||
{# the entire logged in page goes here #}
|
{# the entire logged in page goes here #}
|
||||||
|
|
||||||
<div class="tablet:grid-col-12">
|
<div class="tablet:grid-col-11 desktop:grid-col-10 tablet:grid-offset-1">
|
||||||
{% block messages %}
|
{% block messages %}
|
||||||
{% include "includes/form_messages.html" %}
|
{% include "includes/form_messages.html" %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load custom_filters %}
|
||||||
|
{% load static url_helpers %}
|
||||||
|
|
||||||
|
{% block title %}Domain request status | {{ DomainRequest.requested_domain.name }} | {% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{% include "includes/portfolio_request_status_view.html" %}
|
||||||
|
{% endblock %}
|
|
@ -9,6 +9,10 @@
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block portfolio_content %}
|
{% block portfolio_content %}
|
||||||
|
{% block messages %}
|
||||||
|
{% include "includes/form_messages.html" %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
<div id="main-content">
|
<div id="main-content">
|
||||||
<h1 id="domains-header">Domains</h1>
|
<h1 id="domains-header">Domains</h1>
|
||||||
{% include "includes/domains_table.html" with portfolio=portfolio user_domain_count=user_domain_count %}
|
{% include "includes/domains_table.html" with portfolio=portfolio user_domain_count=user_domain_count %}
|
||||||
|
|
|
@ -5,6 +5,12 @@
|
||||||
{% block title %} Domains | {% endblock %}
|
{% block title %} Domains | {% endblock %}
|
||||||
|
|
||||||
{% block portfolio_content %}
|
{% block portfolio_content %}
|
||||||
|
|
||||||
|
{% block messages %}
|
||||||
|
{% include "includes/form_messages.html" %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
<div id="main-content">
|
<div id="main-content">
|
||||||
<h1 id="domains-header">Domains</h1>
|
<h1 id="domains-header">Domains</h1>
|
||||||
<section class="section-outlined">
|
<section class="section-outlined">
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{% extends 'portfolio_base.html' %}
|
{% extends 'portfolio_base.html' %}
|
||||||
{% load static field_helpers%}
|
{% load static field_helpers%}
|
||||||
|
|
||||||
{% block title %}Organization mailing address | {{ portfolio.name }}{% endblock %}
|
{% block title %}Organization name and mailing address | {{ portfolio.name }}{% endblock %}
|
||||||
|
|
||||||
{% load static %}
|
{% load static %}
|
||||||
|
|
||||||
|
@ -19,21 +19,25 @@
|
||||||
|
|
||||||
<div class="tablet:grid-col-9" id="main-content">
|
<div class="tablet:grid-col-9" id="main-content">
|
||||||
|
|
||||||
|
{% block messages %}
|
||||||
|
{% include "includes/form_messages.html" %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
<h1>Organization</h1>
|
<h1>Organization</h1>
|
||||||
|
|
||||||
<p>The name of your federal agency will be publicly listed as the domain registrant.</p>
|
<p>The name of your organization will be publicly listed as the domain registrant.</p>
|
||||||
|
|
||||||
{% if has_edit_org_portfolio_permission %}
|
{% if has_edit_org_portfolio_permission %}
|
||||||
<p>
|
<p>
|
||||||
The federal agency for your organization can’t be updated here.
|
Your organization name can’t be updated here.
|
||||||
To suggest an update, email <a href="mailto:help@get.gov" class="usa-link">help@get.gov</a>.
|
To suggest an update, email <a href="mailto:help@get.gov" class="usa-link">help@get.gov</a>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
{% include "includes/form_errors.html" with form=form %}
|
{% include "includes/form_errors.html" with form=form %}
|
||||||
{% include "includes/required_fields.html" %}
|
{% include "includes/required_fields.html" %}
|
||||||
<form class="usa-form usa-form--large" method="post" novalidate>
|
<form class="usa-form usa-form--large desktop:margin-top-4" method="post" novalidate>
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<h4 class="read-only-label">Federal agency</h4>
|
<h4 class="read-only-label">Organization name</h4>
|
||||||
<p class="read-only-value">
|
<p class="read-only-value">
|
||||||
{{ portfolio.federal_agency }}
|
{{ portfolio.federal_agency }}
|
||||||
</p>
|
</p>
|
||||||
|
@ -49,7 +53,7 @@
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
{% else %}
|
{% else %}
|
||||||
<h4 class="read-only-label">Federal agency</h4>
|
<h4 class="read-only-label">Organization name</h4>
|
||||||
<p class="read-only-value">
|
<p class="read-only-value">
|
||||||
{{ portfolio.federal_agency }}
|
{{ portfolio.federal_agency }}
|
||||||
</p>
|
</p>
|
||||||
|
|
|
@ -9,6 +9,10 @@
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block portfolio_content %}
|
{% block portfolio_content %}
|
||||||
|
{% block messages %}
|
||||||
|
{% include "includes/form_messages.html" %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
<div id="main-content">
|
<div id="main-content">
|
||||||
<h1 id="domain-requests-header">Domain requests</h1>
|
<h1 id="domain-requests-header">Domain requests</h1>
|
||||||
<div class="grid-row grid-gap">
|
<div class="grid-row grid-gap">
|
||||||
|
|
|
@ -6,6 +6,10 @@
|
||||||
{% load static %}
|
{% load static %}
|
||||||
|
|
||||||
{% block portfolio_content %}
|
{% block portfolio_content %}
|
||||||
|
{% block messages %}
|
||||||
|
{% include "includes/form_messages.html" %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
<div class="grid-row grid-gap">
|
<div class="grid-row grid-gap">
|
||||||
<div class="tablet:grid-col-3">
|
<div class="tablet:grid-col-3">
|
||||||
<p class="font-body-md margin-top-0 margin-bottom-2
|
<p class="font-body-md margin-top-0 margin-bottom-2
|
||||||
|
|
|
@ -3,6 +3,9 @@ from django import template
|
||||||
import re
|
import re
|
||||||
from registrar.models.domain_request import DomainRequest
|
from registrar.models.domain_request import DomainRequest
|
||||||
from phonenumber_field.phonenumber import PhoneNumber
|
from phonenumber_field.phonenumber import PhoneNumber
|
||||||
|
from registrar.views.domain_request import DomainRequestWizard
|
||||||
|
|
||||||
|
from registrar.models.utility.generic_helper import get_url_name
|
||||||
|
|
||||||
register = template.Library()
|
register = template.Library()
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
@ -174,3 +177,65 @@ def has_contact_info(user):
|
||||||
@register.filter
|
@register.filter
|
||||||
def model_name_lowercase(instance):
|
def model_name_lowercase(instance):
|
||||||
return instance.__class__.__name__.lower()
|
return instance.__class__.__name__.lower()
|
||||||
|
|
||||||
|
|
||||||
|
@register.filter(name="is_domain_subpage")
|
||||||
|
def is_domain_subpage(path):
|
||||||
|
"""Checks if the given page is a subpage of domains.
|
||||||
|
Takes a path name, like '/domains/'."""
|
||||||
|
# Since our pages aren't unified under a common path, we need this approach for now.
|
||||||
|
url_names = [
|
||||||
|
"domains",
|
||||||
|
"no-portfolio-domains",
|
||||||
|
"domain",
|
||||||
|
"domain-users",
|
||||||
|
"domain-dns",
|
||||||
|
"domain-dns-nameservers",
|
||||||
|
"domain-dns-dnssec",
|
||||||
|
"domain-dns-dnssec-dsdata",
|
||||||
|
"domain-your-contact-information",
|
||||||
|
"domain-org-name-address",
|
||||||
|
"domain-senior-official",
|
||||||
|
"domain-security-email",
|
||||||
|
"domain-users-add",
|
||||||
|
"domain-request-delete",
|
||||||
|
"domain-user-delete",
|
||||||
|
"invitation-delete",
|
||||||
|
]
|
||||||
|
return get_url_name(path) in url_names
|
||||||
|
|
||||||
|
|
||||||
|
@register.filter(name="is_domain_request_subpage")
|
||||||
|
def is_domain_request_subpage(path):
|
||||||
|
"""Checks if the given page is a subpage of domain requests.
|
||||||
|
Takes a path name, like '/requests/'."""
|
||||||
|
# Since our pages aren't unified under a common path, we need this approach for now.
|
||||||
|
url_names = [
|
||||||
|
"domain-requests",
|
||||||
|
"no-portfolio-requests",
|
||||||
|
"domain-request-status",
|
||||||
|
"domain-request-withdraw-confirmation",
|
||||||
|
"domain-request-withdrawn",
|
||||||
|
"domain-request-delete",
|
||||||
|
]
|
||||||
|
|
||||||
|
# The domain request wizard pages don't have a defined path,
|
||||||
|
# so we need to check directly on it.
|
||||||
|
wizard_paths = [
|
||||||
|
DomainRequestWizard.EDIT_URL_NAME,
|
||||||
|
DomainRequestWizard.URL_NAMESPACE,
|
||||||
|
DomainRequestWizard.NEW_URL_NAME,
|
||||||
|
]
|
||||||
|
return get_url_name(path) in url_names or any(wizard in path for wizard in wizard_paths)
|
||||||
|
|
||||||
|
|
||||||
|
@register.filter(name="is_portfolio_subpage")
|
||||||
|
def is_portfolio_subpage(path):
|
||||||
|
"""Checks if the given page is a subpage of portfolio.
|
||||||
|
Takes a path name, like '/organization/'."""
|
||||||
|
# Since our pages aren't unified under a common path, we need this approach for now.
|
||||||
|
url_names = [
|
||||||
|
"organization",
|
||||||
|
"senior-official",
|
||||||
|
]
|
||||||
|
return get_url_name(path) in url_names
|
||||||
|
|
|
@ -535,8 +535,10 @@ class MockDb(TestCase):
|
||||||
first_name = "First"
|
first_name = "First"
|
||||||
last_name = "Last"
|
last_name = "Last"
|
||||||
email = "info@example.com"
|
email = "info@example.com"
|
||||||
|
title = "title"
|
||||||
|
phone = "8080102431"
|
||||||
cls.user = get_user_model().objects.create(
|
cls.user = get_user_model().objects.create(
|
||||||
username=username, first_name=first_name, last_name=last_name, email=email
|
username=username, first_name=first_name, last_name=last_name, email=email, title=title, phone=phone
|
||||||
)
|
)
|
||||||
|
|
||||||
current_date = get_time_aware_date(datetime(2024, 4, 2))
|
current_date = get_time_aware_date(datetime(2024, 4, 2))
|
||||||
|
@ -845,6 +847,7 @@ def create_superuser():
|
||||||
last_name="last",
|
last_name="last",
|
||||||
is_staff=True,
|
is_staff=True,
|
||||||
password=p,
|
password=p,
|
||||||
|
phone="8003111234",
|
||||||
)
|
)
|
||||||
# Retrieve the group or create it if it doesn't exist
|
# Retrieve the group or create it if it doesn't exist
|
||||||
group, _ = UserGroup.objects.get_or_create(name="full_access_group")
|
group, _ = UserGroup.objects.get_or_create(name="full_access_group")
|
||||||
|
@ -862,7 +865,9 @@ def create_user():
|
||||||
first_name="first",
|
first_name="first",
|
||||||
last_name="last",
|
last_name="last",
|
||||||
is_staff=True,
|
is_staff=True,
|
||||||
|
title="title",
|
||||||
password=p,
|
password=p,
|
||||||
|
phone="8003111234",
|
||||||
)
|
)
|
||||||
# Retrieve the group or create it if it doesn't exist
|
# Retrieve the group or create it if it doesn't exist
|
||||||
group, _ = UserGroup.objects.get_or_create(name="cisa_analysts_group")
|
group, _ = UserGroup.objects.get_or_create(name="cisa_analysts_group")
|
||||||
|
@ -879,7 +884,12 @@ def create_test_user():
|
||||||
phone = "8003111234"
|
phone = "8003111234"
|
||||||
title = "test title"
|
title = "test title"
|
||||||
user = get_user_model().objects.create(
|
user = get_user_model().objects.create(
|
||||||
username=username, first_name=first_name, last_name=last_name, email=email, phone=phone, title=title
|
username=username,
|
||||||
|
first_name=first_name,
|
||||||
|
last_name=last_name,
|
||||||
|
email=email,
|
||||||
|
phone=phone,
|
||||||
|
title=title,
|
||||||
)
|
)
|
||||||
return user
|
return user
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,6 @@ from .common import (
|
||||||
GenericTestHelper,
|
GenericTestHelper,
|
||||||
)
|
)
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
from waffle.testutils import override_flag
|
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
import boto3_mocking # type: ignore
|
import boto3_mocking # type: ignore
|
||||||
|
@ -957,7 +956,6 @@ class TestDomainRequestAdmin(MockEppLib):
|
||||||
self.transition_state_and_send_email(domain_request, DomainRequest.DomainRequestStatus.SUBMITTED)
|
self.transition_state_and_send_email(domain_request, DomainRequest.DomainRequestStatus.SUBMITTED)
|
||||||
self.assertEqual(len(self.mock_client.EMAILS_SENT), 3)
|
self.assertEqual(len(self.mock_client.EMAILS_SENT), 3)
|
||||||
|
|
||||||
@override_flag("profile_feature", True)
|
|
||||||
@less_console_noise_decorator
|
@less_console_noise_decorator
|
||||||
def test_save_model_sends_approved_email(self):
|
def test_save_model_sends_approved_email(self):
|
||||||
"""When transitioning to approved on a domain request,
|
"""When transitioning to approved on a domain request,
|
||||||
|
|
|
@ -114,6 +114,54 @@ class TestDomainRequest(TestCase):
|
||||||
with less_console_noise():
|
with less_console_noise():
|
||||||
return self.assertRaises(Exception, None, exception_type)
|
return self.assertRaises(Exception, None, exception_type)
|
||||||
|
|
||||||
|
@less_console_noise_decorator
|
||||||
|
def test_request_is_withdrawable(self):
|
||||||
|
"""Tests the is_withdrawable function"""
|
||||||
|
domain_request_1 = completed_domain_request(
|
||||||
|
status=DomainRequest.DomainRequestStatus.SUBMITTED,
|
||||||
|
name="city2.gov",
|
||||||
|
)
|
||||||
|
domain_request_2 = completed_domain_request(
|
||||||
|
status=DomainRequest.DomainRequestStatus.IN_REVIEW,
|
||||||
|
name="city3.gov",
|
||||||
|
)
|
||||||
|
domain_request_3 = completed_domain_request(
|
||||||
|
status=DomainRequest.DomainRequestStatus.ACTION_NEEDED,
|
||||||
|
name="city4.gov",
|
||||||
|
)
|
||||||
|
domain_request_4 = completed_domain_request(
|
||||||
|
status=DomainRequest.DomainRequestStatus.REJECTED,
|
||||||
|
name="city5.gov",
|
||||||
|
)
|
||||||
|
self.assertTrue(domain_request_1.is_withdrawable())
|
||||||
|
self.assertTrue(domain_request_2.is_withdrawable())
|
||||||
|
self.assertTrue(domain_request_3.is_withdrawable())
|
||||||
|
self.assertFalse(domain_request_4.is_withdrawable())
|
||||||
|
|
||||||
|
@less_console_noise_decorator
|
||||||
|
def test_request_is_awaiting_review(self):
|
||||||
|
"""Tests the is_awaiting_review function"""
|
||||||
|
domain_request_1 = completed_domain_request(
|
||||||
|
status=DomainRequest.DomainRequestStatus.SUBMITTED,
|
||||||
|
name="city2.gov",
|
||||||
|
)
|
||||||
|
domain_request_2 = completed_domain_request(
|
||||||
|
status=DomainRequest.DomainRequestStatus.IN_REVIEW,
|
||||||
|
name="city3.gov",
|
||||||
|
)
|
||||||
|
domain_request_3 = completed_domain_request(
|
||||||
|
status=DomainRequest.DomainRequestStatus.ACTION_NEEDED,
|
||||||
|
name="city4.gov",
|
||||||
|
)
|
||||||
|
domain_request_4 = completed_domain_request(
|
||||||
|
status=DomainRequest.DomainRequestStatus.REJECTED,
|
||||||
|
name="city5.gov",
|
||||||
|
)
|
||||||
|
self.assertTrue(domain_request_1.is_awaiting_review())
|
||||||
|
self.assertTrue(domain_request_2.is_awaiting_review())
|
||||||
|
self.assertFalse(domain_request_3.is_awaiting_review())
|
||||||
|
self.assertFalse(domain_request_4.is_awaiting_review())
|
||||||
|
|
||||||
@less_console_noise_decorator
|
@less_console_noise_decorator
|
||||||
def test_federal_agency_set_to_non_federal_on_approve(self):
|
def test_federal_agency_set_to_non_federal_on_approve(self):
|
||||||
"""Ensures that when the federal_agency field is 'none' when .approve() is called,
|
"""Ensures that when the federal_agency field is 'none' when .approve() is called,
|
||||||
|
@ -256,19 +304,9 @@ class TestDomainRequest(TestCase):
|
||||||
|
|
||||||
email_allowed.delete()
|
email_allowed.delete()
|
||||||
|
|
||||||
@override_flag("profile_feature", active=False)
|
|
||||||
@less_console_noise_decorator
|
|
||||||
def test_submit_from_started_sends_email(self):
|
|
||||||
msg = "Create a domain request and submit it and see if email was sent."
|
|
||||||
domain_request = completed_domain_request(user=self.dummy_user_2)
|
|
||||||
self.check_email_sent(
|
|
||||||
domain_request, msg, "submit", 1, expected_content="Lava", expected_email=self.dummy_user_2.email
|
|
||||||
)
|
|
||||||
|
|
||||||
@override_flag("profile_feature", active=True)
|
|
||||||
@less_console_noise_decorator
|
@less_console_noise_decorator
|
||||||
def test_submit_from_started_sends_email_to_creator(self):
|
def test_submit_from_started_sends_email_to_creator(self):
|
||||||
"""Tests if, when the profile feature flag is on, we send an email to the creator"""
|
"""tests that we send an email to the creator"""
|
||||||
msg = "Create a domain request and submit it and see if email was sent when the feature flag is on."
|
msg = "Create a domain request and submit it and see if email was sent when the feature flag is on."
|
||||||
domain_request = completed_domain_request(user=self.dummy_user_2)
|
domain_request = completed_domain_request(user=self.dummy_user_2)
|
||||||
self.check_email_sent(
|
self.check_email_sent(
|
||||||
|
|
|
@ -9,6 +9,9 @@ from registrar.templatetags.custom_filters import (
|
||||||
find_index,
|
find_index,
|
||||||
slice_after,
|
slice_after,
|
||||||
contains_checkbox,
|
contains_checkbox,
|
||||||
|
is_domain_request_subpage,
|
||||||
|
is_domain_subpage,
|
||||||
|
is_portfolio_subpage,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -90,3 +93,18 @@ class CustomFiltersTestCase(TestCase):
|
||||||
]
|
]
|
||||||
result = contains_checkbox(html_list)
|
result = contains_checkbox(html_list)
|
||||||
self.assertFalse(result) # Expecting False
|
self.assertFalse(result) # Expecting False
|
||||||
|
|
||||||
|
def test_is_domain_subpage(self):
|
||||||
|
"""Tests if the path is recognized as a domain subpage."""
|
||||||
|
self.assertTrue(is_domain_subpage("/domains/"))
|
||||||
|
self.assertFalse(is_domain_subpage("/"))
|
||||||
|
|
||||||
|
def test_is_domain_request_subpage(self):
|
||||||
|
"""Tests if the path is recognized as a domain request subpage."""
|
||||||
|
self.assertTrue(is_domain_request_subpage("/requests/"))
|
||||||
|
self.assertFalse(is_domain_request_subpage("/"))
|
||||||
|
|
||||||
|
def test_is_portfolio_subpage(self):
|
||||||
|
"""Tests if the path is recognized as a portfolio subpage."""
|
||||||
|
self.assertTrue(is_portfolio_subpage("/organization/"))
|
||||||
|
self.assertFalse(is_portfolio_subpage("/"))
|
||||||
|
|
23
src/registrar/tests/test_utilities.py
Normal file
23
src/registrar/tests/test_utilities.py
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
from django.test import TestCase
|
||||||
|
from registrar.models import User
|
||||||
|
from waffle.testutils import override_flag
|
||||||
|
from registrar.utility.waffle import flag_is_active_for_user
|
||||||
|
|
||||||
|
|
||||||
|
class FlagIsActiveForUserTest(TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
# Set up a test user
|
||||||
|
self.user = User.objects.create_user(username="testuser")
|
||||||
|
|
||||||
|
@override_flag("test_flag", active=True)
|
||||||
|
def test_flag_active_for_user(self):
|
||||||
|
# Test that the flag is active for the user
|
||||||
|
is_active = flag_is_active_for_user(self.user, "test_flag")
|
||||||
|
self.assertTrue(is_active)
|
||||||
|
|
||||||
|
@override_flag("test_flag", active=False)
|
||||||
|
def test_flag_inactive_for_user(self):
|
||||||
|
# Test that the flag is inactive for the user
|
||||||
|
is_active = flag_is_active_for_user(self.user, "test_flag")
|
||||||
|
self.assertFalse(is_active)
|
|
@ -494,7 +494,13 @@ class HomeTests(TestWithUser):
|
||||||
phone = "8003111234"
|
phone = "8003111234"
|
||||||
status = User.RESTRICTED
|
status = User.RESTRICTED
|
||||||
restricted_user = get_user_model().objects.create(
|
restricted_user = get_user_model().objects.create(
|
||||||
username=username, first_name=first_name, last_name=last_name, email=email, phone=phone, status=status
|
username=username,
|
||||||
|
first_name=first_name,
|
||||||
|
last_name=last_name,
|
||||||
|
email=email,
|
||||||
|
phone=phone,
|
||||||
|
status=status,
|
||||||
|
title="title",
|
||||||
)
|
)
|
||||||
self.client.force_login(restricted_user)
|
self.client.force_login(restricted_user)
|
||||||
response = self.client.get("/request/", follow=True)
|
response = self.client.get("/request/", follow=True)
|
||||||
|
@ -546,7 +552,6 @@ class FinishUserProfileTests(TestWithUser, WebTest):
|
||||||
return page.follow() if follow else page
|
return page.follow() if follow else page
|
||||||
|
|
||||||
@less_console_noise_decorator
|
@less_console_noise_decorator
|
||||||
@override_flag("profile_feature", active=True)
|
|
||||||
def test_full_name_initial_value(self):
|
def test_full_name_initial_value(self):
|
||||||
"""Test that full_name initial value is empty when first_name or last_name is empty.
|
"""Test that full_name initial value is empty when first_name or last_name is empty.
|
||||||
This will later be displayed as "unknown" using javascript."""
|
This will later be displayed as "unknown" using javascript."""
|
||||||
|
@ -600,8 +605,8 @@ class FinishUserProfileTests(TestWithUser, WebTest):
|
||||||
incomplete_regular_user.delete()
|
incomplete_regular_user.delete()
|
||||||
|
|
||||||
@less_console_noise_decorator
|
@less_console_noise_decorator
|
||||||
def test_new_user_with_profile_feature_on(self):
|
def test_new_user(self):
|
||||||
"""Tests that a new user is redirected to the profile setup page when profile_feature is on"""
|
"""Tests that a new user is redirected to the profile setup page"""
|
||||||
username_regular_incomplete = "test_regular_user_incomplete"
|
username_regular_incomplete = "test_regular_user_incomplete"
|
||||||
first_name_2 = "Incomplete"
|
first_name_2 = "Incomplete"
|
||||||
email_2 = "unicorn@igorville.com"
|
email_2 = "unicorn@igorville.com"
|
||||||
|
@ -614,12 +619,10 @@ class FinishUserProfileTests(TestWithUser, WebTest):
|
||||||
)
|
)
|
||||||
|
|
||||||
self.app.set_user(incomplete_regular_user.username)
|
self.app.set_user(incomplete_regular_user.username)
|
||||||
with override_flag("profile_feature", active=True):
|
|
||||||
# This will redirect the user to the setup page.
|
# This will redirect the user to the setup page.
|
||||||
# Follow implicity checks if our redirect is working.
|
# Follow implicity checks if our redirect is working.
|
||||||
finish_setup_page = self.app.get(reverse("home")).follow()
|
finish_setup_page = self.app.get(reverse("home")).follow()
|
||||||
self._set_session_cookie()
|
self._set_session_cookie()
|
||||||
|
|
||||||
# Assert that we're on the right page
|
# Assert that we're on the right page
|
||||||
self.assertContains(finish_setup_page, "Finish setting up your profile")
|
self.assertContains(finish_setup_page, "Finish setting up your profile")
|
||||||
|
|
||||||
|
@ -663,7 +666,6 @@ class FinishUserProfileTests(TestWithUser, WebTest):
|
||||||
verification_type=User.VerificationTypeChoices.REGULAR,
|
verification_type=User.VerificationTypeChoices.REGULAR,
|
||||||
)
|
)
|
||||||
self.app.set_user(incomplete_regular_user.username)
|
self.app.set_user(incomplete_regular_user.username)
|
||||||
with override_flag("profile_feature", active=True):
|
|
||||||
# This will redirect the user to the setup page.
|
# This will redirect the user to the setup page.
|
||||||
# Follow implicity checks if our redirect is working.
|
# Follow implicity checks if our redirect is working.
|
||||||
finish_setup_page = self.app.get(reverse("home")).follow()
|
finish_setup_page = self.app.get(reverse("home")).follow()
|
||||||
|
@ -701,8 +703,8 @@ class FinishUserProfileTests(TestWithUser, WebTest):
|
||||||
incomplete_regular_user.delete()
|
incomplete_regular_user.delete()
|
||||||
|
|
||||||
@less_console_noise_decorator
|
@less_console_noise_decorator
|
||||||
def test_new_user_goes_to_domain_request_with_profile_feature_on(self):
|
def test_new_user_goes_to_domain_request(self):
|
||||||
"""Tests that a new user is redirected to the domain request page when profile_feature is on"""
|
"""Tests that a new user is redirected to the domain request page"""
|
||||||
username_regular_incomplete = "test_regular_user_incomplete"
|
username_regular_incomplete = "test_regular_user_incomplete"
|
||||||
first_name_2 = "Incomplete"
|
first_name_2 = "Incomplete"
|
||||||
email_2 = "unicorn@igorville.com"
|
email_2 = "unicorn@igorville.com"
|
||||||
|
@ -714,7 +716,7 @@ class FinishUserProfileTests(TestWithUser, WebTest):
|
||||||
verification_type=User.VerificationTypeChoices.REGULAR,
|
verification_type=User.VerificationTypeChoices.REGULAR,
|
||||||
)
|
)
|
||||||
self.app.set_user(incomplete_regular_user.username)
|
self.app.set_user(incomplete_regular_user.username)
|
||||||
with override_flag("profile_feature", active=True):
|
with override_flag("", active=True):
|
||||||
# This will redirect the user to the setup page
|
# This will redirect the user to the setup page
|
||||||
finish_setup_page = self.app.get(reverse("domain-request:")).follow()
|
finish_setup_page = self.app.get(reverse("domain-request:")).follow()
|
||||||
self._set_session_cookie()
|
self._set_session_cookie()
|
||||||
|
@ -758,25 +760,6 @@ class FinishUserProfileTests(TestWithUser, WebTest):
|
||||||
self.assertContains(completed_setup_page, "You’re about to start your .gov domain request")
|
self.assertContains(completed_setup_page, "You’re about to start your .gov domain request")
|
||||||
incomplete_regular_user.delete()
|
incomplete_regular_user.delete()
|
||||||
|
|
||||||
@less_console_noise_decorator
|
|
||||||
def test_new_user_with_profile_feature_off(self):
|
|
||||||
"""Tests that a new user is not redirected to the profile setup page when profile_feature is off"""
|
|
||||||
with override_flag("profile_feature", active=False):
|
|
||||||
response = self.client.get("/")
|
|
||||||
self.assertNotContains(response, "Finish setting up your profile")
|
|
||||||
|
|
||||||
@less_console_noise_decorator
|
|
||||||
def test_new_user_goes_to_domain_request_with_profile_feature_off(self):
|
|
||||||
"""Tests that a new user is redirected to the domain request page
|
|
||||||
when profile_feature is off but not the setup page"""
|
|
||||||
with override_flag("profile_feature", active=False):
|
|
||||||
response = self.client.get("/request/")
|
|
||||||
|
|
||||||
self.assertNotContains(response, "Finish setting up your profile")
|
|
||||||
self.assertNotContains(response, "What contact information should we use to reach you?")
|
|
||||||
|
|
||||||
self.assertContains(response, "You’re about to start your .gov domain request")
|
|
||||||
|
|
||||||
|
|
||||||
class FinishUserProfileForOtherUsersTests(TestWithUser, WebTest):
|
class FinishUserProfileForOtherUsersTests(TestWithUser, WebTest):
|
||||||
"""A series of tests that target the user profile page intercept for incomplete IAL1 user profiles."""
|
"""A series of tests that target the user profile page intercept for incomplete IAL1 user profiles."""
|
||||||
|
@ -816,8 +799,8 @@ class FinishUserProfileForOtherUsersTests(TestWithUser, WebTest):
|
||||||
return page.follow() if follow else page
|
return page.follow() if follow else page
|
||||||
|
|
||||||
@less_console_noise_decorator
|
@less_console_noise_decorator
|
||||||
def test_new_user_with_profile_feature_on(self):
|
def test_new_user(self):
|
||||||
"""Tests that a new user is redirected to the profile setup page when profile_feature is on,
|
"""Tests that a new user is redirected to the profile setup page,
|
||||||
and testing that the confirmation modal is present"""
|
and testing that the confirmation modal is present"""
|
||||||
username_other_incomplete = "test_other_user_incomplete"
|
username_other_incomplete = "test_other_user_incomplete"
|
||||||
first_name_2 = "Incomplete"
|
first_name_2 = "Incomplete"
|
||||||
|
@ -831,7 +814,6 @@ class FinishUserProfileForOtherUsersTests(TestWithUser, WebTest):
|
||||||
verification_type=User.VerificationTypeChoices.VERIFIED_BY_STAFF,
|
verification_type=User.VerificationTypeChoices.VERIFIED_BY_STAFF,
|
||||||
)
|
)
|
||||||
self.app.set_user(incomplete_other_user.username)
|
self.app.set_user(incomplete_other_user.username)
|
||||||
with override_flag("profile_feature", active=True):
|
|
||||||
# This will redirect the user to the user profile page.
|
# This will redirect the user to the user profile page.
|
||||||
# Follow implicity checks if our redirect is working.
|
# Follow implicity checks if our redirect is working.
|
||||||
user_profile_page = self.app.get(reverse("home")).follow()
|
user_profile_page = self.app.get(reverse("home")).follow()
|
||||||
|
@ -881,9 +863,7 @@ class FinishUserProfileForOtherUsersTests(TestWithUser, WebTest):
|
||||||
# NOTE: "anage" is not a typo. It is to accomodate the fact that the "m" is uppercase in one
|
# NOTE: "anage" is not a typo. It is to accomodate the fact that the "m" is uppercase in one
|
||||||
# instance and lowercase in the other.
|
# instance and lowercase in the other.
|
||||||
self.assertContains(save_page, "anage your domains", count=2)
|
self.assertContains(save_page, "anage your domains", count=2)
|
||||||
self.assertNotContains(
|
self.assertNotContains(save_page, "Before you can manage your domains, we need you to add contact information")
|
||||||
save_page, "Before you can manage your domains, we need you to add contact information"
|
|
||||||
)
|
|
||||||
# Assert that modal does not appear on subsequent submits
|
# Assert that modal does not appear on subsequent submits
|
||||||
self.assertNotContains(save_page, "domain registrants must maintain accurate contact information")
|
self.assertNotContains(save_page, "domain registrants must maintain accurate contact information")
|
||||||
|
|
||||||
|
@ -915,113 +895,59 @@ class UserProfileTests(TestWithUser, WebTest):
|
||||||
DomainInformation.objects.all().delete()
|
DomainInformation.objects.all().delete()
|
||||||
|
|
||||||
@less_console_noise_decorator
|
@less_console_noise_decorator
|
||||||
def error_500_main_nav_with_profile_feature_turned_on(self):
|
def error_500_main_nav(self):
|
||||||
"""test that Your profile is in main nav of 500 error page when profile_feature is on.
|
"""test that Your profile is in main nav of 500 error page.
|
||||||
|
|
||||||
Our treatment of 401 and 403 error page handling with that waffle feature is similar, so we
|
Our treatment of 401 and 403 error page handling with that waffle feature is similar, so we
|
||||||
assume that the same test results hold true for 401 and 403."""
|
assume that the same test results hold true for 401 and 403."""
|
||||||
with override_flag("profile_feature", active=True):
|
|
||||||
with self.assertRaises(Exception):
|
with self.assertRaises(Exception):
|
||||||
response = self.client.get(reverse("home"), follow=True)
|
response = self.client.get(reverse("home"), follow=True)
|
||||||
self.assertEqual(response.status_code, 500)
|
self.assertEqual(response.status_code, 500)
|
||||||
self.assertContains(response, "Your profile")
|
self.assertContains(response, "Your profile")
|
||||||
|
|
||||||
@less_console_noise_decorator
|
@less_console_noise_decorator
|
||||||
def error_500_main_nav_with_profile_feature_turned_off(self):
|
def test_home_page_main_nav(self):
|
||||||
"""test that Your profile is not in main nav of 500 error page when profile_feature is off.
|
"""test that Your profile is in main nav of home page"""
|
||||||
|
|
||||||
Our treatment of 401 and 403 error page handling with that waffle feature is similar, so we
|
|
||||||
assume that the same test results hold true for 401 and 403."""
|
|
||||||
with override_flag("profile_feature", active=False):
|
|
||||||
with self.assertRaises(Exception):
|
|
||||||
response = self.client.get(reverse("home"), follow=True)
|
|
||||||
self.assertEqual(response.status_code, 500)
|
|
||||||
self.assertNotContains(response, "Your profile")
|
|
||||||
|
|
||||||
@less_console_noise_decorator
|
|
||||||
def test_home_page_main_nav_with_profile_feature_on(self):
|
|
||||||
"""test that Your profile is in main nav of home page when profile_feature is on"""
|
|
||||||
with override_flag("profile_feature", active=True):
|
|
||||||
response = self.client.get("/", follow=True)
|
response = self.client.get("/", follow=True)
|
||||||
self.assertContains(response, "Your profile")
|
self.assertContains(response, "Your profile")
|
||||||
|
|
||||||
@less_console_noise_decorator
|
@less_console_noise_decorator
|
||||||
def test_home_page_main_nav_with_profile_feature_off(self):
|
def test_new_request_main_nav(self):
|
||||||
"""test that Your profile is not in main nav of home page when profile_feature is off"""
|
"""test that Your profile is in main nav of new request"""
|
||||||
with override_flag("profile_feature", active=False):
|
|
||||||
response = self.client.get("/", follow=True)
|
|
||||||
self.assertNotContains(response, "Your profile")
|
|
||||||
|
|
||||||
@less_console_noise_decorator
|
|
||||||
def test_new_request_main_nav_with_profile_feature_on(self):
|
|
||||||
"""test that Your profile is in main nav of new request when profile_feature is on"""
|
|
||||||
with override_flag("profile_feature", active=True):
|
|
||||||
response = self.client.get("/request/", follow=True)
|
response = self.client.get("/request/", follow=True)
|
||||||
self.assertContains(response, "Your profile")
|
self.assertContains(response, "Your profile")
|
||||||
|
|
||||||
@less_console_noise_decorator
|
@less_console_noise_decorator
|
||||||
def test_new_request_main_nav_with_profile_feature_off(self):
|
def test_user_profile_main_nav(self):
|
||||||
"""test that Your profile is not in main nav of new request when profile_feature is off"""
|
"""test that Your profile is in main nav of user profile"""
|
||||||
with override_flag("profile_feature", active=False):
|
|
||||||
response = self.client.get("/request/", follow=True)
|
|
||||||
self.assertNotContains(response, "Your profile")
|
|
||||||
|
|
||||||
@less_console_noise_decorator
|
|
||||||
def test_user_profile_main_nav_with_profile_feature_on(self):
|
|
||||||
"""test that Your profile is in main nav of user profile when profile_feature is on"""
|
|
||||||
with override_flag("profile_feature", active=True):
|
|
||||||
response = self.client.get("/user-profile", follow=True)
|
response = self.client.get("/user-profile", follow=True)
|
||||||
self.assertContains(response, "Your profile")
|
self.assertContains(response, "Your profile")
|
||||||
|
|
||||||
@less_console_noise_decorator
|
|
||||||
def test_user_profile_returns_404_when_feature_off(self):
|
|
||||||
"""test that Your profile returns 404 when profile_feature is off"""
|
|
||||||
with override_flag("profile_feature", active=False):
|
|
||||||
response = self.client.get("/user-profile", follow=True)
|
|
||||||
self.assertEqual(response.status_code, 404)
|
|
||||||
|
|
||||||
@less_console_noise_decorator
|
@less_console_noise_decorator
|
||||||
def test_user_profile_back_button_when_coming_from_domain_request(self):
|
def test_user_profile_back_button_when_coming_from_domain_request(self):
|
||||||
"""tests user profile when profile_feature is on,
|
"""tests user profile,
|
||||||
and when they are redirected from the domain request page"""
|
and when they are redirected from the domain request page"""
|
||||||
with override_flag("profile_feature", active=True):
|
|
||||||
response = self.client.get("/user-profile?redirect=domain-request:")
|
response = self.client.get("/user-profile?redirect=domain-request:")
|
||||||
self.assertContains(response, "Your profile")
|
self.assertContains(response, "Your profile")
|
||||||
self.assertContains(response, "Go back to your domain request")
|
self.assertContains(response, "Go back to your domain request")
|
||||||
self.assertNotContains(response, "Back to manage your domains")
|
self.assertNotContains(response, "Back to manage your domains")
|
||||||
|
|
||||||
@less_console_noise_decorator
|
@less_console_noise_decorator
|
||||||
def test_domain_detail_profile_feature_on(self):
|
def test_domain_detail_contains_your_profile(self):
|
||||||
"""test that domain detail view when profile_feature is on"""
|
"""Tests that the domain detail view contains 'your profile' rather than 'your contact information'"""
|
||||||
with override_flag("profile_feature", active=True):
|
|
||||||
response = self.client.get(reverse("domain", args=[self.domain.pk]))
|
response = self.client.get(reverse("domain", args=[self.domain.pk]))
|
||||||
self.assertContains(response, "Your profile")
|
self.assertContains(response, "Your profile")
|
||||||
self.assertNotContains(response, "Your contact information")
|
self.assertNotContains(response, "Your contact information")
|
||||||
|
|
||||||
@less_console_noise_decorator
|
@less_console_noise_decorator
|
||||||
def test_request_when_profile_feature_on(self):
|
def test_domain_your_contact_information(self):
|
||||||
"""test that Your profile is in request page when profile feature is on"""
|
"""test that your contact information is not accessible"""
|
||||||
|
response = self.client.get(f"/domain/{self.domain.id}/your-contact-information", follow=True)
|
||||||
contact_user, _ = Contact.objects.get_or_create(
|
self.assertEqual(response.status_code, 404)
|
||||||
first_name="Hank",
|
|
||||||
last_name="McFakerson",
|
|
||||||
)
|
|
||||||
site = DraftDomain.objects.create(name="igorville.gov")
|
|
||||||
domain_request = DomainRequest.objects.create(
|
|
||||||
creator=self.user,
|
|
||||||
requested_domain=site,
|
|
||||||
status=DomainRequest.DomainRequestStatus.SUBMITTED,
|
|
||||||
senior_official=contact_user,
|
|
||||||
)
|
|
||||||
with override_flag("profile_feature", active=True):
|
|
||||||
response = self.client.get(f"/domain-request/{domain_request.id}", follow=True)
|
|
||||||
self.assertContains(response, "Your profile")
|
|
||||||
response = self.client.get(f"/domain-request/{domain_request.id}/withdraw", follow=True)
|
|
||||||
self.assertContains(response, "Your profile")
|
|
||||||
|
|
||||||
@less_console_noise_decorator
|
@less_console_noise_decorator
|
||||||
def test_request_when_profile_feature_off(self):
|
def test_profile_request_page(self):
|
||||||
"""test that Your profile is not in request page when profile feature is off"""
|
"""test that your profile is in request"""
|
||||||
|
|
||||||
contact_user, _ = Contact.objects.get_or_create(
|
contact_user, _ = Contact.objects.get_or_create(
|
||||||
first_name="Hank",
|
first_name="Hank",
|
||||||
|
@ -1034,20 +960,16 @@ class UserProfileTests(TestWithUser, WebTest):
|
||||||
status=DomainRequest.DomainRequestStatus.SUBMITTED,
|
status=DomainRequest.DomainRequestStatus.SUBMITTED,
|
||||||
senior_official=contact_user,
|
senior_official=contact_user,
|
||||||
)
|
)
|
||||||
with override_flag("profile_feature", active=False):
|
|
||||||
response = self.client.get(f"/domain-request/{domain_request.id}", follow=True)
|
response = self.client.get(f"/domain-request/{domain_request.id}", follow=True)
|
||||||
self.assertNotContains(response, "Your profile")
|
self.assertContains(response, "Your profile")
|
||||||
response = self.client.get(f"/domain-request/{domain_request.id}/withdraw", follow=True)
|
response = self.client.get(f"/domain-request/{domain_request.id}/withdraw", follow=True)
|
||||||
self.assertNotContains(response, "Your profile")
|
self.assertContains(response, "Your profile")
|
||||||
# cleanup
|
|
||||||
domain_request.delete()
|
|
||||||
site.delete()
|
|
||||||
|
|
||||||
@less_console_noise_decorator
|
@less_console_noise_decorator
|
||||||
def test_user_profile_form_submission(self):
|
def test_user_profile_form_submission(self):
|
||||||
"""test user profile form submission"""
|
"""test user profile form submission"""
|
||||||
self.app.set_user(self.user.username)
|
self.app.set_user(self.user.username)
|
||||||
with override_flag("profile_feature", active=True):
|
|
||||||
profile_page = self.app.get(reverse("user-profile"))
|
profile_page = self.app.get(reverse("user-profile"))
|
||||||
session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
|
session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
|
||||||
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
|
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
|
||||||
|
|
|
@ -723,7 +723,7 @@ class TestDomainManagers(TestDomainOverview):
|
||||||
email_address = "mayor@igorville.gov"
|
email_address = "mayor@igorville.gov"
|
||||||
invitation, _ = DomainInvitation.objects.get_or_create(domain=self.domain, email=email_address)
|
invitation, _ = DomainInvitation.objects.get_or_create(domain=self.domain, email=email_address)
|
||||||
|
|
||||||
other_user = User()
|
other_user = create_user()
|
||||||
other_user.save()
|
other_user.save()
|
||||||
self.client.force_login(other_user)
|
self.client.force_login(other_user)
|
||||||
mock_client = MagicMock()
|
mock_client = MagicMock()
|
||||||
|
@ -737,6 +737,12 @@ class TestDomainManagers(TestDomainOverview):
|
||||||
def test_domain_invitation_flow(self):
|
def test_domain_invitation_flow(self):
|
||||||
"""Send an invitation to a new user, log in and load the dashboard."""
|
"""Send an invitation to a new user, log in and load the dashboard."""
|
||||||
email_address = "mayor@igorville.gov"
|
email_address = "mayor@igorville.gov"
|
||||||
|
username = "mayor"
|
||||||
|
first_name = "First"
|
||||||
|
last_name = "Last"
|
||||||
|
title = "title"
|
||||||
|
phone = "8080102431"
|
||||||
|
title = "title"
|
||||||
User.objects.filter(email=email_address).delete()
|
User.objects.filter(email=email_address).delete()
|
||||||
|
|
||||||
add_page = self.app.get(reverse("domain-users-add", kwargs={"pk": self.domain.id}))
|
add_page = self.app.get(reverse("domain-users-add", kwargs={"pk": self.domain.id}))
|
||||||
|
@ -752,7 +758,9 @@ class TestDomainManagers(TestDomainOverview):
|
||||||
add_page.form.submit()
|
add_page.form.submit()
|
||||||
|
|
||||||
# user was invited, create them
|
# user was invited, create them
|
||||||
new_user = User.objects.create(username=email_address, email=email_address)
|
new_user = User.objects.create(
|
||||||
|
username=username, email=email_address, first_name=first_name, last_name=last_name, title=title, phone=phone
|
||||||
|
)
|
||||||
# log them in to `self.app`
|
# log them in to `self.app`
|
||||||
self.app.set_user(new_user.username)
|
self.app.set_user(new_user.username)
|
||||||
# and manually call the on each login callback
|
# and manually call the on each login callback
|
||||||
|
@ -1298,7 +1306,9 @@ class TestDomainOrganization(TestDomainOverview):
|
||||||
"""Can load domain's org name and mailing address page."""
|
"""Can load domain's org name and mailing address page."""
|
||||||
page = self.client.get(reverse("domain-org-name-address", kwargs={"pk": self.domain.id}))
|
page = self.client.get(reverse("domain-org-name-address", kwargs={"pk": self.domain.id}))
|
||||||
# once on the sidebar, once in the page title, once as H1
|
# once on the sidebar, once in the page title, once as H1
|
||||||
self.assertContains(page, "Organization name and mailing address", count=4)
|
self.assertContains(page, "/org-name-address")
|
||||||
|
self.assertContains(page, "Organization name and mailing address")
|
||||||
|
self.assertContains(page, "Organization</h1>")
|
||||||
|
|
||||||
@less_console_noise_decorator
|
@less_console_noise_decorator
|
||||||
def test_domain_org_name_address_content(self):
|
def test_domain_org_name_address_content(self):
|
||||||
|
@ -1607,7 +1617,7 @@ class TestDomainSuborganization(TestDomainOverview):
|
||||||
|
|
||||||
# Test for the title change
|
# Test for the title change
|
||||||
self.assertContains(page, "Suborganization")
|
self.assertContains(page, "Suborganization")
|
||||||
self.assertNotContains(page, "Organization name")
|
self.assertNotContains(page, "Organization")
|
||||||
|
|
||||||
# Test for the good value
|
# Test for the good value
|
||||||
self.assertContains(page, "Ice Cream")
|
self.assertContains(page, "Ice Cream")
|
||||||
|
|
|
@ -200,7 +200,7 @@ class TestPortfolio(WebTest):
|
||||||
# Assert the response is a 200
|
# Assert the response is a 200
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
# The label for Federal agency will always be a h4
|
# The label for Federal agency will always be a h4
|
||||||
self.assertContains(response, '<h4 class="read-only-label">Federal agency</h4>')
|
self.assertContains(response, '<h4 class="read-only-label">Organization name</h4>')
|
||||||
# The read only label for city will be a h4
|
# The read only label for city will be a h4
|
||||||
self.assertContains(response, '<h4 class="read-only-label">City</h4>')
|
self.assertContains(response, '<h4 class="read-only-label">City</h4>')
|
||||||
self.assertNotContains(response, 'for="id_city"')
|
self.assertNotContains(response, 'for="id_city"')
|
||||||
|
@ -225,10 +225,10 @@ class TestPortfolio(WebTest):
|
||||||
# Assert the response is a 200
|
# Assert the response is a 200
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
# The label for Federal agency will always be a h4
|
# The label for Federal agency will always be a h4
|
||||||
self.assertContains(response, '<h4 class="read-only-label">Federal agency</h4>')
|
self.assertContains(response, '<h4 class="read-only-label">Organization name</h4>')
|
||||||
# The read only label for city will be a h4
|
# The read only label for city will be a h4
|
||||||
self.assertNotContains(response, '<h4 class="read-only-label">City</h4>')
|
self.assertNotContains(response, '<h4 class="read-only-label">City</h4>')
|
||||||
self.assertNotContains(response, '<p class="read-only-value">Los Angeles</p>>')
|
self.assertNotContains(response, '<p class="read-only-value">Los Angeles</p>')
|
||||||
self.assertContains(response, 'for="id_city"')
|
self.assertContains(response, 'for="id_city"')
|
||||||
|
|
||||||
@less_console_noise_decorator
|
@less_console_noise_decorator
|
||||||
|
@ -342,9 +342,7 @@ class TestPortfolio(WebTest):
|
||||||
user=self.user, portfolio=self.portfolio, additional_permissions=portfolio_additional_permissions
|
user=self.user, portfolio=self.portfolio, additional_permissions=portfolio_additional_permissions
|
||||||
)
|
)
|
||||||
page = self.app.get(reverse("organization"))
|
page = self.app.get(reverse("organization"))
|
||||||
self.assertContains(
|
self.assertContains(page, "The name of your organization will be publicly listed as the domain registrant.")
|
||||||
page, "The name of your federal agency will be publicly listed as the domain registrant."
|
|
||||||
)
|
|
||||||
|
|
||||||
@less_console_noise_decorator
|
@less_console_noise_decorator
|
||||||
def test_domain_org_name_address_content(self):
|
def test_domain_org_name_address_content(self):
|
||||||
|
@ -537,6 +535,41 @@ class TestPortfolio(WebTest):
|
||||||
self.assertContains(response, "Domain name")
|
self.assertContains(response, "Domain name")
|
||||||
permission.delete()
|
permission.delete()
|
||||||
|
|
||||||
|
def check_widescreen_is_loaded(self, page_to_check):
|
||||||
|
"""Tests if class modifiers for widescreen mode are appropriately loaded into the DOM
|
||||||
|
for the given page"""
|
||||||
|
|
||||||
|
self.client.force_login(self.user)
|
||||||
|
|
||||||
|
# Ensure that this user can see domains with the right permissions
|
||||||
|
permission, _ = UserPortfolioPermission.objects.get_or_create(
|
||||||
|
user=self.user, portfolio=self.portfolio, roles=[UserPortfolioRoleChoices.ORGANIZATION_MEMBER]
|
||||||
|
)
|
||||||
|
permission.additional_permissions = [UserPortfolioPermissionChoices.VIEW_ALL_DOMAINS]
|
||||||
|
permission.save()
|
||||||
|
permission.refresh_from_db()
|
||||||
|
|
||||||
|
response = self.client.get(reverse(page_to_check))
|
||||||
|
# Make sure that the page is loaded correctly
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
# Test for widescreen modifier
|
||||||
|
self.assertContains(response, "--widescreen")
|
||||||
|
|
||||||
|
@less_console_noise_decorator
|
||||||
|
@override_flag("organization_feature", active=True)
|
||||||
|
def test_widescreen_css_org_model(self):
|
||||||
|
"""Tests if class modifiers for widescreen mode are appropriately
|
||||||
|
loaded into the DOM for org model pages"""
|
||||||
|
self.check_widescreen_is_loaded("domains")
|
||||||
|
|
||||||
|
@less_console_noise_decorator
|
||||||
|
@override_flag("organization_feature", active=False)
|
||||||
|
def test_widescreen_css_non_org_model(self):
|
||||||
|
"""Tests if class modifiers for widescreen mode are appropriately
|
||||||
|
loaded into the DOM for non-org model pages"""
|
||||||
|
self.check_widescreen_is_loaded("home")
|
||||||
|
|
||||||
@less_console_noise_decorator
|
@less_console_noise_decorator
|
||||||
@override_flag("organization_feature", active=True)
|
@override_flag("organization_feature", active=True)
|
||||||
@override_flag("organization_requests", active=False)
|
@override_flag("organization_requests", active=False)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
from unittest import skip
|
from unittest import skip
|
||||||
from unittest.mock import Mock
|
from unittest.mock import Mock, patch
|
||||||
|
from datetime import datetime
|
||||||
|
from django.utils import timezone
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from api.tests.common import less_console_noise_decorator
|
from api.tests.common import less_console_noise_decorator
|
||||||
|
@ -56,6 +57,46 @@ class DomainRequestTests(TestWithUser, WebTest):
|
||||||
intro_page = self.app.get(reverse("domain-request:"))
|
intro_page = self.app.get(reverse("domain-request:"))
|
||||||
self.assertContains(intro_page, "You’re about to start your .gov domain request")
|
self.assertContains(intro_page, "You’re about to start your .gov domain request")
|
||||||
|
|
||||||
|
@less_console_noise_decorator
|
||||||
|
def test_template_status_display(self):
|
||||||
|
"""Tests the display of status-related information in the template."""
|
||||||
|
domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.SUBMITTED, user=self.user)
|
||||||
|
domain_request.last_submitted_date = datetime.now()
|
||||||
|
domain_request.save()
|
||||||
|
response = self.app.get(f"/domain-request/{domain_request.id}")
|
||||||
|
self.assertContains(response, "Submitted on:")
|
||||||
|
self.assertContains(response, domain_request.last_submitted_date.strftime("%B %-d, %Y"))
|
||||||
|
|
||||||
|
@patch.object(DomainRequest, "get_first_status_set_date")
|
||||||
|
def test_get_first_status_started_date(self, mock_get_first_status_set_date):
|
||||||
|
"""Tests retrieval of the first date the status was set to 'started'."""
|
||||||
|
|
||||||
|
# Set the mock to return a fixed date
|
||||||
|
fixed_date = timezone.datetime(2023, 1, 1).date()
|
||||||
|
mock_get_first_status_set_date.return_value = fixed_date
|
||||||
|
|
||||||
|
domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.STARTED, user=self.user)
|
||||||
|
domain_request.last_status_update = None
|
||||||
|
domain_request.save()
|
||||||
|
|
||||||
|
response = self.app.get(f"/domain-request/{domain_request.id}")
|
||||||
|
# Ensure that the date is still set to None
|
||||||
|
self.assertIsNone(domain_request.last_status_update)
|
||||||
|
print(response)
|
||||||
|
# We should still grab a date for this field in this event - but it should come from the audit log instead
|
||||||
|
self.assertContains(response, "Started on:")
|
||||||
|
self.assertContains(response, fixed_date.strftime("%B %-d, %Y"))
|
||||||
|
|
||||||
|
# If a status date is set, we display that instead
|
||||||
|
domain_request.last_status_update = datetime.now()
|
||||||
|
domain_request.save()
|
||||||
|
|
||||||
|
response = self.app.get(f"/domain-request/{domain_request.id}")
|
||||||
|
|
||||||
|
# We should still grab a date for this field in this event - but it should come from the audit log instead
|
||||||
|
self.assertContains(response, "Started on:")
|
||||||
|
self.assertContains(response, domain_request.last_status_update.strftime("%B %-d, %Y"))
|
||||||
|
|
||||||
@less_console_noise_decorator
|
@less_console_noise_decorator
|
||||||
def test_domain_request_form_intro_is_skipped_when_edit_access(self):
|
def test_domain_request_form_intro_is_skipped_when_edit_access(self):
|
||||||
"""Tests that user is NOT presented with intro acknowledgement page when accessed through 'edit'"""
|
"""Tests that user is NOT presented with intro acknowledgement page when accessed through 'edit'"""
|
||||||
|
@ -2206,7 +2247,6 @@ class DomainRequestTests(TestWithUser, WebTest):
|
||||||
senior_official = domain_request.senior_official
|
senior_official = domain_request.senior_official
|
||||||
self.assertEquals("Testy2", senior_official.first_name)
|
self.assertEquals("Testy2", senior_official.first_name)
|
||||||
|
|
||||||
@override_flag("profile_feature", active=True)
|
|
||||||
@less_console_noise_decorator
|
@less_console_noise_decorator
|
||||||
def test_edit_creator_in_place(self):
|
def test_edit_creator_in_place(self):
|
||||||
"""When you:
|
"""When you:
|
||||||
|
@ -2985,3 +3025,40 @@ class TestWizardUnlockingSteps(TestWithUser, WebTest):
|
||||||
|
|
||||||
else:
|
else:
|
||||||
self.fail(f"Expected a redirect, but got a different response: {response}")
|
self.fail(f"Expected a redirect, but got a different response: {response}")
|
||||||
|
|
||||||
|
|
||||||
|
class TestPortfolioDomainRequestViewonly(TestWithUser, WebTest):
|
||||||
|
|
||||||
|
# Doesn't work with CSRF checking
|
||||||
|
# hypothesis is that CSRF_USE_SESSIONS is incompatible with WebTest
|
||||||
|
csrf_checks = False
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super().setUp()
|
||||||
|
self.federal_agency, _ = FederalAgency.objects.get_or_create(agency="General Services Administration")
|
||||||
|
self.app.set_user(self.user.username)
|
||||||
|
self.TITLES = DomainRequestWizard.TITLES
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
super().tearDown()
|
||||||
|
DomainRequest.objects.all().delete()
|
||||||
|
DomainInformation.objects.all().delete()
|
||||||
|
self.federal_agency.delete()
|
||||||
|
|
||||||
|
@less_console_noise_decorator
|
||||||
|
@override_flag("organization_feature", active=True)
|
||||||
|
def test_domain_request_viewonly_displays_correct_fields(self):
|
||||||
|
"""Tests that the viewonly page displays different fields"""
|
||||||
|
portfolio, _ = Portfolio.objects.get_or_create(creator=self.user, organization_name="Test Portfolio")
|
||||||
|
UserPortfolioPermission.objects.get_or_create(
|
||||||
|
user=self.user, portfolio=portfolio, roles=[UserPortfolioRoleChoices.ORGANIZATION_ADMIN]
|
||||||
|
)
|
||||||
|
dummy_user, _ = User.objects.get_or_create(username="testusername123456")
|
||||||
|
domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.SUBMITTED, user=dummy_user)
|
||||||
|
domain_request.save()
|
||||||
|
|
||||||
|
detail_page = self.app.get(f"/domain-request/viewonly/{domain_request.id}")
|
||||||
|
self.assertContains(detail_page, "Requesting entity")
|
||||||
|
self.assertNotContains(detail_page, "Type of organization")
|
||||||
|
self.assertContains(detail_page, "city.gov")
|
||||||
|
self.assertContains(detail_page, "Status:")
|
||||||
|
|
|
@ -341,7 +341,9 @@ class GetRequestsJsonTest(TestWithUser, WebTest):
|
||||||
if creator[i] != self.user.email:
|
if creator[i] != self.user.email:
|
||||||
# Test case where action is View
|
# Test case where action is View
|
||||||
self.assertEqual("View", action_labels[i])
|
self.assertEqual("View", action_labels[i])
|
||||||
self.assertEqual("#", action_urls[i])
|
self.assertEqual(
|
||||||
|
reverse("domain-request-status-viewonly", kwargs={"pk": expected_domain_request.id}), action_urls[i]
|
||||||
|
)
|
||||||
self.assertEqual("visibility", svg_icons[i])
|
self.assertEqual("visibility", svg_icons[i])
|
||||||
elif status[i] in [
|
elif status[i] in [
|
||||||
DomainRequest.DomainRequestStatus.STARTED.label,
|
DomainRequest.DomainRequestStatus.STARTED.label,
|
||||||
|
@ -458,3 +460,81 @@ class GetRequestsJsonTest(TestWithUser, WebTest):
|
||||||
# Ensure no approved requests are included
|
# Ensure no approved requests are included
|
||||||
for domain_request in data["domain_requests"]:
|
for domain_request in data["domain_requests"]:
|
||||||
self.assertNotEqual(domain_request["status"], DomainRequest.DomainRequestStatus.APPROVED)
|
self.assertNotEqual(domain_request["status"], DomainRequest.DomainRequestStatus.APPROVED)
|
||||||
|
|
||||||
|
def test_search(self):
|
||||||
|
"""Tests our search functionality. We expect that search filters on creator only when we are in a portfolio"""
|
||||||
|
# Test search for domain name
|
||||||
|
response = self.app.get(reverse("get_domain_requests_json"), {"search_term": "lamb"})
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
data = response.json
|
||||||
|
self.assertEqual(len(data["domain_requests"]), 1)
|
||||||
|
|
||||||
|
requested_domain = data["domain_requests"][0]["requested_domain"]
|
||||||
|
self.assertEqual(requested_domain, "lamb-chops.gov")
|
||||||
|
|
||||||
|
# Test search for 'New domain request'
|
||||||
|
response = self.app.get(reverse("get_domain_requests_json"), {"search_term": "new domain"})
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
data = response.json
|
||||||
|
self.assertTrue(any(req["requested_domain"] is None for req in data["domain_requests"]))
|
||||||
|
|
||||||
|
# Test search with portfolio (including creator search)
|
||||||
|
self.client.force_login(self.user)
|
||||||
|
with override_flag("organization_feature", active=True), override_flag("organization_requests", active=True):
|
||||||
|
user_perm, _ = UserPortfolioPermission.objects.get_or_create(
|
||||||
|
user=self.user,
|
||||||
|
portfolio=self.portfolio,
|
||||||
|
roles=[UserPortfolioRoleChoices.ORGANIZATION_ADMIN],
|
||||||
|
)
|
||||||
|
response = self.app.get(
|
||||||
|
reverse("get_domain_requests_json"), {"search_term": "info", "portfolio": self.portfolio.id}
|
||||||
|
)
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
data = response.json
|
||||||
|
self.assertTrue(any(req["creator"].startswith("info") for req in data["domain_requests"]))
|
||||||
|
|
||||||
|
# Test search without portfolio (should not search on creator)
|
||||||
|
with override_flag("organization_feature", active=False), override_flag("organization_requests", active=False):
|
||||||
|
user_perm.delete()
|
||||||
|
response = self.app.get(reverse("get_domain_requests_json"), {"search_term": "info"})
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
data = response.json
|
||||||
|
self.assertEqual(len(data["domain_requests"]), 0)
|
||||||
|
|
||||||
|
@override_flag("organization_feature", active=True)
|
||||||
|
@override_flag("organization_requests", active=True)
|
||||||
|
def test_status_filter(self):
|
||||||
|
"""Test that status filtering works properly"""
|
||||||
|
# Test a single status
|
||||||
|
response = self.app.get(reverse("get_domain_requests_json"), {"status": "started"})
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
data = response.json
|
||||||
|
self.assertTrue(all(req["status"] == "Started" for req in data["domain_requests"]))
|
||||||
|
|
||||||
|
# Test an invalid status
|
||||||
|
response = self.app.get(reverse("get_domain_requests_json"), {"status": "approved"})
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
data = response.json
|
||||||
|
self.assertEqual(len(data["domain_requests"]), 0)
|
||||||
|
|
||||||
|
@override_flag("organization_feature", active=True)
|
||||||
|
@override_flag("organization_requests", active=True)
|
||||||
|
def test_combined_filtering_and_sorting(self):
|
||||||
|
"""Test that combining filters and sorting works properly"""
|
||||||
|
user_perm, _ = UserPortfolioPermission.objects.get_or_create(
|
||||||
|
user=self.user,
|
||||||
|
portfolio=self.portfolio,
|
||||||
|
roles=[UserPortfolioRoleChoices.ORGANIZATION_ADMIN],
|
||||||
|
)
|
||||||
|
self.client.force_login(self.user)
|
||||||
|
response = self.app.get(
|
||||||
|
reverse("get_domain_requests_json"),
|
||||||
|
{"search_term": "beef", "status": "started", "portfolio": self.portfolio.id},
|
||||||
|
)
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
data = response.json
|
||||||
|
self.assertTrue(all("beef" in req["requested_domain"] for req in data["domain_requests"]))
|
||||||
|
self.assertTrue(all(req["status"] == "Started" for req in data["domain_requests"]))
|
||||||
|
created_at_dates = [req["created_at"] for req in data["domain_requests"]]
|
||||||
|
self.assertEqual(created_at_dates, sorted(created_at_dates, reverse=True))
|
||||||
|
user_perm.delete()
|
||||||
|
|
|
@ -108,6 +108,8 @@ def send_templated_email(
|
||||||
def _can_send_email(to_address, bcc_address):
|
def _can_send_email(to_address, bcc_address):
|
||||||
"""Raises an EmailSendingError if we cannot send an email. Does nothing otherwise."""
|
"""Raises an EmailSendingError if we cannot send an email. Does nothing otherwise."""
|
||||||
|
|
||||||
|
# testing below a global waffle flag which will not be associated with a user
|
||||||
|
# or with http request, so pass None to flag_is_active
|
||||||
if flag_is_active(None, "disable_email_sending"): # type: ignore
|
if flag_is_active(None, "disable_email_sending"): # type: ignore
|
||||||
message = "Could not send email. Email sending is disabled due to flag 'disable_email_sending'."
|
message = "Could not send email. Email sending is disabled due to flag 'disable_email_sending'."
|
||||||
raise EmailSendingError(message)
|
raise EmailSendingError(message)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
"""Used for holding various enums"""
|
"""Used for holding various enums"""
|
||||||
|
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
from registrar.utility import StrEnum
|
||||||
|
|
||||||
|
|
||||||
class ValidationReturnType(Enum):
|
class ValidationReturnType(Enum):
|
||||||
|
@ -38,3 +39,45 @@ class DefaultEmail(Enum):
|
||||||
|
|
||||||
PUBLIC_CONTACT_DEFAULT = "dotgov@cisa.dhs.gov"
|
PUBLIC_CONTACT_DEFAULT = "dotgov@cisa.dhs.gov"
|
||||||
LEGACY_DEFAULT = "registrar@dotgov.gov"
|
LEGACY_DEFAULT = "registrar@dotgov.gov"
|
||||||
|
|
||||||
|
|
||||||
|
class Step(StrEnum):
|
||||||
|
"""
|
||||||
|
Names for each page of the domain request wizard.
|
||||||
|
|
||||||
|
As with Django's own `TextChoices` class, steps will
|
||||||
|
appear in the order they are defined. (Order matters.)
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Non-Portfolio
|
||||||
|
ORGANIZATION_TYPE = "generic_org_type"
|
||||||
|
TRIBAL_GOVERNMENT = "tribal_government"
|
||||||
|
ORGANIZATION_FEDERAL = "organization_federal"
|
||||||
|
ORGANIZATION_ELECTION = "organization_election"
|
||||||
|
ORGANIZATION_CONTACT = "organization_contact"
|
||||||
|
ABOUT_YOUR_ORGANIZATION = "about_your_organization"
|
||||||
|
SENIOR_OFFICIAL = "senior_official"
|
||||||
|
CURRENT_SITES = "current_sites"
|
||||||
|
DOTGOV_DOMAIN = "dotgov_domain"
|
||||||
|
PURPOSE = "purpose"
|
||||||
|
OTHER_CONTACTS = "other_contacts"
|
||||||
|
ADDITIONAL_DETAILS = "additional_details"
|
||||||
|
REQUIREMENTS = "requirements"
|
||||||
|
REVIEW = "review"
|
||||||
|
|
||||||
|
|
||||||
|
class PortfolioDomainRequestStep(StrEnum):
|
||||||
|
"""
|
||||||
|
Names for each page of the portfolio domain request wizard.
|
||||||
|
|
||||||
|
As with Django's own `TextChoices` class, steps will
|
||||||
|
appear in the order they are defined. (Order matters.)
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Portfolio
|
||||||
|
REQUESTING_ENTITY = "organization_name"
|
||||||
|
CURRENT_SITES = "current_sites"
|
||||||
|
DOTGOV_DOMAIN = "dotgov_domain"
|
||||||
|
PURPOSE = "purpose"
|
||||||
|
ADDITIONAL_DETAILS = "additional_details"
|
||||||
|
REQUIREMENTS = "requirements"
|
||||||
|
|
12
src/registrar/utility/waffle.py
Normal file
12
src/registrar/utility/waffle.py
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
from django.http import HttpRequest
|
||||||
|
from waffle.decorators import flag_is_active
|
||||||
|
|
||||||
|
|
||||||
|
def flag_is_active_for_user(user, flag_name):
|
||||||
|
"""flag_is_active_for_user can be used when a waffle_flag may be
|
||||||
|
activated for a user, but the context of where the flag needs to
|
||||||
|
be tested does not have a request object available.
|
||||||
|
When the request is available, flag_is_active should be used."""
|
||||||
|
request = HttpRequest()
|
||||||
|
request.user = user
|
||||||
|
return flag_is_active(request, flag_name)
|
|
@ -204,7 +204,7 @@ class DomainView(DomainBaseView):
|
||||||
|
|
||||||
|
|
||||||
class DomainOrgNameAddressView(DomainFormBaseView):
|
class DomainOrgNameAddressView(DomainFormBaseView):
|
||||||
"""Organization name and mailing address view"""
|
"""Organization view"""
|
||||||
|
|
||||||
model = Domain
|
model = Domain
|
||||||
template_name = "domain_org_name_address.html"
|
template_name = "domain_org_name_address.html"
|
||||||
|
|
|
@ -7,48 +7,25 @@ from django.utils.safestring import mark_safe
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django.views.generic import TemplateView
|
from django.views.generic import TemplateView
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
|
|
||||||
from registrar.forms import domain_request_wizard as forms
|
from registrar.forms import domain_request_wizard as forms
|
||||||
|
from registrar.forms.utility.wizard_form_helper import request_step_list
|
||||||
from registrar.models import DomainRequest
|
from registrar.models import DomainRequest
|
||||||
from registrar.models.contact import Contact
|
from registrar.models.contact import Contact
|
||||||
from registrar.models.user import User
|
from registrar.models.user import User
|
||||||
from registrar.utility import StrEnum
|
|
||||||
from registrar.views.utility import StepsHelper
|
from registrar.views.utility import StepsHelper
|
||||||
from registrar.views.utility.permission_views import DomainRequestPermissionDeleteView
|
from registrar.views.utility.permission_views import DomainRequestPermissionDeleteView
|
||||||
|
from registrar.utility.enums import Step, PortfolioDomainRequestStep
|
||||||
|
|
||||||
from .utility import (
|
from .utility import (
|
||||||
DomainRequestPermissionView,
|
DomainRequestPermissionView,
|
||||||
DomainRequestPermissionWithdrawView,
|
DomainRequestPermissionWithdrawView,
|
||||||
DomainRequestWizardPermissionView,
|
DomainRequestWizardPermissionView,
|
||||||
|
DomainRequestPortfolioViewonlyView,
|
||||||
)
|
)
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class Step(StrEnum):
|
|
||||||
"""
|
|
||||||
Names for each page of the domain request wizard.
|
|
||||||
|
|
||||||
As with Django's own `TextChoices` class, steps will
|
|
||||||
appear in the order they are defined. (Order matters.)
|
|
||||||
"""
|
|
||||||
|
|
||||||
ORGANIZATION_TYPE = "generic_org_type"
|
|
||||||
TRIBAL_GOVERNMENT = "tribal_government"
|
|
||||||
ORGANIZATION_FEDERAL = "organization_federal"
|
|
||||||
ORGANIZATION_ELECTION = "organization_election"
|
|
||||||
ORGANIZATION_CONTACT = "organization_contact"
|
|
||||||
ABOUT_YOUR_ORGANIZATION = "about_your_organization"
|
|
||||||
SENIOR_OFFICIAL = "senior_official"
|
|
||||||
CURRENT_SITES = "current_sites"
|
|
||||||
DOTGOV_DOMAIN = "dotgov_domain"
|
|
||||||
PURPOSE = "purpose"
|
|
||||||
OTHER_CONTACTS = "other_contacts"
|
|
||||||
ADDITIONAL_DETAILS = "additional_details"
|
|
||||||
REQUIREMENTS = "requirements"
|
|
||||||
REVIEW = "review"
|
|
||||||
|
|
||||||
|
|
||||||
class DomainRequestWizard(DomainRequestWizardPermissionView, TemplateView):
|
class DomainRequestWizard(DomainRequestWizardPermissionView, TemplateView):
|
||||||
"""
|
"""
|
||||||
A common set of methods and configuration.
|
A common set of methods and configuration.
|
||||||
|
@ -66,6 +43,7 @@ class DomainRequestWizard(DomainRequestWizardPermissionView, TemplateView):
|
||||||
although not without consulting the base implementation, first.
|
although not without consulting the base implementation, first.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
StepEnum: Step = Step # type: ignore
|
||||||
template_name = ""
|
template_name = ""
|
||||||
|
|
||||||
# uniquely namespace the wizard in urls.py
|
# uniquely namespace the wizard in urls.py
|
||||||
|
@ -78,29 +56,29 @@ class DomainRequestWizard(DomainRequestWizardPermissionView, TemplateView):
|
||||||
NEW_URL_NAME = "/request/"
|
NEW_URL_NAME = "/request/"
|
||||||
# We need to pass our human-readable step titles as context to the templates.
|
# We need to pass our human-readable step titles as context to the templates.
|
||||||
TITLES = {
|
TITLES = {
|
||||||
Step.ORGANIZATION_TYPE: _("Type of organization"),
|
StepEnum.ORGANIZATION_TYPE: _("Type of organization"),
|
||||||
Step.TRIBAL_GOVERNMENT: _("Tribal government"),
|
StepEnum.TRIBAL_GOVERNMENT: _("Tribal government"),
|
||||||
Step.ORGANIZATION_FEDERAL: _("Federal government branch"),
|
StepEnum.ORGANIZATION_FEDERAL: _("Federal government branch"),
|
||||||
Step.ORGANIZATION_ELECTION: _("Election office"),
|
StepEnum.ORGANIZATION_ELECTION: _("Election office"),
|
||||||
Step.ORGANIZATION_CONTACT: _("Organization name and mailing address"),
|
StepEnum.ORGANIZATION_CONTACT: _("Organization"),
|
||||||
Step.ABOUT_YOUR_ORGANIZATION: _("About your organization"),
|
StepEnum.ABOUT_YOUR_ORGANIZATION: _("About your organization"),
|
||||||
Step.SENIOR_OFFICIAL: _("Senior official"),
|
StepEnum.SENIOR_OFFICIAL: _("Senior official"),
|
||||||
Step.CURRENT_SITES: _("Current websites"),
|
StepEnum.CURRENT_SITES: _("Current websites"),
|
||||||
Step.DOTGOV_DOMAIN: _(".gov domain"),
|
StepEnum.DOTGOV_DOMAIN: _(".gov domain"),
|
||||||
Step.PURPOSE: _("Purpose of your domain"),
|
StepEnum.PURPOSE: _("Purpose of your domain"),
|
||||||
Step.OTHER_CONTACTS: _("Other employees from your organization"),
|
StepEnum.OTHER_CONTACTS: _("Other employees from your organization"),
|
||||||
Step.ADDITIONAL_DETAILS: _("Additional details"),
|
StepEnum.ADDITIONAL_DETAILS: _("Additional details"),
|
||||||
Step.REQUIREMENTS: _("Requirements for operating a .gov domain"),
|
StepEnum.REQUIREMENTS: _("Requirements for operating a .gov domain"),
|
||||||
Step.REVIEW: _("Review and submit your domain request"),
|
StepEnum.REVIEW: _("Review and submit your domain request"),
|
||||||
}
|
}
|
||||||
|
|
||||||
# We can use a dictionary with step names and callables that return booleans
|
# We can use a dictionary with step names and callables that return booleans
|
||||||
# to show or hide particular steps based on the state of the process.
|
# to show or hide particular steps based on the state of the process.
|
||||||
WIZARD_CONDITIONS = {
|
WIZARD_CONDITIONS = {
|
||||||
Step.ORGANIZATION_FEDERAL: lambda w: w.from_model("show_organization_federal", False),
|
StepEnum.ORGANIZATION_FEDERAL: lambda w: w.from_model("show_organization_federal", False),
|
||||||
Step.TRIBAL_GOVERNMENT: lambda w: w.from_model("show_tribal_government", False),
|
StepEnum.TRIBAL_GOVERNMENT: lambda w: w.from_model("show_tribal_government", False),
|
||||||
Step.ORGANIZATION_ELECTION: lambda w: w.from_model("show_organization_election", False),
|
StepEnum.ORGANIZATION_ELECTION: lambda w: w.from_model("show_organization_election", False),
|
||||||
Step.ABOUT_YOUR_ORGANIZATION: lambda w: w.from_model("show_about_your_organization", False),
|
StepEnum.ABOUT_YOUR_ORGANIZATION: lambda w: w.from_model("show_about_your_organization", False),
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
@ -439,15 +417,7 @@ class DomainRequestWizard(DomainRequestWizardPermissionView, TemplateView):
|
||||||
|
|
||||||
def get_step_list(self) -> list:
|
def get_step_list(self) -> list:
|
||||||
"""Dynamically generated list of steps in the form wizard."""
|
"""Dynamically generated list of steps in the form wizard."""
|
||||||
step_list = []
|
return request_step_list(self)
|
||||||
for step in Step:
|
|
||||||
condition = self.WIZARD_CONDITIONS.get(step, True)
|
|
||||||
if callable(condition):
|
|
||||||
condition = condition(self)
|
|
||||||
if condition:
|
|
||||||
step_list.append(step)
|
|
||||||
|
|
||||||
return step_list
|
|
||||||
|
|
||||||
def goto(self, step):
|
def goto(self, step):
|
||||||
if step == "generic_org_type":
|
if step == "generic_org_type":
|
||||||
|
@ -529,6 +499,26 @@ class DomainRequestWizard(DomainRequestWizardPermissionView, TemplateView):
|
||||||
form.to_database(self.domain_request)
|
form.to_database(self.domain_request)
|
||||||
|
|
||||||
|
|
||||||
|
# TODO - this is a WIP until the domain request experience for portfolios is complete
|
||||||
|
class PortfolioDomainRequestWizard(DomainRequestWizard):
|
||||||
|
StepEnum: PortfolioDomainRequestStep = PortfolioDomainRequestStep # type: ignore
|
||||||
|
|
||||||
|
TITLES = {
|
||||||
|
StepEnum.REQUESTING_ENTITY: _("Requesting entity"),
|
||||||
|
StepEnum.CURRENT_SITES: _("Current websites"),
|
||||||
|
StepEnum.DOTGOV_DOMAIN: _(".gov domain"),
|
||||||
|
StepEnum.PURPOSE: _("Purpose of your domain"),
|
||||||
|
StepEnum.ADDITIONAL_DETAILS: _("Additional details"),
|
||||||
|
StepEnum.REQUIREMENTS: _("Requirements for operating a .gov domain"),
|
||||||
|
# Step.REVIEW: _("Review and submit your domain request"),
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.steps = StepsHelper(self)
|
||||||
|
self._domain_request = None # for caching
|
||||||
|
|
||||||
|
|
||||||
class OrganizationType(DomainRequestWizard):
|
class OrganizationType(DomainRequestWizard):
|
||||||
template_name = "domain_request_org_type.html"
|
template_name = "domain_request_org_type.html"
|
||||||
forms = [forms.OrganizationTypeForm]
|
forms = [forms.OrganizationTypeForm]
|
||||||
|
@ -750,6 +740,21 @@ class Finished(DomainRequestWizard):
|
||||||
class DomainRequestStatus(DomainRequestPermissionView):
|
class DomainRequestStatus(DomainRequestPermissionView):
|
||||||
template_name = "domain_request_status.html"
|
template_name = "domain_request_status.html"
|
||||||
|
|
||||||
|
def has_permission(self):
|
||||||
|
"""
|
||||||
|
Override of the base has_permission class to account for portfolio permissions
|
||||||
|
"""
|
||||||
|
has_base_perms = super().has_permission()
|
||||||
|
if not has_base_perms:
|
||||||
|
return False
|
||||||
|
|
||||||
|
if self.request.user.is_org_user(self.request):
|
||||||
|
portfolio = self.request.session.get("portfolio")
|
||||||
|
if not self.request.user.has_edit_request_portfolio_permission(portfolio):
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
class DomainRequestWithdrawConfirmation(DomainRequestPermissionWithdrawView):
|
class DomainRequestWithdrawConfirmation(DomainRequestPermissionWithdrawView):
|
||||||
"""This page will ask user to confirm if they want to withdraw
|
"""This page will ask user to confirm if they want to withdraw
|
||||||
|
@ -883,3 +888,21 @@ class DomainRequestDeleteView(DomainRequestPermissionDeleteView):
|
||||||
|
|
||||||
duplicates = [item for item, count in object_dict.items() if count > 1]
|
duplicates = [item for item, count in object_dict.items() if count > 1]
|
||||||
return duplicates
|
return duplicates
|
||||||
|
|
||||||
|
|
||||||
|
# region Portfolio views
|
||||||
|
class PortfolioDomainRequestStatusViewOnly(DomainRequestPortfolioViewonlyView):
|
||||||
|
template_name = "portfolio_domain_request_status_viewonly.html"
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super().get_context_data(**kwargs)
|
||||||
|
# Create a temp wizard object to grab the step list
|
||||||
|
wizard = PortfolioDomainRequestWizard()
|
||||||
|
wizard.request = self.request
|
||||||
|
context["Step"] = wizard.StepEnum.__members__
|
||||||
|
context["steps"] = request_step_list(wizard)
|
||||||
|
context["form_titles"] = wizard.TITLES
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
# endregion
|
||||||
|
|
|
@ -20,6 +20,7 @@ def get_domain_requests_json(request):
|
||||||
unfiltered_total = objects.count()
|
unfiltered_total = objects.count()
|
||||||
|
|
||||||
objects = apply_search(objects, request)
|
objects = apply_search(objects, request)
|
||||||
|
objects = apply_status_filter(objects, request)
|
||||||
objects = apply_sorting(objects, request)
|
objects = apply_sorting(objects, request)
|
||||||
|
|
||||||
paginator = Paginator(objects, 10)
|
paginator = Paginator(objects, 10)
|
||||||
|
@ -63,6 +64,7 @@ def get_domain_request_ids_from_request(request):
|
||||||
|
|
||||||
def apply_search(queryset, request):
|
def apply_search(queryset, request):
|
||||||
search_term = request.GET.get("search_term")
|
search_term = request.GET.get("search_term")
|
||||||
|
is_portfolio = request.GET.get("portfolio")
|
||||||
|
|
||||||
if search_term:
|
if search_term:
|
||||||
search_term_lower = search_term.lower()
|
search_term_lower = search_term.lower()
|
||||||
|
@ -75,11 +77,34 @@ def apply_search(queryset, request):
|
||||||
queryset = queryset.filter(
|
queryset = queryset.filter(
|
||||||
Q(requested_domain__name__icontains=search_term) | Q(requested_domain__isnull=True)
|
Q(requested_domain__name__icontains=search_term) | Q(requested_domain__isnull=True)
|
||||||
)
|
)
|
||||||
|
elif is_portfolio:
|
||||||
|
queryset = queryset.filter(
|
||||||
|
Q(requested_domain__name__icontains=search_term)
|
||||||
|
| Q(creator__first_name__icontains=search_term)
|
||||||
|
| Q(creator__last_name__icontains=search_term)
|
||||||
|
| Q(creator__email__icontains=search_term)
|
||||||
|
)
|
||||||
|
# For non org users
|
||||||
else:
|
else:
|
||||||
queryset = queryset.filter(Q(requested_domain__name__icontains=search_term))
|
queryset = queryset.filter(Q(requested_domain__name__icontains=search_term))
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
|
|
||||||
|
def apply_status_filter(queryset, request):
|
||||||
|
status_param = request.GET.get("status")
|
||||||
|
if status_param:
|
||||||
|
status_list = status_param.split(",")
|
||||||
|
statuses = [status for status in status_list if status in DomainRequest.DomainRequestStatus.values]
|
||||||
|
# Construct Q objects for statuses that can be queried through ORM
|
||||||
|
status_query = Q()
|
||||||
|
if statuses:
|
||||||
|
status_query |= Q(status__in=statuses)
|
||||||
|
# Apply the combined query
|
||||||
|
queryset = queryset.filter(status_query)
|
||||||
|
|
||||||
|
return queryset
|
||||||
|
|
||||||
|
|
||||||
def apply_sorting(queryset, request):
|
def apply_sorting(queryset, request):
|
||||||
sort_by = request.GET.get("sort_by", "id") # Default to 'id'
|
sort_by = request.GET.get("sort_by", "id") # Default to 'id'
|
||||||
order = request.GET.get("order", "asc") # Default to 'asc'
|
order = request.GET.get("order", "asc") # Default to 'asc'
|
||||||
|
@ -121,7 +146,7 @@ def serialize_domain_request(request, domain_request, user):
|
||||||
action_url_map = {
|
action_url_map = {
|
||||||
"Edit": reverse("edit-domain-request", kwargs={"id": domain_request.id}),
|
"Edit": reverse("edit-domain-request", kwargs={"id": domain_request.id}),
|
||||||
"Manage": reverse("domain-request-status", kwargs={"pk": domain_request.id}),
|
"Manage": reverse("domain-request-status", kwargs={"pk": domain_request.id}),
|
||||||
"View": "#",
|
"View": reverse("domain-request-status-viewonly", kwargs={"pk": domain_request.id}),
|
||||||
}
|
}
|
||||||
|
|
||||||
svg_icon_map = {"Edit": "edit", "Manage": "settings", "View": "visibility"}
|
svg_icon_map = {"Edit": "edit", "Manage": "settings", "View": "visibility"}
|
||||||
|
|
|
@ -11,7 +11,6 @@ from django.urls import NoReverseMatch, reverse
|
||||||
from registrar.models.user import User
|
from registrar.models.user import User
|
||||||
from registrar.models.utility.generic_helper import replace_url_queryparams
|
from registrar.models.utility.generic_helper import replace_url_queryparams
|
||||||
from registrar.views.utility.permission_views import UserProfilePermissionView
|
from registrar.views.utility.permission_views import UserProfilePermissionView
|
||||||
from waffle.decorators import waffle_flag
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -46,7 +45,6 @@ class UserProfileView(UserProfilePermissionView, FormMixin):
|
||||||
|
|
||||||
return self.render_to_response(context)
|
return self.render_to_response(context)
|
||||||
|
|
||||||
@waffle_flag("profile_feature") # type: ignore
|
|
||||||
def dispatch(self, request, *args, **kwargs): # type: ignore
|
def dispatch(self, request, *args, **kwargs): # type: ignore
|
||||||
return super().dispatch(request, *args, **kwargs)
|
return super().dispatch(request, *args, **kwargs)
|
||||||
|
|
||||||
|
|
|
@ -8,5 +8,6 @@ from .permission_views import (
|
||||||
DomainInvitationPermissionDeleteView,
|
DomainInvitationPermissionDeleteView,
|
||||||
DomainRequestWizardPermissionView,
|
DomainRequestWizardPermissionView,
|
||||||
PortfolioMembersPermission,
|
PortfolioMembersPermission,
|
||||||
|
DomainRequestPortfolioViewonlyView,
|
||||||
)
|
)
|
||||||
from .api_views import get_senior_official_from_federal_agency_json
|
from .api_views import get_senior_official_from_federal_agency_json
|
||||||
|
|
|
@ -289,6 +289,29 @@ class DomainRequestPermission(PermissionsLoginMixin):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class DomainRequestPortfolioViewonlyPermission(PermissionsLoginMixin):
|
||||||
|
"""Permission mixin that redirects to domain request if user
|
||||||
|
has access, otherwise 403"""
|
||||||
|
|
||||||
|
def has_permission(self):
|
||||||
|
"""Check if this user has access to this domain request.
|
||||||
|
|
||||||
|
The user is in self.request.user and the domain needs to be looked
|
||||||
|
up from the domain's primary key in self.kwargs["pk"]
|
||||||
|
"""
|
||||||
|
if not self.request.user.is_authenticated:
|
||||||
|
return False
|
||||||
|
|
||||||
|
if not self.request.user.is_org_user(self.request):
|
||||||
|
return False
|
||||||
|
|
||||||
|
portfolio = self.request.session.get("portfolio")
|
||||||
|
if not self.request.user.has_view_all_requests_portfolio_permission(portfolio):
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
class UserDeleteDomainRolePermission(PermissionsLoginMixin):
|
class UserDeleteDomainRolePermission(PermissionsLoginMixin):
|
||||||
"""Permission mixin for UserDomainRole if user
|
"""Permission mixin for UserDomainRole if user
|
||||||
has access, otherwise 403"""
|
has access, otherwise 403"""
|
||||||
|
|
|
@ -19,6 +19,7 @@ from .mixins import (
|
||||||
UserProfilePermission,
|
UserProfilePermission,
|
||||||
PortfolioBasePermission,
|
PortfolioBasePermission,
|
||||||
PortfolioMembersPermission,
|
PortfolioMembersPermission,
|
||||||
|
DomainRequestPortfolioViewonlyPermission,
|
||||||
)
|
)
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
@ -100,6 +101,25 @@ class DomainRequestPermissionView(DomainRequestPermission, DetailView, abc.ABC):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
|
class DomainRequestPortfolioViewonlyView(DomainRequestPortfolioViewonlyPermission, DetailView, abc.ABC):
|
||||||
|
"""Abstract base view for domain requests that enforces permissions
|
||||||
|
|
||||||
|
This abstract view cannot be instantiated. Actual views must specify
|
||||||
|
`template_name`.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# DetailView property for what model this is viewing
|
||||||
|
model = DomainRequest
|
||||||
|
# variable name in template context for the model object
|
||||||
|
context_object_name = "DomainRequest"
|
||||||
|
|
||||||
|
# Abstract property enforces NotImplementedError on an attribute.
|
||||||
|
@property
|
||||||
|
@abc.abstractmethod
|
||||||
|
def template_name(self):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
class DomainRequestPermissionWithdrawView(DomainRequestPermissionWithdraw, DetailView, abc.ABC):
|
class DomainRequestPermissionWithdrawView(DomainRequestPermissionWithdraw, DetailView, abc.ABC):
|
||||||
"""Abstract base view for domain request withdraw function
|
"""Abstract base view for domain request withdraw function
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue