Compare commits

...

15 Commits

Author SHA1 Message Date
Andrew Shumway
0d94e45da3 poetry lock 2024-05-21 11:41:27 -06:00
Andrew Shumway
3a6e5e9c2d Pull main 2024-05-20 10:25:43 -06:00
Andrew Shumway
ed827d0c29 Fix tests 2024-05-20 10:24:50 -06:00
Andrew Shumway
013154d5cf Refactor create/start job 2024-05-14 09:11:19 -06:00
Andrew Shumway
8a6802be8f pull main 2024-05-10 10:42:32 -06: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
Andrew Shumway
7108c5f1c8 pull main down 2024-04-30 10:06:49 -06: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
Andrew Shumway
ff1956ce70 Merge branch 'main' of https://github.com/GSA/notifications-admin 2024-04-24 09:29:58 -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
Andrew Shumway
fcf2e31911 Merge branch 'main' of https://github.com/GSA/notifications-admin 2024-04-17 10:42:18 -06:00
Andrew Shumway
2454a6e94b poetry lock 2024-04-15 10:38:27 -06:00
8 changed files with 86 additions and 52 deletions

View File

@@ -653,17 +653,18 @@ def preview_job(service_id, template_id, upload_id, row_index=2):
data = _check_messages(
service_id, template_id, upload_id, row_index, force_hide_sender=True
)
create_job(service_id, upload_id)
return render_template(
"views/check/preview.html",
scheduled_for=session["scheduled_for"],
scheduled_for=session.get("scheduled_for"),
**data,
)
@main.route("/services/<uuid:service_id>/start-job/<uuid:upload_id>", methods=["POST"])
@main.route("/services/<uuid:service_id>/create-job/<uuid:upload_id>", methods=["POST"])
@user_has_permissions("send_messages", restrict_admin_usage=True)
def start_job(service_id, upload_id):
def create_job(service_id, upload_id):
scheduled_for = session.pop("scheduled_for", None)
job_api_client.create_job(
upload_id,
@@ -671,8 +672,12 @@ def start_job(service_id, upload_id):
scheduled_for=scheduled_for,
)
session.pop("sender_id", None)
@main.route("/services/<uuid:service_id>/start-job/<uuid:upload_id>", methods=["POST"])
@user_has_permissions("send_messages", restrict_admin_usage=True)
def start_job(service_id, upload_id):
job_api_client.start_job(service_id, upload_id)
session.pop("sender_id", None)
return redirect(
url_for(
"main.view_job",
@@ -908,36 +913,7 @@ def preview_notification(service_id, template_id):
template_id=template_id,
)
)
session["scheduled_for"] = request.form.get("scheduled_for", "")
return render_template(
"views/notifications/preview.html",
**_check_notification(
service_id, template_id, show_recipient=False, force_hide_sender=True
),
scheduled_for=session["scheduled_for"],
recipient=recipient,
)
@main.route(
"/services/<uuid:service_id>/template/<uuid:template_id>/notification/check",
methods=["POST"],
)
@user_has_permissions("send_messages", restrict_admin_usage=True)
def send_notification(service_id, template_id):
scheduled_for = session.pop("scheduled_for", "")
recipient = get_recipient()
if not recipient:
return redirect(
url_for(
".send_one_off",
service_id=service_id,
template_id=template_id,
)
)
keys = []
values = []
for k, v in session["placeholders"].items():
@@ -968,10 +944,39 @@ def send_notification(service_id, template_id):
notification_count=1,
valid="True",
)
session["recipient"] = recipient
session["upload_id"] = upload_id
session["scheduled_for"] = request.form.get("scheduled_for", "")
session.pop("recipient")
session.pop("placeholders")
return render_template(
"views/notifications/preview.html",
**_check_notification(
service_id, template_id, show_recipient=False, force_hide_sender=True
),
upload_id=upload_id,
scheduled_for=session["scheduled_for"],
recipient=recipient,
)
@main.route(
"/services/<uuid:service_id>/template/<uuid:template_id>/notification/check",
methods=["POST"],
)
@user_has_permissions("send_messages", restrict_admin_usage=True)
def send_notification(service_id, template_id):
recipient = get_recipient()
if not recipient:
return redirect(
url_for(
".send_one_off",
service_id=service_id,
template_id=template_id,
)
)
upload_id = session.pop("upload_id")
job_api_client.start_job(service_id, upload_id)
# We have to wait for the job to run and create the notification in the database
time.sleep(0.1)
notifications = notification_api_client.get_notifications_for_service(
@@ -1000,12 +1005,15 @@ def send_notification(service_id, template_id):
job_id=upload_id,
)
)
session.pop("recipient")
session.pop("placeholders")
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

