mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-05-16 17:47:02 +02:00
Update migration and conflict
This commit is contained in:
commit
7d85dced0d
10 changed files with 313 additions and 10 deletions
|
@ -1,7 +1,8 @@
|
||||||
from datetime import date
|
from datetime import date
|
||||||
import logging
|
import logging
|
||||||
import copy
|
import copy
|
||||||
|
import json
|
||||||
|
from django.template.loader import get_template
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.db.models import Value, CharField, Q
|
from django.db.models import Value, CharField, Q
|
||||||
from django.db.models.functions import Concat, Coalesce
|
from django.db.models.functions import Concat, Coalesce
|
||||||
|
@ -1689,6 +1690,10 @@ class DomainRequestAdmin(ListHeaderAdmin, ImportExportModelAdmin):
|
||||||
return super().save_model(request, obj, form, change)
|
return super().save_model(request, obj, form, change)
|
||||||
|
|
||||||
# == Handle non-status changes == #
|
# == Handle non-status changes == #
|
||||||
|
# Change this in #1901. Add a check on "not self.action_needed_reason_email"
|
||||||
|
if obj.action_needed_reason:
|
||||||
|
self._handle_action_needed_reason_email(obj)
|
||||||
|
should_save = True
|
||||||
|
|
||||||
# Get the original domain request from the database.
|
# Get the original domain request from the database.
|
||||||
original_obj = models.DomainRequest.objects.get(pk=obj.pk)
|
original_obj = models.DomainRequest.objects.get(pk=obj.pk)
|
||||||
|
@ -1697,14 +1702,17 @@ class DomainRequestAdmin(ListHeaderAdmin, ImportExportModelAdmin):
|
||||||
return super().save_model(request, obj, form, change)
|
return super().save_model(request, obj, form, change)
|
||||||
|
|
||||||
# == Handle status changes == #
|
# == Handle status changes == #
|
||||||
|
|
||||||
# Run some checks on the current object for invalid status changes
|
# Run some checks on the current object for invalid status changes
|
||||||
obj, should_save = self._handle_status_change(request, obj, original_obj)
|
obj, should_save = self._handle_status_change(request, obj, original_obj)
|
||||||
|
|
||||||
# We should only save if we don't display any errors in the step above.
|
# We should only save if we don't display any errors in the steps above.
|
||||||
if should_save:
|
if should_save:
|
||||||
return super().save_model(request, obj, form, change)
|
return super().save_model(request, obj, form, change)
|
||||||
|
|
||||||
|
def _handle_action_needed_reason_email(self, obj):
|
||||||
|
text = self._get_action_needed_reason_default_email_text(obj, obj.action_needed_reason)
|
||||||
|
obj.action_needed_reason_email = text.get("email_body_text")
|
||||||
|
|
||||||
def _handle_status_change(self, request, obj, original_obj):
|
def _handle_status_change(self, request, obj, original_obj):
|
||||||
"""
|
"""
|
||||||
Checks for various conditions when a status change is triggered.
|
Checks for various conditions when a status change is triggered.
|
||||||
|
@ -1898,10 +1906,45 @@ class DomainRequestAdmin(ListHeaderAdmin, ImportExportModelAdmin):
|
||||||
# Initialize extra_context and add filtered entries
|
# Initialize extra_context and add filtered entries
|
||||||
extra_context = extra_context or {}
|
extra_context = extra_context or {}
|
||||||
extra_context["filtered_audit_log_entries"] = filtered_audit_log_entries
|
extra_context["filtered_audit_log_entries"] = filtered_audit_log_entries
|
||||||
|
extra_context["action_needed_reason_emails"] = self.get_all_action_needed_reason_emails_as_json(obj)
|
||||||
|
|
||||||
# Call the superclass method with updated extra_context
|
# Call the superclass method with updated extra_context
|
||||||
return super().change_view(request, object_id, form_url, extra_context)
|
return super().change_view(request, object_id, form_url, extra_context)
|
||||||
|
|
||||||
|
def get_all_action_needed_reason_emails_as_json(self, domain_request):
|
||||||
|
"""Returns a json dictionary of every action needed reason and its associated email
|
||||||
|
for this particular domain request."""
|
||||||
|
emails = {}
|
||||||
|
for action_needed_reason in domain_request.ActionNeededReasons:
|
||||||
|
enum_value = action_needed_reason.value
|
||||||
|
# Change this in #1901. Just add a check for the current value.
|
||||||
|
emails[enum_value] = self._get_action_needed_reason_default_email_text(domain_request, enum_value)
|
||||||
|
return json.dumps(emails)
|
||||||
|
|
||||||
|
def _get_action_needed_reason_default_email_text(self, domain_request, action_needed_reason: str):
|
||||||
|
"""Returns the default email associated with the given action needed reason"""
|
||||||
|
if action_needed_reason is None or action_needed_reason == domain_request.ActionNeededReasons.OTHER:
|
||||||
|
return {
|
||||||
|
"subject_text": None,
|
||||||
|
"email_body_text": None,
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get the email body
|
||||||
|
template_path = f"emails/action_needed_reasons/{action_needed_reason}.txt"
|
||||||
|
template = get_template(template_path)
|
||||||
|
|
||||||
|
# Get the email subject
|
||||||
|
template_subject_path = f"emails/action_needed_reasons/{action_needed_reason}_subject.txt"
|
||||||
|
subject_template = get_template(template_subject_path)
|
||||||
|
|
||||||
|
# Return the content of the rendered views
|
||||||
|
context = {"domain_request": domain_request}
|
||||||
|
|
||||||
|
return {
|
||||||
|
"subject_text": subject_template.render(context=context),
|
||||||
|
"email_body_text": template.render(context=context),
|
||||||
|
}
|
||||||
|
|
||||||
def process_log_entry(self, log_entry):
|
def process_log_entry(self, log_entry):
|
||||||
"""Process a log entry and return filtered entry dictionary if applicable."""
|
"""Process a log entry and return filtered entry dictionary if applicable."""
|
||||||
changes = log_entry.changes
|
changes = log_entry.changes
|
||||||
|
|
|
@ -8,6 +8,25 @@
|
||||||
|
|
||||||
// <<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>>
|
// <<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>><<>>
|
||||||
// Helper functions.
|
// Helper functions.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hide element
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
const hideElement = (element) => {
|
||||||
|
if (element && !element.classList.contains("display-none"))
|
||||||
|
element.classList.add('display-none');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show element
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
const showElement = (element) => {
|
||||||
|
if (element && element.classList.contains("display-none"))
|
||||||
|
element.classList.remove('display-none');
|
||||||
|
};
|
||||||
|
|
||||||
/** Either sets attribute target="_blank" to a given element, or removes it */
|
/** Either sets attribute target="_blank" to a given element, or removes it */
|
||||||
function openInNewTab(el, removeAttribute = false){
|
function openInNewTab(el, removeAttribute = false){
|
||||||
if(removeAttribute){
|
if(removeAttribute){
|
||||||
|
@ -57,6 +76,7 @@ function openInNewTab(el, removeAttribute = false){
|
||||||
createPhantomModalFormButtons();
|
createPhantomModalFormButtons();
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
|
||||||
/** An IIFE for DomainRequest to hook a modal to a dropdown option.
|
/** An IIFE for DomainRequest to hook a modal to a dropdown option.
|
||||||
* This intentionally does not interact with createPhantomModalFormButtons()
|
* This intentionally does not interact with createPhantomModalFormButtons()
|
||||||
*/
|
*/
|
||||||
|
@ -408,13 +428,21 @@ function initializeWidgetOnList(list, parentId) {
|
||||||
function moveStatusChangelog(actionNeededReasonFormGroup, statusSelect) {
|
function moveStatusChangelog(actionNeededReasonFormGroup, statusSelect) {
|
||||||
let flexContainer = actionNeededReasonFormGroup.querySelector('.flex-container');
|
let flexContainer = actionNeededReasonFormGroup.querySelector('.flex-container');
|
||||||
let statusChangelog = document.getElementById('dja-status-changelog');
|
let statusChangelog = document.getElementById('dja-status-changelog');
|
||||||
|
|
||||||
|
// On action needed, show the email that will be sent out
|
||||||
|
let showReasonEmailContainer = document.querySelector("#action_needed_reason_email_readonly")
|
||||||
|
|
||||||
|
// Prepopulate values on page load.
|
||||||
if (statusSelect.value === "action needed") {
|
if (statusSelect.value === "action needed") {
|
||||||
flexContainer.parentNode.insertBefore(statusChangelog, flexContainer.nextSibling);
|
flexContainer.parentNode.insertBefore(statusChangelog, flexContainer.nextSibling);
|
||||||
|
showElement(showReasonEmailContainer);
|
||||||
} else {
|
} else {
|
||||||
// Move the changelog back to its original location
|
// Move the changelog back to its original location
|
||||||
let statusFlexContainer = statusSelect.closest('.flex-container');
|
let statusFlexContainer = statusSelect.closest('.flex-container');
|
||||||
statusFlexContainer.parentNode.insertBefore(statusChangelog, statusFlexContainer.nextSibling);
|
statusFlexContainer.parentNode.insertBefore(statusChangelog, statusFlexContainer.nextSibling);
|
||||||
|
hideElement(showReasonEmailContainer);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call the function on page load
|
// Call the function on page load
|
||||||
|
@ -518,3 +546,60 @@ function initializeWidgetOnList(list, parentId) {
|
||||||
handleShowMoreButton(toggleButton, descriptionDiv)
|
handleShowMoreButton(toggleButton, descriptionDiv)
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
/** An IIFE that hooks up to the "show email" button.
|
||||||
|
* which shows the auto generated email on action needed reason.
|
||||||
|
*/
|
||||||
|
(function () {
|
||||||
|
let actionNeededReasonDropdown = document.querySelector("#id_action_needed_reason");
|
||||||
|
let actionNeededEmail = document.querySelector("#action_needed_reason_email_view_more");
|
||||||
|
if(actionNeededReasonDropdown && actionNeededEmail && container) {
|
||||||
|
// Add a change listener to the action needed reason dropdown
|
||||||
|
handleChangeActionNeededEmail(actionNeededReasonDropdown, actionNeededEmail);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleChangeActionNeededEmail(actionNeededReasonDropdown, actionNeededEmail) {
|
||||||
|
actionNeededReasonDropdown.addEventListener("change", function() {
|
||||||
|
let reason = actionNeededReasonDropdown.value;
|
||||||
|
|
||||||
|
// If a reason isn't specified, no email will be sent.
|
||||||
|
// You also cannot save the model in this state.
|
||||||
|
// This flow occurs if you switch back to the empty picker state.
|
||||||
|
if(!reason) {
|
||||||
|
showNoEmailMessage(actionNeededEmail);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let actionNeededEmails = JSON.parse(document.getElementById('action-needed-emails-data').textContent)
|
||||||
|
let emailData = actionNeededEmails[reason];
|
||||||
|
if (emailData) {
|
||||||
|
let emailBody = emailData.email_body_text
|
||||||
|
if (emailBody) {
|
||||||
|
actionNeededEmail.value = emailBody
|
||||||
|
showActionNeededEmail(actionNeededEmail);
|
||||||
|
}else {
|
||||||
|
showNoEmailMessage(actionNeededEmail);
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
showNoEmailMessage(actionNeededEmail);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show the text field. Hide the "no email" message.
|
||||||
|
function showActionNeededEmail(actionNeededEmail){
|
||||||
|
let noEmailMessage = document.getElementById("no-email-message");
|
||||||
|
showElement(actionNeededEmail);
|
||||||
|
hideElement(noEmailMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hide the text field. Show the "no email" message.
|
||||||
|
function showNoEmailMessage(actionNeededEmail) {
|
||||||
|
let noEmailMessage = document.getElementById("no-email-message");
|
||||||
|
hideElement(actionNeededEmail);
|
||||||
|
showElement(noEmailMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
})();
|
||||||
|
|
|
@ -786,3 +786,44 @@ div.dja__model-description{
|
||||||
.usa-button--dja-link-color {
|
.usa-button--dja-link-color {
|
||||||
color: var(--link-fg);
|
color: var(--link-fg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dja-readonly-textarea-container {
|
||||||
|
textarea {
|
||||||
|
width: 100%;
|
||||||
|
min-width: 610px;
|
||||||
|
resize: none;
|
||||||
|
cursor: auto;
|
||||||
|
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
width: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Style the scroll bar handle
|
||||||
|
&::-webkit-scrollbar-thumb {
|
||||||
|
background-color: var(--body-fg);
|
||||||
|
border-radius: 99px;
|
||||||
|
background-clip: content-box;
|
||||||
|
border: 3px solid transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.max-full {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thin-border {
|
||||||
|
background-color: var(--selected-bg);
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
border-radius: 8px;
|
||||||
|
label {
|
||||||
|
padding-top: 0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.display-none {
|
||||||
|
// Many elements in django admin try to override this, so we need !important.
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 4.2.10 on 2024-06-26 14:10
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("registrar", "0106_create_groups_v14"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="domainrequest",
|
||||||
|
name="action_needed_reason_email",
|
||||||
|
field=models.TextField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,59 @@
|
||||||
|
# Generated by Django 4.2.10 on 2024-06-24 19:00
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("registrar", "0107_domainrequest_action_needed_reason_email"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name="domaininformation",
|
||||||
|
name="authorizing_official",
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name="domainrequest",
|
||||||
|
name="authorizing_official",
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="domaininformation",
|
||||||
|
name="senior_official",
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.PROTECT,
|
||||||
|
related_name="information_senior_official",
|
||||||
|
to="registrar.contact",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="domainrequest",
|
||||||
|
name="senior_official",
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.PROTECT,
|
||||||
|
related_name="senior_official",
|
||||||
|
to="registrar.contact",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="domainrequest",
|
||||||
|
name="action_needed_reason",
|
||||||
|
field=models.TextField(
|
||||||
|
blank=True,
|
||||||
|
choices=[
|
||||||
|
("eligibility_unclear", "Unclear organization eligibility"),
|
||||||
|
("questionable_senior_official", "Questionable senior official"),
|
||||||
|
("already_has_domains", "Already has domains"),
|
||||||
|
("bad_name", "Doesn’t meet naming requirements"),
|
||||||
|
("other", "Other (no auto-email sent)"),
|
||||||
|
],
|
||||||
|
null=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
|
@ -296,6 +296,11 @@ class DomainRequest(TimeStampedModel):
|
||||||
blank=True,
|
blank=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
action_needed_reason_email = models.TextField(
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
)
|
||||||
|
|
||||||
federal_agency = models.ForeignKey(
|
federal_agency = models.ForeignKey(
|
||||||
"registrar.FederalAgency",
|
"registrar.FederalAgency",
|
||||||
on_delete=models.PROTECT,
|
on_delete=models.PROTECT,
|
||||||
|
|
|
@ -5,7 +5,9 @@
|
||||||
{% block field_sets %}
|
{% block field_sets %}
|
||||||
{# Create an invisible <a> tag so that we can use a click event to toggle the modal. #}
|
{# Create an invisible <a> tag so that we can use a click event to toggle the modal. #}
|
||||||
<a id="invisible-ineligible-modal-toggler" class="display-none" href="#toggle-set-ineligible" aria-controls="toggle-set-ineligible" data-open-modal></a>
|
<a id="invisible-ineligible-modal-toggler" class="display-none" href="#toggle-set-ineligible" aria-controls="toggle-set-ineligible" data-open-modal></a>
|
||||||
|
{# Store the current object id so we can access it easier #}
|
||||||
|
<input id="domain_request_id" class="display-none" value="{{original.id}}" />
|
||||||
|
<input id="has_audit_logs" class="display-none" value="{%if filtered_audit_log_entries %}true{% else %}false{% endif %}"/>
|
||||||
{% for fieldset in adminform %}
|
{% for fieldset in adminform %}
|
||||||
{% comment %}
|
{% comment %}
|
||||||
TODO: this will eventually need to be changed to something like this
|
TODO: this will eventually need to be changed to something like this
|
||||||
|
|
|
@ -62,17 +62,18 @@ This is using a custom implementation fieldset.html (see admin/fieldset.html)
|
||||||
{% endwith %}
|
{% endwith %}
|
||||||
</div>
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="readonly">{{ field.contents }}</div>
|
<div class="readonly">{{ field.contents }}</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endwith %}
|
{% endwith %}
|
||||||
{% endblock field_readonly %}
|
{% endblock field_readonly %}
|
||||||
|
|
||||||
{% block after_help_text %}
|
{% block after_help_text %}
|
||||||
{% if field.field.name == "status" and filtered_audit_log_entries %}
|
{% if field.field.name == "status" %}
|
||||||
<div class="flex-container" id="dja-status-changelog">
|
<div class="flex-container" id="dja-status-changelog">
|
||||||
<label aria-label="Status changelog"></label>
|
<label aria-label="Status changelog"></label>
|
||||||
<div>
|
<div>
|
||||||
<div class="usa-table-container--scrollable collapse--dgsimple collapsed" tabindex="0">
|
<div class="usa-table-container--scrollable collapse--dgsimple collapsed" tabindex="0">
|
||||||
|
{% if filtered_audit_log_entries %}
|
||||||
<table class="usa-table usa-table--borderless">
|
<table class="usa-table usa-table--borderless">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -105,7 +106,34 @@ This is using a custom implementation fieldset.html (see admin/fieldset.html)
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
{% else %}
|
||||||
|
<p>No changelog to display.</p>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% comment %}
|
||||||
|
Store the action needed reason emails in a json-based dictionary.
|
||||||
|
This allows us to change the action_needed_reason_email field dynamically, depending on value.
|
||||||
|
The alternative to this is an API endpoint.
|
||||||
|
|
||||||
|
Given that we have a limited number of emails, doing it this way makes sense.
|
||||||
|
{% endcomment %}
|
||||||
|
{% if action_needed_reason_emails %}
|
||||||
|
<script id="action-needed-emails-data" type="application/json">
|
||||||
|
{{ action_needed_reason_emails|safe }}
|
||||||
|
</script>
|
||||||
|
{% endif %}
|
||||||
|
<div id="action_needed_reason_email_readonly" class="dja-readonly-textarea-container padding-1 margin-top-2 thin-border display-none">
|
||||||
|
<label class="max-full" for="action_needed_reason_email_view_more">
|
||||||
|
<strong>Auto-generated email (sent to submitter)</strong>
|
||||||
|
</label>
|
||||||
|
<textarea id="action_needed_reason_email_view_more" cols="40" rows="20" class="{% if not original_object.action_needed_reason %}display-none{% endif %}" readonly>
|
||||||
|
{{ original_object.action_needed_reason_email }}
|
||||||
|
</textarea>
|
||||||
|
<p id="no-email-message" class="{% if original_object.action_needed_reason %}display-none{% endif %}">No email will be sent.</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<button type="button" class="collapse-toggle--dgsimple usa-button usa-button--unstyled margin-top-2 margin-bottom-1 margin-left-1">
|
<button type="button" class="collapse-toggle--dgsimple usa-button usa-button--unstyled margin-top-2 margin-bottom-1 margin-left-1">
|
||||||
<span>Show details</span>
|
<span>Show details</span>
|
||||||
<svg class="usa-icon" aria-hidden="true" focusable="false" role="img" width="24" height="24">
|
<svg class="usa-icon" aria-hidden="true" focusable="false" role="img" width="24" height="24">
|
||||||
|
|
|
@ -858,6 +858,7 @@ def completed_domain_request( # noqa
|
||||||
is_election_board=False,
|
is_election_board=False,
|
||||||
organization_type=None,
|
organization_type=None,
|
||||||
federal_agency=None,
|
federal_agency=None,
|
||||||
|
action_needed_reason=None,
|
||||||
):
|
):
|
||||||
"""A completed domain request."""
|
"""A completed domain request."""
|
||||||
if not user:
|
if not user:
|
||||||
|
@ -922,6 +923,9 @@ def completed_domain_request( # noqa
|
||||||
if organization_type:
|
if organization_type:
|
||||||
domain_request_kwargs["organization_type"] = organization_type
|
domain_request_kwargs["organization_type"] = organization_type
|
||||||
|
|
||||||
|
if action_needed_reason:
|
||||||
|
domain_request_kwargs["action_needed_reason"] = action_needed_reason
|
||||||
|
|
||||||
domain_request, _ = DomainRequest.objects.get_or_create(**domain_request_kwargs)
|
domain_request, _ = DomainRequest.objects.get_or_create(**domain_request_kwargs)
|
||||||
|
|
||||||
if has_other_contacts:
|
if has_other_contacts:
|
||||||
|
|
|
@ -1596,6 +1596,24 @@ 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)
|
||||||
|
|
||||||
|
@less_console_noise_decorator
|
||||||
|
def test_model_displays_action_needed_email(self):
|
||||||
|
"""Tests if the action needed email is visible for Domain Requests"""
|
||||||
|
|
||||||
|
_domain_request = completed_domain_request(
|
||||||
|
status=DomainRequest.DomainRequestStatus.ACTION_NEEDED,
|
||||||
|
action_needed_reason=DomainRequest.ActionNeededReasons.BAD_NAME,
|
||||||
|
)
|
||||||
|
|
||||||
|
p = "userpass"
|
||||||
|
self.client.login(username="staffuser", password=p)
|
||||||
|
response = self.client.get(
|
||||||
|
"/admin/registrar/domainrequest/{}/change/".format(_domain_request.pk),
|
||||||
|
follow=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertContains(response, "DOMAIN NAME DOES NOT MEET .GOV REQUIREMENTS")
|
||||||
|
|
||||||
@override_settings(IS_PRODUCTION=True)
|
@override_settings(IS_PRODUCTION=True)
|
||||||
def test_save_model_sends_submitted_email_with_bcc_on_prod(self):
|
def test_save_model_sends_submitted_email_with_bcc_on_prod(self):
|
||||||
"""When transitioning to submitted from started or withdrawn on a domain request,
|
"""When transitioning to submitted from started or withdrawn on a domain request,
|
||||||
|
@ -2161,15 +2179,14 @@ class TestDomainRequestAdmin(MockEppLib):
|
||||||
self.assertContains(response, "testy@town.com", count=2)
|
self.assertContains(response, "testy@town.com", count=2)
|
||||||
expected_so_fields = [
|
expected_so_fields = [
|
||||||
# Field, expected value
|
# Field, expected value
|
||||||
("title", "Chief Tester"),
|
|
||||||
("phone", "(555) 555 5555"),
|
("phone", "(555) 555 5555"),
|
||||||
]
|
]
|
||||||
self.test_helper.assert_response_contains_distinct_values(response, expected_so_fields)
|
|
||||||
|
|
||||||
self.assertContains(response, "Testy Tester", count=10)
|
self.test_helper.assert_response_contains_distinct_values(response, expected_so_fields)
|
||||||
|
self.assertContains(response, "Chief Tester")
|
||||||
|
|
||||||
# == Test the other_employees field == #
|
# == Test the other_employees field == #
|
||||||
self.assertContains(response, "testy2@town.com", count=2)
|
self.assertContains(response, "testy2@town.com")
|
||||||
expected_other_employees_fields = [
|
expected_other_employees_fields = [
|
||||||
# Field, expected value
|
# Field, expected value
|
||||||
("title", "Another Tester"),
|
("title", "Another Tester"),
|
||||||
|
@ -2290,6 +2307,7 @@ class TestDomainRequestAdmin(MockEppLib):
|
||||||
"status",
|
"status",
|
||||||
"rejection_reason",
|
"rejection_reason",
|
||||||
"action_needed_reason",
|
"action_needed_reason",
|
||||||
|
"action_needed_reason_email",
|
||||||
"federal_agency",
|
"federal_agency",
|
||||||
"portfolio",
|
"portfolio",
|
||||||
"creator",
|
"creator",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue