diff --git a/app/main/views/dashboard.py b/app/main/views/dashboard.py index def963624..5b9c6988d 100644 --- a/app/main/views/dashboard.py +++ b/app/main/views/dashboard.py @@ -1,6 +1,4 @@ from datetime import datetime, timedelta -from collections import namedtuple -from itertools import groupby import dateutil from flask import ( @@ -20,7 +18,7 @@ from app import ( service_api_client, template_statistics_client ) -from app.statistics_utils import add_rates_to, get_formatted_percentage, add_rate_to_jobs +from app.statistics_utils import get_formatted_percentage, add_rate_to_job from app.utils import user_has_permissions @@ -117,20 +115,21 @@ def aggregate_usage(template_statistics): def get_dashboard_partials(service_id): + # all but scheduled and cancelled + statuses_to_display = job_api_client.JOB_STATUSES - {'scheduled', 'cancelled'} template_statistics = aggregate_usage( template_statistics_client.get_template_statistics_for_service(service_id, limit_days=7) ) - jobs = add_rate_to_jobs([ - job for job in job_api_client.get_job(service_id, limit_days=7)['data'] - if job['original_file_name'] != current_app.config['TEST_MESSAGE_FILENAME'] - ]) - scheduled_jobs = sorted([ - job for job in jobs if job['job_status'] == 'scheduled' - ], key=lambda job: job['scheduled_for']) + scheduled_jobs = sorted( + job_api_client.get_jobs(service_id, statuses=['scheduled'])['data'], + key=lambda job: job['scheduled_for'] + ) immediate_jobs = [ - job for job in jobs if job['job_status'] not in ['scheduled', 'cancelled'] + add_rate_to_job(job) + for job in job_api_client.get_jobs(service_id, statuses=statuses_to_display)['data'] + if job['original_file_name'] != current_app.config['TEST_MESSAGE_FILENAME'] ] service = service_api_client.get_detailed_service(service_id) diff --git a/app/main/views/jobs.py b/app/main/views/jobs.py index 756394bcc..9cdf91824 100644 --- a/app/main/views/jobs.py +++ b/app/main/views/jobs.py @@ -1,8 +1,6 @@ # -*- coding: utf-8 -*- import ago -import time import dateutil -import json from orderedset import OrderedSet from datetime import datetime, timedelta, timezone from itertools import chain @@ -29,11 +27,13 @@ from app import ( from app.main import main from app.utils import ( get_page_from_request, - generate_previous_next_dict, + generate_next_dict, + generate_previous_dict, user_has_permissions, - generate_notifications_csv) -from app.statistics_utils import add_rate_to_jobs -from app.utils import get_help_argument + generate_notifications_csv, + get_help_argument +) +from app.statistics_utils import add_rate_to_job def _parse_filter_args(filter_dict): @@ -65,12 +65,28 @@ def _set_status_filters(filter_args): @login_required @user_has_permissions('view_activity', admin_override=True) def view_jobs(service_id): + page = int(request.args.get('page', 1)) + # all but scheduled and cancelled + statuses_to_display = job_api_client.JOB_STATUSES - {'scheduled', 'cancelled'} + jobs_response = job_api_client.get_jobs(service_id, statuses=statuses_to_display, page=page) + jobs = [ + add_rate_to_job(job) for job in jobs_response['data'] + if job['original_file_name'] != current_app.config['TEST_MESSAGE_FILENAME'] + ] + + prev_page = None + if jobs_response['links'].get('prev', None): + prev_page = generate_previous_dict('main.view_jobs', service_id, page) + next_page = None + if jobs_response['links'].get('next', None): + next_page = generate_next_dict('main.view_jobs', service_id, page) + return render_template( 'views/jobs/jobs.html', - jobs=add_rate_to_jobs([ - job for job in job_api_client.get_job(service_id)['data'] - if job['job_status'] not in ['scheduled', 'cancelled'] - ]) + jobs=jobs, + page=page, + prev_page=prev_page, + next_page=next_page, ) @@ -205,28 +221,18 @@ def get_notifications(service_id, message_type, status_override=None): template_type=[message_type], status=filter_args.get('status'), limit_days=current_app.config['ACTIVITY_STATS_LIMIT_DAYS']) - view_dict = dict( - message_type=message_type, - status=request.args.get('status') - ) + + url_args = { + 'message_type': message_type, + 'status': request.args.get('status') + } prev_page = None if notifications['links'].get('prev', None): - prev_page = generate_previous_next_dict( - 'main.view_notifications', - service_id, - view_dict, - page - 1, - 'Previous page', - 'page {}'.format(page - 1)) + prev_page = generate_previous_dict('main.view_notifications', service_id, page, url_args=url_args) next_page = None if notifications['links'].get('next', None): - next_page = generate_previous_next_dict( - 'main.view_notifications', - service_id, - view_dict, - page + 1, - 'Next page', - 'page {}'.format(page + 1)) + next_page = generate_next_dict('main.view_notifications', service_id, page, url_args) + if request.path.endswith('csv'): csv_content = generate_notifications_csv( notification_api_client.get_notifications_for_service( diff --git a/app/notify_client/job_api_client.py b/app/notify_client/job_api_client.py index 614a01560..4ec07bc8f 100644 --- a/app/notify_client/job_api_client.py +++ b/app/notify_client/job_api_client.py @@ -5,6 +5,16 @@ from app.notify_client import _attach_current_user class JobApiClient(BaseAPIClient): + + JOB_STATUSES = { + 'scheduled', + 'pending', + 'in progress', + 'finished', + 'cancelled', + 'sending limits exceeded', + } + def __init__(self): super().__init__("a", "b", "c") @@ -26,24 +36,24 @@ class JobApiClient(BaseAPIClient): results['requested'] += outcome['count'] return results - def get_job(self, service_id, job_id=None, limit_days=None, status=None): - if job_id: - params = {} - if status is not None: - params['status'] = status - job = self.get(url='/service/{}/job/{}'.format(service_id, job_id), params=params) - - 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 - + def get_job(self, service_id, job_id): params = {} + job = self.get(url='/service/{}/job/{}'.format(service_id, job_id), params=params) + + 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 + + def get_jobs(self, service_id, limit_days=None, statuses=None, page=1): + params = {'page': page} if limit_days is not None: params['limit_days'] = limit_days + if statuses is not None: + params['statuses'] = ','.join(statuses) jobs = self.get(url='/service/{}/job'.format(service_id), params=params) for job in jobs['data']: diff --git a/app/statistics_utils.py b/app/statistics_utils.py index 4581e069d..c9a08992e 100644 --- a/app/statistics_utils.py +++ b/app/statistics_utils.py @@ -74,17 +74,15 @@ def statistics_by_state(statistics): def get_failure_rate_for_job(job): if not job.get('notifications_delivered'): - if job.get('notifications_failed'): - return 1 - return 0 + return 1 if job.get('notifications_failed') else 0 return ( job.get('notifications_failed', 0) / (job.get('notifications_failed', 0) + job.get('notifications_delivered', 0)) ) -def add_rate_to_jobs(jobs): - return [dict( +def add_rate_to_job(job): + return dict( failure_rate=(get_failure_rate_for_job(job)) * 100, **job - ) for job in jobs] + ) diff --git a/app/templates/components/previous-next-navigation.html b/app/templates/components/previous-next-navigation.html index 9704ea939..525555396 100644 --- a/app/templates/components/previous-next-navigation.html +++ b/app/templates/components/previous-next-navigation.html @@ -8,7 +8,7 @@ {{previous_page['label']}} - {% endif %} + {% endif %} {% if next_page %}