@@ -147,5 +147,10 @@ class JobApiClient(NotifyAdminAPIClient):
url="/service/{}/job/{}/cancel".format(service_id, job_id), data={}
)
def start_job(self, service_id, job_id):
return self.post(
url="/service/{}/job/{}/start-job".format(service_id, job_id), data={}
)
job_api_client = JobApiClient()

View File

@@ -37,11 +37,10 @@ class NotificationApiClient(NotifyAdminAPIClient):
# we do not want in our logs, so we do a POST request instead of a GET
method = self.post if to else self.get
kwargs = {"data": params} if to else {"params": params}
if job_id:
return method(
url="/service/{}/job/{}/notifications".format(service_id, job_id),
**kwargs
**kwargs,
)
else:
if limit_days is not None:
@@ -100,5 +99,8 @@ class NotificationApiClient(NotifyAdminAPIClient):
url="/service/{}/job/{}/notification_count".format(service_id, job_id)
)["count"]
def get_total_notification_message_parts_by_job_id(self, job_id):
return self.get(url="/notifications/{}/message_parts".format(job_id))
notification_api_client = NotificationApiClient()

View File

@@ -61,6 +61,7 @@
)}}" class='page-footer'>
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
<!-- <p>Placeholder: This message will be delivered to <b>400 phone numbers</b> and will use a total of <b>800 message parts</b>, leaving Washington DSHS with <b>249,200 message parts remaining</b>.</p> -->
<h3>Does everything look good?</h3>
{% if not error %}
{% set button_text %}

1
poetry.lock generated
View File

