mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-09-10 18:22:37 -04:00
Merge branch 'main' of https://github.com/GSA/notifications-admin into notify-678
This commit is contained in:
@@ -112,14 +112,14 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
NOTIFY_ENVIRONMENT: scanning
|
NOTIFY_ENVIRONMENT: scanning
|
||||||
- name: Run OWASP Baseline Scan
|
- name: Run OWASP Baseline Scan
|
||||||
uses: zaproxy/action-baseline@v0.7.0
|
uses: zaproxy/action-baseline@v0.9.0
|
||||||
with:
|
with:
|
||||||
docker_name: "owasp/zap2docker-stable"
|
docker_name: 'ghcr.io/zaproxy/zaproxy:weekly'
|
||||||
target: "http://localhost:6012"
|
target: 'http://localhost:6012'
|
||||||
fail_action: true
|
fail_action: true
|
||||||
allow_issue_writing: false
|
allow_issue_writing: false
|
||||||
rules_file_name: "zap.conf"
|
rules_file_name: 'zap.conf'
|
||||||
cmd_options: "-I"
|
cmd_options: '-I'
|
||||||
|
|
||||||
a11y-scan:
|
a11y-scan:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
|
|||||||
@@ -50,9 +50,9 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
NOTIFY_ENVIRONMENT: scanning
|
NOTIFY_ENVIRONMENT: scanning
|
||||||
- name: Run OWASP Full Scan
|
- name: Run OWASP Full Scan
|
||||||
uses: zaproxy/action-full-scan@v0.4.0
|
uses: zaproxy/action-full-scan@v0.7.0
|
||||||
with:
|
with:
|
||||||
docker_name: 'owasp/zap2docker-stable'
|
docker_name: 'ghcr.io/zaproxy/zaproxy:weekly'
|
||||||
target: 'http://localhost:6012'
|
target: 'http://localhost:6012'
|
||||||
fail_action: true
|
fail_action: true
|
||||||
allow_issue_writing: false
|
allow_issue_writing: false
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 52 KiB |
+1
-1
@@ -1980,7 +1980,7 @@ class TemplateAndFoldersSelectionForm(Form):
|
|||||||
None,
|
None,
|
||||||
[
|
[
|
||||||
# ('email', 'Email') if 'email' in available_template_types else 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
|
if "sms" in available_template_types
|
||||||
else None,
|
else None,
|
||||||
("copy-existing", "Copy an existing template")
|
("copy-existing", "Copy an existing template")
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{% macro mapping_table(caption='', field_headings=[], field_headings_visible=True, caption_visible=True, equal_length=False) -%}
|
{% macro mapping_table(caption='', field_headings=[], field_headings_visible=True, caption_visible=True, equal_length=False) -%}
|
||||||
<table class="usa-table usa-table--borderless">
|
<table class="usa-table usa-table--borderless width-full">
|
||||||
<caption class="font-body-lg table-heading{{ ' usa-sr-only' if not caption_visible}}">
|
<caption class="font-body-lg table-heading{{ ' usa-sr-only' if not caption_visible}}">
|
||||||
{{ caption }}
|
{{ caption }}
|
||||||
</caption>
|
</caption>
|
||||||
|
|||||||
@@ -14,7 +14,6 @@
|
|||||||
|
|
||||||
{% call mapping_table(
|
{% call mapping_table(
|
||||||
caption='General',
|
caption='General',
|
||||||
field_headings=['Label', 'Value', 'Action'],
|
|
||||||
field_headings_visible=False,
|
field_headings_visible=False,
|
||||||
caption_visible=False
|
caption_visible=False
|
||||||
) %}
|
) %}
|
||||||
|
|||||||
@@ -20,15 +20,18 @@
|
|||||||
<div id='pill-selected-item'>
|
<div id='pill-selected-item'>
|
||||||
<div class='grid-row'>
|
<div class='grid-row'>
|
||||||
|
|
||||||
<div class='grid-col-6'>
|
<div class='grid-col-12'>
|
||||||
<h2 class='heading-small'>Text messages</h2>
|
<h2 class='heading-small'>Text messages</h2>
|
||||||
<div class="keyline-block">
|
<div class="keyline-block">
|
||||||
{{ big_number(sms_sent, 'sent', smaller=True) }}
|
You have sent
|
||||||
{{ big_number(sms_free_allowance, 'free allowance', smaller=True) }}
|
{{ big_number(sms_sent, 'messages of your', smaller=True) }}
|
||||||
|
{{ big_number(sms_free_allowance, 'free messages allowance.', smaller=True) }}
|
||||||
|
<br />
|
||||||
|
You have
|
||||||
{% if sms_free_allowance > 0 %}
|
{% 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 %}
|
{% endif %}
|
||||||
{% for row in sms_breakdown %}
|
{# {% for row in sms_breakdown %}
|
||||||
{% if row.charged_units > 0 %}
|
{% if row.charged_units > 0 %}
|
||||||
{{ big_number(
|
{{ big_number(
|
||||||
row.charged_units,
|
row.charged_units,
|
||||||
@@ -36,7 +39,7 @@
|
|||||||
smaller=True
|
smaller=True
|
||||||
) }}
|
) }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %} #}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{# <div class='grid-col-6'>
|
{# <div class='grid-col-6'>
|
||||||
|
|||||||
@@ -13,7 +13,6 @@
|
|||||||
<div class="body-copy-table">
|
<div class="body-copy-table">
|
||||||
{% call mapping_table(
|
{% call mapping_table(
|
||||||
caption='Your profile',
|
caption='Your profile',
|
||||||
field_headings=['Label', 'Value', 'Action'],
|
|
||||||
field_headings_visible=False,
|
field_headings_visible=False,
|
||||||
caption_visible=False
|
caption_visible=False
|
||||||
) %}
|
) %}
|
||||||
|
|||||||
@@ -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.
|
||||||
@@ -100,8 +100,8 @@ To get involved, email us at [tts-benefits-studio@gsa.gov](mailto:tts-benefits-s
|
|||||||
|
|
||||||
## Notify.gov Demo
|
## 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
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+11
-1
@@ -1,6 +1,16 @@
|
|||||||
# Notify Sprint Goals Log
|
# 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 |
|
| | Goals | Impact |
|
||||||
|-------------|-----------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------|
|
|-------------|-----------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
|
|||||||
Generated
+4
-4
@@ -3270,17 +3270,17 @@ files = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "urllib3"
|
name = "urllib3"
|
||||||
version = "1.26.16"
|
version = "1.26.17"
|
||||||
description = "HTTP library with thread-safe connection pooling, file post, and more."
|
description = "HTTP library with thread-safe connection pooling, file post, and more."
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
|
||||||
files = [
|
files = [
|
||||||
{file = "urllib3-1.26.16-py2.py3-none-any.whl", hash = "sha256:8d36afa7616d8ab714608411b4a3b13e58f463aee519024578e062e141dce20f"},
|
{file = "urllib3-1.26.17-py2.py3-none-any.whl", hash = "sha256:94a757d178c9be92ef5539b8840d48dc9cf1b2709c9d6b588232a055c524458b"},
|
||||||
{file = "urllib3-1.26.16.tar.gz", hash = "sha256:8f135f6502756bde6b2a9b28989df5fbe87c9970cecaa69041edcce7f0589b14"},
|
{file = "urllib3-1.26.17.tar.gz", hash = "sha256:24d6a242c28d29af46c3fae832c36db3bbebcc533dd1bb549172cd739c82df21"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.extras]
|
[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"]
|
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)"]
|
socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ def mock_get_service_settings_page_common(
|
|||||||
(
|
(
|
||||||
create_active_user_with_permissions(),
|
create_active_user_with_permissions(),
|
||||||
[
|
[
|
||||||
"Label Value Action",
|
"",
|
||||||
"Service name Test Service Change service name",
|
"Service name Test Service Change service name",
|
||||||
"Sign-in method Text message code Change sign-in method",
|
"Sign-in method Text message code Change sign-in method",
|
||||||
"Send text messages On Change your settings for sending text messages",
|
"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(),
|
create_platform_admin_user(),
|
||||||
[
|
[
|
||||||
"Label Value Action",
|
"",
|
||||||
"Service name Test Service Change service name",
|
"Service name Test Service Change service name",
|
||||||
"Sign-in method Text message code Change sign-in method",
|
"Sign-in method Text message code Change sign-in method",
|
||||||
"Send text messages On Change your settings for sending text messages",
|
"Send text messages On Change your settings for sending text messages",
|
||||||
|
|||||||
@@ -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[0].text) == "2010 to 2011 fiscal year"
|
||||||
assert normalize_spaces(unselected_nav_links[1].text) == "2009 to 2010 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
|
# 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)
|
# 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
|
# assert '1,000 sent' in email_column
|
||||||
|
|
||||||
sms_column = normalize_spaces(annual_usage[0].text)
|
sms_column = normalize_spaces(annual_usage[0].text)
|
||||||
assert "Text messages" in sms_column
|
assert (
|
||||||
assert "251,800 sent" in sms_column
|
"You have sent 251,800 messages of your 250,000 free messages allowance. You have 0 messages remaining."
|
||||||
assert "250,000 free allowance" in sms_column
|
in sms_column
|
||||||
assert "0 free allowance remaining" in sms_column
|
)
|
||||||
assert "$29.85 spent" not in sms_column
|
assert "$29.85 spent" not in sms_column
|
||||||
assert "1,500 at 1.65 pence" in sms_column
|
assert "1,500 at 1.65 pence" not in sms_column
|
||||||
assert "300 at 1.70 pence" in sms_column
|
assert "300 at 1.70 pence" not in sms_column
|
||||||
|
|
||||||
|
|
||||||
@freeze_time("2012-03-31 12:12:12")
|
@freeze_time("2012-03-31 12:12:12")
|
||||||
@@ -862,12 +862,12 @@ def test_usage_page_no_sms_spend(
|
|||||||
service_id=SERVICE_ONE_ID,
|
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)
|
sms_column = normalize_spaces(annual_usage[0].text)
|
||||||
assert "Text messages" in sms_column
|
assert (
|
||||||
assert "1,000 sent" in sms_column
|
"You have sent 1,000 messages of your 250,000 free messages allowance. You have 249,000 messages remaining."
|
||||||
assert "250,000 free allowance" in sms_column
|
in sms_column
|
||||||
assert "249,000 free allowance remaining" in sms_column
|
)
|
||||||
assert "$0.00 spent" not in sms_column
|
assert "$0.00 spent" not in sms_column
|
||||||
assert "pence per message" 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,
|
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)
|
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
|
assert "free allowance remaining" not in sms_column
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -310,7 +310,7 @@ def test_should_show_live_search_if_service_has_lots_of_folders(
|
|||||||
],
|
],
|
||||||
[
|
[
|
||||||
# 'Email',
|
# 'Email',
|
||||||
"Text message",
|
"Start with a blank template",
|
||||||
"Copy an existing template",
|
"Copy an existing template",
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -323,7 +323,7 @@ def test_should_show_live_search_if_service_has_lots_of_folders(
|
|||||||
],
|
],
|
||||||
[
|
[
|
||||||
# 'Email',
|
# 'Email',
|
||||||
"Text message",
|
"Start with a blank template",
|
||||||
"Copy an existing template",
|
"Copy an existing template",
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
Reference in New Issue
Block a user