diff --git a/app/dao/__init__.py b/app/dao/__init__.py index 483e45fd1..a56fbce58 100644 --- a/app/dao/__init__.py +++ b/app/dao/__init__.py @@ -28,3 +28,8 @@ class DAOClass(object): db.session.delete(inst) if _commit: db.session.commit() + + +def days_ago(number_of_days): + from datetime import date, timedelta + return date.today() - timedelta(days=number_of_days) diff --git a/app/dao/jobs_dao.py b/app/dao/jobs_dao.py index 7b6a052ae..13742418a 100644 --- a/app/dao/jobs_dao.py +++ b/app/dao/jobs_dao.py @@ -1,5 +1,8 @@ -from sqlalchemy import desc +from datetime import date, timedelta + +from sqlalchemy import desc, cast, Date as sql_date from app import db +from app.dao import days_ago from app.models import Job @@ -7,8 +10,11 @@ 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() -def dao_get_jobs_by_service_id(service_id): - return Job.query.filter_by(service_id=service_id).order_by(desc(Job.created_at)).all() +def dao_get_jobs_by_service_id(service_id, limit_days=None): + query_filter = [Job.service_id == service_id] + if limit_days is not None: + query_filter.append(cast(Job.created_at, sql_date) >= days_ago(limit_days)) + return Job.query.filter(*query_filter).order_by(desc(Job.created_at)).all() def dao_get_job_by_id(job_id): diff --git a/app/dao/notifications_dao.py b/app/dao/notifications_dao.py index 4a8d279cb..72fc3a2f7 100644 --- a/app/dao/notifications_dao.py +++ b/app/dao/notifications_dao.py @@ -11,6 +11,7 @@ from flask import current_app from werkzeug.datastructures import MultiDict from app import db +from app.dao import days_ago from app.models import ( Service, Notification, @@ -342,7 +343,3 @@ def delete_notifications_created_more_than_a_week_ago(status): ).delete(synchronize_session='fetch') db.session.commit() return deleted - - -def days_ago(number_of_days): - return date.today() - timedelta(days=number_of_days) diff --git a/app/job/rest.py b/app/job/rest.py index 5c4147177..9b2d44382 100644 --- a/app/job/rest.py +++ b/app/job/rest.py @@ -1,8 +1,8 @@ from flask import ( Blueprint, jsonify, - request -) + request, + current_app) from app.dao.jobs_dao import ( dao_create_job, @@ -36,7 +36,17 @@ def get_job_by_service_and_job_id(service_id, job_id): @job.route('', methods=['GET']) def get_jobs_by_service(service_id): - jobs = dao_get_jobs_by_service_id(service_id) + if request.args.get('limit_days'): + try: + limit_days = int(request.args['limit_days']) + except ValueError as e: + error = '{} is not an integer'.format(request.args['limit_days']) + current_app.logger.error(error) + return jsonify(result="error", message={'limit_days': [error]}), 400 + else: + limit_days = None + + jobs = dao_get_jobs_by_service_id(service_id, limit_days) data, errors = job_schema.dump(jobs, many=True) if errors: return jsonify(result="error", message=errors), 400 diff --git a/tests/app/dao/test_jobs_dao.py b/tests/app/dao/test_jobs_dao.py index 79d9d08c5..9f265ab0d 100644 --- a/tests/app/dao/test_jobs_dao.py +++ b/tests/app/dao/test_jobs_dao.py @@ -1,4 +1,4 @@ -from datetime import datetime +from datetime import (datetime, timedelta) import uuid from app.dao.jobs_dao import ( @@ -66,6 +66,46 @@ def test_get_jobs_for_service(notify_db, notify_db_session, sample_template): assert one_job_from_db != other_job_from_db +def test_get_jobs_for_service_with_limit_days_param(notify_db, notify_db_session, sample_template): + from tests.app.conftest import sample_job as create_job + + one_job = create_job(notify_db, notify_db_session, sample_template.service, sample_template) + old_job = create_job(notify_db, notify_db_session, sample_template.service, sample_template, + created_at=datetime.now() - timedelta(days=8)) + + jobs = dao_get_jobs_by_service_id(one_job.service_id) + + assert len(jobs) == 2 + assert one_job in jobs + assert old_job in jobs + + jobs_limit_days = dao_get_jobs_by_service_id(one_job.service_id, limit_days=7) + assert len(jobs_limit_days) == 1 + assert one_job in jobs_limit_days + assert old_job not in jobs_limit_days + + +def test_get_jobs_for_service_with_limit_days_edge_case(notify_db, notify_db_session, sample_template): + from tests.app.conftest import sample_job as create_job + + one_job = create_job(notify_db, notify_db_session, sample_template.service, sample_template) + job_two = create_job(notify_db, notify_db_session, sample_template.service, sample_template, + created_at=(datetime.now() - timedelta(days=7)).date()) + one_second_after_midnight = datetime.combine((datetime.now() - timedelta(days=7)).date(), + datetime.strptime("000001", "%H%M%S").time()) + just_after_midnight_job = create_job(notify_db, notify_db_session, sample_template.service, sample_template, + created_at=one_second_after_midnight) + job_eight_days_old = create_job(notify_db, notify_db_session, sample_template.service, sample_template, + created_at=datetime.now() - timedelta(days=8)) + + jobs_limit_days = dao_get_jobs_by_service_id(one_job.service_id, limit_days=7) + assert len(jobs_limit_days) == 3 + assert one_job in jobs_limit_days + assert job_two in jobs_limit_days + assert just_after_midnight_job in jobs_limit_days + assert job_eight_days_old not in jobs_limit_days + + def test_get_jobs_for_service_in_created_at_order(notify_db, notify_db_session, sample_template): from tests.app.conftest import sample_job as create_job diff --git a/tests/app/job/test_rest.py b/tests/app/job/test_rest.py index 6e45a0195..761cecbf7 100644 --- a/tests/app/job/test_rest.py +++ b/tests/app/job/test_rest.py @@ -1,5 +1,7 @@ import json import uuid +from datetime import datetime, timedelta + import app.celery.tasks from tests import create_authorization_header @@ -22,6 +24,32 @@ def test_get_jobs(notify_api, notify_db, notify_db_session, sample_template): assert len(resp_json['data']) == 5 +def test_get_jobs_with_limit_days(notify_api, notify_db, notify_db_session, sample_template): + create_job( + notify_db, + notify_db_session, + service=sample_template.service, + template=sample_template, + ) + create_job( + notify_db, + notify_db_session, + service=sample_template.service, + template=sample_template, + created_at=datetime.now() - timedelta(days=7)) + + service_id = sample_template.service.id + + with notify_api.test_request_context(): + with notify_api.test_client() as client: + path = '/service/{}/job'.format(service_id) + auth_header = create_authorization_header(service_id=service_id) + response = client.get(path, headers=[auth_header], query_string={'limit_days': 5}) + assert response.status_code == 200 + resp_json = json.loads(response.get_data(as_text=True)) + assert len(resp_json['data']) == 1 + + def test_get_job_with_invalid_service_id_returns404(notify_api, sample_api_key, sample_service): with notify_api.test_request_context(): with notify_api.test_client() as client: