Audit firm/organization address
@@ -370,18 +392,18 @@ Primary auditor information
Country
-
- USA
-
-
- non-USA
-
+ id="auditor_country"
+ name="auditor_country">
+
+ USA
+
+
+ non-USA
+
+ {{ errors.auditor_country|space_before_striptags }}
@@ -392,6 +414,7 @@ Primary auditor information
name="auditor_international_address"
aria-required="false"
data-validate-not-null="">{{ auditor_international_address | default_if_none:'' }}
+ {{ errors.auditor_international_address|space_before_striptags }}
@@ -402,6 +425,7 @@ Primary auditor information
name="auditor_address_line_1"
aria-required="false"
value="{{ auditor_address_line_1 | default_if_none:'' }}" />
+ {{ errors.auditor_address_line_1|space_before_striptags }}
@@ -412,7 +436,7 @@ Primary auditor information
name="auditor_city"
aria-required="false"
value="{{ auditor_city | default_if_none:'' }}" />
- {{ errors.auditor_city|striptags }}
+ {{ errors.auditor_city|space_before_striptags }}
@@ -432,6 +456,7 @@ Primary auditor information
{% endfor %}
+ {{ errors.auditor_state|space_before_striptags }}
@@ -442,7 +467,7 @@ Primary auditor information
name="auditor_zip"
aria-required="false"
value="{{ auditor_zip | default_if_none:'' }}" />
- {{ errors.auditor_zip|striptags }}
+ {{ errors.auditor_zip|space_before_striptags }}
@@ -455,6 +480,7 @@
diff --git a/backend/report_submission/templates/report_submission/step-3.html b/backend/report_submission/templates/report_submission/step-3.html
index 9394fc637..780ca7341 100644
--- a/backend/report_submission/templates/report_submission/step-3.html
+++ b/backend/report_submission/templates/report_submission/step-3.html
@@ -38,13 +38,15 @@
id="certifying_auditee_contact_fullname-error-message"
role="alert">
Please enter the certifying official's first and last names.
+ Please enter a name between two and 100 characters long.
+ data-validate-not-null=""
+ data-validate-length="<= 100 >= 2"/>
@@ -62,6 +64,7 @@
An email address should have a username, an '@' symbol, and a domain name
{{ certifiers_emails_must_not_match }}
+ Please enter an email between six and 340 characters long.
+ data-validate-must-not-match="certifying_auditor_contact_email"
+ data-validate-length="<= 340 >= 6"/>
@@ -83,13 +87,15 @@
id="certifying_auditee_contact_re_email-error-message"
role="alert">
This field should match the one before it
+ Please enter an email between six and 340 characters long.
+ data-validate-must-match="certifying_auditee_contact_email"
+ data-validate-length="<= 340 >= 6"/>
@@ -116,13 +122,15 @@
id="certifying_auditor_contact_fullname-error-message"
role="alert">
Please enter the certifying official's first and last names.
+ Please enter a name between two and 100 characters long.
+ data-validate-not-null=""
+ data-validate-length="<= 100 >= 2"/>
@@ -140,6 +148,7 @@
An email address should have a username, an '@' symbol, and a domain name
{{ certifiers_emails_must_not_match }}
+ Please enter an email between six and 340 characters long.
+ data-validate-must-not-match="certifying_auditee_contact_email"
+ data-validate-length="<= 340 >= 6"/>
@@ -161,13 +171,15 @@
id="certifying_auditor_contact_re_email-error-message"
role="alert">
This field should match the one before it
+ Please enter an email between six and 340 characters long.
+ data-validate-must-match="certifying_auditor_contact_email"
+ data-validate-length="<= 340 >= 6"/>
@@ -191,13 +203,15 @@
-
+ data-validate-not-null=""
+ data-validate-length="<= 100 >= 2"/>
+
@@ -229,11 +245,13 @@
id="auditee_contacts_re_email-error-message"
role="alert">
This field should match the one before it
+ Please enter an email between six and 340 characters long.
+ data-validate-must-match="auditee_contacts_email"
+ data-validate-length="<= 340 >= 6"/>
@@ -248,13 +266,15 @@
+ When adding an auditee contact, please provide both an email address and a first and last name.
+ Please enter a name between two and 100 characters long.
+
-
+ data-validate-not-null=""
+ data-validate-length="<= 100 >= 2"/>
+
@@ -332,11 +356,13 @@
id="auditor_contacts_fullname-error-message"
role="alert">
When adding an auditor contact, please provide both an email address and a first and last name.
+ Please enter a name between two and 100 characters long.
+ data-validate-matched-field="auditor_contacts_email"
+ data-validate-length="<= 100 >= 2"/>
@@ -351,13 +377,14 @@
An email address should have a username, an '@' symbol, and a domain name
- When adding an auditor contact, please provide both an email address and a first and last name.
+ When adding an auditor contact, please provide both an email address and a first and last name.
+ Please enter an email between six and 340 characters long.
+ data-validate-length="<= 340 >= 6"/>
@@ -369,11 +396,13 @@
id="auditor_contacts_re_email-error-message"
role="alert">
This field should match the one before it
+ Please enter an email between six and 340 characters long.
+ data-validate-must-match="auditor_contacts_email"
+ data-validate-length="<= 340 >= 6"/>
@@ -389,11 +418,13 @@
id="auditor_contacts_fullname-error-message"
role="alert">
When adding an auditor contact, please provide both an email address and a first and last name.
+ Please enter a name between two and 100 characters long.
+ data-validate-matched-field="auditor_contacts_email"
+ data-validate-length="<= 100 >= 2"/>
@@ -408,13 +439,14 @@
An email address should have a username, an '@' symbol, and a domain name
- When adding an auditor contact, please provide both an email address and a first and last name.
+ When adding an auditor contact, please provide both an email address and a first and last name.
+ Please enter an email between six and 340 characters long.
+ data-validate-length="<= 340 >= 6"/>
@@ -426,11 +458,13 @@
id="auditor_contacts_re_email-error-message"
role="alert">
This field should match the one before it
+ Please enter an email between six and 340 characters long.
+ data-validate-must-match="auditor_contacts_email"
+ data-validate-length="<= 340 >= 6"/>
diff --git a/backend/report_submission/templatetags/space_before_striptags.py b/backend/report_submission/templatetags/space_before_striptags.py
new file mode 100644
index 000000000..d43071d3a
--- /dev/null
+++ b/backend/report_submission/templatetags/space_before_striptags.py
@@ -0,0 +1,22 @@
+"""
+Custom tag to add spaces between list items when using `striptags`.
+Example:
+"An error. Another error. "
+"An error. Another error."
+"""
+
+from django import template
+from django.utils.html import strip_tags
+
+register = template.Library()
+
+
+@register.filter(name="space_before_striptags")
+def space_before_striptags(value):
+ result = str(value)
+
+ result = result.replace("", " ")
+ result = strip_tags(result)
+ result = result.strip()
+
+ return result
diff --git a/backend/report_submission/views.py b/backend/report_submission/views.py
index ab244a3d8..866355828 100644
--- a/backend/report_submission/views.py
+++ b/backend/report_submission/views.py
@@ -240,10 +240,12 @@ def post(self, request, *args, **kwargs):
except SingleAuditChecklist.DoesNotExist as err:
raise PermissionDenied("You do not have access to this audit.") from err
except ValidationError as err:
+ form.cleaned_data = self._dates_to_slashes(form.cleaned_data)
context = form.cleaned_data | {
"errors": [err.message],
"report_id": report_id,
"state_abbrevs": STATE_ABBREVS,
+ "unexpected_errors": True,
}
return render(request, "report_submission/gen-form.html", context)
except LateChangeError:
diff --git a/backend/schemas/output/sections/GeneralInformation.schema.json b/backend/schemas/output/sections/GeneralInformation.schema.json
index 24edbb5a5..5e4e26891 100644
--- a/backend/schemas/output/sections/GeneralInformation.schema.json
+++ b/backend/schemas/output/sections/GeneralInformation.schema.json
@@ -15,7 +15,9 @@
"type": "string"
},
"audit_period_other_months": {
- "pattern": "^0[0-9]|1[0-8]$",
+ "maxLength": 2,
+ "minLength": 0,
+ "pattern": "^0?[1-9]$|^1[0-8]$",
"type": "string"
},
"audit_type": {
@@ -37,25 +39,30 @@
},
"auditee_address_line_1": {
"maxLength": 100,
+ "minLength": 2,
"type": "string"
},
"auditee_city": {
"maxLength": 100,
+ "minLength": 2,
"type": "string"
},
"auditee_contact_name": {
"maxLength": 100,
+ "minLength": 2,
"type": "string"
},
"auditee_contact_title": {
"maxLength": 100,
+ "minLength": 2,
"type": "string"
},
"auditee_email": {
"oneOf": [
{
"format": "email",
- "maxLength": 100,
+ "maxLength": 320,
+ "minLength": 6,
"type": "string"
},
{
@@ -73,6 +80,7 @@
},
"auditee_name": {
"maxLength": 100,
+ "minLength": 2,
"type": "string"
},
"auditee_phone": {
@@ -183,20 +191,22 @@
},
"auditor_address_line_1": {
"maxLength": 100,
- "minLength": 1,
+ "minLength": 0,
"type": "string"
},
"auditor_city": {
"maxLength": 100,
- "minLength": 1,
+ "minLength": 0,
"type": "string"
},
"auditor_contact_name": {
"maxLength": 100,
+ "minLength": 2,
"type": "string"
},
"auditor_contact_title": {
"maxLength": 100,
+ "minLength": 2,
"type": "string"
},
"auditor_country": {
@@ -227,7 +237,8 @@
"oneOf": [
{
"format": "email",
- "maxLength": 100,
+ "maxLength": 320,
+ "minLength": 6,
"type": "string"
},
{
@@ -238,11 +249,12 @@
},
"auditor_firm_name": {
"maxLength": 100,
+ "minLength": 2,
"type": "string"
},
"auditor_international_address": {
- "maxLength": 500,
- "minLength": 1,
+ "maxLength": 100,
+ "minLength": 0,
"type": "string"
},
"auditor_phone": {
diff --git a/backend/schemas/output/sections/GeneralInformationRequired.schema.json b/backend/schemas/output/sections/GeneralInformationRequired.schema.json
index b7eeb8944..bc2eb5c39 100644
--- a/backend/schemas/output/sections/GeneralInformationRequired.schema.json
+++ b/backend/schemas/output/sections/GeneralInformationRequired.schema.json
@@ -125,7 +125,9 @@
"type": "string"
},
"audit_period_other_months": {
- "pattern": "^0[0-9]|1[0-8]$",
+ "maxLength": 2,
+ "minLength": 0,
+ "pattern": "^0?[1-9]$|^1[0-8]$",
"type": "string"
},
"audit_type": {
@@ -147,25 +149,30 @@
},
"auditee_address_line_1": {
"maxLength": 100,
+ "minLength": 2,
"type": "string"
},
"auditee_city": {
"maxLength": 100,
+ "minLength": 2,
"type": "string"
},
"auditee_contact_name": {
"maxLength": 100,
+ "minLength": 2,
"type": "string"
},
"auditee_contact_title": {
"maxLength": 100,
+ "minLength": 2,
"type": "string"
},
"auditee_email": {
"oneOf": [
{
"format": "email",
- "maxLength": 100,
+ "maxLength": 320,
+ "minLength": 6,
"type": "string"
},
{
@@ -183,6 +190,7 @@
},
"auditee_name": {
"maxLength": 100,
+ "minLength": 2,
"type": "string"
},
"auditee_phone": {
@@ -293,20 +301,22 @@
},
"auditor_address_line_1": {
"maxLength": 100,
- "minLength": 1,
+ "minLength": 0,
"type": "string"
},
"auditor_city": {
"maxLength": 100,
- "minLength": 1,
+ "minLength": 0,
"type": "string"
},
"auditor_contact_name": {
"maxLength": 100,
+ "minLength": 2,
"type": "string"
},
"auditor_contact_title": {
"maxLength": 100,
+ "minLength": 2,
"type": "string"
},
"auditor_country": {
@@ -337,7 +347,8 @@
"oneOf": [
{
"format": "email",
- "maxLength": 100,
+ "maxLength": 320,
+ "minLength": 6,
"type": "string"
},
{
@@ -348,11 +359,12 @@
},
"auditor_firm_name": {
"maxLength": 100,
+ "minLength": 2,
"type": "string"
},
"auditor_international_address": {
- "maxLength": 500,
- "minLength": 1,
+ "maxLength": 100,
+ "minLength": 0,
"type": "string"
},
"auditor_phone": {
diff --git a/backend/schemas/source/base/Base.libsonnet b/backend/schemas/source/base/Base.libsonnet
index 5a35f2ddb..8930eac24 100644
--- a/backend/schemas/source/base/Base.libsonnet
+++ b/backend/schemas/source/base/Base.libsonnet
@@ -4,6 +4,7 @@ local FederalProgramNames = import 'FederalProgramNames.json';
local Func = import 'Functions.libsonnet';
local GAAP = import 'GAAP.libsonnet';
local States = import 'States.json';
+local GeneralCharacterLimits = import './character_limits/general.json';
local Const = {
Y: 'Y',
@@ -248,7 +249,9 @@ local email_regex = "^[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-zA-Z0-9!#$%&'*+/=?
local REGEX_ZIPCODE = '^[0-9]{5}(?:[0-9]{4})?$';
local REGEX_DBKEY = '[1-9][0-9]+';
-local REGEX_MONTHS_OTHER = '^0[0-9]|1[0-8]$';
+// 0?[1-9] --> (1-9 or 01-09) OR 1[1-8] --> 10-18
+// Allows single or double digit values - 7 vs 07
+local REGEX_MONTHS_OTHER = '^0?[1-9]$|^1[0-8]$';
local type_zipcode = Types.string {
pattern: REGEX_ZIPCODE,
};
@@ -337,6 +340,8 @@ local Compound = {
Zip: type_zipcode,
MonthsOther: Types.string {
pattern: REGEX_MONTHS_OTHER,
+ minLength: GeneralCharacterLimits.number_months.min,
+ maxLength: GeneralCharacterLimits.number_months.max,
},
EmptyString: Types.string {
const: Const.empty_string,
diff --git a/backend/schemas/source/base/character_limits/README.md b/backend/schemas/source/base/character_limits/README.md
new file mode 100644
index 000000000..bb22061b1
--- /dev/null
+++ b/backend/schemas/source/base/character_limits/README.md
@@ -0,0 +1,74 @@
+# Character Limits Info
+
+
+## Overview
+
+Character limits are used here (/schemas/) in generating the schemas for validation, and in the greater application (/report_submission/, /audit/) for web form fields and the like.
+
+Character limits were determined by pulling a large amount of data from a table and making a decision based on the stats.
+
+1. Field length averages, medians, and min/max values were determined for string and int values.
+ * Floats, or other value types, are initially set to zero.
+2. Mins and maxes are separated into JSON to be included in this folder.
+3. Character limits are determined based on the mins/maxes.
+4. With outlier values, we use the average & median to make a decision.
+ * Ex. The maximum length of 31439 in notes_to_sefa.accounting_policies, when the average & median are about 500.
+
+**Most character limits will be unused initially. Maybe forever. Many fields do not have variable length, or their length is decided by factors other than user input.**
+
+## Notes on Particular Fields:
+
+### Names
+ Minimum - 2
+ Maximum - 100
+The max with CENSUS data seemed to be 100. Kept for consistency.
+
+### Emails
+ Minimum - 6
+ Maximum - 320
+'a@a.a' is 5, but names have a minimum of 2. So, 'aa@a.a' is the minimum at 6.
+The max of 320 is standard (RFC 5321 and RFC 5322).
+
+### UEIs
+ Minimum - 12
+ Maximum - 13
+UEIs are of length 12. But we have lots of 'GSA_MIGRATION' UEIs, which are of length 13.
+
+### ZIP Codes
+ Minimum - 5
+ Maximum - 9
+Either in format '12345' OR '12345-6789' with the dash removed.
+
+### Auditor Country
+ Minimum - 2
+ Maximum - 56
+Allows for the shortest acronyms. The longest possible is "The United Kingdom of Great Britain and Northern Ireland" at length 56.
+
+### GAAP Results
+ Minimum - 15
+ Maximum - 77
+The shortest possible result is just "adverse_opinion" at length 15.
+The longest possible result is every option - "unmodified_opinion, qualified_opinion, adverse_opinion, disclaimer_of_opinion" at length 77.
+
+### Audit Type
+ Minimum - 12
+ Maximum - 16
+Shortest is "single-audit" at 12. Longest is "program-specific" at 16
+
+### Yes/No Fields:
+ is_going_concern_included
+ is_internal_control_deficiency_disclosed
+ is_internal_control_material_weakness_disclosed
+ is_material_noncompliance_disclosed
+ is_low_risk_auditee
+ is_aicpa_audit_guide_included
+ is_additional_ueis
+ is_multiple_eins
+ is_secondary_auditors
+Always of length 3 or 2 ("Yes" or "No")
+
+### Static Length Fields:
+ Report IDs - 25
+ Dates - 10
+ EINs - 9
+ Cognizant/Oversight Agency - 2
\ No newline at end of file
diff --git a/backend/schemas/source/base/character_limits/additional_eins.json b/backend/schemas/source/base/character_limits/additional_eins.json
new file mode 100644
index 000000000..685f34cd1
--- /dev/null
+++ b/backend/schemas/source/base/character_limits/additional_eins.json
@@ -0,0 +1,18 @@
+{
+ "report_id": {
+ "min": 25,
+ "max": 25
+ },
+ "auditee_uei": {
+ "min": 12,
+ "max": 13
+ },
+ "audit_year": {
+ "min": 4,
+ "max": 4
+ },
+ "additional_ein": {
+ "min": 9,
+ "max": 9
+ }
+}
\ No newline at end of file
diff --git a/backend/schemas/source/base/character_limits/additional_ueis.json b/backend/schemas/source/base/character_limits/additional_ueis.json
new file mode 100644
index 000000000..3c93b2c15
--- /dev/null
+++ b/backend/schemas/source/base/character_limits/additional_ueis.json
@@ -0,0 +1,18 @@
+{
+ "report_id": {
+ "min": 25,
+ "max": 25
+ },
+ "auditee_uei": {
+ "min": 12,
+ "max": 12
+ },
+ "audit_year": {
+ "min": 4,
+ "max": 4
+ },
+ "additional_uei": {
+ "min": 12,
+ "max": 12
+ }
+}
\ No newline at end of file
diff --git a/backend/schemas/source/base/character_limits/corrective_action_plans.json b/backend/schemas/source/base/character_limits/corrective_action_plans.json
new file mode 100644
index 000000000..7b7f683e3
--- /dev/null
+++ b/backend/schemas/source/base/character_limits/corrective_action_plans.json
@@ -0,0 +1,26 @@
+{
+ "report_id": {
+ "min": 25,
+ "max": 25
+ },
+ "auditee_uei": {
+ "min": 12,
+ "max": 13
+ },
+ "audit_year": {
+ "min": 4,
+ "max": 4
+ },
+ "finding_ref_number": {
+ "min": 8,
+ "max": 8
+ },
+ "contains_chart_or_table": {
+ "min": 1,
+ "max": 13
+ },
+ "planned_action": {
+ "min": 1,
+ "max": 21741
+ }
+}
\ No newline at end of file
diff --git a/backend/schemas/source/base/character_limits/federal_awards.json b/backend/schemas/source/base/character_limits/federal_awards.json
new file mode 100644
index 000000000..a75875171
--- /dev/null
+++ b/backend/schemas/source/base/character_limits/federal_awards.json
@@ -0,0 +1,90 @@
+{
+ "report_id": {
+ "min": 25,
+ "max": 25
+ },
+ "auditee_uei": {
+ "min": 12,
+ "max": 13
+ },
+ "audit_year": {
+ "min": 4,
+ "max": 4
+ },
+ "award_reference": {
+ "min": 10,
+ "max": 10
+ },
+ "federal_agency_prefix": {
+ "min": 2,
+ "max": 2
+ },
+ "federal_award_extension": {
+ "min": 2,
+ "max": 13
+ },
+ "additional_award_identification": {
+ "min": 0,
+ "max": 241
+ },
+ "federal_program_name": {
+ "min": 0,
+ "max": 371
+ },
+ "amount_expended": {
+ "min": -447813896,
+ "max": 54873398849
+ },
+ "cluster_name": {
+ "min": 1,
+ "max": 75
+ },
+ "other_cluster_name": {
+ "min": 0,
+ "max": 111
+ },
+ "state_cluster_name": {
+ "min": 0,
+ "max": 75
+ },
+ "cluster_total": {
+ "min": -2963764,
+ "max": 54935748805
+ },
+ "federal_program_total": {
+ "min": -10726532,
+ "max": 54873398849
+ },
+ "is_major": {
+ "min": 1,
+ "max": 1
+ },
+ "is_loan": {
+ "min": 1,
+ "max": 1
+ },
+ "loan_balance": {
+ "min": 0,
+ "max": 12
+ },
+ "is_direct": {
+ "min": 1,
+ "max": 1
+ },
+ "audit_report_type": {
+ "min": 0,
+ "max": 1
+ },
+ "findings_count": {
+ "min": 0,
+ "max": 21
+ },
+ "is_passthrough_award": {
+ "min": 1,
+ "max": 1
+ },
+ "passthrough_amount": {
+ "min": 0,
+ "max": 0
+ }
+}
\ No newline at end of file
diff --git a/backend/schemas/source/base/character_limits/findings.json b/backend/schemas/source/base/character_limits/findings.json
new file mode 100644
index 000000000..88b828941
--- /dev/null
+++ b/backend/schemas/source/base/character_limits/findings.json
@@ -0,0 +1,58 @@
+{
+ "report_id": {
+ "min": 25,
+ "max": 25
+ },
+ "auditee_uei": {
+ "min": 12,
+ "max": 13
+ },
+ "audit_year": {
+ "min": 4,
+ "max": 4
+ },
+ "award_reference": {
+ "min": 10,
+ "max": 11
+ },
+ "reference_number": {
+ "min": 8,
+ "max": 8
+ },
+ "is_material_weakness": {
+ "min": 1,
+ "max": 1
+ },
+ "is_modified_opinion": {
+ "min": 1,
+ "max": 1
+ },
+ "is_other_findings": {
+ "min": 1,
+ "max": 1
+ },
+ "is_other_matters": {
+ "min": 1,
+ "max": 1
+ },
+ "prior_finding_ref_numbers": {
+ "min": 3,
+ "max": 118
+ },
+ "is_questioned_costs": {
+ "min": 1,
+ "max": 1
+ },
+ "is_repeat_finding": {
+ "min": 1,
+ "max": 1
+ },
+ "is_significant_deficiency": {
+ "min": 1,
+ "max": 1
+ },
+ "type_requirement": {
+ "min": 1,
+ "max": 13
+ }
+}
\ No newline at end of file
diff --git a/backend/schemas/source/base/character_limits/findings_text.json b/backend/schemas/source/base/character_limits/findings_text.json
new file mode 100644
index 000000000..df26d77f7
--- /dev/null
+++ b/backend/schemas/source/base/character_limits/findings_text.json
@@ -0,0 +1,26 @@
+{
+ "report_id": {
+ "min": 25,
+ "max": 25
+ },
+ "auditee_uei": {
+ "min": 12,
+ "max": 13
+ },
+ "audit_year": {
+ "min": 4,
+ "max": 4
+ },
+ "finding_ref_number": {
+ "min": 8,
+ "max": 8
+ },
+ "contains_chart_or_table": {
+ "min": 1,
+ "max": 13
+ },
+ "finding_text": {
+ "min": 1,
+ "max": 31991
+ }
+}
\ No newline at end of file
diff --git a/backend/schemas/source/base/character_limits/general.json b/backend/schemas/source/base/character_limits/general.json
new file mode 100644
index 000000000..88be298ab
--- /dev/null
+++ b/backend/schemas/source/base/character_limits/general.json
@@ -0,0 +1,242 @@
+{
+ "report_id": {
+ "min": 25,
+ "max": 25
+ },
+ "auditee_uei": {
+ "min": 12,
+ "max": 13
+ },
+ "audit_year": {
+ "min": 4,
+ "max": 4
+ },
+ "auditee_certify_name": {
+ "min": 2,
+ "max": 100
+ },
+ "auditee_certify_title": {
+ "min": 2,
+ "max": 100
+ },
+ "auditee_contact_name": {
+ "min": 2,
+ "max": 100
+ },
+ "auditee_email": {
+ "min": 6,
+ "max": 320
+ },
+ "auditee_name": {
+ "min": 2,
+ "max": 100
+ },
+ "auditee_phone": {
+ "min": 10,
+ "max": 10
+ },
+ "auditee_contact_title": {
+ "min": 2,
+ "max": 100
+ },
+ "auditee_address_line_1": {
+ "min": 2,
+ "max": 100
+ },
+ "auditee_city": {
+ "min": 2,
+ "max": 100
+ },
+ "auditee_state": {
+ "min": 2,
+ "max": 2
+ },
+ "auditee_ein": {
+ "min": 9,
+ "max": 9
+ },
+ "auditee_zip": {
+ "min": 5,
+ "max": 9
+ },
+ "auditor_phone": {
+ "min": 10,
+ "max": 10
+ },
+ "auditor_state": {
+ "min": 2,
+ "max": 2
+ },
+ "auditor_city": {
+ "min": 0,
+ "max": 100
+ },
+ "auditor_contact_title": {
+ "min": 2,
+ "max": 100
+ },
+ "auditor_address_line_1": {
+ "min": 0,
+ "max": 100
+ },
+ "auditor_zip": {
+ "min": 0,
+ "max": 9
+ },
+ "auditor_country": {
+ "min": 2,
+ "max": 56
+ },
+ "auditor_contact_name": {
+ "min": 2,
+ "max": 100
+ },
+ "auditor_email": {
+ "min": 6,
+ "max": 320
+ },
+ "auditor_firm_name": {
+ "min": 2,
+ "max": 100
+ },
+ "auditor_foreign_address": {
+ "min": 0,
+ "max": 100
+ },
+ "auditor_ein": {
+ "min": 9,
+ "max": 9
+ },
+ "cognizant_agency": {
+ "min": 2,
+ "max": 2
+ },
+ "oversight_agency": {
+ "min": 2,
+ "max": 2
+ },
+ "date_created": {
+ "min": 10,
+ "max": 10
+ },
+ "ready_for_certification_date": {
+ "min": 10,
+ "max": 10
+ },
+ "auditor_certified_date": {
+ "min": 10,
+ "max": 10
+ },
+ "auditee_certified_date": {
+ "min": 10,
+ "max": 10
+ },
+ "submitted_date": {
+ "min": 10,
+ "max": 10
+ },
+ "fac_accepted_date": {
+ "min": 10,
+ "max": 10
+ },
+ "fy_end_date": {
+ "min": 10,
+ "max": 10
+ },
+ "fy_start_date": {
+ "min": 10,
+ "max": 10
+ },
+ "audit_type": {
+ "min": 12,
+ "max": 16
+ },
+ "gaap_results": {
+ "min": 15,
+ "max": 77
+ },
+ "sp_framework_basis": {
+ "min": 0,
+ "max": 17
+ },
+ "is_sp_framework_required": {
+ "min": 0,
+ "max": 3
+ },
+ "sp_framework_opinions": {
+ "min": 0,
+ "max": 60
+ },
+ "is_going_concern_included": {
+ "min": 2,
+ "max": 3
+ },
+ "is_internal_control_deficiency_disclosed": {
+ "min": 2,
+ "max": 3
+ },
+ "is_internal_control_material_weakness_disclosed": {
+ "min": 2,
+ "max": 3
+ },
+ "is_material_noncompliance_disclosed": {
+ "min": 2,
+ "max": 3
+ },
+ "dollar_threshold": {
+ "min": 1,
+ "max": 7409350297
+ },
+ "is_low_risk_auditee": {
+ "min": 2,
+ "max": 3
+ },
+ "agencies_with_prior_findings": {
+ "min": 2,
+ "max": 142
+ },
+ "entity_type": {
+ "min": 5,
+ "max": 10
+ },
+ "number_months": {
+ "min": 0,
+ "max": 2
+ },
+ "audit_period_covered": {
+ "min": 5,
+ "max": 8
+ },
+ "total_amount_expended": {
+ "min": 0,
+ "max": 241863115093
+ },
+ "type_audit_code": {
+ "min": 2,
+ "max": 2
+ },
+ "is_public": {
+ "min": 0,
+ "max": 0
+ },
+ "data_source": {
+ "min": 6,
+ "max": 6
+ },
+ "is_aicpa_audit_guide_included": {
+ "min": 2,
+ "max": 3
+ },
+ "is_additional_ueis": {
+ "min": 2,
+ "max": 3
+ },
+ "is_multiple_eins": {
+ "min": 2,
+ "max": 3
+ },
+ "is_secondary_auditors": {
+ "min": 2,
+ "max": 3
+ }
+}
diff --git a/backend/schemas/source/base/character_limits/notes_to_sefa.json b/backend/schemas/source/base/character_limits/notes_to_sefa.json
new file mode 100644
index 000000000..68f83e2a8
--- /dev/null
+++ b/backend/schemas/source/base/character_limits/notes_to_sefa.json
@@ -0,0 +1,38 @@
+{
+ "report_id": {
+ "min": 25,
+ "max": 25
+ },
+ "auditee_uei": {
+ "min": 12,
+ "max": 13
+ },
+ "audit_year": {
+ "min": 4,
+ "max": 4
+ },
+ "title": {
+ "min": 0,
+ "max": 822
+ },
+ "accounting_policies": {
+ "min": 1,
+ "max": 31439
+ },
+ "is_minimis_rate_used": {
+ "min": 1,
+ "max": 13
+ },
+ "rate_explained": {
+ "min": 0,
+ "max": 3800
+ },
+ "content": {
+ "min": 0,
+ "max": 18801
+ },
+ "contains_chart_or_table": {
+ "min": 0,
+ "max": 13
+ }
+}
\ No newline at end of file
diff --git a/backend/schemas/source/base/character_limits/passthrough.json b/backend/schemas/source/base/character_limits/passthrough.json
new file mode 100644
index 000000000..eb63b302d
--- /dev/null
+++ b/backend/schemas/source/base/character_limits/passthrough.json
@@ -0,0 +1,26 @@
+{
+ "report_id": {
+ "min": 25,
+ "max": 25
+ },
+ "auditee_uei": {
+ "min": 12,
+ "max": 13
+ },
+ "audit_year": {
+ "min": 4,
+ "max": 4
+ },
+ "award_reference": {
+ "min": 10,
+ "max": 10
+ },
+ "passthrough_id": {
+ "min": 0,
+ "max": 368
+ },
+ "passthrough_name": {
+ "min": 0,
+ "max": 421
+ }
+}
\ No newline at end of file
diff --git a/backend/schemas/source/base/character_limits/secondary_auditors.json b/backend/schemas/source/base/character_limits/secondary_auditors.json
new file mode 100644
index 000000000..70d9ad158
--- /dev/null
+++ b/backend/schemas/source/base/character_limits/secondary_auditors.json
@@ -0,0 +1,54 @@
+{
+ "report_id": {
+ "min": 25,
+ "max": 25
+ },
+ "auditee_uei": {
+ "min": 12,
+ "max": 13
+ },
+ "audit_year": {
+ "min": 4,
+ "max": 4
+ },
+ "auditor_ein": {
+ "min": 9,
+ "max": 9
+ },
+ "auditor_name": {
+ "min": 3,
+ "max": 64
+ },
+ "contact_name": {
+ "min": 5,
+ "max": 31
+ },
+ "contact_title": {
+ "min": 3,
+ "max": 49
+ },
+ "contact_email": {
+ "min": 13,
+ "max": 34
+ },
+ "contact_phone": {
+ "min": 10,
+ "max": 14
+ },
+ "address_street": {
+ "min": 2,
+ "max": 52
+ },
+ "address_city": {
+ "min": 4,
+ "max": 19
+ },
+ "address_state": {
+ "min": 2,
+ "max": 2
+ },
+ "address_zipcode": {
+ "min": 5,
+ "max": 9
+ }
+}
\ No newline at end of file
diff --git a/backend/schemas/source/excel/libs/SheetValidations.libsonnet b/backend/schemas/source/excel/libs/SheetValidations.libsonnet
index 86e4d9e7b..98844377f 100644
--- a/backend/schemas/source/excel/libs/SheetValidations.libsonnet
+++ b/backend/schemas/source/excel/libs/SheetValidations.libsonnet
@@ -122,8 +122,7 @@ local AwardReferenceValidation = {
custom_error: 'If the Program Name was provided, please, do not change it unless necessary or unknown. ' +
'The Program Name must be under 300 characters. ' +
'If the drop-down menu is empty, you may need to enter an Agency Prefix ' +
- 'and ALN in columns B and C. ' +
- 'Continue?',
+ 'and ALN in columns B and C.',
custom_title: 'Unknown Federal Program Name',
},
YoNoBValidation: YoNoBValidation,
diff --git a/backend/schemas/source/sections/AuditInformation.schema.jsonnet b/backend/schemas/source/sections/AuditInformation.schema.jsonnet
index a3581e43f..c1e11a0d5 100644
--- a/backend/schemas/source/sections/AuditInformation.schema.jsonnet
+++ b/backend/schemas/source/sections/AuditInformation.schema.jsonnet
@@ -19,56 +19,56 @@ local AuditInformation = Types.object {
oneOf: [
Types.boolean,
Types.string {
- const: Base.Const.GSA_MIGRATION,
- },
+ const: Base.Const.GSA_MIGRATION,
+ },
],
},
is_going_concern_included: {
oneOf: [
Types.boolean,
Types.string {
- const: Base.Const.GSA_MIGRATION,
- },
+ const: Base.Const.GSA_MIGRATION,
+ },
],
},
is_internal_control_deficiency_disclosed: {
oneOf: [
Types.boolean,
Types.string {
- const: Base.Const.GSA_MIGRATION,
- },
+ const: Base.Const.GSA_MIGRATION,
+ },
],
},
is_internal_control_material_weakness_disclosed: {
oneOf: [
Types.boolean,
Types.string {
- const: Base.Const.GSA_MIGRATION,
- },
+ const: Base.Const.GSA_MIGRATION,
+ },
],
},
is_material_noncompliance_disclosed: {
oneOf: [
Types.boolean,
Types.string {
- const: Base.Const.GSA_MIGRATION,
- },
+ const: Base.Const.GSA_MIGRATION,
+ },
],
},
is_aicpa_audit_guide_included: {
oneOf: [
Types.boolean,
Types.string {
- const: Base.Const.GSA_MIGRATION,
- },
+ const: Base.Const.GSA_MIGRATION,
+ },
],
},
is_low_risk_auditee: {
oneOf: [
Types.boolean,
Types.string {
- const: Base.Const.GSA_MIGRATION,
- },
+ const: Base.Const.GSA_MIGRATION,
+ },
],
},
agencies: Types.array {
diff --git a/backend/schemas/source/sections/FederalAwardsAuditFindings.schema.jsonnet b/backend/schemas/source/sections/FederalAwardsAuditFindings.schema.jsonnet
index 436e9739d..f54763ce9 100644
--- a/backend/schemas/source/sections/FederalAwardsAuditFindings.schema.jsonnet
+++ b/backend/schemas/source/sections/FederalAwardsAuditFindings.schema.jsonnet
@@ -28,7 +28,7 @@ local Parts = {
additionalProperties: false,
properties: {
award_reference: Base.Compound.AwardReference,
- compliance_requirement:{
+ compliance_requirement: {
oneOf: [
Base.Compound.ComplianceRequirementTypes,
Types.string {
diff --git a/backend/schemas/source/sections/GeneralInformation.schema.jsonnet b/backend/schemas/source/sections/GeneralInformation.schema.jsonnet
index 6a1d25d56..c001d1122 100644
--- a/backend/schemas/source/sections/GeneralInformation.schema.jsonnet
+++ b/backend/schemas/source/sections/GeneralInformation.schema.jsonnet
@@ -1,5 +1,6 @@
local Base = import '../base/Base.libsonnet';
local Func = import '../base/Functions.libsonnet';
+local GeneralCharacterLimits = import '../base/character_limits/general.json';
local Types = Base.Types;
/*
@@ -41,13 +42,16 @@ Typechecks fields, but allows for empty data as well. Contains conditional check
},
ein_not_an_ssn_attestation: Types.boolean,
auditee_name: Types.string {
- maxLength: 100,
+ minLength: GeneralCharacterLimits.auditee_name.min,
+ maxLength: GeneralCharacterLimits.auditee_name.max,
},
auditee_address_line_1: Types.string {
- maxLength: 100,
+ minLength: GeneralCharacterLimits.auditee_address_line_1.min,
+ maxLength: GeneralCharacterLimits.auditee_address_line_1.max,
},
auditee_city: Types.string {
- maxLength: 100,
+ minLength: GeneralCharacterLimits.auditee_city.min,
+ maxLength: GeneralCharacterLimits.auditee_city.max,
},
auditee_state: Base.Enum.UnitedStatesStateAbbr,
auditee_zip: {
@@ -60,17 +64,20 @@ Typechecks fields, but allows for empty data as well. Contains conditional check
},
auditee_contact_name: Types.string {
- maxLength: 100,
+ minLength: GeneralCharacterLimits.auditee_contact_name.min,
+ maxLength: GeneralCharacterLimits.auditee_contact_name.max,
},
auditee_contact_title: Types.string {
- maxLength: 100,
+ minLength: GeneralCharacterLimits.auditee_contact_title.min,
+ maxLength: GeneralCharacterLimits.auditee_contact_title.max,
},
auditee_phone: Base.Compound.UnitedStatesPhone,
auditee_email: Types.string {
oneOf: [
Types.string {
format: 'email',
- maxLength: 100,
+ minLength: GeneralCharacterLimits.auditee_email.min,
+ maxLength: GeneralCharacterLimits.auditee_email.max,
},
Types.string {
const: Base.Const.GSA_MIGRATION,
@@ -89,20 +96,21 @@ Typechecks fields, but allows for empty data as well. Contains conditional check
},
auditor_ein_not_an_ssn_attestation: Types.boolean,
auditor_firm_name: Types.string {
- maxLength: 100,
+ minLength: GeneralCharacterLimits.auditor_firm_name.min,
+ maxLength: GeneralCharacterLimits.auditor_firm_name.max,
},
auditor_country: Base.Enum.CountryType,
auditor_international_address: Types.string {
- minLength: 1,
- maxLength: 500,
+ minLength: GeneralCharacterLimits.auditor_foreign_address.min,
+ maxLength: GeneralCharacterLimits.auditor_foreign_address.max,
},
auditor_address_line_1: Types.string {
- minLength: 1,
- maxLength: 100,
+ minLength: GeneralCharacterLimits.auditor_address_line_1.min,
+ maxLength: GeneralCharacterLimits.auditor_address_line_1.max,
},
auditor_city: Types.string {
- minLength: 1,
- maxLength: 100,
+ minLength: GeneralCharacterLimits.auditor_city.min,
+ maxLength: GeneralCharacterLimits.auditor_city.max,
},
auditor_state: Base.Enum.UnitedStatesStateAbbr,
auditor_zip: {
@@ -115,17 +123,20 @@ Typechecks fields, but allows for empty data as well. Contains conditional check
},
auditor_contact_name: Types.string {
- maxLength: 100,
+ minLength: GeneralCharacterLimits.auditor_contact_name.min,
+ maxLength: GeneralCharacterLimits.auditor_contact_name.max,
},
auditor_contact_title: Types.string {
- maxLength: 100,
+ minLength: GeneralCharacterLimits.auditor_contact_title.min,
+ maxLength: GeneralCharacterLimits.auditor_contact_title.max,
},
auditor_phone: Base.Compound.UnitedStatesPhone,
auditor_email: {
oneOf: [
Types.string {
format: 'email',
- maxLength: 100,
+ minLength: GeneralCharacterLimits.auditor_email.min,
+ maxLength: GeneralCharacterLimits.auditor_email.max,
},
Types.string {
const: Base.Const.GSA_MIGRATION,
diff --git a/backend/schemas/source/sections/GeneralInformationRequired.schema.jsonnet b/backend/schemas/source/sections/GeneralInformationRequired.schema.jsonnet
index dcfbc4f00..2421891f2 100644
--- a/backend/schemas/source/sections/GeneralInformationRequired.schema.jsonnet
+++ b/backend/schemas/source/sections/GeneralInformationRequired.schema.jsonnet
@@ -90,16 +90,16 @@ GeneralInformation {
},
},
'then': {
- allOf:[
+ allOf: [
{
not: {
required: ['auditor_international_address'],
},
},
{
- required: ['auditor_address_line_1', 'auditor_city', 'auditor_state','auditor_zip'],
- }
- ]
+ required: ['auditor_address_line_1', 'auditor_city', 'auditor_state', 'auditor_zip'],
+ },
+ ],
},
},
// If auditor is NOT from the USA, international things should be filled in.
@@ -117,13 +117,13 @@ GeneralInformation {
allOf: [
{
not: {
- required: ['auditor_address_line_1', 'auditor_city', 'auditor_state','auditor_zip'],
+ required: ['auditor_address_line_1', 'auditor_city', 'auditor_state', 'auditor_zip'],
},
},
{
required: ['auditor_international_address'],
- }
- ]
+ },
+ ],
},
},
],
diff --git a/backend/static/js/validate.js b/backend/static/js/validate.js
index fc6673bb0..11ccefe89 100644
--- a/backend/static/js/validate.js
+++ b/backend/static/js/validate.js
@@ -152,10 +152,15 @@ export const validations = {
: result;
},
+ /**
+ * Determines if a field has satisfied its self-defined length requirements.
+ * @param {String} field The field, containing its id and value.
+ * @param {String} compStr The contraint, with space separated comparators and values.
+ * @return {Object} A result object containing the error status.
+ */
validateLength: (field, compStr) => {
- const [comparator, compValue] = compStr.split(' ');
+ const splitCompStr = compStr.split(' ');
const valueLength = field.value.length;
- const compValueLength = parseInt(compValue);
const result = {
error: false,
@@ -163,12 +168,23 @@ export const validations = {
validation: 'length',
};
- switch (comparator) {
- case '==':
- return valueLength != compValueLength
- ? { ...result, error: true }
- : result;
+ // The splitCompStr looks something like [">=", "2", "<=", "100"]
+ // So we loop over the array and use comparator [i] with comparator value [i + 1], against the field length.
+ for (let i = 0; i < splitCompStr.length; i += 2) {
+ let comparator = splitCompStr[i];
+ let compValue = splitCompStr[i + 1];
+ let compValueLength = parseInt(compValue);
+
+ if (comparator == '==' && valueLength != compValueLength) {
+ return { ...result, error: true };
+ } else if (comparator == '>=' && valueLength < compValueLength) {
+ return { ...result, error: true };
+ } else if (comparator == '<=' && valueLength > compValueLength) {
+ return { ...result, error: true };
+ }
}
+
+ return result;
},
validateDateComesAfter: (field) => {
diff --git a/backend/support/api/admin_api_v1_1_0/create_access_tables.sql b/backend/support/api/admin_api_v1_1_0/create_access_tables.sql
index e36a1e592..03f37be67 100644
--- a/backend/support/api/admin_api_v1_1_0/create_access_tables.sql
+++ b/backend/support/api/admin_api_v1_1_0/create_access_tables.sql
@@ -1,43 +1,37 @@
--- This is explicitly not a Django managed table.
--- In order to have an administrative key added,
--- it must be added via a Github commit, and a PR
--- must be performed to merge the key into the tree.
-
--- This is because administrative keys can read/write
--- to some tables in the database. They can read internal and
--- in-flight data.
-
-DROP TABLE IF EXISTS support_administrative_key_uuids;
-
-CREATE TABLE support_administrative_key_uuids
- (
- id BIGSERIAL PRIMARY KEY,
- email TEXT,
- uuid TEXT,
- permissions TEXT,
- added DATE
- );
-
-INSERT INTO support_administrative_key_uuids
- (email, uuid, permissions, added)
- VALUES
- (
- 'matthew.jadud@gsa.gov',
- '61ba59b2-f545-4c2f-9b24-9655c706a06c',
- 'CREATE,READ,DELETE',
- '2023-12-04'
- ),
- (
- 'timothy.ballard@gsa.gov',
- '1e2845a0-c844-4a6f-84ac-f398b58ce7c9',
- 'CREATE,READ,DELETE',
- '2023-12-08'
- ),
- (
- 'daniel.swick@gsa.gov',
- 'b6e08808-ecb2-4b6a-b928-46d4205497ff',
- 'CREATE,READ,DELETE',
- '2023-12-08'
- )
- ;
-
+-- This is explicitly not a Django managed table.
+-- In order to have an administrative key added,
+-- it must be added via a Github commit, and a PR
+-- must be performed to merge the key into the tree.
+
+-- This is because administrative keys can read/write
+-- to some tables in the database. They can read internal and
+-- in-flight data.
+
+DROP TABLE IF EXISTS support_administrative_key_uuids;
+
+CREATE TABLE support_administrative_key_uuids
+ (
+ id BIGSERIAL PRIMARY KEY,
+ email TEXT,
+ uuid TEXT,
+ permissions TEXT,
+ added DATE
+ );
+
+INSERT INTO support_administrative_key_uuids
+ (email, uuid, permissions, added)
+ VALUES
+ (
+ 'matthew.jadud@gsa.gov',
+ '61ba59b2-f545-4c2f-9b24-9655c706a06c',
+ 'CREATE,READ,DELETE',
+ '2023-12-04'
+ ),
+ (
+ 'daniel.swick@gsa.gov',
+ 'b6e08808-ecb2-4b6a-b928-46d4205497ff',
+ 'CREATE,READ,DELETE',
+ '2023-12-08'
+ )
+ ;
+
diff --git a/backend/templates/includes/nav_primary.html b/backend/templates/includes/nav_primary.html
index c1a938491..14f0754bb 100644
--- a/backend/templates/includes/nav_primary.html
+++ b/backend/templates/includes/nav_primary.html
@@ -120,7 +120,10 @@
-
+
Helpdesk
diff --git a/terraform/meta/config.tf b/terraform/meta/config.tf
index 791603d47..618cda612 100644
--- a/terraform/meta/config.tf
+++ b/terraform/meta/config.tf
@@ -20,9 +20,6 @@ locals {
# TODO: Automate updates via GitHub's GraphQL API
"bret.mogilefsky@gsa.gov",
"james.person@gsa.gov",
- "jeanmarie.mariadassou@gsa.gov",
- "tadhg.ohiggins@gsa.gov",
- "timothy.ballard@gsa.gov",
"matthew.jadud@gsa.gov",
"hassandeme.mamasambo@gsa.gov",
"daniel.swick@gsa.gov",
@@ -41,10 +38,8 @@ locals {
# TODO: Automate updates via GitHub's GraphQL API
"bret.mogilefsky@gsa.gov",
"daniel.swick@gsa.gov",
- "jeanmarie.mariadassou@gsa.gov",
"matthew.jadud@gsa.gov",
- "tadhg.ohiggins@gsa.gov",
- "timothy.ballard@gsa.gov",
+ "alexander.steel@gsa.gov",
]
internal_asgs = [