From 677516ccb43a59cd157da6dbbc9c21944b7df36c Mon Sep 17 00:00:00 2001 From: Alex Steel <130377221+asteel-gsa@users.noreply.github.com> Date: Fri, 6 Dec 2024 09:35:00 -0500 Subject: [PATCH 1/7] Remove pre-deploy zap scan from staging and prod deploy (#4504) * Remove dev zap scan from staging deploy * Also happens in prod --- .github/workflows/deploy-production.yml | 8 -------- .github/workflows/deploy-staging.yml | 7 ------- 2 files changed, 15 deletions(-) diff --git a/.github/workflows/deploy-production.yml b/.github/workflows/deploy-production.yml index c66205a864..3e1859de3b 100644 --- a/.github/workflows/deploy-production.yml +++ b/.github/workflows/deploy-production.yml @@ -14,18 +14,10 @@ jobs: uses: ./.github/workflows/linting.yml secrets: inherit - # up to date scan of the staging instance - scan-staging: - name: ZAP scan of the staging site - uses: ./.github/workflows/zap-scan.yml - with: - url: "https://fac-staging.app.cloud.gov/" - deploy-infrastructure-production: name: Deploy infrastructure (production) needs: - testing - - scan-staging uses: ./.github/workflows/terraform-apply-env.yml with: environment: "production" diff --git a/.github/workflows/deploy-staging.yml b/.github/workflows/deploy-staging.yml index cdc59bf003..e2acb5d116 100644 --- a/.github/workflows/deploy-staging.yml +++ b/.github/workflows/deploy-staging.yml @@ -14,17 +14,10 @@ jobs: uses: ./.github/workflows/linting.yml secrets: inherit - scan-dev: - name: Zap Scan - uses: ./.github/workflows/zap-scan.yml - with: - url: "https://fac-dev.app.cloud.gov/" - deploy-infrastructure-staging: name: Deploy infrastructure (staging) needs: - testing - - scan-dev uses: ./.github/workflows/terraform-apply-env.yml with: environment: "staging" From 535f9482e98f16b3ca63e488cca2125d4e245767 Mon Sep 17 00:00:00 2001 From: James Person Date: Fri, 6 Dec 2024 11:14:34 -0500 Subject: [PATCH 2/7] Maintenance Banner Copy Update (#4515) * Center the maintenance banner content * 'grid-container' on the body, not just the text. * doing site upgrade -> performing maintenance --- backend/config/settings.py | 2 +- backend/templates/includes/maintenance_banner.html | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/config/settings.py b/backend/config/settings.py index 92b8071364..1bbced2674 100644 --- a/backend/config/settings.py +++ b/backend/config/settings.py @@ -594,6 +594,6 @@ "start": datetime(2024, 12, 5, 17, tzinfo=timezone.utc), "end": datetime(2024, 12, 10, 17, tzinfo=timezone.utc), "template_name": "maintenance_20241210.html", - "message": "FAC.gov will be doing a site upgrade on Tuesday, December 10, 2024 between 12:00 p.m. and 6:00 p.m ET. During this period, the entire website will be unavailable.", + "message": "FAC.gov will be performing maintenance on Tuesday, December 10, 2024 between 12:00 p.m. and 6:00 p.m ET. During this period, the entire website will be unavailable.", }, ] diff --git a/backend/templates/includes/maintenance_banner.html b/backend/templates/includes/maintenance_banner.html index df5941b214..a9e539e98c 100644 --- a/backend/templates/includes/maintenance_banner.html +++ b/backend/templates/includes/maintenance_banner.html @@ -1,13 +1,13 @@
-

Scheduled system upgrade

+

Scheduled system maintenance

{% comment %} If a message is given, use it. If not, display a generic message with the timeframe. {% endcomment %}

{% if MAINTENANCE_BANNER_MESSAGE %} {{ MAINTENANCE_BANNER_MESSAGE }} {% else %} - FAC.gov will be doing a site upgrade from {{ MAINTENANCE_BANNER_START_TIME|date:"N j, Y, f A" }} to {{ MAINTENANCE_BANNER_END_TIME|date:"N j, Y, f A" }}. + FAC.gov will be performing maintenance from {{ MAINTENANCE_BANNER_START_TIME|date:"N j, Y, f A" }} to {{ MAINTENANCE_BANNER_END_TIME|date:"N j, Y, f A" }}. During this period, the entire website will be unavailable. {% endif %}

From a2f9c99533293f958397cbafecc9895137c329e3 Mon Sep 17 00:00:00 2001 From: "Hassan D. M. Sambo" Date: Mon, 9 Dec 2024 10:15:57 -0500 Subject: [PATCH 3/7] #4513 fix logic to prevent index out of range error (#4519) --- .../xform_resize_award_references.py | 20 ++++++++++++++----- .../test_xform_resize_award_references.py | 7 +++++++ 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/backend/audit/intakelib/transforms/xform_resize_award_references.py b/backend/audit/intakelib/transforms/xform_resize_award_references.py index 822ce8090a..aa2f444b80 100644 --- a/backend/audit/intakelib/transforms/xform_resize_award_references.py +++ b/backend/audit/intakelib/transforms/xform_resize_award_references.py @@ -9,6 +9,8 @@ logger = logging.getLogger(__name__) +AWARD_REFERENCE_PREFIX = "AWARD" + def resize_award_reference(ir): references = get_range_by_name(ir, "award_reference") @@ -19,9 +21,17 @@ def resize_award_reference(ir): def _format_reference(v): + """Format the award reference to have 5 digits, padding with zeros if necessary""" + if not v or len(v) >= AWARD_LEN_5_DIGITS: + return v + + parts = v.split("-") + if len(parts) != 2 or not parts[0] or not parts[1]: + return v + + prefix, number = parts + if prefix.upper() != AWARD_REFERENCE_PREFIX: + return v - if v and len(v) < AWARD_LEN_5_DIGITS: - parts = v.split("-") - padding = "0" * (AWARD_LEN_5_DIGITS - len(v)) - return f"{parts[0]}-{padding}{parts[1]}" - return v + padding = "0" * (AWARD_LEN_5_DIGITS - len(v)) + return f"{prefix}-{padding}{number}" diff --git a/backend/audit/test_xform_resize_award_references.py b/backend/audit/test_xform_resize_award_references.py index 90648c87a1..da053da15f 100644 --- a/backend/audit/test_xform_resize_award_references.py +++ b/backend/audit/test_xform_resize_award_references.py @@ -51,3 +51,10 @@ def test_format_reference(self): self.assertEqual(_format_reference("AWARD-12345"), "AWARD-12345") self.assertEqual(_format_reference(None), None) self.assertEqual(_format_reference(""), "") + + def test_format_reference_malformed(self): + """Test the _format_reference function with malformed inputs""" + # Malformed cases should return as is, as the function does not raise exceptions + self.assertEqual(_format_reference("AWARD123"), "AWARD123") # Missing dash + self.assertEqual(_format_reference("123-456"), "123-456") # Incorrect prefix + self.assertEqual(_format_reference("AWARD-"), "AWARD-") # Missing second part From d9c7dfdb9b8264030ce7d96f9d798a9cd516eefd Mon Sep 17 00:00:00 2001 From: Alex Steel <130377221+asteel-gsa@users.noreply.github.com> Date: Mon, 9 Dec 2024 10:44:04 -0500 Subject: [PATCH 4/7] Various NPM Dependency upgrades (#4521) --- backend/package-lock.json | 123 ++++++++++++++++---------------------- backend/package.json | 12 ++-- 2 files changed, 58 insertions(+), 77 deletions(-) diff --git a/backend/package-lock.json b/backend/package-lock.json index 0b726edd1a..c81a3f134c 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -21,21 +21,21 @@ "devDependencies": { "@4tw/cypress-drag-drop": "^2.2.5", "@babel/eslint-parser": "^7.25.9", - "@eslint/js": "^9.14.0", - "cypress": "^13.16.0", + "@eslint/js": "^9.16.0", + "cypress": "^13.16.1", "cypress-axe": "^1.5.0", "cypress-downloadfile": "^1.2.4", "cypress-file-upload": "^5.0.8", "cypress-otp": "^1.0.3", - "eslint": "^9.14.0", + "eslint": "^9.16.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-cypress": "^4.1.0", "eslint-plugin-prettier": "^5.2.1", - "prettier": "^3.4.0", - "stylelint": "^16.1.0", + "prettier": "^3.4.2", + "stylelint": "^16.11.0", "stylelint-config-scss": "^1.0.0-security", "stylelint-config-standard": "^36.0.1", - "stylelint-config-standard-scss": "^13.1.0" + "stylelint-config-standard-scss": "^14.0.0" }, "engines": { "node": ">=18.0.0 <21.0.0", @@ -452,9 +452,9 @@ } }, "node_modules/@csstools/media-query-list-parser": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-3.0.1.tgz", - "integrity": "sha512-HNo8gGD02kHmcbX6PvCoUuOQvn4szyB9ca63vZHKX5A81QytgDG4oxG4IaEfHTlEZSZ6MjPEMWIVU+zF2PZcgw==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-4.0.2.tgz", + "integrity": "sha512-EUos465uvVvMJehckATTlNqGj4UJWkTmdWuDMjqvSUkjGpmOyFZBVwb4knxCm/k2GMTXY+c/5RkdndzFYWeX5A==", "dev": true, "funding": [ { @@ -470,14 +470,14 @@ "node": ">=18" }, "peerDependencies": { - "@csstools/css-parser-algorithms": "^3.0.1", - "@csstools/css-tokenizer": "^3.0.1" + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3" } }, "node_modules/@csstools/selector-specificity": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-4.0.0.tgz", - "integrity": "sha512-189nelqtPd8++phaHNwYovKZI0FOzH1vQEE3QhHHkNIGrg5fSs9CbYP3RvfEH5geztnIA9Jwq91wyOIwAW5JIQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz", + "integrity": "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==", "dev": true, "funding": [ { @@ -493,7 +493,7 @@ "node": ">=18" }, "peerDependencies": { - "postcss-selector-parser": "^6.1.0" + "postcss-selector-parser": "^7.0.0" } }, "node_modules/@cypress/request": { @@ -1009,9 +1009,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.15.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.15.0.tgz", - "integrity": "sha512-tMTqrY+EzbXmKJR5ToI8lxu7jaN5EdmrBFJpQk5JmSlyLsx6o4t27r883K5xsLuCYCpfKBCGswMSWXsM+jB7lg==", + "version": "9.16.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.16.0.tgz", + "integrity": "sha512-tw2HxzQkrbeuvyj1tG2Yqq+0H9wGoI2IMk4EOsQeX+vmd75FtJAzf+gTA69WF+baUKRYQ3x2kbLE08js5OsTVg==", "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2253,9 +2253,9 @@ } }, "node_modules/cypress": { - "version": "13.16.0", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.16.0.tgz", - "integrity": "sha512-g6XcwqnvzXrqiBQR/5gN+QsyRmKRhls1y5E42fyOvsmU7JuY+wM6uHJWj4ZPttjabzbnRvxcik2WemR8+xT6FA==", + "version": "13.16.1", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.16.1.tgz", + "integrity": "sha512-17FtCaz0cx7ssWYKXzGB0Vub8xHwpVPr+iPt2fHhLMDhVAPVrplD+rTQsZUsfb19LVBn5iwkEUFjQ1yVVJXsLA==", "dev": true, "hasInstallScript": true, "dependencies": { @@ -2883,9 +2883,9 @@ } }, "node_modules/eslint": { - "version": "9.15.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.15.0.tgz", - "integrity": "sha512-7CrWySmIibCgT1Os28lUU6upBshZ+GxybLOrmRzi08kS8MBuO8QA7pXEgYgY5W8vK3e74xv0lpjo9DbaGU9Rkw==", + "version": "9.16.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.16.0.tgz", + "integrity": "sha512-whp8mSQI4C8VXd+fLgSM0lh3UlmcFtVwUQjyKCFfsp+2ItAIYhlq/hqGahGqHE6cv9unM41VlqKk2VtKYR2TaA==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", @@ -2893,7 +2893,7 @@ "@eslint/config-array": "^0.19.0", "@eslint/core": "^0.9.0", "@eslint/eslintrc": "^3.2.0", - "@eslint/js": "9.15.0", + "@eslint/js": "9.16.0", "@eslint/plugin-kit": "^0.2.3", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", @@ -4559,9 +4559,9 @@ } }, "node_modules/known-css-properties": { - "version": "0.34.0", - "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.34.0.tgz", - "integrity": "sha512-tBECoUqNFbyAY4RrbqsBQqDFpGXAEbdD5QKr8kACx3+rnArmuuR22nKQWKazvp07N9yjTyDZaw/20UIH8tL9DQ==", + "version": "0.35.0", + "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.35.0.tgz", + "integrity": "sha512-a/RAk2BfKk+WFGhhOCAYqSiFLc34k8Mt/6NWRI4joER0EYUzXIcFivjjnoD3+XU1DggLn/tZc3DOAgke7l8a4A==", "dev": true }, "node_modules/lazy-ass": { @@ -5715,9 +5715,9 @@ } }, "node_modules/postcss-selector-parser": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", - "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", "dev": true, "dependencies": { "cssesc": "^3.0.0", @@ -5742,9 +5742,9 @@ } }, "node_modules/prettier": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.1.tgz", - "integrity": "sha512-G+YdqtITVZmOJje6QkXQWzl3fSfMxFwm1tjTyo9exhkmWSqC4Yhd1+lug++IlR2mvRVAxEDDWYkQdeSztajqgg==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.2.tgz", + "integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==", "dev": true, "bin": { "prettier": "bin/prettier.cjs" @@ -6851,9 +6851,9 @@ } }, "node_modules/stylelint": { - "version": "16.10.0", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.10.0.tgz", - "integrity": "sha512-z/8X2rZ52dt2c0stVwI9QL2AFJhLhbPkyfpDFcizs200V/g7v+UYY6SNcB9hKOLcDDX/yGLDsY/pX08sLkz9xQ==", + "version": "16.11.0", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.11.0.tgz", + "integrity": "sha512-zrl4IrKmjJQ+h9FoMp69UMCq5SxeHk0URhxUBj4d3ISzo/DplOFBJZc7t7Dr6otB+1bfbbKNLOmCDpzKSlW+Nw==", "dev": true, "funding": [ { @@ -6866,16 +6866,16 @@ } ], "dependencies": { - "@csstools/css-parser-algorithms": "^3.0.1", - "@csstools/css-tokenizer": "^3.0.1", - "@csstools/media-query-list-parser": "^3.0.1", - "@csstools/selector-specificity": "^4.0.0", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "@csstools/media-query-list-parser": "^4.0.2", + "@csstools/selector-specificity": "^5.0.0", "@dual-bundle/import-meta-resolve": "^4.1.0", "balanced-match": "^2.0.0", "colord": "^2.9.3", "cosmiconfig": "^9.0.0", "css-functions-list": "^3.2.3", - "css-tree": "^3.0.0", + "css-tree": "^3.0.1", "debug": "^4.3.7", "fast-glob": "^3.3.2", "fastest-levenshtein": "^1.0.16", @@ -6887,16 +6887,16 @@ "ignore": "^6.0.2", "imurmurhash": "^0.1.4", "is-plain-object": "^5.0.0", - "known-css-properties": "^0.34.0", + "known-css-properties": "^0.35.0", "mathml-tag-names": "^2.1.3", "meow": "^13.2.0", "micromatch": "^4.0.8", "normalize-path": "^3.0.0", - "picocolors": "^1.0.1", - "postcss": "^8.4.47", + "picocolors": "^1.1.1", + "postcss": "^8.4.49", "postcss-resolve-nested-selector": "^0.1.6", "postcss-safe-parser": "^7.0.1", - "postcss-selector-parser": "^6.1.2", + "postcss-selector-parser": "^7.0.0", "postcss-value-parser": "^4.2.0", "resolve-from": "^5.0.0", "string-width": "^4.2.3", @@ -6989,20 +6989,20 @@ } }, "node_modules/stylelint-config-standard-scss": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/stylelint-config-standard-scss/-/stylelint-config-standard-scss-13.1.0.tgz", - "integrity": "sha512-Eo5w7/XvwGHWkeGLtdm2FZLOMYoZl1omP2/jgFCXyl2x5yNz7/8vv4Tj6slHvMSSUNTaGoam/GAZ0ZhukvalfA==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/stylelint-config-standard-scss/-/stylelint-config-standard-scss-14.0.0.tgz", + "integrity": "sha512-6Pa26D9mHyi4LauJ83ls3ELqCglU6VfCXchovbEqQUiEkezvKdv6VgsIoMy58i00c854wVmOw0k8W5FTpuaVqg==", "dev": true, "dependencies": { - "stylelint-config-recommended-scss": "^14.0.0", - "stylelint-config-standard": "^36.0.0" + "stylelint-config-recommended-scss": "^14.1.0", + "stylelint-config-standard": "^36.0.1" }, "engines": { "node": ">=18.12.0" }, "peerDependencies": { "postcss": "^8.3.3", - "stylelint": "^16.3.1" + "stylelint": "^16.11.0" }, "peerDependenciesMeta": { "postcss": { @@ -7032,31 +7032,12 @@ "stylelint": "^16.0.2" } }, - "node_modules/stylelint-scss/node_modules/known-css-properties": { - "version": "0.35.0", - "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.35.0.tgz", - "integrity": "sha512-a/RAk2BfKk+WFGhhOCAYqSiFLc34k8Mt/6NWRI4joER0EYUzXIcFivjjnoD3+XU1DggLn/tZc3DOAgke7l8a4A==", - "dev": true - }, "node_modules/stylelint-scss/node_modules/mdn-data": { "version": "2.12.2", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.12.2.tgz", "integrity": "sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==", "dev": true }, - "node_modules/stylelint-scss/node_modules/postcss-selector-parser": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", - "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", - "dev": true, - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/stylelint/node_modules/balanced-match": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-2.0.0.tgz", diff --git a/backend/package.json b/backend/package.json index d024485c59..f170159307 100644 --- a/backend/package.json +++ b/backend/package.json @@ -25,21 +25,21 @@ "devDependencies": { "@4tw/cypress-drag-drop": "^2.2.5", "@babel/eslint-parser": "^7.25.9", - "@eslint/js": "^9.14.0", - "cypress": "^13.16.0", + "@eslint/js": "^9.16.0", + "cypress": "^13.16.1", "cypress-axe": "^1.5.0", "cypress-downloadfile": "^1.2.4", "cypress-file-upload": "^5.0.8", "cypress-otp": "^1.0.3", - "eslint": "^9.14.0", + "eslint": "^9.16.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-cypress": "^4.1.0", "eslint-plugin-prettier": "^5.2.1", - "prettier": "^3.4.0", - "stylelint": "^16.1.0", + "prettier": "^3.4.2", + "stylelint": "^16.11.0", "stylelint-config-scss": "^1.0.0-security", "stylelint-config-standard": "^36.0.1", - "stylelint-config-standard-scss": "^13.1.0" + "stylelint-config-standard-scss": "^14.0.0" }, "dependencies": { "@uswds/uswds": "3.10.0", From adbac51308cc85dbfcf540640bd34b84bf9c767d Mon Sep 17 00:00:00 2001 From: Bobby Novak <176936850+rnovak338@users.noreply.github.com> Date: Mon, 9 Dec 2024 12:30:38 -0500 Subject: [PATCH 5/7] Handle empty JSON in LogEntry on new save (#4518) * Handle empty JSON in LogEntry on new save Sometimes, there are no actual changes made when attempting to save edits to a record in the DB. This change creates a condition that verifies that JSON exists before parsing. * Syntax refactoring --- backend/support/admin.py | 64 +++++++++++++++++++++++++++------------- 1 file changed, 44 insertions(+), 20 deletions(-) diff --git a/backend/support/admin.py b/backend/support/admin.py index 2ace7c3301..95513bd8a4 100644 --- a/backend/support/admin.py +++ b/backend/support/admin.py @@ -149,12 +149,16 @@ class LogEntryAdmin(SupportAdmin): ) def staff_user(self, obj): + """The staffuser.""" return obj.user.email def record_affected(self, obj): + """The record associated with the staffuser's action.""" return obj.object_repr def event(self, obj): + """Shares the action taken by the staffuser.""" + if obj.action_flag == ADDITION: return "Created" elif obj.action_flag == DELETION: @@ -162,19 +166,38 @@ def event(self, obj): elif obj.action_flag == CHANGE: res = "Updated" if obj.change_message: - _json = json.loads(obj.change_message)[0] - if "changed" in _json: - res = "Updated\n" - for field in _json["changed"]["fields"]: - res += f"\n- {field}" + _json = json.loads(obj.change_message) + + # The LogEntry has recorded changes. + if _json: + _json = _json[0] + if "changed" in _json: + res = "Updated\n" + for field in _json["changed"]["fields"]: + res += f"\n- {field}" + + # No changes were actually made. + else: + res += "\n- No changes" return res return "-" def content(self, obj): + """The raw contents of the record that was changed.""" + if obj.change_message: - _json = json.loads(obj.change_message)[0] - if "content" in _json: - return _json["content"] + _json = json.loads(obj.change_message) + + # The LogEntry has recorded changes. + if _json: + _json = _json[0] + if "content" in _json: + return _json["content"] + + # No changes were actually made. + else: + return "No changes" + return "-" @@ -193,18 +216,19 @@ def add_custom_field_to_log(sender, instance, created, **kwargs): # update content of record after save occurred. change_message_json = json.loads(instance.change_message) - if model_class == UserPermission: - change_message_json[0]["content"] = list( - qset.values("email", "permission__slug") - ) - elif model_class == TribalApiAccessKeyIds: - change_message_json[0]["content"] = list(qset.values("email", "key_id")) - else: - change_message_json[0]["content"] = list(qset.values("id")) - - # record still exists. - if obj: - change_message_json[0]["id"] = obj.pk + if change_message_json: + if model_class == UserPermission: + change_message_json[0]["content"] = list( + qset.values("email", "permission__slug") + ) + elif model_class == TribalApiAccessKeyIds: + change_message_json[0]["content"] = list(qset.values("email", "key_id")) + else: + change_message_json[0]["content"] = list(qset.values("id")) + + # record still exists. + if obj: + change_message_json[0]["id"] = obj.pk # write changes to instance. instance.change_message = json.dumps(change_message_json, cls=DateEncoder) From 569ef19e59ea81a3db67f2782205db96cb670f00 Mon Sep 17 00:00:00 2001 From: Phil Dominguez <142051477+phildominguez-gsa@users.noreply.github.com> Date: Mon, 9 Dec 2024 14:52:30 -0500 Subject: [PATCH 6/7] Supporting multiple expenditure thresholds on eligibility page (#4405) * Supporting multiple expenditure thresholds for step 1 * Comments * Lint * Lint * Making start dates inclusive * Unit tests * Tweaking error message * Removing unused DOLLAR_THRESHOLD * Lint * Lint * Including the message in settings.py * Updating unit test * Lint --- backend/config/settings.py | 17 ++++++++++++++++- .../templates/report_submission/step-1.html | 13 +++++++------ backend/report_submission/test_views.py | 7 +++++++ backend/report_submission/views.py | 13 ++++++++----- 4 files changed, 38 insertions(+), 12 deletions(-) diff --git a/backend/config/settings.py b/backend/config/settings.py index 1bbced2674..2deaf68ee6 100644 --- a/backend/config/settings.py +++ b/backend/config/settings.py @@ -554,7 +554,6 @@ # APP-level constants CENSUS_DATA_SOURCE = "CENSUS" -DOLLAR_THRESHOLD = 750000 SUMMARY_REPORT_DOWNLOAD_LIMIT = 1000 DEFAULT_MAX_ROWS = ( 10000 # A version of this constant also exists in schemas.scrpits.render.py @@ -583,6 +582,22 @@ # https://docs.djangoproject.com/en/dev/ref/settings/#session-save-every-request SESSION_SAVE_EVERY_REQUEST = True +# Minimum expenditure thresholds +DOLLAR_THRESHOLDS = [ + { + "start": None, + "end": datetime(2024, 10, 1), + "minimum": 750000, + "message": "$750,000 or more with a Fiscal Year starting BEFORE October 01, 2024", + }, + { + "start": datetime(2024, 10, 1), + "end": None, + "minimum": 1000000, + "message": "$1,000,000 or more with a Fiscal Year starting ON or AFTER October 01, 2024", + }, +] + # Times for the maintenance banner to display. # Requires a 'start' and an 'end'. # 'template_name' is optional, and defines what will display if maintenance mode is enabled during this timeframe. If no name is given, the 503 error page is used. diff --git a/backend/report_submission/templates/report_submission/step-1.html b/backend/report_submission/templates/report_submission/step-1.html index 6f72bd0e48..9a5ea450e6 100644 --- a/backend/report_submission/templates/report_submission/step-1.html +++ b/backend/report_submission/templates/report_submission/step-1.html @@ -94,10 +94,13 @@
- Did this entity spend $750,000 or more in federal awards during its audit period in accordance with - Uniform - Guidance? + Did this entity spend an amount of federal awards meeting one of the following criteria during its audit period, in accordance with Uniform Guidance? * +
    + {% for dollar_threshold in dollar_thresholds %} +
  • {{ dollar_threshold }}
  • + {% endfor %} +
- You only need to submit a report for an entity that spent $750,000 - or more in federal awards during its audit period (fiscal period beginning dates on or after - 12/26/2014). + You do not meet the requirements for submitting a single audit report.
diff --git a/backend/report_submission/test_views.py b/backend/report_submission/test_views.py index 46f8d3fb25..37d679bcf4 100644 --- a/backend/report_submission/test_views.py +++ b/backend/report_submission/test_views.py @@ -141,6 +141,13 @@ def test_step_one_eligibility_submission_pass(self): self.assertEqual(get_response.status_code, 200) self.assertTemplateUsed(get_response, "report_submission/step-base.html") self.assertTemplateUsed(get_response, "report_submission/step-1.html") + self.assertEqual( + get_response.context["dollar_thresholds"], + [ + "$750,000 or more with a Fiscal Year starting BEFORE October 01, 2024", + "$1,000,000 or more with a Fiscal Year starting ON or AFTER October 01, 2024", + ], + ) response = self.client.post(url, data=self.step1_data) self.assertEqual(response.status_code, 302) diff --git a/backend/report_submission/views.py b/backend/report_submission/views.py index 9a74ac1f32..8cbd337e2d 100644 --- a/backend/report_submission/views.py +++ b/backend/report_submission/views.py @@ -20,7 +20,7 @@ from audit.utils import Util from audit.models.models import ExcelFile from audit.fixtures.excel import FORM_SECTIONS -from config.settings import STATIC_SITE_URL, STATE_ABBREVS +from config.settings import STATIC_SITE_URL, STATE_ABBREVS, DOLLAR_THRESHOLDS from report_submission.forms import AuditeeInfoForm, GeneralInformationForm @@ -35,11 +35,14 @@ def get(self, request): # Step 1 class EligibilityFormView(LoginRequiredMixin, View): def get(self, request): - args = {} - args["step"] = 1 - return render(request, "report_submission/step-1.html", args) + args = { + "step": 1, + "dollar_thresholds": [ + dict_item["message"] for dict_item in DOLLAR_THRESHOLDS + ], + } - # render eligibility form + return render(request, "report_submission/step-1.html", args) # gather/save step 1 info, redirect to step 2 def post(self, post_request): From a92e2e5e36c25f75ef5021bca307e4aaf3431e7c Mon Sep 17 00:00:00 2001 From: Jason Rothacker Date: Mon, 9 Dec 2024 13:04:19 -0800 Subject: [PATCH 7/7] Adding myself to TF developer config (#4523) --- terraform/meta/config.tf | 1 + 1 file changed, 1 insertion(+) diff --git a/terraform/meta/config.tf b/terraform/meta/config.tf index ec4b282110..c89aa05012 100644 --- a/terraform/meta/config.tf +++ b/terraform/meta/config.tf @@ -28,6 +28,7 @@ locals { "sudha.kumar@gsa.gov", "philip.dominguez@gsa.gov", "robert.novak@gsa.gov", + "jason.rothacker@gsa.gov", ] # All spaces have the same SpaceManagers for now