mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-09-05 14:08:25 -04:00
Add a cancel job button
If you schedule a job you might change your mind or circumstances might change. So you need to be able to cancel it. This commit adds a button on the job page which hits the `…/cancel` API endpoint for a job.
This commit is contained in:
@@ -12,7 +12,8 @@ from flask import (
|
|||||||
jsonify,
|
jsonify,
|
||||||
request,
|
request,
|
||||||
url_for,
|
url_for,
|
||||||
current_app
|
current_app,
|
||||||
|
redirect
|
||||||
)
|
)
|
||||||
from flask_login import login_required
|
from flask_login import login_required
|
||||||
from werkzeug.datastructures import MultiDict
|
from werkzeug.datastructures import MultiDict
|
||||||
@@ -147,6 +148,14 @@ def view_job_csv(service_id, job_id):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@main.route("/services/<service_id>/jobs/<job_id>", methods=['POST'])
|
||||||
|
@login_required
|
||||||
|
@user_has_permissions('send_texts', 'send_emails', 'send_letters', admin_override=True)
|
||||||
|
def cancel_job(service_id, job_id):
|
||||||
|
job_api_client.cancel_job(service_id, job_id)
|
||||||
|
return redirect(url_for('main.service_dashboard', service_id=service_id))
|
||||||
|
|
||||||
|
|
||||||
@main.route("/services/<service_id>/jobs/<job_id>.json")
|
@main.route("/services/<service_id>/jobs/<job_id>.json")
|
||||||
@login_required
|
@login_required
|
||||||
@user_has_permissions('view_activity', admin_override=True)
|
@user_has_permissions('view_activity', admin_override=True)
|
||||||
|
|||||||
@@ -77,3 +77,18 @@ class JobApiClient(BaseAPIClient):
|
|||||||
job['data']['notifications_requested'] = stats['requested']
|
job['data']['notifications_requested'] = stats['requested']
|
||||||
|
|
||||||
return job
|
return job
|
||||||
|
|
||||||
|
def cancel_job(self, service_id, job_id):
|
||||||
|
|
||||||
|
job = self.post(
|
||||||
|
url='/service/{}/job/{}/cancel'.format(service_id, job_id),
|
||||||
|
data={}
|
||||||
|
)
|
||||||
|
|
||||||
|
stats = self.__convert_statistics(job['data'])
|
||||||
|
job['data']['notifications_sent'] = stats['delivered'] + stats['failed']
|
||||||
|
job['data']['notifications_delivered'] = stats['delivered']
|
||||||
|
job['data']['notifications_failed'] = stats['failed']
|
||||||
|
job['data']['notifications_requested'] = stats['requested']
|
||||||
|
|
||||||
|
return job
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
{% from "components/table.html" import list_table, field, right_aligned_field_heading, date_field, row_heading %}
|
{% from "components/table.html" import list_table, field, right_aligned_field_heading, date_field, row_heading %}
|
||||||
|
{% from "components/page-footer.html" import page_footer %}
|
||||||
|
|
||||||
<div class="ajax-block-container">
|
<div class="ajax-block-container">
|
||||||
{% if job.job_status == 'scheduled' %}
|
{% if job.job_status == 'scheduled' %}
|
||||||
@@ -6,6 +7,14 @@
|
|||||||
<p>
|
<p>
|
||||||
Sending will start at {{ job.scheduled_for|format_time }}
|
Sending will start at {{ job.scheduled_for|format_time }}
|
||||||
</p>
|
</p>
|
||||||
|
<div class="page-footer">
|
||||||
|
<form method="post">
|
||||||
|
{{ page_footer(
|
||||||
|
button_text="Cancel sending",
|
||||||
|
destructive=True
|
||||||
|
) }}
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|
||||||
|
|||||||
@@ -147,6 +147,28 @@ def test_should_show_scheduled_job(
|
|||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser')
|
page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser')
|
||||||
assert page.find('main').find_all('p')[2].text.strip() == 'Sending will start at midnight'
|
assert page.find('main').find_all('p')[2].text.strip() == 'Sending will start at midnight'
|
||||||
|
assert page.find('input', {'type': 'submit', 'value': 'Cancel sending'})
|
||||||
|
|
||||||
|
|
||||||
|
def test_should_cancel_job(
|
||||||
|
app_,
|
||||||
|
service_one,
|
||||||
|
active_user_with_permissions,
|
||||||
|
fake_uuid,
|
||||||
|
mocker
|
||||||
|
):
|
||||||
|
with app_.test_request_context(), app_.test_client() as client:
|
||||||
|
client.login(active_user_with_permissions, mocker, service_one)
|
||||||
|
mock_cancel = mocker.patch('app.main.jobs.job_api_client.cancel_job')
|
||||||
|
response = client.post(url_for(
|
||||||
|
'main.cancel_job',
|
||||||
|
service_id=service_one['id'],
|
||||||
|
job_id=fake_uuid
|
||||||
|
))
|
||||||
|
|
||||||
|
mock_cancel.assert_called_once_with(service_one['id'], fake_uuid)
|
||||||
|
assert response.status_code == 302
|
||||||
|
assert response.location == url_for('main.service_dashboard', service_id=service_one['id'], _external=True)
|
||||||
|
|
||||||
|
|
||||||
def test_should_not_show_cancelled_job(
|
def test_should_not_show_cancelled_job(
|
||||||
|
|||||||
@@ -361,3 +361,15 @@ def test_client_parses_empty_job_stats_for_service(mocker):
|
|||||||
assert result['data'][1]['notifications_sent'] == 0
|
assert result['data'][1]['notifications_sent'] == 0
|
||||||
assert result['data'][1]['notification_count'] == 40
|
assert result['data'][1]['notification_count'] == 40
|
||||||
assert result['data'][1]['notifications_failed'] == 0
|
assert result['data'][1]['notifications_failed'] == 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_cancel_job(mocker):
|
||||||
|
|
||||||
|
mock_post = mocker.patch('app.notify_client.job_api_client.JobApiClient.post')
|
||||||
|
|
||||||
|
JobApiClient().cancel_job('service_id', 'job_id')
|
||||||
|
|
||||||
|
mock_post.assert_called_once_with(
|
||||||
|
url='/service/{}/job/{}/cancel'.format('service_id', 'job_id'),
|
||||||
|
data={}
|
||||||
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user