@@ -1278,6 +1278,7 @@ files = [
{file = "lxml-5.2.1-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c38d7b9a690b090de999835f0443d8aa93ce5f2064035dfc48f27f02b4afc3d0"},
{file = "lxml-5.2.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5670fb70a828663cc37552a2a85bf2ac38475572b0e9b91283dc09efb52c41d1"},
{file = "lxml-5.2.1-cp36-cp36m-manylinux_2_28_x86_64.whl", hash = "sha256:958244ad566c3ffc385f47dddde4145088a0ab893504b54b52c041987a8c1863"},
{file = "lxml-5.2.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:b6241d4eee5f89453307c2f2bfa03b50362052ca0af1efecf9fef9a41a22bb4f"},
{file = "lxml-5.2.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:2a66bf12fbd4666dd023b6f51223aed3d9f3b40fef06ce404cb75bafd3d89536"},
{file = "lxml-5.2.1-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:9123716666e25b7b71c4e1789ec829ed18663152008b58544d95b008ed9e21e9"},
{file = "lxml-5.2.1-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:0c3f67e2aeda739d1cc0b1102c9a9129f7dc83901226cc24dd72ba275ced4218"},

View File

@@ -937,6 +937,7 @@ def test_upload_valid_csv_shows_preview_and_table(
mock_get_service_statistics,
mock_get_job_doesnt_exist,
mock_get_jobs,
mock_create_job,
mock_s3_get_metadata,
mock_s3_set_metadata,
fake_uuid,
@@ -1993,7 +1994,7 @@ def test_preview_button_is_correctly_labelled(
@pytest.mark.parametrize("when", ["", "2016-08-25T13:04:21.767198"])
def test_create_job_should_call_api(
client_request,
mock_create_job,
mock_start_job,
mock_get_job,
mock_get_notifications,
mock_get_service_template,
@@ -2032,11 +2033,7 @@ def test_create_job_should_call_api(
assert "Message status" in page.text
mock_create_job.assert_called_with(
job_id,
SERVICE_ONE_ID,
scheduled_for=when,
)
mock_start_job.assert_called_once()
@pytest.mark.parametrize(
@@ -2092,11 +2089,13 @@ def test_route_permissions_send_check_notifications(
response_code,
method,
mock_create_job,
mock_start_job,
mock_s3_upload,
):
with client_request.session_transaction() as session:
session["recipient"] = "2028675301"
session["placeholders"] = {"name": "a"}
session["upload_id"] = fake_uuid
mocker.patch("app.main.views.send.check_messages")
mocker.patch(
@@ -2606,17 +2605,22 @@ def test_preview_notification_shows_preview(
fake_uuid,
mock_get_service_template,
when,
mocker,
mock_create_job,
):
with client_request.session_transaction() as session:
session["recipient"] = "15555555555"
session["placeholders"] = {}
session["upload_id"] = fake_uuid
mocker.patch("app.main.views.send.check_messages", return_value="")
page = client_request.post(
"main.preview_notification",
service_id=service_one["id"],
template_id=fake_uuid,
_expected_status=200,
)
assert page.h1.text.strip() == "Preview"
assert (page.find_all("a", {"class": "usa-back-link"})[0]["href"]) == url_for(
"main.check_notification",
@@ -2661,25 +2665,24 @@ def test_send_notification_submits_data(
placeholders,
expected_personalisation,
mocker,
mock_create_job,
mock_start_job,
mock_s3_upload,
):
with client_request.session_transaction() as session:
session["recipient"] = recipient
session["placeholders"] = placeholders
session["upload_id"] = fake_uuid
mocker.patch(
"app.notification_api_client.get_notifications_for_service",
return_value=FAKE_ONE_OFF_NOTIFICATION,
)
mocker.patch("app.main.views.send.check_messages", return_value="")
client_request.post(
"main.send_notification", service_id=SERVICE_ONE_ID, template_id=fake_uuid
)
mock_create_job.assert_called_once()
mock_start_job.assert_called_once()
def test_send_notification_clears_session(
@@ -2689,12 +2692,13 @@ def test_send_notification_clears_session(
mock_send_notification,
mock_get_service_template,
mocker,
mock_create_job,
mock_start_job,
mock_s3_upload,
):
with client_request.session_transaction() as session:
session["recipient"] = "2028675301"
session["placeholders"] = {"a": "b"}
session["upload_id"] = fake_uuid
mocker.patch("app.main.views.send.check_messages")
mocker.patch(
@@ -2709,6 +2713,7 @@ def test_send_notification_clears_session(
with client_request.session_transaction() as session:
assert "recipient" not in session
assert "placeholders" not in session
assert "upload_id" not in session
@pytest.mark.parametrize(
@@ -2751,12 +2756,13 @@ def test_send_notification_redirects_to_view_page(
extra_args,
extra_redirect_args,
mocker,
mock_create_job,
mock_start_job,
mock_s3_upload,
):
with client_request.session_transaction() as session:
session["recipient"] = "2028675301"
session["placeholders"] = {"a": "b"}
session["upload_id"] = fake_uuid
mocker.patch("app.main.views.send.check_messages")
@@ -2808,7 +2814,7 @@ def test_send_notification_shows_error_if_400(
fake_uuid,
mocker,
mock_get_service_template_with_placeholders,
mock_create_job,
mock_start_job,
exception_msg,
expected_h1,
expected_err_details,
@@ -2833,6 +2839,7 @@ def test_send_notification_shows_error_if_400(
with client_request.session_transaction() as session:
session["recipient"] = "2028675301"
session["placeholders"] = {"name": "a" * 900}
session["upload_id"] = fake_uuid
# This now redirects to the jobs results page
page = client_request.post(
@@ -2850,7 +2857,7 @@ def test_send_notification_shows_email_error_in_trial_mode(
fake_uuid,
mocker,
mock_get_service_email_template,
mock_create_job,
mock_start_job,
mock_s3_upload,
):
class MockHTTPError(HTTPError):
@@ -2870,6 +2877,7 @@ def test_send_notification_shows_email_error_in_trial_mode(
with client_request.session_transaction() as session:
session["recipient"] = "test@example.com"
session["placeholders"] = {"date": "foo", "thing": "bar"}
session["upload_id"] = fake_uuid
# Calling this means we successful ran a job so we will be redirect to the jobs page
client_request.post(

View File

@@ -60,6 +60,7 @@ EXCLUDED_ENDPOINTS = tuple(
"count_content_length",
"create_and_send_messages",
"create_api_key",
"create_job",
"data_retention",
"delete_service_template",
"delete_template_folder",

View File

@@ -1416,6 +1416,14 @@ def mock_create_job(mocker, api_user_active):
return mocker.patch("app.job_api_client.create_job", side_effect=_create)
@pytest.fixture()
def mock_start_job(mocker, api_user_active):
def _start(service_id, fake_uuid):
return {}, 201
return mocker.patch("app.job_api_client.start_job", side_effect=_start)
@pytest.fixture()
def mock_get_job(mocker, api_user_active):
def _get_job(service_id, job_id):