Skip to content

Commit

Permalink
Tribal Audit Consent Form (#2238)
Browse files Browse the repository at this point in the history
* Tribal audit consent form, first pass

* What is code without linting?

* Rename files/classes. Update to match Figma.

* no-late-changes id change.

* Djlint autoformat tribal data release

* Title, not date.

* Name/title side by side. Title moved out of grey box

* Fix grey box boundary. Underline grey box title

* We out here, linting python files

* Validate against schema on upload. Copy updates

* Checklist tribal data release description

* add function for tribal audit form+add to full sub

* tribal data consent cross-val

* Grey box encompasses all questions

* Remove-old-wkbks-edit tri-audit-form+gen-info.js

* tribal data consent cross-val (#2283)

* add two functions for tribal audi public & private

* Submission Progress Check - Tribal Data Release (#2310)

* Submission progress check - tribal data release

* Edit link for tribal data release.

* Tribal release above validation

* Don't err if no auditee certifier is found.

* remove is_public from audit model (#2319)

* Cypress - New Report ID Format and Tribal Fix (#2366)

* Remove pre-release instructions from prod deploy notes (#2328)

* Resume mocking SAM.gov call (#2360)

We meant to mock this and when we changed to using requests.session
we missed updating the mock call in api/test_views.py.
This wasn't detected because the actual call to SAM.gov would
work—until this week, when the larger volume of SAM.gov API calls
from actual users as well as our tests pushed us past the rate limit.

Co-authored-by: Tadhg O'Higgins <[email protected]>

* Tribal - sign out/in as auditee, then as auditor

* Cypress - New regex for report_ids

* Oops, committed a local JWT.

* Change tribal audit to private and not in API

---------

Co-authored-by: Dan Swick <[email protected]>
Co-authored-by: Tadhg O'Higgins <[email protected]>
Co-authored-by: Edward Zapata <[email protected]>

---------

Co-authored-by: Edward Zapata <[email protected]>
Co-authored-by: danswick <[email protected]>
Co-authored-by: Tadhg O'Higgins <[email protected]>
  • Loading branch information
4 people authored Oct 3, 2023
1 parent 9884d58 commit 5c75dd4
Show file tree
Hide file tree
Showing 32 changed files with 429 additions and 33 deletions.
4 changes: 4 additions & 0 deletions backend/audit/cross_validation/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ def err_missing_tribal_data_sharing_consent():
)


def err_unexpected_tribal_data_sharing_consent():
return "Tribal consent privacy flag set but non-tribal org type."


def err_certifying_contacts_should_not_match():
return "The certifying auditor and auditee should not have the same email address."

Expand Down
2 changes: 1 addition & 1 deletion backend/audit/cross_validation/sac_validation_shape.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
snake_to_camel,
)

at_root_sections = (NC.AUDIT_INFORMATION, NC.GENERAL_INFORMATION) # type: ignore
at_root_sections = (NC.AUDIT_INFORMATION, NC.GENERAL_INFORMATION, NC.TRIBAL_DATA_CONSENT) # type: ignore


def get_shaped_section(sac, section_name):
Expand Down
7 changes: 4 additions & 3 deletions backend/audit/cross_validation/submission_progress_check.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,12 @@ def submission_progress_check(sac, sar=None, crossval=True):
{
"section_sname": [snake_case name of section],
"display": "hidden"/"incomplete"/"complete",
"display": "inactive"/"incomplete"/"complete",
"completed": [bool],
"completed_by": [email],
"completed_date": [date],
}
"""
# TODO: remove these once tribal data consent are implemented:
del sac["sf_sac_sections"][NC.TRIBAL_DATA_CONSENT]

# Add the status of the SAR into the list of sections:
sac["sf_sac_sections"][NC.SINGLE_AUDIT_REPORT] = bool(sar)
Expand Down Expand Up @@ -106,6 +104,9 @@ def get_num_findings(award):
NC.ADDITIONAL_EINS: bool(general_info.get("multiple_eins_covered")),
NC.SECONDARY_AUDITORS: bool(general_info.get("secondary_auditors_exist")),
NC.SINGLE_AUDIT_REPORT: True,
NC.TRIBAL_DATA_CONSENT: bool(
general_info.get("user_provided_organization_type") == "tribal"
),
}

# The General Information has its own condition, as it can be partially completed.
Expand Down
46 changes: 42 additions & 4 deletions backend/audit/cross_validation/test_tribal_data_sharing_consent.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

from audit.models import SingleAuditChecklist

from .errors import err_missing_tribal_data_sharing_consent
from .errors import (
err_missing_tribal_data_sharing_consent,
err_unexpected_tribal_data_sharing_consent,
)
from .tribal_data_sharing_consent import tribal_data_sharing_consent
from .sac_validation_shape import sac_validation_shape

Expand Down Expand Up @@ -53,11 +56,46 @@ def test_tribal_org_with_consent(self):

sac.general_information = {"user_provided_organization_type": "tribal"}

shaped_sac = sac_validation_shape(sac)
sac.tribal_data_consent = {
"tribal_authorization_certifying_official_title": "Assistant Regional Manager",
"is_tribal_information_authorized_to_be_public": True,
"tribal_authorization_certifying_official_name": "A. Human",
}

# placeholder consent form until schema is finalized
shaped_sac["sf_sac_sections"]["tribal_data_consent"] = {"complete": True}
shaped_sac = sac_validation_shape(sac)

validation_result = tribal_data_sharing_consent(shaped_sac)

self.assertEqual(validation_result, [])

def test_non_tribal_org_with_consent(self):
"""SACS for non-tribal orgs should not pass if they have filled out a tribal consent form"""
sac = baker.make(SingleAuditChecklist)

sac.tribal_data_consent = {
"tribal_authorization_certifying_official_title": "Assistant Regional Manager",
"is_tribal_information_authorized_to_be_public": True,
"tribal_authorization_certifying_official_name": "A. Human",
}

non_tribal_org_types = [
"state",
"local",
"higher-ed",
"non-profit",
"unknown",
"none",
]

for type in non_tribal_org_types:
with self.subTest():
sac.general_information = {"user_provided_organization_type": type}

shaped_sac = sac_validation_shape(sac)

validation_result = tribal_data_sharing_consent(shaped_sac)

self.assertEqual(
validation_result,
[{"error": err_unexpected_tribal_data_sharing_consent()}],
)
28 changes: 26 additions & 2 deletions backend/audit/cross_validation/tribal_data_sharing_consent.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
from .errors import err_missing_tribal_data_sharing_consent
from .errors import (
err_missing_tribal_data_sharing_consent,
err_unexpected_tribal_data_sharing_consent,
)


def tribal_data_sharing_consent(sac_dict, *_args, **_kwargs):
Expand All @@ -11,12 +14,33 @@ def tribal_data_sharing_consent(sac_dict, *_args, **_kwargs):
"user_provided_organization_type"
)

required_fields = (
"tribal_authorization_certifying_official_title",
"is_tribal_information_authorized_to_be_public",
"tribal_authorization_certifying_official_name",
)
must_be_truthy_fields = (
"tribal_authorization_certifying_official_title",
"tribal_authorization_certifying_official_name",
)
if organization_type == "tribal":
if not (tribal_data_consent := all_sections.get("tribal_data_consent")):
return [{"error": err_missing_tribal_data_sharing_consent()}]

# this should check for consent form completeness once form data structure is finalized
if not tribal_data_consent["complete"]:
for rfield in required_fields:
if rfield not in tribal_data_consent:
return [{"error": err_missing_tribal_data_sharing_consent()}]
for tfield in must_be_truthy_fields:
if not tribal_data_consent.get(tfield):
return [{"error": err_missing_tribal_data_sharing_consent()}]
if not tribal_data_consent.get(
"is_tribal_information_authorized_to_be_public"
) in (True, False):
return [{"error": err_missing_tribal_data_sharing_consent()}]

# this shouldn't be possible now, but may be in the future
elif tc := all_sections.get("tribal_data_consent"):
if tc.get("is_tribal_information_authorized_to_be_public"):
return [{"error": err_unexpected_tribal_data_sharing_consent()}]
return []
20 changes: 20 additions & 0 deletions backend/audit/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,3 +135,23 @@ class AuditeeCertificationStep2Form(forms.Form):
auditee_name = forms.CharField()
auditee_title = forms.CharField()
auditee_certification_date_signed = forms.DateField()


class TribalAuditConsentForm(forms.Form):
def clean_booleans(self):
data = self.cleaned_data
for k, v in data.items():
if v == ["True"]:
data[k] = True
elif v == ["False"]:
data[k] = False
self.cleaned_data = data
return data

choices_YoN = (("True", "Yes"), ("False", "No"))

is_tribal_information_authorized_to_be_public = forms.MultipleChoiceField(
choices=choices_YoN
)
tribal_authorization_certifying_official_name = forms.CharField()
tribal_authorization_certifying_official_title = forms.CharField()
6 changes: 2 additions & 4 deletions backend/audit/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -563,10 +563,6 @@ def is_auditor_certified(self):
def is_submitted(self):
return self.submission_status in [SingleAuditChecklist.STATUS.SUBMITTED]

@property
def is_public(self):
return self.general_information["user_provided_organization_type"] != "tribal"

def get_transition_date(self, status):
index = self.transition_name.index(status)
if index >= 0:
Expand Down Expand Up @@ -770,6 +766,7 @@ class EventType:
NOTES_TO_SEFA_UPDATED = "notes-to-sefa-updated"
SECONDARY_AUDITORS_UPDATED = "secondary-auditors-updated"
SUBMITTED = "submitted"
TRIBAL_CONSENT_UPDATED = "tribal-consent-updated"

EVENT_TYPES = (
(EventType.ACCESS_GRANTED, _("Access granted")),
Expand Down Expand Up @@ -805,6 +802,7 @@ class EventType:
(EventType.NOTES_TO_SEFA_UPDATED, _("Notes to SEFA updated")),
(EventType.SECONDARY_AUDITORS_UPDATED, _("Secondary auditors updated")),
(EventType.SUBMITTED, _("Submitted to the FAC for processing")),
(EventType.TRIBAL_CONSENT_UPDATED, _("Tribal audit consent updated")),
)

sac = models.ForeignKey(SingleAuditChecklist, on_delete=models.CASCADE)
Expand Down
2 changes: 1 addition & 1 deletion backend/audit/templates/audit/no-late-changes.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<form class="usa-form usa-form--large" id="ready-for-certification" method="post">
{% csrf_token %}
<fieldset class="usa-fieldset">
<legend class="usa-legend usa-legend--large" id="federal-awards">
<legend class="usa-legend usa-legend--large" id="access-denied">
Access denied
</legend>
<p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,67 @@
</div>
</div>
</div>

{% comment %} Tribal data release consent {% endcomment %}
{% comment %}
Five display cases:
1. Does not appear at all for non-tribal entities.
2. The auditee certifying official sees the link and can complete it.
3. The form is complete. The auditee certifying official can edit it.
4. Anyone else with access sees an inactive section, no link.
5. The form is complete. Anyone else with access sees that it's done but still can't click a link.
{% endcomment %}
{% comment %} 1. Does not appear at all for non-tribal entities. {% endcomment %}
{% if user_provided_organization_type == "tribal" %}
<li class="usa-icon-list__item padding-bottom-105" id="tribal_consent-completed">
{% if not is_tribal_data_consent_complete %}
{% comment %} 2. The auditee certifying official sees the link and can complete it. {% endcomment %}
{% if is_user_auditee_certifier %}
{% include './icon-list-icon.html' with completed=False %}
<div>
<p class="text-bold margin-0">
<a class="usa-link"
href="{% url 'audit:TribalAuditConsent' report_id %}">Tribal data release</a>
</p>
<p class="margin-0">Auditees must opt in or opt out of making their reporting package publicly available.</p>
</div>
{% comment %} 4. Anyone else with access sees an inactive section, no link. {% endcomment %}
{% else %}
{% include './icon-list-icon.html' with completed=False %}
<div>
<p class="text-bold margin-0">Tribal data release</p>
<p class="margin-0">
Auditees must opt in or opt out of making their reporting package publicly available.
</p>
</div>
{% endif %}
{% else %}
{% comment %} 3. The form is complete. The auditee certifying official can edit it. {% endcomment %}
{% if is_user_auditee_certifier %}
{% include './icon-list-icon.html' with completed=True %}
<div class="text-success-darker">
<p class="text-bold text-underline margin-0">Tribal data release (Complete)</p>
<p class="margin-0">
Auditees must opt in or opt out of making their reporting package publicly available.
</p>
<p class="margin-0">
<a class="usa-link"
href="{% url 'audit:TribalAuditConsent' report_id %}">Edit the Tribal data release form</a>
</p>
</div>
{% comment %} 5. The form is complete. Anyone else with access sees that it's done but still can't click a link. {% endcomment %}
{% else %}
{% include './icon-list-icon.html' with completed=True %}
<div>
<p class="text-bold margin-0">Tribal data release (Complete)</p>
<p class="margin-0">
Auditees must opt in or opt out of making their reporting package publicly available.
</p>
</div>
{% endif %}
{% endif %}
</li>
{% endif %}

{% comment %} Pre-submission validation {% endcomment %}
<li class="usa-icon-list__item padding-bottom-105" id="SF-SAC-completed">
Expand Down
Loading

0 comments on commit 5c75dd4

Please sign in to comment.