From 27ba71d97cc02bcd1cc1a6db8c24d1042e52908c Mon Sep 17 00:00:00 2001 From: Lukas Holecek Date: May 07 2018 08:12:57 +0000 Subject: Allow creating multiple waivers To create multiple waivers, POST list to "waivers/" instead of single waiver (`[{...}, ...]` instead of `{...}`). Fixes #98 --- diff --git a/tests/test_api_v10.py b/tests/test_api_v10.py index 9ab0541..7291682 100644 --- a/tests/test_api_v10.py +++ b/tests/test_api_v10.py @@ -9,6 +9,7 @@ from mock import patch, Mock from .utils import create_waiver from waiverdb import __version__ +from waiverdb.models import Waiver @patch('waiverdb.auth.get_user', return_value=('foo', {})) @@ -567,3 +568,59 @@ def test_no_cors_waivers(client, session): res_data = json.loads(r.get_data(as_text=True)) assert r.status_code == 200 assert len(res_data['data']) == 3 + + +@patch('waiverdb.auth.get_user', return_value=('foo', {})) +def test_create_multiple_waivers(mocked_get_user, client, session): + item1 = { + 'subject': {'subject.test': 'subject1'}, + 'testcase': 'testcase1', + 'product_version': 'fool-1', + 'waived': True, + 'comment': 'it broke', + } + item2 = { + 'subject': {'subject.test': 'subject2'}, + 'testcase': 'testcase2', + 'product_version': 'fool-2', + 'waived': False, + 'comment': 'fixed', + } + data = [item1, item2] + + r = client.post('/api/v1.0/waivers/', data=json.dumps(data), + content_type='application/json') + + res_data = json.loads(r.get_data(as_text=True)) + assert r.status_code == 201 + assert isinstance(res_data, list) + assert len(res_data) == 2 + + actual_item1 = {k: v for k, v in res_data[0].items() if k in item1} + actual_item2 = {k: v for k, v in res_data[1].items() if k in item2} + assert actual_item1 == item1 + assert actual_item2 == item2 + + # Transaction was not rolled back. + assert session.query(Waiver).count() == 2 + + +@patch('waiverdb.auth.get_user', return_value=('foo', {})) +def test_create_multiple_waivers_rollback_on_error(mocked_get_user, client, session): + item1 = { + 'subject': {'subject.test': 'subject1'}, + 'testcase': 'testcase1', + 'product_version': 'fool-1', + 'waived': True, + 'comment': 'it broke', + } + item2 = {} + data = [item1, item2] + + r = client.post('/api/v1.0/waivers/', data=json.dumps(data), + content_type='application/json') + + assert r.status_code == 400 + + # Transaction was rolled back. + assert session.query(Waiver).count() == 0 diff --git a/waiverdb/api_v1.py b/waiverdb/api_v1.py index 8090f13..a62ab3a 100644 --- a/waiverdb/api_v1.py +++ b/waiverdb/api_v1.py @@ -111,6 +111,15 @@ RP['get_waivers'].add_argument('limit', default=10, type=int, location='args') RP['get_waivers'].add_argument('proxied_by', location='args') +class DummyJsonRequest(object): + """ + Can be passed to reqparse.RequestParser.parse_args() instead of current + request. + """ + def __init__(self, data): + self.json = data + + class WaiversResource(Resource): @jsonp def get(self): @@ -194,7 +203,10 @@ class WaiversResource(Resource): @marshal_with(waiver_fields) def post(self): """ - Create a new waiver. + Create a new waiver or multiple waivers. + + To create multiple waivers, pass list of dict instead. Response also + contains list on success. **Sample request**: @@ -251,7 +263,26 @@ class WaiversResource(Resource): """ user, headers = waiverdb.auth.get_user(request) - args = RP['create_waiver'].parse_args() + data = request.get_json(force=True) + + if isinstance(data, list): + result = [] + for sub_data in data: + sub_request = DummyJsonRequest(sub_data) + args = RP['create_waiver'].parse_args(sub_request) + one_result = self._create_waiver(args, user) + result.append(one_result) + db.session.add_all(result) + else: + args = RP['create_waiver'].parse_args() + result = self._create_waiver(args, user) + db.session.add(result) + + db.session.commit() + + return result, 201, headers + + def _create_waiver(self, args, user): proxied_by = None if args.get('username'): if user not in current_app.config['SUPERUSERS']: @@ -295,11 +326,14 @@ class WaiversResource(Resource): if not args['comment']: raise BadRequest('Comment is a required argument.') - waiver = Waiver(args['subject'], args['testcase'], user, - args['product_version'], args['waived'], args['comment'], proxied_by) - db.session.add(waiver) - db.session.commit() - return waiver, 201, headers + return Waiver( + args['subject'], + args['testcase'], + user, + args['product_version'], + args['waived'], + args['comment'], + proxied_by) class WaiverResource(Resource):