Compare commits

..

383 Commits

Author SHA1 Message Date
Kenneth Kehl
3590c87334 fix report gen 2024-11-14 08:21:19 -08:00
Kenneth Kehl
8c53c137f6 fix imports 2024-11-14 08:11:41 -08:00
Kenneth Kehl
92674bfeea add methods for asynchronous report generation 2024-11-14 07:59:15 -08:00
Steven Reilly
01e52b9a20 Merge pull request #2093 from GSA/fix-login-staging-env-var-url
Fix Login.gov sign in URL formatting for staging
2024-11-08 11:04:21 -05:00
Carlo Costino
044f1cf170 Fix flake8 warnings on comments
Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2024-11-08 10:53:20 -05:00
Carlo Costino
8f89d25909 Comment out part of test
This is due to recent changes in the API and an error now being thrown because the job cache cannot be properly accessed.

Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2024-11-08 10:45:07 -05:00
Jonathan Bobel
3afffde6cb Merge pull request #2076 from GSA/2056-template-creation-flow-voiceover-gets-stuck-in-a-loop
Template voiceover gets stuck in a loop #2056
2024-11-08 10:13:32 -05:00
Carlo Costino
312612a04d Fix Login.gov sign in URL formatting for staging
This changeset fixes a typo by removing an extra E from the Login.gov sign in URL, which was causing the STATE variable to not be properly replaced with the actual state, because STATE != STATEE.

Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2024-11-07 22:22:24 -05:00
Carlo Costino
fe00050e1f Merge pull request #2075 from GSA/USN-COMPLY-51-Verify_State
Verify state for login.gov
2024-11-07 14:18:17 -05:00
Alex Janousek
822fa6f397 Merge pull request #2084 from GSA/dependabot/npm_and_yarn/multi-9f37c16f8f
Bump cookie and express
2024-11-07 12:51:22 -05:00
Cliff Hill
e9b515d4cc Another test fixed.
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2024-11-07 12:01:06 -05:00
Cliff Hill
923a345d19 Fixed tests.
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2024-11-07 11:56:03 -05:00
Cliff Hill
6e3a569a0a Resend invites works.
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2024-11-07 09:56:18 -05:00
Cliff Hill
14bbabcab7 Invites are now working.
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2024-11-07 08:37:45 -05:00
Cliff Hill
95a39cfd31 Trying to get invites to flow correctly.
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2024-11-06 16:04:18 -05:00
Cliff Hill
f363a8e184 Getting all the needed data in place.
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2024-11-06 14:30:28 -05:00
Cliff Hill
d798d3695e More little fixes.
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2024-11-06 10:48:28 -05:00
Cliff Hill
c8ed66cbfe Storing user data in redis.
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2024-11-06 10:41:20 -05:00
Cliff Hill
b532ce8959 Fixing tests, and resend invites endpoint.
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2024-11-06 08:20:11 -05:00
Cliff Hill
fc09e70579 Working on fixing the tests. 2024-11-06 08:20:11 -05:00
Cliff Hill
a090c90ed6 Debuggin'
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2024-11-06 08:20:11 -05:00
Cliff Hill
a39c844c30 Properly handling and validating the state for login.gov
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2024-11-06 08:20:10 -05:00
Cliff Hill
a02448a0fa Removing unused state parameter for _get_access_token()
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2024-11-06 08:20:10 -05:00
dependabot[bot]
0500da354d Bump cookie and express
Bumps [cookie](https://github.com/jshttp/cookie) and [express](https://github.com/expressjs/express). These dependencies needed to be updated together.

Updates `cookie` from 0.6.0 to 0.7.1
- [Release notes](https://github.com/jshttp/cookie/releases)
- [Commits](https://github.com/jshttp/cookie/compare/v0.6.0...v0.7.1)

Updates `express` from 4.21.0 to 4.21.1
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/4.21.1/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.21.0...4.21.1)

---
updated-dependencies:
- dependency-name: cookie
  dependency-type: indirect
- dependency-name: express
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-05 17:56:50 +00:00
Alex Janousek
ff194b2f2b Merge pull request #2082 from GSA/dependabot/npm_and_yarn/sass-embedded-1.80.6
Bump sass-embedded from 1.80.5 to 1.80.6
2024-11-05 12:56:03 -05:00
Alex Janousek
0aa2c76f9a Merge pull request #2083 from GSA/dependabot/npm_and_yarn/rollup-4.24.4
Bump rollup from 4.24.3 to 4.24.4
2024-11-05 12:55:48 -05:00
dependabot[bot]
2503eac887 Bump rollup from 4.24.3 to 4.24.4
Bumps [rollup](https://github.com/rollup/rollup) from 4.24.3 to 4.24.4.
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v4.24.3...v4.24.4)

---
updated-dependencies:
- dependency-name: rollup
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-04 23:49:15 +00:00
dependabot[bot]
1564507e13 Bump sass-embedded from 1.80.5 to 1.80.6
Bumps [sass-embedded](https://github.com/sass/embedded-host-node) from 1.80.5 to 1.80.6.
- [Changelog](https://github.com/sass/embedded-host-node/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sass/embedded-host-node/compare/1.80.5...1.80.6)

---
updated-dependencies:
- dependency-name: sass-embedded
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-04 23:49:02 +00:00
Alex Janousek
737d7b70bf Merge pull request #2065 from GSA/dependabot/npm_and_yarn/babel/preset-env-7.26.0
Bump @babel/preset-env from 7.25.9 to 7.26.0
2024-11-04 12:47:55 -05:00
Alex Janousek
937e258d2b Merge pull request #2066 from GSA/dependabot/npm_and_yarn/playwright-1.48.2
Bump playwright from 1.48.1 to 1.48.2
2024-11-04 12:47:40 -05:00
dependabot[bot]
569de1ab49 Bump @babel/preset-env from 7.25.9 to 7.26.0
Bumps [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) from 7.25.9 to 7.26.0.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.26.0/packages/babel-preset-env)

---
updated-dependencies:
- dependency-name: "@babel/preset-env"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-04 17:13:47 +00:00
dependabot[bot]
154912fda5 Bump playwright from 1.48.1 to 1.48.2
Bumps [playwright](https://github.com/microsoft/playwright) from 1.48.1 to 1.48.2.
- [Release notes](https://github.com/microsoft/playwright/releases)
- [Commits](https://github.com/microsoft/playwright/compare/v1.48.1...v1.48.2)

---
updated-dependencies:
- dependency-name: playwright
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-04 17:13:02 +00:00
Alex Janousek
8c3b83091d Merge pull request #2064 from GSA/dependabot/npm_and_yarn/babel/core-7.26.0
Bump @babel/core from 7.25.8 to 7.26.0
2024-11-04 12:12:25 -05:00
Alex Janousek
78474aea65 Merge pull request #2070 from GSA/dependabot/npm_and_yarn/sass-embedded-1.80.5
Bump sass-embedded from 1.80.4 to 1.80.5
2024-11-04 12:11:58 -05:00
Alex Janousek
643b4a3d7c Merge pull request #2071 from GSA/dependabot/npm_and_yarn/rollup-4.24.3
Bump rollup from 4.24.0 to 4.24.3
2024-11-04 12:11:39 -05:00
Beverly Nguyen
66d18ced10 fixed testing 2024-11-01 12:16:22 -07:00
Beverly Nguyen
334cd4041a fixed managed folder position 2024-11-01 12:00:00 -07:00
Beverly Nguyen
4d0d92f825 added attributes for a11y 2024-11-01 11:47:25 -07:00
Alex Janousek
60e9ac18f5 Merge pull request #1949 from GSA/1928-develop-new-page-templates-in-code-to-sit-behind-the-log-in
New guidance and subpages, and return to previous pages.
2024-10-31 12:49:47 -04:00
Carlo Costino
1933dad137 Merge pull request #2063 from GSA/API-1328_Logging_Formatter_With_Scrub
API-1328 - Using a custom formatter to scrub PII from all log records.
2024-10-30 13:45:47 -04:00
Cliff Hill
278541fa5b Compiling email regex
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2024-10-30 11:44:39 -04:00
Cliff Hill
452ab7eb86 Fixing dependency error.
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2024-10-30 09:36:22 -04:00
Cliff Hill
005e97f034 Using re.compile().
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2024-10-30 09:09:53 -04:00
Beverly Nguyen
4700534155 removed js from gulp 2024-10-29 20:33:56 -07:00
Beverly Nguyen
02e3efd105 adjusted subnav to hover 2024-10-29 20:19:51 -07:00
dependabot[bot]
4de7b5a5ec Bump rollup from 4.24.0 to 4.24.3
Bumps [rollup](https://github.com/rollup/rollup) from 4.24.0 to 4.24.3.
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v4.24.0...v4.24.3)

---
updated-dependencies:
- dependency-name: rollup
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-29 23:41:33 +00:00
dependabot[bot]
77716e254e Bump sass-embedded from 1.80.4 to 1.80.5
Bumps [sass-embedded](https://github.com/sass/embedded-host-node) from 1.80.4 to 1.80.5.
- [Changelog](https://github.com/sass/embedded-host-node/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sass/embedded-host-node/compare/1.80.4...1.80.5)

---
updated-dependencies:
- dependency-name: sass-embedded
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-29 23:41:21 +00:00
alexjanousekGSA
fd68a918e7 Updated feature flagging readme 2024-10-29 15:53:43 -04:00
Kenneth Kehl
64b979c0f7 Merge pull request #2005 from GSA/notify-admin-2001
fix moderate accessibility violation scope='row'
2024-10-29 12:38:07 -07:00
alexjanousekGSA
b806fd5eec Updated code based on comments 2024-10-29 15:28:07 -04:00
Beverly Nguyen
7ed04c82d6 removed feature flag content 2024-10-28 13:43:53 -07:00
Beverly Nguyen
a601906ef5 fixed a11y 2024-10-28 13:11:29 -07:00
Andrew Shumway
b352a13328 Merge pull request #2067 from GSA/dependabot/pip/werkzeug-3.0.6
Bump werkzeug from 3.0.3 to 3.0.6
2024-10-28 13:58:19 -06:00
alexjanousekGSA
d7db335a99 Updated depedency 2024-10-28 11:49:24 -04:00
alexjanousekGSA
94f90454e3 Linting issue addressed 2024-10-28 11:13:02 -04:00
alexjanousekGSA
de02780bd8 Added back tests that were removed 2024-10-28 11:07:48 -04:00
dependabot[bot]
70c95cdeb6 Bump werkzeug from 3.0.3 to 3.0.6
Bumps [werkzeug](https://github.com/pallets/werkzeug) from 3.0.3 to 3.0.6.
- [Release notes](https://github.com/pallets/werkzeug/releases)
- [Changelog](https://github.com/pallets/werkzeug/blob/main/CHANGES.rst)
- [Commits](https://github.com/pallets/werkzeug/compare/3.0.3...3.0.6)

---
updated-dependencies:
- dependency-name: werkzeug
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-26 00:08:52 +00:00
Beverly Nguyen
a11bd0e344 removed pdf test 2024-10-25 13:33:08 -07:00
Beverly Nguyen
822682f256 fixed test failures 2024-10-25 13:23:58 -07:00
Beverly Nguyen
6a6a54e889 fixed test failures 2024-10-25 13:16:07 -07:00
Beverly Nguyen
bdb3e777c5 adjust settimeout 2024-10-25 11:20:41 -07:00
Beverly Nguyen
cf3c7be9bf pdf added 2024-10-25 11:00:51 -07:00
Beverly Nguyen
d8ae3f3056 pdf added 2024-10-25 10:59:55 -07:00
alexjanousekGSA
96a8ccc64a More linting 2024-10-25 11:35:56 -04:00
alexjanousekGSA
ccdf9f16d8 fixing lint errors, added another test 2024-10-25 11:29:07 -04:00
dependabot[bot]
b4f4e19665 Bump @babel/core from 7.25.8 to 7.26.0
Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.25.8 to 7.26.0.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.26.0/packages/babel-core)

---
updated-dependencies:
- dependency-name: "@babel/core"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-25 14:59:28 +00:00
Alex Janousek
1f1f8bcd75 Merge pull request #2060 from GSA/dependabot/npm_and_yarn/babel/preset-env-7.25.9
Bump @babel/preset-env from 7.25.8 to 7.25.9
2024-10-25 10:58:24 -04:00
Alex Janousek
e4445b097e Merge pull request #2062 from GSA/dependabot/npm_and_yarn/sass-embedded-1.80.4
Bump sass-embedded from 1.80.3 to 1.80.4
2024-10-25 10:58:10 -04:00
alexjanousekGSA
09f400ad8e Merge branch '1928-develop-new-page-templates-in-code-to-sit-behind-the-log-in' of https://github.com/GSA/notifications-admin into 1928-develop-new-page-templates-in-code-to-sit-behind-the-log-in 2024-10-25 10:57:40 -04:00
alexjanousekGSA
01f1175e52 Added back removed tests 2024-10-25 10:57:34 -04:00
Beverly Nguyen
12b2d0d86d isort 2024-10-24 17:43:10 -07:00
Beverly Nguyen
2bbc58c8af changed guidanced to best practices 2024-10-24 17:03:45 -07:00
Beverly Nguyen
4b85ae6493 remove files not needed 2024-10-24 16:39:48 -07:00
Beverly Nguyen
3010ae1d9e changed guidance to best practices 2024-10-24 16:30:15 -07:00
alexjanousekGSA
cf4ac930c5 Merge branch 'main' into 1928-develop-new-page-templates-in-code-to-sit-behind-the-log-in 2024-10-24 17:58:48 -04:00
alexjanousekGSA
09896b98cd Merge branch '1928-develop-new-page-templates-in-code-to-sit-behind-the-log-in' of https://github.com/GSA/notifications-admin into 1928-develop-new-page-templates-in-code-to-sit-behind-the-log-in 2024-10-24 17:58:28 -04:00
alexjanousekGSA
14880bf7ee Fixed one test 2024-10-24 17:58:23 -04:00
Sheev Davé
846b5b51e7 Merge pull request #2012 from GSA/1999-dashboard-a11y-fixes
1999 dashboard a11y fixes
2024-10-24 14:07:10 -07:00
Beverly Nguyen
00ad7b7581 updated content from feedback 2024-10-24 13:57:01 -07:00
alexjanousekGSA
e64ba86a2b Enabled new feature in demo 2024-10-24 13:02:44 -04:00
alexjanousekGSA
4dd8b578a9 Toggled guidance feature off from staging 2024-10-24 12:38:22 -04:00
Cliff Hill
a9948131cc Scrubbing log records with the formatter.
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2024-10-24 12:35:40 -04:00
Cliff Hill
543239d078 Reversing accidental commit.
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2024-10-24 12:32:26 -04:00
Cliff Hill
e6c0f045a5 Added PII scrub for all logging through the formatter.
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2024-10-24 12:23:32 -04:00
alexjanousekGSA
1b18b4c146 Merge branch '1928-develop-new-page-templates-in-code-to-sit-behind-the-log-in' of https://github.com/GSA/notifications-admin into 1928-develop-new-page-templates-in-code-to-sit-behind-the-log-in 2024-10-24 11:54:26 -04:00
alexjanousekGSA
661d9b5517 Added feature flagging document 2024-10-24 11:54:21 -04:00
Carlo Costino
a349fb82dc Merge pull request #2004 from GSA/notify-admin-2003
Users can be invited with no permissions
2024-10-24 09:57:07 -04:00
Carlo Costino
a715b33fd0 Merge pull request #2053 from GSA/notify-admin-2037
remove permission to manage API integration
2024-10-24 09:49:21 -04:00
Carlo Costino
9ce00acec3 Merge pull request #2024 from GSA/USN-COMPLY-50-Verify_Nonce_for_Invite
US-NOTIFY-COMPLY 50: Verify Nonce For Invite
2024-10-24 09:36:58 -04:00
dependabot[bot]
353e2bb9a6 Bump sass-embedded from 1.80.3 to 1.80.4
Bumps [sass-embedded](https://github.com/sass/embedded-host-node) from 1.80.3 to 1.80.4.
- [Changelog](https://github.com/sass/embedded-host-node/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sass/embedded-host-node/compare/1.80.3...1.80.4)

---
updated-dependencies:
- dependency-name: sass-embedded
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-23 23:58:09 +00:00
Beverly Nguyen
c0d05c99a2 testing errors 2024-10-23 10:09:47 -07:00
dependabot[bot]
c95e949856 Bump @babel/preset-env from 7.25.8 to 7.25.9
Bumps [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) from 7.25.8 to 7.25.9.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.25.9/packages/babel-preset-env)

---
updated-dependencies:
- dependency-name: "@babel/preset-env"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-22 23:50:01 +00:00
Beverly Nguyen
ff4380b5a0 fixed testing 2024-10-22 16:48:07 -07:00
Beverly Nguyen
f2ea113856 subnav 2024-10-22 16:41:41 -07:00
Andrew Shumway
f4b6ca4a79 Merge pull request #2054 from GSA/dependabot/pip/coverage-7.6.4
Bump coverage from 7.6.0 to 7.6.4
2024-10-22 14:15:00 -06:00
Cliff Hill
341e5d4cb2 Removed logging.
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2024-10-22 14:51:09 -04:00
alexjanousekGSA
4f802587b9 Fixing linting errors 2024-10-22 12:20:35 -04:00
Alex Janousek
3013d27d7c Merge pull request #2055 from GSA/dependabot/npm_and_yarn/sass-embedded-1.80.3
Bump sass-embedded from 1.79.5 to 1.80.3
2024-10-22 10:27:05 -04:00
dependabot[bot]
17e12495dd Bump sass-embedded from 1.79.5 to 1.80.3
Bumps [sass-embedded](https://github.com/sass/embedded-host-node) from 1.79.5 to 1.80.3.
- [Changelog](https://github.com/sass/embedded-host-node/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sass/embedded-host-node/compare/1.79.5...1.80.3)

---
updated-dependencies:
- dependency-name: sass-embedded
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-21 23:55:37 +00:00
dependabot[bot]
35d95e4f5c Bump coverage from 7.6.0 to 7.6.4
Bumps [coverage](https://github.com/nedbat/coveragepy) from 7.6.0 to 7.6.4.
- [Release notes](https://github.com/nedbat/coveragepy/releases)
- [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst)
- [Commits](https://github.com/nedbat/coveragepy/compare/7.6.0...7.6.4)

---
updated-dependencies:
- dependency-name: coverage
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-21 23:44:06 +00:00
Cliff Hill
e04adba4fd Test written for get_id_token.
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2024-10-21 16:41:50 -04:00
Cliff Hill
866a4ad7bd Got the unit test to be fixed, still figuring out a new test for the new
function.

Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2024-10-21 16:41:49 -04:00
Cliff Hill
579a65c92d Removed defunct imports.
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2024-10-21 16:41:49 -04:00
Cliff Hill
7275dac6a0 black, isort, and flake8.
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2024-10-21 16:41:49 -04:00
Cliff Hill
8c40538334 Nonce is working now for invites.
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2024-10-21 16:41:49 -04:00
Cliff Hill
da6882774b Getting the redis stuff configured correctly.
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2024-10-21 16:41:49 -04:00
Cliff Hill
d0cda995cf Standardising nonce storage/retrieval through redis for both login and
invite.

Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2024-10-21 16:41:49 -04:00
Cliff Hill
82cef7dbd3 Nonce stuff added.
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2024-10-21 16:41:33 -04:00
Kenneth Kehl
e2020c188a remove permsision to manage API integration 2024-10-21 12:38:08 -07:00
Kenneth Kehl
7db678ddec remove permsision to manage API integration 2024-10-21 12:27:44 -07:00
Beverly Nguyen
7775508c97 fixed testing 2024-10-21 10:45:08 -07:00
Kenneth Kehl
3601b16c7b Merge pull request #2049 from GSA/nonce_nonce_nonce
comment out check for now
2024-10-18 10:24:44 -07:00
Kenneth Kehl
eaed2fc879 comment out check for now 2024-10-18 07:23:19 -07:00
Alex Janousek
00f63aed23 Merge pull request #2033 from GSA/dependabot/npm_and_yarn/rollup/plugin-commonjs-28.0.1
Bump @rollup/plugin-commonjs from 28.0.0 to 28.0.1
2024-10-17 15:10:10 -04:00
Carlo Costino
185f00cd01 Merge pull request #2025 from GSA/notify-compliance-52
investigate security.txt
2024-10-17 14:51:00 -04:00
alexjanousekGSA
088c2244a3 Merge branch '1928-develop-new-page-templates-in-code-to-sit-behind-the-log-in' of https://github.com/GSA/notifications-admin into 1928-develop-new-page-templates-in-code-to-sit-behind-the-log-in 2024-10-17 14:48:10 -04:00
alexjanousekGSA
93bc3792be Added feature flagging to each environment yml 2024-10-17 14:48:02 -04:00
Alex Janousek
417fac6dd1 Merge branch 'main' into 1928-develop-new-page-templates-in-code-to-sit-behind-the-log-in 2024-10-17 13:17:18 -04:00
alexjanousekGSA
4b62d0e685 Added command variable from env ymls to manifest 2024-10-17 13:16:39 -04:00
Alex Janousek
149065576f Merge pull request #2034 from GSA/dependabot/npm_and_yarn/playwright-1.48.1
Bump playwright from 1.48.0 to 1.48.1
2024-10-17 13:11:08 -04:00
alexjanousekGSA
4eed138dc6 Merge branch '1928-develop-new-page-templates-in-code-to-sit-behind-the-log-in' of https://github.com/GSA/notifications-admin into 1928-develop-new-page-templates-in-code-to-sit-behind-the-log-in 2024-10-17 13:10:40 -04:00
alexjanousekGSA
7e505f7fda Updated sandbox and environment yamls 2024-10-17 13:09:58 -04:00
dependabot[bot]
4973cb84b1 Bump playwright from 1.48.0 to 1.48.1
Bumps [playwright](https://github.com/microsoft/playwright) from 1.48.0 to 1.48.1.
- [Release notes](https://github.com/microsoft/playwright/releases)
- [Commits](https://github.com/microsoft/playwright/compare/v1.48.0...v1.48.1)

---
updated-dependencies:
- dependency-name: playwright
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-16 23:18:40 +00:00
dependabot[bot]
c2ea4684f6 Bump @rollup/plugin-commonjs from 28.0.0 to 28.0.1
Bumps [@rollup/plugin-commonjs](https://github.com/rollup/plugins/tree/HEAD/packages/commonjs) from 28.0.0 to 28.0.1.
- [Changelog](https://github.com/rollup/plugins/blob/master/packages/commonjs/CHANGELOG.md)
- [Commits](https://github.com/rollup/plugins/commits/commonjs-v28.0.1/packages/commonjs)

---
updated-dependencies:
- dependency-name: "@rollup/plugin-commonjs"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-16 23:18:17 +00:00
Carlo Costino
ca60eb03c0 Merge pull request #2030 from GSA/fix-deploy-actions
Fix demo and prod deploy actions
2024-10-16 14:36:23 -04:00
Carlo Costino
a3c021b154 Fix demo and prod deploy actions
This changeset makes a couple of more adjustments to the prod and demo deploy actions to make sure they are in sync with staging and work.

Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2024-10-16 14:26:02 -04:00
Carlo Costino
31076781a3 Merge pull request #2027 from GSA/fix-deploy-actions
Fix the prod and demo deployment actions
2024-10-16 13:11:16 -04:00
Carlo Costino
e54d18170e Add missing env var
Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2024-10-16 13:03:35 -04:00
Alex Janousek
c3f4482677 Merge pull request #2009 from GSA/dependabot/npm_and_yarn/uswds/uswds-3.9.0
Bump @uswds/uswds from 3.8.2 to 3.9.0
2024-10-16 12:50:18 -04:00
Alex Janousek
0183f37c7b Merge pull request #2022 from GSA/dependabot/npm_and_yarn/sass-embedded-1.79.5
Bump sass-embedded from 1.79.4 to 1.79.5
2024-10-16 12:49:58 -04:00
Carlo Costino
fc6adc6771 Fix the prod and demo deployment actions
This changeset fixes the prod and deployment actions so they have the correct environment variables.  It also fixes the egress proxy deploy config for each.

Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2024-10-16 12:44:55 -04:00
Kenneth Kehl
1dbb369143 fix test 2024-10-16 08:38:12 -07:00
Kenneth Kehl
f32845752a update email address 2024-10-16 08:18:19 -07:00
Kenneth Kehl
ae0f8d58d9 investigate security.txt 2024-10-16 07:48:00 -07:00
Beverly Nguyen
90e8017cd5 remove photos and edit content 2024-10-15 10:15:08 -07:00
Kenneth Kehl
34ccfb5bd7 Merge pull request #1996 from GSA/e2e_tests_uncomment
Make e2e tests work fully with staging API
2024-10-15 09:57:19 -07:00
alexjanousekGSA
2504e58a87 Fixed linting errors 2024-10-15 12:54:37 -04:00
dependabot[bot]
db5626f5b0 Bump sass-embedded from 1.79.4 to 1.79.5
Bumps [sass-embedded](https://github.com/sass/embedded-host-node) from 1.79.4 to 1.79.5.
- [Changelog](https://github.com/sass/embedded-host-node/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sass/embedded-host-node/compare/1.79.4...1.79.5)

---
updated-dependencies:
- dependency-name: sass-embedded
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-14 23:36:07 +00:00
alexjanousekGSA
e62cc021e9 Added code for hiding guidance pages and updated backstop reference files 2024-10-14 14:44:20 -04:00
Alex Janousek
2624bd885d Merge pull request #2019 from GSA/dependabot/npm_and_yarn/babel/core-7.25.8
Bump @babel/core from 7.25.2 to 7.25.8
2024-10-14 13:53:01 -04:00
Alex Janousek
a5ff9af1eb Merge pull request #2011 from GSA/dependabot/npm_and_yarn/playwright-1.48.0
Bump playwright from 1.47.2 to 1.48.0
2024-10-14 13:44:34 -04:00
dependabot[bot]
8e29229d8b Bump @babel/core from 7.25.2 to 7.25.8
Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.25.2 to 7.25.8.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.25.8/packages/babel-core)

---
updated-dependencies:
- dependency-name: "@babel/core"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-14 17:39:42 +00:00
Alex Janousek
c30dbec6ce Merge pull request #2020 from GSA/dependabot/npm_and_yarn/babel/preset-env-7.25.8
Bump @babel/preset-env from 7.25.7 to 7.25.8
2024-10-14 13:38:24 -04:00
Jonathan Bobel
bfead7ffac Merge branch 'main' of https://github.com/GSA/notifications-admin into 1999-dashboard-a11y-fixes 2024-10-11 10:22:14 -04:00
dependabot[bot]
29854c6164 Bump @babel/preset-env from 7.25.7 to 7.25.8
Bumps [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) from 7.25.7 to 7.25.8.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.25.8/packages/babel-preset-env)

---
updated-dependencies:
- dependency-name: "@babel/preset-env"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-10 23:19:49 +00:00
Carlo Costino
978031744f Merge pull request #2016 from GSA/use-the-correct-env-var-names
Use the correct environment variable names
2024-10-10 14:20:16 -04:00
Carlo Costino
f27703112a Use the correct environment variable names
This changeset corrects the reference to the environment names that we are actually trying to reference.

Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2024-10-10 13:06:47 -04:00
alexjanousekGSA
035c4158f9 Added new reference files 2024-10-10 11:29:20 -04:00
Carlo Costino
c47144a8b0 Merge pull request #2014 from GSA/swap-egress-proxy-config-to-env
Swap out config variables for env variables
2024-10-10 10:33:18 -04:00
alexjanousekGSA
54d5ee96d0 Merge branch 'main' into 1928-develop-new-page-templates-in-code-to-sit-behind-the-log-in 2024-10-10 09:47:04 -04:00
Carlo Costino
fd447e9a75 Swap out config variables for env variables
This changeset swaps the CF_USERNAME and CF_PASSWORD config vars to be proper env vars so they can be read in as expected.

Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2024-10-09 14:20:10 -06:00
Carlo Costino
9ee0da0b32 Merge pull request #2013 from GSA/add-missing-egress-proxy-inputs
Add missing inputs to egress proxy deploy action
2024-10-09 14:00:27 -06:00
Carlo Costino
2fbce24f97 Add missing inputs to egress proxy deploy action
This changeset adds a few missing inputs to the egress proxy deploy action so that it can use the provided environment variables properly.

Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2024-10-09 13:48:47 -06:00
Carlo Costino
10da94dbf8 Merge pull request #1997 from GSA/update-egress-proxy-even-more
Add missing environment veriables to egress deploy action
2024-10-09 13:24:56 -06:00
Kenneth Kehl
d86b1afb9a code review feedback 2024-10-09 11:42:20 -07:00
Beverly Nguyen
34f133cf62 Merge branch 'main' into 1928-develop-new-page-templates-in-code-to-sit-behind-the-log-in 2024-10-09 11:21:29 -07:00
Kenneth Kehl
10a8d1b938 code review feedback 2024-10-09 11:04:15 -07:00
Kenneth Kehl
b7b23ba6c8 try reverting hardcoding 2024-10-09 10:06:56 -07:00
Jonathan Bobel
a65f9f9bbf Updates to the js and tests 2024-10-09 12:46:19 -04:00
Kenneth Kehl
1cc760c153 write a script to get the VCAP value 2024-10-09 09:43:48 -07:00
Jonathan Bobel
175a47310e Adding the correct ID to the popup to read correctly to screen readers 2024-10-09 11:20:43 -04:00
Jonathan Bobel
77f96e901b Merge branch 'main' of https://github.com/GSA/notifications-admin into 1999-dashboard-a11y-fixes 2024-10-09 10:27:20 -04:00
Steven Reilly
338fbfc407 Merge pull request #2008 from GSA/2007-bug-total-messages-sms-sent-always-zero
2007 - bug - total messages sms sent always zero
2024-10-09 10:26:20 -04:00
Jonathan Bobel
5adcfae5d8 Fixing a test 2024-10-09 09:56:19 -04:00
dependabot[bot]
b8b4a707a3 Bump playwright from 1.47.2 to 1.48.0
Bumps [playwright](https://github.com/microsoft/playwright) from 1.47.2 to 1.48.0.
- [Release notes](https://github.com/microsoft/playwright/releases)
- [Commits](https://github.com/microsoft/playwright/compare/v1.47.2...v1.48.0)

---
updated-dependencies:
- dependency-name: playwright
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-08 23:37:52 +00:00
dependabot[bot]
61ea8e0b03 Bump @uswds/uswds from 3.8.2 to 3.9.0
Bumps [@uswds/uswds](https://github.com/uswds/uswds) from 3.8.2 to 3.9.0.
- [Release notes](https://github.com/uswds/uswds/releases)
- [Commits](https://github.com/uswds/uswds/compare/v3.8.2...v3.9.0)

---
updated-dependencies:
- dependency-name: "@uswds/uswds"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-08 23:37:27 +00:00
Beverly Nguyen
edca721f5b content updates vs 2 2024-10-08 15:32:11 -07:00
Jonathan Bobel
3ad6f9daae Removing reference to financial year 2024-10-08 16:37:33 -04:00
Jonathan Bobel
947f85ba51 This was from a previous commit 2024-10-08 16:24:03 -04:00
Jonathan Bobel
65c99bf8e8 Removing instances of a financial year 2024-10-08 16:12:50 -04:00
Jonathan Bobel
d8feea6bd5 Merge branch 'main' of https://github.com/GSA/notifications-admin 2024-10-08 16:06:19 -04:00
Jonathan Bobel
98fb68ad14 Updated to table captions and hiding the legend on the dashboard if it's empty 2024-10-08 16:05:00 -04:00
Beverly Nguyen
6213a9bc96 font changes 2024-10-08 11:34:46 -07:00
Kenneth Kehl
9c59e40de7 fix moderate accessibility violation scope='row' 2024-10-08 11:32:55 -07:00
Alex Janousek
c89a6089a0 Merge pull request #1984 from GSA/dependabot/npm_and_yarn/babel/preset-env-7.25.7
Bump @babel/preset-env from 7.25.4 to 7.25.7
2024-10-08 12:55:44 -04:00
Alex Janousek
971486be20 Merge pull request #1994 from GSA/dependabot/npm_and_yarn/multi-cf87d80143
Bump send and express
2024-10-08 12:55:18 -04:00
Alex Janousek
cd6c9af0bc Merge pull request #1983 from GSA/dependabot/npm_and_yarn/rollup-4.24.0
Bump rollup from 4.22.5 to 4.24.0
2024-10-08 12:54:04 -04:00
Alex Janousek
7eb7ed1855 Merge pull request #1977 from GSA/dependabot/npm_and_yarn/sass-embedded-1.79.4
Bump sass-embedded from 1.79.3 to 1.79.4
2024-10-08 12:53:35 -04:00
Alex Janousek
ea93b57190 Merge pull request #1960 from GSA/dependabot/npm_and_yarn/rollup/plugin-commonjs-28.0.0
Bump @rollup/plugin-commonjs from 26.0.1 to 28.0.0
2024-10-08 12:52:58 -04:00
Kenneth Kehl
8df380ca0d Users can be invited with no permissions 2024-10-08 08:32:20 -07:00
Jonathan Bobel
3865c5b952 Update to address a11y issue of "Broken Aria link" in the dialog 2024-10-08 10:36:35 -04:00
Kenneth Kehl
f37b89849e cleanup 2024-10-07 13:44:43 -07:00
Kenneth Kehl
397bbeabde Merge pull request #2000 from GSA/stvnrlly-patch-1
Update notify-pilot-info.md
2024-10-07 13:42:33 -07:00
Kenneth Kehl
a11c567de3 fix moderate axe-core accessibility violation 2024-10-07 11:45:14 -07:00
Steven Reilly
bdc27c10d0 Update notify-pilot-info.md 2024-10-07 14:40:50 -04:00
Kenneth Kehl
f7f449ff07 try h2 2024-10-07 11:31:02 -07:00
Kenneth Kehl
b133def7fc cleanup 2024-10-07 11:02:04 -07:00
Kenneth Kehl
b4b15bc209 cleanup 2024-10-07 10:45:02 -07:00
Kenneth Kehl
44524eb9e2 try to not put vcap services into a secret 2024-10-07 10:26:43 -07:00
Kenneth Kehl
4b8b078476 try to not put vcap services into a secret 2024-10-07 10:03:45 -07:00
Kenneth Kehl
22f9ff603a try using h3 instead of h4 2024-10-07 09:11:10 -07:00
Kenneth Kehl
3f7e600ac1 try using h3 instead of h4 2024-10-07 08:37:34 -07:00
Kenneth Kehl
5a5b0649e0 restore axe_core level to minor 2024-10-07 08:23:18 -07:00
Kenneth Kehl
a23fe5c046 relax axe-core tests for now 2024-10-07 08:03:51 -07:00
Kenneth Kehl
306391c958 relax axe-core tests for now 2024-10-07 07:54:14 -07:00
Kenneth Kehl
e41ad9fab9 update secrets 2024-10-07 07:47:30 -07:00
Kenneth Kehl
fb83e8610c update secrets 2024-10-07 07:33:40 -07:00
Carlo Costino
d0a435becd Merge pull request #1978 from GSA/1971-bug-two-skip-links
1971 - BUG - There were two main content skip links
2024-10-05 15:47:58 -06:00
Carlo Costino
62f58c6e27 Merge pull request #1981 from GSA/1967-remove-uk-reference
1967 - Remove reference to UK on error page
2024-10-05 15:39:43 -06:00
Carlo Costino
0db68453b9 Merge pull request #1987 from GSA/1986-go-live-form-link-change
1986 - Updated links for Go Live Form
2024-10-05 15:29:10 -06:00
Carlo Costino
fbba1a735f Merge pull request #1992 from GSA/change-deploytools-demoprod
Switch out deprecated tools in demo/prod deploy scripts
2024-10-05 15:22:11 -06:00
Carlo Costino
35eb2a9013 Add missing environment veriables to egress deploy action
This changeset adds missing environment variables needed by the egress proxy to now properly deploy.

Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2024-10-04 22:49:42 -04:00
Kenneth Kehl
108e93d06a update secrets 2024-10-04 15:44:08 -07:00
Kenneth Kehl
4d4288d3c7 try again 2024-10-04 15:20:30 -07:00
Kenneth Kehl
c0ffa63f88 try again 2024-10-04 15:14:45 -07:00
Kenneth Kehl
89413c56ba try again 2024-10-04 15:04:34 -07:00
Kenneth Kehl
e6a3c0d4b7 try again 2024-10-04 14:52:58 -07:00
Kenneth Kehl
7d2f7d1c8a try again 2024-10-04 14:37:52 -07:00
Kenneth Kehl
f118b1c4bf try again 2024-10-04 14:28:12 -07:00
Kenneth Kehl
85a5e3075a try again 2024-10-04 14:18:48 -07:00
Kenneth Kehl
59959cfab4 try again 2024-10-04 14:09:39 -07:00
Kenneth Kehl
68cf422ca8 try again 2024-10-04 13:23:23 -07:00
Kenneth Kehl
a9999aa8ec try again 2024-10-04 13:18:15 -07:00
Kenneth Kehl
3a50fff6ea try again 2024-10-04 13:08:36 -07:00
Kenneth Kehl
c15d388fc2 try again 2024-10-04 13:00:31 -07:00
Kenneth Kehl
ec3ebe5b90 try again 2024-10-04 12:32:04 -07:00
Beverly Nguyen
fbdc01b109 Merge pull request #1995 from GSA/update-egress-proxy-more
Add one more potentially missing step
2024-10-04 12:29:08 -07:00
Kenneth Kehl
60e3c5291e try again 2024-10-04 12:18:46 -07:00
Carlo Costino
c178a3e77e Add one more potentially missing step
This changeset adds one more step that hopefully takes care of the egress proxy deploy.

Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2024-10-04 15:16:16 -04:00
Kenneth Kehl
4e3eb03040 try again 2024-10-04 12:10:16 -07:00
Carlo Costino
29b9e122ba Merge pull request #1993 from GSA/update-egress-proxy
Update cg-egress-proxy installation
2024-10-04 14:57:56 -04:00
dependabot[bot]
63c1652c40 Bump sass-embedded from 1.79.3 to 1.79.4
Bumps [sass-embedded](https://github.com/sass/embedded-host-node) from 1.79.3 to 1.79.4.
- [Changelog](https://github.com/sass/embedded-host-node/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sass/embedded-host-node/compare/1.79.3...1.79.4)

---
updated-dependencies:
- dependency-name: sass-embedded
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-04 18:48:30 +00:00
dependabot[bot]
f28a618e78 Bump @babel/preset-env from 7.25.4 to 7.25.7
Bumps [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) from 7.25.4 to 7.25.7.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.25.7/packages/babel-preset-env)

---
updated-dependencies:
- dependency-name: "@babel/preset-env"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-04 18:48:27 +00:00
dependabot[bot]
aa7c7b7d9a Bump rollup from 4.22.5 to 4.24.0
Bumps [rollup](https://github.com/rollup/rollup) from 4.22.5 to 4.24.0.
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v4.22.5...v4.24.0)

---
updated-dependencies:
- dependency-name: rollup
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-04 18:48:26 +00:00
dependabot[bot]
4c0221e295 Bump @rollup/plugin-commonjs from 26.0.1 to 28.0.0
Bumps [@rollup/plugin-commonjs](https://github.com/rollup/plugins/tree/HEAD/packages/commonjs) from 26.0.1 to 28.0.0.
- [Changelog](https://github.com/rollup/plugins/blob/master/packages/commonjs/CHANGELOG.md)
- [Commits](https://github.com/rollup/plugins/commits/commonjs-v28.0.0/packages/commonjs)

---
updated-dependencies:
- dependency-name: "@rollup/plugin-commonjs"
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-04 18:48:20 +00:00
dependabot[bot]
21d1b69c22 Bump send and express
Bumps [send](https://github.com/pillarjs/send) and [express](https://github.com/expressjs/express). These dependencies needed to be updated together.

Updates `send` from 0.18.0 to 0.19.0
- [Release notes](https://github.com/pillarjs/send/releases)
- [Changelog](https://github.com/pillarjs/send/blob/master/HISTORY.md)
- [Commits](https://github.com/pillarjs/send/compare/0.18.0...0.19.0)

Updates `express` from 4.20.0 to 4.21.0
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/4.21.0/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.20.0...4.21.0)

---
updated-dependencies:
- dependency-name: send
  dependency-type: indirect
- dependency-name: express
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-04 18:48:06 +00:00
Alex Janousek
5aac3130b3 Merge pull request #1950 from GSA/1927-user-story-brief-description-of-the-user-story
Backstop is implemented locally
2024-10-04 14:47:06 -04:00
Carlo Costino
75ce12f5da Update cg-egress-proxy installation
This changeset updates the installation of the cg-egress-proxy repo on account of the recent change to use the newer cg-cli-tools.  It also forces the update for staging to test this out for now; we will have to uncomment the check once this is working.

Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2024-10-04 14:41:26 -04:00
Kenneth Kehl
21bd20f607 try again 2024-10-04 11:32:16 -07:00
Andrew Shumway
371eb58392 Remove duplicate code in reference 2024-10-04 12:08:45 -06:00
Kenneth Kehl
a27b9a701b try again 2024-10-04 11:08:15 -07:00
Andrew Shumway
c328044636 Switch out deprecated tools in demo/prod deploy scripts 2024-10-04 12:03:16 -06:00
Kenneth Kehl
77f44d4d5e try again 2024-10-04 11:02:52 -07:00
alexjanousekGSA
73b3a61746 Moved condition back to top of method 2024-10-04 13:49:10 -04:00
alexjanousekGSA
c5b2535b8e Fixed calling of response.json() 2024-10-04 13:38:13 -04:00
Carlo Costino
9449b80975 Merge pull request #1991 from GSA/remove-extra-login-env-var
Remove an extra Login.gov environment variable
2024-10-04 13:01:49 -04:00
Kenneth Kehl
cc3d70303c add vcap secret 2024-10-04 09:57:15 -07:00
Carlo Costino
ef528360be Undo change to the cloud.gov repo
They reverted the repo name change

Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2024-10-04 12:54:19 -04:00
Carlo Costino
ae1a51ff79 Update reference to the renaming of the cloud-gov/cli-tools repo
Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2024-10-04 12:14:07 -04:00
Carlo Costino
e9b364010a Remove an extra Login.gov environment variable
This changeset removes the LOGIN_DOT_GOV_REGISTRATION_URL environment variable from the admin app deployment configuration.  This is only needed for the API.

Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2024-10-04 11:33:40 -04:00
Carlo Costino
a8bf2414b4 Merge pull request #1990 from GSA/remove-e2e-env-vars-from-deploy
Remove E2E env vars from deploy
2024-10-04 11:11:54 -04:00
Kenneth Kehl
ced229167f add vcap secret 2024-10-04 08:04:41 -07:00
alexjanousekGSA
8deed320f8 Tweaked mismatch percentage 2024-10-04 11:02:39 -04:00
Kenneth Kehl
114814b0b5 add vcap secret 2024-10-04 07:50:34 -07:00
Kenneth Kehl
88262302e6 add VCAP_SERVICES 2024-10-04 07:06:35 -07:00
Carlo Costino
2e8f82be3b Remove E2E env vars from deploy
The E2E environment variables should not be included with our deploys because we do not want to enable or run E2E tests in production or production-like environments.

Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2024-10-04 08:35:35 -04:00
Carlo Costino
d63cfb3cb0 Merge pull request #1988 from GSA/switch-18f-deploy-tool-to-CG
Switch 18f deploy tool to CG
2024-10-04 08:06:11 -04:00
Andrew Shumway
6980e28786 Switch 18f deploy tool to CG 2024-10-03 14:19:09 -06:00
Andrew Shumway
c9acf937cf Merge pull request #1975 from GSA/fix-cfcommand-deploytool
Fix cf_command argument for deploy tool
2024-10-03 14:05:13 -06:00
Kenneth Kehl
37bb89402e add VCAP_SERVICES 2024-10-03 12:09:15 -07:00
Kenneth Kehl
f20803ecae add VCAP_SERVICES 2024-10-03 12:04:50 -07:00
Kenneth Kehl
addf4f0959 add VCAP_SERVICES 2024-10-03 12:00:31 -07:00
Kenneth Kehl
b7f26454ff add VCAP_SERVICES 2024-10-03 11:53:11 -07:00
Kenneth Kehl
a669477f48 add VCAP_SERVICES 2024-10-03 11:49:42 -07:00
Jonathan Bobel
8c932a6072 Updated links for Go Live Form 2024-10-03 14:39:51 -04:00
Kenneth Kehl
d2c654214b add VCAP_SERVICES 2024-10-03 11:28:12 -07:00
Kenneth Kehl
3120f82b1e add VCAP_SERVICES 2024-10-03 11:09:17 -07:00
Kenneth Kehl
0e45588e5a add VCAP_SERVICES 2024-10-03 10:52:49 -07:00
Kenneth Kehl
d4223429ec merge from main 2024-10-03 10:49:56 -07:00
Jonathan Bobel
1ea15d5ba1 Updated text for this error page (although I don't know when someone would see it) 2024-10-02 16:02:18 -04:00
Kenneth Kehl
915b18bbbd Merge pull request #1970 from GSA/notify-api-1299
optimize S3 partitioning
2024-10-02 09:55:14 -07:00
Beverly Nguyen
cecfeb7441 revised content phone content 2024-10-02 09:52:44 -07:00
alexjanousekGSA
f2fc6da0ee Updated docs 2024-10-02 11:19:33 -04:00
alexjanousekGSA
e96aec9898 Merged in main, created reference images and added delay to screenshots 2024-10-02 11:16:30 -04:00
alexjanousekGSA
e11b6376c2 Redid reference files 2024-10-02 10:37:04 -04:00
Andrew Shumway
4e2630d675 Remove whitespace/fix caps on var 2024-10-02 08:18:47 -06:00
Andrew Shumway
0a5ca7d0d6 Pull in main/fix merge conflicts 2024-10-02 07:58:04 -06:00
Andrew Shumway
64a01e70b7 Wrap vars with quotes and indent 2024-10-02 07:55:58 -06:00
Beverly Nguyen
4eff686e17 revising stylnig 2024-10-01 12:38:01 -07:00
Beverly Nguyen
282e27034d revised content 2024-10-01 12:28:05 -07:00
Alex Janousek
466137ba07 Update docs/backstop.md
Co-authored-by: Carlo Costino <ccostino@users.noreply.github.com>
2024-10-01 12:13:35 -04:00
Carlo Costino
0d04524525 Merge pull request #1966 from GSA/USN-COMPLY-49_Verify_Nonce_on_Login
Verify NONCE on login.
2024-10-01 11:05:09 -04:00
Jonathan Bobel
08c97a8066 Removing this link since it was duplicated 2024-10-01 10:42:33 -04:00
Andrew Shumway
6815493f4a Remove brackets from hardcoded var 2024-09-30 14:49:28 -06:00
Andrew Shumway
f578a52010 Retry syntax on cf command 2024-09-30 14:34:47 -06:00
Carlo Costino
40a0418731 Merge pull request #1972 from GSA/dependabot/npm_and_yarn/rollup-4.22.5
Bump rollup from 4.22.4 to 4.22.5
2024-09-30 15:56:25 -04:00
Andrew Shumway
b7d699feae Move admin client username to env variable block 2024-09-30 13:46:13 -06:00
Andrew Shumway
8b9293db0e Fix cf_command syntax 2024-09-30 13:42:48 -06:00
Kenneth Kehl
6ff8be5d3e Merge pull request #1973 from GSA/add-awscli
Add awscli tools to the admin
2024-09-30 11:35:08 -07:00
Andrew Shumway
475bd0c1b4 fix yaml 2024-09-30 11:26:27 -06:00
Carlo Costino
2c7d090b82 Merge pull request #1964 from GSA/notify-admin-1956
make sure phone number is always last in the one-off csv
2024-09-30 13:03:09 -04:00
Carlo Costino
4f193e362c Add awscli tools to the admin
This changeset adds the awscli tools as a development dependency so that we are able to manage local connectivity to AWS resources when needed.  It is also needed to help with deploying the project to the sandbox environment and/or updating the Terraform to manage the infrastructure.

Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2024-09-30 10:13:12 -04:00
alexjanousekGSA
687372fd6c Added new reference images, removed a few custom pages 2024-09-30 09:58:44 -04:00
dependabot[bot]
302a79b41f Bump rollup from 4.22.4 to 4.22.5
Bumps [rollup](https://github.com/rollup/rollup) from 4.22.4 to 4.22.5.
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v4.22.4...v4.22.5)

---
updated-dependencies:
- dependency-name: rollup
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-27 23:20:05 +00:00
Kenneth Kehl
f0299c4042 optimize S3 partitioning 2024-09-27 08:39:19 -07:00
Kenneth Kehl
bc5b980431 more debug 2024-09-27 07:49:15 -07:00
Kenneth Kehl
08384dd1fa more debug 2024-09-27 07:36:55 -07:00
Kenneth Kehl
bdc5614fff Update app/main/views/send.py
Co-authored-by: Carlo Costino <ccostino@users.noreply.github.com>
2024-09-27 07:20:40 -07:00
alexjanousekGSA
060db76640 Removed comment 2024-09-26 15:01:34 -04:00
alexjanousekGSA
b2b758ca8d Updated sensitivity 2024-09-26 14:54:55 -04:00
Kenneth Kehl
584ccce53d check bucket name 2024-09-26 10:51:51 -07:00
Kenneth Kehl
dda788b073 check bucket name 2024-09-26 10:46:26 -07:00
Kenneth Kehl
feff8ec1be try specifying region in the config 2024-09-26 10:32:22 -07:00
Kenneth Kehl
cfc9acc6f2 try specifying region in the config 2024-09-26 10:24:38 -07:00
Kenneth Kehl
959a680664 try specifying region in the config 2024-09-26 10:13:19 -07:00
Cliff Hill
a5e72ea4eb manifest.yml changed.
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2024-09-26 12:46:07 -04:00
Kenneth Kehl
122343e46e try not using fips 2024-09-26 09:37:07 -07:00
Kenneth Kehl
86b217b1df remove extrtaneous comments 2024-09-26 09:22:16 -07:00
alexjanousekGSA
982f77413e updated mismatch threshold 2024-09-26 12:02:35 -04:00
Kenneth Kehl
3967612eb1 more debug 2024-09-26 08:53:40 -07:00
alexjanousekGSA
b0f0a8d8db Updated readme 2024-09-26 11:50:10 -04:00
Kenneth Kehl
fd2de9bf9b more debug 2024-09-26 08:44:10 -07:00
Kenneth Kehl
cd24c2b029 more debug 2024-09-26 08:23:13 -07:00
Cliff Hill
63747515db Updated the sample.env with new var.
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2024-09-26 10:16:57 -04:00
Cliff Hill
55f588f13d Updated deploy workflows with new env var.
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2024-09-26 10:11:46 -04:00
Cliff Hill
81a629935c Ok, now working 100% correctly with nonce.
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2024-09-26 09:18:02 -04:00
Jonathan Bobel
49ec3dc559 Merge pull request #1963 from GSA/notify-admin-1937b
Fix moderate a11y violations reported by axe-core
2024-09-25 16:35:02 -04:00
Jonathan Bobel
647b37ae61 Removing moderate violations for the a11y scan 2024-09-25 16:19:00 -04:00
Cliff Hill
7b2d495c1b fixing so nonce check works correctly.
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2024-09-25 16:01:13 -04:00
Cliff Hill
47f0952125 Getting id_token to decode correctly.
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2024-09-25 15:34:31 -04:00
Jonathan Bobel
e0fb031cf5 Semantic update 2024-09-25 15:29:58 -04:00
Jonathan Bobel
72eff3235e Making sure it's testing against this code 2024-09-25 15:15:50 -04:00
Jonathan Bobel
67ad9148d6 Testing back button for a11y issues 2024-09-25 13:58:54 -04:00
alexjanousekGSA
2f40be8cd0 Added documentation 2024-09-25 13:12:18 -04:00
Beverly Nguyen
7d1c7fabc2 links fixed 2024-09-25 10:03:49 -07:00
Kenneth Kehl
a088409dfe fix 2024-09-25 09:54:31 -07:00
Kenneth Kehl
ddd413f299 fix 2024-09-25 09:38:59 -07:00
Beverly Nguyen
67097957f5 content 2024-09-25 09:38:21 -07:00
Kenneth Kehl
250a36836d fix 2024-09-25 09:29:50 -07:00
Kenneth Kehl
f8fd0422bf uncomment test code 2024-09-25 09:16:22 -07:00
Cliff Hill
4cdac9eba3 Making coverage not bother with sign in stuff since login.gov.
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2024-09-25 12:05:56 -04:00
Cliff Hill
76863cd4dc Some unit test cleanup.
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2024-09-25 11:23:36 -04:00
Cliff Hill
3d00b0c94f Making nonce passed through redis.
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2024-09-25 10:45:57 -04:00
Kenneth Kehl
4594dc317f merge from main 2024-09-25 07:03:02 -07:00
Kenneth Kehl
5e93f2d572 merge from main 2024-09-25 07:00:10 -07:00
Cliff Hill
a2dbb6c9e6 Typo fix.
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2024-09-24 20:46:48 -04:00
Cliff Hill
d097a0e2a6 I believe nonce is set up for sign_in.py.
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2024-09-24 20:39:08 -04:00
Beverly Nguyen
cff1fb8f2e guidance pages 2024-09-24 15:42:16 -07:00
Beverly Nguyen
5a1b59561f guidance content 2024-09-24 15:38:13 -07:00
Beverly Nguyen
1aad5f0ac1 merge main 2024-09-24 15:15:22 -07:00
Beverly Nguyen
d89fa8b987 Merge branch 'main' into 1928-develop-new-page-templates-in-code-to-sit-behind-the-log-in 2024-09-24 15:13:54 -07:00
Carlo Costino
d3855f47ac Merge pull request #1959 from GSA/dependabot/npm_and_yarn/rollup-4.22.4
Bump rollup from 4.22.2 to 4.22.4
2024-09-24 15:57:00 -04:00
Kenneth Kehl
6f91d60030 make sure phone number is always last in the one-off csv 2024-09-24 10:35:22 -07:00
Beverly Nguyen
9eb54bd837 updated 2024-09-24 10:07:18 -07:00
Beverly Nguyen
968f7881e7 fixed test 2024-09-24 10:01:56 -07:00
alexjanousekGSA
f4d8816eac Added updates 2024-09-24 12:19:20 -04:00
Kenneth Kehl
99ce42fc4a revert test setting to ignore moderate failures 2024-09-24 08:44:01 -07:00
Kenneth Kehl
899347d349 fix tests 2024-09-24 08:23:17 -07:00
Kenneth Kehl
14b37524ae revert to nav 2024-09-24 08:02:32 -07:00
Kenneth Kehl
5caa26e93c try adding service nav 2024-09-24 07:52:10 -07:00
Kenneth Kehl
5ee559da10 try adding service nav 2024-09-24 07:44:43 -07:00
Kenneth Kehl
73852a54f2 add aria-labels 2024-09-24 07:36:21 -07:00
Kenneth Kehl
ec806ce385 1937b 2024-09-24 07:11:08 -07:00
Beverly Nguyen
8eaaf1b067 fix test 2024-09-23 19:15:21 -07:00
Beverly Nguyen
296ebb5655 reverting index 2024-09-23 18:58:52 -07:00
Beverly Nguyen
d9805495de adjusting css margin and nav 2024-09-23 18:58:22 -07:00
dependabot[bot]
8c3cdabb92 Bump rollup from 4.22.2 to 4.22.4
Bumps [rollup](https://github.com/rollup/rollup) from 4.22.2 to 4.22.4.
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v4.22.2...v4.22.4)

---
updated-dependencies:
- dependency-name: rollup
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-23 23:13:18 +00:00
alexjanousekGSA
4e52d60a7c Fixed linting issue 2024-09-23 13:53:08 -04:00
Jonathan Bobel
a5889d3448 Merge pull request #1957 from GSA/notify-admin-1936
Fix serious a11y violations reported by axe-core
2024-09-23 13:40:37 -04:00
alexjanousekGSA
5234706ae1 Added script 2024-09-23 13:08:29 -04:00
alexjanousekGSA
70c9801f1d Added script 2024-09-23 13:07:24 -04:00
alexjanousekGSA
df22530fa4 Remove BackstopJS generated folders from Git tracking 2024-09-23 12:03:21 -04:00
alexjanousekGSA
df630b58d8 Merge branch 'main' into 1927-user-story-brief-description-of-the-user-story 2024-09-23 11:57:37 -04:00
alexjanousekGSA
f9337b614f Reverted sign in 2024-09-23 11:57:13 -04:00
Carlo Costino
09a775fdad Merge pull request #1953 from GSA/dependabot/npm_and_yarn/sass-embedded-1.79.3
Bump sass-embedded from 1.78.0 to 1.79.3
2024-09-23 11:50:48 -04:00
Carlo Costino
62cfa2c39c Merge pull request #1954 from GSA/dependabot/npm_and_yarn/rollup-4.22.2
Bump rollup from 4.21.2 to 4.22.2
2024-09-23 11:43:42 -04:00
Kenneth Kehl
8b6f719510 try to fix li elements 2024-09-23 08:18:41 -07:00
Kenneth Kehl
b953d316c4 fix aria label issue 2024-09-23 08:01:56 -07:00
Kenneth Kehl
5c3b5790ae try overriding default govuk-frontend font weight 2024-09-23 07:50:52 -07:00
Carlo Costino
d0d3878881 Merge pull request #1931 from GSA/notify-admin-1926
Integrate axe-core a11y tests into our e2e tests
2024-09-23 10:26:44 -04:00
Kenneth Kehl
b6e0249adb merge from main 2024-09-23 07:10:31 -07:00
dependabot[bot]
4a8d768b6f Bump rollup from 4.21.2 to 4.22.2
Bumps [rollup](https://github.com/rollup/rollup) from 4.21.2 to 4.22.2.
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v4.21.2...v4.22.2)

---
updated-dependencies:
- dependency-name: rollup
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-20 23:34:39 +00:00
dependabot[bot]
876db282d5 Bump sass-embedded from 1.78.0 to 1.79.3
Bumps [sass-embedded](https://github.com/sass/embedded-host-node) from 1.78.0 to 1.79.3.
- [Changelog](https://github.com/sass/embedded-host-node/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sass/embedded-host-node/compare/1.78.0...1.79.3)

---
updated-dependencies:
- dependency-name: sass-embedded
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-20 23:34:30 +00:00
alexjanousekGSA
028423adc1 Fixinng linting issues 2024-09-19 16:54:15 -04:00
alexjanousekGSA
56f7ad47e5 Solved merge conflict 2024-09-19 16:11:43 -04:00
Beverly Nguyen
1368384fdf fixed testing 2024-09-19 13:04:33 -07:00
Beverly Nguyen
17c63c0790 fix sort 2024-09-19 09:55:59 -07:00
Beverly Nguyen
d21e85278e fixed flake8 2024-09-18 22:45:49 -07:00
Beverly Nguyen
a4b9c16763 added guidance directory and nav 2024-09-18 22:40:48 -07:00
alexjanousekGSA
c44084f325 Backstop is working locally 2024-09-18 13:59:16 -04:00
Kenneth Kehl
892705b125 revert fix for aria label 2024-09-11 14:19:31 -07:00
Kenneth Kehl
ef9e3aecbe set to critical for now 2024-09-11 14:11:19 -07:00
Kenneth Kehl
6da52f91b3 get list of serious violations 2024-09-11 14:01:57 -07:00
Kenneth Kehl
5eadcc0319 switch to serious and above try removing aria label 2024-09-11 13:54:42 -07:00
Kenneth Kehl
8d6478c3c1 switch to serious and above try removing aria label 2024-09-11 13:31:50 -07:00
Kenneth Kehl
a267cf3d4b expand to all tests 2024-09-11 13:16:58 -07:00
Kenneth Kehl
f82bcb0509 expand to all tests 2024-09-11 13:08:50 -07:00
Kenneth Kehl
c3a2441ade try expanding use of axe 2024-09-11 12:57:10 -07:00
Kenneth Kehl
8ef357ea61 try expanding use of axe 2024-09-11 12:36:58 -07:00
Kenneth Kehl
286166c2ad fix import 2024-09-11 11:07:59 -07:00
Kenneth Kehl
7b9e5288f8 fix import 2024-09-11 11:02:01 -07:00
Kenneth Kehl
df85f66a43 fix import 2024-09-11 10:48:26 -07:00
Kenneth Kehl
a91d6d25c8 initial test axe-core 2024-09-11 10:39:28 -07:00
126 changed files with 6417 additions and 2538 deletions

View File

@@ -133,7 +133,7 @@
"filename": ".github/workflows/checks.yml",
"hashed_secret": "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8",
"is_verified": false,
"line_number": 66,
"line_number": 68,
"is_secret": false
}
],
@@ -161,7 +161,7 @@
"filename": "app/config.py",
"hashed_secret": "577a4c667e4af8682ca431857214b3a920883efc",
"is_verified": false,
"line_number": 118,
"line_number": 121,
"is_secret": false
}
],
@@ -425,7 +425,7 @@
"filename": "deploy-config/sandbox.yml",
"hashed_secret": "113151dd10316fcb0d5507b6215d78e2f3fe9e54",
"is_verified": false,
"line_number": 8,
"line_number": 9,
"is_secret": false
}
],
@@ -684,5 +684,5 @@
}
]
},
"generated_at": "2024-09-03T17:36:57Z"
"generated_at": "2024-10-29T19:28:03Z"
}

View File

@@ -1,6 +1,9 @@
name: Deploy egress proxy
description: Set egress space security groups and deploy proxy
inputs:
cf_org:
description: The org the target app exists in.
required: true
cf_space:
description: The space the target app exists in.
required: true
@@ -16,6 +19,19 @@ inputs:
runs:
using: composite
steps:
- name: Install cf-cli
shell: bash
run: |
curl -A "cg-deploy-action" -v -L -o cf-cli_amd64.deb 'https://packages.cloudfoundry.org/stable?release=debian64&version=v8&source=github'
sudo dpkg -i cf-cli_amd64.deb
- name: Login to cf-cli
shell: bash
run: |
cf api api.fr.cloud.gov
cf auth
- name: Target org and space
shell: bash
run: cf target -o ${{ inputs.cf_org }} -s ${{ inputs.cf_space }}
- name: Set restricted space egress
shell: bash
run: ./terraform/set_space_egress.sh -t -s ${{ inputs.cf_space }}

View File

@@ -53,11 +53,13 @@ jobs:
end-to-end-tests:
if: ${{ github.actor != 'dependabot[bot]' }}
permissions:
checks: write
pull-requests: write
contents: write
runs-on: ubuntu-latest
environment: staging
services:
postgres:
image: postgres
@@ -97,13 +99,17 @@ jobs:
# insert this line:
# tail -f admin-server.log &
# above make e2e-test
run: |
make run-flask > admin-server.log 2>&1 &
tail -f admin-server.log &
make e2e-test
env:
API_HOST_NAME: https://notify-api-staging.app.cloud.gov/
DANGEROUS_SALT: ${{ secrets.DANGEROUS_SALT }}
SECRET_KEY: ${{ secrets.SECRET_KEY }}
DANGEROUS_SALT: ${{ secrets.DANGEROUS_SALT }}
ADMIN_CLIENT_SECRET: ${{ secrets.ADMIN_CLIENT_SECRET }}
ADMIN_CLIENT_USERNAME: notify-admin
NOTIFY_ENVIRONMENT: e2etest
@@ -111,7 +117,7 @@ jobs:
NOTIFY_E2E_TEST_EMAIL: ${{ secrets.NOTIFY_E2E_TEST_EMAIL }}
NOTIFY_E2E_TEST_PASSWORD: ${{ secrets.NOTIFY_E2E_TEST_PASSWORD }}
NOTIFY_E2E_TEST_URI: http://localhost:6012/
VCAP_SERVICES: ${{ secrets.VCAP_SERVICES }}
validate-new-relic-config:
runs-on: ubuntu-latest
environment: staging

View File

@@ -47,11 +47,12 @@ jobs:
run: poetry export --without-hashes --format=requirements.txt > requirements.txt
- name: Deploy to cloud.gov
uses: 18f/cg-deploy-action@main
uses: cloud-gov/cg-cli-tools@main
env:
DANGEROUS_SALT: ${{ secrets.DANGEROUS_SALT }}
SECRET_KEY: ${{ secrets.SECRET_KEY }}
ADMIN_CLIENT_SECRET: ${{ secrets.ADMIN_CLIENT_SECRET }}
ADMIN_CLIENT_USERNAME: "notify-admin"
NEW_RELIC_LICENSE_KEY: ${{ secrets.NEW_RELIC_LICENSE_KEY }}
NR_BROWSER_KEY: ${{ secrets.NR_BROWSER_KEY }}
COMMIT_HASH: ${{ github.sha }}
@@ -63,21 +64,22 @@ jobs:
LOGIN_DOT_GOV_BASE_LOGOUT_URL: "https://secure.login.gov/openid_connect/logout?"
LOGIN_DOT_GOV_SIGNOUT_REDIRECT: "https://notify-demo.app.cloud.gov/sign-out"
LOGIN_DOT_GOV_INITIAL_SIGNIN_URL: "https://secure.login.gov/openid_connect/authorize?acr_values=http%3A%2F%2Fidmanagement.gov%2Fns%2Fassurance%2Fial%2F1&client_id=urn:gov:gsa:openidconnect.profiles:sp:sso:gsa:notify-gov&nonce=NONCE&prompt=select_account&redirect_uri=https://notify-demo.app.cloud.gov/sign-in&response_type=code&scope=openid+email&state=STATE"
LOGIN_DOT_GOV_CERTS_URL: "https://secure.login.gov/api/openid_connect/certs"
with:
cf_username: ${{ secrets.CLOUDGOV_USERNAME }}
cf_password: ${{ secrets.CLOUDGOV_PASSWORD }}
cf_org: gsa-tts-benefits-studio
cf_space: notify-demo
push_arguments: >-
cf_command: >-
push -f manifest.yml
--vars-file deploy-config/demo.yml
--var DANGEROUS_SALT="$DANGEROUS_SALT"
--var SECRET_KEY="$SECRET_KEY"
--var ADMIN_CLIENT_USERNAME="notify-admin"
--var ADMIN_CLIENT_SECRET="$ADMIN_CLIENT_SECRET"
--var ADMIN_CLIENT_USERNAME="$ADMIN_CLIENT_USERNAME"
--var NEW_RELIC_LICENSE_KEY="$NEW_RELIC_LICENSE_KEY"
--var NR_BROWSER_KEY="$NR_BROWSER_KEY"
--var COMMIT_HASH="$COMMIT_HASH"
--var LOGIN_PEM="$LOGIN_PEM"
--var LOGIN_DOT_GOV_CLIENT_ID="$LOGIN_DOT_GOV_CLIENT_ID"
--var LOGIN_DOT_GOV_USER_INFO_URL="$LOGIN_DOT_GOV_USER_INFO_URL"
--var LOGIN_DOT_GOV_ACCESS_TOKEN_URL="$LOGIN_DOT_GOV_ACCESS_TOKEN_URL"
@@ -85,6 +87,9 @@ jobs:
--var LOGIN_DOT_GOV_BASE_LOGOUT_URL="$LOGIN_DOT_GOV_BASE_LOGOUT_URL"
--var LOGIN_DOT_GOV_SIGNOUT_REDIRECT="$LOGIN_DOT_GOV_SIGNOUT_REDIRECT"
--var LOGIN_DOT_GOV_INITIAL_SIGNIN_URL="$LOGIN_DOT_GOV_INITIAL_SIGNIN_URL"
--var LOGIN_DOT_GOV_CERTS_URL="$LOGIN_DOT_GOV_CERTS_URL"
--var LOGIN_PEM="$LOGIN_PEM"
--strategy rolling
- name: Check for changes to egress config
id: changed-egress-config
@@ -97,6 +102,10 @@ jobs:
- name: Deploy egress proxy
if: steps.changed-egress-config.outputs.any_changed == 'true'
uses: ./.github/actions/deploy-proxy
env:
CF_USERNAME: ${{ secrets.CLOUDGOV_USERNAME }}
CF_PASSWORD: ${{ secrets.CLOUDGOV_PASSWORD }}
with:
cf_org: gsa-tts-benefits-studio
cf_space: notify-demo
app: notify-admin-demo

View File

@@ -47,11 +47,12 @@ jobs:
run: poetry export --without-hashes --format=requirements.txt > requirements.txt
- name: Deploy to cloud.gov
uses: 18f/cg-deploy-action@main
uses: cloud-gov/cg-cli-tools@main
env:
DANGEROUS_SALT: ${{ secrets.DANGEROUS_SALT }}
SECRET_KEY: ${{ secrets.SECRET_KEY }}
ADMIN_CLIENT_SECRET: ${{ secrets.ADMIN_CLIENT_SECRET }}
ADMIN_CLIENT_USERNAME: "notify-admin"
NEW_RELIC_LICENSE_KEY: ${{ secrets.NEW_RELIC_LICENSE_KEY }}
NR_BROWSER_KEY: ${{ secrets.NR_BROWSER_KEY }}
COMMIT_HASH: ${{ github.sha }}
@@ -63,21 +64,22 @@ jobs:
LOGIN_DOT_GOV_BASE_LOGOUT_URL: "https://secure.login.gov/openid_connect/logout?"
LOGIN_DOT_GOV_SIGNOUT_REDIRECT: "https://beta.notify.gov/sign-out"
LOGIN_DOT_GOV_INITIAL_SIGNIN_URL: "https://secure.login.gov/openid_connect/authorize?acr_values=http%3A%2F%2Fidmanagement.gov%2Fns%2Fassurance%2Fial%2F1&client_id=urn:gov:gsa:openidconnect.profiles:sp:sso:gsa:notify-gov&nonce=NONCE&prompt=select_account&redirect_uri=https://beta.notify.gov/sign-in&response_type=code&scope=openid+email&state=STATE"
LOGIN_DOT_GOV_CERTS_URL: "https://secure.login.gov/api/openid_connect/certs"
with:
cf_username: ${{ secrets.CLOUDGOV_USERNAME }}
cf_password: ${{ secrets.CLOUDGOV_PASSWORD }}
cf_org: gsa-tts-benefits-studio
cf_space: notify-production
push_arguments: >-
cf_command: >-
push -f manifest.yml
--vars-file deploy-config/production.yml
--var DANGEROUS_SALT="$DANGEROUS_SALT"
--var SECRET_KEY="$SECRET_KEY"
--var ADMIN_CLIENT_USERNAME="notify-admin"
--var ADMIN_CLIENT_SECRET="$ADMIN_CLIENT_SECRET"
--var ADMIN_CLIENT_USERNAME="$ADMIN_CLIENT_USERNAME"
--var NEW_RELIC_LICENSE_KEY="$NEW_RELIC_LICENSE_KEY"
--var NR_BROWSER_KEY="$NR_BROWSER_KEY"
--var COMMIT_HASH="$COMMIT_HASH"
--var LOGIN_PEM="$LOGIN_PEM"
--var LOGIN_DOT_GOV_CLIENT_ID="$LOGIN_DOT_GOV_CLIENT_ID"
--var LOGIN_DOT_GOV_USER_INFO_URL="$LOGIN_DOT_GOV_USER_INFO_URL"
--var LOGIN_DOT_GOV_ACCESS_TOKEN_URL="$LOGIN_DOT_GOV_ACCESS_TOKEN_URL"
@@ -85,6 +87,9 @@ jobs:
--var LOGIN_DOT_GOV_BASE_LOGOUT_URL="$LOGIN_DOT_GOV_BASE_LOGOUT_URL"
--var LOGIN_DOT_GOV_SIGNOUT_REDIRECT="$LOGIN_DOT_GOV_SIGNOUT_REDIRECT"
--var LOGIN_DOT_GOV_INITIAL_SIGNIN_URL="$LOGIN_DOT_GOV_INITIAL_SIGNIN_URL"
--var LOGIN_DOT_GOV_CERTS_URL="$LOGIN_DOT_GOV_CERTS_URL"
--var LOGIN_PEM="$LOGIN_PEM"
--strategy rolling
- name: Check for changes to egress config
id: changed-egress-config
@@ -97,6 +102,10 @@ jobs:
- name: Deploy egress proxy
if: steps.changed-egress-config.outputs.any_changed == 'true'
uses: ./.github/actions/deploy-proxy
env:
CF_USERNAME: ${{ secrets.CLOUDGOV_USERNAME }}
CF_PASSWORD: ${{ secrets.CLOUDGOV_PASSWORD }}
with:
cf_org: gsa-tts-benefits-studio
cf_space: notify-production
app: notify-admin-production

View File

@@ -53,11 +53,12 @@ jobs:
- name: Deploy to cloud.gov
uses: 18f/cg-deploy-action@main
uses: cloud-gov/cg-cli-tools@main
env:
DANGEROUS_SALT: ${{ secrets.DANGEROUS_SALT }}
SECRET_KEY: ${{ secrets.SECRET_KEY }}
ADMIN_CLIENT_SECRET: ${{ secrets.ADMIN_CLIENT_SECRET }}
ADMIN_CLIENT_USERNAME: "notify-admin"
NEW_RELIC_LICENSE_KEY: ${{ secrets.NEW_RELIC_LICENSE_KEY }}
NR_BROWSER_KEY: ${{ secrets.NR_BROWSER_KEY }}
COMMIT_HASH: ${{ github.sha }}
@@ -68,22 +69,23 @@ jobs:
LOGIN_DOT_GOV_LOGOUT_URL: "https://secure.login.gov/openid_connect/logout?client_id=urn:gov:gsa:openidconnect.profiles:sp:sso:gsa:notify-gov&post_logout_redirect_uri=https://notify-staging.app.cloud.gov/sign-out"
LOGIN_DOT_GOV_BASE_LOGOUT_URL: "https://secure.login.gov/openid_connect/logout?"
LOGIN_DOT_GOV_SIGNOUT_REDIRECT: "https://notify-staging.app.cloud.gov/sign-out"
LOGIN_DOT_GOV_INITIAL_SIGNIN_URL: "https://secure.login.gov/openid_connect/authorize?acr_values=http%3A%2F%2Fidmanagement.gov%2Fns%2Fassurance%2Fial%2F1&client_id=urn:gov:gsa:openidconnect.profiles:sp:sso:gsa:notify-gov&nonce=NONCE&prompt=select_account&redirect_uri=https://notify-staging.app.cloud.gov/sign-in&response_type=code&scope=openid+email&state=STATEE"
LOGIN_DOT_GOV_INITIAL_SIGNIN_URL: "https://secure.login.gov/openid_connect/authorize?acr_values=http%3A%2F%2Fidmanagement.gov%2Fns%2Fassurance%2Fial%2F1&client_id=urn:gov:gsa:openidconnect.profiles:sp:sso:gsa:notify-gov&nonce=NONCE&prompt=select_account&redirect_uri=https://notify-staging.app.cloud.gov/sign-in&response_type=code&scope=openid+email&state=STATE"
LOGIN_DOT_GOV_CERTS_URL: "https://secure.login.gov/api/openid_connect/certs"
with:
cf_username: ${{ secrets.CLOUDGOV_USERNAME }}
cf_password: ${{ secrets.CLOUDGOV_PASSWORD }}
cf_org: gsa-tts-benefits-studio
cf_space: notify-staging
push_arguments: >-
cf_command: >-
push -f manifest.yml
--vars-file deploy-config/staging.yml
--var DANGEROUS_SALT="$DANGEROUS_SALT"
--var SECRET_KEY="$SECRET_KEY"
--var ADMIN_CLIENT_USERNAME="notify-admin"
--var ADMIN_CLIENT_SECRET="$ADMIN_CLIENT_SECRET"
--var ADMIN_CLIENT_USERNAME="$ADMIN_CLIENT_USERNAME"
--var NEW_RELIC_LICENSE_KEY="$NEW_RELIC_LICENSE_KEY"
--var NR_BROWSER_KEY="$NR_BROWSER_KEY"
--var COMMIT_HASH="$COMMIT_HASH"
--var LOGIN_PEM="$LOGIN_PEM"
--var LOGIN_DOT_GOV_CLIENT_ID="$LOGIN_DOT_GOV_CLIENT_ID"
--var LOGIN_DOT_GOV_USER_INFO_URL="$LOGIN_DOT_GOV_USER_INFO_URL"
--var LOGIN_DOT_GOV_ACCESS_TOKEN_URL="$LOGIN_DOT_GOV_ACCESS_TOKEN_URL"
@@ -91,6 +93,9 @@ jobs:
--var LOGIN_DOT_GOV_BASE_LOGOUT_URL="$LOGIN_DOT_GOV_BASE_LOGOUT_URL"
--var LOGIN_DOT_GOV_SIGNOUT_REDIRECT="$LOGIN_DOT_GOV_SIGNOUT_REDIRECT"
--var LOGIN_DOT_GOV_INITIAL_SIGNIN_URL="$LOGIN_DOT_GOV_INITIAL_SIGNIN_URL"
--var LOGIN_DOT_GOV_CERTS_URL="$LOGIN_DOT_GOV_CERTS_URL"
--var LOGIN_PEM="$LOGIN_PEM"
--strategy rolling
- name: Check for changes to egress config
@@ -104,7 +109,11 @@ jobs:
- name: Deploy egress proxy
if: steps.changed-egress-config.outputs.any_changed == 'true'
uses: ./.github/actions/deploy-proxy
env:
CF_USERNAME: ${{ secrets.CLOUDGOV_USERNAME }}
CF_PASSWORD: ${{ secrets.CLOUDGOV_PASSWORD }}
with:
cf_org: gsa-tts-benefits-studio
cf_space: notify-staging
app: notify-admin-staging

6
.gitignore vendored
View File

@@ -14,6 +14,7 @@
*.XLSX
## Non user files allowed to be commited
!app/assets/pdf/tcpa_overview.pdf
!tests/test_pdf_files/no_eof_marker.pdf
!tests/test_pdf_files/multi_page_pdf.pdf
!tests/test_pdf_files/big.pdf
@@ -134,3 +135,8 @@ playwright/
# Nodenv
.node-version
# BackstopJS
backstop_data/bitmaps_test/
backstop_data/html_report/
backstop_data/engine_scripts/playwright/

3
.prettierrc Normal file
View File

@@ -0,0 +1,3 @@
{
"singleQuote": true
}

View File

@@ -507,3 +507,13 @@ insurance.
For more information on what we're working on, the Notify tool, and how to get
involved with our team,
[see our flyer.](https://github.com/GSA/notifications-admin/blob/main/docs/notify-pilot-flyer.md)
## Updating secrets for the E2E tests
At some point, E2E tests will fail because the secrets held in VCAP_SERVICES have expired. To refresh
them, you will need to do the following:
1. Log in the normal way to access cloudfoundry command line options
2. In your terminal, run `chmod +x print_vcap.sh`
3. In your terminal, run `./print_vcap.sh`
4. Copy the value in your terminal and paste it into the VCAP_SERVICES secret in Github on the staging tier.

View File

@@ -0,0 +1,2 @@
Contact: mailto:notify-support@gsa.gov
Expires: 2035-10-15T23:59:59Z

View File

@@ -68,11 +68,8 @@
<p class="usa-body">
Try again later.
</p>
<p class="usa-body">
You can check our <a class="usa-link"
href="https://status.notifications.service.gov.uk/">system status</a> page to see if there are any known
issues.<br />To report a problem, email <a
href="mailto:gov-uk-notify-support@digital.cabinet-office.gov.uk">gov-uk-notify-support@digital.cabinet-office.gov.uk</a>
<p>To report a problem you can email us at <a class="usa-link" href="mailto:notify-support@gsa.gov">notify-support@gsa.gov</a>.</p>
<p>You can expect a response within one business day.</p>
</div>
</div>
</main>

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 26 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.2 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.3 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 7.2 KiB

View File

@@ -0,0 +1,3 @@
<svg viewBox="0 0 563 670" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M553.831 334.751V335.974L555.03 335.731C555.104 335.716 555.181 335.708 555.262 335.708H557.846C558.483 335.708 559 336.224 559 336.862V418.708C559 419.345 558.483 419.862 557.846 419.862H555.262C555.181 419.862 555.104 419.853 555.03 419.838L553.831 419.595V420.818V955.446C553.831 970.12 547.528 991.015 535.312 1008.3C522.978 1025.76 503.794 1040.6 477.723 1040.6H82.2769C56.206 1040.6 37.022 1025.76 24.6885 1008.3C12.472 991.015 6.16923 970.12 6.16923 955.446V420.818V419.595L4.97026 419.838C4.89621 419.853 4.8188 419.862 4.73846 419.862H2.15385C1.51659 419.862 1 419.345 1 418.708V358.4C1 357.763 1.51659 357.246 2.15385 357.246H4.73846C4.8188 357.246 4.89621 357.254 4.97026 357.269L6.16923 357.513V356.289V347.588V346.364L4.97026 346.608C4.89621 346.623 4.8188 346.631 4.73846 346.631H2.15385C1.51659 346.631 1 346.114 1 345.477V285.169C1 284.532 1.51659 284.015 2.15385 284.015H4.73846C4.8188 284.015 4.89621 284.023 4.97026 284.038L6.16923 284.282V283.058V261.434V260.21L4.97026 260.454C4.89621 260.469 4.8188 260.477 4.73846 260.477H2.15385C1.51659 260.477 1 259.96 1 259.323V220.554C1 219.917 1.51659 219.4 2.15385 219.4H4.73846C4.8188 219.4 4.89624 219.408 4.97036 219.423L6.16923 219.666V218.443V86.1538C6.16923 71.4804 12.472 50.5848 24.6885 33.2974C37.022 15.8443 56.206 1 82.2769 1H477.723C503.794 1 522.978 15.8443 535.312 33.2974C547.528 50.5848 553.831 71.4804 553.831 86.1538V334.751ZM400.615 16.2308H399.615V17.2308V43.0769C399.615 49.6619 394.277 55 387.692 55H172.308C165.723 55 160.385 49.6619 160.385 43.0769V17.2308V16.2308H159.385H82.2769C62.6883 16.2308 47.6257 27.2304 37.1269 42.0872C26.5125 57.1076 21.4 74.9813 21.4 86.1538V955.446C21.4 966.619 26.5125 984.492 37.1269 999.513C47.6257 1014.37 62.6883 1025.37 82.2769 1025.37H477.723C497.312 1025.37 512.374 1014.37 522.873 999.513C533.487 984.492 538.6 966.619 538.6 955.446V86.1538C538.6 74.9813 533.488 57.1076 522.873 42.0872C512.374 27.2304 497.312 16.2308 477.723 16.2308H400.615Z" stroke="black" stroke-width="2"/>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

View File

@@ -0,0 +1 @@
<svg id="Capa_1" enable-background="new 0 0 512 512" height="512" viewBox="0 0 512 512" width="512" xmlns="http://www.w3.org/2000/svg"><g><g><path d="m291.532 66.273c4.142 0 7.5-3.357 7.5-7.5v-.057c0-4.143-3.358-7.472-7.5-7.472s-7.5 3.386-7.5 7.528 3.358 7.501 7.5 7.501z"/><path d="m254.455 66.273c4.142 0 7.5-3.357 7.5-7.5v-.057c0-4.143-3.358-7.472-7.5-7.472s-7.5 3.386-7.5 7.528 3.358 7.501 7.5 7.501z"/><path d="m217.378 66.273c4.142 0 7.5-3.357 7.5-7.5v-.057c0-4.143-3.358-7.472-7.5-7.472s-7.5 3.386-7.5 7.528 3.358 7.501 7.5 7.501z"/><path d="m123.925 51.273-76.763-.057c-.002 0-.003 0-.005 0-4.14 0-7.497 3.354-7.5 7.494-.003 4.143 3.353 7.503 7.495 7.506l76.763.057h.005c4.14 0 7.497-3.354 7.5-7.494.002-4.142-3.353-7.503-7.495-7.506z"/><path d="m287.507 124.863h-111.062c-6.933 0-12.574 5.641-12.574 12.574v33.479c0 6.948 5.641 12.602 12.574 12.602h111.062c6.933 0 12.574-5.653 12.574-12.602v-33.479c0-6.933-5.641-12.574-12.574-12.574zm-2.426 43.655h-106.209v-28.654h106.209z"/><path d="m292.581 210.217h-121.209c-4.142 0-7.5 3.357-7.5 7.5s3.358 7.5 7.5 7.5h121.209c4.142 0 7.5-3.357 7.5-7.5s-3.358-7.5-7.5-7.5z"/><path d="m189.882 245.736h-18.51c-4.142 0-7.5 3.357-7.5 7.5s3.358 7.5 7.5 7.5h18.51c4.142 0 7.5-3.357 7.5-7.5s-3.358-7.5-7.5-7.5z"/><path d="m292.581 245.736h-62.05c-4.142 0-7.5 3.357-7.5 7.5s3.358 7.5 7.5 7.5h62.05c4.142 0 7.5-3.357 7.5-7.5s-3.358-7.5-7.5-7.5z"/><path d="m444.802 450.744h-.255c-4.142 0-7.5 3.357-7.5 7.5s3.358 7.5 7.5 7.5h.255c4.142 0 7.5-3.357 7.5-7.5s-3.358-7.5-7.5-7.5z"/><path d="m490.667 301.75h-59.114v-129.049c0-11.669-9.494-21.163-21.163-21.163h-71.7v-114.592c0-11.404-9.278-20.682-20.682-20.682h-297.327c-11.404.001-20.681 9.278-20.681 20.682v241.718c0 11.419 9.277 20.709 20.681 20.709h33.801v97.131c0 11.669 9.494 21.163 21.163 21.163h104.223l-8.866 29.646h-14.994c-13.342 0-24.196 10.867-24.196 24.226v11.707c0 6.887 5.603 12.489 12.489 12.489h197.434c6.887 0 12.489-5.603 12.489-12.489v-11.707c0-13.358-10.867-24.226-24.225-24.226h-14.991l-8.847-29.646h71.443v56.735c0 11.763 9.557 21.333 21.305 21.333h91.758c11.763 0 21.333-9.57 21.333-21.333v-151.346c0-11.748-9.57-21.306-21.333-21.306zm-475.667-23.086v-177.438h137.039c4.142 0 7.5-3.357 7.5-7.5s-3.358-7.5-7.5-7.5h-137.039v-49.28c0-3.133 2.548-5.682 5.681-5.682h297.327c3.133 0 5.682 2.549 5.682 5.682v49.279h-137.011c-4.142 0-7.5 3.357-7.5 7.5s3.358 7.5 7.5 7.5h137.011v177.438c0 3.147-2.549 5.709-5.682 5.709h-297.327c-3.133.001-5.681-2.56-5.681-5.708zm303.008 20.709c11.404 0 20.682-9.29 20.682-20.709v-112.126h71.7c3.398 0 6.163 2.765 6.163 6.163v129.049h-17.644c-11.748 0-21.305 9.558-21.305 21.306v41.683h-308.122v-65.365h248.526zm21.215 172.166v9.196h-192.411v-9.196c0-5.087 4.125-9.226 9.196-9.226h173.991c5.086 0 9.224 4.139 9.224 9.226zm-79.014-68.872c-4.142 0-7.5 3.357-7.5 7.5s3.358 7.5 7.5 7.5h30.298l8.847 29.646h-112.696l8.866-29.646h30.188c4.142 0 7.5-3.357 7.5-7.5s-3.358-7.5-7.5-7.5h-150.067c-3.398 0-6.163-2.765-6.163-6.163v-16.766h308.123v22.929zm236.791 71.735c0 3.492-2.841 6.333-6.333 6.333h-91.758c-3.477 0-6.305-2.841-6.305-6.333v-151.346c0-3.477 2.828-6.306 6.305-6.306h91.758c3.492 0 6.333 2.829 6.333 6.306z"/><path d="m127.661 124.863h-76.451c-6.949 0-12.603 5.641-12.603 12.574v110.696c0 6.949 5.653 12.603 12.603 12.603h76.451c6.949 0 12.602-5.653 12.602-12.603v-110.695c0-6.934-5.653-12.575-12.602-12.575zm-2.398 120.873h-71.655v-105.873h71.655z"/></g></g></svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@@ -33,30 +33,43 @@
.attr('id', 'tooltip')
.style('display', 'none');
}
// Create legend
// Calculate total messages
const totalMessages = d3.sum(deliveredData) + d3.sum(failedData);
// Create legend only if there are messages
const legendContainer = d3.select('.chart-legend');
legendContainer.selectAll('*').remove(); // Clear any existing legend
const legendData = [
{ label: 'Delivered', color: COLORS.delivered },
{ label: 'Failed', color: COLORS.failed }
];
if (totalMessages > 0) {
// Show legend if there are messages
const legendData = [
{ label: 'Delivered', color: COLORS.delivered },
{ label: 'Failed', color: COLORS.failed }
];
const legendItem = legendContainer.selectAll('.legend-item')
.data(legendData)
.enter()
.append('div')
.attr('class', 'legend-item');
const legendItem = legendContainer.selectAll('.legend-item')
.data(legendData)
.enter()
.append('div')
.attr('class', 'legend-item');
legendItem.append('div')
.attr('class', 'legend-rect')
.style('background-color', d => d.color)
.style('display', 'inline-block')
.style('margin-right', '5px');
legendItem.append('div')
.attr('class', 'legend-rect')
.style('background-color', d => d.color)
.style('display', 'inline-block')
.style('margin-right', '5px');
legendItem.append('span')
.attr('class', 'legend-label')
.text(d => d.label);
legendItem.append('span')
.attr('class', 'legend-label')
.text(d => d.label);
// Ensure the legend is shown
legendContainer.style('display', 'flex');
} else {
// Hide the legend if there are no messages
legendContainer.style('display', 'none');
}
const x = d3.scaleBand()
.domain(labels)

Binary file not shown.

View File

@@ -671,3 +671,229 @@ details form {
border: 1px solid #face00;
border-radius: 7px;
}
.usa-prose.margin-top-0 {
margin-top: 0;
}
ol.best-practices-list {
counter-reset: item;
list-style-type: none;
padding-left: 0;
}
ol.best-practices-list.set-two {
counter-reset: item 6;
}
ol.best-practices-list.set-three {
counter-reset: item 10;
}
ol.best-practices-list li {
counter-increment: item;
margin-bottom: 15px;
position: relative;
padding-left: 40px;
}
ol.best-practices-list li::before {
content: counter(item);
background-color: #005ea2;
color: white;
width: 32px;
height: 32px;
border-radius: 50%;
display: inline-flex;
justify-content: center;
align-items: center;
line-height: 1;
position: absolute;
left: 0;
top: 0;
}
li.best-practices {
padding-bottom: 50px;
}
div.best-practices {
height: 400px
}
$do-dont-color-do: "green-cool-50v";
$do-dont-color-dont: "red-cool-50v";
$do-dont-color-border: "gray-cool-20";
$do-dont-padding: 3;
$do-dont-top-bar-width: 1;
.do-dont {
display: flex;
height: 100%;
padding-top: units(2);
}
.do-dont__do,
.do-dont__dont {
background-color: color("white");
border: 1px solid color($do-dont-color-border);
flex: 1 0 0;
height: 100%;
position: relative;
}
.do-dont__do {
padding: 0rem;
}
.do-dont__do:before,
.do-dont__dont:before {
content: "";
position: absolute;
height: units($do-dont-top-bar-width);
width: calc(100% + 2px);
top: -1px;
left: -1px;
}
.do-dont__do:before {
background-color: color($do-dont-color-do);
}
.do-dont__dont:before {
background-color: color($do-dont-color-dont);
}
.do-dont__heading {
// @include typeset("lang", "lg", 2);
align-items: center;
border-bottom: 1px solid color($do-dont-color-border);
display: flex;
font-weight: fw("bold");
margin: 0;
padding: units(4) units($do-dont-padding) units($do-dont-padding);
.usa-icon {
@include u-square(3);
margin-right: units(0.5);
}
}
.do-dont__do .do-dont__heading {
color: color($do-dont-color-do);
}
.do-dont__dont .do-dont__heading {
color: color($do-dont-color-dont);
}
.do-dont__content {
padding: 0 units($do-dont-padding) units($do-dont-padding) units($do-dont-padding);
ul {
margin-bottom: 0;
overflow-wrap: anywhere;
}
li+li {
margin-top: units(1);
}
}
.site-note {
background-color: #dfe1e2;
max-width: 72ex;
padding: .5rem;
border-radius: 2px;
}
.svg-circle-icon {
display: inline-block;
margin: 0;
padding: 0;
vertical-align: text-bottom;
margin-right: -2px;
}
.height-phone-lg {
max-height: 500px;
}
@media (max-width: 758px) {
.best-practices-flex-container {
flex-direction: column;
}
}
.linked-content:hover {
cursor: pointer;
transform: scale(1.05);
transition: transform 0.3s ease, background-color 0.3s ease,
}
li.linked-card:hover > div:first-child:hover {
border-color: #005ea2;
}
li.linked-card:hover h4,
li.linked-card:hover p,
li.linked-card:hover svg,
.best-practices_card_img:hover{
color: #005ea2;
}
.best-practices_card_img {
display: block;
width: 50%;
height: auto;
margin: 0 auto;
}
.best-practices_link {
text-decoration: none;
}
.usa-link--downloadable {
position: relative;
}
.usa-link--downloadable::after {
background-image: url(../img/material-icons/download.svg);
background-repeat: no-repeat;
background-position: center center;
background-size: 1.75ex 1.75ex;
height: 1.75ex;
width: 1.75ex;
content: "";
display: inline;
margin-top: .7ex;
margin-left: 2px;
padding-left: 1.75ex;
vertical-align: middle;
}
.usa-link--downloadable::after {
background: 0 0;
background-color: currentColor;
-webkit-mask-image: url(../img/material-icons/download.svg), linear-gradient(transparent, transparent);
mask-image: url(../img/material-icons/download.svg), linear-gradient(transparent, transparent);
-webkit-mask-position: center center;
mask-position: center center;
-webkit-mask-repeat: no-repeat;
mask-repeat: no-repeat;
-webkit-mask-size: 1.75ex 1.75ex;
mask-size: 1.75ex 1.75ex;
}
.usa-sidenav__sublist {
display: none;
}
.usa-sidenav__item:hover .usa-sidenav__sublist,
.usa-sidenav__item:focus-within .usa-sidenav__sublist {
display: block;
}
.usa-sidenav__item a {
display: block;
}

View File

@@ -34,6 +34,11 @@ $path: '/static/images/';
// Dependencies from GOV.UK Frontend, packaged to be specific to this application
@import './govuk-frontend/all';
// Custom overrides
.govuk-link {
font-weight: bold;
}
// Specific to this application
@import 'local/typography';
@import 'grids';

View File

@@ -87,6 +87,9 @@ class Config(object):
"tts-benefits-studio@gsa.gov",
],
}
FEATURE_BEST_PRACTICES_ENABLED = (
getenv("FEATURE_BEST_PRACTICES_ENABLED", "false") == "true"
)
def _s3_credentials_from_env(bucket_prefix):

View File

@@ -14,7 +14,7 @@ Learn how to [personalize messages](/using-notify/guidance) to increase response
Learn about message _parts_ and [how limits are calculated](/using-notify/pricing).
5. ## Start sending messages
To remove the restrictions of Trial Mode and begin sending messages to clients complete the [Live Campaign Form](https://airtable.com/appe4n7jYOALPLcyU/shrIPWnLTw9U1fclL).
To remove the restrictions of Trial Mode and begin sending messages to clients complete the <a class="usa-link usa-link--external" href="https://docs.google.com/forms/d/1fnaBtxuGf3q-OdGVyt2LqBKvp9_P21kmKJa0yIK8rWM/edit">Go-Live Form</a>.
Well respond within one business day.
### Questions?

View File

@@ -1,31 +1,58 @@
import os
import secrets
from urllib.parse import unquote
from flask import abort, current_app, redirect, render_template, request, url_for
from flask_login import current_user
from app import status_api_client
from app import redis_client, status_api_client
from app.formatters import apply_html_class, convert_markdown_template
from app.main import main
from app.main.views.pricing import CURRENT_SMS_RATE
from app.main.views.sub_navigation_dictionaries import features_nav, using_notify_nav
from app.main.views.sub_navigation_dictionaries import (
best_practices_nav,
features_nav,
using_notify_nav,
)
from app.utils.user import user_is_logged_in
from notifications_utils.url_safe_token import generate_token
# Hook to check for guidance routes
@main.before_request
def check_guidance_feature():
current_app.logger.warning("best practices 1234")
current_app.logger.warning(current_app.config["FEATURE_BEST_PRACTICES_ENABLED"])
if (
request.path.startswith("/best-practices")
and not current_app.config["FEATURE_BEST_PRACTICES_ENABLED"]
):
abort(404)
@main.route("/")
def index():
if current_user and current_user.is_authenticated:
return redirect(url_for("main.choose_account"))
token = generate_token(
# make and store the state
state = generate_token(
str(request.remote_addr),
current_app.config["SECRET_KEY"],
current_app.config["DANGEROUS_SALT"],
)
state_key = f"login-state-{unquote(state)}"
redis_client.set(state_key, state)
# make and store the nonce
nonce = secrets.token_urlsafe()
nonce_key = f"login-nonce-{unquote(nonce)}"
redis_client.set(nonce_key, nonce)
url = os.getenv("LOGIN_DOT_GOV_INITIAL_SIGNIN_URL")
# handle unit tests
if url is not None:
url = url.replace("NONCE", token)
url = url.replace("STATE", token)
url = url.replace("NONCE", nonce)
url = url.replace("STATE", state)
return render_template(
"views/signedout.html",
sms_rate=CURRENT_SMS_RATE,
@@ -178,12 +205,78 @@ def trial_mode_new():
)
@main.route("/best-practices")
@user_is_logged_in
def best_practices():
return render_template(
"views/best-practices/best-practices.html",
navigation_links=best_practices_nav(),
)
@main.route("/best-practices/clear-goals")
@user_is_logged_in
def clear_goals():
return render_template(
"views/best-practices/clear-goals.html",
navigation_links=best_practices_nav(),
)
@main.route("/best-practices/rules-and-regulations")
@user_is_logged_in
def rules_and_regulations():
return render_template(
"views/best-practices/rules-and-regulations.html",
navigation_links=best_practices_nav(),
)
@main.route("/best-practices/establish-trust")
@user_is_logged_in
def establish_trust():
return render_template(
"views/best-practices/establish-trust.html",
navigation_links=best_practices_nav(),
)
@main.route("/best-practices/write-for-action")
@user_is_logged_in
def write_for_action():
return render_template(
"views/best-practices/write-for-action.html",
navigation_links=best_practices_nav(),
)
@main.route("/best-practices/multiple-languages")
@user_is_logged_in
def multiple_languages():
return render_template(
"views/best-practices/multiple-languages.html",
navigation_links=best_practices_nav(),
)
@main.route("/best-practices/benchmark-performance")
@user_is_logged_in
def benchmark_performance():
return render_template(
"views/best-practices/benchmark-performance.html",
navigation_links=best_practices_nav(),
)
@main.route("/using-notify/guidance")
@user_is_logged_in
def guidance_index():
return render_template(
"views/guidance/index.html",
navigation_links=using_notify_nav(),
feature_best_practices_enabled=current_app.config[
"FEATURE_BEST_PRACTICES_ENABLED"
],
)

View File

@@ -17,14 +17,12 @@ def accept_invite(token):
and current_user.email_address.lower() != invited_user.email_address.lower()
):
message = Markup(
"""
Youre signed in as {}.
f"""
Youre signed in as {current_user.email_address}.
This invite is for another email address.
<a href={} class="usa-link">Sign out</a>
<a href={url_for("main.sign_out")} class="usa-link">Sign out</a>
and click the link again to accept this invite.
""".format(
current_user.email_address, url_for("main.sign_out")
)
"""
)
flash(message=message)

View File

@@ -77,6 +77,11 @@ def invite_user(service_id, user_id=None):
form.login_authentication.data = "sms_auth"
if form.validate_on_submit():
if not form.permissions or len(form.permissions) == 0:
return render_template(
"views/user-has-no-permissions.html",
user_to_invite=user_to_invite,
)
email_address = form.email_address.data
invited_user = InvitedUser.create(
current_user.id,

View File

@@ -10,10 +10,12 @@ from flask import (
stream_with_context,
url_for,
)
from flask_login import current_user
from app import current_service, job_api_client, notification_api_client
from app.main import main
from app.notify_client.api_key_api_client import KEY_TYPE_TEST
from app.s3_client.s3_csv_client import delete_report, report_upload
from app.utils import (
DELIVERED_STATUSES,
FAILURE_STATUSES,
@@ -144,6 +146,36 @@ def download_notifications_csv(service_id):
file_time = datetime.now().strftime("%Y-%m-%d %I:%M:%S %p")
file_time = f"{file_time} {get_user_preferred_timezone()}"
csv = generate_notifications_csv(
service_id=service_id,
job_id=None,
status=filter_args.get("status"),
page=request.args.get("page", 1),
page_size=10000,
format_for_csv=True,
template_type=filter_args.get("message_type"),
limit_days=service_data_retention_days,
)
# START asynchronous reporting block
csv_file = "".join(csv)
file_location = f"reports/{service_id}/{current_user.id}/{service_data_retention_days}/report.csv"
# TODO these are some capabilities we will probably need when
# report generation becomes asynchronous.
# old_content = report_download(file_location)
# current_app.logger.info(f"OLD CONTENT IS {old_content}")
# reports = get_downloadable_reports(current_user.id, service_id)
# TODO these are to support asynchronous report generation.
# Leaving them commented in so they get exercised.
delete_report(file_location)
report_upload(file_location, csv_file)
# END asynchronous reporting block
# TODO eventually we want to remove this, when reports become fully asynchronous
# The UI should be retrieving the report elsewhere via the download_report() method call
return Response(
stream_with_context(
generate_notifications_csv(

View File

@@ -1,7 +1,7 @@
import base64
import json
import uuid
from datetime import datetime, timedelta
from urllib.parse import unquote
from flask import (
abort,
@@ -161,17 +161,29 @@ def set_up_your_profile():
debug_msg(f"Enter set_up_your_profile with request.args {request.args}")
code = request.args.get("code")
state = request.args.get("state")
state_key = f"login-state-{unquote(state)}"
stored_state = unquote(redis_client.get(state_key).decode("utf8"))
if state != stored_state:
current_app.logger.error(f"State Error: {state} != {stored_state}")
abort(403)
login_gov_error = request.args.get("error")
if redis_client.get(f"invitedata-{state}") is None:
access_token = sign_in._get_access_token(code, state)
user_email = redis_client.get(f"user_email-{state}")
user_uuid = redis_client.get(f"user_uuid-{state}")
new_user = user_email is None or user_uuid is None
if new_user: # invite path
access_token = sign_in._get_access_token(code)
debug_msg("Got the access token for login.gov")
user_email, user_uuid = sign_in._get_user_email_and_uuid(access_token)
debug_msg(
f"Got the user_email {user_email} and user_uuid {user_uuid} from login.gov"
)
invite_data = state.encode("utf8")
invite_data = base64.b64decode(invite_data)
invite_data = redis_client.get(f"invitedata-{state}")
invite_data = json.loads(invite_data)
debug_msg(f"final state {invite_data}")
invited_user_id = invite_data["invited_user_id"]
@@ -193,10 +205,7 @@ def set_up_your_profile():
form = SetupUserProfileForm()
if (
form.validate_on_submit()
and redis_client.get(f"invitedata-{state}") is not None
):
if form.validate_on_submit() and not new_user:
invite_data, user_email, user_uuid, invited_user_email_address = (
get_invite_data_from_redis(state)
)
@@ -221,6 +230,7 @@ def set_up_your_profile():
activate_user(user["id"])
debug_msg("activated user")
usr = User.from_id(user["id"])
usr.add_to_service(
invite_data["service_id"],
invite_data["permissions"],

View File

@@ -1,4 +1,4 @@
from flask import redirect
from flask import send_from_directory
from app.main import main
@@ -6,6 +6,4 @@ from app.main import main
@main.route("/.well-known/security.txt", methods=["GET"])
@main.route("/security.txt", methods=["GET"])
def security_policy():
# See GDS Way security policy which this implements
# https://gds-way.cloudapps.digital/standards/vulnerability-disclosure.html#vulnerability-disclosure-and-security-txt
return redirect("https://vdp.cabinetoffice.gov.uk/.well-known/security.txt")
return send_from_directory(".well-known", "security.txt")

View File

@@ -802,9 +802,15 @@ def get_skip_link(step_index, template):
)
@user_has_permissions("send_messages", restrict_admin_usage=True)
def send_one_off_to_myself(service_id, template_id):
db_template = current_service.get_template_with_user_permission_or_403(
template_id, current_user
)
current_app.logger.info("Send one off to myself")
try:
db_template = current_service.get_template_with_user_permission_or_403(
template_id, current_user
)
except Exception:
current_app.logger.exception("Couldnt get template for one off")
# Use 406 just because we're limited to certain codes here and it will point us back to a problem here
abort(406)
if db_template["template_type"] not in ("sms", "email"):
abort(404)
@@ -1009,9 +1015,16 @@ def _send_notification(service_id, template_id):
keys = []
values = []
# Guarantee that the real phone number comes last, because some
# users will have placeholders like "add your second phone number"
# or something like as custom placeholders.
for k, v in session["placeholders"].items():
keys.append(k)
values.append(v)
if k != "phone number":
keys.append(k)
values.append(v)
if "phone number" in session["placeholders"].keys():
keys.append("phone number")
values.append(session["placeholders"]["phone number"])
data = ",".join(keys)
vals = ",".join(values)
@@ -1027,7 +1040,7 @@ def _send_notification(service_id, template_id):
# on the API side to find out what happens to the message.
current_app.logger.info(
hilite(
f"One-off file: {filename} job_id: {upload_id} s3 location: service-{service_id}-notify/{upload_id}.csv"
f"One-off file: {filename} job_id: {upload_id} s3 location: {service_id}-service-notify/{upload_id}.csv"
)
)

View File

@@ -1,6 +1,8 @@
import os
import secrets
import time
import uuid
from urllib.parse import unquote
import jwt
import requests
@@ -16,19 +18,19 @@ from flask import (
)
from flask_login import current_user
from app import login_manager, user_api_client
from app import login_manager, redis_client, user_api_client
from app.main import main
from app.main.views.index import error
from app.main.views.verify import activate_user
from app.models.user import User
from app.utils import hide_from_search_engines
from app.utils.login import is_safe_redirect_url
from app.utils.login import get_id_token, is_safe_redirect_url
from app.utils.time import is_less_than_days_ago
from app.utils.user import is_gov_user
from notifications_utils.url_safe_token import generate_token
def _reformat_keystring(orig):
def _reformat_keystring(orig): # pragma: no cover
arr = orig.split("-----")
begin = arr[1]
end = arr[3]
@@ -37,7 +39,7 @@ def _reformat_keystring(orig):
return new_keystring
def _get_access_token(code, state):
def _get_access_token(code): # pragma: no cover
client_id = os.getenv("LOGIN_DOT_GOV_CLIENT_ID")
access_token_url = os.getenv("LOGIN_DOT_GOV_ACCESS_TOKEN_URL")
keystring = os.getenv("LOGIN_PEM")
@@ -60,17 +62,28 @@ def _get_access_token(code, state):
url = f"{base_url}{cli_assert}&{cli_assert_type}&{code_param}&grant_type=authorization_code"
headers = {"Authorization": "Bearer %s" % token}
response = requests.post(url, headers=headers)
if response.json().get("access_token") is None:
# Capture the response json here so it hopefully shows up in error reports
current_app.logger.error(
response_json = response.json()
id_token = get_id_token(response_json)
nonce = id_token["nonce"]
nonce_key = f"login-nonce-{unquote(nonce)}"
stored_nonce = redis_client.get(nonce_key).decode("utf8")
if nonce != stored_nonce:
current_app.logger.error(f"Nonce Error: {nonce} != {stored_nonce}")
abort(403)
try:
access_token = response_json["access_token"]
except KeyError as e:
current_app.logger.exception(
f"Error when getting access token {response.json()} #notify-admin-1505"
)
raise KeyError(f"'access_token' {response.json()}")
access_token = response.json()["access_token"]
raise KeyError(f"'access_token' {response.json()}") from e
return access_token
def _get_user_email_and_uuid(access_token):
def _get_user_email_and_uuid(access_token): # pragma: no cover
headers = {"Authorization": "Bearer %s" % access_token}
user_info_url = os.getenv("LOGIN_DOT_GOV_USER_INFO_URL")
user_attributes = requests.get(
@@ -82,10 +95,11 @@ def _get_user_email_and_uuid(access_token):
return user_email, user_uuid
def _do_login_dot_gov():
def _do_login_dot_gov(): # $ pragma: no cover
# start login.gov
code = request.args.get("code")
state = request.args.get("state")
login_gov_error = request.args.get("error")
if login_gov_error:
@@ -94,10 +108,15 @@ def _do_login_dot_gov():
)
raise Exception(f"Could not login with login.gov {login_gov_error}")
elif code and state:
state_key = f"login-state-{unquote(state)}"
stored_state = unquote(redis_client.get(state_key).decode("utf8"))
if state != stored_state:
current_app.logger.error(f"State Error: {state} != {stored_state}")
abort(403)
# activate the user
try:
access_token = _get_access_token(code, state)
access_token = _get_access_token(code)
user_email, user_uuid = _get_user_email_and_uuid(access_token)
if not is_gov_user(user_email):
current_app.logger.error(
@@ -124,12 +143,13 @@ def _do_login_dot_gov():
except BaseException as be: # noqa B036
current_app.logger.error(f"Error signing in: {be} #notify-admin-1505 ")
error(401)
return redirect(url_for("main.show_accounts_or_dashboard", next=redirect_url))
# end login.gov
def verify_email(user, redirect_url):
def verify_email(user, redirect_url): # pragma: no cover
user_api_client.send_verify_code(user["id"], "email", None, redirect_url)
title = "Email resent" if request.args.get("email_resent") else "Check your email"
redirect_url = request.args.get("next")
@@ -138,7 +158,7 @@ def verify_email(user, redirect_url):
)
def _handle_e2e_tests(redirect_url):
def _handle_e2e_tests(redirect_url): # pragma: no cover
try:
current_app.logger.warning("E2E TESTS ARE ENABLED.")
current_app.logger.warning(
@@ -146,26 +166,32 @@ def _handle_e2e_tests(redirect_url):
)
user = user_api_client.get_user_by_email(os.getenv("NOTIFY_E2E_TEST_EMAIL"))
activate_user(user["id"])
# Check if the redirect URL is present and safe before proceeding further
if redirect_url and is_safe_redirect_url(redirect_url):
return redirect(redirect_url)
return redirect(
url_for(
"main.show_accounts_or_dashboard",
next="EMAIL_IS_OK",
)
)
except Exception as e:
stre = str(e)
stre = stre.replace(" ", "_")
# Trying to get a message back to playwright somehow since we can't see the admin logs
# Trying to get a message back to playwright somehow since we can't raise an error
return redirect(url_for(f"https://{stre}"))
@main.route("/sign-in", methods=(["GET", "POST"]))
@hide_from_search_engines
def sign_in():
def sign_in(): # pragma: no cover
redirect_url = request.args.get("next")
if os.getenv("NOTIFY_E2E_TEST_EMAIL"):
return _handle_e2e_tests(None)
return _handle_e2e_tests(redirect_url)
# If we have to revalidated the email, send the message
# via email and redirect to the "verify your email page"
@@ -183,16 +209,24 @@ def sign_in():
return redirect(redirect_url)
return redirect(url_for("main.show_accounts_or_dashboard"))
token = generate_token(
state = generate_token(
str(request.remote_addr),
current_app.config["SECRET_KEY"],
current_app.config["DANGEROUS_SALT"],
)
state_key = f"login-state-{unquote(state)}"
redis_client.set(state_key, state)
nonce = secrets.token_urlsafe()
nonce_key = f"login-nonce-{unquote(nonce)}"
redis_client.set(nonce_key, nonce)
url = os.getenv("LOGIN_DOT_GOV_INITIAL_SIGNIN_URL")
# handle unit tests
if url is not None:
url = url.replace("NONCE", token)
url = url.replace("STATE", token)
url = url.replace("NONCE", nonce)
url = url.replace("STATE", state)
return render_template(
"views/signin.html",
again=bool(redirect_url),
@@ -201,5 +235,5 @@ def sign_in():
@login_manager.unauthorized_handler
def sign_in_again():
def sign_in_again(): # pragma: no cover
return redirect(url_for("main.sign_in", next=request.path))

View File

@@ -58,3 +58,46 @@ def using_notify_nav():
# },
},
]
def best_practices_nav():
return [
{
"name": "Best Practices",
"link": "main.best_practices",
},
{
"name": "Clear goals",
"link": "main.clear_goals",
},
{
"name": "Rules and regulations",
"link": "main.rules_and_regulations",
},
{
"name": "Establish trust",
"link": "main.establish_trust",
"sub_navigation_items": [
{
"name": "Get the word out",
"link": "main.establish_trust#get-the-word-out",
},
{
"name": "As people receive texts",
"link": "main.establish_trust#as-people-receive-texts",
},
],
},
{
"name": "Write for action",
"link": "main.write_for_action",
},
{
"name": "Multiple languages",
"link": "main.multiple_languages",
},
{
"name": "Benchmark performance",
"link": "main.benchmark_performance",
},
]

View File

@@ -201,7 +201,7 @@ class User(JSONModel, UserMixin):
@property
def is_gov_user(self):
is_gov = is_gov_user(self.email_address)
current_app.logger.info(f"User {self.id} is_gov_user: {is_gov}")
# current_app.logger.info(f"User {self.id} is_gov_user: {is_gov}")
return is_gov
@property
@@ -210,9 +210,9 @@ class User(JSONModel, UserMixin):
@property
def platform_admin(self):
current_app.logger.warn(
f"Checking User {self.id} for platform admin: {self._platform_admin}"
)
# current_app.logger.warning(
# f"Checking User {self.id} for platform admin: {self._platform_admin}"
# )
return self._platform_admin and not session.get(
"disable_platform_admin_view", False
)
@@ -242,26 +242,31 @@ class User(JSONModel, UserMixin):
# we shouldn't have any pages that require permissions, but don't specify a service or organization.
# use @user_is_platform_admin for platform admin only pages
# raise NotImplementedError
current_app.logger.warn(f"VIEW ARGS ARE {request.view_args}")
# current_app.logger.warning(f"VIEW ARGS ARE {request.view_args}")
pass
log_msg = f"has_permissions user: {self.id} service: {service_id}"
# platform admins should be able to do most things (except eg send messages, or create api keys)
if self.platform_admin and not restrict_admin_usage:
current_app.logger.warn(f"{log_msg} true because user is platform_admin")
current_app.logger.debug(
"has_permissions is true because user is platform_admin"
)
return True
if org_id:
value = self.belongs_to_organization(org_id)
current_app.logger.warn(f"{log_msg} org: {org_id} returning {value}")
current_app.logger.debug(
f"has_permissions returns org: {org_id} returning {value}"
)
return value
if not permissions and self.belongs_to_service(service_id):
current_app.logger.warn(f"{log_msg} True because belongs_to_service")
current_app.logger.debug("has_permissions True because belongs_to_service")
return True
if any(self.permissions_for_service(service_id) & set(permissions)):
current_app.logger.warn(f"{log_msg} permissions valid")
current_app.logger.debug(
"has_permissions returns True because permissions valid"
)
return True
from app.models.service import Service
@@ -269,7 +274,7 @@ class User(JSONModel, UserMixin):
org_value = allow_org_user and self.belongs_to_organization(
Service.from_id(service_id).organization_id
)
current_app.logger.warn(f"{log_msg} returning {org_value}")
current_app.logger.debug(f"has_permissions returning {org_value}")
return org_value
def permissions_for_service(self, service_id):
@@ -277,7 +282,7 @@ class User(JSONModel, UserMixin):
def has_permission_for_service(self, service_id, permission):
has_permission = permission in self.permissions_for_service(service_id)
current_app.logger.warn(
current_app.logger.debug(
f"has_permission_for_service user: {self.id} service: {service_id} "
f"permission: {permission} retuning {has_permission}"
)
@@ -558,17 +563,17 @@ class InvitedUser(JSONModel):
return cls.by_id(invited_user_id) if invited_user_id else None
def has_permissions(self, *permissions):
current_app.logger.warn(
f"Checking invited user {self.id} for permissions: {permissions}"
)
# current_app.logger.warning(
# f"Checking invited user {self.id} for permissions: {permissions}"
# )
if self.status == "cancelled":
return False
return set(self.permissions) > set(permissions)
def has_permission_for_service(self, service_id, permission):
current_app.logger.warn(
f"Checking invited user {self.id} for permission: {permission} on service {service_id}"
)
# current_app.logger.warn(
# f"Checking invited user {self.id} for permission: {permission} on service {service_id}"
# )
if self.status == "cancelled":
return False
return self.service == service_id and permission in self.permissions

View File

@@ -1,8 +1,16 @@
import json
import secrets
from urllib.parse import unquote
from flask import current_app, request
from app import redis_client
from app.notify_client import NotifyAdminAPIClient, _attach_current_user, cache
from app.utils.user_permissions import (
all_ui_permissions,
translate_permissions_from_ui_to_db,
)
from notifications_utils.url_safe_token import generate_token
class InviteApiClient(NotifyAdminAPIClient):
@@ -32,8 +40,33 @@ class InviteApiClient(NotifyAdminAPIClient):
"folder_permissions": folder_permissions,
}
data = _attach_current_user(data)
# make and store the state
state = generate_token(
str(request.remote_addr),
current_app.config["SECRET_KEY"],
current_app.config["DANGEROUS_SALT"],
)
state_key = f"login-state-{unquote(state)}"
redis_client.set(state_key, state)
# make and store the nonce
nonce = secrets.token_urlsafe()
nonce_key = f"login-nonce-{unquote(nonce)}"
redis_client.set(nonce_key, nonce) # save the nonce to redis.
data["nonce"] = nonce # This is passed to api for the invite url.
data["state"] = state # This is passed to api for the invite url.
resp = self.post(url=f"/service/{service_id}/invite", data=data)
return resp["data"]
resp_data = resp["data"]
invite_data_key = f"invitedata-{unquote(state)}"
redis_invite_data = resp["invite"]
redis_invite_data = json.dumps(redis_invite_data)
redis_client.set(invite_data_key, redis_invite_data)
return resp_data
def get_invites_for_service(self, service_id):
return self.get(f"/service/{service_id}/invite")["data"]
@@ -64,7 +97,32 @@ class InviteApiClient(NotifyAdminAPIClient):
self.post(url=f"/service/{service_id}/invite/{invited_user_id}", data=data)
def resend_invite(self, service_id, invited_user_id):
self.post(url=f"/service/{service_id}/invite/{invited_user_id}/resend", data={})
# make and store the state
state = generate_token(
str(request.remote_addr),
current_app.config["SECRET_KEY"],
current_app.config["DANGEROUS_SALT"],
)
state_key = f"login-state-{unquote(state)}"
redis_client.set(state_key, state)
# make and store the nonce
nonce = secrets.token_urlsafe()
nonce_key = f"login-nonce-{unquote(nonce)}"
redis_client.set(nonce_key, nonce)
data = {
"nonce": nonce,
"state": state,
}
resp = self.post(
url=f"/service/{service_id}/invite/{invited_user_id}/resend", data=data
)
invite_data_key = f"invitedata-{unquote(state)}"
redis_invite_data = resp["invite"]
redis_invite_data = json.dumps(redis_invite_data)
redis_client.set(invite_data_key, redis_invite_data)
@cache.delete("service-{service_id}")
@cache.delete("user-{invited_user_id}")

View File

@@ -168,7 +168,7 @@ class UserApiClient(NotifyAdminAPIClient):
@cache.delete("user-{user_id}")
def add_user_to_service(self, service_id, user_id, permissions, folder_permissions):
# permissions passed in are the combined UI permissions, not DB permissions
endpoint = "/service/{}/users/{}".format(service_id, user_id)
endpoint = f"/service/{service_id}/users/{user_id}"
data = {
"permissions": [
{"permission": x}

View File

@@ -29,7 +29,10 @@ def get_s3_object(
aws_secret_access_key=secret_key,
region_name=region,
)
s3 = session.resource("s3", config=AWS_CLIENT_CONFIG)
s3 = session.resource(
"s3",
config=AWS_CLIENT_CONFIG,
)
obj = s3.Object(bucket_name, filename)
# This 'proves' that use of moto in the relevant tests in test_send.py
# mocks everything related to S3. What you will see in the logs is:

View File

@@ -1,8 +1,11 @@
import os
import uuid
import boto3
from flask import current_app
from app.s3_client import (
AWS_CLIENT_CONFIG,
get_s3_contents,
get_s3_metadata,
get_s3_object,
@@ -10,13 +13,13 @@ from app.s3_client import (
)
from notifications_utils.s3 import s3upload as utils_s3upload
FILE_LOCATION_STRUCTURE = "service-{}-notify/{}.csv"
NEW_FILE_LOCATION_STRUCTURE = "{}-service-notify/{}.csv"
def get_csv_location(service_id, upload_id):
return (
current_app.config["CSV_UPLOAD_BUCKET"]["bucket"],
FILE_LOCATION_STRUCTURE.format(service_id, upload_id),
NEW_FILE_LOCATION_STRUCTURE.format(service_id, upload_id),
current_app.config["CSV_UPLOAD_BUCKET"]["access_key_id"],
current_app.config["CSV_UPLOAD_BUCKET"]["secret_access_key"],
current_app.config["CSV_UPLOAD_BUCKET"]["region"],
@@ -33,6 +36,14 @@ def s3upload(service_id, filedata):
bucket_name, file_location, access_key, secret_key, region = get_csv_location(
service_id, upload_id
)
if bucket_name == "":
exp_bucket = current_app.config["CSV_UPLOAD_BUCKET"]["bucket"]
exp_region = current_app.config["CSV_UPLOAD_BUCKET"]["region"]
tier = os.getenv("NOTIFY_ENVIRONMENT")
raise Exception(
f"NO BUCKET NAME SHOULD BE: {exp_bucket} WITH REGION {exp_region} TIER {tier}"
)
utils_s3upload(
filedata=filedata["data"],
region=region,
@@ -54,3 +65,70 @@ def set_metadata_on_csv_upload(service_id, upload_id, **kwargs):
def get_csv_metadata(service_id, upload_id):
return get_s3_metadata(get_csv_upload(service_id, upload_id))
def report_upload(file_location, report_content):
bucket_name = current_app.config["CSV_UPLOAD_BUCKET"]["bucket"]
access_key = current_app.config["CSV_UPLOAD_BUCKET"]["access_key_id"]
secret_key = current_app.config["CSV_UPLOAD_BUCKET"]["secret_access_key"]
region = current_app.config["CSV_UPLOAD_BUCKET"]["region"]
utils_s3upload(
filedata=report_content,
region=region,
bucket_name=bucket_name,
file_location=file_location,
access_key=access_key,
secret_key=secret_key,
)
current_app.logger.info(f"Succcessfully uploaded report to {file_location}")
def report_download(file_location):
current_app.logger.info(f"Downloading report from {file_location}")
bucket_name = current_app.config["CSV_UPLOAD_BUCKET"]["bucket"]
access_key = current_app.config["CSV_UPLOAD_BUCKET"]["access_key_id"]
secret_key = current_app.config["CSV_UPLOAD_BUCKET"]["secret_access_key"]
region = current_app.config["CSV_UPLOAD_BUCKET"]["region"]
return get_s3_contents(
get_s3_object(bucket_name, file_location, access_key, secret_key, region)
)
def delete_report(file_location):
current_app.logger.info(f"Deleting report from {file_location}")
bucket_name = current_app.config["CSV_UPLOAD_BUCKET"]["bucket"]
access_key = current_app.config["CSV_UPLOAD_BUCKET"]["access_key_id"]
secret_key = current_app.config["CSV_UPLOAD_BUCKET"]["secret_access_key"]
region = current_app.config["CSV_UPLOAD_BUCKET"]["region"]
obj = get_s3_object(bucket_name, file_location, access_key, secret_key, region)
if obj is None:
return None
return obj.delete()
def get_downloadable_reports(user_id, service_id):
prefix = f"reports/{service_id}/{user_id}/"
bucket_name = current_app.config["CSV_UPLOAD_BUCKET"]["bucket"]
access_key = current_app.config["CSV_UPLOAD_BUCKET"]["access_key_id"]
secret_key = current_app.config["CSV_UPLOAD_BUCKET"]["secret_access_key"]
region = current_app.config["CSV_UPLOAD_BUCKET"]["region"]
session = boto3.Session(
aws_access_key_id=access_key,
aws_secret_access_key=secret_key,
region_name=region,
)
s3 = session.client(
"s3",
config=AWS_CLIENT_CONFIG,
)
response = s3.list_objects_v2(Bucket=bucket_name, Prefix=prefix)
object_keys = []
if "Contents" in response:
for obj in response["Contents"]:
object_keys.append(obj["Key"])
return object_keys

View File

@@ -53,9 +53,30 @@
<div class="grid-row">
{% if navigation_links %}
<div class="tablet:grid-col-2 margin-bottom-4">
{{ sub_navigation(navigation_links) }}
<nav class="nav">
<ul class="usa-sidenav">
{% for item in navigation_links %}
<li class="usa-sidenav__item">
<a href="{{ url_for(item.link) }}"
class="parent-link {% if item['link'] == request.endpoint %} usa-current {% endif %}"
aria-haspopup="true" aria-expanded="false">
{{ item.name }}
</a>
{% if item.sub_navigation_items %}
<ul class="usa-sidenav__sublist" role="menu">
{% for sub_item in item.sub_navigation_items %}
<li role="menuitem">
<a href="{{ url_for(sub_item.link.split('#')[0]) }}#{{ sub_item.link.split('#')[1] }}">{{ sub_item.name }}</a>
</li>
{% endfor %}
</ul>
{% endif %}
</li>
{% endfor %}
</ul>
</nav>
</div>
<div class="tablet:grid-col-10 padding-left-4 usa-prose site-prose">
<div class="tablet:grid-col-10 tablet:padding-left-4 usa-prose site-prose">
{% else %}
<div class="tablet:grid-col-10">
{% endif %}
@@ -82,7 +103,7 @@
{% if current_user.is_authenticated %}
{% block sessionUserWarning %}
<dialog class="usa-modal" id="sessionTimer" aria-labelledby="sessionTimerHeading" aria-describedby="timerWarning">
<dialog class="usa-modal" id="sessionTimer" aria-labelledby="sessionTimerHeading" aria-describedby="timeLeft">
<div class="usa-modal__content">
<div class="usa-modal__main">
<h2 class="usa-modal__heading" id="sessionTimerHeading">

View File

@@ -0,0 +1,42 @@
<ul class="usa-card-group">
{% for item in card_contents %}
<li class="usa-card grid-col tablet:grid-col-4 {% if item.link %}linked-card linked-content{% endif %}">
<div class="usa-card__container">
{% if item.card_heading %}
<div class="usa-card__header">
{% if item.link %}
<a href="{{ item.link }}">
{% endif %}
<h3
class="usa-card__heading {% if text_align != 'left' or text_align is not defined %}text-center{% else %}text-left{% endif %} {% if item.link %}linked-card{% endif %}">
{{ item.card_heading }}
</h3>
{% if item.link %}
</a>
{% endif %}
</div>
{% endif %}
{% if item.svg_src or item.image_src%}
<div class="usa-card__media usa-card__media--inset">
{% if item.svg_src %}
<svg aria-hidden="true" focusable="false" role="img" class="best-practices_card_img">
<use xlink:href="{{asset_url('images/best-practices-card-sprite.svg')}}#{{item.svg_src}}"></use>
</svg>
{% endif %}
{% if item.image_src %}
<img class="best-practices_card_img" src="{{item.image_src}}" alt="{{ item.alt_text }}" />
{% endif %}
</div>
{% endif %}
{% if item.p_text %}
<div class="usa-card__body">
<p
class="{% if text_align != 'left' or text_align is not defined %}text-center{% else %}text-left{% endif %} {% if item.link %}linked-card{% endif %}">
{{item.p_text|safe}}
</p>
</div>
{% endif %}
</div>
</li>
{% endfor %}
</ul>

View File

@@ -0,0 +1,9 @@
{% macro circle_number(number) %}
<svg xmlns="http://www.w3.org/2000/svg" class="svg-circle-icon" width="24" height="24" viewBox="0 0 100 100">
<circle cx="50" cy="50" r="37" stroke="#005ea2" stroke-width="7" fill="none" />
<text x="50%" y="50%" text-anchor="middle" font-size="40" font-weight="bolder" fill="#005ea2" font-family="Arial"
dy=".35em">
{{ number }}
</text>
</svg>
{% endmacro %}

View File

@@ -0,0 +1,13 @@
<nav class="navigation-service usa-breadcrumb padding-top-0">
<ol class="usa-breadcrumb__list">
<li class="usa-breadcrumb__list-item">
<span class="usa-breadcrumb__label"><a href="{{ url_for('.best_practices') }}"
class="usa-link navigation-organization-link">Best Practices</a></span>
</li>
{% if title %}
<li class="usa-breadcrumb__list-item">
<span class="usa-breadcrumb__label">{{ title }}</span>
</li>
{% endif %}
</ol>
</nav>

View File

@@ -1,2 +1,4 @@
<a href="{%- if params.href %}{{ params.href }}{% else %}#{% endif -%}" class="usa-link usa-back-link display-inline-flex margin-bottom-3 {%- if params.classes %} {{ params.classes }}{% endif -%}"
{%- for attribute, value in params.attributes %} {{attribute}}="{{value}}"{% endfor %}>{{ (params.html | safe if params.html else (params.text if params.text else 'Back')) }}</a>
<nav class="usa-breadcrumb" aria-label="Breadcrumb">
<a href="{{ params.href or '#' }}" class="usa-link usa-back-link display-inline-flex {{ params.classes or '' }}"
{%- for attribute, value in params.attributes %} {{ attribute }}="{{ value }}" {% endfor %}>{{ params.html | safe or params.text or 'Back' }}</a>
</nav>

View File

@@ -1,7 +1,3 @@
<a href="{{ params.href | default('#content') }}" class="usa-skipnav{%- if params.classes %} {{ params.classes }}{% endif -%}"{%- for attribute, value in params.attributes %} {{ attribute }}="{{ value }}"{% endfor %}>
{{- params.html | safe if params.html else params.text -}}
</a>
<a class="usa-skipnav " href="#main-content">
Skip to main content
</a>

View File

@@ -1,7 +1,7 @@
{% if help %}
{% include 'partials/tour.html' %}
{% else %}
<nav class="nav margin-bottom-4">
<nav id="nav-main-nav" aria-label="Main navigation" class="nav margin-bottom-4">
<a class="usa-button margin-top-1 margin-bottom-5 width-full"
href="{{ url_for('.choose_template', service_id=current_service.id) }}">Send messages</a>
<ul class="usa-sidenav">

View File

@@ -1,4 +1,4 @@
<nav class="nav margin-bottom-4">
<nav id="nav-org-nav" aria-label="Organization navigation" class="nav margin-bottom-4">
<ul class="usa-sidenav">
<li class="usa-sidenav__item"><a class="usa-link{{ org_navigation.is_selected('dashboard') }}" href="{{ url_for('.organization_dashboard', org_id=current_org.id) }}">Usage</a></li>
<li class="usa-sidenav__item"><a class="usa-link{{ org_navigation.is_selected('team-members') }}" href="{{ url_for('.manage_org_users', org_id=current_org.id) }}">Team members</a></li>

View File

@@ -1,3 +1,4 @@
<nav id="nav-service-nav" aria-label="Service navigation">
<div class="navigation-service margin-top-5 display-flex flex-align-end flex-justify border-bottom padding-bottom-1">
{% if current_service.organization_id %}
{% if current_user.platform_admin or
@@ -13,3 +14,4 @@
</div>
<a href="{{ url_for('main.choose_account') }}" class="usa-link">Switch service</a>
</div>
</nav>

View File

@@ -25,7 +25,7 @@
{% if job.scheduled_for %}
<div class="usa-alert usa-alert--info">
<div class="usa-alert__body">
<h4 class="usa-alert__heading">Your text has been scheduled</h4>
<h2 class="usa-alert__heading">Your text has been scheduled</h2>
<p class="usa-alert__text">
{{ job.template_name }} - {{ current_service.name }} was scheduled on {{ job.scheduled_for|format_datetime_normal }} by {{ job.created_by.name }}
</p>
@@ -35,7 +35,7 @@
{% else %}
<div class="usa-alert usa-alert--success">
<div class="usa-alert__body">
<h4 class="usa-alert__heading">Your text has been sent</h4>
<h2 class="usa-alert__heading">Your text has been sent</h2>
<p class="usa-alert__text">
{{ job.template_name }} - {{ current_service.name }} was sent on {% if job.processing_started %}
{{ job.processing_started|format_datetime_table }} {% else %}

View File

@@ -60,7 +60,7 @@
<h2 class="margin-top-4 margin-bottom-1">Sent jobs</h2>
<div class="usa-table-container--scrollable-mobile">
<table class="usa-table usa-table--compact job-table">
<caption></caption>
<caption class="usa-sr-only">Table showing all sent jobs for this service</caption>
<thead class="table-field-headings">
<tr>
<th scope="col" role="columnheader" class="table-field-heading-first" id="jobId">
@@ -90,7 +90,7 @@
{% if all_jobs_dict %}
{% for job in all_jobs_dict %}
<tr class="table-row">
<td class="table-field jobid" scope="row" role="rowheader">
<td class="table-field jobid" role="rowheader">
<a class="usa-link" href="{{ job.view_job_link }}">
{{ job.job_id[:8] if job.job_id else 'Manually entered number' }}
</a>
@@ -103,7 +103,10 @@
<td class="table-field sender">{{ job.created_by.name }}</td>
<td class="table-field report">
{% if job.time_left != "Data no longer available" %}
<a href="{{ job.download_link }}"><img src="{{ url_for('static', filename='img/material-icons/file_download.svg') }}" alt="File Download Icon"></a>
<a href="{{ job.download_link }}">
<img src="{{ url_for('static', filename='img/material-icons/file_download.svg') }}" alt="">
<span class="usa-sr-only">Download report link</span>
</a>
{% else %}
<span>N/A</span>
{% endif %}

View File

@@ -0,0 +1,145 @@
{% extends "base.html" %}
{% set page_title = "Measuring performance with benchmarking" %}
{% block per_page_title %}
{{page_title}}
{% endblock %}
{% block content_column_content %}
{% with title=page_title %}{% include "components/best-practices/nav_breadcrumb.html" %}{% endwith %}
<section class="usa-prose">
<h1>{{page_title}}</h1>
<p class="font-sans-lg text-base">Learn how effective your texting program can be.</p>
<p>
Several factors determine a messaging campaigns success, but the performance of previous projects can help set
expectations. Get to know what other government texting initiatives have done as a way to benchmark your own
performance.
</p>
<h2>What other texting studies have found</h2>
<p>
When the <a
href="https://www.cbpp.org/research/food-assistance/targeted-text-message-outreach-can-increase-wic-enrollment-pilots-show"
target="_blank">Center on Budget and Policy Priorities</a> studied WIC, they found key learnings about the
quantity of messages delivered, how people engage with messages, and how they take action.
</p>
<h3 class="padding-left-5">Message delivery</h3>
<p class="font-body-lg text-light padding-left-5">Benchmark: <span class="text-bold">80%</span> of texts are
successfully delivered
</p>
<div class="padding-left-2 measure-4">
<ul>
<li>
<p>
You may discover that some numbers are temporarily or permanently unavailable due to service being
discontinued,
numbers changing, or being a landline.
</p>
</li>
</ul>
</div>
<h3 class="padding-left-5">Engagement</h3>
<div class="measure-4 padding-left-5">
<p class="font-body-lg text-light">Benchmark: Engagement rates with texts ranged from <span
class="text-bold">17%</span>
to <span class="text-bold">26%</span></p>
</div>
<div class="padding-left-2 measure-4">
<ul>
<li>
<p>
The highest rate of engagement with a text comes within hours of sending. Engagement rates include any kind
of
action taken due to a text, including replying “STOP” to prevent future texts.
</p>
</li>
</ul>
</div>
<h3 class="padding-left-5">Appointment requests</h3>
<div class="measure-4 padding-left-5">
<p class="font-body-lg text-light">Benchmark: Requesting appointments after receiving texts ranged
from <span class="text-bold">4%</span> to <span class="text-bold">9%</span></p>
</div>
<div class="padding-left-2 measure-4">
<ul>
<li>
<p>
Requesting appointments is a specific type of engagement. Provide a phone number or link to an online
appointment
request form.
</p>
</li>
</ul>
</div>
<p>
The <a href="https://codeforamerica.org/resources/texting-playbook/" target="_blank">Code for Americas Texting
Playbook</a>
reported specific learnings around appointment reminders, completing
document submission, and maintenance reminders.
</p>
<h3 class="padding-left-5">Appointment reminders</h3>
<div class="measure-4 padding-left-5">
<p class="font-body-lg text-light">Benchmark: Clients were <span class="text-bold">79%</span> more
likely
to keep
their appointment after receiving a text reminder.</p>
</div>
<div class="padding-left-2 measure-4">
<ul>
<li>
<p>You will likely see more completed appointments.</p>
</li>
</ul>
</div>
<div class="measure-4 padding-left-5">
<p class="font-body-lg text-light">Benchmark: Clients were <span class="text-bold">55%</span> more
likely
to complete
an interview after receiving an interview reminder</p>
</div>
<div class="padding-left-2 measure-4">
<ul>
<li>
<p>You will likely see more completed interviews.</p>
</li>
</ul>
</div>
<h3 class="padding-left-5">Document submission</h3>
<div class="measure-4 padding-left-5">
<p class="font-body-lg text-light">
Benchmark: Clients were <span class="text-bold">6%</span> more likely to complete document submission after
receiving a customized list of required documents via text
</p>
</div>
<div class="padding-left-2 measure-4">
<ul>
<li>
<p>To encourage response, provide a custom list of the needed documents and information about how to submit
them.
</p>
</li>
</ul>
</div>
<h3 class="padding-left-5">Reminders</h3>
<div class="measure-4 padding-left-5">
<p class="font-body-lg text-light">Benchmark: Text reminders improved case maintenance rates by <span
class="text-bold">21%</span></p>
</div>
<div class="padding-left-2 measure-4">
<ul>
<li>
<p>You may see less turnover in your case rates.</p>
</li>
</ul>
</div>
</section>
{% endblock %}

View File

@@ -0,0 +1,64 @@
{% extends "base.html" %}
{% block per_page_title %}
Best Practices
{% endblock %}
{% block content_column_content %}
<section class="usa-prose">
<h1>Best Practices</h1>
<p class="font-sans-lg text-base">For texting the public</p>
<p>Effectively reaching your audience and supporting your programs goals starts with strategically planning out what
text messages can help you achieve and how to approach a thoughtful rollout.
</p>
<p>This set of best practices will help you get an effective texting initiative up and running.</p>
<h2 class="padding-bottom-2">
Key elements of a texting campaign
</h2>
{% set card_contents = [
{
"svg_src": "goal",
"card_heading": "Establish clear goals",
"p_text": "Start with a singular purpose. Make explicit what you want to achieve.",
"link": "/best-practices/clear-goals"
},
{
"svg_src": "compliant",
"card_heading": "Follow rules & regulations",
"p_text": "Understand what is required when texting the public.",
"link": "/best-practices/rules-and-regulations"
},
{
"svg_src": "trust",
"card_heading": "Establish trust",
"p_text": "Help your audience anticipate and welcome your texts.",
"link": "/best-practices/establish-trust"
},
{
"svg_src": "runner",
"card_heading": "Write texts that provoke action",
"p_text": "Help your audience know what to do with the information you send.",
"link": "/best-practices/write-for-action"
},
{
"svg_src": "language",
"card_heading": "Send texts in multiple languages",
"p_text": "What to know as you plan translated texts.",
"link": "/best-practices/multiple-languages"
},
{
"svg_src": "chart",
"card_heading": "Measure performance with benchmarking",
"p_text": "Learn how effective your texting program can be.",
"link": "/best-practices/benchmark-performance"
}
] %}
{% with card_contents=card_contents %}{% include "components/best-practices/cards.html" %}{%
endwith %}
</section>
{% endblock %}

View File

@@ -0,0 +1,201 @@
{% extends "base.html" %}
{% set page_title = "Establish clear goals" %}
{% block per_page_title %}
{{page_title}}
{% endblock %}
{% block content_column_content %}
{% with title=page_title %}{% include "components/best-practices/nav_breadcrumb.html" %}{% endwith %}
<section class="usa-prose">
<h1>{{page_title}}</h1>
<p class="font-sans-lg text-base">Start with a singular purpose. Make explicit what you want to achieve.</p>
<div class="grid-row grid-gap-3">
<div class="tablet:grid-col">
<p>Text messaging should be one part of how you communicate with the people you serve, and it is best used to
provoke
action or influence behavior. Therefore, when starting to plan your texting campaign, its important to start
with
the end in mind.
</p>
<div class="usa-summary-box maxw-tablet" role="region" aria-labelledby="summary-box-establish-clear-goals">
<div class="usa-summary-box__body">
<p class="usa-summary-box__heading" id="summary-box-establish-clear-goals">
To establish clear goals, start by answering the following questions:
</p>
<div class="usa-summary-box__text">
<ul class="usa-list">
<li><i>Who</i> do you want to text?</li>
<li><i>At what moments</i> do you want to text them?</li>
<li><i>Why</i> do you want to text them?</li>
<li>What do you want them to <i>do</i>?</li>
</ul>
</div>
</div>
</div>
</div>
<div class="tablet:grid-col width-full padding-top-3">
<div class="grid-container">
<div class="usa-card__container border-0 width-full overflow-hidden maxh-mobile-lg">
<img class="width-full" src="{{ asset_url('images/phone_grey.svg') }}" role="img" alt="Phone" />
<div class="position-absolute flex text-center padding-5 padding-top-15">
<p class="sms-message-wrapper text-left">Dept. of Human Services: We believe your EBT card may have been
used by
someone else. Please call the number on the back of your card (888-123-5555) to cancel and get a new
one.
If
you
need a new card immediately, please visit your local office.
</p>
</div>
</div>
</div>
</div>
</div>
<hr>
<h2>When should you send a text?</h2>
<div class="grid-row grid-gap-3">
<div class="tablet:grid-col">
<div class="do-dont">
<div class="do-dont__do">
<h3 class="do-dont__heading"><a id="what-to-do" class="usa-anchor"></a>
<svg class="usa-icon" aria-hidden="true" focusable="false" role="img">
<use xlink:href="{{ url_for('static', filename='img/sprite.svg') }}#check_circle"></use>
</svg>
What to do
</h3>
<div class="do-dont__content">
<p><b>Use texting to</b> share timely
information, provide critical status updates, or remind someone to do something.</p>
<p class="margin-bottom-2">Examples:</p>
{% set list_item_dos = [
{
"list_content": "Your application is due on…",
},
{
"list_content": "We need more information from you to process your application for…",
},
{
"list_content": "We will be calling you about…at…",
},
{
"list_content": "We will be calling you about…at…",
},
] %}
<ul>
{% for item in list_item_dos %}
<li>
{{item.list_content}}
</li>
{% endfor %}
</ul>
</div>
</div>
</div>
</div>
<div class="tablet:grid-col">
<div class="do-dont">
<div class="do-dont__dont">
<h3 class="do-dont__heading"><a id="what-not-to-do" class="usa-anchor"></a>
<svg class="usa-icon" aria-hidden="true" focusable="false" role="img">
<use xlink:href="{{ url_for('static', filename='img/sprite.svg') }}#cancel"></use>
</svg> What not to do
</h3>
<div class="do-dont__content">
<p>Texting is <b>not great for</b> long,
detailed instructions or frequent reminders that may be ignored.
</p>
<p class="margin-bottom-2">Examples:</p>
{% set list_item_donts = [
{
"list_content": "Your rights and responsibilities",
},
{
"list_content": "How to complete your application",
},
{
"list_content": "Weekly reminder not to share your account information",
},
] %}
<ul>
{% for item in list_item_donts %}
<li>
{{item.list_content}}
</li>
{% endfor %}
</ul>
</div>
</div>
</div>
</div>
</div>
<p>Your program may already be communicating with your audience through methods like mailed notices and phone calls.
Think of text messages as complementary to your existing communications. Review how well you are currently reaching
your audience. Are there methods or gaps that could be supplemented with a text message?
</p>
<p>
The Department of Veterans Affairs provides a <a class="use-link usa-link--external"
href="https://github.com/department-of-veterans-affairs/va.gov-team/blob/master/products/va-notify/notification-guide.md#vanotify-notification-guide"
target="_blank">helpful flow-chart</a> that can help you decide if a text message is needed
for the communication problem you are trying to solve.
</p>
<h2>Use a hypothesis framework to plan your campaign</h2>
<p>
Think of your texting campaign as a scientific experiment, and try to articulate what you hope to improve as a
result of implementing text messaging at your agency. For example:
</p>
<div class="usa-summary-box maxw-tablet" role="region" aria-labelledby="summary-box-establish-clear-goals">
<div class="usa-summary-box__body">
<div class="usa-summary-box__text">
<p class="margin-top-0 font-body-lg">
We believe that texting <i>[specific group of people]</i> when <i>[this happens or on this
cadence]</i> to inform/alert them about <i>[subject]</i> will result in <i>[desired action]</i>.
</p>
</div>
</div>
</div>
<p>
Review your drafted hypothesis with your team to make sure everyone is aligned on your desired goals. A clear and
concise hypothesis can help you decide how to <a href="../best-practices/write-for-action">write text message
content
that provokes action</a>.
</p>
<h2>Begin with a small test</h2>
<p>
To help you decide how much to invest in text messaging over time, we highly recommend starting small and testing
your message campaigns to refine based on feedback and evidence.
</p>
<p>
Starting small has less risk and more flexibility. It can help you gather data and decide <i>if and how</i> to send
more text messages. For example, start by sending one message to a smaller sample of your audience and track their
resulting behavior.
</p>
<p>
At a minimum, make sure to get feedback on your message content from staff, community-based organizations, and,
ideally, from people who receive the texts themselves to ensure your messages are clear and actionable.
</p>
<h2>Measure performance</h2>
<p>Building and operationalizing a texting initiative requires time and effort, and you want to be able to demonstrate
the results of that effort.</p>
<div class="usa-summary-box maxw-tablet" role="region" aria-labelledby="summary-box-establish-clear-goals">
<div class="usa-summary-box__body">
<div class="usa-summary-box__text">
<p class="margin-top-0">
To understand if your texting program is successful, ask:
</p>
<ul class="usa-list">
<li>What do you want to be different for your program or your desired audience after a text message is sent,
as compared to your current state?</li>
<li>How will you know if text recipients take the desired action?</li>
<li>Do you have access to existing data in your system that you could use to determine whether texting is
giving you the results you want?</li>
</ul>
</div>
</div>
</div>
</section>
{% endblock %}

View File

@@ -0,0 +1,193 @@
{% extends "base.html" %}
{% from "components/best-practices/circle_number.html" import circle_number %}
{% set page_title = "Establish trust" %}
{% block per_page_title %}
{{page_title}}
{% endblock %}
{% block content_column_content %}
{% with title=page_title %}{% include "components/best-practices/nav_breadcrumb.html" %}{% endwith %}
<section class="usa-prose">
<h1>{{page_title}}</h1>
<p class="font-sans-lg text-base">Help your audience anticipate and welcome your texts.</p>
<p>
People are wary of texts theyre not expecting to receive. Before you send your first text, consider how you will
gain trust with your audience and address any concerns of spam. Seize specific moments to reinforce what your
audience should expect from your messages.
</p>
<h2 id="get-the-word-out">Get the word out</h2>
<p>Before you launch, let your audience know you are adding texting as a communication method. People are more likely
to trust your text once they get it if they know that your program is sending texts.</p>
<p>How you currently communicate with your audience will determine the best approaches to announce your new
initiative. Harness channels youre already using like social media, public websites, mailing inserts, or fliers at
key service locations as well as partnering with community organizations to get the word out about your new texting
program.</p>
<h3>An example of key messages in direct mail</h3>
<figure>
<img src="{{asset_url('images/snap-renewal.jpg')}}" alt="snap-renewal" width="100%">
<figcaption>A paper mailer sent out by the State of Connecticut, in partnership with Code for America, to get the
word out about their new SNAP texting initiative. Flier displays an image of an introduction text and includes key
messages to reinforce legitimacy.</figcaption>
</figure>
<h3>Prime your audiences to trust you</h3>
<ul class="usa-card-group flex-1 flex-wrap padding-top-2">
<li class="flex-1 width-full height-full padding-bottom-2">
<div class="usa-card__container border-0">
<p>To reinforce legitimacy, include these key messages in your outreach:</p>
<ol class="best-practices-list">
<li><b>Introduce yourself</b> Give people time to get to know your texting communications before you need
direct action from them</li>
<li><b>Phone number</b> Note the sending phone number your texts will come from</li>
<li><b>Text types</b> Be clear on the types of texts you intend to send, how often, and why they matter</li>
<li><b>Privacy policy</b> For example, state that you will not collect personal information, including the
types of information you will never ask for</li>
<li><b>Places to verify</b> Include a phone number, website, or human where people can verify that the texts
are coming from you</li>
<li><b>Opt out</b> Provide opt-out instructions and a disclaimer for the potential cost of receiving the
text
</li>
</ol>
</div>
</li>
<li class="usa-card flex-1 usa-card--media-right width-full padding-top-3">
<div class="usa-card__container border-0 width-full overflow-hidden height-phone-lg">
<img class="width-full" src="{{ asset_url('images/phone_grey.svg') }}" role="img" alt="Phone" />
<div class="position-absolute flex text-center padding-5 padding-top-15">
<p class="sms-message-wrapper text-left">Dept. of Social Services: Welcome to text updates from the
{{circle_number(1)}}<b>Department of Social Services.</b> {{ circle_number(2) }}<b>Well always text
you from
this number,</b> save us to your contact list. Our goal is to {{ circle_number(3) }} <b>keep you up to
date on
your account status.</b> {{ circle_number(4) }} <b>We will never ask for personal details in a text.</b>
{{ circle_number(5) }} If you have questions about how we protect your privacy, see
state.gov/privacy.{{circle_number(6) }}<b>Reply STOP to stop.</b>
</p>
</div>
</div>
</li>
</ul>
<hr>
<h2 id="as-people-receive-texts">As people receive texts</h2>
<p>When a person has questions or needs assistance, reaching out for support may be natural for them. Give direction
in your texts so your audience understands what to do with the information you provide. Remember, its important to
repeat consistent and standardized language across texts and programs.</p>
<h3>Be trustworthy</h3>
<ul class="usa-card-group flex-1 flex-wrap padding-top-2">
<li class="flex-1 width-full height-full padding-bottom-2">
<div class="usa-card__container border-0">
<ol start="7" class="best-practices-list set-two">
<li>Identify yourself in the text message. Use a consistent and familiar <b>program name</b> to precede each
text you send.</li>
<li>Personalize with <b>first name</b>. Through A/B testing, Code for America saw an increase in
follow-through by 25% if someones first name was included.</li>
<li>Use <b>full and direct .gov website URLs</b>. Avoid link shorteners, as they obscure your links and
potentially make it easier for a malicious actor to spoof your text.</li>
<li>If providing a phone number, use a familiar phone number and <b>provide information on how to verify</b>
its legitimacy.</li>
</ol>
</div>
</li>
<li class="usa-card flex-1 usa-card--media-right width-full padding-top-1">
<div class="usa-card__container border-0 width-full height-mobile overflow-hidden">
<img class="width-full" src="{{ asset_url('images/phone_grey.svg') }}" role="img" alt="Phone" />
<div class="position-absolute flex text-center padding-5 padding-top-10">
<p class="sms-message-wrapper text-left">
{{circle_number(7) }}<b>Dept. of Social Services:</b> Hi {{circle_number(8) }}<b>Julie,</b> Your Medicaid
renewal is closing December 31, 2023. You can renew online at {{circle_number(9) }}<a
href="https://www.application.yourstate.gov" target="_blank"
rel="application.yourstate.gov">https://www.application.yourstate.gov</a> or {{circle_number(10) }}
<b>call the number on the back</b> of your Medicaid card.
</p>
</div>
</div>
</li>
</ul>
<h3>Provide helpful auto-responses</h3>
<ul class="usa-card-group flex-1 flex-wrap padding-top-2">
<li class="flex-1 width-full height-full padding-bottom-2">
<div class="usa-card__container border-0">
<p>If you're sending one-way notifications, phone carriers allow a single auto-response message that will be
generated if a recipient tries to text a response to your message. Use the auto-response to reaffirm your key
messages around legitimacy and communicate to recipients that texts are coming from an automated system.</p>
<ol class="best-practices-list set-three">
<li>Provide <b>a way to contact a human</b> in any auto-response text</li>
<li>Provide <b>information on how to opt out</b> and opt back in</li>
</ol>
</div>
</li>
<li class="usa-card flex-1 usa-card--media-right width-full padding-top-3">
<div class="usa-card__container border-0 width-full overflow-hidden best-practices">
<img class="width-full" src="{{ asset_url('images/phone_grey.svg') }}" role="img" alt="Phone" />
<div class="position-absolute flex text-center padding-5 padding-top-15">
<p class="sms-message-wrapper text-left">
Dept. of Social Services: This number is unmonitored. To {{circle_number(11) }} <b>contact us, call
888-123-4567</b>. We will never ask for personal details in a text. If you have questions about how to
protect your privacy, see state.gov/privacy {{circle_number(12) }} <b>Reply “STOP”</b> to this phone number
to opt out of receiving texts, and “START” to opt back in.
</p>
</div>
</div>
</li>
</ul>
<h2>Be prepared for questions</h2>
<p>
Your texting program will only be perceived as legitimate if you get the word out in many different ways. It's also
important that agency employees who support text recipients (for example, the call center) are familiar with the
texting program. They can accurately respond to recipient questions about them, so make sure youre priming your
delivery staff, especially those who interact directly with your intended audience.
</p>
<h3 class="padding-bottom-2">Harness trusted communication channels</h3>
{% set card_contents = [
{
"image_src": asset_url('images/website.svg'),
"card_heading": "Websites",
"alt_text": "Graphic representing a website browser",
"p_text": "Post banner alerts about texting on your agency website and link to a press release for more information.
Publish a public texting privacy policy.",
},
{
"image_src": asset_url('images/community-org.svg'),
"card_heading": "Community organizations",
"alt_text": "Illustration of community organizations spreading awareness",
"p_text": "Alert trusted community-based organizations that texts are coming and what they look like. Equip them with
fliers, posters, and talking points to spread the word.",
},
{
"image_src": asset_url('images/call-center.svg'),
"card_heading": "IVR / Call Centers",
"alt_text": "Illustration of a call center promoting texting initiative",
"p_text": "Consider adding hold message announcements about your texting initiative to further get the word out.",
},
] %}
{% with card_contents=card_contents %}{% include "components/best-practices/cards.html" %}{%
endwith %}
<h3 class="padding-bottom-2">Prepare your team</h3>
{% set card_contents = [
{
"image_src": asset_url('images/grouping.svg'),
"card_heading": "Staff",
"alt_text": "Illustration of staff group briefing",
"p_text": "Give all staff a heads-up about texts before and when they are sent. Share talking points on what texts
youre sending, when youll start to send them, the phone number they are coming from, and where staff can escalate
any issues.",
},
{
"image_src": asset_url('images/project-management.svg'),
"card_heading": "Case management systems",
"alt_text": "Graphic representing project management",
"p_text": "When it makes sense, include information about texts being sent to specific clients on individual splash
pages or within case management notes.",
},
] %}
{% with card_contents=card_contents %}{% include "components/best-practices/cards.html" %}{%
endwith %}
</section>
{% endblock %}

View File

@@ -0,0 +1,30 @@
{% extends "base.html" %}
{% set page_title = "Text in multiple languages" %}
{% block per_page_title %}
{{page_title}}
{% endblock %}
{% block content_column_content %}
{% with title=page_title %}{% include "components/best-practices/nav_breadcrumb.html" %}{% endwith %}
<section class="usa-prose">
<h1>{{page_title}}</h1>
<p class="font-sans-lg text-base"> What to know as you plan translated texts.</p>
<p>
Sending messages in recipients preferred language demonstrates respect, makes it more likely that recipients will
understand and take action on the message, and may be required by your agency or program.
</p>
<p>
To send translated messages using Notify.gov you will need two things: a record of your recipients preferred
language and translation/s of the message template. Notify.gov does not provide translation services.
</p>
<p>
As with messages in English, we strongly recommend user testing the translations with people who speak the language
to ensure the messages are understandable.
</p>
</section>
{% endblock %}

View File

@@ -0,0 +1,126 @@
{% extends "base.html" %}
{% set page_title = "Rules and regulations" %}
{% block per_page_title %}
{{page_title}}
{% endblock %}
{% block content_column_content %}
{% with title=page_title %}{% include "components/best-practices/nav_breadcrumb.html" %}{% endwith %}
<section class="usa-prose">
<h1>{{page_title}}</h1>
<p class="font-sans-lg text-base">Understand what is required when texting the public.</p>
<h2>What to know about consent and opting out</h2>
<p>
Providing consent and opting out are key ways for text recipients to express their text communication preferences.
Discuss your obligation to obtain consent with your legal counsel.
</p>
<p>
If you do need expressed consent, consider including a pre-checked plain language opt-in (i.e. “Its OK to text
me.”) on
digital forms. Be sure to ask for an up-to-date phone number and include a question about the recipients preferred
language for text messages if you expect to <a href="../best-practices/multiple-languages">translate your text
messages</a> in
languages other than English.
</p>
{% set links = [
{
"p_text": 'The <a class="use-link usa-link--external" href="https://www.fcc.gov/sites/default/files/tcpa-rules.pdf"
target="_blank">Telephone Consumer
Protection Act (TCPA)</a> (47 USC § 227) is the federal law that impacts how organizations are allowed to
communicate
in bulk with the public via telephone (including text message or SMS).'
},
{
"p_text": 'The <a class="use-link usa-link--external"
href="https://www.fcc.gov/document/fcc-provides-best-practices-enable-critical-health-care-coverage-calls"
target="_blank">FCC has ruled</a> that <b>Federal</b> and <b>State</b> programs are exempt from the TCPA and can
send
text messages to the public without consent if conducting official business. Without explicit mention in the ruling,
local governments, phone carriers, or any texting intermediaries might require it.'
},
{
"url_link":
"pdf/tcpa_overview.pdf",
"url_text":"Download and share our overview of the TCPA with your legal counsel",
"is_downloadable": true,
"p_text": 'It provides a baseline
interpretation to aid your legal counsel in getting up to speed with what might be needed for your program or use
case.
For additional questions about the enforcement of the TCPA, you can watch <a class="use-link usa-link--external"
href="https://www.performance.gov/cx/life-experiences/facing-a-financial-shock/outputs/fcc-training/"
target="_blank">a recorded training on public
benefits texting</a> provided by the FCC.'
},
] %}
<h3>Complying with the Telephone Consumer Protection Act (TCPA)</h3>
<ul class="usa-collection">
{% for item in links %}
<li class="usa-collection__item">
<div class="usa-collection__body">
{% if item.url_text %}
<h4 class="usa-collection__heading">
<a class="usa-link {% if item.is_downloadable %}usa-link--downloadable{% else %}usa-link--external{% endif %}"
href="{% if item.is_downloadable %}{{ asset_url(item.url_link) }}{% else %}{{ item.url_link }}{% endif %}"
target="_blank">
{{ item.url_text }}
</a>
</h4>
{% endif %}
<p class="usa-collection__description">
{{item.p_text |safe}}
</p>
</div>
</li>
{% endfor %}
</ul>
<h3>Opting out</h3>
<p>
There is no policy requirement for senders to communicate opt-out options, but <a
href="../best-practices/establish-trust#as-people-receive-texts"> including instructions in introductory and/or
auto-response texts </a> on how to opt out and opt back in are effective ways to establish trust with your
audience.
</p>
<p>
In the US, no matter where texts are coming from, a recipient has the right to revoke consent at any time through
any
reasonable means. For example, a text recipient can always opt out of receiving text messages from a phone number by
responding “STOP”, “QUIT”, or <a class="usa-link usa-link--external"
href="https://docs.aws.amazon.com/pinpoint/latest/userguide/channels-sms-limitations-opt-out.html#settings-sms-self-opt-out-terms"
target="_blank">one of several other keywords</a>.
</p>
<p>
Any subsequent messages sent to that number will be blocked by the phone carrier and not delivered. We recommend
establishing an internal process to obtain and remove numbers that fail multiple times to avoid continuing to send
messages to them.
</p>
<h2>Honoring privacy</h2>
<h3>Phone numbers are personally identifiable information (PII)</h3>
<p>
When putting together the data spreadsheet (or CSV) file containing text message data, follow relevant security
processes for storing and transmitting the file that contains PII.
</p>
<h3>Dont text sensitive information</h3>
<p>
Sensitive information should be protected and secure. Social Security Numbers, drivers license numbers, personal
health information, and passwords are all sensitive PII that should not be shared via text message. Consult with
your privacy office to understand what information you can and cannot include in a text message. Different programs
and jurisdictions may have different rules and interpretations.
</p>
<h3>Assess risk</h3>
<p>
Consider the risks if someone who is not the intended recipient receives the text message. Establish an internal
process
to keep your phone number list up-to-date. The FCC offers a <a class="use-link usa-link--external"
href="https://www.fcc.gov/reassigned-numbers-database" target="_blank"
rel="Reassigned Numbers Database">Reassigned
Numbers Database</a> to identify phone numbers that may have been reassigned since your agency obtained them.
</p>
</section>
{% endblock %}

View File

@@ -0,0 +1,106 @@
{% extends "base.html" %}
{% from "components/best-practices/circle_number.html" import circle_number %}
{% set page_title = "Write texts that provoke action" %}
{% block per_page_title %}
{{page_title}}
{% endblock %}
{% block content_column_content %}
{% with title=page_title %}{% include "components/best-practices/nav_breadcrumb.html" %}{% endwith %}
<section class="usa-prose">
<h1>{{page_title}}</h1>
<p class="font-sans-lg text-base"> Help your audience know what to do with the information you send.</p>
<p>
When writing a text, focus on the person who is going to receive the message and write it for them. Use plain
language and provide easy to understand next steps.
</p>
<div class="usa-summary-box maxw-tablet" role="region" aria-labelledby="summary-box-establish-clear-goals">
<div class="usa-summary-box__body">
<p class="usa-summary-box__heading" id="summary-box-establish-clear-goals">
When deciding what types of messages to draft for your campaign, think through the following questions:
</p>
<div class="usa-summary-box__text">
<ul class="usa-list">
<li>What do you want recipients to do when they receive the text?</li>
<li>What will happen if a recipient doesn't take the action you want them to take?</li>
<li>Will you send any follow-up texts depending on if the action was taken or not?</li>
</ul>
</div>
</div>
</div>
<h2>Be clear and concise</h2>
<ul>
<li>Use simple, everyday language. Keep the text short and clear. Stay under 300 characters.</li>
<li>
Say only one important thing per message. Focus on the most essential instructions and information. If there are
multiple actions you want someone to take, consider sending a series of well-timed messages.
</li>
<li>Use a neutral, direct, and professional tone. This works better than a friendly or overly casual tone.</li>
</ul>
<h2>Build conditions for action</h2>
<ul class="usa-card-group flex-1 flex-wrap padding-top-2 best-practices-flex-container">
<li class="flex-1 width-full height-full padding-bottom-2">
<div class="usa-card__container border-0">
<p>For example, getting a person to update their mailing address:</p>
<ol class="best-practices-list">
<li>Clearly state the information and the response you want the recipient to take.</li>
<li>Point directly to where the action can be completed, not to more information.</li>
<li>Make sure the action can be completed via mobile phone, like calling a person or going to a
mobile-friendly URL.
</li>
<li>
Include at least two options for a recipient to take action. Some recipients may be more comfortable talking
directly
to a person, while others may prefer a web-based experience.
</li>
<li>Consider clearly explaining any consequences if the desired action is not completed.</li>
</ol>
</div>
</li>
<li class="flex-1 usa-card--media-right width-full padding-top-3">
<div class="usa-card__container border-0 width-full">
<img class="width-full" src="{{ asset_url('images/phone_grey.svg') }}" role="img" alt="Phone" />
<div class="position-absolute flex text-center padding-5 padding-top-15">
<p class="sms-message-wrapper text-left">{{circle_number(1) }}State Medicare Agency: Hello, MEDICARE has
attempted to
send you an update about your claim, but the mail was returned. <br>{{circle_number(2) }}Please go to
https://www.medicare.gov/account/login?utm_source=TEXT, {{circle_number(3) }}log in to your account, and
click “My
Account Information” to verify that your address is correct. If you are having difficulty logging in,
{{circle_number(4) }}call 1-800-MEDICARE for assistance. {{circle_number(5) }}We will attempt to send the
mail again
in 14 days.
</p>
</div>
</div>
</li>
</ul>
<h2>What provoking action looks like</h2>
<p class="padding-bottom-2"><a href="https://www.ncbi.nlm.nih.gov/pmc/articles/PMC10002044/" target="_blank">Evidence
shows</a> that employing
behavioral science is an effective way to increase the
likelihood of a recipient
taking action upon receiving your text. Keep in mind these three foundational principles while drafting your text
message:</p>
{% set card_contents = [
{
"card_heading": "Feeling a sense of ownership can influence behavior.",
"p_text": "Example <b>Don't miss this chance to get free internet</b> or $30 per month off your internet bill.",
},
{
"card_heading": "Individuals are strongly influenced by others behaviors.",
"p_text": "Example <b>Thousands of residents</b> already get an
average of $113/month in money for food.",
},
{
"card_heading": "Individuals perceive losses more powerfully than gains.",
"p_text": "Example Contact us for potentially unclaimed free
internet services <b>that belong to you</b>.",
},
] %}
{% with card_contents=card_contents, text_align='left' %}{% include "components/best-practices/cards.html" %}{%
endwith %}
</section>
{% endblock %}

View File

@@ -38,7 +38,7 @@
<form class="usa-form">
<label class="usa-label" for="options">Account</label>
<select class="usa-select margin-bottom-2" name="options" id="options">
<option value>- Select -</option>
<option value disabled>- Select -</option>
<option value="service" selected>{{ current_service.name }}</option>
<option value="individual">{{ current_user.name }}</option>
</select>
@@ -46,7 +46,7 @@
<div id="activityChart">
<div class="chart-header">
<div class="chart-subtitle">{{ current_service.name }} - last 7 days</div>
<div class="chart-legend" aria-label="Legend"></div>
<div class="chart-legend" role="region" aria-label="Legend"></div>
</div>
<div class="chart-container" id="weeklyChart"></div>
<table id="weeklyTable" class="usa-sr-only usa-table"></table>
@@ -60,6 +60,7 @@
<div id="table1" class="table-overflow-x-auto hidden">
<h2 class="margin-top-4 margin-bottom-1">My activity</h2>
<table class="usa-table job-table">
<caption class="usa-sr-only">Table showing the sent jobs for {{current_user.name}}</caption>
<thead class="table-field-headings">
<tr>
<th scope="col" class="table-field-heading-first" id="jobId"><span>Job ID#</span></th>
@@ -74,7 +75,7 @@
{% if job.created_by.name == current_user.name %}
{% set notification = job.notifications[0] %}
<tr id="{{ job.job_id }}">
<td class="table-field jobid" scope="row" role="rowheader">
<td class="table-field jobid" role="rowheader">
<a class="usa-link" href="{{ job.view_job_link }}">
{{ job.job_id[:8] if job.job_id else 'Manually entered number' }}
</a>
@@ -100,6 +101,7 @@
<div id="table2" class="table-overflow-x-auto visible">
<h2 class="margin-top-4 margin-bottom-1">Service activity</h2>
<table class="usa-table job-table">
<caption class="usa-sr-only">Table showing the sent jobs for this service</caption>
<thead class="table-field-headings">
<tr>
<th scope="col" role="columnheader" class="table-field-heading-first" id="jobId"><span>Job ID#</span></th>
@@ -114,7 +116,7 @@
{% for job in jobs[:5] %}
{% set notification = job.notifications[0] %}
<tr id="{{ job.job_id }}">
<td class="table-field jobid" scope="row" role="rowheader">
<td class="table-field jobid" role="rowheader">
<a class="usa-link" href="{{ job.view_job_link }}">
{{ job.job_id[:8] if job.job_id else 'Manually entered number' }}
</a>

View File

@@ -16,17 +16,22 @@
<p>Below we explain how to:</p>
<ul class="list list-bullet">
{% if not feature_best_practices_enabled %}
<li><a class="usa-link" href="#format-content">Format your content</a></li>
<li><a class="usa-link" href="#add-links">Add links</a></li>
{% endif %}
<li><a class="usa-link" href="#personalize-content">Personalize your content</a></li>
<li><a class="usa-link" href="#conditional-content">Add conditional content</a></li>
<li><a class="usa-link" href="#indentify-program">Identify your program</a></li>
<li><a class="usa-link" href="#prepare-data">Prepare your data</a></li>
{% if not feature_best_practices_enabled %}
<li><a class="usa-link" href="#prevent-fraud">Prevent fraud</a></li>
{% endif%}
</ul>
{# Format content #}
<h2 class="padding-top-1" id="format-content">Format your content</h2>
{% if not feature_best_practices_enabled %}
<p>Effective texts will help your message recipients take the steps needed to secure and keep the benefits and services
they depend on. To craft an effective text:</p>
@@ -37,7 +42,7 @@
<li>Say only one important thing per message.</li>
<li>Frame the message to encourage action and explain the consequences of not completing the desired action.</li>
</ul>
{% endif %}
<h3>To create and format your message</h3>
<ol class="list">
<li>All messages start from a template</li>
@@ -45,6 +50,7 @@
<li>Add a new template or choose an existing template and select Edit.</li>
</ol>
{% if not feature_best_practices_enabled %}
{# Add links #}
<h2 class="padding-top-1" id="add-links">Add links</h2>
<p>When composing a text message, links to websites or online applications can help your recipient respond quickly.</p>
@@ -64,6 +70,7 @@
<li>Your link might stop working if theres a service outage.</li>
<li>You can no longer control where the redirect goes.</li>
</ul>
{% endif %}
{# Personalize content #}
<h2 class="padding-top-1" id="personalize-content">Personalize your content</h2>
@@ -214,6 +221,7 @@
</table>
</div>
{% if not feature_best_practices_enabled %}
{# Preventing fraud #}
<h2 class="padding-top-1" id="prevent-fraud">Preventing fraud</h2>
<p>Texting fraud is ever prevalent and while we cant eliminate the risk, we can reduce the chances that recipients will
@@ -240,5 +248,5 @@
in a text. If you have questions about how to protect your privacy, see statename.gov/privacy.</p>
</li>
</ol>
{% endif %}
{% endblock %}

View File

@@ -33,7 +33,7 @@
<ul class="list list-bullet">
<li>Achieve compliance to begin piloting, such as ATO and privacy standards.
<svg class="usa-icon" aria-hidden="true" focusable="false" role="img">
use xlink:href="/assets/img/sprite.svg#check"></use>
<use xlink:href="/assets/img/sprite.svg#check"></use>
</svg>
</li>
<li>Demonstrate that a government-run notifications tool provides a unique value.</li>

View File

@@ -21,7 +21,7 @@
{% endif %}
</p>
{% else %}
<nav id="template-list">
<nav id="template-list" aria-label="Template list">
{% set checkboxes_data = [] %}
{% if not current_user.has_permissions('manage_templates') %}
@@ -38,22 +38,28 @@
{% for item in template_list %}
{% set item_link_content %}
{% if item.is_folder %}
<a href="{{ url_for('.choose_template', service_id=current_service.id, template_type=template_type, template_folder_id=item.id) }}"
class="usa-link template-list-folder">
<span class="live-search-relevant">{{- format_item_name(item.name) -}}</span>
</a>
{% elif not item.ancestors %}
<a href="{{ url_for('.view_template', service_id=current_service.id, template_id=item.id) }}"
class="usa-link template-list-template">
<span class="live-search-relevant">
{%- if current_service.api_keys -%}
<span class="display-none">{{ item.id }} </span>
{%- endif -%}
{{- format_item_name(item.name) -}}
</span>
</a>
{% endif %}
{% if item.is_folder %}
<a href="{{ url_for('.choose_template', service_id=current_service.id, template_type=template_type, template_folder_id=item.id) }}"
class="usa-link template-list-folder"
tabindex="0"
role="link"
aria-label="{{ item.name }}">
<span class="live-search-relevant">{{- format_item_name(item.name) -}}</span>
</a>
{% elif not item.ancestors %}
<a href="{{ url_for('.view_template', service_id=current_service.id, template_id=item.id) }}"
class="usa-link template-list-template"
tabindex="0"
role="link"
aria-label="{{ item.name }}">
<span class="live-search-relevant">
{%- if current_service.api_keys -%}
<span class="display-none">{{ item.id }} </span>
{%- endif -%}
{{- format_item_name(item.name) -}}
</span>
</a>
{% endif %}
{% endset %}
{% set label_content %}
@@ -82,6 +88,8 @@
"id": "templates-or-folder-" ~ item.id,
"classes": "template-list-item template-list-item-with-checkbox {}".format(
"template-list-item-hidden-by-default" if item.ancestors else "template-list-item-without-ancestors"),
"attributes": { "role": "checkbox", "aria-describedby": item.id ~ "-item-hint" },
"after": item_link_content ~ item_meta
} %}
{% set _ = checkboxes_data.append(checkbox_config) %}

View File

@@ -37,7 +37,7 @@
{{ live_search(target_selector='#template-list .template-list-item', show=True, form=search_form) }}
<nav id="template-list">
<nav id="template-list" aria-label="Choose reply">
<ul>
{% for item in templates_and_folders %}
<li class="template-list-item {% if item.ancestors %}template-list-item-hidden-by-default{% endif %} {% if not item.ancestors %}template-list-item-without-ancestors{% endif %}">

View File

@@ -33,7 +33,7 @@
{% else %}
<div class="grid-row">
<div class="grid-row flex-column">
<div class="{% if current_user.has_permissions('manage_templates') %} grid-col-10 {% else %} grid-col-12 {% endif %}">
<div class="usa-alert usa-alert--slim usa-alert--info">
<div class="usa-alert__body">
@@ -51,7 +51,7 @@
</div>
{% if current_user.has_permissions('manage_templates') and current_template_folder_id and user_has_template_folder_permission %}
<div class="grid-col-2">
<a href="{{ url_for('.manage_template_folder', service_id=current_service.id, template_folder_id=current_template_folder_id) }}" class="usa-link folder-heading-manage-link">Manage<span class="usa-sr-only"> this folder</span></a>
<a href="{{ url_for('.manage_template_folder', service_id=current_service.id, template_folder_id=current_template_folder_id) }}" class="usa-link folder-heading-manage-link">Manage this folder<span class="usa-sr-only">Manage this folder</span></a>
</div>
{% endif %}
</div>

View File

@@ -25,7 +25,7 @@
form=search_form,
autofocus=True
) }}
<nav id="template-list">
<nav id="template-list" aria-label="Copy template list">
<ul>
{% for item in services_templates_and_folders %}

View File

@@ -63,24 +63,29 @@
href="{{ url_for('.view_template_versions', service_id=current_service.id, template_id=template.id) }}">See previous
versions</a>
</li>
</ul>
{% endif %}
{% if current_user.has_permissions('manage_templates') and user_has_template_permission %}
{% if not template._template.archived %}
<ul class="usa-list usa-list--unstyled">
<li>
<a class="usa-link margin-right-3"
href="{{ url_for('.delete_service_template', service_id=current_service.id, template_id=template.id) }}">Delete this
template</a>
</li>
</ul>
{% endif %}
{% if not template._template.redact_personalisation %}
<ul class="usa-list usa-list--unstyled">
<li>
<a class="usa-link" href="{{ url_for('.confirm_redact_template', service_id=current_service.id, template_id=template.id) }}">Hide all personalized and conditional content after sending</a> for increased privacy protection
</li>
</ul>
{% else %}
<p class="hint">Personalization is hidden after sending</p>
{% endif %}
{% endif %}
</ul>
</div>
<!--<div class="">

View File

@@ -33,7 +33,7 @@
<h3 class="font-body-lg">Going Live</h3>
<p>To remove the restrictions of Trial Mode and begin sending messages to clients complete the <a href="https://airtable.com/appe4n7jYOALPLcyU/shrIPWnLTw9U1fclL">Live Campaign Form</a>.</p>
<p>To remove the restrictions of Trial Mode and begin sending messages to clients complete the <a class="usa-link usa-link--external" href="https://docs.google.com/forms/d/1fnaBtxuGf3q-OdGVyt2LqBKvp9_P21kmKJa0yIK8rWM/edit">Go-Live Form</a>.</p>
<p>We'll get back to you within one working day. </p>
{% endblock %}

View File

@@ -0,0 +1,22 @@
{% extends "withnav_template.html" %}
{% from "components/page-header.html" import page_header %}
{% from "components/components/back-link/macro.njk" import usaBackLink %}
{% block service_page_title %}
You must specify at least one permission for the user.
{% endblock %}
{% block backLink %}
{{ usaBackLink({ "href": url_for('main.manage_users', service_id=current_service.id) }) }}
{% endblock %}
{% block maincolumn_content %}
{{ page_header('This person has no permissions') }}
<p class="usa-body">
Your invited user currently has no permissions for
{{ current_service.name }}. Please specify grant some permissions to the user.
</p>
{% endblock %}

View File

@@ -1,6 +1,10 @@
import json
import os
from functools import wraps
from flask import redirect, request, session, url_for
import jwt
import requests
from flask import current_app, redirect, request, session, url_for
from app.models.user import User
from app.utils.time import is_less_than_days_ago
@@ -57,3 +61,32 @@ def is_safe_redirect_url(target):
redirect_url.scheme in ("http", "https")
and host_url.netloc == redirect_url.netloc
)
def get_id_token(json_data):
"""Decode and return the id_token."""
client_id = os.getenv("LOGIN_DOT_GOV_CLIENT_ID")
certs_url = os.getenv("LOGIN_DOT_GOV_CERTS_URL")
try:
encoded_id_token = json_data["id_token"]
except KeyError as e:
current_app.logger.exception(f"Error when getting id token {json_data}")
raise KeyError(f"'access_token' {request.json()}") from e
# Getting Login.gov signing keys for unpacking the id_token correctly.
jwks = requests.get(certs_url, timeout=5).json()
public_keys = {
jwk["kid"]: {
"key": jwt.algorithms.RSAAlgorithm.from_jwk(json.dumps(jwk)),
"algo": jwk["alg"],
}
for jwk in jwks["keys"]
}
kid = jwt.get_unverified_header(encoded_id_token)["kid"]
pub_key = public_keys[kid]["key"]
algo = public_keys[kid]["algo"]
id_token = jwt.decode(
encoded_id_token, pub_key, audience=client_id, algorithms=[algo]
)
return id_token

View File

@@ -9,9 +9,8 @@ from app.utils.csv import get_user_preferred_timezone
def get_current_financial_year():
preferred_tz = pytz.timezone(get_user_preferred_timezone())
now = datetime.now(preferred_tz)
current_month = int(now.strftime("%-m"))
current_year = int(now.strftime("%Y"))
return current_year if current_month < 10 else current_year + 1
return current_year
def is_less_than_days_ago(date_from_db, number_of_days):

View File

@@ -17,7 +17,6 @@ permission_options = (
("send_messages", "Send messages"),
("manage_templates", "Add and edit templates"),
("manage_service", "Manage settings, team and usage"),
("manage_api_keys", "Manage API integration"),
)

61
backstop.config.js Normal file
View File

@@ -0,0 +1,61 @@
const { urls, baseUrl } = require('./urls');
const MISMATCH_THRESHOLD = 0.3;
const SCREENSHOT_DELAY = 2000;
const createScenariosFromUrls = (urls, delay = SCREENSHOT_DELAY) => {
return Object.keys(urls).map((label) => ({
label,
url: urls[label],
selectors: ['document'],
misMatchThreshold: MISMATCH_THRESHOLD,
requireSameDimensions: true,
delay,
}));
};
module.exports = {
id: 'backstop_test',
viewports: [
{
label: 'desktop',
width: 1024,
height: 768,
},
],
scenarios: [
...createScenariosFromUrls(urls),
{
label: 'Choose Service - Accounts',
url: `${baseUrl}/accounts`,
selectors: ['h1.heading-large', 'a.usa-button[href="/add-service"]'],
misMatchThreshold: MISMATCH_THRESHOLD,
requireSameDimensions: true,
delay: SCREENSHOT_DELAY,
},
// example page with script
{
label: 'Get Started Page - Highlight Trial Mode',
url: `${baseUrl}/using-notify/get-started`,
selectors: ['document'],
misMatchThreshold: MISMATCH_THRESHOLD,
requireSameDimensions: true,
onBeforeScript: 'puppeteer/countFeatureLinks.js',
delay: SCREENSHOT_DELAY,
},
],
paths: {
bitmaps_reference: 'backstop_data/bitmaps_reference',
bitmaps_test: 'backstop_data/bitmaps_test',
engine_scripts: 'backstop_data/engine_scripts',
html_report: 'backstop_data/html_report',
ci_report: 'backstop_data/ci_report',
},
engine: 'puppeteer',
engineOptions: {
browser: 'chromium',
timeout: 30000,
},
report: ['browser'],
debug: false,
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 349 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 323 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 417 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 374 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 282 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 558 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

View File

@@ -0,0 +1,18 @@
module.exports = async (page, scenario) => {
await page.goto(scenario.url, { waitUntil: 'networkidle2' });
console.log('Page loaded.');
// Count the number of items in the side navigation and log their text
const navItems = await page.$$eval('nav ul li.usa-sidenav__item a', (items) =>
items.map((item) => item.textContent.trim())
);
console.log(`Found ${navItems.length} navigation items:`);
navItems.forEach((itemText, index) => {
console.log(`${index + 1}: ${itemText}`);
});
// Wait a moment for the logging to complete
await new Promise((resolve) => setTimeout(resolve, 1000));
};

View File

@@ -1,8 +1,10 @@
env: demo
instances: 1
memory: 1G
command: newrelic-admin run-program gunicorn -c /home/vcap/app/gunicorn_config.py application
public_admin_route: notify-demo.app.cloud.gov
cloud_dot_gov_route: notify-demo.app.cloud.gov
redis_enabled: 1
nr_agent_id: "1134302465"
nr_app_id: "1083160688"
nr_agent_id: '1134302465'
nr_app_id: '1083160688'
FEATURE_BEST_PRACTICES_ENABLED: true

View File

@@ -1,8 +1,10 @@
env: production
instances: 2
memory: 1.5G
command: newrelic-admin run-program gunicorn -c /home/vcap/app/gunicorn_config.py application
public_admin_route: beta.notify.gov
cloud_dot_gov_route: notify.app.cloud.gov
redis_enabled: 1
nr_agent_id: "1050708682"
nr_app_id: "1050708682"
nr_agent_id: '1050708682'
nr_app_id: '1050708682'
FEATURE_BEST_PRACTICES_ENABLED: false

View File

@@ -1,6 +1,7 @@
env: sandbox
instances: 1
memory: 1G
command: gunicorn -c /home/vcap/app/gunicorn_config.py application
public_admin_route: notify-sandbox.app.cloud.gov
cloud_dot_gov_route: notify-sandbox.app.cloud.gov
redis_enabled: 1
@@ -8,6 +9,7 @@ ADMIN_CLIENT_USERNAME: notify-admin
ADMIN_CLIENT_SECRET: sandbox-notify-secret-key
DANGEROUS_SALT: sandbox-notify-salt
SECRET_KEY: sandbox-notify-secret-key
nr_agent_id: ""
nr_app_id: ""
NR_BROWSER_KEY: ""
nr_agent_id: ''
nr_app_id: ''
NR_BROWSER_KEY: ''
FEATURE_BEST_PRACTICES_ENABLED: true

View File

@@ -1,8 +1,10 @@
env: staging
instances: 1
memory: 1G
command: newrelic-admin run-program gunicorn -c /home/vcap/app/gunicorn_config.py application
public_admin_route: notify-staging.app.cloud.gov
cloud_dot_gov_route: notify-staging.app.cloud.gov
redis_enabled: 1
nr_agent_id: "1134291385"
nr_app_id: "1031640326"
nr_agent_id: '1134291385'
nr_app_id: '1031640326'
FEATURE_BEST_PRACTICES_ENABLED: false

65
docs/backstop.md Normal file
View File

@@ -0,0 +1,65 @@
# BackstopJS Getting Started Guide
## Overview
BackstopJS is currently optional in this project and is used for visual regression testing to ensure consistency in the UI. To get started with BackstopJS, follow the steps below. The official guide can be found at the [BackstopJS GitHub Repository](https://github.com/garris/BackstopJS).
## Goal
Eventually BackstopJS will be implemented in the pipeline process to help catch errors before they make their way to higher environments.
## Prerequisites
Before running BackstopJS, ensure the following:
- Both the API and Admin projects must be running.
- In the .env file of both the API and Admin projects, make sure the following environment variables are uncommented and set to matching values:
- `NOTIFY_E2E_TEST_EMAIL`
- `NOTIFY_E2E_TEST_PASSWORD`
Example:
```bash
NOTIFY_E2E_TEST_EMAIL=your-email@example.com
NOTIFY_E2E_TEST_PASSWORD=your-password
```
### How to Run BackstopJS
#### Step 1: Install Gulp Globally
First, make sure all dependencies are installed and updated:
```
make bootstrap
```
#### Step 2: Run the Gulp Test Task
To run the visual regression tests, use the following command:
```
gulp backstopTest
```
If there are new expected changes in the UI, one will need to update the reference images before testing. To do this, run the following command:
```
gulp backstopReference
```
**_Note: After running the `gulp backstopReference` command, immediately running the test (`gulp backstopTest`) should pass all tests, assuming the changes are expected._**
### Adding New Tests
The entry point for BackstopJS configuration can be found in the `backstop.config.js` file.
To add a new feature or page to be tested, modify the `scenarios` array. Refer to the [official documentation](https://github.com/garris/BackstopJS) for details on the structure of the object.
In most cases, one will be testing entire pages instead of individual components. To reduce redundancy, helper functions were created with our default settings that will be applied to every URL in the `urls.js` file. To add a new URL, one would add an object like such:
```
{ label: 'Support', path: '/support' }
```
For unique cases that involve UI interaction, scripts linked to the `engine_scripts/puppeteer` directory can be used to simulate user interactions during tests. An example can be found with `countFeatureLinks.js`

56
docs/feature-flagging.md Normal file
View File

@@ -0,0 +1,56 @@
# Feature Flagging
## Using Environment Variables
This guide explains how to update cloud foundry envirionment variables to enable or disable feature flagging.
### Prerequisites
- Cloud Foundry CLI (`cf`) must be installed.
- Access to Cloud Foundry with the necessary credentials.
## Steps to Update
### 1. Log in to Cloud Foundry
```bash
cf login -a api.fr.cloud.gov --sso
```
### 2. Target Correct Space
This should be handled after authenticating but if not, you can target the spaces specifically
```
cf target -o gsa-tts-benefits-studio -s notify-sandbox
```
### 3. Set Environment Variable
```
cf set-env <APP_NAME> <ENV_VAR_NAME> <VALUE>
```
#### Example:
```
cf set-env notify-admin-sandbox FEATURE_BEST_PRACTICES_ENABLED true
```
### 4. Restage the Application
```
cf restage <APP_NAME>
```
#### Example:
```
cf restage notify-admin-sandbox
```
### 5. Update environment specific manifest file(s) and merge into source code
#### Example:
If demo environment had a feature flag flipped, then navigate to the demo.yml file and add appropriate value.

View File

@@ -100,7 +100,8 @@ To get involved, email us at [tts-benefits-studio@gsa.gov](mailto:tts-benefits-s
## Notify.gov Demo
https://github.com/GSA/notifications-admin/assets/6556888/b87e12a3-6963-4fab-8124-7d0d2bb59901
https://github.com/user-attachments/assets/e0bc4c61-6154-46b5-8b40-380ecd868b58

View File

@@ -5,8 +5,8 @@ const rollupPluginNodeResolve = require('@rollup/plugin-node-resolve');
const source = require('vinyl-source-stream');
const buffer = require('vinyl-buffer');
const gulpMerge = require('gulp-merge');
const uswds = require("@uswds/compile");
const uswds = require('@uswds/compile');
const { exec } = require('child_process');
const plugins = {};
plugins.addSrc = require('gulp-add-src');
plugins.babel = require('gulp-babel');
@@ -21,7 +21,7 @@ const paths = {
dist: 'app/static/',
npm: 'node_modules/',
toolkit: 'node_modules/govuk_frontend_toolkit/',
govuk_frontend: 'node_modules/govuk-frontend/'
govuk_frontend: 'node_modules/govuk-frontend/',
};
const javascripts = () => {
@@ -29,28 +29,30 @@ const javascripts = () => {
input: paths.src + 'javascripts/modules/all.mjs',
plugins: [
rollupPluginNodeResolve({
mainFields: ['module', 'main']
mainFields: ['module', 'main'],
}),
rollupPluginCommonjs({
include: 'node_modules/**'
})
include: 'node_modules/**',
}),
],
output: {
format: 'iife',
name: 'GOVUK'
}
name: 'GOVUK',
},
})
.pipe(source('all.mjs'))
.pipe(buffer())
.pipe(plugins.addSrc.prepend([
paths.npm + 'hogan.js/dist/hogan-3.0.2.js',
paths.npm + 'jquery/dist/jquery.min.js',
paths.npm + 'query-command-supported/dist/queryCommandSupported.min.js',
paths.npm + 'timeago/jquery.timeago.js',
paths.npm + 'textarea-caret/index.js',
paths.npm + 'cbor-js/cbor.js',
paths.npm + 'd3/dist/d3.min.js'
]));
.pipe(
plugins.addSrc.prepend([
paths.npm + 'hogan.js/dist/hogan-3.0.2.js',
paths.npm + 'jquery/dist/jquery.min.js',
paths.npm + 'query-command-supported/dist/queryCommandSupported.min.js',
paths.npm + 'timeago/jquery.timeago.js',
paths.npm + 'textarea-caret/index.js',
paths.npm + 'cbor-js/cbor.js',
paths.npm + 'd3/dist/d3.min.js',
])
);
const local = src([
paths.toolkit + 'javascripts/govuk/modules.js',
@@ -81,9 +83,11 @@ const javascripts = () => {
paths.src + 'javascripts/activityChart.js',
])
.pipe(plugins.prettyerror())
.pipe(plugins.babel({
presets: ['@babel/preset-env']
}));
.pipe(
plugins.babel({
presets: ['@babel/preset-env'],
})
);
return gulpMerge(vendored, local)
.pipe(plugins.uglify())
@@ -93,29 +97,34 @@ const javascripts = () => {
// Task to copy `gtm_head.js`
const copyGtmHead = () => {
return src(paths.src + 'js/gtm_head.js')
.pipe(dest(paths.dist + 'js/'));
return src(paths.src + 'js/gtm_head.js').pipe(dest(paths.dist + 'js/'));
};
// Task to copy `setTimezone.js`
const copySetTimezone = () => {
return src(paths.src + 'js/setTimezone.js')
.pipe(dest(paths.dist + 'js/'));
return src(paths.src + 'js/setTimezone.js').pipe(dest(paths.dist + 'js/'));
};
// Task to copy images
const copyImages = () => {
return src(paths.src + 'images/**/*', { encoding: false })
.pipe(dest(paths.dist + 'images/'));
return src(paths.src + 'images/**/*', { encoding: false }).pipe(
dest(paths.dist + 'images/')
);
};
// Task to pdf files
const copyPDF = () => {
return src(paths.src + 'pdf/**/*', { encoding: false }).pipe(
dest(paths.dist + 'pdf/')
);
};
// Configure USWDS paths
uswds.settings.version = 3;
uswds.paths.dist.css = paths.dist + 'css';
uswds.paths.dist.js = paths.dist + 'js';
uswds.paths.dist.img = paths.dist + 'img';
uswds.paths.dist.pdf = paths.dist + 'pdf';
uswds.paths.dist.fonts = paths.dist + 'fonts';
uswds.paths.dist.theme = paths.src + 'sass/uswds';
@@ -129,4 +138,41 @@ const copyAssets = async () => {
await uswds.copyAssets();
};
exports.default = series(styles, javascripts, copyGtmHead, copySetTimezone, copyImages, copyAssets);
// Optional backstopJS task
// Install gulp globally and run `gulp backstopTest`
const backstopTest = (done) => {
exec(
'npx backstop test --configPath=backstop.config.js',
(err, stdout, stderr) => {
console.log(stdout);
console.error(stderr);
done(err);
}
);
};
// Optional backstopJS reference task
// Install gulp globally and run `gulp backstopReference`
const backstopReference = (done) => {
exec(
'npx backstop reference --configPath=backstop.config.js',
(err, stdout, stderr) => {
console.log(stdout);
console.error(stderr);
done(err);
}
);
};
// Export tasks
exports.default = series(
styles,
javascripts,
copyGtmHead,
copySetTimezone,
copyImages,
copyPDF,
copyAssets
);
exports.backstopTest = backstopTest;
exports.backstopReference = backstopReference;

Some files were not shown because too many files have changed in this diff Show More