mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-08-18 21:49:37 -04:00
Merge pull request #658 from alphagov/last-used-message
Last used message
This commit is contained in:
@@ -1,9 +1,11 @@
|
|||||||
|
from datetime import datetime, timedelta
|
||||||
from string import ascii_uppercase
|
from string import ascii_uppercase
|
||||||
|
|
||||||
from flask import request, render_template, redirect, url_for, flash, abort, session
|
from flask import request, render_template, redirect, url_for, flash, abort
|
||||||
from flask_login import login_required
|
from flask_login import login_required
|
||||||
|
from dateutil.parser import parse
|
||||||
|
|
||||||
from notifications_utils.template import Template, TemplateChange
|
from notifications_utils.template import Template
|
||||||
from notifications_utils.recipients import first_column_heading
|
from notifications_utils.recipients import first_column_heading
|
||||||
from notifications_python_client.errors import HTTPError
|
from notifications_python_client.errors import HTTPError
|
||||||
|
|
||||||
@@ -11,7 +13,7 @@ from app.main import main
|
|||||||
from app.utils import user_has_permissions
|
from app.utils import user_has_permissions
|
||||||
from app.main.forms import SMSTemplateForm, EmailTemplateForm
|
from app.main.forms import SMSTemplateForm, EmailTemplateForm
|
||||||
from app.main.views.send import get_example_csv_rows
|
from app.main.views.send import get_example_csv_rows
|
||||||
from app import service_api_client, current_service
|
from app import service_api_client, current_service, template_statistics_client
|
||||||
|
|
||||||
|
|
||||||
form_objects = {
|
form_objects = {
|
||||||
@@ -183,7 +185,10 @@ def delete_service_template(service_id, template_id):
|
|||||||
|
|
||||||
template['template_content'] = template['content']
|
template['template_content'] = template['content']
|
||||||
form = form_objects[template['template_type']](**template)
|
form = form_objects[template['template_type']](**template)
|
||||||
flash('Are you sure you want to delete ‘{}’?'.format(form.name.data), 'delete')
|
|
||||||
|
template_statistics = template_statistics_client.get_template_statistics_for_service(service_id, template['id'])
|
||||||
|
last_use_message = get_last_use_message(form.name.data, template_statistics)
|
||||||
|
flash('{}. Are you sure you want to delete it?'.format(last_use_message), 'delete')
|
||||||
return render_template(
|
return render_template(
|
||||||
'views/edit-{}-template.html'.format(template['template_type']),
|
'views/edit-{}-template.html'.format(template['template_type']),
|
||||||
h1='Edit template',
|
h1='Edit template',
|
||||||
@@ -216,3 +221,33 @@ def view_template_versions(service_id, template_id):
|
|||||||
) for template in service_api_client.get_service_template_versions(service_id, template_id)['data']
|
) for template in service_api_client.get_service_template_versions(service_id, template_id)['data']
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def get_last_use_message(template_name, template_statistics):
|
||||||
|
try:
|
||||||
|
most_recent_use = max(
|
||||||
|
parse(template_stats['updated_at']).replace(tzinfo=None)
|
||||||
|
for template_stats in template_statistics
|
||||||
|
)
|
||||||
|
except ValueError:
|
||||||
|
return '{} has never been used'.format(template_name)
|
||||||
|
|
||||||
|
return '{} was last used {} ago'.format(
|
||||||
|
template_name,
|
||||||
|
get_human_readable_delta(most_recent_use, datetime.utcnow())
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def get_human_readable_delta(from_time, until_time):
|
||||||
|
delta = until_time - from_time
|
||||||
|
if delta < timedelta(seconds=60):
|
||||||
|
return 'under a minute'
|
||||||
|
elif delta < timedelta(hours=1):
|
||||||
|
minutes = int(delta.seconds / 60)
|
||||||
|
return '{} minute{}'.format(minutes, '' if minutes == 1 else 's')
|
||||||
|
elif delta < timedelta(days=1):
|
||||||
|
hours = int(delta.seconds / 3600)
|
||||||
|
return '{} hour{}'.format(hours, '' if hours == 1 else 's')
|
||||||
|
else:
|
||||||
|
days = delta.days
|
||||||
|
return '{} day{}'.format(days, '' if days == 1 else 's')
|
||||||
|
|||||||
@@ -20,3 +20,8 @@ class TemplateStatisticsApiClient(BaseAPIClient):
|
|||||||
url='/service/{}/template-statistics'.format(service_id),
|
url='/service/{}/template-statistics'.format(service_id),
|
||||||
params=params
|
params=params
|
||||||
)['data']
|
)['data']
|
||||||
|
|
||||||
|
def get_template_statistics_for_template(self, service_id, template_id):
|
||||||
|
return self.get(
|
||||||
|
url='/service/{}/template-statistics/{}'.format(service_id, template_id)
|
||||||
|
)['data']
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import uuid
|
|||||||
from app.notify_client.template_statistics_api_client import TemplateStatisticsApiClient
|
from app.notify_client.template_statistics_api_client import TemplateStatisticsApiClient
|
||||||
|
|
||||||
|
|
||||||
def test_template_statistics_client_calls_correct_api_endpoint(mocker, api_user_active):
|
def test_template_statistics_client_calls_correct_api_endpoint_for_service(mocker, api_user_active):
|
||||||
|
|
||||||
some_service_id = uuid.uuid4()
|
some_service_id = uuid.uuid4()
|
||||||
expected_url = '/service/{}/template-statistics'.format(some_service_id)
|
expected_url = '/service/{}/template-statistics'.format(some_service_id)
|
||||||
@@ -15,3 +15,16 @@ def test_template_statistics_client_calls_correct_api_endpoint(mocker, api_user_
|
|||||||
client.get_template_statistics_for_service(some_service_id)
|
client.get_template_statistics_for_service(some_service_id)
|
||||||
|
|
||||||
mock_get.assert_called_once_with(url=expected_url, params={})
|
mock_get.assert_called_once_with(url=expected_url, params={})
|
||||||
|
|
||||||
|
|
||||||
|
def test_template_statistics_client_calls_correct_api_endpoint_for_template(mocker, api_user_active):
|
||||||
|
some_service_id = uuid.uuid4()
|
||||||
|
some_template_id = uuid.uuid4()
|
||||||
|
expected_url = '/service/{}/template-statistics/{}'.format(some_service_id, some_template_id)
|
||||||
|
|
||||||
|
client = TemplateStatisticsApiClient()
|
||||||
|
mock_get = mocker.patch('app.notify_client.template_statistics_api_client.TemplateStatisticsApiClient.get')
|
||||||
|
|
||||||
|
client.get_template_statistics_for_template(some_service_id, some_template_id)
|
||||||
|
|
||||||
|
mock_get.assert_called_once_with(url=expected_url)
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
import json
|
from datetime import datetime
|
||||||
import uuid
|
|
||||||
from bs4 import BeautifulSoup
|
|
||||||
from tests import validate_route_permission
|
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
from bs4 import BeautifulSoup
|
||||||
from flask import url_for
|
from flask import url_for
|
||||||
|
from freezegun import freeze_time
|
||||||
|
|
||||||
|
from tests import validate_route_permission
|
||||||
|
from app.main.views.templates import get_last_use_message, get_human_readable_delta
|
||||||
|
|
||||||
|
|
||||||
def test_should_show_page_for_one_templates(app_,
|
def test_should_show_page_for_one_templates(app_,
|
||||||
@@ -226,6 +229,8 @@ def test_should_show_delete_template_page(app_,
|
|||||||
mock_get_user,
|
mock_get_user,
|
||||||
mock_get_user_by_email,
|
mock_get_user_by_email,
|
||||||
mock_has_permissions,
|
mock_has_permissions,
|
||||||
|
mock_get_template_statistics,
|
||||||
|
mock_get_template_statistics_for_template,
|
||||||
fake_uuid):
|
fake_uuid):
|
||||||
with app_.test_request_context():
|
with app_.test_request_context():
|
||||||
with app_.test_client() as client:
|
with app_.test_client() as client:
|
||||||
@@ -292,6 +297,8 @@ def test_route_permissions(mocker,
|
|||||||
api_user_active,
|
api_user_active,
|
||||||
service_one,
|
service_one,
|
||||||
mock_get_service_template,
|
mock_get_service_template,
|
||||||
|
mock_get_template_statistics,
|
||||||
|
mock_get_template_statistics_for_template,
|
||||||
fake_uuid):
|
fake_uuid):
|
||||||
routes = [
|
routes = [
|
||||||
'main.add_service_template',
|
'main.add_service_template',
|
||||||
@@ -360,3 +367,35 @@ def test_route_invalid_permissions(mocker,
|
|||||||
['view_activity'],
|
['view_activity'],
|
||||||
api_user_active,
|
api_user_active,
|
||||||
service_one)
|
service_one)
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_last_use_message_returns_no_template_message():
|
||||||
|
assert get_last_use_message('My Template', []) == 'My Template has never been used'
|
||||||
|
|
||||||
|
|
||||||
|
@freeze_time('2000-01-01T15:00')
|
||||||
|
def test_get_last_use_message_uses_most_recent_statistics():
|
||||||
|
template_statistics = [
|
||||||
|
{
|
||||||
|
'updated_at': '2000-01-01T12:00:00.000000+00:00'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'updated_at': '2000-01-01T09:00:00.000000+00:00'
|
||||||
|
},
|
||||||
|
]
|
||||||
|
assert get_last_use_message('My Template', template_statistics) == 'My Template was last used 3 hours ago'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('from_time, until_time, message', [
|
||||||
|
(datetime(2000, 1, 1, 12, 0), datetime(2000, 1, 1, 12, 0, 59), 'under a minute'),
|
||||||
|
(datetime(2000, 1, 1, 12, 0), datetime(2000, 1, 1, 12, 1), '1 minute'),
|
||||||
|
(datetime(2000, 1, 1, 12, 0), datetime(2000, 1, 1, 12, 2, 35), '2 minutes'),
|
||||||
|
(datetime(2000, 1, 1, 12, 0), datetime(2000, 1, 1, 12, 59), '59 minutes'),
|
||||||
|
(datetime(2000, 1, 1, 12, 0), datetime(2000, 1, 1, 13, 0), '1 hour'),
|
||||||
|
(datetime(2000, 1, 1, 12, 0), datetime(2000, 1, 1, 14, 0), '2 hours'),
|
||||||
|
(datetime(2000, 1, 1, 12, 0), datetime(2000, 1, 2, 11, 59), '23 hours'),
|
||||||
|
(datetime(2000, 1, 1, 12, 0), datetime(2000, 1, 2, 12, 0), '1 day'),
|
||||||
|
(datetime(2000, 1, 1, 12, 0), datetime(2000, 1, 3, 14, 0), '2 days'),
|
||||||
|
])
|
||||||
|
def test_get_human_readable_delta(from_time, until_time, message):
|
||||||
|
assert get_human_readable_delta(from_time, until_time) == message
|
||||||
|
|||||||
@@ -995,7 +995,8 @@ def mock_get_template_statistics(mocker, service_one, fake_uuid):
|
|||||||
},
|
},
|
||||||
"service": template['service'],
|
"service": template['service'],
|
||||||
"id": str(generate_uuid()),
|
"id": str(generate_uuid()),
|
||||||
"day": "2016-04-04"
|
"day": "2016-04-04",
|
||||||
|
"updated_at": "2016-04-04T12:00:00.000000+00:00"
|
||||||
}
|
}
|
||||||
|
|
||||||
def _get_stats(service_id, limit_days=None):
|
def _get_stats(service_id, limit_days=None):
|
||||||
@@ -1005,6 +1006,29 @@ def mock_get_template_statistics(mocker, service_one, fake_uuid):
|
|||||||
'app.template_statistics_client.get_template_statistics_for_service', side_effect=_get_stats)
|
'app.template_statistics_client.get_template_statistics_for_service', side_effect=_get_stats)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope='function')
|
||||||
|
def mock_get_template_statistics_for_template(mocker, service_one):
|
||||||
|
def _get_stats(service_id, template_id):
|
||||||
|
template = template_json(service_id, template_id, "Test template", "sms", "Something very interesting")
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
"usage_count": 1,
|
||||||
|
"template": {
|
||||||
|
"name": template['name'],
|
||||||
|
"template_type": template['template_type'],
|
||||||
|
"id": template['id']
|
||||||
|
},
|
||||||
|
"service": template['service'],
|
||||||
|
"id": str(generate_uuid()),
|
||||||
|
"day": "2016-04-04",
|
||||||
|
"updated_at": "2016-04-04T12:00:00.000000+00:00"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
return mocker.patch(
|
||||||
|
'app.template_statistics_client.get_template_statistics_for_service', side_effect=_get_stats)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope='function')
|
@pytest.fixture(scope='function')
|
||||||
def mock_get_usage(mocker, service_one, fake_uuid):
|
def mock_get_usage(mocker, service_one, fake_uuid):
|
||||||
def _get_usage(service_id):
|
def _get_usage(service_id):
|
||||||
|
|||||||
Reference in New Issue
Block a user