Compare commits

..

491 Commits

Author SHA1 Message Date
Andrew Shumway
98f3abeaac Add quotes to values in one off 2024-07-23 16:10:22 -06:00
Andrew Shumway
8a3bdd181d Pull main 2024-07-10 08:36:49 -06:00
Carlo Costino
3a2ba3a8c0 Merge pull request #1700 from GSA/update-python-deps-7-5-24
Update Python Dependencies - 7/5/2024
2024-07-05 15:44:12 -04:00
Andrew Shumway
a81dc83133 pull main 2024-07-05 09:07:08 -06:00
Carlo Costino
c80ec7e5fa Update Python Dependencies - 7/5/2024
This changeset updates several Python dependencies that Dependabot had flagged for updating.  It includes a few others that we are getting ahead of, as well.

Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2024-07-05 08:36:28 -04:00
Carlo Costino
ffd935c4b6 Merge pull request #1629 from GSA/1256-bug-tour-steps-needs-to-be-adjusted-for-the-new-preview-page
made changes/fixes to tour flow
2024-07-03 14:37:07 -04:00
Carlo Costino
28efb2716b Merge pull request #1618 from GSA/1612-add-in-new-endpoint-for-weekly-by-user_id
1612 add in new endpoint for week stats by user
2024-07-03 14:21:49 -04:00
Carlo Costino
bd3c6de002 Merge pull request #1691 from GSA/update-deps-7-2-24
Update Python dependencies - 7/2/2024
2024-07-03 11:12:22 -04:00
Beverly Nguyen
b8a4303a97 Merge branch 'main' into 1256-bug-tour-steps-needs-to-be-adjusted-for-the-new-preview-page 2024-07-02 16:02:29 -07:00
Beverly Nguyen
bd3e8e15c8 revised e2e 2024-07-02 15:55:10 -07:00
Carlo Costino
cc6f60353f Update Python dependencies - 7/2/2024
This changeset updates several Python dependencies that Dependabot had flagged for updates.

Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2024-07-02 17:36:12 -04:00
Carlo Costino
b96a2dc935 Merge pull request #1686 from GSA/1460-update-the-lodash-js-library
Removed package that seems to be unused that caused a security concern
2024-07-02 16:57:28 -04:00
alexjanousekGSA
feb879be53 Removed package that seems to be unused that caused a security concern 2024-07-02 10:49:09 -06:00
Carlo Costino
256626ca4f Merge pull request #1683 from GSA/debug_wash
more debug for user who can't send all messages
2024-07-02 11:37:07 -04:00
Kenneth Kehl
0c097c6592 more debug 2024-07-01 10:53:21 -07:00
Carlo Costino
068af5fccf Merge pull request #1680 from GSA/update-pr-template
Update pull request template
2024-07-01 11:45:00 -04:00
Carlo Costino
003d257589 Update pull request template
This changeset updates our pull request template to be much more streamlined and shifts most of the information to our documentation.  The PR template now links to the docs for folks who are new and unfamiliar with what we require in our pull requests so that the template itself just has the headings and quick outlines to get started more easily and quickly.

Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2024-06-28 17:23:07 -04:00
Carlo Costino
889d7ae4eb Merge pull request #1625 from GSA/notify-admin-1495
Upgrade Node.js to the latest stable release
2024-06-28 12:26:07 -04:00
Carlo Costino
1f42dbdd63 Merge branch 'main' into notify-admin-1495 2024-06-28 11:01:13 -04:00
Carlo Costino
b9b2495af1 Updated several other Python dependencies
Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2024-06-28 10:57:50 -04:00
Carlo Costino
137e2a5683 Updated the flake8 dependency and poetry.lock file
Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2024-06-28 10:49:00 -04:00
Carlo Costino
cc59404a8a Merge pull request #1670 from GSA/remove-old-redis
Removed old redis from terraform.
2024-06-27 11:23:59 -04:00
Cliff Hill
f051883a92 Removed old redis from terraform.
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2024-06-27 10:56:57 -04:00
Andrew Shumway
cc24604aa4 Pull main 2024-06-27 08:47:01 -06:00
Carlo Costino
8350620c76 Merge pull request #1667 from GSA/jskinne3-restore-redis-v70
Restore Redis instance at v7.0
2024-06-26 22:19:17 -04:00
John Skiles Skinner
e897800cb5 Restore v7.0 Redis at the correct plan name in Prod 2024-06-26 19:11:55 -07:00
Carlo Costino
6eeeaa6066 Merge pull request #1665 from GSA/jskinne3-update-deploy-paths
Update deploy paths
2024-06-26 21:55:01 -04:00
John Skiles Skinner
ea1dc14ab3 Add /** to paths in three deploy YAML files 2024-06-26 18:47:21 -07:00
Carlo Costino
89365cd405 Merge pull request #1663 from GSA/jskinne3-update-redis-plan-name
Temp switch manifest to old Redis name, delete new Redis block
2024-06-26 21:19:58 -04:00
John Skiles Skinner
3e258d3910 Temp remove new Redis, revert to old in Manifest 2024-06-26 18:13:13 -07:00
Beverly Nguyen
4fe3e54dd0 removed blank statements 2024-06-26 17:04:19 -07:00
Beverly Nguyen
abb011fcb6 removed print statements 2024-06-26 17:00:00 -07:00
Beverly Nguyen
83d3b1684f removed commented preview button 2024-06-26 16:59:12 -07:00
Beverly Nguyen
6e5ca94643 commented out get_by_text_ preview 2024-06-26 16:52:23 -07:00
Carlo Costino
bce751750d Merge pull request #1660 from GSA/jskinne3-yaml-indentation
Adjust indentation in deploy.yml
2024-06-26 18:50:44 -04:00
John Skiles Skinner
ece3bd201d Adjust indentation in deploy.yml 2024-06-26 15:44:01 -07:00
Carlo Costino
269ff8d2a2 Merge pull request #1659 from GSA/jskinne3-poke-terraform
Added null_resource technique previously used in API repo
2024-06-26 18:22:57 -04:00
John Skiles Skinner
789ca4cb1b Added null_resource technique previously used in API repo 2024-06-26 15:16:15 -07:00
Carlo Costino
c204a31ccc Merge pull request #1658 from GSA/jskinne3-manifest-update-redis-name
Update name of Redis to include v70
2024-06-26 18:04:23 -04:00
John Skiles Skinner
41d1a3e1b5 Update name of Redis to include v70 2024-06-26 14:51:20 -07:00
Carlo Costino
8f8e06db6f Merge pull request #1656 from GSA/readme-update
Updated readme to include instructions for adding login pem to .env file
2024-06-26 15:53:52 -04:00
Carlo Costino
54578b58ea Merge pull request #1605 from GSA/add-report-options
Add report options
2024-06-26 15:38:32 -04:00
alexjanousekGSA
18da813fe6 Updated readme 2024-06-26 11:08:20 -06:00
Andrew Shumway
e3a85aab0c Pull main 2024-06-26 08:34:47 -06:00
Andrew Shumway
f218c01244 Remove commented out code 2024-06-26 08:34:05 -06:00
Carlo Costino
d59960df44 Merge pull request #1650 from GSA/jskinne3-redis-upgrade-step-1
Redis upgrade step 1
2024-06-25 23:55:14 -04:00
John Skiles Skinner
ab48aea438 Merge branch 'main' into jskinne3-redis-upgrade-step-1 2024-06-25 20:46:27 -07:00
Carlo Costino
0974fdceb4 Merge pull request #1649 from GSA/jskinne3-get-sandbox-working
Version upgrades
2024-06-25 22:51:21 -04:00
John Skiles Skinner
f591ef21fc Upgrade tj-actions from v41 to v44 2024-06-25 15:19:49 -07:00
John Skiles Skinner
73b42b4abf Same new resource in Demo and Production envs 2024-06-25 15:05:58 -07:00
John Skiles Skinner
302a0f51f6 Redis v7 in sandbox and staging env main.tf 2024-06-25 14:59:12 -07:00
John Skiles Skinner
382c1910c9 Missed one 2024-06-25 14:25:32 -07:00
John Skiles Skinner
6095471166 Terraform minimum version upgrade 2024-06-25 14:24:31 -07:00
John Skiles Skinner
624e161292 Upgrade cloudfoundry to v0.53.1 to match api app 2024-06-25 14:18:14 -07:00
Andrew Shumway
7cfa00197e Pull main 2024-06-25 09:05:52 -06:00
Andrew Shumway
9685a4bd24 Remove code that shouldn't be in 2024-06-25 09:04:59 -06:00
Carlo Costino
b05678a095 Merge pull request #1609 from GSA/notify-admin-1456
Need magic PII-free debugging method for Admin
2024-06-25 09:52:12 -04:00
Beverly Nguyen
e72af9671b removed print 2024-06-24 16:54:31 -07:00
Beverly Nguyen
44baaf665a fixed testing 2024-06-24 15:33:48 -07:00
Beverly Nguyen
5028054034 Merge branch 'main' into 1256-bug-tour-steps-needs-to-be-adjusted-for-the-new-preview-page 2024-06-24 14:25:00 -07:00
Carlo Costino
a9de6be102 Merge pull request #1645 from GSA/increase-prod-memory
Increased production memory to 2 GB
2024-06-24 12:45:56 -04:00
Andrew Shumway
7027cae3de pull main 2024-06-24 10:45:33 -06:00
Andrew Shumway
a9e4df0591 Todays data is only todays 2024-06-24 10:44:19 -06:00
Carlo Costino
a887f3f527 Increased production memory to 2 GB
This changeset increases our memory for the API app and its corresponding workers to 2 GB each.

Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2024-06-24 12:07:28 -04:00
Carlo Costino
9c3c2ad9f8 Merge pull request #1643 from GSA/notify-admin-1642
fix gunicorn config
2024-06-24 10:26:00 -04:00
Kenneth Kehl
81dd764a54 fix gunicorn config 2024-06-21 09:22:20 -07:00
Kenneth Kehl
82aa564eb2 merge from main 2024-06-21 07:47:49 -07:00
Beverly Nguyen
fba6187fd9 Merge branch 'main' into 1612-add-in-new-endpoint-for-weekly-by-user_id 2024-06-20 19:37:43 -07:00
Beverly Nguyen
4b5c77f6c4 fixing flake8 error 2024-06-20 16:14:07 -07:00
Carlo Costino
144337e617 Merge pull request #1639 from GSA/pin_python_to_3_12_2
Pin Python to 3.13.3
2024-06-20 18:40:24 -04:00
Carlo Costino
31cd55725f Update runtime.txt to reference Python 3.12.3
Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2024-06-20 18:28:26 -04:00
Carlo Costino
96af45d1f9 Merge branch 'main' into pin_python_to_3_12_2 2024-06-20 18:27:49 -04:00
Carlo Costino
bf38e121c6 Merge pull request #1636 from GSA/fix_raw_set
fix raw set
2024-06-20 17:39:26 -04:00
Kenneth Kehl
3b6ccc031a fix format? 2024-06-20 13:16:45 -07:00
Kenneth Kehl
f890635f24 merge from main 2024-06-20 12:57:15 -07:00
Kenneth Kehl
87c3efd312 switch to 3.12.3 2024-06-20 12:37:11 -07:00
Carlo Costino
4f93757a1a Merge pull request #1633 from GSA/fix-python-runtime
Fix runtime.txt for cloud.gov and Python
2024-06-20 14:51:13 -04:00
Kenneth Kehl
7b5fdd41df fix raw set 2024-06-20 11:50:51 -07:00
Carlo Costino
27befe0806 Fix runtime.txt for cloud.gov and Python
This changeset updates the runtime.txt file to match the recent Python version pinning that we had to do to fix a dependency issue.

Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2024-06-20 14:32:19 -04:00
Carlo Costino
f0b95f3c81 Merge pull request #1599 from GSA/admin-1587_Logging_stuff
admin-1587: Adding some logging that hopefully might shed some light on things.
2024-06-20 14:20:17 -04:00
Carlo Costino
ac670ad60a Merge pull request #1632 from GSA/pin_python_to_3_12_2
pin python to 3.12.2
2024-06-20 14:08:56 -04:00
Kenneth Kehl
5429af16d4 pin python to 3.12.2 2024-06-20 10:45:22 -07:00
Beverly Nguyen
5e98ec396e made changes/fixes to tour flow 2024-06-19 13:59:39 -07:00
Beverly Nguyen
637f3d4b42 added fetch stats user to js 2024-06-19 10:03:12 -07:00
Kenneth Kehl
b126518940 update readme 2024-06-19 08:40:11 -07:00
Kenneth Kehl
ecbceb3b63 upgrade chokidar and mkdirp 2024-06-19 08:32:17 -07:00
Kenneth Kehl
aa02e65c1f revert upgrade of gulp 2024-06-18 11:25:05 -07:00
Kenneth Kehl
8f985f2429 update gulp to 5.0.0 2024-06-18 11:17:01 -07:00
Carlo Costino
e68aa60b42 Merge pull request #1624 from GSA/fix-npm-steps
Fix npm steps in make bootstrap
2024-06-18 14:09:44 -04:00
Beverly Nguyen
d54cfdd6c0 added utc time 2024-06-18 10:06:57 -07:00
Cliff Hill
56abd154c1 Now not revealing env var lengths.
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2024-06-18 12:57:22 -04:00
Cliff Hill
708af19697 Fixes.
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2024-06-18 12:57:22 -04:00
Cliff Hill
79bf8d1225 Better exception handling.
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2024-06-18 12:57:22 -04:00
Cliff Hill
f13898442c Reversing poetry.lock changes.
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2024-06-18 12:57:22 -04:00
Cliff Hill
cdf4a40591 Stuff was done.
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2024-06-18 12:57:22 -04:00
Cliff Hill
fbc51a2c0c Changest made to fix things.
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2024-06-18 12:57:21 -04:00
Cliff Hill
1a385c6346 More cleanup stuff.
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2024-06-18 12:57:21 -04:00
Cliff Hill
530206e33a Cleaning up the logging, gave some additional notes, removed hashing.
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2024-06-18 12:57:21 -04:00
Cliff Hill
9e94b5a242 saabling CSRF in dev because it breaks all the tests.
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2024-06-18 12:57:21 -04:00
Cliff Hill
ec9a36e0dd Activating CSRF for staging/demo/dev environments.
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2024-06-18 12:57:21 -04:00
Cliff Hill
f539cad4b4 Added some logging up front when the app is initialized to see if
DANGEROUS_SALT and SECRET_KEY are both available and have data in them.

Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2024-06-18 12:57:21 -04:00
Beverly Nguyen
e26324638a Merge branch 'main' into 1612-add-in-new-endpoint-for-weekly-by-user_id 2024-06-18 09:50:50 -07:00
Kenneth Kehl
7f1f97a60b move to 22 2024-06-18 09:16:25 -07:00
Kenneth Kehl
9469b6a138 upgrade to 20 2024-06-18 08:53:25 -07:00
Kenneth Kehl
388cb1796a move to node 18.20.3 2024-06-18 07:59:07 -07:00
Kenneth Kehl
f000fa0ff3 merge from main 2024-06-18 07:50:35 -07:00
Kenneth Kehl
b1624c25dc more updated 2024-06-18 07:49:20 -07:00
Carlo Costino
b26c3a78b8 Fix npm steps in make bootstrap
This changeset fixes the order of steps in the make bootstrap command so npm does not fail.

Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2024-06-18 10:21:23 -04:00
Carlo Costino
17bafd74e3 Merge pull request #1619 from GSA/notify-admin-1495
initial
2024-06-17 23:58:16 -04:00
Carlo Costino
59b0325124 Adjust npm install line and update Python dependencies
The npm install line needs to be run within the context of the nvm-managed Node.js and should happen after that environment is initialized but before the build step.  This also adds a couple more Python dependency updates that Dependabot flagged as well.

Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2024-06-17 23:46:59 -04:00
Beverly Nguyen
6ae2f5b3f1 fixed lint in js 2024-06-17 17:46:43 -07:00
Beverly Nguyen
30a3c9ce73 merge main 2024-06-17 17:39:57 -07:00
Beverly Nguyen
71901f4912 comment out mychart 2024-06-17 17:34:37 -07:00
Beverly Nguyen
a1f2deda8f added test_fetch_daily_stats_by_user test 2024-06-17 17:32:24 -07:00
Kenneth Kehl
daa75c56d9 edit package lock 2024-06-17 16:04:29 -07:00
Kenneth Kehl
3674dd4e4d edit package lock 2024-06-17 15:08:31 -07:00
Kenneth Kehl
9817f9e434 revert gulp 2024-06-17 14:41:31 -07:00
Kenneth Kehl
00ab6f5122 hmm 2024-06-17 14:36:06 -07:00
Kenneth Kehl
5544400212 fix vulnerability 2024-06-17 14:27:59 -07:00
Kenneth Kehl
c491b4152c initial 2024-06-17 13:55:25 -07:00
Beverly Nguyen
fc7500932b added daily stats by user to js 2024-06-17 12:39:08 -07:00
Beverly Nguyen
3594694de2 added fetch by user 2024-06-17 12:36:21 -07:00
Kenneth Kehl
7e533731ed fix flake 8 2024-06-17 11:40:13 -07:00
Kenneth Kehl
16ad4a6c0c revamp PII masking 2024-06-17 11:13:03 -07:00
Carlo Costino
e426449a38 Merge pull request #1611 from GSA/notify-admin-740
update gunicorn config
2024-06-14 17:12:23 -04:00
Carlo Costino
ddaec17034 Merge pull request #1600 from GSA/notify-admin-1457
fix set and get in redis_client
2024-06-14 16:49:25 -04:00
Kenneth Kehl
c3ae47e7f9 merge from main 2024-06-14 12:50:15 -07:00
Steven Reilly
0a56941bb9 Merge pull request #1607 from GSA/1546-remove-effective-april-16-login-landing-page
Remove "Effective April 16" Login Landing Page
2024-06-14 15:28:13 -04:00
Steven Reilly
60256c0cba Merge pull request #1617 from GSA/update-deps-6-14-24
Updated dependencies - 6/14/2024
2024-06-14 10:36:27 -04:00
Carlo Costino
79df8288df Updated dependencies - 6/14/2024
This changeset updates Python dependencies that Dependabot has flagged in addition to several others that were due for updates.  It also reformats a test file via black.

Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2024-06-14 10:22:01 -04:00
Beverly Nguyen
b5623ca96b updated css 2024-06-13 12:10:22 -07:00
Kenneth Kehl
4e8e1acb5b fix email masking algorithm 2024-06-13 10:17:47 -07:00
Andrew Shumway
ea8cfbdadb poetry lock 2024-06-13 10:43:46 -06:00
Beverly Nguyen
0fa6e59a49 fetch notification stats by user 2024-06-12 14:32:25 -07:00
Kenneth Kehl
51a9dfdfd2 update gunicorn config 2024-06-12 13:42:04 -07:00
Kenneth Kehl
f6f99b6124 fix bug where only exception is passed to logger 2024-06-12 10:20:06 -07:00
Andrew Shumway
d1ed7e1d0c Pull main 2024-06-12 09:29:37 -06:00
Beverly Nguyen
d028beda4f Removed comments 2024-06-11 16:29:31 -07:00
Beverly Nguyen
6be4f878e4 fixed end2end 2024-06-11 16:22:38 -07:00
Beverly Nguyen
5147072621 fixed e2e test 2024-06-11 15:46:36 -07:00
Beverly Nguyen
c8fb1b2f91 fixed import errors 2024-06-11 15:28:46 -07:00
Beverly Nguyen
53c938ebc6 fixed css 2024-06-11 15:12:05 -07:00
Beverly Nguyen
7b8db70552 fixed testing 2024-06-11 14:01:40 -07:00
Beverly Nguyen
cfa31af652 fixed testing 2024-06-11 13:38:26 -07:00
Kenneth Kehl
096658ab75 Need magic PII-free debugging method for Admin 2024-06-11 13:24:05 -07:00
Beverly Nguyen
89bd835cd8 update testing 2024-06-11 12:35:59 -07:00
Beverly Nguyen
8407f5605b add back signin.html and removed login banner 2024-06-11 11:06:13 -07:00
Beverly Nguyen
ed0f5a7b9e removed old login announcement page and added new sign in button 2024-06-10 16:05:59 -07:00
Andrew Shumway
35e27ff25a Merge main 2024-06-10 10:44:09 -06:00
Andrew Shumway
a401562735 Add report options 1/3/5-day 2024-06-10 10:15:22 -06:00
Carlo Costino
749935e94d Merge pull request #1595 from GSA/notify-admin-1588
Add debug for admin #1588
2024-06-08 00:44:55 -04:00
Carlo Costino
9f9614d292 Merge pull request #1596 from GSA/1305-delivery-status-content-update
Delivery status content updates
2024-06-08 00:33:34 -04:00
Kenneth Kehl
da96edbfcd fix set and get in redis_client 2024-06-07 09:07:42 -07:00
Kenneth Kehl
63bd660403 code review feedback 2024-06-07 08:03:43 -07:00
Carlo Costino
4321e31377 Merge pull request #1558 from GSA/socketIO
Installing socketIO and connecting new dashboard API endpoints
2024-06-06 17:44:58 -04:00
Beverly Nguyen
33f8f4c000 fix import sort 2024-06-06 10:50:24 -07:00
Jonathan Bobel
934f8927c6 Updated content, removed test no longer needed 2024-06-06 13:50:08 -04:00
Kenneth Kehl
83f5b6f0ab add comment 2024-06-06 10:43:41 -07:00
Beverly Nguyen
c0b2c42473 removed imported unused style issue 2024-06-06 10:42:49 -07:00
Beverly Nguyen
e413f8c640 added sampleChartDashboard.js 2024-06-06 10:05:36 -07:00
Beverly Nguyen
f98cff8d40 fixed linting issues 2024-06-06 10:01:58 -07:00
Kenneth Kehl
adc89a8326 merge from main 2024-06-06 09:35:07 -07:00
Kenneth Kehl
82690d6e3d add debug for user issue 2024-06-06 09:34:49 -07:00
Beverly Nguyen
ae7a14f3f2 fixed js chart referenced 2024-06-06 01:10:09 -07:00
Beverly Nguyen
61253963f7 added socketiotestclent 2024-06-06 00:48:08 -07:00
Beverly Nguyen
9d3dc047ea added chartjs to path in gulp 2024-06-05 15:03:19 -07:00
Beverly Nguyen
e5a9eed626 installing socketio 2024-06-05 14:56:22 -07:00
Carlo Costino
834c6df7dc Merge pull request #1593 from GSA/update-deps-6-5-24
Update Python dependencies - 6/5/2024
2024-06-05 17:03:20 -04:00
Carlo Costino
43d67a4821 Update Python dependencies - 6/5/2024
This changeset updates several Python dependencies flagged by Dependabot.

Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2024-06-05 16:55:17 -04:00
Beverly Nguyen
fed2aff43c cleaned up code 2024-06-04 16:52:32 -07:00
Beverly Nguyen
0a4cf290ac added flask-socketio 2024-06-04 16:33:55 -07:00
Beverly Nguyen
fec6c2ff72 removed comments 2024-06-04 16:27:35 -07:00
Beverly Nguyen
7a9d260717 fix testing 2024-06-03 15:34:43 -07:00
Andrew Shumway
f9169fcbcb poetry lock 2024-06-03 15:55:37 -06:00
Carlo Costino
44a3c9a13b Merge pull request #1585 from GSA/update-deps-6-3-24
Update Python dependencies - 6/3/24
2024-06-03 17:31:23 -04:00
Beverly Nguyen
8554df58f8 cleared up style checks 2024-06-03 13:51:59 -07:00
Beverly Nguyen
d3bee61742 cleared up style checks 2024-06-03 13:45:36 -07:00
Beverly Nguyen
89f19bb63d cleared up style checks 2024-06-03 13:35:30 -07:00
Beverly Nguyen
d12b798bba removed sending status 2024-06-03 13:17:31 -07:00
Beverly Nguyen
2e41b752f5 Remove .ds.baseline from repository 2024-06-03 12:50:05 -07:00
Beverly Nguyen
72e82c818b added socket.io.min.js 2024-06-03 11:39:02 -07:00
Beverly Nguyen
4ebd5734d6 removed socket.js 2024-06-03 11:32:56 -07:00
Beverly Nguyen
8152985f9b Merge branch 'main' into socketIO 2024-06-03 09:52:41 -07:00
Carlo Costino
f0fcb8f21d Update Python dependencies - 6/3/24
This changeset updates several Python dependencies to stay on top of Dependabot alerts.

Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2024-06-03 11:03:29 -04:00
Carlo Costino
37546dd7d4 Merge pull request #1582 from GSA/invalidate-cancelled-service-invites
Update expired and cancelled service invite handling
2024-06-03 10:54:33 -04:00
Carlo Costino
f6cf493266 Update expired and cancelled service invite handling
This changeset adds a bit of extra handling for expired and cancelled service invites so that users can no longer accept them and are provided with more detailed error messages.

Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2024-05-31 17:20:08 -04:00
Carlo Costino
5fa2e77a71 Merge pull request #1570 from GSA/notify-admin-1041
use moto to mock s3
2024-05-31 16:12:06 -04:00
Carlo Costino
7bc8e64f36 Merge pull request #1555 from GSA/notify-admin-1545b
Admin: Use Vulture to identify potentially unused code
2024-05-31 15:57:25 -04:00
Kenneth Kehl
29dbe45cbe code review feedback 2024-05-31 11:27:39 -07:00
Kenneth Kehl
5f92f9a95d merge from main 2024-05-31 09:54:52 -07:00
Carlo Costino
42912bbbc4 Merge pull request #1581 from GSA/update-deps-05-31-24
Update dependencies and fix E2E test
2024-05-31 12:48:09 -04:00
Kenneth Kehl
2414b09c0f fix flake8 2024-05-31 09:47:19 -07:00
Kenneth Kehl
2f366ff65c code review feedback 2024-05-31 09:41:36 -07:00
Carlo Costino
8c85d99449 Update dependencies and fix E2E test
This changeset updates a couple of dependencies flagged by Dependabot and fixes an end-to-end test that needed to be updated with the one-off send filename changes.

Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2024-05-31 12:09:22 -04:00
Kenneth Kehl
a834166f41 merge from main 2024-05-31 08:56:11 -07:00
Andrew Shumway
17b21b2382 Pull main 2024-05-31 09:27:42 -06:00
Carlo Costino
fc29871b57 Merge pull request #1560 from GSA/terrazoon-patch-1
Look into enabling Dependabot Code Scanning for our API and admin repos
2024-05-31 10:39:58 -04:00
Carlo Costino
56d21ecbcd Merge pull request #1554 from GSA/500-pricing-content-updates
500 - Updating "Pricing" page content
2024-05-31 10:34:11 -04:00
Carlo Costino
8a6637075e Merge pull request #1552 from GSA/notify-admin-1545
change vulture rules in Makefile
2024-05-31 10:32:56 -04:00
Carlo Costino
2fdc8e7e64 Merge pull request #1530 from GSA/notify-admin-1481
add check for government email addresses
2024-05-31 10:30:31 -04:00
Carlo Costino
67523fb535 Merge pull request #1502 from GSA/1405-bug-long-complicated-csv-name
Updated filename string into db for a notification and UI display
2024-05-31 10:29:16 -04:00
Carlo Costino
4bf6af4e45 Merge pull request #1480 from GSA/1464-switch-to-the-new-withnav_template
Switch to the new withnav_template
2024-05-31 10:28:01 -04:00
Beverly Nguyen
6c44982a5e removed socket.js 2024-05-30 21:20:09 -07:00
Beverly Nguyen
01321aeddc connecting api data to socket and setting up chartjs to use the data 2024-05-30 21:17:10 -07:00
Beverly Nguyen
d5934855a0 Merge branch '1513-provide-notification-stats-data-within-7-days-month-and-year' into socketIO 2024-05-30 14:51:23 -07:00
Beverly Nguyen
108e889ac5 added example of fetch 2024-05-30 14:48:25 -07:00
Kenneth Kehl
2332744cdf merge from main 2024-05-30 08:32:19 -07:00
Kenneth Kehl
a4fc04a659 test that S3 not getting hit in tests 2024-05-30 08:25:00 -07:00
Kenneth Kehl
df032ba76d remove mock_aws where its not useful 2024-05-30 07:58:30 -07:00
Carlo Costino
5508796779 Merge pull request #1577 from GSA/update-deps-05-29-24
Update admin repo dependencies
2024-05-30 09:05:53 -04:00
Carlo Costino
43b99a5905 Update admin repo dependencies
This changeset updates several Python dependencies that Dependabot flagged for updates due to end-to-end tests still failing in Dependabot PRs.

Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2024-05-29 19:40:02 -04:00
Kenneth Kehl
e694b9a5f6 clean up mock_s3_download 2024-05-29 14:49:06 -07:00
Kenneth Kehl
9368f6a496 remove some fixtures 2024-05-29 14:18:08 -07:00
Beverly Nguyen
758c1cd8a0 added new api for month, by year, previous 7 day stats 2024-05-29 12:13:09 -07:00
Andrew Shumway
8e6b3fa39e Poetry lock 2024-05-29 10:15:11 -06:00
Andrew Shumway
91bb6d254f Pull main 2024-05-29 10:09:02 -06:00
Carlo Costino
502b65aaeb Merge pull request #1569 from GSA/update-admin-deps
Update Python dependencies
2024-05-28 21:16:47 -04:00
Carlo Costino
548b7cd3a2 Updated boto3 and botocore again
Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2024-05-28 17:52:29 -04:00
Kenneth Kehl
17fec1c99e use moto to mock s3 2024-05-28 11:27:57 -07:00
Carlo Costino
1c1918ba52 Update Python dependencies
This changeset updates a few Python dependencies the week of May 28th to help keep our project up-to-date.

Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2024-05-28 12:11:53 -04:00
Kenneth Kehl
be4b1d558d merge from main 2024-05-24 08:59:03 -07:00
Kenneth Kehl
f939687283 merge 2024-05-24 08:58:47 -07:00
Kenneth Kehl
6494f44c43 merge from main 2024-05-24 08:23:21 -07:00
Steven Reilly
184d181e15 Merge pull request #1553 from GSA/update-pre-commit-hooks
Update pre-commit hooks
2024-05-24 10:54:18 -04:00
Carlo Costino
408b00c697 Removed duplicate pre-commit hook
Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2024-05-24 10:36:32 -04:00
Carlo Costino
fe836f2d3d Updated several other dependencies
This includes requests to take care of a Dependabot security alert.

Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2024-05-24 10:22:59 -04:00
Kenneth Kehl
626f4a1ac0 Create codeql.yml 2024-05-21 07:47:12 -07:00
Kenneth Kehl
16dc4512dd fix si.edu 2024-05-21 07:38:23 -07:00
Beverly Nguyen
ad68c26450 installing socketIO and testing the WebSocket connection 2024-05-20 16:21:38 -07:00
Kenneth Kehl
622255e5a6 merges 2024-05-20 13:19:14 -07:00
Kenneth Kehl
7a1ab19583 merge 2024-05-20 12:11:09 -07:00
Kenneth Kehl
9ba5e3b917 code review feedback 2024-05-20 12:09:49 -07:00
Kenneth Kehl
c790921141 Update app/main/views/sign_in.py
Co-authored-by: Carlo Costino <ccostino@users.noreply.github.com>
2024-05-20 11:24:39 -07:00
Kenneth Kehl
309c168f52 revert back to 100% confidence level for vulture and add a comment 2024-05-20 11:18:31 -07:00
Kenneth Kehl
9916632187 set confidence back to 100% here. The 60% confidence is handled in a different PR 2024-05-20 10:55:26 -07:00
Kenneth Kehl
d045ecfa21 remove easy targets 2024-05-20 10:45:34 -07:00
Carlo Costino
210e8b5a33 This changeset updates our pre-commit hooks to help check for things in our code before we commit anything, such as code format and structure as well as sensitive information and credentials.
Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2024-05-20 12:04:25 -04:00
Jonathan Bobel
2c18786486 500 - Updating "Pricing" page content 2024-05-20 11:51:09 -04:00
Kenneth Kehl
5bc652db9e change vulture rules in Makefile 2024-05-20 07:13:19 -07:00
Steven Reilly
8e0724effa Merge pull request #1548 from GSA/fix-utils-deps
Add missing dependencies
2024-05-20 09:34:51 -04:00
Beverly Nguyen
d739324d57 moved flash_message 2024-05-17 15:17:25 -07:00
Carlo Costino
3caf1e1631 Merge pull request #1539 from GSA/testing-chart.js
Installing chart.js
2024-05-17 18:16:28 -04:00
Carlo Costino
6ce5856f3b Add missing dependencies
The merging of notifications_utils to this repo does not deploy because of missing dependencies.  This changeset adds them back in directly.

Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2024-05-17 18:13:09 -04:00
Beverly Nguyen
868edd3c28 Merge branch 'main' into 1464-switch-to-the-new-withnav_template 2024-05-17 15:12:36 -07:00
Beverly Nguyen
f91756d2c3 moved script to base.html 2024-05-17 15:07:05 -07:00
Carlo Costino
1b6741d0e5 Merge pull request #1543 from GSA/notify-admin-1396
Exception Investigation: app.notify_client:InviteTokenError
2024-05-17 17:43:06 -04:00
Carlo Costino
fe9e25ba6f Merge pull request #1542 from GSA/add-utils
Localize notification_utils to the admin
2024-05-17 17:26:58 -04:00
Carlo Costino
aa175aa4be Removing empty test file.
Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2024-05-17 17:15:33 -04:00
Carlo Costino
6f59cff0c4 Merge pull request #1547 from GSA/admin-1534
[ADMIN-1534] API Research - Allowance Count Down
2024-05-17 16:25:37 -04:00
Kenneth Kehl
33d402f9b9 noqa the last one 2024-05-17 12:36:42 -07:00
Beverly Nguyen
90d3dde6b5 Merge branch 'main' into testing-chart.js 2024-05-17 11:26:45 -07:00
Beverly Nguyen
ff1b60cc89 Merge branch 'main' into 1464-switch-to-the-new-withnav_template 2024-05-17 11:20:55 -07:00
Beverly Nguyen
68168a85a1 Merge branch 'main' into testing-chart.js 2024-05-17 11:14:14 -07:00
Carlo Costino
3a42aafad2 Merge pull request #1470 from GSA/1463-convert-basehtml-template-to-become-the-new-main-template
Switch to the new base.html template
2024-05-17 14:11:04 -04:00
Kenneth Kehl
ec6bdee427 almost done 2024-05-17 11:05:22 -07:00
Kenneth Kehl
1b172553f5 more fixes 2024-05-17 10:25:09 -07:00
Cliff Hill
a0e17816e6 Added documentation of findings.
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2024-05-17 12:41:30 -04:00
Kenneth Kehl
7302e4c811 more fixes 2024-05-17 08:52:23 -07:00
Kenneth Kehl
dcfc78d805 some fixes 2024-05-16 15:13:45 -07:00
Kenneth Kehl
e660541e9c Exception Investigation: app.notify_client:InviteTokenError 2024-05-16 09:11:11 -07:00
Carlo Costino
9a83ba7475 Localize notification_utils to the admin
This changeset pulls in all of the notification_utils code directly into the admin and removes it as an external dependency. We are doing this to cut down on operational maintenance of the project and will begin removing parts of it no longer needed for the admin.

Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2024-05-16 10:37:37 -04:00
Beverly Nguyen
7ff0cec147 installing chart.js via npm 2024-05-15 15:43:49 -07:00
Beverly Nguyen
d4a46ae552 installing chart.js via npm 2024-05-15 15:40:15 -07:00
Beverly Nguyen
6855a6ebe4 installing chart.js via npm 2024-05-15 15:35:39 -07:00
Beverly Nguyen
5546de66c4 testing chart plain vanilla 2024-05-15 11:39:03 -07:00
Carlo Costino
6bab682edd Merge pull request #1538 from GSA/973-update-config-for-cloud-gov
Updated config files to split the cloud foundry and public admin routes
2024-05-15 09:58:09 -04:00
Anastasia Gradova
e91723fc26 Updated config files to split the cloud foundry
route and the public admin route
2024-05-14 18:45:50 -06:00
Carlo Costino
b3a401a4c7 Merge pull request #1537 from GSA/update-deps-05-14-24
Update dependencies (05/14/2024)
2024-05-14 15:53:24 -04:00
Carlo Costino
d484c3636b Update dependencies (05/14/2024)
This changeset updates several dependencies flagged by Dependabot that we cannot merge directly due to the E2E test issue.

Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2024-05-14 15:42:08 -04:00
Kenneth Kehl
d47f9933d2 add check for government email addresses 2024-05-13 13:39:51 -07:00
Carlo Costino
b5c7a71215 Merge pull request #1523 from GSA/notify-admin-1501
Users are still asked to complete their profile when attempting to accept an invite for someone else
2024-05-10 17:28:43 -04:00
Andrew Shumway
8a6802be8f pull main 2024-05-10 10:42:32 -06:00
Carlo Costino
b6b0909664 Merge pull request #1521 from GSA/notify-admin-1518
explain how to create a first user in the db
2024-05-10 10:54:35 -04:00
Kenneth Kehl
e973c11d3b write new tests 2024-05-10 07:52:07 -07:00
Kenneth Kehl
c578175e53 write new tests 2024-05-10 07:51:32 -07:00
Carlo Costino
8dd9cf39bc Merge pull request #1522 from GSA/notify-admin-1504
remove debug statement
2024-05-10 10:42:08 -04:00
Kenneth Kehl
11beff2541 get it working 2024-05-09 14:04:30 -07:00
Kenneth Kehl
7f72599401 notify-admin-1501 2024-05-09 13:08:34 -07:00
Kenneth Kehl
85ddd494b3 remove debug statement 2024-05-09 07:33:26 -07:00
Carlo Costino
37c57cb75e Merge pull request #1512 from GSA/notify-admin-1459
Refactor the remaining pieces of the sign-in process
2024-05-08 20:26:14 -04:00
Kenneth Kehl
26988d255f remove logged_in_elsewhere as per code review feedback 2024-05-08 12:45:01 -07:00
Kenneth Kehl
852c0e57c8 convert to test fixture 2024-05-08 11:30:51 -07:00
Kenneth Kehl
e51517347f convert to test fixture 2024-05-08 11:06:10 -07:00
Kenneth Kehl
b79835dfd2 code review feedback 2024-05-08 09:10:41 -07:00
Kenneth Kehl
87a0204fe2 explain how to create a first user in the db 2024-05-08 08:36:39 -07:00
Andrew Shumway
5506da56e2 poetry lock 2024-05-08 09:05:27 -06:00
Andrew Shumway
cdd71fa07d pull down main 2024-05-08 09:03:24 -06:00
Kenneth Kehl
1d9457f9a2 add debug statements 2024-05-07 14:36:21 -07:00
Kenneth Kehl
9c40a10900 cleanup 2024-05-07 13:58:59 -07:00
Carlo Costino
be177726ee Merge pull request #1517 from GSA/dep-updates
Update several dependencies from Dependabot
2024-05-07 16:09:18 -04:00
Kenneth Kehl
64aa45dcaa remove commented out code 2024-05-07 12:37:04 -07:00
Kenneth Kehl
125ad7a2f7 remove logged in elsewhere check 2024-05-07 11:11:12 -07:00
Carlo Costino
39b0a4ff52 Update several dependencies from Dependabot
This changeset updates a few dependencies that Dependabot flagged for updates. We cannot merge the Dependabot PRs at the moment due to E2E test compatability issues.

Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2024-05-07 09:56:34 -04:00
Beverly Nguyen
93d7ca4052 added pending and requested status to monthly stats dict 2024-05-06 17:23:38 -07:00
Kenneth Kehl
78e8dc95fe fix tests 2024-05-06 13:12:27 -07:00
Kenneth Kehl
0b30c9a83f merge from main 2024-05-06 12:15:57 -07:00
Carlo Costino
0de950d2a4 Merge pull request #1511 from GSA/flask-dep-updates
Updating several dependencies related to Flask upgrade
2024-05-06 15:01:21 -04:00
Kenneth Kehl
9ecbfb7e05 notify-admin-1459 2024-05-06 10:43:01 -07:00
Carlo Costino
5fe35b4497 Updating several dependencies related to Flask upgrade
Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2024-05-06 13:02:02 -04:00
Carlo Costino
c100f1cd25 Merge pull request #1387 from GSA/notify-admin-flask
flask upgrade
2024-05-06 11:28:56 -04:00
Carlo Costino
580cdf8fad Merge branch 'main' into notify-admin-flask 2024-05-03 15:07:11 -04:00
Carlo Costino
a6b0a8df90 Merge pull request #1506 from GSA/1334-add-information-landing-page
1334 - Updating content for Eligible partners
2024-05-03 15:06:11 -04:00
Beverly Nguyen
065f1b7c15 removed comments on base.html 2024-05-03 10:58:06 -07:00
Jonathan Bobel
fb66531c44 1334 - Updating content for Eligible partners 2024-05-03 12:10:59 -04:00
Anastasia Gradova
5f531f1f78 Updated filename string into db and UI display 2024-05-02 12:53:27 -06:00
Andrew Shumway
7108c5f1c8 pull main down 2024-04-30 10:06:49 -06:00
Carlo Costino
78ba8a5fc1 Merge branch 'main' into notify-admin-flask 2024-04-29 18:23:05 -04:00
Carlo Costino
a378a58686 Merge pull request #1497 from GSA/Remove/Clean-up-send_notification-redirect
cleaned up and removed from_job and notification_id from redirect
2024-04-29 18:22:27 -04:00
Beverly Nguyen
83481a8b28 cleaned up and removed from_job and notification_id from redirect, no longer needed 2024-04-29 14:25:13 -07:00
Carlo Costino
5dc23947e2 Updated utils to 0.5.1 release in prep for Flask upgrade
Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2024-04-29 15:44:33 -04:00
Carlo Costino
4b37d81c16 Merge branch 'main' into notify-admin-flask 2024-04-29 15:43:12 -04:00
Andrew Shumway
65899f6171 poetry lock 2024-04-26 10:15:44 -06:00
Andrew Shumway
bd633ddc98 Merge branch 'main' of https://github.com/GSA/notifications-admin 2024-04-25 15:27:31 -06:00
Carlo Costino
82279eb357 Merge pull request #1479 from GSA/fix_service_invites
fix service invites
2024-04-25 17:07:12 -04:00
Kenneth Kehl
f0f0661f2a Update app/main/views/register.py
Co-authored-by: Carlo Costino <ccostino@users.noreply.github.com>
2024-04-25 14:00:28 -07:00
Kenneth Kehl
4818b7ce14 code review feedback 2024-04-25 13:48:14 -07:00
Kenneth Kehl
84180fd8e1 Update app/main/views/register.py
Co-authored-by: Carlo Costino <ccostino@users.noreply.github.com>
2024-04-25 13:39:21 -07:00
Beverly Nguyen
8366a4c772 fix testing 2024-04-24 16:12:54 -07:00
Beverly Nguyen
f734e45242 added comments 2024-04-24 13:56:07 -07:00
Beverly Nguyen
04f1f6244c fixed file name 2024-04-24 13:53:28 -07:00
Beverly Nguyen
3b82e136e0 switched to withnav_template for org_template, settings template 2024-04-24 13:43:17 -07:00
Beverly Nguyen
bc945c9420 replaced content_tempalte and withoutnav_template with base.html 2024-04-24 12:31:00 -07:00
samathad2023
2bcad264b8 urllib3 update 2024-04-24 12:11:33 -07:00
Kenneth Kehl
f7fe270171 fix service invites 2024-04-24 11:20:17 -07:00
Andrew Shumway
ff1956ce70 Merge branch 'main' of https://github.com/GSA/notifications-admin 2024-04-24 09:29:58 -06:00
Carlo Costino
0d04347ffd Merge pull request #1473 from GSA/remove-e2e-env-vars-from-manifest
Remove E2E environment variables from the manifest
2024-04-23 19:51:26 -04:00
Carlo Costino
f5f5d0359c Remove E2E environment variables from the manifest
This changeset removes the E2E environment variables from the admin manifest file.  While these might be needed on the API side to ensure that they are exposed and able to be used in the staging environment, we do not need them to be enabled for the admin app; they should only be present in the GitHub Actions that are run in a PR, and the .github/workflows/checks.yml file takes care of that and injects them directly into the container environment that the end-to-end tests run in.

Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2024-04-23 19:43:56 -04:00
Beverly Nguyen
2c0a4f16f2 fixed testing 2024-04-23 16:23:31 -07:00
Beverly Nguyen
d47fbb8eb7 switched base.html in 2024-04-23 14:58:44 -07:00
Carlo Costino
27117d8983 Merge pull request #1466 from GSA/1155-remove-expired-invites
Removed canceled users from displaying in dashboard
2024-04-23 12:44:59 -04:00
Anastasia Gradova
682a798dcd Updated test cases for canceled users 2024-04-22 16:09:25 -06:00
Anastasia Gradova
dc97170956 Removed canceled users from displaying in
dashboard
2024-04-22 14:00:29 -06:00
Andrew Shumway
98f12980ad poetry lock 2024-04-22 10:48:46 -06:00
Andrew Shumway
2d3dbbc532 Merge branch 'main' of https://github.com/GSA/notifications-admin 2024-04-22 10:44:17 -06:00
Carlo Costino
c9e5e2451d Merge pull request #1462 from GSA/notify-admin-1447
fix service invite flow and skip tests for now
2024-04-22 12:27:21 -04:00
Kenneth Kehl
410256821e remove misleading comment 2024-04-19 14:39:52 -07:00
Kenneth Kehl
fe7ad71edf remove need to double down on json.loads 2024-04-19 14:11:32 -07:00
Kenneth Kehl
5b97f33831 fix flow and skip tests for now 2024-04-19 13:53:32 -07:00
Carlo Costino
dc24391d31 Merge pull request #1418 from GSA/1416-combine-withnav_templatehtml-and-org_templatehtml
revised withnav_templates to include org_template
2024-04-19 16:51:27 -04:00
Carlo Costino
8e7cc19bfb Merge pull request #1435 from GSA/e2e-test-invite-to-service
E2e test invite to service
2024-04-19 16:39:32 -04:00
Carlo Costino
76e8487213 Merge pull request #1433 from GSA/notify-admin-1157a
add e2e variables to manifest
2024-04-19 16:21:10 -04:00
Andrew Shumway
4d015eb2c1 format 2024-04-19 13:56:59 -06:00
Andrew Shumway
96f3e231d7 format 2024-04-19 13:52:45 -06:00
Andrew Shumway
c5e103338d Merge branch 'main' of https://github.com/GSA/notifications-admin into e2e-test-invite-to-service 2024-04-19 13:10:26 -06:00
Andrew Shumway
a748159d22 Remove steps to pass in github 2024-04-19 13:10:09 -06:00
Carlo Costino
fc4dc0dda0 Merge pull request #1458 from GSA/more-dep-updates
Update exceptiongroup and newrelic packages
2024-04-19 14:53:52 -04:00
Carlo Costino
dd0070209e Update exceptiongroup and newrelic packages
This changeset updates the exceptiongroup and newrelic packages due to the Dependabot E2E test failures

Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2024-04-19 14:43:51 -04:00
Carlo Costino
907619cc7d Merge pull request #1452 from GSA/1442-bug-adjust-emailpassword-settings-to-reflect-logingov
Bug: Adjust email/password Settings to reflect Login.gov
2024-04-19 14:36:51 -04:00
Beverly Nguyen
360ebba45d fixed testing 2024-04-19 11:26:36 -07:00
Carlo Costino
3815e62a2a Merge pull request #1455 from GSA/notify-admin-1447
add debug to see why invited user is not added to service
2024-04-19 11:33:26 -04:00
Kenneth Kehl
1ba6d200ee fix typo 2024-04-19 08:18:21 -07:00
Kenneth Kehl
41e72a4b17 add debug 2024-04-19 07:55:45 -07:00
Kenneth Kehl
e8c3870cab add debug 2024-04-19 07:51:18 -07:00
Andrew Shumway
a5fe85d54e Remove extra code 2024-04-19 08:44:34 -06:00
Beverly Nguyen
e176af10c8 content changes to reflect Login.gov 2024-04-18 16:06:05 -07:00
Beverly Nguyen
0ae3b66f5d reorganized org templates and styling 2024-04-18 15:33:06 -07:00
Carlo Costino
e410fa3d20 Merge pull request #1450 from GSA/notify-admin-1447
fix service invites
2024-04-18 17:22:47 -04:00
Kenneth Kehl
7ed7b4e1f4 fix service invites 2024-04-18 14:01:33 -07:00
Beverly Nguyen
830c724ee8 Merge branch 'main' into 1416-combine-withnav_templatehtml-and-org_templatehtml 2024-04-18 11:08:01 -07:00
Andrew Shumway
3d9fe172c2 Check work around due to email noti 2024-04-18 10:51:01 -06:00
Andrew Shumway
21e7dea739 formatting 2024-04-18 10:35:15 -06:00
Andrew Shumway
65776318e0 Merge branch 'main' of https://github.com/GSA/notifications-admin into e2e-test-invite-to-service 2024-04-18 10:27:31 -06:00
Andrew Shumway
f3a3876d43 format 2024-04-18 10:27:21 -06:00
Carlo Costino
4f7717158c Merge pull request #1441 from GSA/update-gunicorn
Update gunicorn and its-dangerous to latest releases
2024-04-18 10:48:06 -04:00
Carlo Costino
2484ea08df Update gunicorn to latest release
This changeset updates the gunicorn dependency to the latest release to address a recent CVE.  It also updates the its-dangerous package.

Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2024-04-17 18:05:19 -04:00
Carlo Costino
4579d88210 Merge pull request #1439 from GSA/1437-you-need-to-sign-in-again-login-gov
1437 you need to sign in again login gov
2024-04-17 15:12:00 -04:00
Carlo Costino
ca577d9bdc Merge pull request #1438 from GSA/1436-change-content-setupprofile-template
1436 change content setupprofile template
2024-04-17 14:59:07 -04:00
Jonathan Bobel
ecaa7d9ab7 It shouldn't say "again" 2024-04-17 14:41:04 -04:00
Jonathan Bobel
04ce58831b 1437 - Adding link to sign-in again if statement 2024-04-17 14:39:48 -04:00
Kenneth Kehl
fc4db59818 fix 4 out of 5 checkboxes 2024-04-17 11:32:44 -07:00
Andrew Shumway
fcf2e31911 Merge branch 'main' of https://github.com/GSA/notifications-admin 2024-04-17 10:42:18 -06:00
Jonathan Bobel
7bd9c748e5 1436 - small content change for mobile number hint 2024-04-17 12:39:10 -04:00
Jonathan Bobel
337920389f Merge branch 'main' of https://github.com/GSA/notifications-admin 2024-04-17 12:27:29 -04:00
Andrew Shumway
e5dbe6e428 e2e test wip with checkboxes 2024-04-17 10:17:56 -06:00
Carlo Costino
b83f496d76 Merge pull request #1399 from GSA/1269-content-update-for-login-gov-settings
1269 - Content updates for Service Settings after login.gov integration
2024-04-17 12:12:21 -04:00
Jonathan Bobel
78c08e69f7 Fixed failing test 2024-04-17 12:01:37 -04:00
Jonathan Bobel
7755e02ad8 Removing instances of the login_gov_enabled flag as it will be live with this push to production 2024-04-17 11:49:47 -04:00
Carlo Costino
b8dda01680 Merge pull request #1432 from GSA/1427-remove-email-and-password-from-settings-because-login-gov
1427 remove email and password from settings because login gov
2024-04-17 11:43:19 -04:00
Jonathan Bobel
8596a9cdb3 Removing the email and password fields in the settings area because login.gov will take care of this 2024-04-17 11:26:14 -04:00
Kenneth Kehl
431bc28a89 add e2e variables to manifest 2024-04-17 08:25:05 -07:00
Jonathan Bobel
e14fc8b654 Changed the flag to true 2024-04-17 11:03:45 -04:00
Jonathan Bobel
383a3a0d4b Merge branch 'main' of https://github.com/GSA/notifications-admin into 1427-remove-email-and-password-from-settings-because-login-gov 2024-04-17 10:52:04 -04:00
Jonathan Bobel
2c4a694815 Merge branch 'main' of https://github.com/GSA/notifications-admin into 1269-content-update-for-login-gov-settings 2024-04-17 10:43:02 -04:00
Carlo Costino
a5fa6541ac Merge pull request #1428 from GSA/notify-admin-1425
fix 90 day email validation
2024-04-16 16:51:09 -04:00
Kenneth Kehl
80fb024827 merge from main 2024-04-16 13:08:06 -07:00
Kenneth Kehl
f30899d762 fix 90 day email validation 2024-04-16 12:06:33 -07:00
Jonathan Bobel
99ac0c4ba7 Merge branch 'main' of https://github.com/GSA/notifications-admin 2024-04-16 13:45:42 -04:00
Carlo Costino
dc9826cb90 Merge pull request #1424 from GSA/1423-Sign-in-content-changes-for-login-gov
1423 - Few final updates to switch over to login.gov
2024-04-16 13:07:02 -04:00
Jonathan Bobel
5b484d98c3 Merge branch 'main' of https://github.com/GSA/notifications-admin 2024-04-16 12:49:23 -04:00
Jonathan Bobel
b6ed2deac2 Merge branch 'main' of https://github.com/GSA/notifications-admin into 1423-Sign-in-content-changes-for-login-gov 2024-04-16 12:43:58 -04:00
Carlo Costino
e5bf60c2a2 Merge pull request #1426 from GSA/update-deps-again
Updated dependencies and ignore gunicorn audit flag
2024-04-16 12:41:52 -04:00
Carlo Costino
0044beaeed Updated dependencies and ignore gunicorn audit flag
This changeset updates a couple of dependencies, including our Python dependency audit check, and specifically ignores a gunicorn audit flag that appeared on 4/16/2024.

As soon as there is an update available for gunicorn that addresses the issue we will remove the flag to ignore the vulnerability report and update the dependency.

Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2024-04-16 11:46:57 -04:00
Jonathan Bobel
5a23905d21 Merge branch 'main' of https://github.com/GSA/notifications-admin into 1423-Sign-in-content-changes-for-login-gov 2024-04-16 11:10:46 -04:00
Jonathan Bobel
96293598f8 Fixing pa11y scan 2024-04-16 10:57:47 -04:00
Jonathan Bobel
b83019fdb7 Fixing pa11y scan 2024-04-16 10:57:16 -04:00
Beverly Nguyen
a171ba73c4 cleaning up navigation 2024-04-15 16:08:31 -07:00
Carlo Costino
c94ef02e77 Merge pull request #1195 from GSA/sms-allowance-dashboardbug
Sms allowance dashboardbug
2024-04-15 16:36:49 -04:00
Jonathan Bobel
6784cf9f3c 1423 - Few final updates to switch over to login.gov 2024-04-15 15:50:42 -04:00
Andrew Shumway
3f2dcc3022 Merge main fix conflicts 2024-04-15 10:45:23 -06:00
Andrew Shumway
2454a6e94b poetry lock 2024-04-15 10:38:27 -06:00
Andrew Shumway
33e8d7c09a Merge branch 'main' of https://github.com/GSA/notifications-admin into e2e-test-invite-to-service 2024-04-15 10:36:36 -06:00
Andrew Shumway
b722768182 e2e up to invite button 2024-04-15 10:36:27 -06:00
Beverly Nguyen
dfe5b2e020 Merge branch 'main' into 1416-combine-withnav_templatehtml-and-org_templatehtml 2024-04-12 09:18:54 -07:00
Steven Reilly
5d0461f52b Merge pull request #1419 from GSA/update-utils-0-4-6
Update utils to 0.4.6
2024-04-12 09:53:20 -04:00
Kenneth Kehl
ae5561862d fix tests, eliminate or tweak bogus incoming or foreign number tests 2024-04-11 15:39:50 -07:00
Carlo Costino
5fd1a8c836 Update utils to 0.4.6
This changeset updates notifications-utils to 0.4.6 in order to address some dependency updates and incorporate a few minor changes.

Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2024-04-11 18:02:56 -04:00
Beverly Nguyen
9c21e054cb merge main 2024-04-11 14:44:16 -07:00
Carlo Costino
d464dd2e98 Merge pull request #1409 from GSA/1353-convert-main_navhtml-to-component
Moved main_nav to components
2024-04-11 17:32:03 -04:00
Beverly Nguyen
2f443c56f6 merge main 2024-04-11 14:25:54 -07:00
Carlo Costino
6fb7f03f1b Merge pull request #1410 from GSA/1354-convert-org_navhtml-to-component
Moved org_nav to components
2024-04-11 16:41:02 -04:00
Carlo Costino
9418e6a86f Merge pull request #1408 from GSA/1351-convert-service_navigationhtml-marco-to-component
service_navigation.html moved to components
2024-04-11 16:21:43 -04:00
Carlo Costino
4d9a0d054c Merge pull request #1407 from GSA/1352-convert-settings_navhtml-to-component
Moved settings_nav to /new/components
2024-04-11 16:06:13 -04:00
Beverly Nguyen
85f73db416 revised withnav_templates to include org_template 2024-04-11 12:18:25 -07:00
samathad2023
c73be38c02 lock changes with merge 2024-04-11 09:01:26 -07:00
Carlo Costino
990b1813ea Merge pull request #1415 from GSA/notify-admin-1398
Exception Investigation: builtins:KeyError
2024-04-11 09:31:21 -04:00
Kenneth Kehl
5538b802ee Exception Investigation: builtins:KeyError 2024-04-10 13:17:00 -07:00
Jonathan Bobel
3e3edec558 Merge branch 'main' of https://github.com/GSA/notifications-admin into 1269-content-update-for-login-gov-settings 2024-04-10 14:32:11 -04:00
Beverly Nguyen
460399dd68 revised notes 2024-04-10 10:41:35 -07:00
Carlo Costino
004343a2c5 Merge pull request #1411 from GSA/notify-admin-1323
fix service stats
2024-04-10 12:22:12 -04:00
Jonathan Bobel
0708f3c785 Merge branch 'main' of https://github.com/GSA/notifications-admin into 1269-content-update-for-login-gov-settings 2024-04-10 11:30:21 -04:00
Kenneth Kehl
96ec868e3e fix service stats 2024-04-10 07:45:10 -07:00
Beverly Nguyen
5626267c94 org_nav 2024-04-09 16:43:01 -07:00
Beverly Nguyen
7fe90a14aa org_nav 2024-04-09 16:40:20 -07:00
Beverly Nguyen
7f3728e0d5 moved main_nav to components 2024-04-09 16:32:56 -07:00
Beverly Nguyen
beedce1796 moved main_nav to components 2024-04-09 16:31:53 -07:00
Beverly Nguyen
8915bf16ed moved main_nav to components 2024-04-09 16:28:05 -07:00
Beverly Nguyen
d250542b7f converted and moved service_navigation.html to /components 2024-04-09 16:07:56 -07:00
Beverly Nguyen
35f836e5d6 service_navigation.html moved to components 2024-04-09 15:57:15 -07:00
Beverly Nguyen
4a61575859 moved settings_nav to /new/components 2024-04-09 15:28:36 -07:00
Carlo Costino
5b4d5118d8 Merge pull request #1346 from GSA/notify-admin-1336
Add end-to-end test: Sending a message from existing template
2024-04-09 17:08:01 -04:00
Carlo Costino
a118056683 Merge pull request #1360 from GSA/notify-admin-1337
create new template test
2024-04-09 17:00:34 -04:00
Carlo Costino
6eb3e5b2b0 Merge pull request #1406 from GSA/1401-tests-with-timezone-checks-are-failing-locally
Tests with timezone checks are failing locally
2024-04-09 16:21:02 -04:00
Beverly Nguyen
63bc85d8d4 added format_datetime_scheduled_notification to formatters and removed unneccesary format changes 2024-04-09 12:52:45 -07:00
Kenneth Kehl
f28bbd77a4 code review feedback 2024-04-09 10:41:54 -07:00
Kenneth Kehl
931d5f4fed remove end-to-end context 2024-04-09 09:10:02 -07:00
Kenneth Kehl
6a29d2c814 code review feedback 2024-04-09 09:07:19 -07:00
Carlo Costino
de0aed60f9 Merge pull request #1375 from GSA/1373-bug-single-job---preview-does-not-display-variable-information
Bug: Single Job - Preview does not display variable information
2024-04-08 17:44:59 -04:00
samathad2023
2e55133f83 flask 3.0.2 to 3.0.3 2024-04-08 12:21:26 -07:00
Carlo Costino
84bef51d7d Merge pull request #1400 from GSA/update-utils-0-4-5
Update utils to 0.4.5
2024-04-08 12:02:43 -04:00
Carlo Costino
d5d5a45138 Update utils to 0.4.5
This changeset updates notifications-utils to 0.4.5, which includes a few minor fixes and several dependency updates.

Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2024-04-08 11:41:39 -04:00
Jonathan Bobel
f46f9661f1 1269 - Content updates for Service Settings after login.gov integration 2024-04-08 11:32:09 -04:00
Beverly Nguyen
6acbce0858 removed jobs template 2024-04-05 12:14:56 -07:00
samathad2023
e71989022d flask upgrade 2024-04-04 18:09:22 -07:00
Beverly Nguyen
745532e657 added template for personalisation 2024-04-02 16:30:40 -07:00
Beverly Nguyen
32f36d433a updated css to placeholder 2024-04-02 14:11:44 -07:00
Beverly Nguyen
acdd2806fc added force_hide_sender 2024-04-01 18:03:38 -07:00
Kenneth Kehl
5a81c11348 add comment 2024-03-27 12:40:45 -07:00
Kenneth Kehl
81412ddd1e fix 2024-03-27 12:32:29 -07:00
Kenneth Kehl
a85681252f fix 2024-03-27 12:15:44 -07:00
Kenneth Kehl
f6f750e5d0 try current service link 2024-03-27 11:02:53 -07:00
Kenneth Kehl
70c3457dbd try current service link 2024-03-27 10:52:22 -07:00
Kenneth Kehl
939c1c978e try current service link 2024-03-27 10:35:09 -07:00
Kenneth Kehl
bbb351861d create new template test 2024-03-27 10:26:56 -07:00
Kenneth Kehl
624a89a546 create new template test 2024-03-27 10:21:01 -07:00
Andrew Shumway
d4ca4cfc44 Merge branch 'main' of https://github.com/GSA/notifications-admin into sms-allowance-dashboardbug 2024-03-27 10:11:24 -06:00
Andrew Shumway
c9c8882dc9 Fix test 2024-03-27 10:10:56 -06:00
Kenneth Kehl
abef1230b8 final? 2024-03-26 11:22:22 -07:00
Kenneth Kehl
6f56123eea works locally and maybe on github as well 2024-03-26 11:13:54 -07:00
Kenneth Kehl
b9b59ea453 works locally and maybe on github as well 2024-03-26 10:59:16 -07:00
Kenneth Kehl
11bfc829e7 works locally and maybe on github as well 2024-03-26 10:45:17 -07:00
Kenneth Kehl
edf3961f0d works locally and maybe on github as well 2024-03-26 10:30:11 -07:00
Kenneth Kehl
c4a594663b put back firefox tests 2024-03-26 09:57:16 -07:00
Kenneth Kehl
790c274a6e only test chromium right now 2024-03-26 09:43:54 -07:00
Kenneth Kehl
4874c91f0a only test chromium right now 2024-03-26 09:38:41 -07:00
Kenneth Kehl
96c1a2b59f only test chromium right now 2024-03-26 09:33:07 -07:00
Kenneth Kehl
08603c993c only test chromium right now 2024-03-26 09:24:31 -07:00
Kenneth Kehl
578d00a9ee only test chromium right now 2024-03-26 09:18:32 -07:00
Kenneth Kehl
d6a0e25c38 only test chromium right now 2024-03-26 09:10:52 -07:00
Andrew Shumway
c4401b3394 Merge branch 'main' of https://github.com/GSA/notifications-admin into sms-allowance-dashboardbug 2024-03-26 10:04:14 -06:00
Kenneth Kehl
8b33fcc1f5 only test chromium right now 2024-03-26 09:03:30 -07:00
Kenneth Kehl
afefa092ed only test chromium right now 2024-03-26 08:56:50 -07:00
Kenneth Kehl
25f2175147 only test chromium right now 2024-03-26 08:45:30 -07:00
Kenneth Kehl
5e16f210d8 only test chromium right now 2024-03-26 08:32:37 -07:00
Kenneth Kehl
6700f85784 only test chromium right now 2024-03-26 08:22:11 -07:00
Kenneth Kehl
1ecb617eac only test chromium right now 2024-03-26 08:14:49 -07:00
Kenneth Kehl
7ebc337bb0 only test chromium right now 2024-03-26 08:06:39 -07:00
Kenneth Kehl
e1be811ed5 only test chromium right now 2024-03-26 07:57:45 -07:00
Kenneth Kehl
8bc41c59dc try button instead of text 2024-03-25 14:12:31 -07:00
Kenneth Kehl
86efe62b22 try button instead of text 2024-03-25 14:07:33 -07:00
Kenneth Kehl
c4cce69f71 try button instead of text 2024-03-25 13:52:51 -07:00
Kenneth Kehl
9dcf157ccb add existing template case 2024-03-25 13:29:59 -07:00
Kenneth Kehl
3660dce9f5 add existing template case 2024-03-25 13:21:07 -07:00
Kenneth Kehl
dbb60fc963 add existing template case 2024-03-25 13:15:41 -07:00
Kenneth Kehl
6367b2ce76 add existing template case 2024-03-25 13:09:32 -07:00
Kenneth Kehl
e1c2a6a2fd add existing template case 2024-03-25 12:23:53 -07:00
Kenneth Kehl
54b9d2a5d6 add existing template case 2024-03-25 12:06:38 -07:00
Kenneth Kehl
cf56ec4263 merge from main 2024-03-25 11:45:19 -07:00
Kenneth Kehl
404ef2c3c3 initial 2024-03-25 11:38:07 -07:00
Andrew Shumway
5a440863af Fix trial mode allowance bug 2024-02-07 14:43:39 -07:00
Andrew Shumway
53c193587d Merge branch 'main' of https://github.com/GSA/notifications-admin into sms-allowance-dashboardbug 2024-02-07 09:38:43 -07:00
Andrew Shumway
6999d72f76 Fix dashboard bug/usage page 2024-02-07 09:38:18 -07:00
236 changed files with 7242 additions and 5442 deletions

706
.ds.baseline Normal file
View File

@@ -0,0 +1,706 @@
{
"version": "1.5.0",
"plugins_used": [
{
"name": "ArtifactoryDetector"
},
{
"name": "AWSKeyDetector"
},
{
"name": "AzureStorageKeyDetector"
},
{
"name": "Base64HighEntropyString",
"limit": 4.5
},
{
"name": "BasicAuthDetector"
},
{
"name": "CloudantDetector"
},
{
"name": "DiscordBotTokenDetector"
},
{
"name": "GitHubTokenDetector"
},
{
"name": "GitLabTokenDetector"
},
{
"name": "HexHighEntropyString",
"limit": 3.0
},
{
"name": "IbmCloudIamDetector"
},
{
"name": "IbmCosHmacDetector"
},
{
"name": "IPPublicDetector"
},
{
"name": "JwtTokenDetector"
},
{
"name": "KeywordDetector",
"keyword_exclude": ""
},
{
"name": "MailchimpDetector"
},
{
"name": "NpmDetector"
},
{
"name": "OpenAIDetector"
},
{
"name": "PrivateKeyDetector"
},
{
"name": "PypiTokenDetector"
},
{
"name": "SendGridDetector"
},
{
"name": "SlackDetector"
},
{
"name": "SoftlayerDetector"
},
{
"name": "SquareOAuthDetector"
},
{
"name": "StripeDetector"
},
{
"name": "TelegramBotTokenDetector"
},
{
"name": "TwilioKeyDetector"
}
],
"filters_used": [
{
"path": "detect_secrets.filters.allowlist.is_line_allowlisted"
},
{
"path": "detect_secrets.filters.common.is_baseline_file",
"filename": ".ds.baseline"
},
{
"path": "detect_secrets.filters.common.is_ignored_due_to_verification_policies",
"min_level": 2
},
{
"path": "detect_secrets.filters.heuristic.is_indirect_reference"
},
{
"path": "detect_secrets.filters.heuristic.is_likely_id_string"
},
{
"path": "detect_secrets.filters.heuristic.is_lock_file"
},
{
"path": "detect_secrets.filters.heuristic.is_not_alphanumeric_string"
},
{
"path": "detect_secrets.filters.heuristic.is_potential_uuid"
},
{
"path": "detect_secrets.filters.heuristic.is_prefixed_with_dollar_sign"
},
{
"path": "detect_secrets.filters.heuristic.is_sequential_string"
},
{
"path": "detect_secrets.filters.heuristic.is_swagger_file"
},
{
"path": "detect_secrets.filters.heuristic.is_templated_secret"
}
],
"results": {
".github/workflows/checks.yml": [
{
"type": "Secret Keyword",
"filename": ".github/workflows/checks.yml",
"hashed_secret": "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8",
"is_verified": false,
"line_number": 61,
"is_secret": false
},
{
"type": "Basic Auth Credentials",
"filename": ".github/workflows/checks.yml",
"hashed_secret": "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8",
"is_verified": false,
"line_number": 95,
"is_secret": false
}
],
"app/assets/js/uswds.min.js": [
{
"type": "Secret Keyword",
"filename": "app/assets/js/uswds.min.js",
"hashed_secret": "372ea08cab33e71c02c651dbc83a474d32c676ea",
"is_verified": false,
"line_number": 85,
"is_secret": false
},
{
"type": "Secret Keyword",
"filename": "app/assets/js/uswds.min.js",
"hashed_secret": "53e07a32bf191d6917ee6fd863f0b52632a86798",
"is_verified": false,
"line_number": 85,
"is_secret": false
}
],
"app/config.py": [
{
"type": "Secret Keyword",
"filename": "app/config.py",
"hashed_secret": "577a4c667e4af8682ca431857214b3a920883efc",
"is_verified": false,
"line_number": 117,
"is_secret": false
}
],
"app/main/_commonly_used_passwords.py": [
{
"type": "Hex High Entropy String",
"filename": "app/main/_commonly_used_passwords.py",
"hashed_secret": "82e19fa12aab7cfc718a002fc82c0f074bf070e7",
"is_verified": false,
"line_number": 123,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "app/main/_commonly_used_passwords.py",
"hashed_secret": "a172ffc990129fe6f68b50f6037c54a1894ee3fd",
"is_verified": false,
"line_number": 240,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "app/main/_commonly_used_passwords.py",
"hashed_secret": "4de69ee6b12b7fc91070873b71ba6e2929b90619",
"is_verified": false,
"line_number": 244,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "app/main/_commonly_used_passwords.py",
"hashed_secret": "370194ff6e0f93a7432e16cc9badd9427e8b4e13",
"is_verified": false,
"line_number": 284,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "app/main/_commonly_used_passwords.py",
"hashed_secret": "3dd635a808ddb6dd4b6731f7c409d53dd4b14df2",
"is_verified": false,
"line_number": 356,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "app/main/_commonly_used_passwords.py",
"hashed_secret": "67a74306b06d0c01624fe0d0249a570f4d093747",
"is_verified": false,
"line_number": 374,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "app/main/_commonly_used_passwords.py",
"hashed_secret": "61d6504733ca7757e259c644acd085c4dd471019",
"is_verified": false,
"line_number": 910,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "app/main/_commonly_used_passwords.py",
"hashed_secret": "4ea872dfd7eefbde0036da7f0780826353dc7477",
"is_verified": false,
"line_number": 940,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "app/main/_commonly_used_passwords.py",
"hashed_secret": "b214f706bb602c1cc2adc5c6165e73622305f4bb",
"is_verified": false,
"line_number": 1010,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "app/main/_commonly_used_passwords.py",
"hashed_secret": "5cbabd43e49a1fedbbc3b86311aa6c8fe446abf9",
"is_verified": false,
"line_number": 1195,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "app/main/_commonly_used_passwords.py",
"hashed_secret": "18ad10fd4a67f21fc07b1aa5046b410f6b2bedf1",
"is_verified": false,
"line_number": 1213,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "app/main/_commonly_used_passwords.py",
"hashed_secret": "10470c3b4b1fed12c3baac014be15fac67c6e815",
"is_verified": false,
"line_number": 1263,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "app/main/_commonly_used_passwords.py",
"hashed_secret": "65e1946c8f102eca8ba0af291f7c5e807516d94c",
"is_verified": false,
"line_number": 1346,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "app/main/_commonly_used_passwords.py",
"hashed_secret": "0075df0a74c07ee295c98238c018401c9a80183b",
"is_verified": false,
"line_number": 1397,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "app/main/_commonly_used_passwords.py",
"hashed_secret": "ca0023d7b345802fbc227b902cb9c57a3e02195f",
"is_verified": false,
"line_number": 1442,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "app/main/_commonly_used_passwords.py",
"hashed_secret": "c8c6ca2e11c2dfd2a40914585b5944bffea15c8c",
"is_verified": false,
"line_number": 1555,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "app/main/_commonly_used_passwords.py",
"hashed_secret": "b85b97a99eab8c809570c61d6404c1e49bdefbb4",
"is_verified": false,
"line_number": 1596,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "app/main/_commonly_used_passwords.py",
"hashed_secret": "dec7dd342a499dfd4d283d872ccf598d8a7b6039",
"is_verified": false,
"line_number": 1789,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "app/main/_commonly_used_passwords.py",
"hashed_secret": "2dc5053699a351121bf839c446bd4a878dda5735",
"is_verified": false,
"line_number": 1939,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "app/main/_commonly_used_passwords.py",
"hashed_secret": "e5d54f0ac13abbdaa94b696c2469148b96dd11ab",
"is_verified": false,
"line_number": 2242,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "app/main/_commonly_used_passwords.py",
"hashed_secret": "6059f42e2bbae78141e8a9e6286755ee691d5ce0",
"is_verified": false,
"line_number": 2305,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "app/main/_commonly_used_passwords.py",
"hashed_secret": "fe703d258c7ef5f50b71e06565a65aa07194907f",
"is_verified": false,
"line_number": 2348,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "app/main/_commonly_used_passwords.py",
"hashed_secret": "c229b68e1c3ffd9874838b5cb5354a0ee1367ddc",
"is_verified": false,
"line_number": 2349,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "app/main/_commonly_used_passwords.py",
"hashed_secret": "756de479126e911b6f3400ae686d663d9d26b509",
"is_verified": false,
"line_number": 2920,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "app/main/_commonly_used_passwords.py",
"hashed_secret": "6b174322afcdb440ee9cc3cc11eb16f9a00dec04",
"is_verified": false,
"line_number": 2975,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "app/main/_commonly_used_passwords.py",
"hashed_secret": "9860783bfb510cbb2bf34471ec0b84a7ea587695",
"is_verified": false,
"line_number": 3359,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "app/main/_commonly_used_passwords.py",
"hashed_secret": "b227cbd22eaa96019ebfc4aff35ad2add2a47439",
"is_verified": false,
"line_number": 3590,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "app/main/_commonly_used_passwords.py",
"hashed_secret": "381d48209aecab8834eb495c5b5406100da07882",
"is_verified": false,
"line_number": 3811,
"is_secret": false
},
{
"type": "Hex High Entropy String",
"filename": "app/main/_commonly_used_passwords.py",
"hashed_secret": "508b38590a90d32990aadd7350d160b795c3ab41",
"is_verified": false,
"line_number": 3850,
"is_secret": false
}
],
"app/main/views/sign_in.py": [
{
"type": "Private Key",
"filename": "app/main/views/sign_in.py",
"hashed_secret": "1348b145fa1a555461c1b790a2f66614781091e9",
"is_verified": false,
"line_number": 27,
"is_secret": false
}
],
"app/templates/new/components/head.html": [
{
"type": "Base64 High Entropy String",
"filename": "app/templates/new/components/head.html",
"hashed_secret": "ee5048791fc7ff45a1545e24f85bec3317371327",
"is_verified": false,
"line_number": 34,
"is_secret": false
}
],
"app/templates/old/admin_template.html": [
{
"type": "Base64 High Entropy String",
"filename": "app/templates/old/admin_template.html",
"hashed_secret": "ee5048791fc7ff45a1545e24f85bec3317371327",
"is_verified": false,
"line_number": 18,
"is_secret": false
}
],
"deploy-config/sandbox.yml": [
{
"type": "Secret Keyword",
"filename": "deploy-config/sandbox.yml",
"hashed_secret": "113151dd10316fcb0d5507b6215d78e2f3fe9e54",
"is_verified": false,
"line_number": 8,
"is_secret": false
}
],
"pytest.ini": [
{
"type": "Secret Keyword",
"filename": "pytest.ini",
"hashed_secret": "577a4c667e4af8682ca431857214b3a920883efc",
"is_verified": false,
"line_number": 7,
"is_secret": false
},
{
"type": "Base64 High Entropy String",
"filename": "pytest.ini",
"hashed_secret": "d347784b1ab6074a65cda7bc42f1561bed85493f",
"is_verified": false,
"line_number": 7,
"is_secret": false
},
{
"type": "Base64 High Entropy String",
"filename": "pytest.ini",
"hashed_secret": "ed1754d5cc82c8fd83205ebfb8c43fe4e88415a4",
"is_verified": false,
"line_number": 9,
"is_secret": false
},
{
"type": "Secret Keyword",
"filename": "pytest.ini",
"hashed_secret": "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3",
"is_verified": false,
"line_number": 11,
"is_secret": false
}
],
"tests/__init__.py": [
{
"type": "Secret Keyword",
"filename": "tests/__init__.py",
"hashed_secret": "f8377c90fcfd699f0ddbdcb30c2c9183d2d933ea",
"is_verified": false,
"line_number": 388,
"is_secret": false
}
],
"tests/app/main/forms/test_register_user_form.py": [
{
"type": "Secret Keyword",
"filename": "tests/app/main/forms/test_register_user_form.py",
"hashed_secret": "8c6c978dc8e08771c7dea1ea2370fdf2446e5ba5",
"is_verified": false,
"line_number": 38,
"is_secret": false
}
],
"tests/app/main/test_errorhandlers.py": [
{
"type": "Base64 High Entropy String",
"filename": "tests/app/main/test_errorhandlers.py",
"hashed_secret": "005fa73b3f2be8f0d71d361c1f0a9d787cd09b4e",
"is_verified": false,
"line_number": 33,
"is_secret": false
}
],
"tests/app/main/test_request_header.py": [
{
"type": "Secret Keyword",
"filename": "tests/app/main/test_request_header.py",
"hashed_secret": "6866ef97a972ba3a2c6ff8bb2812981054770162",
"is_verified": false,
"line_number": 21,
"is_secret": false
}
],
"tests/app/main/views/organizations/test_organization_invites.py": [
{
"type": "Secret Keyword",
"filename": "tests/app/main/views/organizations/test_organization_invites.py",
"hashed_secret": "bdbb156d25d02fd7792865824201dda1c60f4473",
"is_verified": false,
"line_number": 265,
"is_secret": false
},
{
"type": "Secret Keyword",
"filename": "tests/app/main/views/organizations/test_organization_invites.py",
"hashed_secret": "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8",
"is_verified": false,
"line_number": 273,
"is_secret": false
}
],
"tests/app/main/views/test_accept_invite.py": [
{
"type": "Secret Keyword",
"filename": "tests/app/main/views/test_accept_invite.py",
"hashed_secret": "07f0a6c13923fc3b5f0c57ffa2d29b715eb80d71",
"is_verified": false,
"line_number": 607,
"is_secret": false
}
],
"tests/app/main/views/test_new_password.py": [
{
"type": "Secret Keyword",
"filename": "tests/app/main/views/test_new_password.py",
"hashed_secret": "a41d5c3bbcd0b39c627b9cbf4897c6d25efa694f",
"is_verified": false,
"line_number": 89,
"is_secret": false
}
],
"tests/app/main/views/test_register.py": [
{
"type": "Secret Keyword",
"filename": "tests/app/main/views/test_register.py",
"hashed_secret": "bdbb156d25d02fd7792865824201dda1c60f4473",
"is_verified": false,
"line_number": 116,
"is_secret": false
},
{
"type": "Secret Keyword",
"filename": "tests/app/main/views/test_register.py",
"hashed_secret": "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8",
"is_verified": false,
"line_number": 192,
"is_secret": false
},
{
"type": "Secret Keyword",
"filename": "tests/app/main/views/test_register.py",
"hashed_secret": "bb5b7caa27d005d38039e3797c3ddb9bcd22c3c8",
"is_verified": false,
"line_number": 260,
"is_secret": false
}
],
"tests/app/main/views/test_sign_in.py": [
{
"type": "Secret Keyword",
"filename": "tests/app/main/views/test_sign_in.py",
"hashed_secret": "8b8b69116ee882b5e987e330f55db81aba0636f9",
"is_verified": false,
"line_number": 90,
"is_secret": false
}
],
"tests/app/main/views/test_two_factor.py": [
{
"type": "Secret Keyword",
"filename": "tests/app/main/views/test_two_factor.py",
"hashed_secret": "dc66ad927c29e31c6c374231f57a4684b0687bfe",
"is_verified": false,
"line_number": 267,
"is_secret": false
}
],
"tests/app/main/views/test_user_profile.py": [
{
"type": "Secret Keyword",
"filename": "tests/app/main/views/test_user_profile.py",
"hashed_secret": "8072d7aad32964ec43fbcb699c75dc38890792f7",
"is_verified": false,
"line_number": 350,
"is_secret": false
},
{
"type": "Secret Keyword",
"filename": "tests/app/main/views/test_user_profile.py",
"hashed_secret": "4c9dbb972da179e4f66f023eaa5fb9451d835030",
"is_verified": false,
"line_number": 351,
"is_secret": false
}
],
"tests/app/main/views/test_verify.py": [
{
"type": "Secret Keyword",
"filename": "tests/app/main/views/test_verify.py",
"hashed_secret": "faafcfa63e128929409bf310b7ea5a415f2331ce",
"is_verified": false,
"line_number": 160,
"is_secret": false
}
],
"tests/app/notify_client/test_user_client.py": [
{
"type": "Secret Keyword",
"filename": "tests/app/notify_client/test_user_client.py",
"hashed_secret": "f2c57870308dc87f432e5912d4de6f8e322721ba",
"is_verified": false,
"line_number": 55,
"is_secret": false
}
],
"tests/app/test_cloudfoundry_config.py": [
{
"type": "Secret Keyword",
"filename": "tests/app/test_cloudfoundry_config.py",
"hashed_secret": "5e44dae2de8b6e57c797b968035265c9f2cd2b3e",
"is_verified": false,
"line_number": 12,
"is_secret": false
},
{
"type": "Secret Keyword",
"filename": "tests/app/test_cloudfoundry_config.py",
"hashed_secret": "e5e178db7317356946d13e5d2da037d39ac61c71",
"is_verified": false,
"line_number": 27,
"is_secret": false
}
],
"tests/conftest.py": [
{
"type": "Secret Keyword",
"filename": "tests/conftest.py",
"hashed_secret": "f8377c90fcfd699f0ddbdcb30c2c9183d2d933ea",
"is_verified": false,
"line_number": 3266,
"is_secret": false
}
],
"tests/notifications_utils/clients/antivirus/test_antivirus_client.py": [
{
"type": "Secret Keyword",
"filename": "tests/notifications_utils/clients/antivirus/test_antivirus_client.py",
"hashed_secret": "932b25270abe1301c22c709a19082dff07d469ff",
"is_verified": false,
"line_number": 16,
"is_secret": false
}
],
"tests/notifications_utils/clients/encryption/test_encryption_client.py": [
{
"type": "Secret Keyword",
"filename": "tests/notifications_utils/clients/encryption/test_encryption_client.py",
"hashed_secret": "f1e923a9667de11be6a210849a8651c1bfd81605",
"is_verified": false,
"line_number": 13,
"is_secret": false
}
],
"tests/notifications_utils/clients/zendesk/test_zendesk_client.py": [
{
"type": "Secret Keyword",
"filename": "tests/notifications_utils/clients/zendesk/test_zendesk_client.py",
"hashed_secret": "913a73b565c8e2c8ed94497580f619397709b8b6",
"is_verified": false,
"line_number": 16,
"is_secret": false
}
]
},
"generated_at": "2024-06-11T22:26:18Z"
}

View File

@@ -9,10 +9,10 @@ runs:
sudo apt-get update \
&& sudo apt-get install -y --no-install-recommends \
libcurl4-openssl-dev
- name: Set up Python 3.12
- name: Set up Python 3.12.3
uses: actions/setup-python@v4
with:
python-version: "3.12"
python-version: "3.12.3"
- name: Install poetry
shell: bash
run: pip install poetry

View File

@@ -1,79 +1,22 @@
<!--
Please follow the instructions found in this pull request template so that we
have all of the relevant details needed for our work.
At the minimum, please be sure to fill in all sections found below and also do
the following:
- Provide an appropriate and descriptive title for the pull request
- Link the pull request to its corresponding issue (must be done after creating
the pull request itself)
- Assign yourself as the author
- Attach the appropriate labels to it
- Set it to be on the Notify.gov project board
- Select one or more reviewers from the team or mark the pull request as a draft
depending on its current state
- If the pull request is a draft, please be sure to add reviewers once it is
ready for review and mark it ready for review
For each section, please delete the instructions/sample text (that includes this
text, though it is wrapped in an HTML comment just in case) and put in your own
information. Thank you!
Not sure what you should include or write in a pull request? Please read the
[pull request documentation in our docs!](https://github.com/GSA/notifications-api/blob/main/docs/all.md#pull-requests)
-->
*A note to PR reviewers: it may be helpful to review our
[code review documentation](https://github.com/GSA/notifications-api/blob/main/docs/all.md#code-reviews)
to know what to keep in mind while reviewing pull requests.*
*A note to PR reviewers: it may be helpful to review our [code review documentation](https://github.com/GSA/notifications-api/blob/main/docs/all.md#code-reviews) to know what to keep in mind while reviewing pull requests.*
## Description
Please enter a clear description about your proposed changes and what the
expected outcome(s) is/are from there. If there are complex implementation
details within the changes, this is a great place to explain those details using
plain language.
This should include:
- Links to issues that this PR addresses
- Screenshots or screen captures of any visible changes, especially for UI work
- Dependency changes
If there are any caveats, known issues, follow-up items, etc., make a quick note
of them here as well, though more details are probably warranted in the issue
itself in this case.
Please enter a detailed description here.
## TODO (optional)
If you're opening a draft PR, it might be helpful to list any outstanding work,
especially if you're asking folks to take a look before it's ready for full
review. In this case, create a small checklist with the outstanding items:
- [ ] TODO item 1
- [ ] TODO item 2
- [ ] TODO item ...
* [ ] TODO item 1
* [ ] TODO item 2
* [ ] TODO item ...
## Security Considerations
Please think about the security compliance aspect of your changes and what the
potential impacts might be.
**NOTE: Please be mindful of sharing sensitive information here! If you're not
sure of what to write, please ask the team first before writing anything here.**
Relevant details could include (and are not limited to) the following:
- Handling secrets/credential management (or specifically calling out that there
is nothing to handle)
- Any adjustments to the flow of data in and out the system, or even within it
- Connecting or disconnecting any external services to the application
- Handling of any sensitive information, such as PII
- Handling of information within log statements or other application monitoring
services/hooks
- The inclusion of a new external dependency or the removal of an existing one
- ... (anything else relevant from a security compliance perspective)
There are some cases where there are no security considerations to be had, e.g.,
updating our documentation with publicly available information. In those cases
it is fine to simply put something like this:
- None; this is a documentation update with publicly available information.
* Consideration 1
* Consideration 2
* Consideration ...

View File

@@ -157,7 +157,7 @@ jobs:
- uses: ./.github/actions/setup-project
- name: Create requirements.txt
run: poetry export --without-hashes --format=requirements.txt > requirements.txt
- uses: pypa/gh-action-pip-audit@v1.0.6
- uses: pypa/gh-action-pip-audit@v1.0.8
with:
inputs: requirements.txt
- name: Run npm audit

95
.github/workflows/codeql.yml vendored Normal file
View File

@@ -0,0 +1,95 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: [ "main", "production" ]
pull_request:
branches: [ "main", "production" ]
schedule:
- cron: '18 5 * * 3'
jobs:
analyze:
name: Analyze (${{ matrix.language }})
# Runner size impacts CodeQL analysis time. To learn more, please see:
# - https://gh.io/recommended-hardware-resources-for-running-codeql
# - https://gh.io/supported-runners-and-hardware-resources
# - https://gh.io/using-larger-runners (GitHub.com only)
# Consider using larger runners or machines with greater resources for possible analysis time improvements.
runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }}
permissions:
# required for all workflows
security-events: write
# required to fetch internal or private CodeQL packs
packages: read
# only required for workflows in private repositories
actions: read
contents: read
strategy:
fail-fast: false
matrix:
include:
- language: javascript-typescript
build-mode: none
- language: python
build-mode: none
# CodeQL supports the following values keywords for 'language': 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift'
# Use `c-cpp` to analyze code written in C, C++ or both
# Use 'java-kotlin' to analyze code written in Java, Kotlin or both
# Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both
# To learn more about changing the languages that are analyzed or customizing the build mode for your analysis,
# see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning.
# If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how
# your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
steps:
- name: Checkout repository
uses: actions/checkout@v4
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
build-mode: ${{ matrix.build-mode }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality
# If the analyze step fails for one of the languages you are analyzing with
# "We were unable to automatically build your code", modify the matrix above
# to set the build mode to "manual" for that language. Then modify this step
# to build your code.
# Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
- if: matrix.build-mode == 'manual'
shell: bash
run: |
echo 'If you are using a "manual" build mode for one or more of the' \
'languages you are analyzing, replace this with the commands to build' \
'your code, for example:'
echo ' make bootstrap'
echo ' make release'
exit 1
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: "/language:${{matrix.language}}"

View File

@@ -18,11 +18,11 @@ jobs:
- name: Check for changes to Terraform
id: changed-terraform-files
uses: tj-actions/changed-files@v41.0.0
uses: tj-actions/changed-files@v44
with:
files: |
terraform/demo
terraform/shared
terraform/demo/**
terraform/shared/**
.github/workflows/deploy-demo.yml
- name: Terraform init
if: steps.changed-terraform-files.outputs.any_changed == 'true'
@@ -88,7 +88,7 @@ jobs:
- name: Check for changes to egress config
id: changed-egress-config
uses: tj-actions/changed-files@v41.0.0
uses: tj-actions/changed-files@v44
with:
files: |
deploy-config/egress_proxy/notify-admin-demo.*.acl

View File

@@ -18,11 +18,11 @@ jobs:
- name: Check for changes to Terraform
id: changed-terraform-files
uses: tj-actions/changed-files@v41.0.0
uses: tj-actions/changed-files@v44
with:
files: |
terraform/production
terraform/shared
terraform/production/**
terraform/shared/**
.github/workflows/deploy-prod.yml
- name: Terraform init
if: steps.changed-terraform-files.outputs.any_changed == 'true'
@@ -88,7 +88,7 @@ jobs:
- name: Check for changes to egress config
id: changed-egress-config
uses: tj-actions/changed-files@v41.0.0
uses: tj-actions/changed-files@v44
with:
files: |
deploy-config/egress_proxy/notify-admin-production.*.acl

View File

@@ -17,96 +17,96 @@ jobs:
environment: staging
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 2
- uses: actions/checkout@v4
with:
fetch-depth: 2
- name: Check for changes to Terraform
id: changed-terraform-files
uses: tj-actions/changed-files@v41.0.0
with:
files: |
terraform/staging
terraform/shared
.github/workflows/deploy.yml
- name: Terraform init
if: steps.changed-terraform-files.outputs.any_changed == 'true'
working-directory: terraform/staging
env:
AWS_ACCESS_KEY_ID: ${{ secrets.TERRAFORM_STATE_ACCESS_KEY }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.TERRAFORM_STATE_SECRET_ACCESS_KEY }}
run: terraform init
- name: Terraform apply
if: steps.changed-terraform-files.outputs.any_changed == 'true'
working-directory: terraform/staging
env:
AWS_ACCESS_KEY_ID: ${{ secrets.TERRAFORM_STATE_ACCESS_KEY }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.TERRAFORM_STATE_SECRET_ACCESS_KEY }}
TF_VAR_cf_user: ${{ secrets.CLOUDGOV_USERNAME }}
TF_VAR_cf_password: ${{ secrets.CLOUDGOV_PASSWORD }}
run: terraform apply -auto-approve -input=false
- name: Check for changes to Terraform
id: changed-terraform-files
uses: tj-actions/changed-files@v44
with:
files: |
terraform/staging/**
terraform/shared/**
.github/workflows/deploy.yml
- name: Terraform init
if: steps.changed-terraform-files.outputs.any_changed == 'true'
working-directory: terraform/staging
env:
AWS_ACCESS_KEY_ID: ${{ secrets.TERRAFORM_STATE_ACCESS_KEY }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.TERRAFORM_STATE_SECRET_ACCESS_KEY }}
run: terraform init
- name: Terraform apply
if: steps.changed-terraform-files.outputs.any_changed == 'true'
working-directory: terraform/staging
env:
AWS_ACCESS_KEY_ID: ${{ secrets.TERRAFORM_STATE_ACCESS_KEY }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.TERRAFORM_STATE_SECRET_ACCESS_KEY }}
TF_VAR_cf_user: ${{ secrets.CLOUDGOV_USERNAME }}
TF_VAR_cf_password: ${{ secrets.CLOUDGOV_PASSWORD }}
run: terraform apply -auto-approve -input=false
- uses: ./.github/actions/setup-project
- uses: ./.github/actions/setup-project
- name: Create requirements.txt
run: poetry export --without-hashes --format=requirements.txt > requirements.txt
- name: Create requirements.txt
run: poetry export --without-hashes --format=requirements.txt > requirements.txt
- name: Deploy to cloud.gov
uses: 18f/cg-deploy-action@main
env:
DANGEROUS_SALT: ${{ secrets.DANGEROUS_SALT }}
SECRET_KEY: ${{ secrets.SECRET_KEY }}
ADMIN_CLIENT_SECRET: ${{ secrets.ADMIN_CLIENT_SECRET }}
NEW_RELIC_LICENSE_KEY: ${{ secrets.NEW_RELIC_LICENSE_KEY }}
NR_BROWSER_KEY: ${{ secrets.NR_BROWSER_KEY }}
COMMIT_HASH: ${{ github.sha }}
LOGIN_PEM: ${{ secrets.LOGIN_PEM }}
LOGIN_DOT_GOV_CLIENT_ID: "urn:gov:gsa:openidconnect.profiles:sp:sso:gsa:notify-gov"
LOGIN_DOT_GOV_USER_INFO_URL: "https://secure.login.gov/api/openid_connect/userinfo"
LOGIN_DOT_GOV_ACCESS_TOKEN_URL: "https://secure.login.gov/api/openid_connect/token"
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"
with:
cf_username: ${{ secrets.CLOUDGOV_USERNAME }}
cf_password: ${{ secrets.CLOUDGOV_PASSWORD }}
cf_org: gsa-tts-benefits-studio
cf_space: notify-staging
push_arguments: >-
--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 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"
--var LOGIN_DOT_GOV_LOGOUT_URL="$LOGIN_DOT_GOV_LOGOUT_URL"
--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"
- name: Deploy to cloud.gov
uses: 18f/cg-deploy-action@main
env:
DANGEROUS_SALT: ${{ secrets.DANGEROUS_SALT }}
SECRET_KEY: ${{ secrets.SECRET_KEY }}
ADMIN_CLIENT_SECRET: ${{ secrets.ADMIN_CLIENT_SECRET }}
NEW_RELIC_LICENSE_KEY: ${{ secrets.NEW_RELIC_LICENSE_KEY }}
NR_BROWSER_KEY: ${{ secrets.NR_BROWSER_KEY }}
COMMIT_HASH: ${{ github.sha }}
LOGIN_PEM: ${{ secrets.LOGIN_PEM }}
LOGIN_DOT_GOV_CLIENT_ID: "urn:gov:gsa:openidconnect.profiles:sp:sso:gsa:notify-gov"
LOGIN_DOT_GOV_USER_INFO_URL: "https://secure.login.gov/api/openid_connect/userinfo"
LOGIN_DOT_GOV_ACCESS_TOKEN_URL: "https://secure.login.gov/api/openid_connect/token"
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"
with:
cf_username: ${{ secrets.CLOUDGOV_USERNAME }}
cf_password: ${{ secrets.CLOUDGOV_PASSWORD }}
cf_org: gsa-tts-benefits-studio
cf_space: notify-staging
push_arguments: >-
--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 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"
--var LOGIN_DOT_GOV_LOGOUT_URL="$LOGIN_DOT_GOV_LOGOUT_URL"
--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"
- name: Check for changes to egress config
id: changed-egress-config
uses: tj-actions/changed-files@v41.0.0
with:
files: |
deploy-config/egress_proxy/notify-admin-staging.*.acl
.github/actions/deploy-proxy/action.yml
.github/workflows/deploy.yml
- name: Deploy egress proxy
if: steps.changed-egress-config.outputs.any_changed == 'true'
uses: ./.github/actions/deploy-proxy
with:
cf_space: notify-staging
app: notify-admin-staging
- name: Check for changes to egress config
id: changed-egress-config
uses: tj-actions/changed-files@v44
with:
files: |
deploy-config/egress_proxy/notify-admin-staging.*.acl
.github/actions/deploy-proxy/action.yml
.github/workflows/deploy.yml
- name: Deploy egress proxy
if: steps.changed-egress-config.outputs.any_changed == 'true'
uses: ./.github/actions/deploy-proxy
with:
cf_space: notify-staging
app: notify-admin-staging
bail:
runs-on: ubuntu-latest

2
.nvmrc
View File

@@ -1 +1 @@
16.15.1
22.3.0

View File

@@ -2,7 +2,7 @@
# See https://pre-commit.com/hooks.html for more hooks
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.2.0
rev: v4.6.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
@@ -11,3 +11,14 @@ repos:
- id: debug-statements
- id: check-merge-conflict
- id: check-toml
- id: check-ast
- id: fix-byte-order-marker
- id: detect-aws-credentials
args: [--allow-missing-credentials]
- id: detect-private-key
- id: mixed-line-ending
- repo: https://github.com/Yelp/detect-secrets
rev: v1.5.0
hooks:
- id: detect-secrets
args: ['--baseline', '.ds.baseline']

View File

@@ -21,7 +21,8 @@ bootstrap: generate-version-file ## Set up everything to run the app
poetry install --sync --no-root
poetry run playwright install --with-deps
poetry run pre-commit install
source $(NVMSH) --no-use && nvm install && npm ci --no-audit
source $(NVMSH) --no-use && nvm install && npm install
source $(NVMSH) && npm ci --no-audit
source $(NVMSH) && npm run build
.PHONY: watch-frontend
@@ -40,6 +41,10 @@ run-flask-bare: ## Run flask without invoking poetry so we can override ENV var
npm-audit: ## Check for vulnerabilities in NPM packages
source $(NVMSH) && npm run audit
.PHONY: npm-audit-fix
npm-audit-fix: ## Fix vulnerabilities that do not require attentino (according to npm)
source $(NVMSH) && npm audit fix
.PHONY: help
help:
@cat $(MAKEFILE_LIST) | grep -E '^[a-zA-Z_-]+:.*?## .*$$' | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
@@ -71,18 +76,19 @@ too-complex:
.PHONY: py-test
py-test: export NEW_RELIC_ENVIRONMENT=test
py-test: ## Run python unit tests
poetry run coverage run --omit=*/notifications_utils/* -m pytest --maxfail=10 --ignore=tests/end_to_end tests/
poetry run coverage run -m pytest --maxfail=10 --ignore=tests/end_to_end tests/
poetry run coverage report --fail-under=96
poetry run coverage html -d .coverage_cache
.PHONY: dead-code
dead-code:
poetry run vulture ./app --min-confidence=100
dead-code: ## 60% is our aspirational goal, but currently breaks the build
poetry run vulture ./app ./notifications_utils --min-confidence=100
.PHONY: e2e-test
e2e-test: export NEW_RELIC_ENVIRONMENT=test
e2e-test: ## Run end-to-end integration tests; note that --browser webkit isn't currently working
poetry run pytest -v --browser chromium --browser firefox tests/end_to_end
poetry run pytest -vv --browser chromium --browser firefox tests/end_to_end
.PHONY: js-lint
js-lint: ## Run javascript linting scanners
@@ -101,13 +107,6 @@ py-lock: ## Syncs dependencies and updates lock file without performing recursiv
poetry lock --no-update
poetry install --sync
.PHONY: update-utils
update-utils: ## Forces Poetry to pull the latest changes from the notifications-utils repo; requires that you commit the changes to poetry.lock!
poetry update notifications-utils
@echo
@echo !!! PLEASE MAKE SURE TO COMMIT AND PUSH THE UPDATED poetry.lock FILE !!!
@echo
.PHONY: freeze-requirements
freeze-requirements: ## create static requirements.txt
poetry export --without-hashes --format=requirements.txt > requirements.txt

View File

@@ -19,7 +19,6 @@ UI's backend and is required for most things to function. Set that up first!
Our other repositories are:
- [notifications-admin](https://github.com/GSA/notifications-admin)
- [notifications-utils](https://github.com/GSA/notifications-utils)
- [us-notify-compliance](https://github.com/GSA/us-notify-compliance/)
- [notify-python-demo](https://github.com/GSA/notify-python-demo)
@@ -41,7 +40,7 @@ You will need the following items:
[Follow the instructions here to set up the Notify.gov API.](https://github.com/GSA/notifications-api#before-you-start)
The Notify.gov API is required in order for the Notify.gov Admin UI to run, and
it will also take care of many of the steps that are listed here. The sections
it will also take care of many of the steps that are listed here. The sections
that are a repeat from the API setup are flagged with an **[API Step]** label
in front of them.
@@ -49,7 +48,7 @@ in front of them.
This project is set up to work with
[nvm (Node Version Manager)](https://github.com/nvm-sh/nvm#installing-and-updating)
for managing and using Node.js (version 16.15.1) and the `npm` package manager.
for managing and using Node.js (version 22.3.0) and the `npm` package manager.
These instructions will walk you through how to set your machine up with all of
the required tools for this project.
@@ -84,11 +83,13 @@ Your system `$PATH` environment variable is likely set in one of these
locations:
For BASH shells:
- `~/.bashrc`
- `~/.bash_profile`
- `~/.profile`
For ZSH shells:
- `~/.zshrc`
- `~/.zprofile`
@@ -98,7 +99,7 @@ environments.
Which file you need to modify depends on whether or not you are running an
interactive shell or a login shell
(see [this Stack Overflow post](https://stackoverflow.com/questions/18186929/what-are-the-differences-between-a-login-shell-and-interactive-shell)
for an explanation of the differences). If you're still not sure, please ask
for an explanation of the differences). If you're still not sure, please ask
the team for help!
Once you determine which file you'll need to modify, add these lines before any
@@ -159,7 +160,7 @@ _NOTE: This project currently uses the latest `1.4.x release of Terraform._
#### [API Step] Python Installation
Now we're going to install a tool to help us manage Python versions and
virtual environments on our system. First, we'll install
virtual environments on our system. First, we'll install
[pyenv](https://github.com/pyenv/pyenv) and one of its plugins,
[pyenv-virtualenv](https://github.com/pyenv/pyenv-virtualenv), with Homebrew:
@@ -286,7 +287,7 @@ we'll use `3.12` in our example here since we recently upgraded to this version:
pyenv install 3.12
```
Next, delete the virtual environment you previously had set up. If you followed
Next, delete the virtual environment you previously had set up. If you followed
the instructions above with the first-time set up, you can do this with `pyenv`:
```sh
@@ -307,6 +308,20 @@ you'll be set with an upgraded version of Python.
_If you're not sure about the details of your current virtual environment, you can run `poetry env info` to get more information. If you've been using `pyenv` for everything, you can also see all available virtual environments with `pyenv virtualenvs`._
#### Updating the .env file for Login.gov
To configure the application for Login.gov, you will need to update the following environment variables in the .env file:
```
COMMIT_HASH=”--------”
```
Reach out to someone on the team to get the most recent Login.gov key.
```
LOGIN_PEM="INSERT_LOGIN_GOV_KEY_HERE"
```
#### Updating the .env file for E2E tests
With the newly created `.env` file in place, you'll need to make one more
@@ -351,6 +366,28 @@ This will run the local development web server and make the admin site
available at http://localhost:6012; remember to make sure that the Notify.gov
API is running as well!
## Creating a 'First User' in the database
After you have completed all setup steps, you will be unable to log in, because there
will not be a user in the database to link to the login.gov account you are using. So
you will need to create that user in your database using the 'create-test-user' command.
Open two terminals pointing to the api project and then run these commands in the
respective terminals.
(Server 1)
env ALLOW_EXPIRED_API_TOKEN=1 make run-flask
(Server 2)
poetry run flask command create-admin-jwt | tail -n 1 | pbcopy
poetry run flask command create-test-user --admin=True;
Supply your name, email address, mobile number, and password when prompted. Make sure the email address
is the same one you are using in login.gov and make sure your phone number is in the format 5555555555.
If for any reason in the course of development it is necessary for your to delete your db
via the `dropdb` command, you will need to repeat these steps when you recreate your db.
## Git Hooks
We're using [`pre-commit`](https://pre-commit.com/) to manage hooks in order to
@@ -396,23 +433,6 @@ In either situation, once you are finished and have verified the dependency
changes are working, please be sure to commit both the `pyproject.toml` and
`poetry.lock` files.
### Keeping the notification-utils Dependency Up-to-Date
The `notifications-utils` dependency references the other repository we have at
https://github.com/GSA/notifications-utils - this dependency requires a bit of
extra legwork to ensure it stays up-to-date.
Whenever a PR is merged in the `notifications-utils` repository, we need to make
sure the changes are pulled in here and committed to this repository as well.
You can do this by going through these steps:
- Make sure your local `main` branch is up-to-date
- Create a new branch to work in
- Run `make update-utils`
- Commit the updated `poetry.lock` file and push the changes
- Make a new PR with the change
- Have the PR get reviewed and merged
## Known Installation Issues
### Python Installation Errors

View File

@@ -18,6 +18,7 @@ from flask import (
)
from flask.globals import request_ctx
from flask_login import LoginManager, current_user
from flask_socketio import SocketIO
from flask_talisman import Talisman
from flask_wtf import CSRFProtect
from flask_wtf.csrf import CSRFError
@@ -30,7 +31,7 @@ from werkzeug.local import LocalProxy
from app import proxy_fix
from app.asset_fingerprinter import asset_fingerprinter
from app.config import configs
from app.extensions import redis_client, zendesk_client
from app.extensions import redis_client
from app.formatters import (
convert_markdown_template,
convert_to_boolean,
@@ -46,6 +47,7 @@ from app.formatters import (
format_datetime_human,
format_datetime_normal,
format_datetime_relative,
format_datetime_scheduled_notification,
format_datetime_table,
format_day_of_week,
format_delta,
@@ -117,6 +119,7 @@ from notifications_utils.recipients import format_phone_number_human_readable
login_manager = LoginManager()
csrf = CSRFProtect()
talisman = Talisman()
socketio = SocketIO()
# The current service attached to the request stack.
@@ -174,6 +177,7 @@ def create_app(application):
init_govuk_frontend(application)
init_jinja(application)
socketio.init_app(application)
for client in (
csrf,
@@ -201,7 +205,6 @@ def create_app(application):
user_api_client,
# External API clients
redis_client,
zendesk_client,
):
client.init_app(application)
@@ -230,6 +233,24 @@ def create_app(application):
)
logging.init_app(application)
# Hopefully will help identify if there is a race condition causing the CSRF errors
# that we have occasionally seen in our environments.
for key in ("SECRET_KEY", "DANGEROUS_SALT"):
try:
value = application.config[key]
except KeyError:
application.logger.error(f"Env Var {key} doesn't exist.")
else:
try:
data_len = len(value.strip())
except (TypeError, AttributeError):
application.logger.error(f"Env Var {key} invalid type: {type(value)}")
else:
if data_len:
application.logger.info(f"Env Var {key} is a non-zero length.")
else:
application.logger.error(f"Env Var {key} is empty.")
login_manager.login_view = "main.sign_in"
login_manager.login_message_category = "default"
login_manager.session_protection = None
@@ -551,6 +572,7 @@ def add_template_filters(application):
format_datetime,
format_datetime_24h,
format_datetime_normal,
format_datetime_scheduled_notification,
format_datetime_table,
valid_phone_number,
linkable_name,

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 292.1 39.47"><path fill="#fff" d="M7.44 6.89h17.2v22.06H7.44z"/><path fill="#112e51" d="M53.45 5.28h-6.16v27.31h17.87v-5.38H53.45V5.28zm30.76-.19c-8.35 0-14.67 5.89-14.67 13.85s6.32 13.93 14.67 13.93 14.67-6 14.67-13.93S92.56 5.09 84.21 5.09zm.08 22.39a8.49 8.49 0 0 1-8.43-8.54 8.4 8.4 0 0 1 8.43-8.47 8.29 8.29 0 0 1 8.27 8.47 8.36 8.36 0 0 1-8.27 8.54zm35.36-17.05a11.43 11.43 0 0 1 7.49 3l3.47-4.41a17.21 17.21 0 0 0-11-4c-8.51 0-14.9 6-14.9 13.85s6.29 13.99 14.58 13.99a20.21 20.21 0 0 0 11.08-3.55V17.57h-10.11v4.82H125V26a12.42 12.42 0 0 1-5.34 1.48 8.52 8.52 0 1 1 0-17zm19.61-5.15h6.17v27.31h-6.17zm34.53 17.56L160.52 5.28h-5.61v27.31h5.89V15.07l13.22 17.52h5.62V5.28h-5.85v17.56zm17.47 2.85a3.39 3.39 0 0 0-3.47 3.56 3.47 3.47 0 1 0 6.94 0 3.36 3.36 0 0 0-3.47-3.56zm23.15-15.26a11.43 11.43 0 0 1 7.49 3l3.47-4.41a17.21 17.21 0 0 0-11-4c-8.51 0-14.9 6-14.9 13.85s6.28 13.93 14.55 13.93a20.21 20.21 0 0 0 11.08-3.55V17.57H215v4.82h4.77V26a12.42 12.42 0 0 1-5.34 1.48 8.52 8.52 0 1 1 0-17zm32.23-5.34C238.29 5.09 232 11 232 18.94s6.32 13.93 14.67 13.93 14.67-6 14.67-13.93S255 5.09 246.64 5.09zm.08 22.39a8.49 8.49 0 0 1-8.43-8.54 8.4 8.4 0 0 1 8.43-8.47 8.29 8.29 0 0 1 8.28 8.47 8.36 8.36 0 0 1-8.28 8.54zm39.02-22.2-7.49 20.6-7.45-20.6h-6.63l10.73 27.31h6.36L292.1 5.28h-6.36z"/><path fill="#e21d3e" d="m11.38 25.34 1.45-8.28a4.39 4.39 0 0 1 2.71-7.86V0H4.34A4.34 4.34 0 0 0 0 4.34v21.28a2.62 2.62 0 0 0 .26 1.16c.94 1.9 4.65 8 15.27 12.69V25.7a24.3 24.3 0 0 1-4.15-.36z"/><path fill="#b51e23" d="M26.72 0H15.53v9.19A4.39 4.39 0 0 1 18.28 17l1.45 8.32a24.29 24.29 0 0 1-4.2.36v13.79C26.14 34.8 29.86 28.68 30.8 26.79a2.62 2.62 0 0 0 .26-1.16V4.34A4.34 4.34 0 0 0 26.72 0z"/></svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -0,0 +1,67 @@
(function (window) {
function initializeChartAndSocket() {
var ctx = document.getElementById('myChart');
if (!ctx) {
return;
}
var myBarChart = new Chart(ctx.getContext('2d'), {
type: 'bar',
data: {
labels: [],
datasets: [
{
label: 'Delivered',
data: [],
backgroundColor: '#0076d6',
stack: 'Stack 0'
},
]
},
options: {
scales: {
y: {
beginAtZero: true
}
}
}
});
var socket = io();
socket.on('connect', function() {
socket.emit('fetch_daily_stats_by_user');
});
socket.on('daily_stats_by_user_update', function(data) {
// console.log('Data received:', data);
var labels = [];
var deliveredData = [];
for (var date in data) {
labels.push(date);
deliveredData.push(data[date].sms.delivered);
}
myBarChart.data.labels = labels;
myBarChart.data.datasets[0].data = deliveredData;
myBarChart.update();
});
socket.on('error', function(data) {
// console.log('Error:', data);
});
var sevenDaysButton = document.getElementById('sevenDaysButton');
if (sevenDaysButton) {
sevenDaysButton.addEventListener('click', function() {
socket.emit('fetch_daily_stats_by_user');
// console.log('clicked');
});
}
}
document.addEventListener('DOMContentLoaded', initializeChartAndSocket);
})(window);

View File

@@ -66,6 +66,10 @@ h2.sms-message-header {
margin-bottom: 0.5rem;
}
.usa-prose >*+ h2.message-header {
margin-top: 1em;
}
h2.recipient-list {
margin-bottom: 0.5rem;
}

View File

@@ -157,6 +157,18 @@ td.table-empty-message {
}
}
.usa-button img {
margin-left: .5rem;
height: 1rem;
}
.usa-button.login-button.login-button--primary,.login-button.login-button--primary:hover{
color:#112e51;background-color:#fff;
border:1px solid #767676;
display: inline-flex;
justify-content: center;
}
.user-list-edit-link:active:before,
.user-list-edit-link:focus:before {
box-shadow: none;
@@ -583,3 +595,9 @@ details form {
#countdown-container {
display: none; // Hide the countdown timer
}
.placeholder, .placeholder-conditional {
background-color: #face00;
border: 1px solid #face00;
border-radius: 7px;
}

View File

@@ -38,7 +38,7 @@ class Config(object):
NR_MONITOR_ON = settings and settings.monitor_mode
COMMIT_HASH = getenv("COMMIT_HASH", "--------")[0:7]
GOVERNMENT_EMAIL_DOMAIN_NAMES = ["gov"]
GOVERNMENT_EMAIL_DOMAIN_NAMES = ["gov", "mil", "si.edu"]
# Logging
NOTIFY_LOG_LEVEL = getenv("NOTIFY_LOG_LEVEL", "INFO")
@@ -53,7 +53,13 @@ class Config(object):
PERMANENT_SESSION_LIFETIME = 1800 # 30 Minutes
SEND_FILE_MAX_AGE_DEFAULT = 365 * 24 * 60 * 60 # 1 year
REPLY_TO_EMAIL_ADDRESS_VALIDATION_TIMEOUT = 45
ACTIVITY_STATS_LIMIT_DAYS = 7
ACTIVITY_STATS_LIMIT_DAYS = {
"today": 0,
"one_day": 1,
"three_day": 3,
"five_day": 5,
"seven_day": 7,
}
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_NAME = "notify_admin_session"
SESSION_COOKIE_SECURE = True

View File

@@ -1,5 +1,3 @@
from notifications_utils.clients.redis.redis_client import RedisClient
from notifications_utils.clients.zendesk.zendesk_client import ZendeskClient
zendesk_client = ZendeskClient()
redis_client = RedisClient()

View File

@@ -13,11 +13,12 @@ import humanize
import markdown
import pytz
from bs4 import BeautifulSoup
from flask import Markup, render_template_string, url_for
from flask import render_template_string, url_for
from flask.helpers import get_root_path
from markupsafe import Markup
from app.utils.csv import get_user_preferred_timezone
from app.utils.time import parse_dt, parse_naive_dt
from app.utils.time import parse_naive_dt
from notifications_utils.field import Field
from notifications_utils.formatters import make_quotes_smart
from notifications_utils.formatters import nl2br as utils_nl2br
@@ -93,16 +94,34 @@ def format_datetime_normal(date):
)
def format_datetime_scheduled_notification(date):
# e.g. April 09, 2024 at 04:00 PM US/Eastern.
# Everything except scheduled notifications, the time is always "now".
# Scheduled notifications are the exception to the rule.
# Here we are formating and displaying the datetime without converting datetime to a different timezone.
datetime_obj = parse_naive_dt(date)
format_time_without_tz = datetime_obj.replace(tzinfo=timezone.utc).strftime(
"%I:%M %p"
)
return "{} at {} {}".format(
format_date_normal(date), format_time_without_tz, get_user_preferred_timezone()
)
def format_datetime_table(date):
# example: 03-18-2024 at 04:53 PM, intended for datetimes in tables
return "{} at {}".format(format_date_numeric(date), format_time_12h(date))
def format_time_12h(date):
date = parse_dt(date)
date = parse_naive_dt(date)
preferred_tz = pytz.timezone(get_user_preferred_timezone())
return date.astimezone(preferred_tz).strftime("%I:%M %p")
return (
date.replace(tzinfo=timezone.utc).astimezone(preferred_tz).strftime("%I:%M %p")
)
def format_datetime_relative(date):

View File

@@ -4,12 +4,13 @@ from itertools import chain
from numbers import Number
import pytz
from flask import Markup, render_template, request
from flask import render_template, request
from flask_login import current_user
from flask_wtf import FlaskForm as Form
from flask_wtf.file import FileAllowed
from flask_wtf.file import FileField as FileField_wtf
from flask_wtf.file import FileSize
from markupsafe import Markup
from werkzeug.utils import cached_property
from wtforms import (
BooleanField,

View File

@@ -1,5 +1,6 @@
from flask import Markup, abort, flash, redirect, render_template, request, url_for
from flask import abort, flash, redirect, render_template, request, url_for
from flask_login import current_user
from markupsafe import Markup
from app import (
api_key_api_client,

View File

@@ -6,6 +6,7 @@ from itertools import groupby
from flask import Response, abort, jsonify, render_template, request, session, url_for
from flask_login import current_user
from flask_socketio import emit
from werkzeug.utils import redirect
from app import (
@@ -14,6 +15,7 @@ from app import (
job_api_client,
notification_api_client,
service_api_client,
socketio,
template_statistics_client,
)
from app.formatters import format_date_numeric, format_datetime_numeric, get_time_left
@@ -32,6 +34,38 @@ from app.utils.user import user_has_permissions
from notifications_utils.recipients import format_phone_number_human_readable
@socketio.on("fetch_daily_stats")
def handle_fetch_daily_stats():
service_id = session.get('service_id')
if service_id:
date_range = get_stats_date_range()
daily_stats = service_api_client.get_service_notification_statistics_by_day(
service_id, start_date=date_range["start_date"], days=date_range["days"]
)
emit("daily_stats_update", daily_stats)
else:
emit("error", {"error": "No service_id provided"})
@socketio.on("fetch_daily_stats_by_user")
def handle_fetch_daily_stats_by_user():
service_id = session.get("service_id")
user_id = session.get("user_id")
if service_id and user_id:
date_range = get_stats_date_range()
daily_stats_by_user = (
service_api_client.get_user_service_notification_statistics_by_day(
service_id,
user_id,
start_date=date_range["start_date"],
days=date_range["days"],
)
)
emit("daily_stats_by_user_update", daily_stats_by_user)
else:
emit("error", {"error": "No service_id or user_id provided"})
@main.route("/services/<uuid:service_id>/dashboard")
@user_has_permissions("view_activity", "send_messages")
def old_service_dashboard(service_id):
@@ -134,11 +168,17 @@ def template_usage(service_id):
months=months,
stats=stats,
most_used_template_count=max(
max(
(template["requested_count"] for template in month["templates_used"]),
default=0,
)
for month in months
(
max(
(
template["requested_count"]
for template in month["templates_used"]
),
default=0,
)
for month in months
),
default=0,
),
years=get_tuples_of_financial_years(
partial(url_for, ".template_usage", service_id=service_id),
@@ -155,31 +195,16 @@ def usage(service_id):
year, current_financial_year = requested_and_current_financial_year(request)
free_sms_allowance = billing_api_client.get_free_sms_fragment_limit_for_year(
service_id, year
service_id
)
units = billing_api_client.get_monthly_usage_for_service(service_id, year)
yearly_usage = billing_api_client.get_annual_usage_for_service(service_id, year)
more_stats = format_monthly_stats_to_list(
service_api_client.get_monthly_notification_stats(service_id, year)["data"]
)
if year == current_financial_year:
# This includes Oct, Nov, Dec
# but we don't need next year's data yet
more_stats = [
month
for month in more_stats
if month["name"] in ["October", "November", "December"]
]
elif year == (current_financial_year + 1):
# This is all the other months
# and we need last year's data
more_stats = [
month
for month in more_stats
if month["name"] not in ["October", "November", "December"]
]
return render_template(
"views/usage.html",
months=list(get_monthly_usage_breakdown(year, units, more_stats)),
@@ -341,8 +366,15 @@ def get_dashboard_partials(service_id):
dashboard_totals = (get_dashboard_totals(stats),)
free_sms_allowance = billing_api_client.get_free_sms_fragment_limit_for_year(
current_service.id,
get_current_financial_year(),
)
# These 2 calls will update the dashboard sms allowance count while in trial mode.
billing_api_client.get_monthly_usage_for_service(
service_id, get_current_financial_year()
)
billing_api_client.create_or_update_free_sms_fragment_limit(
service_id, free_sms_fragment_limit=free_sms_allowance
)
yearly_usage = billing_api_client.get_annual_usage_for_service(
service_id,
get_current_financial_year(),
@@ -433,13 +465,25 @@ def aggregate_status_types(counts_dict):
def get_months_for_financial_year(year, time_format="%B"):
return [
month.strftime(time_format)
for month in (
get_months_for_year(10, 13, year) + get_months_for_year(1, 10, year + 1)
)
if month < datetime.now()
]
return [month.strftime(time_format) for month in (get_months_for_year(1, 13, year))]
def get_current_month_for_financial_year(year):
current_month = datetime.now().month
return current_month
def get_stats_date_range():
current_financial_year = get_current_financial_year()
current_month = get_current_month_for_financial_year(current_financial_year)
start_date = datetime.now().strftime("%Y-%m-%d")
days = 7
return {
"current_financial_year": current_financial_year,
"current_month": current_month,
"start_date": start_date,
"days": days,
}
def get_months_for_year(start, end, year):

View File

@@ -1,6 +1,6 @@
import os
from flask import abort, redirect, render_template, request, url_for
from flask import abort, current_app, redirect, render_template, request, url_for
from flask_login import current_user
from app import status_api_client
@@ -9,20 +9,28 @@ 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.utils.user import user_is_logged_in
login_dot_gov_url = os.getenv("LOGIN_DOT_GOV_INITIAL_SIGNIN_URL")
from notifications_utils.url_safe_token import generate_token
@main.route("/")
def index():
if current_user and current_user.is_authenticated:
return redirect(url_for("main.choose_account"))
token = generate_token(
str(request.remote_addr),
current_app.config["SECRET_KEY"],
current_app.config["DANGEROUS_SALT"],
)
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)
return render_template(
"views/signedout.html",
sms_rate=CURRENT_SMS_RATE,
counts=status_api_client.get_count_of_live_services_and_organizations(),
login_dot_gov_url=login_dot_gov_url,
initial_signin_url=url,
)

View File

@@ -3,7 +3,6 @@
from functools import partial
from flask import (
Markup,
Response,
abort,
jsonify,
@@ -15,6 +14,7 @@ from flask import (
url_for,
)
from flask_login import current_user
from markupsafe import Markup
from app import (
current_service,
@@ -143,11 +143,40 @@ def view_notifications(service_id, message_type=None):
True: ["reference"],
False: [],
}.get(bool(current_service.api_keys)),
download_link=url_for(
download_link_one_day=url_for(
".download_notifications_csv",
service_id=current_service.id,
message_type=message_type,
status=request.args.get("status"),
number_of_days="one_day",
),
download_link_today=url_for(
".download_notifications_csv",
service_id=current_service.id,
message_type=message_type,
status=request.args.get("status"),
number_of_days="today",
),
download_link_three_day=url_for(
".download_notifications_csv",
service_id=current_service.id,
message_type=message_type,
status=request.args.get("status"),
number_of_days="three_day",
),
download_link_five_day=url_for(
".download_notifications_csv",
service_id=current_service.id,
message_type=message_type,
status=request.args.get("status"),
number_of_days="five_day",
),
download_link_seven_day=url_for(
".download_notifications_csv",
service_id=current_service.id,
message_type=message_type,
status=request.args.get("status"),
number_of_days="seven_day",
),
)
@@ -183,10 +212,9 @@ def get_notifications(service_id, message_type, status_override=None): # noqa
filter_args["status"] = set_status_filters(filter_args)
service_data_retention_days = None
search_term = request.form.get("to", "")
if message_type is not None:
service_data_retention_days = current_service.get_days_of_retention(
message_type
message_type, number_of_days="seven_day"
)
if request.path.endswith("csv") and current_user.has_permissions("view_activity"):
@@ -212,7 +240,6 @@ def get_notifications(service_id, message_type, status_override=None): # noqa
)
url_args = {"message_type": message_type, "status": request.args.get("status")}
prev_page = None
if "links" in notifications and notifications["links"].get("prev", None):
prev_page = generate_previous_dict(
"main.view_notifications", service_id, page, url_args=url_args
@@ -233,7 +260,6 @@ def get_notifications(service_id, message_type, status_override=None): # noqa
)
else:
download_link = None
return {
"service_data_retention_days": service_data_retention_days,
"counts": render_template(
@@ -362,6 +388,7 @@ def get_job_partials(job):
filter_args = parse_filter_args(request.args)
filter_args["status"] = set_status_filters(filter_args)
notifications = job.get_notifications(status=filter_args["status"])
number_of_days = "seven_day"
counts = render_template(
"partials/count.html",
counts=_get_job_counts(job),
@@ -371,7 +398,7 @@ def get_job_partials(job):
),
)
service_data_retention_days = current_service.get_days_of_retention(
job.template_type
job.template_type, number_of_days
)
if request.referrer is not None:

View File

@@ -137,9 +137,9 @@ def get_all_personalisation_from_notification(notification):
def download_notifications_csv(service_id):
filter_args = parse_filter_args(request.args)
filter_args["status"] = set_status_filters(filter_args)
number_of_days = request.args["number_of_days"]
service_data_retention_days = current_service.get_days_of_retention(
filter_args.get("message_type")[0]
filter_args.get("message_type")[0], number_of_days
)
file_time = datetime.now().strftime("%Y-%m-%d %I:%M:%S %p")
file_time = f"{file_time} {get_user_preferred_timezone()}"

View File

@@ -662,7 +662,21 @@ def create_global_stats(services):
"email": {"delivered": 0, "failed": 0, "requested": 0},
"sms": {"delivered": 0, "failed": 0, "requested": 0},
}
# Issue #1323. The back end is now sending 'failure' instead of
# 'failed'. Adjust it here, but keep it flexible in case
# the backend reverts to 'failed'.
for service in services:
if service["statistics"]["sms"].get("failure") is not None:
service["statistics"]["sms"]["failed"] = service["statistics"]["sms"][
"failure"
]
if service["statistics"]["email"].get("failure") is not None:
service["statistics"]["email"]["failed"] = service["statistics"]["email"][
"failure"
]
for service in services:
for msg_type, status in itertools.product(
("sms", "email"), ("delivered", "failed", "requested")
):

View File

@@ -1,9 +1,12 @@
import base64
import json
import uuid
from datetime import datetime, timedelta
from flask import (
abort,
current_app,
flash,
redirect,
render_template,
request,
@@ -12,18 +15,18 @@ from flask import (
)
from flask_login import current_user
from app import user_api_client
from app import redis_client, user_api_client
from app.main import main
from app.main.forms import (
RegisterUserForm,
RegisterUserFromInviteForm,
RegisterUserFromOrgInviteForm,
SetupUserProfileForm,
)
from app.main.views import sign_in
from app.main.views.verify import activate_user
from app.models.user import InvitedOrgUser, InvitedUser, User
from app.utils import hide_from_search_engines
from app.utils import hide_from_search_engines, hilite
from app.utils.user import is_gov_user
@main.route("/register", methods=["GET", "POST"])
@@ -40,35 +43,10 @@ def register():
return render_template("views/register.html", form=form)
@main.route("/register-from-invite", methods=["GET", "POST"])
def register_from_invite():
invited_user = InvitedUser.from_session()
if not invited_user:
abort(404)
form = RegisterUserFromInviteForm(invited_user)
if form.validate_on_submit():
if (
form.service.data != invited_user.service
or form.email_address.data != invited_user.email_address
):
abort(400)
_do_registration(form, send_email=False, send_sms=invited_user.sms_auth)
invited_user.accept_invite()
if invited_user.sms_auth:
return redirect(url_for("main.verify"))
else:
# we've already proven this user has email because they clicked the invite link,
# so just activate them straight away
return activate_user(session["user_details"]["id"])
return render_template(
"views/register-from-invite.html", invited_user=invited_user, form=form
)
@main.route("/register-from-org-invite", methods=["GET", "POST"])
# TODO This is deprecated, we are now handling invites in the
# login.gov workflow. Leaving it here until we write the new
# org registration.
def register_from_org_invite():
invited_org_user = InvitedOrgUser.from_session()
if not invited_org_user:
@@ -136,31 +114,94 @@ def registration_continue():
raise Exception("Unexpected routing in registration_continue")
def get_invite_data_from_redis(state):
invite_data = json.loads(redis_client.get(f"invitedata-{state}"))
user_email = redis_client.get(f"user_email-{state}").decode("utf8")
user_uuid = redis_client.get(f"user_uuid-{state}").decode("utf8")
invited_user_email_address = redis_client.get(
f"invited_user_email_address-{state}"
).decode("utf8")
return invite_data, user_email, user_uuid, invited_user_email_address
def put_invite_data_in_redis(
state, invite_data, user_email, user_uuid, invited_user_email_address
):
ttl = 60 * 15 # 15 minutes
redis_client.set(f"invitedata-{state}", json.dumps(invite_data), ex=ttl)
redis_client.set(f"user_email-{state}", user_email, ex=ttl)
redis_client.set(f"user_uuid-{state}", user_uuid, ex=ttl)
redis_client.set(
f"invited_user_email_address-{state}",
invited_user_email_address,
ex=ttl,
)
def check_invited_user_email_address_matches_expected(
user_email, invited_user_email_address
):
if user_email.lower() != invited_user_email_address.lower():
debug_msg("invited user email did not match expected email, abort(403)")
flash("You cannot accept an invite for another person.")
abort(403)
if not is_gov_user(user_email):
debug_msg("invited user has a non-government email address.")
flash("You must use a government email address.")
abort(403)
@main.route("/set-up-your-profile", methods=["GET", "POST"])
@hide_from_search_engines
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")
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)
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 = json.loads(invite_data)
debug_msg(f"final state {invite_data}")
invited_user_id = invite_data["invited_user_id"]
invited_user_email_address = get_invited_user_email_address(invited_user_id)
debug_msg(f"email address from the invite_date is {invited_user_email_address}")
check_invited_user_email_address_matches_expected(
user_email, invited_user_email_address
)
invited_user_accept_invite(invited_user_id)
debug_msg(
f"accepted invite user {invited_user_email_address} to service {invite_data['service_id']}"
)
# We need to avoid taking a second trip through the login.gov code because we cannot pull the
# access token twice. So once we retrieve these values, let's park them in redis for 15 minutes
put_invite_data_in_redis(
state, invite_data, user_email, user_uuid, invited_user_email_address
)
form = SetupUserProfileForm()
if form.validate_on_submit():
# start login.gov
code = request.args.get("code")
state = request.args.get("state")
login_gov_error = request.args.get("error")
if code and state:
access_token = sign_in._get_access_token(code, state)
user_email, user_uuid = sign_in._get_user_email_and_uuid(access_token)
redirect_url = request.args.get("next")
elif login_gov_error:
current_app.logger.error(f"login.gov error: {login_gov_error}")
raise Exception(f"Could not login with login.gov {login_gov_error}")
# end login.gov
# create the user
# TODO we have to provide something for password until that column goes away
# TODO ideally we would set the user's preferred timezone here as well
if (
form.validate_on_submit()
and redis_client.get(f"invitedata-{state}") is not None
):
invite_data, user_email, user_uuid, invited_user_email_address = (
get_invite_data_from_redis(state)
)
# create or update the user
user = user_api_client.get_user_by_uuid_or_email(user_uuid, user_email)
if user is None:
user = User.register(
@@ -170,9 +211,63 @@ def set_up_your_profile():
password=str(uuid.uuid4()),
auth_type="sms_auth",
)
debug_msg(f"registered user {form.name.data} with email {user_email}")
else:
user.update(mobile_number=form.mobile_number.data, name=form.name.data)
debug_msg(f"updated user {form.name.data}")
# activate the user
user = user_api_client.get_user_by_uuid_or_email(user_uuid, user_email)
activate_user(user["id"])
return redirect(url_for("main.show_accounts_or_dashboard", next=redirect_url))
debug_msg("activated user")
usr = User.from_id(user["id"])
usr.add_to_service(
invite_data["service_id"],
invite_data["permissions"],
invite_data["folder_permissions"],
invite_data["from_user_id"],
)
debug_msg(
f"Added user {usr.email_address} to service {invite_data['service_id']}"
)
return redirect(url_for("main.show_accounts_or_dashboard"))
elif login_gov_error:
current_app.logger.error(f"login.gov error: {login_gov_error}")
abort(403)
# we take two trips through this method, but should only hit this
# line on the first trip. On the second trip, we should get redirected
# to the accounts page because we have successfully registered.
return render_template("views/set-up-your-profile.html", form=form)
def get_invited_user_email_address(invited_user_id):
# InvitedUser is an unhashable type and hard to mock in tests
# so this convenience method is a workaround for that
invited_user = InvitedUser.by_id(invited_user_id)
return invited_user.email_address
def invited_user_accept_invite(invited_user_id):
invited_user = InvitedUser.by_id(invited_user_id)
if invited_user.status == "expired":
current_app.logger.error("User invitation has expired")
flash(
"Your invitation has expired; please contact the person who invited you for additional help."
)
abort(401)
if invited_user.status == "cancelled":
current_app.logger.error("User invitation has been cancelled")
flash(
"Your invitation is no longer valid; please contact the person who invited you for additional help."
)
abort(401)
invited_user.accept_invite()
def debug_msg(msg):
current_app.logger.debug(hilite(msg))

View File

@@ -1,9 +1,19 @@
from pipes import quote
import time
import uuid
from string import ascii_uppercase
from zipfile import BadZipFile
from flask import abort, flash, redirect, render_template, request, session, url_for
from flask import (
abort,
current_app,
flash,
redirect,
render_template,
request,
session,
url_for,
)
from flask_login import current_user
from markupsafe import Markup
from notifications_python_client.errors import HTTPError
@@ -31,7 +41,12 @@ from app.s3_client.s3_csv_client import (
s3upload,
set_metadata_on_csv_upload,
)
from app.utils import PermanentRedirect, should_skip_template_page, unicode_truncate
from app.utils import (
PermanentRedirect,
hilite,
should_skip_template_page,
unicode_truncate,
)
from app.utils.csv import Spreadsheet, get_errors_for_csv
from app.utils.templates import get_template
from app.utils.user import user_has_permissions
@@ -79,6 +94,7 @@ def get_example_csv_rows(template, use_example_as_example=True, submitted_fields
)
@user_has_permissions("send_messages", restrict_admin_usage=True)
def send_messages(service_id, template_id):
print(hilite("top of send_messages"))
notification_count = service_api_client.get_notification_count(service_id)
remaining_messages = current_service.message_limit - notification_count
@@ -470,7 +486,8 @@ def send_one_off_step(service_id, template_id, step_index):
)
def _check_messages(service_id, template_id, upload_id, preview_row):
def _check_messages(service_id, template_id, upload_id, preview_row, **kwargs):
print(hilite("top of _check_messages"))
try:
# The happy path is that the job doesnt already exist, so the
# API will return a 404 and the client will raise HTTPError.
@@ -510,11 +527,7 @@ def _check_messages(service_id, template_id, upload_id, preview_row):
show_recipient=False,
email_reply_to=email_reply_to,
sms_sender=sms_sender,
)
simplifed_template = get_template(
db_template,
current_service,
show_recipient=False,
**kwargs,
)
allow_list = []
@@ -535,7 +548,7 @@ def _check_messages(service_id, template_id, upload_id, preview_row):
allow_list = None
recipients = RecipientCSV(
contents,
template=template or simplifed_template,
template=template,
max_initial_rows_shown=50,
max_errors_shown=50,
guestlist=allow_list,
@@ -569,9 +582,6 @@ def _check_messages(service_id, template_id, upload_id, preview_row):
if preview_row < len(recipients) + 2:
template.values = recipients[preview_row - 2].recipient_and_personalisation
simplifed_template.values = recipients[
preview_row - 2
].recipient_and_personalisation
elif preview_row > 2:
abort(404)
@@ -599,7 +609,6 @@ def _check_messages(service_id, template_id, upload_id, preview_row):
service_id, template.id, db_template["version"], original_file_name
),
template_id=template_id,
simplifed_template=simplifed_template,
)
@@ -614,6 +623,7 @@ def _check_messages(service_id, template_id, upload_id, preview_row):
@user_has_permissions("send_messages", restrict_admin_usage=True)
def check_messages(service_id, template_id, upload_id, row_index=2):
data = _check_messages(service_id, template_id, upload_id, row_index)
print(hilite(f"data after checking messages: \n {data}"))
data["allowed_file_extensions"] = Spreadsheet.ALLOWED_FILE_EXTENSIONS
if (
@@ -658,7 +668,9 @@ def check_messages(service_id, template_id, upload_id, row_index=2):
@user_has_permissions("send_messages", restrict_admin_usage=True)
def preview_job(service_id, template_id, upload_id, row_index=2):
session["scheduled_for"] = request.form.get("scheduled_for", "")
data = _check_messages(service_id, template_id, upload_id, row_index)
data = _check_messages(
service_id, template_id, upload_id, row_index, force_hide_sender=True
)
return render_template(
"views/check/preview.html",
@@ -825,11 +837,11 @@ def send_one_off_to_myself(service_id, template_id):
def check_notification(service_id, template_id):
return render_template(
"views/notifications/check.html",
**_check_notification(service_id, template_id),
**_check_notification(service_id, template_id, show_recipient=True),
)
def _check_notification(service_id, template_id, exception=None):
def _check_notification(service_id, template_id, exception=None, **kwargs):
db_template = current_service.get_template_with_user_permission_or_403(
template_id, current_user
)
@@ -842,13 +854,9 @@ def _check_notification(service_id, template_id, exception=None):
template = get_template(
db_template,
current_service,
show_recipient=True,
email_reply_to=email_reply_to,
sms_sender=sms_sender,
)
simplifed_template = get_template(
db_template,
current_service,
**kwargs,
)
placeholders = fields_to_fill_in(template)
@@ -874,7 +882,6 @@ def _check_notification(service_id, template_id, exception=None):
back_link_from_preview=back_link_from_preview,
choose_time_form=choose_time_form,
**(get_template_error_dict(exception) if exception else {}),
simplifed_template=simplifed_template,
)
@@ -924,7 +931,9 @@ def preview_notification(service_id, template_id):
return render_template(
"views/notifications/preview.html",
**_check_notification(service_id, template_id),
**_check_notification(
service_id, template_id, show_recipient=False, force_hide_sender=True
),
scheduled_for=session["scheduled_for"],
recipient=recipient,
)
@@ -951,15 +960,31 @@ def send_notification(service_id, template_id):
values = []
for k, v in session["placeholders"].items():
keys.append(k)
values.append(v)
print(hilite(f"value: {v} type: {type(v)}"))
value_quotes = '"' + v + '"'
print(hilite(f"value with quotes: {value_quotes}"))
values.append(value_quotes)
data = ",".join(keys)
vals = ",".join(values)
data = f"{data}\r\n{vals}"
filename = f"one-off-{current_user.name}-{uuid.uuid4()}.csv"
filename = (
f"one-off-{uuid.uuid4()}.csv" # {current_user.name} removed from filename
)
my_data = {"filename": filename, "template_id": template_id, "data": data}
upload_id = s3upload(service_id, my_data)
# To debug messages that the user reports have not been sent, we log
# the csv filename and the job id. The user will give us the file name,
# so we can search on that to obtain the job id, which we can use elsewhere
# 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"
)
)
form = CsvUploadForm()
form.file.data = my_data
form.file.name = filename
@@ -1009,14 +1034,17 @@ def send_notification(service_id, template_id):
job_id=upload_id,
)
)
total = notifications["total"]
current_app.logger.info(
hilite(
f"job_id: {upload_id} has notifications: {total} and attempts: {attempts}"
)
)
return redirect(
url_for(
".view_job",
service_id=service_id,
job_id=upload_id,
from_job=upload_id,
notification_id=notifications["notifications"][0]["id"],
# used to show the final step of the tour (help=3) or not show
# a back link on a just sent one off notification (help=0)
help=request.args.get("help"),

View File

@@ -5,26 +5,26 @@ import uuid
import jwt
import requests
from flask import (
Markup,
Response,
abort,
current_app,
flash,
redirect,
render_template,
request,
session,
url_for,
)
from flask_login import current_user
from app import login_manager, user_api_client
from app.main import main
from app.main.forms import LoginForm
from app.main.views.index import error
from app.main.views.verify import activate_user
from app.models.user import InvitedUser, 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.time import is_less_than_days_ago
from app.utils.user import is_gov_user
from notifications_utils.url_safe_token import generate_token
@@ -63,6 +63,10 @@ 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(f"Error when getting access token {response.json()}")
raise KeyError(f"'access_token' {response.json()}")
access_token = response.json()["access_token"]
return access_token
@@ -84,98 +88,85 @@ def _do_login_dot_gov():
code = request.args.get("code")
state = request.args.get("state")
login_gov_error = request.args.get("error")
if code and state:
access_token = _get_access_token(code, state)
user_email, user_uuid = _get_user_email_and_uuid(access_token)
redirect_url = request.args.get("next")
if login_gov_error:
current_app.logger.error(f"login.gov error: {login_gov_error}")
raise Exception(f"Could not login with login.gov {login_gov_error}")
elif code and state:
# activate the user
try:
access_token = _get_access_token(code, state)
user_email, user_uuid = _get_user_email_and_uuid(access_token)
if not is_gov_user(user_email):
current_app.logger.error(
"invited user has a non-government email address."
)
flash("You must use a government email address.")
abort(403)
redirect_url = request.args.get("next")
user = user_api_client.get_user_by_uuid_or_email(user_uuid, user_email)
activate_user(user["id"])
# Check if the email needs to be revalidated
is_fresh_email = is_less_than_days_ago(
user["email_access_validated_at"], 90
)
if not is_fresh_email:
return verify_email(user, redirect_url)
usr = User.from_email_address(user["email_address"])
activate_user(usr.id)
except BaseException as be: # noqa B036
current_app.logger.error(be)
error(401)
return redirect(url_for("main.show_accounts_or_dashboard", next=redirect_url))
elif login_gov_error:
current_app.logger.error(f"login.gov error: {login_gov_error}")
raise Exception(f"Could not login with login.gov {login_gov_error}")
# end login.gov
def verify_email(user, redirect_url):
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")
return render_template(
"views/re-validate-email-sent.html", title=title, redirect_url=redirect_url
)
def _handle_e2e_tests(redirect_url):
current_app.logger.warning("E2E TESTS ARE ENABLED.")
current_app.logger.warning(
"If you are getting a 404 on signin, comment out E2E vars in .env file!"
)
user = user_api_client.get_user_by_email(os.getenv("NOTIFY_E2E_TEST_EMAIL"))
activate_user(user["id"])
return redirect(url_for("main.show_accounts_or_dashboard", next=redirect_url))
@main.route("/sign-in", methods=(["GET", "POST"]))
@hide_from_search_engines
def sign_in():
_do_login_dot_gov()
# If we have to revalidated the email, send the message
# via email and redirect to the "verify your email page"
# and don't proceed further with login
email_verify_template = _do_login_dot_gov()
if (
email_verify_template
and not isinstance(email_verify_template, Response)
and "Check your email" in email_verify_template
):
return email_verify_template
redirect_url = request.args.get("next")
if os.getenv("NOTIFY_E2E_TEST_EMAIL"):
current_app.logger.warning("E2E TESTS ARE ENABLED.")
current_app.logger.warning(
"If you are getting a 404 on signin, comment out E2E vars in .env file!"
)
user = user_api_client.get_user_by_email(os.getenv("NOTIFY_E2E_TEST_EMAIL"))
activate_user(user["id"])
return redirect(url_for("main.show_accounts_or_dashboard", next=redirect_url))
return _handle_e2e_tests(redirect_url)
current_app.logger.info(f"current user is {current_user}")
if current_user and current_user.is_authenticated:
if redirect_url and is_safe_redirect_url(redirect_url):
return redirect(redirect_url)
return redirect(url_for("main.show_accounts_or_dashboard"))
form = LoginForm()
current_app.logger.info("Got the login form")
password_reset_url = url_for(".forgot_password", next=request.args.get("next"))
if form.validate_on_submit():
user = User.from_email_address_and_password_or_none(
form.email_address.data, form.password.data
)
if user:
# add user to session to mark us as in the process of signing the user in
session["user_details"] = {"email": user.email_address, "id": user.id}
if user.state == "pending":
return redirect(
url_for("main.resend_email_verification", next=redirect_url)
)
if user.is_active:
if session.get("invited_user_id"):
invited_user = InvitedUser.from_session()
if user.email_address.lower() != invited_user.email_address.lower():
flash("You cannot accept an invite for another person.")
session.pop("invited_user_id", None)
abort(403)
else:
invited_user.accept_invite()
user.send_login_code()
if user.sms_auth:
return redirect(url_for(".two_factor_sms", next=redirect_url))
if user.email_auth:
return redirect(
url_for(".two_factor_email_sent", next=redirect_url)
)
# Vague error message for login in case of user not known, locked, inactive or password not verified
flash(
Markup(
(
f"The email address or password you entered is incorrect."
f"&ensp;<a href={password_reset_url} class='usa-link'>Forgot your password?</a>"
)
)
)
other_device = current_user.logged_in_elsewhere()
token = generate_token(
str(request.remote_addr),
current_app.config["SECRET_KEY"],
@@ -186,14 +177,9 @@ def sign_in():
if url is not None:
url = url.replace("NONCE", token)
url = url.replace("STATE", token)
return render_template(
"views/signin.html",
form=form,
again=bool(redirect_url),
other_device=other_device,
login_gov_enabled=True,
password_reset_url=password_reset_url,
initial_signin_url=url,
)

View File

@@ -32,7 +32,7 @@ def using_notify_nav():
"link": "main.trial_mode_new",
},
{
"name": "Pricing",
"name": "Tracking usage",
"link": "main.pricing",
},
{

View File

@@ -195,10 +195,10 @@ def check_tour_notification(service_id, template_id):
)
return render_template(
"views/notifications/check.html",
"views/notifications/preview.html",
template=template,
back_link=back_link,
help="2",
help="3",
)

View File

@@ -4,10 +4,9 @@ from flask import abort, current_app, flash, redirect, render_template, session,
from itsdangerous import SignatureExpired
from app import user_api_client
from app.extensions import redis_client
from app.main import main
from app.main.forms import TwoFactorForm
from app.models.user import InvitedOrgUser, InvitedUser, User
from app.models.user import User
from app.utils.login import redirect_to_sign_in
from notifications_utils.url_safe_token import check_token
@@ -66,59 +65,19 @@ def verify_email(token):
def activate_user(user_id):
user = User.from_id(user_id)
# This is the login.gov path
login_gov_invite_data = redis_client.get(f"service-invite-{user.email_address}")
if login_gov_invite_data:
login_gov_invite_data = json.loads(login_gov_invite_data.decode("utf8"))
# This is the deprecated path for organization invites where we get id from session
session["current_session_id"] = user.current_session_id
organization_id = session.get("organization_id")
activated_user = user.activate()
activated_user.login()
# TODO when login.gov is mandatory, get rid of the if clause, it is deprecated.
invited_user = InvitedUser.from_session()
if invited_user:
service_id = _add_invited_user_to_service(invited_user)
return redirect(url_for("main.service_dashboard", service_id=service_id))
elif login_gov_invite_data:
service_id = login_gov_invite_data["service_id"]
user.add_to_service(
service_id,
login_gov_invite_data["permissions"],
login_gov_invite_data["folder_permissions"],
login_gov_invite_data["from_user_id"],
)
return redirect(url_for("main.service_dashboard", service_id=service_id))
# TODO when login.gov is mandatory, git rid of the if clause, it is deprecated.
invited_org_user = InvitedOrgUser.from_session()
if invited_org_user:
user_api_client.add_user_to_organization(invited_org_user.organization, user_id)
elif redis_client.get(f"organization-invite-{user.email_address}"):
organization_id = redis_client.raw_get(
f"organization-invite-{user.email_address}"
)
user_api_client.add_user_to_organization(
organization_id.decode("utf8"), user_id
)
# TODO add org invites back in the new way
# organization_id = redis_client.get(
# f"organization-invite-{user.email_address}"
# )
# user_api_client.add_user_to_organization(
# organization_id.decode("utf8"), user_id
# )
organization_id = None
if organization_id:
return redirect(url_for("main.organization_dashboard", org_id=organization_id))
else:
activated_user = user.activate()
activated_user.login()
return redirect(url_for("main.add_service", first="first"))
def _add_invited_user_to_service(invitation):
user = User.from_id(session["user_id"])
service_id = invitation.service
user.add_to_service(
service_id,
invitation.permissions,
invitation.folder_permissions,
invitation.from_user.id,
)
return service_id

View File

@@ -390,7 +390,7 @@ class Service(JSONModel, SortByNameMixin):
def get_data_retention_item(self, id):
return next((dr for dr in self.data_retention if dr["id"] == id), None)
def get_days_of_retention(self, notification_type):
def get_days_of_retention(self, notification_type, number_of_days):
return next(
(
dr
@@ -398,7 +398,10 @@ class Service(JSONModel, SortByNameMixin):
if dr["notification_type"] == notification_type
),
{},
).get("days_of_retention", current_app.config["ACTIVITY_STATS_LIMIT_DAYS"])
).get(
"days_of_retention",
current_app.config["ACTIVITY_STATS_LIMIT_DAYS"].get(number_of_days),
)
@cached_property
def organization(self):

View File

@@ -140,9 +140,6 @@ class User(JSONModel, UserMixin):
set_by_id=set_by_id,
)
def logged_in_elsewhere(self):
return session.get("current_session_id") != self.current_session_id
def activate(self):
if self.is_pending:
user_data = user_api_client.activate_user(self.id)
@@ -196,7 +193,7 @@ class User(JSONModel, UserMixin):
@property
def is_authenticated(self):
return not self.logged_in_elsewhere() and super(User, self).is_authenticated
return super(User, self).is_authenticated
@property
def platform_admin(self):
@@ -674,10 +671,6 @@ class InvitedOrgUser(JSONModel):
class AnonymousUser(AnonymousUserMixin):
# set the anonymous user so that if a new browser hits us we don't error http://stackoverflow.com/a/19275188
def logged_in_elsewhere(self):
return False
@property
def default_organization(self):

View File

@@ -1,4 +1,4 @@
from datetime import datetime
from datetime import datetime, timezone
from app.extensions import redis_client
from app.notify_client import NotifyAdminAPIClient, _attach_current_user, cache
@@ -43,6 +43,28 @@ class ServiceAPIClient(NotifyAdminAPIClient):
params={"limit_days": limit_days},
)["data"]
def get_service_notification_statistics_by_day(
self, service_id, start_date=None, days=None
):
if start_date is None:
start_date = datetime.now().strftime("%Y-%m-%d")
return self.get(
"/service/{0}/statistics/{1}/{2}".format(service_id, start_date, days),
)["data"]
def get_user_service_notification_statistics_by_day(
self, service_id, user_id, start_date=None, days=None
):
if start_date is None:
start_date = datetime.now(timezone.utc).strftime("%Y-%m-%d")
return self.get(
"/service/{0}/statistics/user/{1}/{2}/{3}".format(
service_id, user_id, start_date, days
),
)["data"]
def get_services(self, params_dict=None):
"""
Retrieve a list of services.
@@ -497,5 +519,18 @@ class ServiceAPIClient(NotifyAdminAPIClient):
def get_global_notification_count(self, service_id):
return self.get("/service/{}/notification-count".format(service_id))
def get_service_invite_data(self, redis_key):
"""
Retrieve service invite_data.
"""
return self.get("/service/invite/redis/{0}".format(redis_key))
service_api_client = ServiceAPIClient()
# TODO, if we try to call get_service_invite_data directly
# from verify, app complains the method is not defined
# If we wrap it like this, the app can find it.
def retrieve_service_invite_data(redis_key):
return service_api_client.get_service_invite_data(redis_key)

View File

@@ -1,3 +1,5 @@
import os
import botocore
from boto3 import Session
from botocore.config import Config
@@ -29,6 +31,17 @@ def get_s3_object(
)
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:
# Exception: CREATED AT <MagicMock name='resource().Bucket().creation_date' id='4665562448'>
#
# raise Exception(f"CREATED AT {_s3.Bucket(bucket_name).creation_date}")
if os.getenv("NOTIFY_ENVIRONMENT") == "test":
teststr = str(s3.Bucket(bucket_name).creation_date).lower()
if "magicmock" not in teststr:
raise Exception(
"Test is not mocked, use @mock_aws or the relevant mocker.patch to avoid accessing S3"
)
return obj

View File

@@ -28,6 +28,7 @@ def get_csv_upload(service_id, upload_id):
def s3upload(service_id, filedata):
upload_id = str(uuid.uuid4())
bucket_name, file_location, access_key, secret_key, region = get_csv_location(
service_id, upload_id

View File

@@ -1,10 +1,17 @@
{% from "../components/banner.html" import banner %}
{% from "../components/components/skip-link/macro.njk" import usaSkipLink -%}
{% from "components/banner.html" import banner %}
{% from "components/components/skip-link/macro.njk" import usaSkipLink -%}
{% from "components/sub-navigation.html" import sub_navigation %}
<!DOCTYPE html>
<html lang="{{ htmlLang | default('en') }}" class="{{ htmlClasses }}">
{% include "new/components/head.html" %}
<head>
<title>
{% block pageTitle %}
{% block per_page_title %}{% endblock %} Notify.gov
{% endblock %}
</title>
{% include "new/components/head.html" %}
</head>
<body class="usa-template__body {{ bodyClasses }}">
<script nonce="{{ csp_nonce() }}">document.body.className = ((document.body.className) ? document.body.className + ' js-enabled' : 'js-enabled');</script>
{% block bodyStart %}
@@ -23,11 +30,10 @@
}) }}
{% endblock %}
{% block header %}
{% if current_user.is_authenticated %}
{% include 'new/components/usa_banner.html' %}
{% include 'new/components/header.html' %}
{% endif %}
{% include 'new/components/usa_banner.html' %}
{% include 'new/components/header.html' %}
{% endblock %}
{% block main %}
@@ -36,18 +42,17 @@
{% block backLink %}{% endblock %}
{% endblock %}
{% block mainClasses %}
<!-- notes set mainClasses = "margin-top-5 padding-bottom-5" where withoutnav_template was used and maybe templates that are using content_template -->
{% set mainClasses = "margin-top-5 padding-bottom-5" %}
<main class="{{ mainClasses }}" id="main-content" role="main">
{% endblock %}
{% block content %}
{% block flash_messages %}
<!-- flash_message.html was from the withoutnav_template and is only included on child templates that was using withoutnav_template. Now, we can add in flash_message blocks and include 'flash_messages.html' to child templates that was using withoutnav_template. This will help to eliminate the use of a whole other parent template. -->
{% include 'new/components/flash_messages.html' %}
{% endblock %}
{% block maincolumn_content %}
{% block fromContentTemplatetwoColumnGrid %}
<div class="grid-row">
{% if navigation_links %}
<div class="tablet:grid-col-2">
<div class="tablet:grid-col-2 margin-bottom-4">
{{ sub_navigation(navigation_links) }}
</div>
<div class="tablet:grid-col-10 padding-left-4 usa-prose site-prose">
@@ -57,8 +62,6 @@
{% block content_column_content %}{% endblock %}
</div>
</div>
<!-- content_column_content block is from the content_template.html. We do not need this template. We can consolidate and move it to the base.html template. We can call on this block where child templates were using the content_template.html -->
{% endblock %}
{% endblock %}
{% endblock %}
</main>

View File

@@ -1,4 +1,4 @@
{% extends "withoutnav_template.html" %}
{% extends "base.html" %}
{% block per_page_title %}Youre not authorised to see this page{% endblock %}
{% block maincolumn_content %}
<div class="grid-row">

View File

@@ -1,4 +1,4 @@
{% extends "withoutnav_template.html" %}
{% extends "base.html" %}
{% block per_page_title %}Youre not allowed to see this page{% endblock %}
{% block maincolumn_content %}
<div class="grid-row">

View File

@@ -1,4 +1,4 @@
{% extends "withoutnav_template.html" %}
{% extends "base.html" %}
{% block per_page_title %}Page not found{% endblock %}
{% block maincolumn_content %}
<div class="grid-row">

View File

@@ -1,4 +1,4 @@
{% extends "withoutnav_template.html" %}
{% extends "base.html" %}
{% block per_page_title %}Page not found{% endblock %}
{% block maincolumn_content %}
<div class="grid-row">

View File

@@ -1,4 +1,4 @@
{% extends "withoutnav_template.html" %}
{% extends "base.html" %}
{% block per_page_title %}Sorry, theres a problem with the service{% endblock %}
{% block maincolumn_content %}
<div class="grid-row">
@@ -7,7 +7,7 @@
Sorry, we can't deliver what you asked for right now.
</h1>
<p class="usa-body">
Please try again later or <a class="usa-link" href="mailto:notify-support@gsa.gov"></a>email us</a> for more information.</p>
Please try again later or <a class="usa-link" href="mailto:notify-support@gsa.gov">email us</a> for more information.</p>
</p>
</div>
</div>

View File

@@ -1,6 +1,4 @@
<head>
<meta charset="utf-8" />
<title>{% block pageTitle %}Notify.gov{% endblock %}</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="Reach people where they are with a text message platform built just for government">
<meta name="theme-color" media="(prefers-color-scheme: light)" content="f0f0f0" />
@@ -12,7 +10,7 @@
{# Ensure that older IE versions always render with the correct rendering engine #}
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
{% block headIcons %}
<link rel="shortcut icon" href="{{ assetPath | default('/assets') }}/images/favicon.ico" />
<link rel="icon" type="image/png" sizes="32x32" href="{{ assetPath | default('/assets') }}/images/favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="16x16" href="{{ assetPath | default('/assets') }}/images/favicon-16x16.png" />
@@ -22,25 +20,18 @@
<meta name="msapplication-TileColor" content="#da532c">
<link href="{{ assetPath | default('/assets') }}/images/notify-dark-favicon.png" rel="icon" media="(prefers-color-scheme: dark)">
<meta name="theme-color" content="#ffffff">
{% endblock %}
<link rel="stylesheet" media="screen" href="{{ asset_url('css/styles.css') }}" />
{% block extra_stylesheets %}{% endblock %}
{% block meta_format_detection %}
<meta name="format-detection" content="telephone=no">
{% endblock %}
{% block og_image %}
<meta property="og:title" content="Notify.gov">
<meta property="og:description" content="Reach people where they are with a text message platform built just for government">
<meta property="og:image" content="/static/images/notify-og-image.png">
{% endblock %}
{# google #}
<script type="text/javascript" src="{{ asset_url('js/gtm_head.js') }}"></script>
<meta name="google-site-verification" content="niWnSqImOWz6mVQTYqNb5tFK8HaKSB4b3ED4Z9gtUQ0" />
{% if g.hide_from_search_engines %}
<meta name="robots" content="noindex" />
{% endif %}
{% block head %}{% endblock %}
</head>

View File

@@ -1,25 +1,28 @@
{# setting navigation and secondarynavigation #}
{% set navigation = [
{"href": url_for("main.show_accounts_or_dashboard"), "text": "Current service", "active": header_navigation.is_selected('accounts-or-dashboard')},
{"href": url_for('main.get_started'), "text": "Using Notify", "active": header_navigation.is_selected('using_notify')},
{"href": url_for('main.features'), "text": "Features", "active": header_navigation.is_selected('features')},
{"href": url_for('main.support'), "text": "Contact us", "active": header_navigation.is_selected('support')}
] %}
{% if current_user.platform_admin %}
{% set navigation = navigation + [{"href": url_for('main.platform_admin_splash_page'), "text": "Platform admin", "active": header_navigation.is_selected('platform-admin')}] %}
{% else %}
{% set navigation = navigation + [{"href": url_for('main.user_profile'), "text": "User profile", "active": header_navigation.is_selected('user-profile')}] %}
{% endif %}
{% if current_service %}
{% set secondaryNavigation = [
{"href": url_for('main.service_settings', service_id=current_service.id), "text": "Settings", "active": secondary_navigation.is_selected('settings')},
{"href": url_for('main.sign_out'), "text": "Sign out"}
{% if current_user.is_authenticated %}
{% set navigation = [
{"href": url_for("main.show_accounts_or_dashboard"), "text": "Current service", "active": header_navigation.is_selected('accounts-or-dashboard')},
{"href": url_for('main.get_started'), "text": "Using Notify", "active": header_navigation.is_selected('using_notify')},
{"href": url_for('main.features'), "text": "Features", "active": header_navigation.is_selected('features')},
{"href": url_for('main.support'), "text": "Contact us", "active": header_navigation.is_selected('support')}
] %}
{% else %}
{% set secondaryNavigation = [{"href": url_for('main.sign_out'), "text": "Sign out"}] %}
{% if current_user.platform_admin %}
{% set navigation = navigation + [{"href": url_for('main.platform_admin_splash_page'), "text": "Platform admin", "active": header_navigation.is_selected('platform-admin')}] %}
{% else %}
{% set navigation = navigation + [{"href": url_for('main.user_profile'), "text": "User profile", "active": header_navigation.is_selected('user-profile')}] %}
{% endif %}
{% if current_service %}
{% set secondaryNavigation = [
{"href": url_for('main.service_settings', service_id=current_service.id), "text": "Settings", "active": secondary_navigation.is_selected('settings')},
{"href": url_for('main.sign_out'), "text": "Sign out"}
] %}
{% else %}
{% set secondaryNavigation = [{"href": url_for('main.sign_out'), "text": "Sign out"}] %}
{% endif %}
{% endif %}
{# usa header #}
<header class="usa-header usa-header--extended">
<div class="usa-nav-container">

View File

@@ -0,0 +1,30 @@
{% if help %}
{% include 'partials/tour.html' %}
{% else %}
<nav 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">
{% if current_user.has_permissions() %}
{% if current_user.has_permissions('view_activity') %}
<li class="usa-sidenav__item"><a class="{{ main_navigation.is_selected('dashboard') }}" href="{{ url_for('.service_dashboard', service_id=current_service.id) }}">Dashboard</a></li>
{% endif %}
{% if not current_user.has_permissions('view_activity') %}
<li class="usa-sidenav__item"><a class="{{ casework_navigation.is_selected('sent-messages') }}" href="{{ url_for('.view_notifications', service_id=current_service.id, status='sending,delivered,failed') }}">Sent messages</a></li>
{% endif %}
{% if current_user.has_permissions('manage_service', allow_org_user=True) %}
{# <li class="usa-sidenav__item"><a class="{{ main_navigation.is_selected('usage') }}" href="{{ url_for('.usage', service_id=current_service.id) }}">Usage</a></li> #}
{% endif %}
<!-- {% if current_user.has_permissions('manage_api_keys', 'manage_service') %}
<li class="usa-sidenav__item"><a class="{{ main_navigation.is_selected('settings') }}" href="{{ url_for('.service_settings', service_id=current_service.id) }}">Settings</a></li>
{% endif %} -->
{% if current_user.has_permissions('manage_api_keys') %}
<!-- <li><a class="usa-link{{ main_navigation.is_selected('api-integration') }}" href="{{ url_for('.api_integration', service_id=current_service.id) }}">API integration</a></li> -->
{% endif %}
{% elif current_user.has_permissions(allow_org_user=True) %}
<li class="usa-sidenav__item"><a class="usa-link{{ main_navigation.is_selected('usage') }}" href="{{ url_for('.usage', service_id=current_service.id) }}">Usage</a></li>
<li class="usa-sidenav__item"><a class="usa-link{{ main_navigation.is_selected('team-members') }}" href="{{ url_for('.manage_users', service_id=current_service.id) }}">Team members</a></li>
{% endif %}
</ul>
</nav>
{% endif %}

View File

@@ -0,0 +1,11 @@
<nav 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>
{% if current_user.platform_admin %}
<li class="usa-sidenav__item"><a class="usa-link{{ org_navigation.is_selected('settings') }}" href="{{ url_for('.organization_settings', org_id=current_org.id) }}">Settings</a></li>
<li class="usa-sidenav__item"><a class="usa-link{{ org_navigation.is_selected('trial-services') }}" href="{{ url_for('.organization_trial_mode_services', org_id=current_org.id) }}">Trial mode services</a></li>
<li class="usa-sidenav__item"><a class="usa-link{{ org_navigation.is_selected('billing') }}" href="{{ url_for('.organization_billing', org_id=current_org.id) }}">Billing</a></li>
{% endif %}
</ul>
</nav>

View File

@@ -0,0 +1,11 @@
<nav class="navigation-service usa-breadcrumb">
<ol class="usa-breadcrumb__list">
<li class="usa-breadcrumb__list-item">
<span class="usa-breadcrumb__label"><a href="{{ url_for('.organizations') }}" class="usa-link navigation-organization-link">Organizations:</a></span>
</li>
<li class="usa-breadcrumb__list-item">
<span class="usa-breadcrumb__label">{{ current_org.name }}</span>
</li>
<a href="{{ url_for('main.choose_account') }}" class="usa-link navigation-service">Switch service</a>
</ol>
</nav>

View File

@@ -0,0 +1,15 @@
<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
(current_user.belongs_to_organization(current_service.organization_id) and current_service.live) %}
<a href="{{ url_for('.organization_dashboard', org_id=current_service.organization_id) }}" class="usa-link navigation-organization-link">{{ current_service.organization_name }}</a>
{% endif %}
{% endif %}
<div class="font-body-2xl text-bold">
{{ current_service.name }}
{% if not current_service.active %}
<span class="navigation-service-name navigation-service-type--suspended">Suspended</span>
{% endif %}
</div>
<a href="{{ url_for('main.choose_account') }}" class="usa-link">Switch service</a>
</div>

View File

@@ -1,41 +0,0 @@
{% extends "base.html" %}
{% block per_page_title %}
{% block service_page_title %}{% endblock %} {{ current_service.name }}
{% endblock %}
{% block main %}
<div class="grid-container">
{% block serviceNavigation %}
{% include "service_navigation.html" %}
{% endblock %}
<!-- The withnav_template can be used to replace the settings_template. when it comes to setting_template and withnav_template, this service_navigation.html is only used in withnav_template and in settings_template, it was not used. That is one out of the two differences between settings template and withnav template. Child templates that extends settings_template, include the block serviceNavigation but leave it empty. Within the app, the only pages settings_template.html is used: manage-users.html, service-settings.html, and user-profile.html -->
<div class="grid-row margin-top-5">
{% if help %}
<div class="grid-col-3">
{% else %}
<div class="grid-col-3">
{% endif %}
{% block sideNavigation %}
{% include "main_nav.html" %}
<!-- include settings_nav.html for child templates that used settings_template -->
{% endblock %}
</div>
{% if help %}
<div class="grid-col-8">
{% else %}
<div class="grid-col-9 padding-left-4">
{% endif %}
{% block beforeContent %}
{% block backLink %}{% endblock %}
{% endblock %}
<main id="main-content" role="main" class="usa-prose site-prose margin-bottom-10">
{% block content %}
{% include 'flash_messages.html' %}
{% block maincolumn_content %}{% endblock %}
{% endblock %}
</main>
</div>
</div>
</div>
{% endblock %}

View File

@@ -6,33 +6,31 @@ This document serves as a glossary for the templates directory structure of the
## Directory Structure
- `/templates`
- `base.html`: The main base template from which all other templates inherit. This template is a combination of `main_template`, `admin_template`, `withoutnav_template`, `settings_templates`, and `content_template`.
- `base.html`: The main base template from which all other templates inherit. This template is a combination of `main_template`, `admin_template`, `withoutnav_template`, and `content_template`.
- **/layouts**: Contains shared layouts used across the site. Simply put, it defines the overall structure or skeleton of the application (less frequently revised).
- `withnav_template.html`: A variation of the base layout that includes a sidebar.
- `org_template.html`: A variaton of the withnav_template
- `withnav_template.html`: A variation of org_template and settings_template that includes a sidebar.
- **/components**: Houses reusable UI components that can be included in multiple templates and can be tailored with different content or links depending on the context.(more frequently revised or customized)
- `head.html`: Template for the site's <head>, included in `base.html`.
- `header.html`: Template for the site's header, included in `base.html`.
- `footer.html`: Template for the site's footer, included in `base.html`.
- `settings_navigation.html`: The settings navigation used in `withnav_template.html` that previously extended `settings_template.html`.
- `org_nav.html`: The organization's navigation used solely in `org_template.html`.
- `main_nav.html`: The main navigation used in `withnav_template.html`
- `service_navigation.html`: The service navigation used in `withnav_template.html`. In withnav_template.html, the `serviceNavigation` block will be left empty in any child templates that previously extended `settings_template.html`.
- **/views** (or **/pages**): Individual page templates that use the base layouts, components, and partials to present content.
### Best Practices
- Use **inheritance** `{% extends %}` to build on base layouts.
- Employ **components** `{% include %}` for reusable UI elements to keep the code DRY and facilitate easier updates.
### Observation Notes
- The macro-options.json files in the header and footer component act as structural guides. They aren't directly used as data passed to the usaFooter function/macro. Instead, these files outline the expected properties and provide a description of their purpose. The `usaFooter` macro component is currently only invoked in the `admin_template`, which will eventually serve as the `base.html` template. This will simplify the approach when we change the footer macros to componenets by eliminating the need to dynamically pass this data from the base.html template. This is also true for `usaHeader` macro component.
- Employ **components** `{% include %}` for reusable UI elements.
### Old Layout Templates We Don't Need
- withoutnav_template.html Delete
- main_template.html Delete
- withoutnav_template.html Delete, it is now apart of base.html
- main_template.html Delete, it is now apart of base.html
- settings_templates.html `withnav_template` can be used to replace `settings_template`.
- settings_nav.html (move to /new/navigation directory)
- main_nav.html (move to /new/navigation directory)
- service_navigation.html (move to /new/navigation directory)
- org_template, could be under it's own directory called /layout/organization
- org_nav.html (move to /new/navigation directory)
- content_template.html Delete
- settings_nav.html (move to /components/ directory)
- main_nav.html (move to /components/ directory)
- service_navigation.html (move to /components/ directory)
- org_template, Delete, it is now apart of withnav_template.html
- org_nav.html (move to /components/ directory)
- content_template.html Delete, it is now apart of base.html

View File

@@ -291,10 +291,12 @@
{% block bodyEnd %}
{% block extra_javascripts %}
{% endblock %}
<!--[if gt IE 8]><!-->
<script type="text/javascript" src="{{ asset_url('javascripts/all.js') }}"></script>
<script type="text/javascript" src="{{ asset_url('js/uswds.min.js') }}"></script>
<!--<![endif]-->
{% endblock %}

View File

@@ -1,4 +1,4 @@
{% extends "withoutnav_template.html" %}
{% extends "base.html" %}
{% from "components/sub-navigation.html" import sub_navigation %}
{% from "components/page-header.html" import page_header %}

View File

@@ -1,3 +1,4 @@
{# This template is an old version #}
{% if help %}
{% include 'partials/tour.html' %}
{% else %}

View File

@@ -1,3 +1,4 @@
{# This template is an old version #}
<nav class="navigation">
<ul>
<li><a class="usa-link{{ org_navigation.is_selected('dashboard') }}" href="{{ url_for('.organization_dashboard', org_id=current_org.id) }}">Usage</a></li>

View File

@@ -1,3 +1,4 @@
{# This template is an old version #}
{% macro navigation_service_name(service) %}
<div class="font-body-2xl text-bold">
{{ service.name }}

View File

@@ -0,0 +1,17 @@
{# This template is an old version #}
{% if help %}
{% include 'partials/tour.html' %}
{% else %}
<nav class="nav">
<ul class="usa-sidenav">
{# {% if current_user.has_permissions() %} #}
<li class="usa-sidenav__item"><a class="{{ main_navigation.is_selected('settings') }}"
href="{{ url_for('main.service_settings', service_id=current_service.id) }}">General</a></li>
<li class="usa-sidenav__item"><a class="{{ main_navigation.is_selected('user-profile') }}"
href="{{ url_for('main.user_profile', service_id=current_service.id) }}">User profile</a></li>
<li class="usa-sidenav__item"><a class="{{ main_navigation.is_selected('team-members') }}"
href="{{ url_for('main.manage_users', service_id=current_service.id) }}">Team members</a></li>
{# {% endif %} #}
</ul>
</nav>
{% endif %}

View File

@@ -1,3 +1,4 @@
{# This template is an old version #}
{% extends "admin_template.html" %}
{% block per_page_title %}

View File

@@ -0,0 +1,36 @@
{# This template is an old version #}
{% extends "admin_template.html" %}
{% block per_page_title %}
{% block service_page_title %}{% endblock %} {{ current_service.name }}
{% endblock %}
{% block main %}
<div class="grid-container">
{% include "service_navigation.html" %}
<div class="grid-row margin-top-5">
{% if help %}
<div class="tablet:grid-col-3">
{% else %}
<div class="tablet:grid-col-3">
{% endif %}
{% include "main_nav.html" %}
</div>
{% if help %}
<div class="grid-col-8">
{% else %}
<div class="tablet:grid-col-9 tablet:padding-left-4">
{% endif %}
{% block beforeContent %}
{% block backLink %}{% endblock %}
{% endblock %}
<main id="main-content" role="main" class="usa-prose site-prose margin-bottom-10">
{% block content %}
{% include 'flash_messages.html' %}
{% block maincolumn_content %}{% endblock %}
{% endblock %}
</main>
</div>
</div>
</div>
{% endblock %}

View File

@@ -1,4 +1,4 @@
{% extends "admin_template.html" %}
{% extends "base.html" %}
{% set mainClasses = "margin-top-5 padding-bottom-5" %}

View File

@@ -1,35 +0,0 @@
{% extends "admin_template.html" %}
{% block per_page_title %}
{% block org_page_title %}{% endblock %} {{ current_org.name }}
{% endblock %}
{% block main %}
<div class="grid-container">
<div class="navigation-service usa-breadcrumb">
{% if current_user.platform_admin %}
<a href="{{ url_for('.organizations') }}" class="usa-link navigation-organization-link">Organizations</a>
{% endif %}
<div class="navigation-service">
{{ current_org.name }}
</div>
<a href="{{ url_for('main.choose_account') }}" class="usa-link navigation-service">Switch service</a>
</div>
<div class="grid-row">
<div class="grid-col-3">
{% include "org_nav.html" %}
</div>
<div class="grid-col-9">
{% block beforeContent %}
{% block backLink %}{% endblock %}
{% endblock %}
<main class="main" id="main-content" role="main" >
{% block content %}
{% include 'flash_messages.html' %}
{% block maincolumn_content %}{% endblock %}
{% endblock %}
</main>
</div>
</div>
</div>
{% endblock %}

View File

@@ -1,4 +1,4 @@
{% extends "content_template.html" %}
{% extends "base.html" %}
{% from "components/service-link.html" import service_link %}
{% from "components/content-metadata.html" import content_metadata %}
@@ -168,7 +168,7 @@
<p>
The following content on the <a class="usa-link" href="https://status.notifications.service.gov.uk/">Notify status page</a> is not compliant with the WCAG version 2.1 AA standard:
</p>
</p>
<ul class="usa-list">
<li>an incorrect heading hierarchy which fails <a class="usa-link" href="https://www.w3.org/TR/WCAG21/#info-and-relationships">success criterion 1.3.1: info and relationships</a></li>

View File

@@ -1,4 +1,4 @@
{% extends "withoutnav_template.html" %}
{% extends "base.html" %}
{% from "components/page-header.html" import page_header %}
{% from "components/page-footer.html" import page_footer %}
{% from "components/form.html" import form_wrapper %}

View File

@@ -1,4 +1,4 @@
{% extends "withoutnav_template.html" %}
{% extends "base.html" %}
{% from "components/page-header.html" import page_header %}
{% from "components/page-footer.html" import page_footer %}
{% from "components/form.html" import form_wrapper %}

View File

@@ -1,4 +1,4 @@
{% extends "withoutnav_template.html" %}
{% extends "base.html" %}
{% block per_page_title %}The invitation you were sent has been cancelled{% endblock %}
{% block maincolumn_content %}
<div class="grid-row">

View File

@@ -1,4 +1,4 @@
{% extends "withoutnav_template.html" %}
{% extends "base.html" %}
{% block per_page_title %}
Check your email

View File

@@ -21,14 +21,14 @@
{{ page_header('Preview') }}
<div>
<p class="sms-message-scheduler">Scheduled: {{ scheduled_for |format_datetime_normal if scheduled_for else 'Now'}}</p>
<p class="sms-message-scheduler">Scheduled: {{ scheduled_for |format_datetime_scheduled_notification if scheduled_for else 'Now'}}</p>
<p class="sms-message-file-name">File: {{original_file_name}}</p>
<p class="sms-message-template">Template: {{template.name}}</p>
<p class="sms-message-sender" >From: {{ template.sender }}</p>
</div>
<h2 id="{{ file_contents_header_id }}">Message</h2>
<div class="preview-message"> {{ simplifed_template|string }}</div>
<div class="preview-message"> {{ template|string }}</div>
{% if not request.args.from_test %}
<h2>Recipients list</h2>
<div>

View File

@@ -1,4 +1,4 @@
{% extends "withoutnav_template.html" %}
{% extends "base.html" %}
{% from "components/components/button/macro.njk" import usaButton %}
{% macro service_list(

View File

@@ -22,6 +22,8 @@
Messages sent
</h2>
<!-- <button id="sevenDaysButton">7 Days</button>
<canvas id="myChart"></canvas> -->
{{ ajax_block(partials, updates_url, 'inbox') }}
{{ ajax_block(partials, updates_url, 'totals') }}
@@ -59,7 +61,7 @@
{% set notification = job.notifications[0] %}
<tr class="table-row" id="{{ job.job_id }}">
<td class="table-field file-name">
{{ notification.job.original_file_name if notification.job.original_file_name else 'Manually entered number'}}
{{ notification.job.original_file_name[:12] if notification.job.original_file_name else 'Manually entered number'}}
<br>
<a class="usa-link file-list-filename" href="{{ job.view_job_link }}">View Batch</a>
</td>

View File

@@ -1,4 +1,4 @@
{% extends "content_template.html" %}
{% extends "base.html" %}
{% block per_page_title %}
Documentation

View File

@@ -1,4 +1,4 @@
{% extends "withoutnav_template.html" %}
{% extends "base.html" %}
{% from "components/page-header.html" import page_header %}
{% from "components/page-footer.html" import page_footer %}

View File

@@ -1,4 +1,4 @@
{% extends "withoutnav_template.html" %}
{% extends "base.html" %}
{% from "components/page-footer.html" import page_footer %}
{% block per_page_title %}

View File

@@ -1,4 +1,4 @@
{% extends "withoutnav_template.html" %}
{% extends "base.html" %}
{% from "components/components/button/macro.njk" import usaButton %}
{% block per_page_title %}

View File

@@ -1,4 +1,4 @@
{% extends "content_template.html" %}
{% extends "base.html" %}
{% from "components/table.html" import mapping_table, row, text_field, edit_field, field with context %}
{% from "components/sub-navigation.html" import sub_navigation %}
{% from "components/service-link.html" import service_link %}

View File

@@ -1,4 +1,4 @@
{% extends "content_template.html" %}
{% extends "base.html" %}
{% from "components/table.html" import mapping_table, row, text_field, edit_field, field with context %}
{% from "components/service-link.html" import service_link %}

View File

@@ -1,4 +1,4 @@
{% extends "withoutnav_template.html" %}
{% extends "base.html" %}
{% from "components/page-footer.html" import page_footer %}
{% from "components/form.html" import form_wrapper %}

View File

@@ -1,4 +1,4 @@
{% extends "content_template.html" %}
{% extends "base.html" %}
{% from "components/table.html" import mapping_table, row, text_field, edit_field, field with context %}
{% from "components/sub-navigation.html" import sub_navigation %}
{% from "components/components/details/macro.njk" import usaDetails %}

View File

@@ -1,4 +1,4 @@
{% extends "content_template.html" %}
{% extends "base.html" %}
{% from "components/service-link.html" import service_link %}
{% block per_page_title %}

View File

@@ -1,4 +1,4 @@
{% extends "content_template.html" %}
{% extends "base.html" %}
{% from "components/service-link.html" import service_link %}
{% block per_page_title %}

View File

@@ -1,4 +1,4 @@
{% extends "content_template.html" %}
{% extends "base.html" %}
{% from "components/table.html" import mapping_table, row, text_field, edit_field, field with context %}
{% from "components/sub-navigation.html" import sub_navigation %}
{% from "components/service-link.html" import service_link %}

View File

@@ -1,4 +1,4 @@
{% extends "content_template.html" %}
{% extends "base.html" %}
{% block per_page_title %}
Send files by email

View File

@@ -1,5 +1,5 @@
{% from "components/table.html" import mapping_table, row, text_field, edit_field, field with context %}
{% extends "withoutnav_template.html" %}
{% extends "base.html" %}
{% block per_page_title %}
Integration testing

View File

@@ -1,4 +1,4 @@
{% extends "settings_template.html" %}
{% extends "withnav_template.html" %}
{% from "components/tick-cross.html" import tick_cross %}
{% from "components/live-search.html" import live_search %}
{% from "components/components/button/macro.njk" import usaButton %}
@@ -7,6 +7,12 @@
Team members
{% endblock %}
{% block serviceNavigation %}{% endblock %}
{% block sideNavigation %}
{% include "/new/components/settings_nav.html" %}
{% endblock %}
{% block maincolumn_content %}
<div class="button-flex-header">
@@ -31,67 +37,70 @@
<div class="user-list">
{% for user in users %}
<div class="user-list-item">
<h2 class="user-list-item-heading font-body-lg margin-top-0" title="{{ user.email_address }}">
{%- if user.name -%}
<span class="heading-small live-search-relevant">{{ user.name }}</span>
{%- endif -%}
{%- if user.status == 'pending' -%}
<span class="live-search-relevant">{{ user.email_address }}</span><span class="hint">(invited)</span>
{%- elif user.status == 'cancelled' -%}
<span class="live-search-relevant">{{ user.email_address }}</span><span class="hint">(cancelled invite)</span>
{%- elif user.status == 'expired' -%}
<span class="live-search-relevant">{{ user.email_address }}</span><span class="hint">(expired invite)</span>
{%- elif user.id == current_user.id -%}
<span class="live-search-relevant"></span><span class="hint">(you)</span>
{% else %}
<span class="live-search-relevant">{{ user.email_address }}</span>
{% endif %}
</h2>
<h3 class="margin-bottom-0">Permissions</h3>
<ul class="tick-cross-list-permissions">
{% for permission, label in permissions %}
{{ tick_cross(
user.has_permission_for_service(current_service.id, permission),
label
) }}
{% endfor %}
</ul>
{# only show if the service has folders #}
{% if current_service.all_template_folders %}
<p class="usa-body tick-cross-list-hint">
{% set folder_count = user.template_folders_for_service(current_service) | length %}
{% if folder_count == 0 %}
Cannot see any folders
{% elif folder_count != current_service.all_template_folders | length %}
Can see {{ folder_count }} folder{% if folder_count > 1 %}s{% endif %}
{% if user.status != 'cancelled' %}
<div class="user-list-item">
<h2 class="user-list-item-heading font-body-lg margin-top-0" title="{{ user.email_address }}">
{%- if user.name -%}
<span class="heading-small live-search-relevant">{{ user.name }}</span>
{%- endif -%}
{%- if user.status == 'pending' -%}
<span class="live-search-relevant">{{ user.email_address }}</span><span class="hint">(invited)</span>
{%- elif user.status == 'cancelled' -%}
<span class="live-search-relevant">{{ user.email_address }}</span><span class="hint">(cancelled invite)</span>
{%- elif user.status == 'expired' -%}
<span class="live-search-relevant">{{ user.email_address }}</span><span class="hint">(expired invite)</span>
{%- elif user.id == current_user.id -%}
<span class="live-search-relevant"></span><span class="hint">(you)</span>
{% else %}
Can see all folders
{% endif%}
</p>
{% endif %}
{% if current_service.has_permission('email_auth') %}
<p class="usa-body tick-cross-list-hint">
Signs in with
{{ user.auth_type | format_auth_type(with_indefinite_article=True) }}
</p>
{% endif %}
{% if current_service.has_permission('email_auth') %}
<p class="usa-body tick-cross-list-hint">
Signs in with
{{ user.auth_type | format_auth_type(with_indefinite_article=True) }}
</p>
{% endif %}
{% if current_user.has_permissions('manage_service') %}
{% if user.status == 'pending' %}
<a class="user-list-edit-link usa-link" href="{{ url_for('.cancel_invited_user', service_id=current_service.id, invited_user_id=user.id)}}">Cancel invitation<span class="usa-sr-only"> for {{ user.email_address }}</span></a>
{% elif user.status == 'expired' %}
<a class="user-list-edit-link usa-link" href="{{ url_for('.resend_invite', service_id=current_service.id, invited_user_id=user.id)}}">Resend invite<span class="usa-sr-only"> for {{ user.email_address }}</span></a>
{% elif user.is_editable_by(current_user) %}
<a class="user-list-edit-link usa-link" href="{{ url_for('.edit_user_permissions', service_id=current_service.id, user_id=user.id)}}">Change details<span class="usa-sr-only"> for {{ user.name }} {{ user.email_address }}</span></a>
<span class="live-search-relevant">{{ user.email_address }}</span>
{% endif %}
</h2>
<h3 class="margin-bottom-0">Permissions</h3>
<ul class="tick-cross-list-permissions">
{% for permission, label in permissions %}
{{ tick_cross(
user.has_permission_for_service(current_service.id, permission),
label
) }}
{% endfor %}
</ul>
{# only show if the service has folders #}
{% if current_service.all_template_folders %}
<p class="usa-body tick-cross-list-hint">
{% set folder_count = user.template_folders_for_service(current_service) | length %}
{% if folder_count == 0 %}
Cannot see any folders
{% elif folder_count != current_service.all_template_folders | length %}
Can see {{ folder_count }} folder{% if folder_count > 1 %}s{% endif %}
{% else %}
Can see all folders
{% endif%}
</p>
{% endif %}
</div>
{% if current_service.has_permission('email_auth') %}
<p class="usa-body tick-cross-list-hint">
Signs in with
{{ user.auth_type | format_auth_type(with_indefinite_article=True) }}
</p>
{% endif %}
{% if current_service.has_permission('email_auth') %}
<p class="usa-body tick-cross-list-hint">
Signs in with
{{ user.auth_type | format_auth_type(with_indefinite_article=True) }}
</p>
{% endif %}
{% if current_user.has_permissions('manage_service') %}
{% if user.status == 'pending' or user.status == 'expired' %}
<a class="user-list-edit-link usa-link" href="{{ url_for('.cancel_invited_user', service_id=current_service.id, invited_user_id=user.id)}}">Cancel invitation<span class="usa-sr-only"> for {{ user.email_address }}</span></a>
{% endif %}
{% if user.status == 'expired' %}
<a class="user-list-edit-link usa-link" href="{{ url_for('.resend_invite', service_id=current_service.id, invited_user_id=user.id)}}">Resend invite<span class="usa-sr-only"> for {{ user.email_address }}</span></a>
{% elif user.is_editable_by(current_user) %}
<a class="user-list-edit-link usa-link" href="{{ url_for('.edit_user_permissions', service_id=current_service.id, user_id=user.id)}}">Change details<span class="usa-sr-only"> for {{ user.name }} {{ user.email_address }}</span></a>
{% endif %}
{% endif %}
</div>
{% endif %}
{% endfor %}
</div>

View File

@@ -1,4 +1,4 @@
{% extends "content_template.html" %}
{% extends "base.html" %}
{% from "components/table.html" import mapping_table, row, text_field %}
{% block per_page_title %}
@@ -9,9 +9,13 @@
<h1 class="font-body-2xl margin-bottom-3">Delivery status</h1>
<p>Notifys real-time dashboard lets you check the status of any message.</p>
<p>For <a class="usa-link" href="{{ url_for('main.security') }}">security</a>, this information is only available for seven days after a message has been sent. You can download a report, including a list of sent messages, for your own records.</p>
<p>This page describes the statuses you'll see when you're signed in to Notify.</p>
<p>Notify starts sending your text messages immediately. Each message is sent to its cell phone carrier, which attempts
delivery to the recipient. This process is often almost instantaneous, but can sometimes take a while if a phone is
unavailable. The carrier will continue to try to deliver the message for up to 72 hours.</p>
<p>The Notify dashboard provides a high-level view of the number of messages Sent, Pending, Delivered, and Failed. The
dashboard data starts to update about five minutes after a message is sent and will continue to update for four hours.</p>
<p>Delivery statuses reflect delivery to a specific <em>cell phone number</em>, not to a <em>person</em>. No status can confirm that a
specific person actually received or read the message.</p>
<!-- <p>If youre using the Notify API, read our <a class="usa-link" href="{{ url_for('.documentation') }}">documentation</a> for a list of API statuses.<p>
@@ -45,7 +49,7 @@
<p>Notify cannot tell you if your users open an email or click on the links in an email. We do not track open rates and click-throughs because there are privacy issues. Tracking emails without asking permission from users could breach General Data Protection Regulations (GDPR).</p> -->
<h2 id="text-message-statuses" class="heading-medium">Text messages</h2>
<div class="bottom-gutter-3-2">
<div class="margin-bottom-8">
{% call mapping_table(
caption='Message statuses text messages',
field_headings=['Status', 'Description'],
@@ -53,12 +57,14 @@
caption_visible=False
) %}
{% for message_status, description in [
('Total', 'The total number of messages that have been sent during the last seven days.'),
('Pending', 'Notify has sent the message to the provider. The provider will try to deliver the message to the recipient for up to 72 hours. Notify is waiting for delivery information.'),
('Scheduled', 'The total number of messages that have been scheduled to be sent at some future time.'),
('Canceled', 'Messages that were created and scheduled, but canceled prior to Sending.'),
('Total', 'The total number of messages that have been sent during the specified time.'),
('Pending', 'Notify has sent the message to the provider. The provider will try to deliver the message to the recipient for up to 72
hours. “Pending” indicates that Notify is waiting for delivery information.'),
('Delivered', 'The message was successfully delivered. Notify cannot tell you if a user has opened or read a message.'),
('Failed', 'The provider could not deliver the message. This can happen if the phone number was wrong or if the network operator
rejects the message. If youre sure that these phone numbers are correct, you should <a class="usa-link" href="/support">contact us</a>. If not, you should remove them from your database. Youll still be charged for text messages that
cannot be delivered.' | safe),
('Failed', 'The message could not be delivered.'),
('Process error / Delivery not attempted', 'If you receive a large number of process errors, please contact the Notify team.'),
] %}
{% call row() %}
{{ text_field(message_status) }}
@@ -67,5 +73,21 @@
{% endfor %}
{% endcall %}
</div>
<h2 class="heading-medium">About carrier statuses</h2>
<p>Sometimes Notify receives more detailed information from the carriers on the status of messages, and these can be found
in the downloadable reports. Not all carriers provide the same level of detail regarding delivery and some delivery
statutes have a slight variation in word choice. Notify includes this information in the reports to provide you as much
detail as possible. Remember, for <a class="usa-link" href="/features/security">security</a> purposes, detailed information is only available for seven days after a
message has been sent.</p>
<h2 class="heading-medium">Opting out</h2>
<p>A text recipient can opt out of receiving text messages from your phone number at any time by responding “STOP” or
“QUIT” or <a class="usa-link" href="https://docs.aws.amazon.com/pinpoint/latest/userguide/channels-sms-limitations-opt-out.html#settings-sms-self-opt-out-terms">one of several other keywords</a>. If they opt out,</p>
<ul>
<li>They may receive a response from their carrier stating that they will no longer receive text messages from that number.</li>
<li>Any subsequent messages sent to that number will not be delivered (unless the recipient opts back in by texting “START”
or “OPT-IN”).</li>
</ul>
<p>Notify.gov does not yet have a way to pull opt-out status and make it available in the UI for agencies to download.</p>
{% endblock %}

View File

@@ -1,4 +1,4 @@
{% extends "withoutnav_template.html" %}
{% extends "base.html" %}
{% from "components/page-footer.html" import page_footer %}
{% from "components/form.html" import form_wrapper %}

View File

@@ -64,10 +64,22 @@
{% if current_user.has_permissions('view_activity') %}
<p class="font-body-sm">
<a href="{{ download_link }}" download="download" class="usa-link">Download this report (<abbr title="Comma separated values">CSV</abbr>)</a>
<a href="{{ download_link_seven_day }}" download="download" class="usa-link">Download all data last 7 days (<abbr title="Comma separated values">CSV</abbr>)</a>
&emsp;
Data available for {{ partials.service_data_retention_days }} days
</p>
<p class="font-body-sm">
<a href="{{ download_link_five_day }}" download="download" class="usa-link">Download all data last 5 days (<abbr title="Comma separated values">CSV</abbr>)</a>
&emsp;
</p>
<p class="font-body-sm">
<a href="{{ download_link_three_day }}" download="download" class="usa-link">Download all data last 3 days (<abbr title="Comma separated values">CSV</abbr>)</a>
&emsp;
</p>
<p class="font-body-sm">
<a href="{{ download_link_today }}" download="download" class="usa-link">Download all data today (<abbr title="Comma separated values">CSV</abbr>)</a>
&emsp;
</p>
{% endif %}
{{ ajax_block(

View File

@@ -5,11 +5,21 @@
{% from "components/components/button/macro.njk" import usaButton %}
{% block service_page_title %}
{{ "Error" if error else "Preview" }}
{% if error %}
{{ "Error" }}
{% elif help %}
{{ "Example text message" }}
{% else %}
{{ "Preview" }}
{% endif %}
{% endblock %}
{% block backLink %}
{{ usaBackLink({ "href": back_link_from_preview }) }}
{% if help %}
{{ usaBackLink({ "href": back_link }) }}
{% else %}
{{ usaBackLink({ "href": back_link_from_preview }) }}
{% endif %}
{% endblock %}
{% block maincolumn_content %}
@@ -40,17 +50,24 @@
{% endcall %}
</div>
{% else %}
{{ page_header('Preview') }}
{{ page_header("Example text message" if help else "Preview") }}
{% endif %}
<div>
<p class="sms-message-scheduler">Scheduled: {{ scheduled_for |format_datetime_normal if scheduled_for else 'Now'}}</p>
<p class="sms-message-template">Template: {{template.name}}</p>
<p class="sms-message-sender" >From: {{ template.sender }}</p>
<p class="sms-message-sender" >To: {{ recipient }}</p>
</div>
<h2 id="{{ file_contents_header_id }}">Message</h2>
<div class="preview-message"> {{ simplifed_template|string }}</div>
{% if not help %}
<div>
<p class="sms-message-scheduler">Scheduled: {{ scheduled_for |format_datetime_scheduled_notification if scheduled_for else 'Now'}}</p>
<p class="sms-message-template">Template: {{template.name}}</p>
<p class="sms-message-sender" >From: {{ template.sender }}</p>
<p class="sms-message-sender" >To: {{ recipient }}</p>
</div>
{% endif %}
{% if not help %}
<h2 class="message-header">Message</h2>
{% endif %}
<div class="preview-message"> {{ template|string }}</div>
<div class="js-stick-at-bottom-when-scrolling">
<form method="post" enctype="multipart/form-data" action="{{url_for(

View File

@@ -1,4 +1,4 @@
{% extends "withoutnav_template.html" %}
{% extends "base.html" %}
{% from "components/page-header.html" import page_header %}
{% from "components/page-footer.html" import page_footer %}
{% from "components/form.html" import form_wrapper %}

View File

@@ -1,4 +1,4 @@
{% extends "org_template.html" %}
{% extends "withnav_template.html" %}
{% from "components/page-header.html" import page_header %}
{% block org_page_title %}

View File

@@ -2,7 +2,7 @@
{% from "components/big-number.html" import big_number %}
{% from "components/live-search.html" import live_search %}
{% from "components/pill.html" import pill %}
{% extends "org_template.html" %}
{% extends "withnav_template.html" %}
{% block org_page_title %}
Usage

View File

@@ -1,4 +1,4 @@
{% extends "org_template.html" %}
{% extends "withnav_template.html" %}
{% from "components/page-footer.html" import page_footer %}
{% from "components/page-header.html" import page_header %}
{% from "components/list-entry.html" import list_entry %}

View File

@@ -1,4 +1,4 @@
{% extends "org_template.html" %}
{% extends "withnav_template.html" %}
{% from "components/page-header.html" import page_header %}
{% from "components/page-footer.html" import page_footer %}
{% from "components/form.html" import form_wrapper %}

View File

@@ -1,4 +1,4 @@
{% extends "org_template.html" %}
{% extends "withnav_template.html" %}
{% from "components/page-header.html" import page_header %}
{% from "components/page-footer.html" import page_footer %}
{% from "components/form.html" import form_wrapper %}

View File

@@ -1,4 +1,4 @@
{% extends "org_template.html" %}
{% extends "withnav_template.html" %}
{% from "components/page-header.html" import page_header %}
{% from "components/page-footer.html" import page_footer %}
{% from "components/form.html" import form_wrapper %}

View File

@@ -1,4 +1,4 @@
{% extends "org_template.html" %}
{% extends "withnav_template.html" %}
{% from "components/page-footer.html" import page_footer %}
{% from "components/page-header.html" import page_header %}
{% from "components/form.html" import form_wrapper %}

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