table with sending/delivered/failed stats for each service today

This commit is contained in:
Leo Hemsted
2016-05-31 11:08:22 +01:00
parent a8c38b7478
commit 9669024f49
5 changed files with 140 additions and 21 deletions

View File

@@ -2,13 +2,12 @@ from datetime import datetime
import pytz import pytz
from flask import render_template from flask import render_template
from flask_login import login_required, current_user from flask_login import login_required
from app import statistics_api_client, service_api_client from app import statistics_api_client, service_api_client
from app.main import main from app.main import main
from app.utils import user_has_permissions from app.utils import user_has_permissions
from app.statistics_utils import sum_of_statistics, add_rates_to from app.statistics_utils import sum_of_statistics, add_rates_to
from app.notify_client.api_client import ServicesBrowsableItem
@main.route("/platform-admin") @main.route("/platform-admin")
@@ -17,13 +16,33 @@ from app.notify_client.api_client import ServicesBrowsableItem
def platform_admin(): def platform_admin():
return render_template( return render_template(
'views/platform-admin.html', 'views/platform-admin.html',
global_stats=get_global_stats(), **get_statistics()
services=[ServicesBrowsableItem(x) for x in
service_api_client.get_services({'user_id': current_user.id})['data']]
) )
def get_global_stats(): def get_statistics():
day = datetime.now(tz=pytz.timezone('Europe/London')).date() day = datetime.now(tz=pytz.timezone('Europe/London')).date()
all_stats = statistics_api_client.get_statistics_for_all_services_for_day(day)['data'] all_stats = statistics_api_client.get_statistics_for_all_services_for_day(day)['data']
return add_rates_to(sum_of_statistics(all_stats)) services = service_api_client.get_services()['data']
service_stats = format_stats_by_service(all_stats, services)
return {
'global_stats': add_rates_to(sum_of_statistics(all_stats)),
'service_stats': service_stats
}
def format_stats_by_service(all_stats, services):
services = {service['id']: service for service in services}
return [
{
'id': stats['service'],
'name': services[stats['service']]['name'],
'sending': (
(stats['sms_requested'] - stats['sms_delivered'] - stats['sms_failed']) +
(stats['emails_requested'] - stats['emails_delivered'] - stats['emails_failed'])
),
'delivered': stats['sms_delivered'] + stats['emails_delivered'],
'failed': stats['sms_failed'] + stats['emails_failed']
}
for stats in all_stats
]

View File

