-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Change auditee/auditor certifying official (#2891)
* Add GET side of page for changing Auditor Certifying Official. * Add POST side of page for changing Auditor Certifying Official. * Remove stray import. * Add page for changing Auditee Certifying Official. * Use variable for role in template instead of hard-coding. * Typo correction.
- Loading branch information
1 parent
8b65c09
commit 7bd8af9
Showing
5 changed files
with
351 additions
and
0 deletions.
There are no files selected for viewing
44 changes: 44 additions & 0 deletions
44
backend/audit/templates/audit/manage-submission-change-access.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
{% extends "base.html" %} | ||
{% load static %} | ||
{% block content %} | ||
<div class="grid-container margin-top-6"> | ||
<div class="grid-row"> | ||
<form class="grid-col-8 grid-offset-2" | ||
id="auditor-certification-step-2" | ||
method="post"> | ||
{% csrf_token %} | ||
<fieldset class="usa-fieldset padding-bottom-2"> | ||
<h1 id="auditor-certification">Change {{ friendly_role }}</h1> | ||
<h3>Current {{ friendly_role }}</h3> | ||
|
||
<p>Name: {{ certifier_name }}</p> | ||
|
||
<p>Email: <code>{{ email }}</code></p> | ||
|
||
<hr /> | ||
|
||
{% if errors %} | ||
<ul> | ||
{% for error in errors %} | ||
<li class="usa-error-message">{{ error }}</li> | ||
{% endfor %} | ||
</ul> | ||
{% endif %} | ||
|
||
<label class="usa-label" for="fullname">Name of new {{ friendly_role }}</label> | ||
<input class="usa-input" | ||
id="name" | ||
name="fullname" | ||
placeholder="[name]" /> | ||
<label class="usa-label" for="email">Email address of new {{ friendly_role }}</label> | ||
<input class="usa-input" | ||
id="email" | ||
name="email" | ||
placeholder="[email address]" /> | ||
</fieldset> | ||
<button class="usa-button margin-bottom-8 margin-top-4" id="continue">Remove {{ email }} from the {{ friendly_role }} role for this submission and replace them with the above user.</button> | ||
</form> | ||
</div> | ||
</div> | ||
{% include "audit-metadata.html" %} | ||
{% endblock content %} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
from django.contrib.auth.models import User as DjangoUser | ||
from django.test import TestCase | ||
from django.urls import reverse | ||
|
||
from model_bakery import baker | ||
from .models import ( | ||
Access, | ||
DeletedAccess, | ||
SingleAuditChecklist, | ||
User, | ||
) | ||
|
||
|
||
def _make_test_users_by_email(emails: list[str]) -> list[DjangoUser]: | ||
return [baker.make(User, email=email) for email in emails] | ||
|
||
|
||
def _make_access(sac: SingleAuditChecklist, role: str, user: DjangoUser) -> Access: | ||
return baker.make(Access, user=user, email=user.email, sac=sac, role=role) | ||
|
||
|
||
def _make_user_and_sac(**kwargs): | ||
user = baker.make(User) | ||
sac = baker.make(SingleAuditChecklist, **kwargs) | ||
return user, sac | ||
|
||
|
||
class ChangeAuditorCertifyingOfficialViewTests(TestCase): | ||
""" | ||
GET and POST tests for changing auditor certifying official. | ||
""" | ||
|
||
role = "certifying_auditor_contact" | ||
other_role = "certifying_auditee_contact" | ||
view = "audit:ChangeAuditorCertifyingOfficial" | ||
|
||
def test_basic_get(self): | ||
""" | ||
A user should be able to access this page for a SAC they're associated with. | ||
""" | ||
user, sac = _make_user_and_sac() | ||
baker.make(Access, user=user, sac=sac, role="editor") | ||
sac.general_information = {"auditee_uei": "YESIAMAREALUEI"} | ||
sac.save() | ||
current_cac = baker.make(Access, sac=sac, role=self.role) | ||
|
||
self.client.force_login(user) | ||
url = reverse(self.view, kwargs={"report_id": sac.report_id}) | ||
response = self.client.get(url) | ||
|
||
self.assertEqual(response.status_code, 200) | ||
self.assertIn("YESIAMAREALUEI", response.content.decode("UTF-8")) | ||
self.assertIn(current_cac.email, response.content.decode("UTF-8")) | ||
|
||
def test_basic_post(self): | ||
""" | ||
Submitting the form with a new email address should delete the existing | ||
Access, create a DeletedAccess, and create a new Access. | ||
""" | ||
user = baker.make(User, email="[email protected]") | ||
sac = baker.make(SingleAuditChecklist) | ||
baker.make(Access, user=user, sac=sac, role="editor") | ||
baker.make( | ||
Access, | ||
sac=sac, | ||
role=self.other_role, | ||
email="[email protected]", | ||
) | ||
sac.general_information = {"auditee_uei": "YESIAMAREALUEI"} | ||
sac.save() | ||
current_cac = baker.make(Access, sac=sac, role=self.role) | ||
|
||
self.client.force_login(user) | ||
|
||
data = { | ||
"fullname": "The New CAC", | ||
"email": "[email protected]", | ||
} | ||
|
||
url = reverse(self.view, kwargs={"report_id": sac.report_id}) | ||
response = self.client.post(url, data=data) | ||
self.assertEqual(302, response.status_code) | ||
|
||
newaccess = Access.objects.get( | ||
sac=sac, fullname=data["fullname"], email=data["email"] | ||
) | ||
self.assertEqual(self.role, newaccess.role) | ||
oldaccess = DeletedAccess.objects.get( | ||
sac=sac, | ||
fullname=current_cac.fullname, | ||
email=current_cac.email, | ||
) | ||
self.assertEqual(self.role, oldaccess.role) | ||
|
||
def test_bad_email_post(self): | ||
""" | ||
Submitting an email address that's already in use for the other role should | ||
result in a 400 and returning to the form page. | ||
""" | ||
new_email = "[email protected]" | ||
user = baker.make(User, email="[email protected]") | ||
sac = baker.make(SingleAuditChecklist) | ||
baker.make(Access, user=user, sac=sac, role="editor") | ||
baker.make(Access, sac=sac, role=self.other_role, email=new_email) | ||
baker.make(Access, sac=sac, role=self.role) | ||
sac.general_information = {"auditee_uei": "YESIAMAREALUEI"} | ||
sac.save() | ||
|
||
self.client.force_login(user) | ||
|
||
data = {"fullname": "The New CAC", "email": new_email} | ||
|
||
url = reverse(self.view, kwargs={"report_id": sac.report_id}) | ||
response = self.client.post(url, data=data) | ||
self.assertEqual(400, response.status_code) | ||
|
||
def test_login_required(self): | ||
"""When an unauthenticated request is made""" | ||
|
||
response = self.client.get( | ||
reverse( | ||
self.view, | ||
kwargs={"report_id": "12345"}, | ||
) | ||
) | ||
|
||
self.assertEqual(response.status_code, 403) | ||
|
||
def test_bad_report_id_returns_403(self): | ||
""" | ||
When a request is made for a malformed or nonexistent report_id, | ||
a 403 error should be returned | ||
""" | ||
user = baker.make(User) | ||
|
||
self.client.force_login(user) | ||
|
||
response = self.client.get( | ||
reverse(self.view, kwargs={"report_id": "this is not a report id"}) | ||
) | ||
|
||
self.assertEqual(response.status_code, 403) | ||
|
||
def test_inaccessible_audit_returns_403(self): | ||
"""When a request is made for an audit that is inaccessible for this user, a 403 error should be returned""" | ||
user, sac = _make_user_and_sac() | ||
|
||
self.client.force_login(user) | ||
response = self.client.post( | ||
reverse(self.view, kwargs={"report_id": sac.report_id}) | ||
) | ||
|
||
self.assertEqual(response.status_code, 403) | ||
|
||
|
||
class ChangeAuditeeCertifyingOfficialViewTests( | ||
ChangeAuditorCertifyingOfficialViewTests | ||
): | ||
""" | ||
GET and POST tests for changing auditee certifying official. | ||
""" | ||
|
||
role = "certifying_auditee_contact" | ||
other_role = "certifying_auditor_contact" | ||
view = "audit:ChangeAuditeeCertifyingOfficial" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
from django import forms | ||
from django.db import transaction | ||
from django.shortcuts import redirect, render, reverse | ||
from django.views import generic | ||
|
||
from audit.mixins import ( | ||
SingleAuditChecklistAccessRequiredMixin, | ||
) | ||
from audit.models import ( | ||
ACCESS_ROLES, | ||
Access, | ||
SingleAuditChecklist, | ||
) | ||
|
||
|
||
class ChangeAccessForm(forms.Form): | ||
""" | ||
Form for changing access. The view class, not this class, has the responsibility for handling whether we’re deleting access (in the cases where only one user can have the role) or adding access (in the cases where multiple users can have the role). | ||
""" | ||
|
||
fullname = forms.CharField() | ||
email = forms.EmailField() | ||
# email_confirm = forms.EmailField() | ||
|
||
# def clean(self): | ||
# cleaned = super().clean() | ||
# if cleaned.get("email") != cleaned.get("email_confirm"): | ||
# raise ValidationError( | ||
# "Email address and confirmed email address must match" | ||
# ) | ||
|
||
|
||
class ChangeAuditorCertifyingOfficialView( | ||
SingleAuditChecklistAccessRequiredMixin, generic.View | ||
): | ||
""" | ||
View for changing the auditor certifying official | ||
""" | ||
|
||
role = "certifying_auditor_contact" | ||
other_role = "certifying_auditee_contact" | ||
|
||
def get(self, request, *args, **kwargs): | ||
""" | ||
Show the current auditor certifying official and the form. | ||
""" | ||
report_id = kwargs["report_id"] | ||
sac = SingleAuditChecklist.objects.get(report_id=report_id) | ||
access = Access.objects.get(sac=sac, role=self.role) | ||
friendly_role = [r for r in ACCESS_ROLES if r[0] == self.role][0][1] | ||
context = { | ||
"role": self.role, | ||
"friendly_role": friendly_role, | ||
"auditee_uei": sac.general_information["auditee_uei"], | ||
"auditee_name": sac.general_information.get("auditee_name"), | ||
"certifier_name": access.fullname, | ||
"email": access.email, | ||
"report_id": report_id, | ||
"errors": [], | ||
} | ||
|
||
return render(request, "audit/manage-submission-change-access.html", context) | ||
|
||
def post(self, request, *args, **kwargs): | ||
""" | ||
Change the current auditor certifying official and redirect to submission | ||
progress. | ||
""" | ||
report_id = kwargs["report_id"] | ||
sac = SingleAuditChecklist.objects.get(report_id=report_id) | ||
form = ChangeAccessForm(request.POST) | ||
form.full_clean() | ||
url = reverse("audit:SubmissionProgress", kwargs={"report_id": report_id}) | ||
|
||
if not self.other_role: | ||
Access( | ||
sac=sac, | ||
role=self.role, | ||
fullname=form.cleaned_data["fullname"], | ||
email=form.cleaned_data["email"], | ||
).save() | ||
return redirect(url) | ||
|
||
access = Access.objects.get(sac=sac, role=self.role) | ||
other_access = Access.objects.get(sac=sac, role=self.other_role) | ||
if form.cleaned_data["email"] == other_access.email: | ||
friendly_role = [r for r in ACCESS_ROLES if r[0] == self.role][0][1] | ||
context = { | ||
"role": self.role, | ||
"friendly_role": friendly_role, | ||
"auditee_uei": sac.general_information["auditee_uei"], | ||
"auditee_name": sac.general_information.get("auditee_name"), | ||
"certifier_name": access.fullname, | ||
"email": access.email, | ||
"report_id": report_id, | ||
"errors": [ | ||
"Cannot use the same email address for both certifying officials." | ||
], | ||
} | ||
return render( | ||
request, | ||
"audit/manage-submission-change-access.html", | ||
context, | ||
status=400, | ||
) | ||
|
||
with transaction.atomic(): | ||
access.delete(removing_user=request.user, removal_event="access-change") | ||
|
||
Access( | ||
sac=sac, | ||
role=self.role, | ||
fullname=form.cleaned_data["fullname"], | ||
email=form.cleaned_data["email"], | ||
).save() | ||
|
||
return redirect(url) | ||
|
||
|
||
class ChangeAuditeeCertifyingOfficialView(ChangeAuditorCertifyingOfficialView): | ||
""" | ||
View for changing the auditee certifying official | ||
""" | ||
|
||
role = "certifying_auditee_contact" | ||
other_role = "certifying_auditor_contact" |