diff --git a/tests/conftest.py b/tests/conftest.py index d966338..b25309a 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -21,7 +21,12 @@ def bob(client): @pytest.fixture -def created_manifestation_resp(client, user): +def carly(client): + return client.post(url_for('user_views.userapi')).json + + +@pytest.fixture +def created_manifestation_resp(client, alice): import json from time import sleep payload = { @@ -44,3 +49,27 @@ def created_manifestation_resp(client, user): # Sleep for a bit to let the transaction become valid sleep(3) return resp.json + + +@pytest.fixture +def created_derived_right(client, alice, created_manifestation_resp): + import json + from time import sleep + + copyright_id = created_manifestation_resp['copyright']['@id'] + copyright_id = copyright_id.split('../rights/')[1] + payload = { + 'currentHolder': alice, + 'right': { + 'license': 'http://www.ascribe.io/terms', + }, + 'sourceRightId': copyright_id, + } + + resp = client.post(url_for('right_views.rightapi'), + data=json.dumps(payload), + headers={'Content-Type': 'application/json'}) + + # Sleep for a bit to let the transaction become valid + sleep(3) + return resp.json['right'] diff --git a/tests/test_api.py b/tests/test_api.py index bc54402..c37f622 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -169,3 +169,60 @@ def test_create_right_missing_argument_in_body(client, alice): assert resp.status_code == 400 assert resp.json['message']['sourceRightId'] == \ 'Missing required parameter in the JSON body' + + +def test_transfer_right(client, alice, bob, carly, created_derived_right): + from time import sleep + + payload = { + 'rightId': created_derived_right['@id'], + 'rightsAssignment': { + 'action': 'loan', + }, + 'currentHolder': alice, + 'to': bob, + } + + expected = { + 'rightsAssignment': { + '@context': ['', 'http://schema.org/'], + '@type': 'RightsTransferAction', + '@id': '', + 'action': 'loan', + }, + } + + resp = client.post(url_for('right_views.righttransferapi'), + data=json.dumps(payload), + headers={'Content-Type': 'application/json'}) + assert resp.status_code == 200 + assert resp.json == expected + + # Test re-transfer, after waiting for the first transfer to become valid + sleep(3) + retransfer_payload = { + 'rightId': created_derived_right['@id'], + 'rightsAssignment': { + 'action': 'reloan', + }, + 'currentHolder': bob, + 'to': { + 'publicKey': carly['publicKey'], + 'privateKey': None, + } + } + + retransfer_expected = { + 'rightsAssignment': { + '@context': ['', 'http://schema.org/'], + '@type': 'RightsTransferAction', + '@id': '', + 'action': 'reloan', + }, + } + + resp = client.post(url_for('right_views.righttransferapi'), + data=json.dumps(retransfer_payload), + headers={'Content-Type': 'application/json'}) + assert resp.status_code == 200 + assert resp.json == retransfer_expected diff --git a/web/views/rights.py b/web/views/rights.py index 6f94fe0..4241587 100644 --- a/web/views/rights.py +++ b/web/views/rights.py @@ -1,7 +1,7 @@ from flask import Blueprint from flask_restful import reqparse, Resource, Api -from coalaip import CoalaIp +from coalaip import CoalaIp, ModelDataError, entities from coalaip_bigchaindb.plugin import Plugin from web.models import right_model, user_model from web.utils import get_bigchaindb_api_url @@ -42,4 +42,49 @@ def post(self): return res +class RightTransferApi(Resource): + def post(self): + parser = reqparse.RequestParser() + parser.add_argument('rightId', type=str, required=True, + location='json') + parser.add_argument('currentHolder', type=user_model, required=True, + location='json') + parser.add_argument('to', type=user_model, required=True, + location='json') + parser.add_argument('rightsAssignment', type=dict, location='json') + args = parser.parse_args() + + right_id = args['rightId'] + current_holder = args['currentHolder'] + to = args['to'] + rights_assignment = args['rightsAssignment'] + + for user in [current_holder, to]: + user['public_key'] = user.pop('publicKey') + user['private_key'] = user.pop('privateKey') + + # We can't be sure of the type of Right that's given by using just the + # id, so let's assume it's a normal Right first before trying to make a + # Copyright + try: + right = entities.Right.from_persist_id(right_id, + plugin=coalaip.plugin, + force_load=True) + except ModelDataError: + right = entities.Copyright.from_persist_id(right_id, + plugin=coalaip.plugin, + force_load=True) + + res = coalaip.transfer_right(right=right, + rights_assignment_data=rights_assignment, + current_holder=current_holder, + to=to) + + res = {'rightsAssignment': res.to_jsonld()} + + return res + + right_api.add_resource(RightApi, '/rights', strict_slashes=False) +right_api.add_resource(RightTransferApi, '/rights/transfer', + strict_slashes=False)