@@ -1,7 +1,8 @@
{% extends "withoutnav_template.html" %} {% extends "withoutnav_template.html" %}
{% from "components/big-number.html" import big_number_with_status %} {% from "components/big-number.html" import big_number, big_number_with_status %}
{% from "components/message-count-label.html" import message_count_label %} {% from "components/message-count-label.html" import message_count_label %}
{% from "components/browse-list.html" import browse_list %} {% from "components/browse-list.html" import browse_list %}
{% from "components/table.html" import list_table, field, right_aligned_field_heading %}
{% block page_title %} {% block page_title %}
Platform admin GOV.UK Notify Platform admin GOV.UK Notify
@@ -21,6 +22,7 @@
]) }} ]) }}
<h2 class='heading-medium'>Today's statistics</h2>
<div class="grid-row"> <div class="grid-row">
<div class="column-half"> <div class="column-half">
{{ big_number_with_status( {{ big_number_with_status(
@@ -43,8 +45,32 @@
</div> </div>
<h2 class='heading-medium'>Services</h2> <h2 class='heading-medium'>Services</h2>
{{ browse_list(services) }} {% call(item, row_number) list_table(
service_stats,
caption="All services",
caption_visible=False,
field_headings=[
'Service',
right_aligned_field_heading('Sending'),
right_aligned_field_heading('Delivered'),
right_aligned_field_heading('Failed')
],
field_headings_visible=True
) %}
{% call field() %}
<div>
<a href="{{ url_for('main.service_dashboard', service_id=item['id']) }}" class="browse-list-link">{{ item['name'] }}</a>
</div>
{% endcall %}
{% call field(align='right') %}
{{ big_number(item['sending'], smaller=True) }}
{% endcall %}
{% call field(align='right') %}
{{ big_number(item['delivered'], smaller=True) }}
{% endcall %}
{% call field(align='right', status='error' if 0 else '') %}
{{ big_number(item['failed'], smaller=True) }}
{% endcall %}
{% endcall %}
{% endblock %} {% endblock %}

View File

@@ -1,6 +1,6 @@
import pytest import pytest
import uuid import uuid
from datetime import datetime, timedelta from datetime import datetime, timedelta, date
from flask.testing import FlaskClient from flask.testing import FlaskClient
from flask import url_for from flask import url_for
from flask_login import login_user from flask_login import login_user

View File

@@ -5,7 +5,7 @@ from freezegun import freeze_time
from tests.conftest import mock_get_user from tests.conftest import mock_get_user
from app.main.views.platform_admin import get_global_stats from app.main.views.platform_admin import get_statistics, format_stats_by_service
def test_should_redirect_if_not_logged_in(app_): def test_should_redirect_if_not_logged_in(app_):
@@ -27,7 +27,13 @@ def test_should_403_if_not_platform_admin(app_, active_user_with_permissions, mo
assert response.status_code == 403 assert response.status_code == 403
def test_should_render_platform_admin_page(app_, platform_admin_user, mocker, mock_get_all_service_statistics): def test_should_render_platform_admin_page(
app_,
platform_admin_user,
mocker,
mock_get_services,
mock_get_all_service_statistics
):
with app_.test_request_context(): with app_.test_request_context():
with app_.test_client() as client: with app_.test_client() as client:
mock_get_user(mocker, user=platform_admin_user) mock_get_user(mocker, user=platform_admin_user)
@@ -37,12 +43,12 @@ def test_should_render_platform_admin_page(app_, platform_admin_user, mocker, mo
assert response.status_code == 200 assert response.status_code == 200
resp_data = response.get_data(as_text=True) resp_data = response.get_data(as_text=True)
assert 'Platform admin' in resp_data assert 'Platform admin' in resp_data
assert 'List all services' in resp_data assert 'Today\'s statistics' in resp_data
assert 'View providers' in resp_data assert 'Services' in resp_data
def test_get_global_stats_should_summarise_all_stats(mock_get_all_service_statistics): def test_get_statistics_should_summarise_all_stats(mock_get_all_service_statistics, mock_get_services):
resp = get_global_stats() resp = get_statistics()['global_stats']
assert 'emails_delivered' in resp assert 'emails_delivered' in resp
assert 'emails_failed' in resp assert 'emails_failed' in resp
@@ -53,7 +59,75 @@ def test_get_global_stats_should_summarise_all_stats(mock_get_all_service_statis
@freeze_time('2000-06-30T23:30:00', tz_offset=0) @freeze_time('2000-06-30T23:30:00', tz_offset=0)
def test_get_global_stats_should_query_for_today_forced_to_GMT(mock_get_all_service_statistics): def test_get_statistics_should_query_for_today_forced_to_GMT(mock_get_all_service_statistics, mock_get_services):
get_global_stats() get_statistics()
mock_get_all_service_statistics.assert_called_once_with(date(2000, 7, 1)) mock_get_all_service_statistics.assert_called_once_with(date(2000, 7, 1))
def create_stats(
service,
emails_requested=0,
emails_delivered=0,
emails_failed=0,
sms_requested=0,
sms_delivered=0,
sms_failed=0
):
return {
'service': service,
'emails_requested': emails_requested,
'emails_delivered': emails_delivered,
'emails_failed': emails_failed,
'sms_requested': sms_requested,
'sms_delivered': sms_delivered,
'sms_failed': sms_failed,
}
def test_format_stats_by_service_gets_correct_stats_for_each_service():
services = [
{'name': 'a', 'id': 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'},
{'name': 'b', 'id': 'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb'}
]
all_stats = [
create_stats('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', emails_requested=1),
create_stats('bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', emails_requested=2)
]
ret = format_stats_by_service(all_stats, services)
assert len(ret) == 2
assert ret[0]['name'] == 'a'
assert ret[0]['sending'] == 1
assert ret[0]['delivered'] == 0
assert ret[0]['failed'] == 0
assert ret[1]['name'] == 'b'
assert ret[1]['sending'] == 2
assert ret[1]['delivered'] == 0
assert ret[1]['failed'] == 0
def test_format_stats_by_service_sums_values_for_sending():
services = [
{'name': 'a', 'id': 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'},
]
all_stats = [
create_stats(
'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa',
emails_requested=10,
emails_delivered=3,
emails_failed=5,
sms_requested=50,
sms_delivered=7,
sms_failed=11
)
]
ret = format_stats_by_service(all_stats, services)
assert len(ret) == 1
assert ret[0]['sending'] == 34
assert ret[0]['delivered'] == 10
assert ret[0]['failed'] == 16

View File

@@ -205,7 +205,7 @@ def mock_get_aggregate_service_statistics(mocker):
@pytest.fixture(scope='function') @pytest.fixture(scope='function')
def mock_get_all_service_statistics(mocker): def mock_get_all_service_statistics(mocker):
def _create(day): def _create(day):
return {'data': [{}]} return {'data': []}
return mocker.patch( return mocker.patch(
'app.statistics_api_client.get_statistics_for_all_services_for_day', side_effect=_create) 'app.statistics_api_client.get_statistics_for_all_services_for_day', side_effect=_create)