add statuses filter to GET /service/{}/job

can now pass in a query string `?statuses=x,y,z` to filter jobs based on
`Job.job_status`. Not passing in a status or passing in an empty string is
equivalent to selecting every filter type at once.
This commit is contained in:
Leo Hemsted
2016-09-23 16:34:13 +01:00
parent 281323b435
commit fb6cb5f236
4 changed files with 56 additions and 7 deletions

View File

@@ -27,10 +27,14 @@ def dao_get_job_by_service_id_and_job_id(service_id, job_id):
return Job.query.filter_by(service_id=service_id, id=job_id).one() return Job.query.filter_by(service_id=service_id, id=job_id).one()
def dao_get_jobs_by_service_id(service_id, limit_days=None, page=1, page_size=50): def dao_get_jobs_by_service_id(service_id, limit_days=None, page=1, page_size=50, statuses=''):
query_filter = [Job.service_id == service_id] query_filter = [Job.service_id == service_id]
if limit_days is not None: if limit_days is not None:
query_filter.append(cast(Job.created_at, sql_date) >= days_ago(limit_days)) query_filter.append(cast(Job.created_at, sql_date) >= days_ago(limit_days))
if statuses != ['']:
query_filter.append(
Job.job_status.in_(statuses)
)
return Job.query \ return Job.query \
.filter(*query_filter) \ .filter(*query_filter) \
.order_by(desc(Job.created_at)) \ .order_by(desc(Job.created_at)) \

View File

@@ -102,8 +102,10 @@ def get_jobs_by_service(service_id):
else: else:
limit_days = None limit_days = None
statuses = [x.strip() for x in request.args.get('statuses', '').split(',')]
page = int(request.args.get('page', 1)) page = int(request.args.get('page', 1))
return jsonify(**get_paginated_jobs(service_id, limit_days, page)) return jsonify(**get_paginated_jobs(service_id, limit_days, statuses, page))
@job.route('', methods=['POST']) @job.route('', methods=['POST'])
@@ -140,14 +142,14 @@ def create_job(service_id):
return jsonify(data=job_json), 201 return jsonify(data=job_json), 201
def get_paginated_jobs(service_id, limit_days, page): def get_paginated_jobs(service_id, limit_days, statuses, page):
pagination = dao_get_jobs_by_service_id( pagination = dao_get_jobs_by_service_id(
service_id, service_id,
limit_days=limit_days, limit_days=limit_days,
page=page, page=page,
page_size=current_app.config['PAGE_SIZE'] page_size=current_app.config['PAGE_SIZE'],
statuses=statuses
) )
data = job_schema.dump(pagination.items, many=True).data data = job_schema.dump(pagination.items, many=True).data
for job_data in data: for job_data in data:
statistics = dao_get_notification_outcomes_for_job(service_id, job_data['id']) statistics = dao_get_notification_outcomes_for_job(service_id, job_data['id'])

View File

@@ -304,7 +304,14 @@ JOB_STATUS_FINISHED = 'finished'
JOB_STATUS_SENDING_LIMITS_EXCEEDED = 'sending limits exceeded' JOB_STATUS_SENDING_LIMITS_EXCEEDED = 'sending limits exceeded'
JOB_STATUS_SCHEDULED = 'scheduled' JOB_STATUS_SCHEDULED = 'scheduled'
JOB_STATUS_CANCELLED = 'cancelled' JOB_STATUS_CANCELLED = 'cancelled'
JOB_STATUS_TYPES = [
JOB_STATUS_PENDING,
JOB_STATUS_IN_PROGRESS,
JOB_STATUS_FINISHED,
JOB_STATUS_SENDING_LIMITS_EXCEEDED,
JOB_STATUS_SCHEDULED,
JOB_STATUS_CANCELLED
]
class JobStatus(db.Model): class JobStatus(db.Model):
__tablename__ = 'job_status' __tablename__ = 'job_status'

View File

@@ -14,7 +14,7 @@ from tests.app.conftest import (
sample_notification as create_notification sample_notification as create_notification
) )
from app.dao.templates_dao import dao_update_template from app.dao.templates_dao import dao_update_template
from app.models import NOTIFICATION_STATUS_TYPES from app.models import NOTIFICATION_STATUS_TYPES, JOB_STATUS_TYPES, JOB_STATUS_PENDING
def test_get_job_with_invalid_service_id_returns404(notify_api, sample_api_key, sample_service): def test_get_job_with_invalid_service_id_returns404(notify_api, sample_api_key, sample_service):
@@ -655,6 +655,42 @@ def test_get_jobs_accepts_page_parameter(
assert set(resp_json['links'].keys()) == {'prev', 'next', 'last'} assert set(resp_json['links'].keys()) == {'prev', 'next', 'last'}
@pytest.mark.parametrize('statuses_filter, expected_statuses', [
('', JOB_STATUS_TYPES),
('pending', [JOB_STATUS_PENDING]),
('pending, in progress, finished, sending limits exceeded, scheduled, cancelled', JOB_STATUS_TYPES),
# bad statuses are accepted, just return no data
('foo', [])
])
def test_get_jobs_can_filter_on_statuses(
notify_db,
notify_db_session,
client,
sample_service,
statuses_filter,
expected_statuses
):
create_job(notify_db, notify_db_session, job_status='pending')
create_job(notify_db, notify_db_session, job_status='in progress')
create_job(notify_db, notify_db_session, job_status='finished')
create_job(notify_db, notify_db_session, job_status='sending limits exceeded')
create_job(notify_db, notify_db_session, job_status='scheduled')
create_job(notify_db, notify_db_session, job_status='cancelled')
path = '/service/{}/job'.format(sample_service.id)
response = client.get(
path,
headers=[create_authorization_header()],
query_string={'statuses': statuses_filter}
)
assert response.status_code == 200
resp_json = json.loads(response.get_data(as_text=True))
from pprint import pprint
pprint(resp_json)
assert {x['job_status'] for x in resp_json['data']} == set(expected_statuses)
def create_10_jobs(db, session, service, template): def create_10_jobs(db, session, service, template):
with freeze_time('2015-01-01T00:00:00') as the_time: with freeze_time('2015-01-01T00:00:00') as the_time:
for _ in range(10): for _ in range(10):