From 1b201965cbbd36eec324ef588b2ab65d344b87ef Mon Sep 17 00:00:00 2001 From: hadleyking Date: Wed, 20 Mar 2024 14:21:44 -0400 Subject: [PATCH] Added Prefix management URLs and APIs Changes to be committed: modified: config/fixtures/local_data.json modified: docs/refactor.md modified: prefix/apis.py modified: prefix/services.py modified: prefix/urls.py modified: tests/fixtures/test_data.json deleted: tests/test_views/test_api_prefixes_create.py new file: tests/test_views/test_prefixes_create.py new file: tests/test_views/test_prefixes_modify.py --- config/fixtures/local_data.json | 48 ---- docs/refactor.md | 1 + prefix/apis.py | 241 ++++++++++++++++--- prefix/services.py | 58 ++++- prefix/urls.py | 4 +- tests/fixtures/test_data.json | 36 +++ tests/test_views/test_api_prefixes_create.py | 182 -------------- tests/test_views/test_prefixes_create.py | 156 ++++++++++++ tests/test_views/test_prefixes_modify.py | 151 ++++++++++++ 9 files changed, 607 insertions(+), 270 deletions(-) delete mode 100644 tests/test_views/test_api_prefixes_create.py create mode 100644 tests/test_views/test_prefixes_create.py create mode 100644 tests/test_views/test_prefixes_modify.py diff --git a/config/fixtures/local_data.json b/config/fixtures/local_data.json index bebfe603..b202c17a 100644 --- a/config/fixtures/local_data.json +++ b/config/fixtures/local_data.json @@ -735,54 +735,6 @@ "model": "blacklistedtoken" } }, - { - "model": "contenttypes.contenttype", - "pk": 10, - "fields": { - "app_label": "guardian", - "model": "groupobjectpermission" - } - }, - { - "model": "contenttypes.contenttype", - "pk": 11, - "fields": { - "app_label": "guardian", - "model": "userobjectpermission" - } - }, - { - "model": "contenttypes.contenttype", - "pk": 12, - "fields": { - "app_label": "authentication", - "model": "newuser" - } - }, - { - "model": "contenttypes.contenttype", - "pk": 13, - "fields": { - "app_label": "authentication", - "model": "authentication" - } - }, - { - "model": "contenttypes.contenttype", - "pk": 14, - "fields": { - "app_label": "biocompute", - "model": "bco" - } - }, - { - "model": "contenttypes.contenttype", - "pk": 15, - "fields": { - "app_label": "prefix", - "model": "prefix" - } - }, { "model": "sessions.session", "pk": "mpq9r3ogmf3pel91gaqfvhzaf0pmdl4f", diff --git a/docs/refactor.md b/docs/refactor.md index f3125a40..dc7a21ce 100644 --- a/docs/refactor.md +++ b/docs/refactor.md @@ -39,3 +39,4 @@ - need tests for token - unwanted swagger endpoints - need tests for token +- prefix api documentation and portal docs for prefix diff --git a/prefix/apis.py b/prefix/apis.py index b2e237a4..08783dc8 100644 --- a/prefix/apis.py +++ b/prefix/apis.py @@ -8,7 +8,33 @@ from rest_framework.response import Response from rest_framework.views import APIView from config.services import legacy_api_converter, response_constructor -from prefix.services import PrefixSerializer +from prefix.services import PrefixSerializer, delete_prefix + +PREFIX_SCHEMA = openapi.Schema( + type=openapi.TYPE_ARRAY, + title="Prefix Schema", + items=openapi.Schema( + type=openapi.TYPE_OBJECT, + required=["prefix"], + properties={ + "prefix": openapi.Schema( + type=openapi.TYPE_STRING, + description="Any prefix which satsifies the naming standard.", + example="test" + ), + "description": openapi.Schema( + type=openapi.TYPE_STRING, + description="A description of what this prefix should represent. For example, the prefix 'GLY' would be related to BCOs which were derived from GlyGen workflows.", + example="Test prefix description." + ), + "authorized_groups": openapi.Schema( + type=openapi.TYPE_ARRAY, + description="Groups which can access the BCOs using this prefix. If it is none then anyone can access.", + items=openapi.Schema(type=openapi.TYPE_STRING, example="") + ) + }, + ) +) class PrefixesCreateApi(APIView): """ @@ -20,38 +46,9 @@ class PrefixesCreateApi(APIView): """ - # Permissions - prefix admins only permission_classes = [IsAuthenticated,] - # 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_ARRAY, - title="Prefix Creation Schema", - items=openapi.Schema( - type=openapi.TYPE_OBJECT, - required=["prefix"], - properties={ - "prefix": openapi.Schema( - type=openapi.TYPE_STRING, - description="Any prefix which satsifies the naming standard (see link...)", - example="test" - ), - "description": openapi.Schema( - type=openapi.TYPE_STRING, - description="A description of what this prefix should represent. For example, the prefix 'GLY' would be related to BCOs which were derived from GlyGen workflows.", - example="Test prefix description." - ), - "authorized_groups": openapi.Schema( - type=openapi.TYPE_ARRAY, - description="Groups which can access the BCOs using this prefix. If it is none then anyone can access.", - items=openapi.Schema(type=openapi.TYPE_STRING, example="") - ) - }, - ) - ) + request_body = PREFIX_SCHEMA @swagger_auto_schema( request_body=request_body, @@ -68,7 +65,7 @@ class PrefixesCreateApi(APIView): ) def post(self, request) -> Response: response_data = [] - owner = request.user + requester = request.user data = request.data rejected_requests = False accepted_requests = False @@ -85,7 +82,7 @@ def post(self, request) -> Response: response_data.append(response_constructor( identifier=response_id, status = "SUCCESS", - code= 200, + code= 201, message= f"Prefix {response_id} created", )) accepted_requests = True @@ -118,4 +115,182 @@ def post(self, request) -> Response: data=response_data ) + return Response(status=status.HTTP_201_CREATED, data=response_data) + +class PrefixesDeleteApi(APIView): + """ + Delete a Prefix + + # Deletes a prefix for BCOs. + -------------------- + The requestor *must* be in the group prefix_admins to delete a prefix. + + __Any object created under this prefix will have its permissions "locked out." This means that any other view which relies on object-level permissions, such as /api/objects/drafts/read/, will not allow any requestor access to particular objects.__ + + + """ + + permission_classes = [IsAuthenticated] + + request_body = openapi.Schema( + type=openapi.TYPE_ARRAY, + title="Prefix Deletion Schema", + description="Provide a list of prefixes to delete.", + items=openapi.Schema( + type=openapi.TYPE_STRING, + example="TEST" + ) + ) + + @swagger_auto_schema( + request_body=request_body, + responses={ + 200: "Deleting a prefix was successful.", + 401: "Unauthorized. Authentication credentials were not provided.", + 403: "Forbidden. User doesnot have permission to perform this action", + 404: "The prefix couldn't be found so therefore it could not be deleted.", + }, + tags=["Prefix Management"], + ) + + def post(self, request) -> Response: + response_data = [] + requester = request.user + data = request.data + rejected_requests = False + accepted_requests = False + + if "POST_api_prefixes_delete" in request.data: + data = legacy_api_converter(request.data) + + for index, object in enumerate(data): + response_id = object + response_status = delete_prefix(object, requester) + print("response_status: ", response_status) + if response_status is True: + response_data.append(response_constructor( + identifier=response_id, + status = "SUCCESS", + code= 200, + message= f"Prefix {response_id} deleted", + )) + accepted_requests = True + print(accepted_requests, response_data) + + else: + response_data.append(response_constructor( + identifier=response_id, + status = "REJECTED", + code= 400, + message= f"Prefix {response_id} NOT deleted", + data=response_status + )) + rejected_requests = True + + if accepted_requests is False: + return Response( + status=status.HTTP_400_BAD_REQUEST, + data=response_data + ) + + if accepted_requests is True and rejected_requests is True: + return Response( + status=status.HTTP_207_MULTI_STATUS, + data=response_data + ) + + if accepted_requests is True and rejected_requests is False: + return Response( + status=status.HTTP_200_OK, + data=response_data + ) + + return Response(status=status.HTTP_201_CREATED, data=response_data) + +class PrefixesModifyApi(APIView): + """ + Modify a Prefix + + -------------------- + + Modify a prefix which already exists. + + The requestor *must* be in the owner to modify a prefix. + """ + + permission_classes = [IsAuthenticated] + + request_body = PREFIX_SCHEMA + + @swagger_auto_schema( + request_body=request_body, + responses={ + 200: "The prefix was successfully modified.", + 400: "Bad request because owner_user and/or owner_group do not exist.", + 404: "The prefix provided could not be found.", + }, + tags=["Prefix Management"], + ) + def post(self, request) -> Response: + response_data = [] + requester = request.user + data = request.data + rejected_requests = False + accepted_requests = False + + if "POST_api_prefixes_modify" in request.data: + data = legacy_api_converter(request.data) + for index, object in enumerate(data): + response_id = object.get("prefix", index).upper() + prefix = PrefixSerializer(data=object, context={'request': request}) + + if prefix.is_valid(): + if requester == prefix.validated_data['owner']: + prefix.update(prefix.validated_data) + response_data.append(response_constructor( + identifier=response_id, + status = "SUCCESS", + code= 200, + message= f"Prefix {response_id} updated", + )) + accepted_requests = True + + else: + response_data.append(response_constructor( + identifier=response_id, + status = "REJECTED", + code= 400, + message= f"Requester does not have permissions to modify {response_id}", + data=prefix.errors + )) + rejected_requests = True + + else: + response_data.append(response_constructor( + identifier=response_id, + status = "REJECTED", + code= 400, + message= f"Prefix {response_id} update rejected", + data=prefix.errors + )) + rejected_requests = True + + if accepted_requests is False and rejected_requests == True: + return Response( + status=status.HTTP_400_BAD_REQUEST, + data=response_data + ) + + if accepted_requests is True and rejected_requests is True: + return Response( + status=status.HTTP_207_MULTI_STATUS, + data=response_data + ) + + if accepted_requests is True and rejected_requests is False: + return Response( + status=status.HTTP_200_OK, + data=response_data + ) + return Response(status=status.HTTP_201_CREATED, data=response_data) \ No newline at end of file diff --git a/prefix/services.py b/prefix/services.py index 0252fc0c..2719804b 100644 --- a/prefix/services.py +++ b/prefix/services.py @@ -31,11 +31,20 @@ def validate(self, attrs): attrs['prefix'] = attrs['prefix'].upper() prefix_name = attrs['prefix'] - # Validate Prefix - if not Prefix.objects.filter(prefix=prefix_name).exists(): - pass - else: - errors["prefix_name"] = f"That Prefix, {prefix_name}, already exists." + # Validate Prefix name and owner + try: + attrs["prefix"] = Prefix.objects.get(prefix=prefix_name) + if "create" in request.path_info: + raise serializers.ValidationError({"prefix_name": f"That Prefix, {prefix_name}, already exists."}) + attrs["owner"] = attrs["prefix"].owner + except Prefix.DoesNotExist: + if "create" in request.path_info: + pass + else: + errors["prefix_name"] = f"That Prefix, {prefix_name}, was not found." + + + # remove blank 'authorized_groups' relic from legacy conversion if attrs['authorized_groups'][0] == "": attrs.pop("authorized_groups") @@ -66,7 +75,31 @@ def create(self, validated_data): authorized_groups = Group.objects.filter(name__in=authorized_group_names) prefix_instance.authorized_groups.set(authorized_groups) return prefix_instance - + + @transaction.atomic + def update(self, validated_data): + """Update function for Prefix.""" + prefix_instance = Prefix.objects.get(prefix=validated_data['prefix']) + if prefix_instance.owner != validated_data['owner']: + # import pdb; pdb.set_trace() + return "denied" + prefix_instance.description = validated_data.get('description', prefix_instance.description) + prefix_instance.save() + + if 'authorized_groups' in validated_data: + authorized_group_names = validated_data['authorized_groups'] + # If the list is empty or contains only an empty string, clear the groups + if not authorized_group_names or authorized_group_names == [""]: + prefix_instance.authorized_groups.clear() + + else: + # Filter groups that exist in the database + authorized_groups = Group.objects.filter(name__in=authorized_group_names) + + # Set the new groups, which automatically handles adding, keeping, or removing + prefix_instance.authorized_groups.set(authorized_groups) + + return prefix_instance def prefix_counter_increment(prefix: Prefix) -> int: """Prefix Counter Increment @@ -78,3 +111,16 @@ def prefix_counter_increment(prefix: Prefix) -> int: Prefix.objects.update(counter=F("counter") + 1) count = prefix.counter return count + +def delete_prefix(prefix: str, user: User) -> bool: + """Delete Prefix + """ + try: + prefix_instance = Prefix.objects.get(prefix=prefix) + except Prefix.DoesNotExist: + return f"That prefix, {prefix}, does not exist." + if prefix_instance.owner == user: + prefix_instance.delete() + return True + + return f"You do not have permissions to delete that prefix, {prefix}." diff --git a/prefix/urls.py b/prefix/urls.py index d60b862d..d3ef8ecc 100644 --- a/prefix/urls.py +++ b/prefix/urls.py @@ -5,8 +5,10 @@ """ from django.urls import path -from prefix.apis import PrefixesCreateApi +from prefix.apis import PrefixesCreateApi, PrefixesDeleteApi, PrefixesModifyApi urlpatterns = [ path("prefixes/create/", PrefixesCreateApi.as_view()), + path("prefixes/delete/", PrefixesDeleteApi.as_view()), + path("prefixes/modify/", PrefixesModifyApi.as_view()), ] \ No newline at end of file diff --git a/tests/fixtures/test_data.json b/tests/fixtures/test_data.json index 70594fde..d18930d5 100644 --- a/tests/fixtures/test_data.json +++ b/tests/fixtures/test_data.json @@ -1,4 +1,28 @@ [ + { + "model": "auth.group", + "pk": 1, + "fields": { + "name": "bco_publisher", + "permissions": [] + } + }, + { + "model": "auth.group", + "pk": 2, + "fields": { + "name": "bco_drafter", + "permissions": [] + } + }, + { + "model": "auth.group", + "pk": 3, + "fields": { + "name": "test_drafter", + "permissions": [] + } + }, { "model": "auth.permission", "pk": 1, @@ -858,5 +882,17 @@ "authorized_groups": [], "counter": 0 } + }, + { + "model": "prefix.prefix", + "pk": "TEST", + "fields": { + "certifying_key": "12345", + "created": "2024-03-14T13:53:59Z", + "description": "Test prefix", + "owner": "tester", + "authorized_groups": [], + "counter": 0 + } } ] \ No newline at end of file diff --git a/tests/test_views/test_api_prefixes_create.py b/tests/test_views/test_api_prefixes_create.py deleted file mode 100644 index cb5e17df..00000000 --- a/tests/test_views/test_api_prefixes_create.py +++ /dev/null @@ -1,182 +0,0 @@ -#!/usr/bin/env python3 - -"""Bulk Create Prefixes -Tests for 'All prefixes were successfully created. 200', 'Some or all prefix -creations failed. 207', and 'Unauthorized. Authentication credentials were -not provided. 401' - -For the 207 response Each object submitted will have it's own response object -with it's own status code and message. These are as follows: - 201: The prefix * was successfully created. - 400: Bad Request. The expiration date * is not valid. - 400: Bad Request. The prefix * does not follow the naming rules for a prefix. - 403: Forbidden. User does not have permission to perform this action. - 404: Not Found. The user * was not found on the server. - 409: Conflict. The prefix the requestor is attempting to create already exists. - """ - -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 django.contrib.auth.models import Group - -class CreatePrefixeTestCase(APITestCase): - fixtures=['tests/fixtures/test_data'] - - def setUp(self): - - self.client= APIClient() - self.data = [{ - "prefix": "test1", - "description": "Test prefix description.", - "authorized_groups": ["bco_publisher", "bco_drafter"] - }, - { - "prefix": "test2", - "description": "Test prefix description.", - "authorized_groups": [""] - }] - - self.legacy_data = { - "POST_api_prefixes_create": [ - { - "owner_group": "bco_publisher", - "owner_user": "bco_api_user", - "prefixes": [ - { - "description": "Just a test prefix.", - "prefix": "testR" - } - ] - } - ] - } - - def test_create_prefix_success(self): - """The prefix was successfully created. 200 - """ - - token = Token.objects.get(user=User.objects.get(username='bco_api_user')).key - - self.client.credentials(HTTP_AUTHORIZATION='Token ' + token) - legacy_response = self.client.post('/api/prefixes/create/', data=self.legacy_data, format='json') - response = self.client.post('/api/prefixes/create/', data=self.data, format='json') - self.assertEqual(legacy_response.status_code, 200) - self.assertEqual(response.status_code, 200) - - # def test_create_prefix_bad_request(self): - # """Tests for 'Some or all prefix creations failed. 207.' - # 201: The prefix * was successfully created. - # 400: Bad Request. The expiration date * is not valid - # 400: Bad Request. The prefix * does not follow the naming rules for a prefix. - # 403: Forbidden. User does not have permission to perform this action. - # 404: Not Found. The user * was not found on the server. - # 409: Conflict. The prefix the requestor is attempting to create already exists. - # """ - - # token = Token.objects.get(user=User.objects.get(username='bco_api_user')).key - # data = { - # "POST_api_prefixes_create": [ - # { - # "owner_group": "test_drafter", - # "owner_user": "bco_api_user", - # "prefixes": [ - # { - # "description": "Invalid expiration date.", - # "expiration_date": "2023-08-22T09:27:49-0400", - # "prefix": "testR" - # } - # ] - # }, - # { - # "owner_group": "test_drafter", - # "owner_user": "bco_api_user", - # "prefixes": [ - # { - # "description": "Invalid prefix naming.", - # "expiration_date": "null", - # "prefix": "invalid-prefix" - # } - # ] - # }, - # { - # "owner_group": "does_not_exist", - # "owner_user": "does_not_exist", - # "prefixes": [ - # { - # "description": "Invalid owner.", - # "prefix": "testR" - # } - # ] - # }, - # { - # "owner_group": "test_drafter", - # "owner_user": "bco_api_user", - # "prefixes": [ - # { - # "description": "Just a test prefix.", - # "prefix": "testR" - # }, - - # ] - # }, - # { - # "owner_group": "test_drafter", - # "owner_user": "bco_api_user", - # "prefixes": [ - # { - # "description": "Just a test prefix.", - # "prefix": "other" - # } - # ] - # } - # ] - # } - - # self.client.credentials(HTTP_AUTHORIZATION='Token ' + token) - # response = self.client.post('/api/prefixes/create/', data=data, format='json') - # # 201: The prefix * was successfully created. - # self.assertEqual(response.data[3]['status_code'], "201") - - # # 400: Bad Request. The expiration date * is not valid - # self.assertIn("not valid either because it does not match the required format 'YYYY-MM-DD-HH-MM-SS'", response.data[0]['message']) - - # # 400: Bad Request. The prefix * does not follow the naming rules for a prefix. - # self.assertIn('does not follow the naming rules for a prefix.', response.data[1]['message']) - - # # TODO => 403: Forbidden. User does not have permission to perform this action. - # # This would require testing an instance where the prefix admins was enforced... - - # # 404: Not Found. The user * was not found on the server. - # self.assertIn('was not found on the server.', response.data[2]['message']) - - # # 409: Conflict. The prefix the requestor is attempting to create already exists. - # self.assertIn('has already been created on this server.', response.data[4]['message']) - - # self.assertEqual(response.status_code, 207) - - # def test_create_prefix_unauthorized(self): - # """Unauthorized. Authentication credentials were not provided. 401 - # """ - - # data = { - # "POST_api_prefixes_create": [ - # { - - - # "owner_group": "test_drafter", - # "owner_user": "bco_api_user", - # "prefixes": [ - # { - # "description": "Just a test prefix.", - # "prefix": "testR" - # } - # ] - # } - # ] - # } - - # response = self.client.post('/api/prefixes/create/', data=data, format='json') - # self.assertEqual(response.status_code, 403) diff --git a/tests/test_views/test_prefixes_create.py b/tests/test_views/test_prefixes_create.py new file mode 100644 index 00000000..91a70a34 --- /dev/null +++ b/tests/test_views/test_prefixes_create.py @@ -0,0 +1,156 @@ +#!/usr/bin/env python3 + +"""Bulk Create Prefixes +Tests for 'All prefixes were successfully created. 200', 'Some or all prefix +creations failed. 207', and 'Unauthorized. Authentication credentials were +not provided. 401' + +For the 207 response Each object submitted will have it's own response object +with it's own status code and message. These are as follows: + 201: The prefix * was successfully created. + 400: Bad Request. The expiration date * is not valid. + 400: Bad Request. The prefix * does not follow the naming rules for a prefix. + 403: Forbidden. User does not have permission to perform this action. + 404: Not Found. The user * was not found on the server. + 409: Conflict. The prefix the requestor is attempting to create already exists. + """ + +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 django.contrib.auth.models import Group + +class CreatePrefixeTestCase(APITestCase): + fixtures=['tests/fixtures/test_data'] + + def setUp(self): + + self.client= APIClient() + self.data = [{ + "prefix": "test1", + "description": "Test prefix description.", + "authorized_groups": ["bco_publisher", "bco_drafter"] + }, + { + "prefix": "test2", + "description": "Test prefix description.", + "authorized_groups": [""] + }] + + self.legacy_data = { + "POST_api_prefixes_create": [ + { + "owner_group": "bco_publisher", + "owner_user": "bco_api_user", + "prefixes": [ + { + "description": "Just a test prefix.", + "prefix": "testR" + } + ] + } + ] + } + + def test_create_prefix_success(self): + """The prefix was successfully created. 200 + """ + + token = Token.objects.get(user=User.objects.get(username='bco_api_user')).key + + self.client.credentials(HTTP_AUTHORIZATION='Token ' + token) + legacy_response = self.client.post('/api/prefixes/create/', data=self.legacy_data, format='json') + response = self.client.post('/api/prefixes/create/', data=self.data, format='json') + self.assertEqual(legacy_response.status_code, 200) + self.assertEqual(response.status_code, 200) + + def test_create_multi_status(self): + """Tests for 'Some prefix creations failed. 207.' + """ + + token = Token.objects.get(user=User.objects.get(username='bco_api_user')).key + data = { + "POST_api_prefixes_create": [ + { + "owner_group": "test_drafter", + "owner_user": "bco_api_user", + "prefixes": [ + { + "description": "Invalid prefix naming.", + "expiration_date": "null", + "prefix": "invalid-prefix" + } + ] + }, + { + "owner_group": "does_not_exist", + "owner_user": "does_not_exist", + "prefixes": [ + { + "description": "Invalid owner.", + "prefix": "testR" + } + ] + }, + { + "owner_group": "test_drafter", + "owner_user": "bco_api_user", + "prefixes": [ + { + "description": "Just a test prefix.", + "prefix": "testR" + }, + + ] + }, + { + "owner_group": "test_drafter", + "owner_user": "bco_api_user", + "prefixes": [ + { + "description": "Just a test prefix.", + "prefix": "test" + } + ] + } + ] + } + + self.client.credentials(HTTP_AUTHORIZATION='Token ' + token) + response = self.client.post('/api/prefixes/create/', data=data, format='json') + # 201: The prefix * was successfully created. + self.assertEqual(response.data[2]['TESTR']['status_code'], 201) + + # 400: Bad Request. The prefix * does not follow the naming rules for a prefix. + self.assertIn('prefix', response.data[0]['INVALID-PREFIX']['data']) + # 404: Not Found. The user * was not found on the server. + self.assertIn('authorized_groups', response.data[1]['TESTR']['data']) + + # 409: Conflict. The prefix the requestor is attempting to create already exists. + self.assertIn('prefix_name', response.data[3]['TEST']['data']) + + self.assertEqual(response.status_code, 207) + + def test_create_prefix_unauthorized(self): + """Unauthorized. Authentication credentials were not provided. 401 + """ + + data = { + "POST_api_prefixes_create": [ + { + "owner_group": "test_drafter", + "owner_user": "bco_api_user", + "prefixes": [ + { + "description": "Just a test prefix.", + "prefix": "testR" + } + ] + } + ] + } + + response = self.client.post('/api/prefixes/create/', data=data, format='json') + self.assertEqual(response.status_code, 403) diff --git a/tests/test_views/test_prefixes_modify.py b/tests/test_views/test_prefixes_modify.py new file mode 100644 index 00000000..1dabbcb5 --- /dev/null +++ b/tests/test_views/test_prefixes_modify.py @@ -0,0 +1,151 @@ +#!/usr/bin/env python3 + +"""Bulk Create Prefixes +Tests for 'All prefixes were successfully created. 200', 'Some prefix +modifications failed. 207', '400: All modifications failed', and 'Unauthorized. Authentication credentials were +not provided. 401' + +For the 207 response Each object submitted will have it's own response object +with it's own status code and message. These are as follows: + 201: The prefix * was successfully created. + 400: Bad Request. The expiration date * is not valid. + 400: Bad Request. The prefix * does not follow the naming rules for a prefix. + 403: Forbidden. User does not have permission to perform this action. + 404: Not Found. The user * was not found on the server. + 409: Conflict. The prefix the requestor is attempting to create already exists. + """ + +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 django.contrib.auth.models import Group + +class CreatePrefixeTestCase(APITestCase): + fixtures=['tests/fixtures/test_data'] + + def setUp(self): + + self.client= APIClient() + self.data = [{ + "prefix": "test", + "description": "Test prefix description.", + "authorized_groups": ["bco_publisher", "bco_drafter"] + }] + + self.legacy_data = { + "POST_api_prefixes_modify": [ + { + "owner_group": "bco_publisher", + "owner_user": "bco_api_user", + "prefixes": [ + { + "description": "Just a test modification for prefix.", + "prefix": "Test" + } + ] + } + ] + } + + def test_modify_prefix_success(self): + """The prefix was successfully modified. 200 + """ + + token = Token.objects.get(user=User.objects.get(username='tester')).key + + self.client.credentials(HTTP_AUTHORIZATION='Token ' + token) + legacy_response = self.client.post('/api/prefixes/modify/', data=self.legacy_data, format='json') + response = self.client.post('/api/prefixes/modify/', data=self.data, format='json') + self.assertEqual(legacy_response.status_code, 200) + self.assertEqual(response.status_code, 200) + + def test_modify_multi_status(self): + """Tests for 'Some prefix modifications failed. 207.' + """ + + token = Token.objects.get(user=User.objects.get(username='tester')).key + data = { + "POST_api_prefixes_modify": [ + { + "owner_group": "test_drafter", + "owner_user": "bco_api_user", + "prefixes": [ + { + "description": "Invalid prefix naming.", + "expiration_date": "null", + "prefix": "invalid-prefix" + } + ] + }, + { + "owner_group": "does_not_exist", + "owner_user": "does_not_exist", + "prefixes": [ + { + "description": "Invalid owner.", + "prefix": "testR" + } + ] + }, + { + "owner_group": "test_drafter", + "owner_user": "bco_api_user", + "prefixes": [ + { + "description": "Just a test prefix update.", + "prefix": "test" + }, + + ] + }, + { + "owner_group": "test_drafter", + "owner_user": "bco_api_user", + "prefixes": [ + { + "description": "Just a test prefix.", + "prefix": "BCO" + } + ] + } + ] + } + + self.client.credentials(HTTP_AUTHORIZATION='Token ' + token) + response = self.client.post('/api/prefixes/modify/', data=data, format='json') + # 201: The prefix * was successfully created. + self.assertEqual(response.data[2]['TEST']['status_code'], 200) + + # 400: Bad Request. The prefix * does not exist. + self.assertIn('prefix', response.data[0]['INVALID-PREFIX']['data']) + # 404: Not Found. The user * was not found on the server. + self.assertIn('authorized_groups', response.data[1]['TESTR']['data']) + + # 409: Conflict. The prefix the requestor is attempting to create already exists. + self.assertIn('permissions', response.data[3]['BCO']['message']) + + self.assertEqual(response.status_code, 207) + + def test_create_prefix_unauthorized(self): + """Unauthorized. Authentication credentials were not provided. 401 + """ + + data = { + "POST_api_prefixes_create": [ + { + "owner_group": "test_drafter", + "owner_user": "bco_api_user", + "prefixes": [ + { + "description": "Just a test prefix.", + "prefix": "testR" + } + ] + } + ] + } + + response = self.client.post('/api/prefixes/create/', data=data, format='json') + self.assertEqual(response.status_code, 403)