diff --git a/pagure/api/user.py b/pagure/api/user.py index d06b5f4..c9e1d9e 100644 --- a/pagure/api/user.py +++ b/pagure/api/user.py @@ -21,7 +21,7 @@ import pagure import pagure.exceptions import pagure.lib.query from pagure.api import API, api_method, APIERROR, get_page, get_per_page -from pagure.utils import is_true +from pagure.utils import is_true, validate_date, validate_date_range def _get_user(username): @@ -414,23 +414,7 @@ def api_view_user_issues(username): updated_after = None if since: - # Validate and convert the time - if since.isdigit(): - # We assume its a timestamp, so convert it to datetime - try: - updated_after = datetime.datetime.fromtimestamp(int(since)) - except ValueError: - raise pagure.exceptions.APIError( - 400, error_code=APIERROR.ETIMESTAMP - ) - else: - # We assume datetime format, so validate it - try: - updated_after = datetime.datetime.strptime(since, "%Y-%m-%d") - except ValueError: - raise pagure.exceptions.APIError( - 400, error_code=APIERROR.EDATETIME - ) + updated_after = validate_date(since) params.update({"updated_after": updated_after}) @@ -755,32 +739,65 @@ def api_view_user_requests_filed(username): Parameters ^^^^^^^^^^ - +---------------+----------+--------------+----------------------------+ - | Key | Type | Optionality | Description | - +===============+==========+==============+============================+ - | ``username`` | string | Mandatory | | The username of the user | - | | | | whose activity you are | - | | | | interested in. | - +---------------+----------+--------------+----------------------------+ - | ``status`` | string | Optional | | Filter the status of | - | | | | pull requests. Default: | - | | | | ``Open`` (open pull | - | | | | requests), can be | - | | | | ``Closed`` for closed | - | | | | requests, ``Merged`` | - | | | | for merged requests, or | - | | | | ``Open`` for open | - | | | | requests. | - | | | | ``All`` returns closed, | - | | | | merged and open requests.| - +---------------+----------+--------------+----------------------------+ - | ``page`` | integer | Mandatory | | The page requested. | - | | | | Defaults to 1. | - +---------------+----------+--------------+----------------------------+ - | ``per_page`` | int | Optional | | The number of items to | - | | | | return per page. | - | | | | The maximum is 100. | - +---------------+----------+--------------+----------------------------+ + +---------------+----------+--------------+-----------------------------+ + | Key | Type | Optionality | Description | + +===============+==========+==============+=============================+ + | ``username`` | string | Mandatory | | The username of the user | + | | | | whose activity you are | + | | | | interested in. | + +---------------+----------+--------------+-----------------------------+ + | ``status`` | string | Optional | | Filter the status of | + | | | | pull requests. Default: | + | | | | ``Open`` (open pull | + | | | | requests), can be | + | | | | ``Closed`` for closed | + | | | | requests, ``Merged`` | + | | | | for merged requests, or | + | | | | ``Open`` for open | + | | | | requests. | + | | | | ``All`` returns closed, | + | | | | merged and open requests. | + +---------------+----------+--------------+-----------------------------+ + | ``created`` | string | Optional | | Filter the pull-requests | + | | | | returned by their creation| + | | | | date. The date can be of | + | | | | specified either using | + | | | | a timestamp format or | + | | | | using the iso format for | + | | | | dates: yyyy-mm-dd. | + | | | | You can specify a start | + | | | | and a end date to this | + | | | | filter using start..end. | + +---------------+----------+--------------+-----------------------------+ + | ``updated`` | string | Optional | | Filter the pull-requests | + | | | | returned by their update | + | | | | date. The date can be of | + | | | | specified either using | + | | | | a timestamp format or | + | | | | using the iso format for | + | | | | dates: yyyy-mm-dd. | + | | | | You can specify a start | + | | | | and a end date to this | + | | | | filter using start..end. | + +---------------+----------+--------------+-----------------------------+ + | ``closed`` | string | Optional | | Filter the pull-requests | + | | | | returned by their closing | + | | | | date. The date can be of | + | | | | specified either using | + | | | | a timestamp format or | + | | | | using the iso format for | + | | | | dates: yyyy-mm-dd. | + | | | | You can specify a start | + | | | | and a end date to this | + | | | | filter using start..end. | + +---------------+----------+--------------+-----------------------------+ + | ``page`` | integer | Mandatory | | The page requested. | + | | | | Defaults to 1. | + +---------------+----------+--------------+-----------------------------+ + | ``per_page`` | int | Optional | | The number of items to | + | | | | return per page. | + | | | | The maximum is 100. | + +---------------+----------+--------------+-----------------------------+ Sample response @@ -793,6 +810,9 @@ def api_view_user_requests_filed(username): "status": "open", "username": "dudemcpants", "page": 1, + "created": null, + "updated": null, + "closed": null, }, "pagination": { "first": "http://localhost:5000/api/0/user/dudemcpants/requests/filed?per_page=1&page=1", @@ -931,6 +951,18 @@ def api_view_user_requests_filed(username): """ # noqa status = flask.request.args.get("status", "open") + created = flask.request.args.get("created") + updated = flask.request.args.get("updated") + closed = flask.request.args.get("closed") + + try: + created_since, created_until = validate_date_range(created) + updated_since, updated_until = validate_date_range(updated) + closed_since, closed_until = validate_date_range(closed) + except pagure.exceptions.InvalidTimestampException: + raise pagure.exceptions.APIError(400, error_code=APIERROR.ETIMESTAMP) + except pagure.exceptions.InvalidDateformatException: + raise pagure.exceptions.APIError(400, error_code=APIERROR.EDATETIME) page = get_page() per_page = get_per_page() @@ -948,6 +980,12 @@ def api_view_user_requests_filed(username): username=username, status=status, filed=username, + created_since=created_since, + created_until=created_until, + updated_since=updated_since, + updated_until=updated_until, + closed_since=closed_since, + closed_until=closed_until, count=True, ) pagination = pagure.lib.query.get_pagination_metadata( @@ -959,6 +997,12 @@ def api_view_user_requests_filed(username): username=username, status=status, filed=username, + created_since=created_since, + created_until=created_until, + updated_since=updated_since, + updated_until=updated_until, + closed_since=closed_since, + closed_until=closed_until, offset=offset, limit=limit, ) @@ -975,6 +1019,9 @@ def api_view_user_requests_filed(username): "username": username, "status": orig_status, "page": page, + "created": created, + "updated": updated, + "closed": closed, }, "pagination": pagination, } @@ -1002,28 +1049,61 @@ def api_view_user_requests_actionable(username): Parameters ^^^^^^^^^^ - +---------------+----------+--------------+----------------------------+ - | Key | Type | Optionality | Description | - +===============+==========+==============+============================+ - | ``username`` | string | Mandatory | | The username of the user | - | | | | whose activity you are | - | | | | interested in. | - +---------------+----------+--------------+----------------------------+ - | ``page`` | integer | Mandatory | | The page requested. | - | | | | Defaults to 1. | - +---------------+----------+--------------+----------------------------+ - | ``status`` | string | Optional | | Filter the status of | - | | | | pull requests. Default: | - | | | | ``Open`` (open pull | - | | | | requests), can be | - | | | | ``Closed`` for closed | - | | | | requests, ``Merged`` | - | | | | for merged requests, or | - | | | | ``Open`` for open | - | | | | requests. | - | | | | ``All`` returns closed, | - | | | | merged and open requests.| - +---------------+----------+--------------+----------------------------+ + +---------------+----------+--------------+-----------------------------+ + | Key | Type | Optionality | Description | + +===============+==========+==============+=============================+ + | ``username`` | string | Mandatory | | The username of the user | + | | | | whose activity you are | + | | | | interested in. | + +---------------+----------+--------------+-----------------------------+ + | ``created`` | string | Optional | | Filter the pull-requests | + | | | | returned by their creation| + | | | | date. The date can be of | + | | | | specified either using | + | | | | a timestamp format or | + | | | | using the iso format for | + | | | | dates: yyyy-mm-dd. | + | | | | You can specify a start | + | | | | and a end date to this | + | | | | filter using start..end. | + +---------------+----------+--------------+-----------------------------+ + | ``updated`` | string | Optional | | Filter the pull-requests | + | | | | returned by their update | + | | | | date. The date can be of | + | | | | specified either using | + | | | | a timestamp format or | + | | | | using the iso format for | + | | | | dates: yyyy-mm-dd. | + | | | | You can specify a start | + | | | | and a end date to this | + | | | | filter using start..end. | + +---------------+----------+--------------+-----------------------------+ + | ``closed`` | string | Optional | | Filter the pull-requests | + | | | | returned by their closing | + | | | | date. The date can be of | + | | | | specified either using | + | | | | a timestamp format or | + | | | | using the iso format for | + | | | | dates: yyyy-mm-dd. | + | | | | You can specify a start | + | | | | and a end date to this | + | | | | filter using start..end. | + +---------------+----------+--------------+-----------------------------+ + | ``page`` | integer | Mandatory | | The page requested. | + | | | | Defaults to 1. | + +---------------+----------+--------------+-----------------------------+ + | ``status`` | string | Optional | | Filter the status of | + | | | | pull requests. Default: | + | | | | ``Open`` (open pull | + | | | | requests), can be | + | | | | ``Closed`` for closed | + | | | | requests, ``Merged`` | + | | | | for merged requests, or | + | | | | ``Open`` for open | + | | | | requests. | + | | | | ``All`` returns closed, | + | | | | merged and open requests. | + +---------------+----------+--------------+-----------------------------+ Sample response ^^^^^^^^^^^^^^^ @@ -1035,6 +1115,9 @@ def api_view_user_requests_actionable(username): "status": "open", "username": "ryanlerch", "page": 1, + "created": null, + "updated": null, + "closed": null, }, "pagination": { "first": "http://localhost:5000/api/0/user/ryanlerch/requests/actionable?per_page=1&page=1", @@ -1173,6 +1256,18 @@ def api_view_user_requests_actionable(username): """ # noqa status = flask.request.args.get("status", "open") + created = flask.request.args.get("created") + updated = flask.request.args.get("updated") + closed = flask.request.args.get("closed") + + try: + created_since, created_until = validate_date_range(created) + updated_since, updated_until = validate_date_range(updated) + closed_since, closed_until = validate_date_range(closed) + except pagure.exceptions.InvalidTimestampException: + raise pagure.exceptions.APIError(400, error_code=APIERROR.ETIMESTAMP) + except pagure.exceptions.InvalidDateformatException: + raise pagure.exceptions.APIError(400, error_code=APIERROR.EDATETIME) page = get_page() per_page = get_per_page() @@ -1190,6 +1285,12 @@ def api_view_user_requests_actionable(username): username=username, status=status, actionable=username, + created_since=created_since, + created_until=created_until, + updated_since=updated_since, + updated_until=updated_until, + closed_since=closed_since, + closed_until=closed_until, count=True, ) pagination = pagure.lib.query.get_pagination_metadata( @@ -1201,6 +1302,12 @@ def api_view_user_requests_actionable(username): username=username, status=status, actionable=username, + created_since=created_since, + created_until=created_until, + updated_since=updated_since, + updated_until=updated_until, + closed_since=closed_since, + closed_until=closed_until, offset=offset, limit=limit, ) @@ -1217,6 +1324,9 @@ def api_view_user_requests_actionable(username): "username": username, "status": orig_status, "page": page, + "created": created, + "updated": updated, + "closed": closed, }, "pagination": pagination, } diff --git a/pagure/exceptions.py b/pagure/exceptions.py index 78677f4..ed2fcc4 100644 --- a/pagure/exceptions.py +++ b/pagure/exceptions.py @@ -117,3 +117,15 @@ class PagurePushDenied(PagureException): """ Exception raised if a remote hook rejected a push """ pass + + +class InvalidTimestampException(PagureException): + """ Exception raised when the hook is inactive. """ + + pass + + +class InvalidDateformatException(PagureException): + """ Exception raised when the hook is inactive. """ + + pass diff --git a/pagure/lib/query.py b/pagure/lib/query.py index 2fad9fd..8ffb8fb 100644 --- a/pagure/lib/query.py +++ b/pagure/lib/query.py @@ -4359,6 +4359,12 @@ def get_pull_request_of_user( actionable=None, offset=None, limit=None, + created_since=None, + created_until=None, + updated_since=None, + updated_until=None, + closed_since=None, + closed_until=None, count=False, ): """List the opened pull-requests of an user. @@ -4456,6 +4462,21 @@ def get_pull_request_of_user( model.User.user != actionable, ) + if created_since: + query = query.filter(model.PullRequest.date_created >= created_since) + if created_until: + query = query.filter(model.PullRequest.date_created <= created_until) + + if updated_since: + query = query.filter(model.PullRequest.updated_on <= updated_since) + if updated_until: + query = query.filter(model.PullRequest.updated_on <= updated_until) + + if closed_since: + query = query.filter(model.PullRequest.closed_at <= closed_since) + if closed_until: + query = query.filter(model.PullRequest.closed_at <= closed_until) + if offset: query = query.offset(offset) if limit: diff --git a/pagure/utils.py b/pagure/utils.py index 45c6d14..d575df8 100644 --- a/pagure/utils.py +++ b/pagure/utils.py @@ -10,6 +10,7 @@ from __future__ import unicode_literals, absolute_import +import datetime import logging import logging.config import os @@ -22,7 +23,11 @@ import pygit2 import six import werkzeug -from pagure.exceptions import PagureException +from pagure.exceptions import ( + PagureException, + InvalidTimestampException, + InvalidDateformatException, +) from pagure.config import config as pagure_config @@ -656,6 +661,49 @@ def is_true(value, trueish=("1", "true", "t", "y")): return value.strip().lower() in trueish +def validate_date(input_date, allow_empty=False): + """ Validate a given time. + The time can either be given as an unix timestamp or using the + yyyy-mm-dd format. + If either fail to parse, we raise a 400 error + """ + if allow_empty and input_date == "": + return None + # Validate and convert the time + if input_date.isdigit(): + # We assume its a timestamp, so convert it to datetime + try: + output_date = datetime.datetime.fromtimestamp(int(input_date)) + except ValueError: + raise InvalidTimestampException() + else: + # We assume datetime format, so validate it + try: + output_date = datetime.datetime.strptime(input_date, "%Y-%m-%d") + except ValueError: + raise InvalidDateformatException() + + return output_date + + +def validate_date_range(value): + """ Validate a given date range specified using the format since..until. + If .. is not present in the range, it is assumed that only since was + provided. + """ + since = until = None + if value is not None: + if ".." in value: + since, _, until = value.partition("..") + else: + since = value + if since is not None: + since = validate_date(since, allow_empty=True) + if until is not None: + until = validate_date(until, allow_empty=True) + return (since, until) + + def get_merge_options(request, merge_status): MERGE_OPTIONS = { "NO_CHANGE": { diff --git a/tests/test_pagure_flask_api_user.py b/tests/test_pagure_flask_api_user.py index dc885af..4f787d8 100644 --- a/tests/test_pagure_flask_api_user.py +++ b/tests/test_pagure_flask_api_user.py @@ -921,6 +921,129 @@ class PagureFlaskApiUsertestrequests(tests.Modeltests): self.assertEqual(data['args']['page'], 2) @patch('pagure.lib.notify.send_email') + def test_api_view_user_requests_filed_created(self, mockemail): + """ Test the api_view_user_requests_filed method of the flask user + api with the created parameter """ + + today = datetime.datetime.utcnow().date() + output = self.app.get( + '/api/0/user/pingou/requests/filed?status=all&created=%s' % ( + today.isoformat())) + self.assertEqual(output.status_code, 200) + data = json.loads(output.get_data(as_text=True)) + self.assertEqual(len(data['requests']), 6) + + yesterday = today - datetime.timedelta(days=1) + output = self.app.get( + '/api/0/user/pingou/requests/filed?status=all&created=%s' % ( + yesterday.isoformat())) + self.assertEqual(output.status_code, 200) + data = json.loads(output.get_data(as_text=True)) + self.assertEqual(len(data['requests']), 6) + + tomorrow = today + datetime.timedelta(days=1) + output = self.app.get( + '/api/0/user/pingou/requests/filed?status=all&created=%s' % ( + tomorrow.isoformat())) + self.assertEqual(output.status_code, 200) + data = json.loads(output.get_data(as_text=True)) + self.assertEqual(len(data['requests']), 0) + + output = self.app.get( + '/api/0/user/pingou/requests/filed?status=all&created=..%s' % ( + today.isoformat())) + self.assertEqual(output.status_code, 200) + data = json.loads(output.get_data(as_text=True)) + self.assertEqual(len(data['requests']), 0) + + output = self.app.get( + '/api/0/user/pingou/requests/filed?status=all&created=..%s' % ( + yesterday.isoformat())) + self.assertEqual(output.status_code, 200) + data = json.loads(output.get_data(as_text=True)) + self.assertEqual(len(data['requests']), 0) + + thedaybefore = today - datetime.timedelta(days=1) + output = self.app.get( + '/api/0/user/pingou/requests/filed?status=all&created=..%s' % ( + thedaybefore.isoformat())) + self.assertEqual(output.status_code, 200) + data = json.loads(output.get_data(as_text=True)) + self.assertEqual(len(data['requests']), 0) + + output = self.app.get( + '/api/0/user/pingou/requests/filed?status=all&created=..%s' % ( + tomorrow.isoformat())) + self.assertEqual(output.status_code, 200) + data = json.loads(output.get_data(as_text=True)) + self.assertEqual(len(data['requests']), 6) + + output = self.app.get( + '/api/0/user/pingou/requests/filed?status=all&created=%s..%s' % ( + thedaybefore.isoformat(), tomorrow.isoformat())) + self.assertEqual(output.status_code, 200) + data = json.loads(output.get_data(as_text=True)) + self.assertEqual(len(data['requests']), 6) + + @patch('pagure.lib.notify.send_email') + def test_api_view_user_requests_filed_updated(self, mockemail): + """ Test the api_view_user_requests_filed method of the flask user + api with the created parameter """ + + today = datetime.datetime.utcnow().date() + output = self.app.get( + '/api/0/user/pingou/requests/filed?status=all&updated=%s' % ( + today.isoformat())) + self.assertEqual(output.status_code, 200) + data = json.loads(output.get_data(as_text=True)) + self.assertEqual(len(data['requests']), 0) + + yesterday = today - datetime.timedelta(days=1) + output = self.app.get( + '/api/0/user/pingou/requests/filed?status=all&updated=%s' % ( + yesterday.isoformat())) + self.assertEqual(output.status_code, 200) + data = json.loads(output.get_data(as_text=True)) + self.assertEqual(len(data['requests']), 0) + + tomorrow = today + datetime.timedelta(days=1) + output = self.app.get( + '/api/0/user/pingou/requests/filed?status=all&updated=%s' % ( + tomorrow.isoformat())) + self.assertEqual(output.status_code, 200) + data = json.loads(output.get_data(as_text=True)) + self.assertEqual(len(data['requests']), 6) + + @patch('pagure.lib.notify.send_email') + def test_api_view_user_requests_filed_closed(self, mockemail): + """ Test the api_view_user_requests_filed method of the flask user + api with the created parameter """ + + today = datetime.datetime.utcnow().date() + output = self.app.get( + '/api/0/user/pingou/requests/filed?status=all&closed=%s' % ( + today.isoformat())) + self.assertEqual(output.status_code, 200) + data = json.loads(output.get_data(as_text=True)) + self.assertEqual(len(data['requests']), 0) + + yesterday = today - datetime.timedelta(days=1) + output = self.app.get( + '/api/0/user/pingou/requests/filed?status=all&closed=%s' % ( + yesterday.isoformat())) + self.assertEqual(output.status_code, 200) + data = json.loads(output.get_data(as_text=True)) + self.assertEqual(len(data['requests']), 0) + + tomorrow = today + datetime.timedelta(days=1) + output = self.app.get( + '/api/0/user/pingou/requests/filed?status=all&closed=%s' % ( + tomorrow.isoformat())) + self.assertEqual(output.status_code, 200) + data = json.loads(output.get_data(as_text=True)) + self.assertEqual(len(data['requests']), 0) + + @patch('pagure.lib.notify.send_email') def test_api_view_user_requests_filed_foo(self, mockemail): """ Test the api_view_user_requests_filed method of the flask user api """ @@ -1111,6 +1234,130 @@ class PagureFlaskApiUsertestrequests(tests.Modeltests): self.assertEqual(data['args']['page'], 2) + @patch('pagure.lib.notify.send_email') + def test_api_view_user_requests_actionable_created(self, mockemail): + """ Test the api_view_user_requests_filed method of the flask user + api with the created parameter """ + + today = datetime.datetime.utcnow().date() + output = self.app.get( + '/api/0/user/pingou/requests/actionable?status=all&created=%s' % ( + today.isoformat())) + self.assertEqual(output.status_code, 200) + data = json.loads(output.get_data(as_text=True)) + self.assertEqual(len(data['requests']), 6) + + yesterday = today - datetime.timedelta(days=1) + output = self.app.get( + '/api/0/user/pingou/requests/actionable?status=all&created=%s' % ( + yesterday.isoformat())) + self.assertEqual(output.status_code, 200) + data = json.loads(output.get_data(as_text=True)) + self.assertEqual(len(data['requests']), 6) + + tomorrow = today + datetime.timedelta(days=1) + output = self.app.get( + '/api/0/user/pingou/requests/actionable?status=all&created=%s' % ( + tomorrow.isoformat())) + self.assertEqual(output.status_code, 200) + data = json.loads(output.get_data(as_text=True)) + self.assertEqual(len(data['requests']), 0) + + output = self.app.get( + '/api/0/user/pingou/requests/actionable?status=all&created=..%s' % ( + today.isoformat())) + self.assertEqual(output.status_code, 200) + data = json.loads(output.get_data(as_text=True)) + self.assertEqual(len(data['requests']), 0) + + output = self.app.get( + '/api/0/user/pingou/requests/actionable?status=all&created=..%s' % ( + yesterday.isoformat())) + self.assertEqual(output.status_code, 200) + data = json.loads(output.get_data(as_text=True)) + self.assertEqual(len(data['requests']), 0) + + thedaybefore = today - datetime.timedelta(days=1) + output = self.app.get( + '/api/0/user/pingou/requests/actionable?status=all&created=..%s' % ( + thedaybefore.isoformat())) + self.assertEqual(output.status_code, 200) + data = json.loads(output.get_data(as_text=True)) + self.assertEqual(len(data['requests']), 0) + + output = self.app.get( + '/api/0/user/pingou/requests/actionable?status=all&created=..%s' % ( + tomorrow.isoformat())) + self.assertEqual(output.status_code, 200) + data = json.loads(output.get_data(as_text=True)) + self.assertEqual(len(data['requests']), 6) + + output = self.app.get( + '/api/0/user/pingou/requests/actionable?status=all&created=%s..%s' % ( + thedaybefore.isoformat(), tomorrow.isoformat())) + self.assertEqual(output.status_code, 200) + data = json.loads(output.get_data(as_text=True)) + self.assertEqual(len(data['requests']), 6) + + @patch('pagure.lib.notify.send_email') + def test_api_view_user_requests_actionable_updated(self, mockemail): + """ Test the api_view_user_requests_filed method of the flask user + api with the created parameter """ + + today = datetime.datetime.utcnow().date() + output = self.app.get( + '/api/0/user/pingou/requests/actionable?status=all&updated=%s' % ( + today.isoformat())) + self.assertEqual(output.status_code, 200) + data = json.loads(output.get_data(as_text=True)) + self.assertEqual(len(data['requests']), 0) + + yesterday = today - datetime.timedelta(days=1) + output = self.app.get( + '/api/0/user/pingou/requests/actionable?status=all&updated=%s' % ( + yesterday.isoformat())) + self.assertEqual(output.status_code, 200) + data = json.loads(output.get_data(as_text=True)) + self.assertEqual(len(data['requests']), 0) + + tomorrow = today + datetime.timedelta(days=1) + output = self.app.get( + '/api/0/user/pingou/requests/actionable?status=all&updated=%s' % ( + tomorrow.isoformat())) + self.assertEqual(output.status_code, 200) + data = json.loads(output.get_data(as_text=True)) + self.assertEqual(len(data['requests']), 6) + + @patch('pagure.lib.notify.send_email') + def test_api_view_user_requests_actionable_closed(self, mockemail): + """ Test the api_view_user_requests_filed method of the flask user + api with the created parameter """ + + today = datetime.datetime.utcnow().date() + output = self.app.get( + '/api/0/user/pingou/requests/actionable?status=all&closed=%s' % ( + today.isoformat())) + self.assertEqual(output.status_code, 200) + data = json.loads(output.get_data(as_text=True)) + self.assertEqual(len(data['requests']), 0) + + yesterday = today - datetime.timedelta(days=1) + output = self.app.get( + '/api/0/user/pingou/requests/actionable?status=all&closed=%s' % ( + yesterday.isoformat())) + self.assertEqual(output.status_code, 200) + data = json.loads(output.get_data(as_text=True)) + self.assertEqual(len(data['requests']), 0) + + tomorrow = today + datetime.timedelta(days=1) + output = self.app.get( + '/api/0/user/pingou/requests/actionable?status=all&closed=%s' % ( + tomorrow.isoformat())) + self.assertEqual(output.status_code, 200) + data = json.loads(output.get_data(as_text=True)) + self.assertEqual(len(data['requests']), 0) + + class PagureFlaskApiUsertestissues(tests.Modeltests): """ Tests for the user issues endpoints """