mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-07-03 09:43:33 +02:00
Merge pull request #640 from cisagov/nmb/519-authorizing-official
Form for editing authorizing official
This commit is contained in:
commit
5d3976a6fd
10 changed files with 152 additions and 16 deletions
|
@ -88,6 +88,11 @@ urlpatterns = [
|
||||||
views.DomainYourContactInformationView.as_view(),
|
views.DomainYourContactInformationView.as_view(),
|
||||||
name="domain-your-contact-information",
|
name="domain-your-contact-information",
|
||||||
),
|
),
|
||||||
|
path(
|
||||||
|
"domain/<int:pk>/authorizing-official",
|
||||||
|
views.DomainAuthorizingOfficialView.as_view(),
|
||||||
|
name="domain-authorizing-official",
|
||||||
|
),
|
||||||
path(
|
path(
|
||||||
"domain/<int:pk>/security-email",
|
"domain/<int:pk>/security-email",
|
||||||
views.DomainSecurityEmailView.as_view(),
|
views.DomainSecurityEmailView.as_view(),
|
||||||
|
|
|
@ -28,13 +28,6 @@ NameserverFormset = formset_factory(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class DomainSecurityEmailForm(forms.Form):
|
|
||||||
|
|
||||||
"""Form for adding or editing a security email to a domain."""
|
|
||||||
|
|
||||||
security_email = forms.EmailField(label="Security email")
|
|
||||||
|
|
||||||
|
|
||||||
class ContactForm(forms.ModelForm):
|
class ContactForm(forms.ModelForm):
|
||||||
|
|
||||||
"""Form for updating contacts."""
|
"""Form for updating contacts."""
|
||||||
|
@ -59,8 +52,15 @@ class ContactForm(forms.ModelForm):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
# take off maxlength attribute for the phone number field
|
# take off maxlength attribute for the phone number field
|
||||||
# which interferes with our input_with_errors template tag
|
# which interferes with out input_with_errors template tag
|
||||||
self.fields["phone"].widget.attrs.pop("maxlength", None)
|
self.fields["phone"].widget.attrs.pop("maxlength", None)
|
||||||
|
|
||||||
for field_name in self.required:
|
for field_name in self.required:
|
||||||
self.fields[field_name].required = True
|
self.fields[field_name].required = True
|
||||||
|
|
||||||
|
|
||||||
|
class DomainSecurityEmailForm(forms.Form):
|
||||||
|
|
||||||
|
"""Form for adding or editing a security email to a domain."""
|
||||||
|
|
||||||
|
security_email = forms.EmailField(label="Security email")
|
||||||
|
|
19
src/registrar/migrations/0024_alter_contact_email.py
Normal file
19
src/registrar/migrations/0024_alter_contact_email.py
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
# Generated by Django 4.2.1 on 2023-06-01 19:23
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
("registrar", "0023_alter_contact_first_name_alter_contact_last_name_and_more"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="contact",
|
||||||
|
name="email",
|
||||||
|
field=models.EmailField(
|
||||||
|
blank=True, db_index=True, help_text="Email", max_length=254, null=True
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
|
@ -41,7 +41,7 @@ class Contact(TimeStampedModel):
|
||||||
help_text="Title",
|
help_text="Title",
|
||||||
verbose_name="title or role in your organization",
|
verbose_name="title or role in your organization",
|
||||||
)
|
)
|
||||||
email = models.TextField(
|
email = models.EmailField(
|
||||||
null=True,
|
null=True,
|
||||||
blank=True,
|
blank=True,
|
||||||
help_text="Email",
|
help_text="Email",
|
||||||
|
|
43
src/registrar/templates/domain_authorizing_official.html
Normal file
43
src/registrar/templates/domain_authorizing_official.html
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
{% extends "domain_base.html" %}
|
||||||
|
{% load static field_helpers%}
|
||||||
|
|
||||||
|
{% block title %}Domain authorizing official | {{ domain.name }} | {% endblock %}
|
||||||
|
|
||||||
|
{% block domain_content %}
|
||||||
|
{# this is right after the messages block in the parent template #}
|
||||||
|
{% include "includes/form_errors.html" with form=form %}
|
||||||
|
|
||||||
|
<h1>Authorizing official</h1>
|
||||||
|
|
||||||
|
<p>Your authorizing official is the person within your organization who can
|
||||||
|
authorize domain requests. This is generally the highest-ranking or
|
||||||
|
highest-elected official in your organization. <a class="usa-link"
|
||||||
|
href="https://federalist-877ab29f-16f6-4f12-961c-96cf064cf070.sites.pages.cloud.gov/site/cisagov/getgov-home/domains/eligibility/#you-must-have-approval-from-an-authorizing-official-within-your-organization">Read more about who can serve
|
||||||
|
as an authorizing official.</a></p>
|
||||||
|
|
||||||
|
{% include "includes/required_fields.html" %}
|
||||||
|
|
||||||
|
<form class="usa-form usa-form--large" method="post" novalidate id="form-container">
|
||||||
|
{% csrf_token %}
|
||||||
|
|
||||||
|
{% input_with_errors form.first_name %}
|
||||||
|
|
||||||
|
{% input_with_errors form.middle_name %}
|
||||||
|
|
||||||
|
{% input_with_errors form.last_name %}
|
||||||
|
|
||||||
|
{% input_with_errors form.title %}
|
||||||
|
|
||||||
|
{% input_with_errors form.email %}
|
||||||
|
|
||||||
|
{% input_with_errors form.phone %}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
class="usa-button"
|
||||||
|
>Save</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% endblock %} {# domain_content #}
|
|
@ -31,7 +31,7 @@
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li class="usa-sidenav__item">
|
<li class="usa-sidenav__item">
|
||||||
{% url 'todo' as url %}
|
{% url 'domain-authorizing-official' pk=domain.id as url %}
|
||||||
<a href="{{ url }}"
|
<a href="{{ url }}"
|
||||||
{% if request.path == url %}class="usa-current"{% endif %}
|
{% if request.path == url %}class="usa-current"{% endif %}
|
||||||
>
|
>
|
||||||
|
|
|
@ -15,6 +15,7 @@ from registrar.forms.application_wizard import (
|
||||||
AnythingElseForm,
|
AnythingElseForm,
|
||||||
TypeOfWorkForm,
|
TypeOfWorkForm,
|
||||||
)
|
)
|
||||||
|
from registrar.forms.domain import ContactForm
|
||||||
|
|
||||||
|
|
||||||
class TestFormValidation(TestCase):
|
class TestFormValidation(TestCase):
|
||||||
|
@ -277,3 +278,13 @@ class TestFormValidation(TestCase):
|
||||||
for error in form.non_field_errors()
|
for error in form.non_field_errors()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class TestContactForm(TestCase):
|
||||||
|
def test_contact_form_email_invalid(self):
|
||||||
|
form = ContactForm(data={"email": "example.net"})
|
||||||
|
self.assertEqual(form.errors["email"], ["Enter a valid email address."])
|
||||||
|
|
||||||
|
def test_contact_form_email_invalid2(self):
|
||||||
|
form = ContactForm(data={"email": "@"})
|
||||||
|
self.assertEqual(form.errors["email"], ["Enter a valid email address."])
|
||||||
|
|
|
@ -1058,6 +1058,7 @@ class TestDomainPermissions(TestWithDomainPermissions):
|
||||||
"domain-users",
|
"domain-users",
|
||||||
"domain-users-add",
|
"domain-users-add",
|
||||||
"domain-nameservers",
|
"domain-nameservers",
|
||||||
|
"domain-authorizing-official",
|
||||||
"domain-your-contact-information",
|
"domain-your-contact-information",
|
||||||
"domain-security-email",
|
"domain-security-email",
|
||||||
]:
|
]:
|
||||||
|
@ -1077,6 +1078,7 @@ class TestDomainPermissions(TestWithDomainPermissions):
|
||||||
"domain-users",
|
"domain-users",
|
||||||
"domain-users-add",
|
"domain-users-add",
|
||||||
"domain-nameservers",
|
"domain-nameservers",
|
||||||
|
"domain-authorizing-official",
|
||||||
"domain-your-contact-information",
|
"domain-your-contact-information",
|
||||||
"domain-security-email",
|
"domain-security-email",
|
||||||
]:
|
]:
|
||||||
|
@ -1087,12 +1089,6 @@ class TestDomainPermissions(TestWithDomainPermissions):
|
||||||
)
|
)
|
||||||
self.assertEqual(response.status_code, 403)
|
self.assertEqual(response.status_code, 403)
|
||||||
|
|
||||||
with less_console_noise():
|
|
||||||
response = self.client.get(
|
|
||||||
reverse("domain-security-email", kwargs={"pk": self.domain.id})
|
|
||||||
)
|
|
||||||
self.assertEqual(response.status_code, 403)
|
|
||||||
|
|
||||||
|
|
||||||
class TestDomainDetail(TestWithDomainPermissions, WebTest):
|
class TestDomainDetail(TestWithDomainPermissions, WebTest):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
@ -1301,6 +1297,24 @@ class TestDomainDetail(TestWithDomainPermissions, WebTest):
|
||||||
# the field.
|
# the field.
|
||||||
self.assertContains(result, "This field is required", count=2, status_code=200)
|
self.assertContains(result, "This field is required", count=2, status_code=200)
|
||||||
|
|
||||||
|
def test_domain_authorizing_official(self):
|
||||||
|
"""Can load domain's authorizing official page."""
|
||||||
|
page = self.client.get(
|
||||||
|
reverse("domain-authorizing-official", kwargs={"pk": self.domain.id})
|
||||||
|
)
|
||||||
|
# once on the sidebar, once in the title
|
||||||
|
self.assertContains(page, "Authorizing official", count=2)
|
||||||
|
|
||||||
|
def test_domain_authorizing_official_content(self):
|
||||||
|
"""Authorizing official information appears on the page."""
|
||||||
|
self.domain_information.authorizing_official = Contact(first_name="Testy")
|
||||||
|
self.domain_information.authorizing_official.save()
|
||||||
|
self.domain_information.save()
|
||||||
|
page = self.app.get(
|
||||||
|
reverse("domain-authorizing-official", kwargs={"pk": self.domain.id})
|
||||||
|
)
|
||||||
|
self.assertContains(page, "Testy")
|
||||||
|
|
||||||
def test_domain_your_contact_information(self):
|
def test_domain_your_contact_information(self):
|
||||||
"""Can load domain's your contact information page."""
|
"""Can load domain's your contact information page."""
|
||||||
page = self.client.get(
|
page = self.client.get(
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
from .application import *
|
from .application import *
|
||||||
from .domain import (
|
from .domain import (
|
||||||
DomainView,
|
DomainView,
|
||||||
|
DomainAuthorizingOfficialView,
|
||||||
DomainNameserversView,
|
DomainNameserversView,
|
||||||
DomainYourContactInformationView,
|
DomainYourContactInformationView,
|
||||||
DomainSecurityEmailView,
|
DomainSecurityEmailView,
|
||||||
|
|
|
@ -15,6 +15,7 @@ from django.urls import reverse
|
||||||
from django.views.generic.edit import FormMixin
|
from django.views.generic.edit import FormMixin
|
||||||
|
|
||||||
from registrar.models import (
|
from registrar.models import (
|
||||||
|
Domain,
|
||||||
DomainInvitation,
|
DomainInvitation,
|
||||||
User,
|
User,
|
||||||
UserDomainRole,
|
UserDomainRole,
|
||||||
|
@ -40,6 +41,48 @@ class DomainView(DomainPermissionView):
|
||||||
template_name = "domain_detail.html"
|
template_name = "domain_detail.html"
|
||||||
|
|
||||||
|
|
||||||
|
class DomainAuthorizingOfficialView(DomainPermissionView, FormMixin):
|
||||||
|
|
||||||
|
"""Domain authorizing official editing view."""
|
||||||
|
|
||||||
|
model = Domain
|
||||||
|
template_name = "domain_authorizing_official.html"
|
||||||
|
context_object_name = "domain"
|
||||||
|
form_class = ContactForm
|
||||||
|
|
||||||
|
def get_form_kwargs(self, *args, **kwargs):
|
||||||
|
"""Add domain_info.authorizing_official instance to make a bound form."""
|
||||||
|
form_kwargs = super().get_form_kwargs(*args, **kwargs)
|
||||||
|
form_kwargs["instance"] = self.get_object().domain_info.authorizing_official
|
||||||
|
return form_kwargs
|
||||||
|
|
||||||
|
def get_success_url(self):
|
||||||
|
"""Redirect to the overview page for the domain."""
|
||||||
|
return reverse("domain-authorizing-official", kwargs={"pk": self.object.pk})
|
||||||
|
|
||||||
|
def post(self, request, *args, **kwargs):
|
||||||
|
"""Form submission posts to this view.
|
||||||
|
|
||||||
|
This post method harmonizes using DetailView and FormMixin together.
|
||||||
|
"""
|
||||||
|
self.object = self.get_object()
|
||||||
|
form = self.get_form()
|
||||||
|
if form.is_valid():
|
||||||
|
return self.form_valid(form)
|
||||||
|
else:
|
||||||
|
return self.form_invalid(form)
|
||||||
|
|
||||||
|
def form_valid(self, form):
|
||||||
|
"""The form is valid, save the authorizing official."""
|
||||||
|
form.save()
|
||||||
|
|
||||||
|
messages.success(
|
||||||
|
self.request, "The authorizing official for this domain has been updated."
|
||||||
|
)
|
||||||
|
# superclass has the redirect
|
||||||
|
return super().form_valid(form)
|
||||||
|
|
||||||
|
|
||||||
class DomainNameserversView(DomainPermissionView, FormMixin):
|
class DomainNameserversView(DomainPermissionView, FormMixin):
|
||||||
|
|
||||||
"""Domain nameserver editing view."""
|
"""Domain nameserver editing view."""
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue