diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index da9a18367..99ef30c3b 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -112,14 +112,14 @@ jobs: env: NOTIFY_ENVIRONMENT: scanning - name: Run OWASP Baseline Scan - uses: zaproxy/action-baseline@v0.7.0 + uses: zaproxy/action-baseline@v0.9.0 with: - docker_name: "owasp/zap2docker-stable" - target: "http://localhost:6012" + docker_name: 'ghcr.io/zaproxy/zaproxy:weekly' + target: 'http://localhost:6012' fail_action: true allow_issue_writing: false - rules_file_name: "zap.conf" - cmd_options: "-I" + rules_file_name: 'zap.conf' + cmd_options: '-I' a11y-scan: runs-on: ubuntu-20.04 diff --git a/.github/workflows/daily_checks.yml b/.github/workflows/daily_checks.yml index 31e370d04..babe60f44 100644 --- a/.github/workflows/daily_checks.yml +++ b/.github/workflows/daily_checks.yml @@ -50,9 +50,9 @@ jobs: env: NOTIFY_ENVIRONMENT: scanning - name: Run OWASP Full Scan - uses: zaproxy/action-full-scan@v0.4.0 + uses: zaproxy/action-full-scan@v0.7.0 with: - docker_name: 'owasp/zap2docker-stable' + docker_name: 'ghcr.io/zaproxy/zaproxy:weekly' target: 'http://localhost:6012' fail_action: true allow_issue_writing: false diff --git a/app/assets/images/product/02-reporting-no-chrome.svg b/app/assets/images/product/02-reporting-no-chrome.svg index e82ec8303..5c77c8e3d 100644 --- a/app/assets/images/product/02-reporting-no-chrome.svg +++ b/app/assets/images/product/02-reporting-no-chrome.svg @@ -75,7 +75,7 @@ - + diff --git a/app/main/forms.py b/app/main/forms.py index 4305d1626..0be785a5e 100644 --- a/app/main/forms.py +++ b/app/main/forms.py @@ -1980,7 +1980,7 @@ class TemplateAndFoldersSelectionForm(Form): None, [ # ('email', 'Email') if 'email' in available_template_types else None, - ("sms", "Text message") + ("sms", "Start with a blank template") if "sms" in available_template_types else None, ("copy-existing", "Copy an existing template") diff --git a/app/templates/components/table.html b/app/templates/components/table.html index 3b9b70570..199b9083c 100644 --- a/app/templates/components/table.html +++ b/app/templates/components/table.html @@ -1,5 +1,5 @@ {% macro mapping_table(caption='', field_headings=[], field_headings_visible=True, caption_visible=True, equal_length=False) -%} - +
diff --git a/app/templates/views/service-settings.html b/app/templates/views/service-settings.html index 3bac5b7b2..5751a6c8c 100644 --- a/app/templates/views/service-settings.html +++ b/app/templates/views/service-settings.html @@ -14,7 +14,6 @@ {% call mapping_table( caption='General', - field_headings=['Label', 'Value', 'Action'], field_headings_visible=False, caption_visible=False ) %} diff --git a/app/templates/views/usage.html b/app/templates/views/usage.html index 5f0654ff3..2b4be5415 100644 --- a/app/templates/views/usage.html +++ b/app/templates/views/usage.html @@ -20,15 +20,18 @@
-
+

Text messages

- {{ big_number(sms_sent, 'sent', smaller=True) }} - {{ big_number(sms_free_allowance, 'free allowance', smaller=True) }} + You have sent + {{ big_number(sms_sent, 'messages of your', smaller=True) }} + {{ big_number(sms_free_allowance, 'free messages allowance.', smaller=True) }} +
+ You have {% if sms_free_allowance > 0 %} - {{ big_number(sms_allowance_remaining, 'free allowance remaining', smaller=True) }} + {{ big_number(sms_allowance_remaining, 'messages remaining.', smaller=True) }} {% endif %} - {% for row in sms_breakdown %} + {# {% for row in sms_breakdown %} {% if row.charged_units > 0 %} {{ big_number( row.charged_units, @@ -36,7 +39,7 @@ smaller=True ) }} {% endif %} - {% endfor %} + {% endfor %} #}
{#
diff --git a/app/templates/views/user-profile.html b/app/templates/views/user-profile.html index b603b7828..b12be1019 100644 --- a/app/templates/views/user-profile.html +++ b/app/templates/views/user-profile.html @@ -13,7 +13,6 @@
{% call mapping_table( caption='Your profile', - field_headings=['Label', 'Value', 'Action'], field_headings_visible=False, caption_visible=False ) %} diff --git a/docs/downloadable_reports.md b/docs/downloadable_reports.md new file mode 100644 index 000000000..0436bb719 --- /dev/null +++ b/docs/downloadable_reports.md @@ -0,0 +1,32 @@ +# Downloadable reports for sent messages and how they work + +Downloadable reports related to sending messages are a little mysterious. They can have a variable number of columns, +some of which contain PII, and it is not immediately clear what drives what gets displayed. This is an explanation. + +## Downloadable reports for one-off messages + +When a user sends an ad-hoc message by typing in a phone number and sending, the downloadable report is only going to +show the bare minimum of columns. There will be a column that shows the name of what template was used, but otherwise +there will be nothing beyond the bare basics of the phone number and the time sent, etc. + +## Downloadable reports for jobs (uploaded csv files) + +When a user uploads a csv file -- creating a job -- the downloadable report becomes more complex and interesting. + +(Sample report) + +|Row number|Phone number|name|date|time|address|English|Spanish|Template|Type|Job|Status|Time| +|----------|------------|----|----|----|-------|-------|-------|--------|----|---|------|----| +|1|17169829002|Tim|10/16|2:00 PM|5678 Tom St.|no|yes|Appointment reminder - 1 week|sms|US Notify Demo CSV - Copy of Sheet1 (11).csv|Sending|2023-07-18 15:25:54| + + +In notifications_admin, in app.util.csv.py, there is a method called generate_notifications_csv(). + +It is using the service_id and job_id to look up the csv file in s3. It is then merging the standard +downloadable report (what we see in the one-off case mentioned above) with the custom csv data. + +This means that the PII displayed is mostly not stored in the database, but rather is stored in S3. + +The only PII stored in the database is the recipient's phone number, and that data is scrubbed. If the +sms message is delivered successfully, the phone number is scrubbed immediately. If the sms message +cannot be delivered, the PII will be scrubbed after seven days. \ No newline at end of file diff --git a/docs/notify-pilot-info.md b/docs/notify-pilot-info.md index 7e06ecc3e..c26bb113c 100644 --- a/docs/notify-pilot-info.md +++ b/docs/notify-pilot-info.md @@ -100,8 +100,8 @@ To get involved, email us at [tts-benefits-studio@gsa.gov](mailto:tts-benefits-s ## Notify.gov Demo +https://github.com/GSA/notifications-admin/assets/6556888/b87e12a3-6963-4fab-8124-7d0d2bb59901 -https://user-images.githubusercontent.com/6556888/208711970-eb70e618-fd13-4e38-bb61-3ddbf6e21a6d.mp4 diff --git a/docs/sprint-goals.md b/docs/sprint-goals.md index 04b848e6d..3321373e6 100644 --- a/docs/sprint-goals.md +++ b/docs/sprint-goals.md @@ -1,6 +1,16 @@ # Notify Sprint Goals Log -## Sprint: S (9/14/23) +## Sprint: T (9/28/23) + +| | Goals | Impact | +|-------------|-----------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------| +| Engineering | Finish retention and [quota strategy](https://github.com/GSA/notifications-api/issues/443), obtain access to [Login.gov sandbox](https://github.com/GSA/notifications-admin/issues/338) and begin integration work, tend to remaining low/medium bugs, request more toll-free [partner numbers](https://github.com/GSA/notifications-admin/issues/764), create a formal [manual qa script](https://github.com/GSA/notifications-admin/issues/809) | Greater sending volume for partners, start down path of ATO-required auth solution | +| UX | Perform observational and formal user feedback sessions with partners to inform flow and look/feel redesign, surface and remedy straightforward UI changes | Inform future features, flow, and feel of the application | +| Security | Complete pre-requisite documentation, start project planning timelines and control group deadlines | Aim to have package completed with enough time to allow for long assessment| +| Content | Work on cloud.gov pages IAA mod for content site | Enable an easy static website for future content | +| Ops | Onboard new back-end dev, get access to tools for them, meet with POC and team, get them oriented to start work | Add valuable dev resources to increase our capacity + +## Sprint: Snowy Owl (9/14/23) | | Goals | Impact | |-------------|-----------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------| diff --git a/poetry.lock b/poetry.lock index 92ddbb43f..8cda8034f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -3270,17 +3270,17 @@ files = [ [[package]] name = "urllib3" -version = "1.26.16" +version = "1.26.17" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" files = [ - {file = "urllib3-1.26.16-py2.py3-none-any.whl", hash = "sha256:8d36afa7616d8ab714608411b4a3b13e58f463aee519024578e062e141dce20f"}, - {file = "urllib3-1.26.16.tar.gz", hash = "sha256:8f135f6502756bde6b2a9b28989df5fbe87c9970cecaa69041edcce7f0589b14"}, + {file = "urllib3-1.26.17-py2.py3-none-any.whl", hash = "sha256:94a757d178c9be92ef5539b8840d48dc9cf1b2709c9d6b588232a055c524458b"}, + {file = "urllib3-1.26.17.tar.gz", hash = "sha256:24d6a242c28d29af46c3fae832c36db3bbebcc533dd1bb549172cd739c82df21"}, ] [package.extras] -brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] +brotli = ["brotli (==1.0.9)", "brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] diff --git a/tests/app/main/views/service_settings/test_service_settings.py b/tests/app/main/views/service_settings/test_service_settings.py index 22847e13c..71662b058 100644 --- a/tests/app/main/views/service_settings/test_service_settings.py +++ b/tests/app/main/views/service_settings/test_service_settings.py @@ -54,7 +54,7 @@ def mock_get_service_settings_page_common( ( create_active_user_with_permissions(), [ - "Label Value Action", + "", "Service name Test Service Change service name", "Sign-in method Text message code Change sign-in method", "Send text messages On Change your settings for sending text messages", @@ -66,7 +66,7 @@ def mock_get_service_settings_page_common( ( create_platform_admin_user(), [ - "Label Value Action", + "", "Service name Test Service Change service name", "Sign-in method Text message code Change sign-in method", "Send text messages On Change your settings for sending text messages", diff --git a/tests/app/main/views/test_dashboard.py b/tests/app/main/views/test_dashboard.py index 69f8115fe..4871caea8 100644 --- a/tests/app/main/views/test_dashboard.py +++ b/tests/app/main/views/test_dashboard.py @@ -819,7 +819,7 @@ def test_usage_page( assert normalize_spaces(unselected_nav_links[0].text) == "2010 to 2011 fiscal year" assert normalize_spaces(unselected_nav_links[1].text) == "2009 to 2010 fiscal year" - annual_usage = page.find_all("div", {"class": "grid-col-6"}) + annual_usage = page.find_all("div", {"class": "keyline-block"}) # annual stats are shown in two rows, each with three column; email is col 1 # email_column = normalize_spaces(annual_usage[0].text + annual_usage[2].text) @@ -827,13 +827,13 @@ def test_usage_page( # assert '1,000 sent' in email_column sms_column = normalize_spaces(annual_usage[0].text) - assert "Text messages" in sms_column - assert "251,800 sent" in sms_column - assert "250,000 free allowance" in sms_column - assert "0 free allowance remaining" in sms_column + assert ( + "You have sent 251,800 messages of your 250,000 free messages allowance. You have 0 messages remaining." + in sms_column + ) assert "$29.85 spent" not in sms_column - assert "1,500 at 1.65 pence" in sms_column - assert "300 at 1.70 pence" in sms_column + assert "1,500 at 1.65 pence" not in sms_column + assert "300 at 1.70 pence" not in sms_column @freeze_time("2012-03-31 12:12:12") @@ -862,12 +862,12 @@ def test_usage_page_no_sms_spend( service_id=SERVICE_ONE_ID, ) - annual_usage = page.find_all("div", {"class": "grid-col-6"}) + annual_usage = page.find_all("div", {"class": "keyline-block"}) sms_column = normalize_spaces(annual_usage[0].text) - assert "Text messages" in sms_column - assert "1,000 sent" in sms_column - assert "250,000 free allowance" in sms_column - assert "249,000 free allowance remaining" in sms_column + assert ( + "You have sent 1,000 messages of your 250,000 free messages allowance. You have 249,000 messages remaining." + in sms_column + ) assert "$0.00 spent" not in sms_column assert "pence per message" not in sms_column @@ -938,10 +938,13 @@ def test_usage_page_with_0_free_allowance( year=2020, ) - annual_usage = page.select("main .grid-col-6") + annual_usage = page.select("main .grid-col-12 .keyline-block") sms_column = normalize_spaces(annual_usage[0].text) - assert "0 free allowance" in sms_column + assert ( + "You have sent 251,800 messages of your 0 free messages allowance. You have" + in sms_column + ) assert "free allowance remaining" not in sms_column diff --git a/tests/app/main/views/test_templates.py b/tests/app/main/views/test_templates.py index 370d5b5f3..32b717460 100644 --- a/tests/app/main/views/test_templates.py +++ b/tests/app/main/views/test_templates.py @@ -310,7 +310,7 @@ def test_should_show_live_search_if_service_has_lots_of_folders( ], [ # 'Email', - "Text message", + "Start with a blank template", "Copy an existing template", ], ), @@ -323,7 +323,7 @@ def test_should_show_live_search_if_service_has_lots_of_folders( ], [ # 'Email', - "Text message", + "Start with a blank template", "Copy an existing template", ], ),
{{ caption }}