From fbb5906058a13d9d9930bd829bf998bf885c5335 Mon Sep 17 00:00:00 2001 From: hadleyking Date: Mon, 11 Sep 2023 10:30:25 -0400 Subject: [PATCH 1/2] Add test file Changes to be committed: modified: api/views.py new file: tests/test_views/test_api_objects_drafts_modify.py --- api/views.py | 112 +++++++++--------- .../test_api_objects_drafts_modify.py | 67 +++++++++++ 2 files changed, 121 insertions(+), 58 deletions(-) create mode 100644 tests/test_views/test_api_objects_drafts_modify.py diff --git a/api/views.py b/api/views.py index 74046e76..6831d187 100755 --- a/api/views.py +++ b/api/views.py @@ -79,7 +79,6 @@ # For helper functions from api.scripts.utilities import UserUtils -from authentication.services import CustomJSONWebTokenAuthentication ################################################################################################ # NOTES @@ -197,10 +196,14 @@ def get(self, request, username: str, temp_identifier: str): {"activation_success": False, "status": status.HTTP_400_BAD_REQUEST} ) + +# Source: https://www.django-rest-framework.org/api-guide/authentication/#by-exposing-an-api-endpoint class ApiAccountsDescribe(APIView): - """Account details + """ + Account details -------------------- + No schema for this request since only the Authorization header is required. The word 'Token' must be included in the header. For example: 'Token 627626823549f787c3ec763ff687169206626149' """ @@ -218,12 +221,16 @@ class ApiAccountsDescribe(APIView): manual_parameters=auth, responses={ 200: "Authorization is successful.", - 403: "Forbidden. Authentication credentials were not provided, or the token is invalid.", + 403: "Forbidden. Authentication credentials were not provided.", + 403: "Invalid token" }, tags=["Account Management"], ) def post(self, request): - """""" + """ + Pass the request to the handling function + Source: https://stackoverflow.com/a/31813810 + """ if request.headers["Authorization"].split(" ")[0] == "Token" or request.headers["Authorization"].split(" ")[0] == "TOKEN": return POST_api_accounts_describe( @@ -624,8 +631,9 @@ class ApiObjectsDraftsModify(APIView): -------------------- - Modifies a BCO object. The BCO object must be a draft in order to be modifiable. The contents of the BCO will be replaced with the - new contents provided in the request body. + Modifies a BCO object. The BCO object must be a draft in order to be + modifiable. WARNING: The contents of the BCO will be replaced with the new + contents provided in the request body. """ POST_api_objects_drafts_modify_schema = openapi.Schema( @@ -661,6 +669,16 @@ class ApiObjectsDraftsModify(APIView): request_body=request_body, responses={ 200: "Modification of BCO draft is successful.", + 207: "Some or all BCO modifications failed. Each object submitted" + " will have it's own response object with it's own status" + " code and message:\n" + "201: The prefix * was successfully created.\n" + "400: Bad Request. The expiration date * is not valid.\n" + "400: Bad Request. The prefix * does not follow the naming rules for a prefix.\n" + "403: Forbidden. User does not have permission to perform this action.\n" + "404: Not Found. The user * was not found on the server.\n" + "409: Conflict. The prefix the requestor is attempting to create already exists.\n", + 401: "Unauthorized. Authentication credentials were not provided.", 400: "Bad request.", 403: "Invalid token.", }, @@ -793,39 +811,22 @@ def post(self, request) -> Response: # TODO: What is the difference between this and ApiObjectsPublish? class ApiObjectsDraftsPublish(APIView): """ - Bulk Publish BCOs + Publish a BCO -------------------- - - Publish draft BCO objects. Once published, a BCO object becomes immutable. - The `object_id` field is optional, and is used to specify if the object - should be published as a specific version, instead of the next available numeric - version. - - ```json - { - "POST_api_objects_drafts_publish": [ - { - "prefix": "TEST", - "draft_id": "http://127.0.0.1:8000/TEST_000001", - "object_id": "http://127.0.0.1:8000/TEST_000001/1.0", - "delete_draft": false - } - ] - } + Publish a draft BCO object. Once published, a BCO object becomes immutable. """ # TODO: This seems to be missing group, which I would expect to be part of the publication - permission_classes = [IsAuthenticated,] - # authentication_classes = [CustomJSONWebTokenAuthentication] + permission_classes = [IsAuthenticated] POST_api_objects_drafts_publish_schema = openapi.Schema( type=openapi.TYPE_OBJECT, required=["draft_id", "prefix"], properties={ "prefix": openapi.Schema( - type=openapi.TYPE_STRING, description="BCO Prefix to publish with." + type=openapi.TYPE_STRING, description="BCO Prefix to publish with." ), "draft_id": openapi.Schema( type=openapi.TYPE_STRING, description="BCO Object Draft ID." @@ -857,14 +858,13 @@ class ApiObjectsDraftsPublish(APIView): @swagger_auto_schema( request_body=request_body, responses={ - 200: "All BCO publications successful.", - 207: "Some or all publications failed.", + 200: "BCO Publication is successful.", + 300: "Some requests failed.", 400: "Bad request.", - 403: "Authentication credentials were not provided.", + 403: "Invalid token.", }, tags=["BCO Management"], ) - def post(self, request) -> Response: return check_post_and_process(request, post_api_objects_drafts_publish) @@ -1045,10 +1045,7 @@ class ApiObjectsSearch(APIView): Shell ```shell - curl -X POST "http://localhost:8000/api/objects/search/" -H "accept: - application/json" -H "Authorization: Token ${token}" -H "Content-Type: - application/json" -d "{\"POST_api_objects_search\": - [{\"type\": \"prefix\",\"search\": \"TEST\"}]}" + curl -X POST "http://localhost:8000/api/objects/search/" -H "accept: application/json" -H "Authorization: Token ${token}" -H "Content-Type: application/json" -d "{\"POST_api_objects_search\":[{\"type\": \"prefix\",\"search\": \"TEST\"}]}" ``` JavaScript @@ -1216,8 +1213,13 @@ class ApiPrefixesCreate(APIView): ``` """ - permission_classes = [RequestorInPrefixAdminsGroup, IsAuthenticated, ] + # Permissions - prefix admins only + permission_classes = [RequestorInPrefixAdminsGroup] + # TYPE_ARRAY explanation + # Source: https://stackoverflow.com/questions/53492889/drf-yasg-doesnt-take-type-array-as-a-valid-type + + # TODO: Need to get the schema that is being sent here from FE request_body = openapi.Schema( type=openapi.TYPE_OBJECT, title="Prefix Creation Schema", @@ -1251,17 +1253,13 @@ class ApiPrefixesCreate(APIView): @swagger_auto_schema( request_body=request_body, responses={ - 200: "All prefixes were successfully created.", - 207: "Some or all prefix creations failed. Each object submitted" - " will have it's own response object with it's own status" - " code and message:\n" - "201: The prefix * was successfully created.\n" - "400: Bad Request. The expiration date * is not valid.\n" - "400: Bad Request. The prefix * does not follow the naming rules for a prefix.\n" - "403: Forbidden. User does not have permission to perform this action.\n" - "404: Not Found. The user * was not found on the server.\n" - "409: Conflict. The prefix the requestor is attempting to create already exists.\n", - 401: "Unauthorized. Authentication credentials were not provided." + 201: "The prefix was successfully created.", + 400: "Bad request for one of two reasons: \n1) the prefix does not" + "follow the naming standard, or \n2) owner_user and/or" + "owner_group do not exist.", + 401: "Unauthorized. Authentication credentials were not provided.", + 403: "Forbidden. User doesnot have permission to perform this action", + 409: "The prefix the requestor is attempting to create already exists.", }, tags=["Prefix Management"], ) @@ -1468,6 +1466,7 @@ class ApiPrefixesPermissionsSet(APIView): ] } ``` + """ # Permissions - prefix admins only @@ -1521,11 +1520,10 @@ class ApiPrefixesToken(APIView): -------------------- - Get all available prefixes and their associated permissions for a given - token. The word 'Token' must be included in the header. + Get all available prefixes and their associated permissions for a given token. + The word 'Token' must be included in the header. - For example: 'Token 627626823549f787c3ec763ff687169206626149'. Using that - token will return an empty list, as that is test user. + For example: 'Token 627626823549f787c3ec763ff687169206626149'. """ auth = [ @@ -1540,20 +1538,18 @@ class ApiPrefixesToken(APIView): @swagger_auto_schema( manual_parameters=auth, responses={ - 200: "The available prefixes were returned.", - 401: "The authorization header was not provided.", - 403: "Invalid token.", + 200: "The Authorization header was provided and available prefixes were returned.", + 400: "The Authorization header was not provided.", }, tags=["Prefix Management"], ) def post(self, request) -> Response: if "Authorization" in request.headers: + # Pass the request to the handling function + # Source: https://stackoverflow.com/a/31813810 return post_api_prefixes_token_flat(request=request) else: - return Response( - data={"detail": "The authorization header was not provided."}, - status=status.HTTP_401_UNAUTHORIZED - ) + return Response(status=status.HTTP_400_BAD_REQUEST) class ApiPrefixesTokenFlat(APIView): diff --git a/tests/test_views/test_api_objects_drafts_modify.py b/tests/test_views/test_api_objects_drafts_modify.py new file mode 100644 index 00000000..02ff16e8 --- /dev/null +++ b/tests/test_views/test_api_objects_drafts_modify.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python3 + +"""Modify BCO Draft +Tests for 200 and 403. +Gives error for 400. requires debugging +""" + +from django.test import TestCase +from rest_framework.test import APIClient +from rest_framework.authtoken.models import Token +from django.contrib.auth.models import User +from rest_framework.test import APITestCase +from api.models import BCO + +class ModifyBCODraftTestCase(APITestCase): + fixtures = ['tests/fixtures/test_data'] + + def setUp(self): + self.client = APIClient() + + def test_modify_bco_draft_success(self): + "Valid request to modify a BCO draft" + + token = Token.objects.get(user=User.objects.get(username='test50')).key + + import pdb; pdb.set_trace() + self.client.credentials(HTTP_AUTHORIZATION='Token ' + self.token.key) + response = self.client.post('/api/objects/drafts/modify/', data={"data"}, format='json') + self.assertEqual(response.status_code, 200) + + def test_modify_bco_draft_bad_request(self): + # Invalid request: Bad request + ##Giving an error I dont understand + + data = { + # Provide invalid or missing data + "POST_api_objects_drafts_modify": [ + { + + "object_id": "http://127.0.0.1:8000/BCO_000001/DRAFT", + "contents": { + "additionalProp1": {} + + } + } + ] + } + self.client.credentials(HTTP_AUTHORIZATION='Token ' + self.token.key) + response = self.client.post('/api/objects/drafts/modify/', data=data, format='json') + self.assertEqual(response.status_code, 400) + + def test_modify_bco_draft_invalid_token(self): + # Request with invalid token or without authentication credentials + + data = { + "POST_api_objects_drafts_modify": [ + { + "object_id": "http://127.0.0.1:8000/OTHER_000001/DRAFT", + "contents": { + "additionalProp1": {} + } + } + ] + } + self.client.credentials(HTTP_AUTHORIZATION='Invalid_token ') + response = self.client.post('/api/objects/drafts/modify/', data=data, format='json') + self.assertEqual(response.status_code, 403) From 933a0010f158f4a516903e9bf18aa4129e1b6f55 Mon Sep 17 00:00:00 2001 From: hadleyking Date: Tue, 12 Sep 2023 14:22:53 -0400 Subject: [PATCH 2/2] Update documentation and tests fix #168 Changes to be committed: modified: api/scripts/method_specific/POST_api_objects_drafts_modify.py modified: api/views.py modified: tests/test_views/test_api_objects_drafts_modify.py --- .../POST_api_objects_drafts_modify.py | 165 +++++++++------- api/views.py | 31 +-- .../test_api_objects_drafts_modify.py | 184 +++++++++++++++--- 3 files changed, 262 insertions(+), 118 deletions(-) diff --git a/api/scripts/method_specific/POST_api_objects_drafts_modify.py b/api/scripts/method_specific/POST_api_objects_drafts_modify.py index e135e36d..73c55241 100755 --- a/api/scripts/method_specific/POST_api_objects_drafts_modify.py +++ b/api/scripts/method_specific/POST_api_objects_drafts_modify.py @@ -41,7 +41,12 @@ def post_api_objects_drafts_modify(request): db_utils = DbUtils.DbUtils() user = UserUtils.UserUtils().user_from_request(request=request) - bulk_request = request.data["POST_api_objects_drafts_modify"] + try: + bulk_request = request.data["POST_api_objects_drafts_modify"] + except KeyError as error: + return Response(status=status.HTTP_400_BAD_REQUEST, data={ + 'KeyError': f'{str(error)}' + }) px_perms = UserUtils.UserUtils().prefix_perms_for_user( flatten=True, user_object=user, specific_permission=["add"] ) @@ -50,101 +55,111 @@ def post_api_objects_drafts_modify(request): returning = [] any_failed = False for draft_object in bulk_request: - # Get the prefix for this draft. - prefix = draft_object["object_id"].split("/")[-2].split("_")[0].upper() + try: + # Get the prefix for this draft. + prefix = draft_object["object_id"].split("/")[-2].split("_")[0].upper() - # Does the requestor have change permissions for - # the *prefix*? + # Does the requestor have change permissions for + # the *prefix*? - # TODO: add permission setting view... - # if 'change_' + prefix in px_perms: - if "add_" + prefix in px_perms: + # TODO: add permission setting view... + # if 'change_' + prefix in px_perms: - # The requestor has change permissions for - # the prefix, but do they have object-level - # change permissions? + if "add_" + prefix in px_perms: - # This can be checked by seeing if the requestor - # is the object owner OR they are a user with - # object-level change permissions OR if they are in a - # group that has object-level change permissions. - # To check these options, we need the actual object. + # The requestor has change permissions for + # the prefix, but do they have object-level + # change permissions? - if draft_object["object_id"] not in draft_object["contents"]["object_id"]: - returning.append( - db_utils.messages( - parameters={ - "object_id": draft_object["contents"]["object_id"], - "draft_object_id": draft_object["object_id"], - } - )["409_draft_object_id_conflict"] - ) - any_failed = True - continue + # This can be checked by seeing if the requestor + # is the object owner OR they are a user with + # object-level change permissions OR if they are in a + # group that has object-level change permissions. + # To check these options, we need the actual object. + if draft_object["object_id"] not in draft_object["contents"]["object_id"]: + returning.append( + db_utils.messages( + parameters={ + "object_id": draft_object["contents"]["object_id"], + "draft_object_id": draft_object["object_id"], + } + )["409_draft_object_id_conflict"] + ) + any_failed = True + continue - if BCO.objects.filter( - object_id=draft_object["contents"]["object_id"] - ).exists(): - objected = BCO.objects.get( + if BCO.objects.filter( object_id=draft_object["contents"]["object_id"] - ) + ).exists(): + objected = BCO.objects.get( + object_id=draft_object["contents"]["object_id"] + ) - # We don't care where the view permission comes from, - # be it a User permission or a Group permission. - all_permissions = get_perms(user, objected) - # TODO: add permission setting view... - if ( - user.username == objected.owner_user.username - or "add_" + prefix in px_perms - ): - - # # User does *NOT* have to be in the owner group! - # # to assign the object's group owner. - # if Group.objects.filter( - # name = draft_object['owner_group'].lower() - # ).exists(): - # - # Update the object. - # *** COMPLETELY OVERWRITES CONTENTS!!! *** - objected.contents = draft_object["contents"] - - if "state" in draft_object: - if draft_object["state"] == "DELETE": - objected.state = "DELETE" - - # Set the update time. - objected.last_update = timezone.now() - - # Save it. - objected.save() - - # Update the request status. + # We don't care where the view permission comes from, + # be it a User permission or a Group permission. + all_permissions = get_perms(user, objected) + # TODO: add permission setting view... + if ( + user.username == objected.owner_user.username + or "add_" + prefix in px_perms + ): + + # # User does *NOT* have to be in the owner group! + # # to assign the object's group owner. + # if Group.objects.filter( + # name = draft_object['owner_group'].lower() + # ).exists(): + # + # Update the object. + # *** COMPLETELY OVERWRITES CONTENTS!!! *** + objected.contents = draft_object["contents"] + + if "state" in draft_object: + if draft_object["state"] == "DELETE": + objected.state = "DELETE" + + # Set the update time. + objected.last_update = timezone.now() + + # Save it. + objected.save() + + # Update the request status. + returning.append( + db_utils.messages( + parameters={"object_id": draft_object["object_id"]} + )["200_update"] + ) + else: + # Insufficient permissions. + returning.append( + db_utils.messages(parameters={ + })["403_insufficient_permissions"] + ) + any_failed = True + + else: returning.append( db_utils.messages( parameters={"object_id": draft_object["object_id"]} - )["200_update"] - ) - else: - # Insufficient permissions. - returning.append( - db_utils.messages(parameters={})["403_insufficient_permissions"] + )["404_object_id"] ) any_failed = True - else: returning.append( - db_utils.messages( - parameters={"object_id": draft_object["object_id"]} - )["404_object_id"] + db_utils.messages(parameters={"prefix": prefix})[ + "401_prefix_unauthorized" + ] ) any_failed = True - else: + except: returning.append( - db_utils.messages(parameters={"prefix": prefix})[ - "401_prefix_unauthorized" + db_utils.messages(parameters={})[ + "400_bad_request" ] ) any_failed = True + if any_failed and len(returning) == 1: if returning[0]["status_code"] == "403": return Response(status=status.HTTP_403_FORBIDDEN, data=returning) diff --git a/api/views.py b/api/views.py index 6831d187..02d80582 100755 --- a/api/views.py +++ b/api/views.py @@ -627,13 +627,13 @@ def post(self, request) -> Response: class ApiObjectsDraftsModify(APIView): """ - Modify a BCO Object + Bulk Modify BCO Objects -------------------- - Modifies a BCO object. The BCO object must be a draft in order to be - modifiable. WARNING: The contents of the BCO will be replaced with the new - contents provided in the request body. + Modifies one or more BCO objects. The BCO objects must be a draft in order + to be modifiable. WARNING: The contents of the BCO will be replaced with + the new contents provided in the request body. """ POST_api_objects_drafts_modify_schema = openapi.Schema( @@ -668,19 +668,24 @@ class ApiObjectsDraftsModify(APIView): @swagger_auto_schema( request_body=request_body, responses={ - 200: "Modification of BCO draft is successful.", + 200: "All modifications of BCO drafts are successful.", 207: "Some or all BCO modifications failed. Each object submitted" " will have it's own response object with it's own status" " code and message:\n" - "201: The prefix * was successfully created.\n" - "400: Bad Request. The expiration date * is not valid.\n" - "400: Bad Request. The prefix * does not follow the naming rules for a prefix.\n" - "403: Forbidden. User does not have permission to perform this action.\n" - "404: Not Found. The user * was not found on the server.\n" - "409: Conflict. The prefix the requestor is attempting to create already exists.\n", - 401: "Unauthorized. Authentication credentials were not provided.", + "200: Success. The object with ID <'object_id'> was" + "updated.\n" + "400: Bad request. The request could not be processed with" + "the parameters provided.\n " + "401: Prefix unauthorized. The token provided does not " + "have draft permissions for this prefix <'prefix'>.\n" + "404: Not Found. The object ID <'object_id'> was not found " + "on the server.\n" + "409: Conflict. The provided object_id <'object_id'> does " + "not match the saved draft object_id <'object_id'>. " + "Once a draft is created you can not change the " + "object_id.\n", 400: "Bad request.", - 403: "Invalid token.", + 403: "Forbidden. Authentication credentials were not provided, or the token is invalid." }, tags=["BCO Management"], ) diff --git a/tests/test_views/test_api_objects_drafts_modify.py b/tests/test_views/test_api_objects_drafts_modify.py index 02ff16e8..1e1aa8d2 100644 --- a/tests/test_views/test_api_objects_drafts_modify.py +++ b/tests/test_views/test_api_objects_drafts_modify.py @@ -1,10 +1,26 @@ #!/usr/bin/env python3 -"""Modify BCO Draft -Tests for 200 and 403. -Gives error for 400. requires debugging +"""Bulk Modify BCO Draft +Tests for 200: 'All modifications of BCO drafts are successful.', +401: 'Unauthorized. Authentication credentials were not provided.', +400: 'Bad request.', 403: 'Invalid token.' and 207: 'Some or all BCO +modifications failed. Each object submitted will have it's own response object +with it's own status code and message: + "200: Success. The object with ID <'object_id'> was" + "updated.\n" + "400: Bad request. The request could not be processed with" + "the parameters provided." + "401: Prefix unauthorized. The token provided does not" + "have draft permissions for this prefix .\n" + "404: Not Found. The object ID was not found" + "on the server.\n" + "409: Conflict. The provided object_id does" + "not match the saved draft object_id ." + "Once a draft is created you can not change the object" + "id.\n", """ +import json from django.test import TestCase from rest_framework.test import APIClient from rest_framework.authtoken.models import Token @@ -19,49 +35,157 @@ def setUp(self): self.client = APIClient() def test_modify_bco_draft_success(self): - "Valid request to modify a BCO draft" + """Tests for 200: 'All modifications of BCO drafts are successful.' + """ token = Token.objects.get(user=User.objects.get(username='test50')).key + bco_0 = BCO.objects.get(object_id='http://127.0.0.1:8000/BCO_000000/DRAFT').contents + bco_1 = BCO.objects.get(object_id='http://127.0.0.1:8000/BCO_000001/DRAFT').contents - import pdb; pdb.set_trace() - self.client.credentials(HTTP_AUTHORIZATION='Token ' + self.token.key) - response = self.client.post('/api/objects/drafts/modify/', data={"data"}, format='json') + bco_0['provenance_domain']['version'] = '99.9' + bco_1['provenance_domain']['version'] = '88.8' + + submission = { + "POST_api_objects_drafts_modify": [ + { + "object_id": bco_0['object_id'], + "contents": bco_0 + }, + { + "object_id": bco_1['object_id'], + "contents": bco_1 + } + ] + } + self.client.credentials(HTTP_AUTHORIZATION='Token ' + token) + response = self.client.post('/api/objects/drafts/modify/', data=submission, format='json') + test_case_1 = BCO.objects.get(object_id='http://127.0.0.1:8000/BCO_000001/DRAFT').contents + + self.assertEqual(test_case_1['provenance_domain']['version'], '88.8') self.assertEqual(response.status_code, 200) - def test_modify_bco_draft_bad_request(self): - # Invalid request: Bad request - ##Giving an error I dont understand + def test_bulk_modification_fail(self): + """Test for 207: 'Some or all BCO modifications failed. Each object + submitted will have it's own response object with it's own status + code and message: + "200: Success. The object with ID <'object_id'> was" + "updated.\n" + "400: Bad request. The request could not be processed with" + "the parameters provided." + "401: Prefix unauthorized. The token provided does not" + "have draft permissions for this prefix .\n" + "404: Not Found. The object ID was not found" + "on the server.\n" + "409: Conflict. The provided object_id does" + "not match the saved draft object_id ." + "Once a draft is created you can not change the object" + "id.\n", + """ - data = { - # Provide invalid or missing data + token = Token.objects.get(user=User.objects.get(username='test50')).key + + bco_0 = BCO.objects.get(object_id='http://127.0.0.1:8000/BCO_000000/DRAFT').contents + bco_1 = BCO.objects.get(object_id='http://127.0.0.1:8000/BCO_000001/DRAFT').contents + bco_3 = BCO.objects.get(object_id='http://127.0.0.1:8000/OTHER_000001/DRAFT').contents + + bco_0['provenance_domain']['version'] = '88.8' + bco_1['object_id'] = 'http://127.0.0.1:8000/BCO_100000/DRAFT' + + submission = { "POST_api_objects_drafts_modify": [ { - - "object_id": "http://127.0.0.1:8000/BCO_000001/DRAFT", - "contents": { - "additionalProp1": {} - - } + "object_id": bco_0['object_id'], + "contents": bco_0 + }, + { + "object_id": 'object_id', + "contents": bco_0 + }, + { + "object_id": 'http://127.0.0.1:8000/BCO_100000/DRAFT', + "contents": bco_1 + }, + { + "object_id": 'http://127.0.0.1:8000/BCO_000000/DRAFT', + "contents": bco_1 + }, + { + "object_id": bco_3['object_id'], + "contents": bco_3 } ] } - self.client.credentials(HTTP_AUTHORIZATION='Token ' + self.token.key) - response = self.client.post('/api/objects/drafts/modify/', data=data, format='json') - self.assertEqual(response.status_code, 400) + self.client.credentials(HTTP_AUTHORIZATION='Token ' + token) + response = self.client.post('/api/objects/drafts/modify/', data=submission, format='json') + + self.assertEqual(response.status_code, 207) + self.assertEqual(response.json()[0]['status_code'], '200') + self.assertEqual(response.json()[1]['status_code'], '400') + self.assertEqual(response.json()[2]['status_code'], '404') + self.assertEqual(response.json()[3]['status_code'], '409') + self.assertEqual(response.json()[4]['status_code'], '401') - def test_modify_bco_draft_invalid_token(self): - # Request with invalid token or without authentication credentials + def test_unauthorized(self): + """Test for 401: Unauthorized. Authentication credentials were not + provided. + """ + bco_0 = BCO.objects.get(object_id='http://127.0.0.1:8000/BCO_000000/DRAFT').contents + bco_1 = BCO.objects.get(object_id='http://127.0.0.1:8000/BCO_000001/DRAFT').contents - data = { + bco_0['provenance_domain']['version'] = '99.9' + bco_1['provenance_domain']['version'] = '88.8' + + submission = { "POST_api_objects_drafts_modify": [ { - "object_id": "http://127.0.0.1:8000/OTHER_000001/DRAFT", - "contents": { - "additionalProp1": {} - } + "object_id": bco_0['object_id'], + "contents": bco_0 + }, + { + "object_id": bco_1['object_id'], + "contents": bco_1 } ] } - self.client.credentials(HTTP_AUTHORIZATION='Invalid_token ') - response = self.client.post('/api/objects/drafts/modify/', data=data, format='json') + + response = self.client.post('/api/objects/drafts/modify/', data=submission, format='json') self.assertEqual(response.status_code, 403) + + def test_bad_request(self): + """Test for 400: Bad request. + """ + + token = Token.objects.get(user=User.objects.get(username='test50')).key + + bco_0 = BCO.objects.get(object_id='http://127.0.0.1:8000/BCO_000000/DRAFT').contents + bco_1 = BCO.objects.get(object_id='http://127.0.0.1:8000/BCO_000001/DRAFT').contents + + bco_0['provenance_domain']['version'] = '99.9' + bco_1['provenance_domain']['version'] = '88.8' + + submission = { + "POST": [ + { + "object_id": bco_0['object_id'], + "contents": bco_0 + }, + { + "object_id": bco_1['object_id'], + "contents": bco_1 + } + ] + } + + self.client.credentials(HTTP_AUTHORIZATION='Token ' + token) + response = self.client.post('/api/objects/drafts/modify/', data=submission, format='json') + self.assertEqual(response.status_code, 400) + + def test_invalid_token(self): + """Test for 403: Invalid token. + """ + + submission = {} + + self.client.credentials(HTTP_AUTHORIZATION='Token ' + 'token') + response = self.client.post('/api/objects/drafts/modify/', data=submission, format='json') + self.assertEqual(response.status_code, 403) \ No newline at end of file