From ee0962fdf825ef4cd19f1c87cae2df933428eed2 Mon Sep 17 00:00:00 2001 From: Chris Armstrong Date: Mon, 24 Jan 2022 22:23:18 -0500 Subject: [PATCH 1/5] Transfer commit. --- bco_api/api/migrations/0001_initial.py | 2 +- .../POST_api_prefixes_create.py | 190 +++++++++--------- .../POST_api_prefixes_delete.py | 2 +- .../POST_api_prefixes_modify.py | 171 ++++++++-------- .../POST_api_prefixes_permissions_set.py | 5 +- bco_api/api/views.py | 81 +++++--- 6 files changed, 240 insertions(+), 211 deletions(-) diff --git a/bco_api/api/migrations/0001_initial.py b/bco_api/api/migrations/0001_initial.py index ee7fa4f5..d94b1bf6 100644 --- a/bco_api/api/migrations/0001_initial.py +++ b/bco_api/api/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 3.2.10 on 2022-01-23 18:21 +# Generated by Django 3.2.10 on 2022-01-24 23:26 from django.conf import settings from django.db import migrations, models diff --git a/bco_api/api/scripts/method_specific/POST_api_prefixes_create.py b/bco_api/api/scripts/method_specific/POST_api_prefixes_create.py index de95284f..cecd1eef 100755 --- a/bco_api/api/scripts/method_specific/POST_api_prefixes_create.py +++ b/bco_api/api/scripts/method_specific/POST_api_prefixes_create.py @@ -26,7 +26,7 @@ def POST_api_prefixes_create( uu = UserUtils.UserUtils() # Define the bulk request. - bulk_request = incoming.data['POST_api_prefixes_create']['prefixes'] + bulk_request = incoming.data['POST_api_prefixes_create'] # Get all existing prefixes. available_prefixes = list( @@ -43,115 +43,117 @@ def POST_api_prefixes_create( # Since bulk_request is an array, go over each # item in the array. for creation_object in bulk_request: - - # Create a list to hold information about errors. - errors = {} - - # Standardize the prefix name. - standardized = creation_object['prefix'].upper() - # TODO: abstract this error check to schema checker? + # Go over each prefix proposed. + for prfx in creation_object['prefixes']: + + # Create a list to hold information about errors. + errors = {} + + # Standardize the prefix name. + standardized = prfx['prefix'].upper() - # Check for each error. + # TODO: abstract this error check to schema checker? - # Create a flag for if one of these checks fails. - error_check = False + # Check for each error. - # Does the prefix follow the regex for prefixes? - if not re.match( - r"^[A-Z]{3,5}$", - standardized - ): + # Create a flag for if one of these checks fails. + error_check = False - error_check = True - - # Bad request because the prefix doesn't follow - # the naming rules. - errors['400_bad_request_malformed_prefix'] = db.messages( - parameters = { - 'prefix': standardized.upper() - } - )['400_bad_request_malformed_prefix'] - - # Has the prefix already been created? - if standardized in available_prefixes: + # Does the prefix follow the regex for prefixes? + if not re.match( + r"^[A-Z]{3,5}$", + standardized + ): - error_check = True - - # Update the request status. - errors['409_prefix_conflict'] = db.messages( - parameters = { - 'prefix': standardized.upper() - } - )['409_prefix_conflict'] - - # Does the user exist? - if uu.check_user_exists(un = creation_object['owner_user']) is False: - - error_check = True + error_check = True + + # Bad request because the prefix doesn't follow + # the naming rules. + errors['400_bad_request_malformed_prefix'] = db.messages( + parameters = { + 'prefix': standardized.upper() + } + )['400_bad_request_malformed_prefix'] - # Bad request. - errors['404_user_not_found'] = db.messages( - parameters = { - 'username': creation_object['owner_user'] - } - )['404_user_not_found'] - - # Does the group exist? - if uu.check_group_exists(n = creation_object['owner_group']) is False: + # Has the prefix already been created? + if standardized in available_prefixes: + + error_check = True + + # Update the request status. + errors['409_prefix_conflict'] = db.messages( + parameters = { + 'prefix': standardized.upper() + } + )['409_prefix_conflict'] - error_check = True + # Does the user exist? + if uu.check_user_exists(un = creation_object['owner_user']) is False: + + error_check = True + + # Bad request. + errors['404_user_not_found'] = db.messages( + parameters = { + 'username': creation_object['owner_user'] + } + )['404_user_not_found'] - # Bad request. - errors['404_group_not_found'] = db.messages( - parameters = { - 'group': creation_object['owner_group'] - } - )['404_group_not_found'] - - # Was the expiration date validly formatted and, if so, - # is it after right now? - if 'expiration_date' in creation_object: - if db.check_expiration(dt_string = creation_object['expiration_date']) is not None: + # Does the group exist? + if uu.check_group_exists(n = creation_object['owner_group']) is False: error_check = True - + # Bad request. - errors['400_invalid_expiration_date'] = db.messages( - parameters = { - 'expiration_date': creation_object['expiration_date'] - } - )['400_invalid_expiration_date'] - - # Did any check fail? - if error_check is False: + errors['404_group_not_found'] = db.messages( + parameters = { + 'group': creation_object['owner_group'] + } + )['404_group_not_found'] - # The prefix has not been created, so create it. + # Was the expiration date validly formatted and, if so, + # is it after right now? + if 'expiration_date' in prfx: + if db.check_expiration(dt_string = prfx['expiration_date']) is not None: + + error_check = True + + # Bad request. + errors['400_invalid_expiration_date'] = db.messages( + parameters = { + 'expiration_date': prfx['expiration_date'] + } + )['400_invalid_expiration_date'] - DbUtils.DbUtils().write_object( - p_app_label = 'api', - p_model_name = 'prefixes', - p_fields = ['created_by', 'description', 'owner_group', 'owner_user', 'prefix'], - p_data = { - 'created_by': uu.user_from_request( - rq = incoming - ).username, - 'description': creation_object['description'], - 'owner_group': creation_object['owner_group'], - 'owner_user': creation_object['owner_user'], - 'prefix': standardized - } - ) - - # Created the prefix. - errors['201_prefix_create'] = db.messages( - parameters = { + # Did any check fail? + if error_check is False: + + # The prefix has not been created, so create it. + DbUtils.DbUtils().write_object( + p_app_label = 'api', + p_model_name = 'prefixes', + p_fields = ['created_by', 'description', 'owner_group', 'owner_user', 'prefix'], + p_data = { + 'created_by': uu.user_from_request( + request = incoming + ).username, + 'description': prfx['description'], + 'owner_group': creation_object['owner_group'], + 'owner_user': creation_object['owner_user'], 'prefix': standardized } - )['201_prefix_create'] - - # Append the possible "errors". - returning.append(errors) + ) + + # Created the prefix. + errors['201_prefix_create'] = db.messages( + parameters = { + 'prefix': standardized + } + )['201_prefix_create'] + + # Append the possible "errors". + returning.append(errors) # As this view is for a bulk operation, status 200 # means that the request was successfully processed, diff --git a/bco_api/api/scripts/method_specific/POST_api_prefixes_delete.py b/bco_api/api/scripts/method_specific/POST_api_prefixes_delete.py index 8c7ba960..ea8383ee 100755 --- a/bco_api/api/scripts/method_specific/POST_api_prefixes_delete.py +++ b/bco_api/api/scripts/method_specific/POST_api_prefixes_delete.py @@ -23,7 +23,7 @@ def POST_api_prefixes_delete( uu = UserUtils.UserUtils() # Define the bulk request. - bulk_request = incoming.data['POST_api_prefixes_delete']['prefixes'] + bulk_request = incoming.data['POST_api_prefixes_delete'] # Get all existing prefixes. available_prefixes = list( diff --git a/bco_api/api/scripts/method_specific/POST_api_prefixes_modify.py b/bco_api/api/scripts/method_specific/POST_api_prefixes_modify.py index fad25832..d1bbfec2 100755 --- a/bco_api/api/scripts/method_specific/POST_api_prefixes_modify.py +++ b/bco_api/api/scripts/method_specific/POST_api_prefixes_modify.py @@ -14,14 +14,16 @@ -def POST_api_prefixes_modify(incoming): +def POST_api_prefixes_modify( + incoming +): # Instantiate any necessary imports. db = DbUtils.DbUtils() uu = UserUtils.UserUtils() # Define the bulk request. - bulk_request = incoming.data['POST_api_prefixes_modify']['prefixes'] + bulk_request = incoming.data['POST_api_prefixes_modify'] # Get all existing prefixes. available_prefixes = list( @@ -39,93 +41,96 @@ def POST_api_prefixes_modify(incoming): # item in the array. for creation_object in bulk_request: - # Create a list to hold information about errors. - errors = {} + # Go over each prefix proposed. + for prfx in creation_object['prefixes']: - # Standardize the prefix name. - standardized = creation_object['prefix'].upper() + # Create a list to hold information about errors. + errors = {} + + # Standardize the prefix name. + standardized = prfx['prefix'].upper() - # Create a flag for if one of these checks fails. - error_check = False + # Create a flag for if one of these checks fails. + error_check = False - if standardized not in available_prefixes: + if standardized not in available_prefixes: - error_check = True + error_check = True + + # Update the request status. + # Bad request. + errors['404_missing_prefix'] = db.messages( + parameters = { + 'prefix': standardized + } + )['404_missing_prefix'] - # Update the request status. - # Bad request. - errors['404_missing_prefix'] = db.messages( - parameters = { - 'prefix': standardized - } - )['404_missing_prefix'] - - # Does the user exist? - if uu.check_user_exists(un = creation_object['owner_user']) is False: - - error_check = True - - # Bad request. - errors['404_user_not_found'] = db.messages( - parameters = { - 'username': creation_object['owner_user'] - } - )['404_user_not_found'] - - # Does the group exist? - if uu.check_group_exists(n = creation_object['owner_group']) is False: - - error_check = True - - # Bad request. - errors['404_group_not_found'] = db.messages( - parameters = { - 'group': creation_object['owner_group'] - } - )['404_group_not_found'] - - # Was the expiration date validly formatted and, if so, - # is it after right now? - if 'expiration_date' in creation_object: - if db.check_expiration(dt_string = creation_object['expiration_date']) is not None: - + # Does the user exist? + if uu.check_user_exists(un = creation_object['owner_user']) is False: + error_check = True - - # Bad request. - errors['400_invalid_expiration_date'] = db.messages( - parameters = { - 'expiration_date': creation_object['expiration_date'] - } - )['400_invalid_expiration_date'] - - # Did any check fail? - if error_check is False: - - # The prefix has not been created, so create it. - DbUtils.DbUtils().write_object( - p_app_label = 'api', - p_model_name = 'prefixes', - p_fields = ['created_by', 'description', 'owner_group', 'owner_user', 'prefix'], - p_data = { - 'created_by': uu.user_from_request( - rq = incoming - ).username, - 'description': creation_object['description'], - 'owner_group': creation_object['owner_group'], - 'owner_user': creation_object['owner_user'], - 'prefix': standardized - } - ) - - # Created the prefix. - errors['201_prefix_modify'] = db.messages( - parameters = { - 'prefix': standardized - } - )['201_prefix_modify'] - - # Append the possible "errors". - returning.append(errors) + + # Bad request. + errors['404_user_not_found'] = db.messages( + parameters = { + 'username': creation_object['owner_user'] + } + )['404_user_not_found'] + + # Does the group exist? + if uu.check_group_exists(n = creation_object['owner_group']) is False: + + error_check = True + + # Bad request. + errors['404_group_not_found'] = db.messages( + parameters = { + 'group': creation_object['owner_group'] + } + )['404_group_not_found'] + + # Was the expiration date validly formatted and, if so, + # is it after right now? + if 'expiration_date' in prfx: + if db.check_expiration(dt_string = prfx['expiration_date']) is not None: + + error_check = True + + # Bad request. + errors['400_invalid_expiration_date'] = db.messages( + parameters = { + 'expiration_date': prfx['expiration_date'] + } + )['400_invalid_expiration_date'] + + # Did any check fail? + if error_check is False: + + # The prefix has not been created, so create it. + DbUtils.DbUtils().write_object( + p_app_label = 'api', + p_model_name = 'prefixes', + p_fields = ['created_by', 'description', 'owner_group', 'owner_user', 'prefix'], + p_data = { + 'created_by': uu.user_from_request( + request = incoming + ).username, + 'description': prfx['description'], + 'owner_group': creation_object['owner_group'], + 'owner_user': creation_object['owner_user'], + 'prefix': standardized + } + ) + + # Created the prefix. + errors['201_prefix_modify'] = db.messages( + parameters = { + 'prefix': standardized + } + )['201_prefix_modify'] + + # Append the possible "errors". + returning.append(errors) # As this view is for a bulk operation, status 200 # means that the request was successfully processed, diff --git a/bco_api/api/scripts/method_specific/POST_api_prefixes_permissions_set.py b/bco_api/api/scripts/method_specific/POST_api_prefixes_permissions_set.py index f655906a..62a34bcc 100755 --- a/bco_api/api/scripts/method_specific/POST_api_prefixes_permissions_set.py +++ b/bco_api/api/scripts/method_specific/POST_api_prefixes_permissions_set.py @@ -77,13 +77,16 @@ def POST_api_prefixes_permissions_set( error_check = True - # Bad request, the user isn't the owner. + # Bad request, the user isn't the owner or wheel. errors['403_requestor_is_not_prefix_owner'] = db.messages( parameters = { 'prefix': standardized } )['403_requestor_is_not_prefix_owner'] + # The "expensive" work of assigning permissions is held off + # if any of the above checks fails. + # Did any check fail? if error_check is False: diff --git a/bco_api/api/views.py b/bco_api/api/views.py index 012d5cfd..bad39d97 100755 --- a/bco_api/api/views.py +++ b/bco_api/api/views.py @@ -873,6 +873,7 @@ def get(self, request) -> Response: return POST_api_objects_published() # return POST_api_objects_token(rqst=request) + class ApiPrefixesCreate(APIView): """ Create a Prefix @@ -885,17 +886,24 @@ class ApiPrefixesCreate(APIView): ```JSON { - "POST_api_prefixes_create": { - "prefixes":[ - { - "description": "Generic testing prefix.", - "expiration_date": "2023-01-01-01-01-01", - "owner_group": "bco_publisher", - "owner_user": "anon", - "prefix": "tEsTr" - } - ] - } + "POST_api_prefixes_create": [ + { + "owner_group": "bco_publisher", + "owner_user": "anon", + "prefixes": [ + { + "description": "Just a test prefix.", + "expiration_date": "2023-01-01-01-01-01", + "prefix": "testR" + }, + { + "description": "Just another prefix.", + "expiration_date": "2023-01-01-01-01-01", + "prefix": "othER" + } + ] + } + ] } ``` @@ -915,7 +923,7 @@ class ApiPrefixesCreate(APIView): 'expiration_date': openapi.Schema(type=openapi.TYPE_STRING, description='The datetime at which this prefix expires in the format YYYY-MM-DD-HH-MM-SS.'), 'owner_group': openapi.Schema(type=openapi.TYPE_STRING, description='Which group should own the prefix. *The requestor does not have to be in owner_group to assign this.*'), 'owner_user': openapi.Schema(type=openapi.TYPE_STRING, description='Which user should own the prefix. *The requestor does not have to be owner_user to assign this.*'), - 'prefix': openapi.Schema(type=openapi.TYPE_STRING, description='Any prefix which satsifies the naming standard (see link...)'), + 'prefixes': openapi.Schema(type=openapi.TYPE_STRING, description='Any prefix which satsifies the naming standard (see link...)') }) @swagger_auto_schema(request_body=request_body, responses={ @@ -941,13 +949,12 @@ class ApiPrefixesDelete(APIView): ```JSON { - "POST_api_prefixes_delete": { - "prefixes":[ - "PRFX", - "OTR", - "GLY" - ] - } + "POST_api_prefixes_delete": [ + "PRFX", + "OTR", + "GLY", + "TESTR" + ] } ``` @@ -986,17 +993,24 @@ class ApiPrefixesModify(APIView): ```JSON { - "POST_api_prefixes_modify": { - "prefixes":[ - { - "description": "Here is some new description.", - "expiration_date": "2023-01-01-01-01-01", - "owner_group": "some_new_owner_group", - "owner_user": "some_new_owner_user", - "prefix": "tEsTr" - } - ] - } + "POST_api_prefixes_modify": [ + { + "owner_group": "bco_drafter", + "owner_user": "wheel", + "prefixes": [ + { + "description": "Just another description here.", + "expiration_date": "2025-01-01-01-01-01", + "prefix": "testR" + }, + { + "description": "Just another prefix description here as well.", + "expiration_date": "2025-01-01-01-01-01", + "prefix": "othER" + } + ] + } + ] } ``` @@ -1047,12 +1061,16 @@ class ApiPrefixesPermissionsSet(APIView): "group": [ "bco_drafter" ], + "mode": "add", "permissions": [ "change", "delete", "view" ], - "prefix": "BCO", + "prefixes": [ + "testR", + "BCO" + ] "username": [ "some_user" ], @@ -1074,6 +1092,7 @@ class ApiPrefixesPermissionsSet(APIView): required=['permissions', 'prefix'], properties={ 'group': openapi.Schema(type=openapi.TYPE_STRING, description='Which group the permission is being assigned to.'), + 'mode': openapi.Schema(type=openapi.TYPE_STRING, description='Whether to \'add\' (append), \'remove\' (subtract), or define the \'full_set\' of permissions.'), 'permissions': openapi.Schema(type=openapi.TYPE_STRING, description='Which permissions to assign.'), 'prefix': openapi.Schema(type=openapi.TYPE_STRING, description='Which prefix to assign the permissions to.'), 'username': openapi.Schema(type=openapi.TYPE_STRING, description='Which user the permission is being assigned to.'), From a5e4af900d93b67b5758e9d2576823ceac3b2b68 Mon Sep 17 00:00:00 2001 From: Chris Armstrong Date: Mon, 24 Jan 2022 23:02:44 -0500 Subject: [PATCH 2/5] Logic looks good. BUT, OpenAPI definitions aren't quite right. --- bco_api/api/migrations/0001_initial.py | 2 +- .../POST_api_prefixes_create.py | 6 +- .../POST_api_prefixes_modify.py | 2 +- .../POST_api_prefixes_permissions_set.py | 239 +++++++++--------- bco_api/api/scripts/utilities/UserUtils.py | 6 +- bco_api/api/views.py | 9 +- 6 files changed, 137 insertions(+), 127 deletions(-) diff --git a/bco_api/api/migrations/0001_initial.py b/bco_api/api/migrations/0001_initial.py index d94b1bf6..ee563255 100644 --- a/bco_api/api/migrations/0001_initial.py +++ b/bco_api/api/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 3.2.10 on 2022-01-24 23:26 +# Generated by Django 3.2.10 on 2022-01-25 04:01 from django.conf import settings from django.db import migrations, models diff --git a/bco_api/api/scripts/method_specific/POST_api_prefixes_create.py b/bco_api/api/scripts/method_specific/POST_api_prefixes_create.py index cecd1eef..55392f2a 100755 --- a/bco_api/api/scripts/method_specific/POST_api_prefixes_create.py +++ b/bco_api/api/scripts/method_specific/POST_api_prefixes_create.py @@ -21,6 +21,10 @@ def POST_api_prefixes_create( incoming ): + # TODO: replace user/group looping with basic filtering + # on the model. Loops now are slower than a single + # filter call. + # Instantiate any necessary imports. db = DbUtils.DbUtils() uu = UserUtils.UserUtils() @@ -136,7 +140,7 @@ def POST_api_prefixes_create( p_fields = ['created_by', 'description', 'owner_group', 'owner_user', 'prefix'], p_data = { 'created_by': uu.user_from_request( - request = incoming + rq = incoming ).username, 'description': prfx['description'], 'owner_group': creation_object['owner_group'], diff --git a/bco_api/api/scripts/method_specific/POST_api_prefixes_modify.py b/bco_api/api/scripts/method_specific/POST_api_prefixes_modify.py index d1bbfec2..2a13ab5f 100755 --- a/bco_api/api/scripts/method_specific/POST_api_prefixes_modify.py +++ b/bco_api/api/scripts/method_specific/POST_api_prefixes_modify.py @@ -113,7 +113,7 @@ def POST_api_prefixes_modify( p_fields = ['created_by', 'description', 'owner_group', 'owner_user', 'prefix'], p_data = { 'created_by': uu.user_from_request( - request = incoming + rq = incoming ).username, 'description': prfx['description'], 'owner_group': creation_object['owner_group'], diff --git a/bco_api/api/scripts/method_specific/POST_api_prefixes_permissions_set.py b/bco_api/api/scripts/method_specific/POST_api_prefixes_permissions_set.py index 62a34bcc..1cf17aaa 100755 --- a/bco_api/api/scripts/method_specific/POST_api_prefixes_permissions_set.py +++ b/bco_api/api/scripts/method_specific/POST_api_prefixes_permissions_set.py @@ -40,8 +40,8 @@ def POST_api_prefixes_permissions_set( prefixes.objects.all().values_list( 'prefix', flat = True - ) ) + ) # Construct an array to return information about processing # the request. @@ -51,146 +51,149 @@ def POST_api_prefixes_permissions_set( # item in the array. for creation_object in bulk_request: - # Create a list to hold information about errors. - errors = {} + # Go over each prefix proposed. + for prfx in creation_object['prefixes']: - # Standardize the prefix name. - standardized = creation_object['prefix'].upper() + # Create a list to hold information about errors. + errors = {} + + # Standardize the prefix name. + standardized = prfx.upper() - # Create a flag for if one of these checks fails. - error_check = False + # Create a flag for if one of these checks fails. + error_check = False - # Has the prefix already been created? - if standardized not in available_prefixes: + # Has the prefix already been created? + if standardized not in available_prefixes: + + error_check = True + + # Update the request status. + errors['404_missing_prefix'] = db.messages( + parameters = { + 'prefix': standardized + } + )['404_missing_prefix'] - error_check = True - - # Update the request status. - errors['404_missing_prefix'] = db.messages( - parameters = { - 'prefix': standardized - } - )['404_missing_prefix'] - - # The prefix exists, but is the requestor the owner? - if uu.check_user_owns_prefix(un = user.username, prfx = standardized) is False and user.username != 'wheel': + # The prefix exists, but is the requestor the owner? + if uu.check_user_owns_prefix(un = user.username, prfx = standardized) is False and user.username != 'wheel': - error_check = True + error_check = True - # Bad request, the user isn't the owner or wheel. - errors['403_requestor_is_not_prefix_owner'] = db.messages( - parameters = { - 'prefix': standardized - } - )['403_requestor_is_not_prefix_owner'] - - # The "expensive" work of assigning permissions is held off - # if any of the above checks fails. - - # Did any check fail? - if error_check is False: - - # Split out the permissions assignees into users and groups. - assignees = { - 'group': [], - 'username': [] - } - - if 'username' in creation_object: - assignees['username'] = creation_object['username'] + # Bad request, the user isn't the owner or wheel. + errors['403_requestor_is_not_prefix_owner'] = db.messages( + parameters = { + 'prefix': standardized + } + )['403_requestor_is_not_prefix_owner'] - if 'group' in creation_object: - assignees['group'] = creation_object['group'] + # The "expensive" work of assigning permissions is held off + # if any of the above checks fails. - # Go through each one. - for un in assignees['username']: + # Did any check fail? + if error_check is False: + + # Split out the permissions assignees into users and groups. + assignees = { + 'group': [], + 'username': [] + } + + if 'username' in creation_object: + assignees['username'] = creation_object['username'] - # Create a list to hold information about sub-errors. - sub_errors = {} - - # Create a flag for if one of these sub-checks fails. - sub_error_check = False + if 'group' in creation_object: + assignees['group'] = creation_object['group'] - # Get the user whose permissions are being assigned. - if uu.check_user_exists(un = un) is False: - - sub_error_check = True + # Go through each one. + for un in assignees['username']: - # Bad request, the user doesn't exist. - sub_errors['404_user_not_found'] = db.messages( - parameters = { - 'username': un - } - )['404_user_not_found'] - - # Was the user found? - if sub_error_check is False: - - assignee = User.objects.get(username = un) - - # Permissions are defined directly as they are - # in the POST request. + # Create a list to hold information about sub-errors. + sub_errors = {} - # Assumes permissions are well-formed... - - # Source: https://docs.djangoproject.com/en/3.2/topics/auth/default/#permissions-and-authorization - assignee.user_permissions.set([Permission.objects.get(codename = i + '_' + creation_object['prefix']) for i in creation_object['permissions']]) + # Create a flag for if one of these sub-checks fails. + sub_error_check = False + + # Get the user whose permissions are being assigned. + if uu.check_user_exists(un = un) is False: + + sub_error_check = True + + # Bad request, the user doesn't exist. + sub_errors['404_user_not_found'] = db.messages( + parameters = { + 'username': un + } + )['404_user_not_found'] + + # Was the user found? + if sub_error_check is False: + + assignee = User.objects.get(username = un) - # Permissions assigned. - sub_errors['200_OK_prefix_permissions_update'] = db.messages( - parameters = { - 'prefix': standardized - } - )['200_OK_prefix_permissions_update'] - - # Add the sub-"errors". - errors['username'] = sub_errors - - for g in assignees['group']: - - # Create a list to hold information about sub-errors. - sub_errors = {} + # Permissions are defined directly as they are + # in the POST request. - # Create a flag for if one of these sub-checks fails. - sub_error_check = False + # Assumes permissions are well-formed... - # Get the group whose permissions are being assigned. - if uu.check_group_exists(n = g) is False: + # Source: https://docs.djangoproject.com/en/3.2/topics/auth/default/#permissions-and-authorization + assignee.user_permissions.set([Permission.objects.get(codename = i + '_' + prfx) for i in creation_object['permissions']]) - sub_error_check = True + # Permissions assigned. + sub_errors['200_OK_prefix_permissions_update'] = db.messages( + parameters = { + 'prefix': standardized + } + )['200_OK_prefix_permissions_update'] - # Bad request, the group doesn't exist. - sub_errors['404_group_not_found'] = db.messages( - parameters = { - 'group': g - } - )['404_group_not_found'] + # Add the sub-"errors". + errors['username'] = sub_errors - # Was the group found? - if sub_error_check is False: - - assignee = Group.objects.get(name = g) + for g in assignees['group']: + + # Create a list to hold information about sub-errors. + sub_errors = {} + + # Create a flag for if one of these sub-checks fails. + sub_error_check = False + + # Get the group whose permissions are being assigned. + if uu.check_group_exists(n = g) is False: + + sub_error_check = True + + # Bad request, the group doesn't exist. + sub_errors['404_group_not_found'] = db.messages( + parameters = { + 'group': g + } + )['404_group_not_found'] + + # Was the group found? + if sub_error_check is False: + + assignee = Group.objects.get(name = g) - # Permissions are defined directly as they are - # in the POST request. + # Permissions are defined directly as they are + # in the POST request. - # Assumes permissions are well-formed... + # Assumes permissions are well-formed... - # Source: https://docs.djangoproject.com/en/3.2/topics/auth/default/#permissions-and-authorization - assignee.permissions.set([Permission.objects.get(codename = i + '_' + creation_object['prefix']) for i in creation_object['permissions']]) + # Source: https://docs.djangoproject.com/en/3.2/topics/auth/default/#permissions-and-authorization + assignee.permissions.set([Permission.objects.get(codename = i + '_' + prfx) for i in creation_object['permissions']]) - # Permissions assigned. - sub_errors['200_OK_prefix_permissions_update'] = db.messages( - parameters = { - 'prefix': standardized - } - )['200_OK_prefix_permissions_update'] + # Permissions assigned. + sub_errors['200_OK_prefix_permissions_update'] = db.messages( + parameters = { + 'prefix': standardized + } + )['200_OK_prefix_permissions_update'] + + # Add the sub-"errors". + errors['group'] = sub_errors - # Add the sub-"errors". - errors['group'] = sub_errors - - # Append the possible "errors". - returning.append(errors) + # Append the possible "errors". + returning.append(errors) # As this view is for a bulk operation, status 200 # means that the request was successfully processed, diff --git a/bco_api/api/scripts/utilities/UserUtils.py b/bco_api/api/scripts/utilities/UserUtils.py index 9e0f586a..5d4f5543 100755 --- a/bco_api/api/scripts/utilities/UserUtils.py +++ b/bco_api/api/scripts/utilities/UserUtils.py @@ -387,12 +387,12 @@ def prefix_perms_for_user( return bco_specific - def user_from_request(self, request): + def user_from_request(self, rq): """Returns a user object from a request. Parameters ---------- - request: rest_framework.request.Request + rq: rest_framework.request.Request Django request object. Returns @@ -401,5 +401,5 @@ def user_from_request(self, request): """ user_id = Token.objects.get( - key=request.META.get('HTTP_AUTHORIZATION').split(' ')[1]).user_id + key=rq.META.get('HTTP_AUTHORIZATION').split(' ')[1]).user_id return User.objects.get(id=user_id) diff --git a/bco_api/api/views.py b/bco_api/api/views.py index bad39d97..d029b10e 100755 --- a/bco_api/api/views.py +++ b/bco_api/api/views.py @@ -912,6 +912,9 @@ class ApiPrefixesCreate(APIView): # 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, @@ -923,7 +926,7 @@ class ApiPrefixesCreate(APIView): 'expiration_date': openapi.Schema(type=openapi.TYPE_STRING, description='The datetime at which this prefix expires in the format YYYY-MM-DD-HH-MM-SS.'), 'owner_group': openapi.Schema(type=openapi.TYPE_STRING, description='Which group should own the prefix. *The requestor does not have to be in owner_group to assign this.*'), 'owner_user': openapi.Schema(type=openapi.TYPE_STRING, description='Which user should own the prefix. *The requestor does not have to be owner_user to assign this.*'), - 'prefixes': openapi.Schema(type=openapi.TYPE_STRING, description='Any prefix which satsifies the naming standard (see link...)') + 'prefixes': openapi.Schema(type=openapi.TYPE_ARRAY, description='Any prefix which satsifies the naming standard (see link...)', items=openapi.Items(type=openapi.TYPE_STRING)) }) @swagger_auto_schema(request_body=request_body, responses={ @@ -1070,10 +1073,10 @@ class ApiPrefixesPermissionsSet(APIView): "prefixes": [ "testR", "BCO" - ] + ], "username": [ "some_user" - ], + ] } ] } From 2c70dac0e913e2ad872cf6d3c0126e9b75a48b99 Mon Sep 17 00:00:00 2001 From: Hadley King Date: Thu, 3 Feb 2022 16:48:44 -0500 Subject: [PATCH 3/5] Linting for prefix files - Fix 0001_initial.py to include original date - linting for POST_api_prefixes_create.py - linting for POST_api_prefixes_delete.py - fix swagger for POST_api_prefixes_delete in views.py --- bco_api/api/migrations/0001_initial.py | 2 + .../POST_api_prefixes_create.py | 297 ++++++++---------- .../POST_api_prefixes_delete.py | 100 +++--- bco_api/api/scripts/utilities/UserUtils.py | 6 +- bco_api/api/views.py | 12 +- 5 files changed, 186 insertions(+), 231 deletions(-) diff --git a/bco_api/api/migrations/0001_initial.py b/bco_api/api/migrations/0001_initial.py index bddb64a9..85b5043f 100644 --- a/bco_api/api/migrations/0001_initial.py +++ b/bco_api/api/migrations/0001_initial.py @@ -1,3 +1,5 @@ +# Generated by Django 3.2 on 2021-10-01 12:33 + from django.conf import settings from django.db import migrations, models import django.db.models.deletion diff --git a/bco_api/api/scripts/method_specific/POST_api_prefixes_create.py b/bco_api/api/scripts/method_specific/POST_api_prefixes_create.py index a4454042..f711b196 100755 --- a/bco_api/api/scripts/method_specific/POST_api_prefixes_create.py +++ b/bco_api/api/scripts/method_specific/POST_api_prefixes_create.py @@ -1,170 +1,147 @@ -# For getting objects out of the database. -from ..utilities import DbUtils +#!/usr/bin/env python3 +"""Create a prefix -# Checking that a user is in a group. -from ..utilities import UserUtils +Create a prefix to be used to classify BCOs and to determine permissions +for objects created under that prefix. The requestor must be in the group +prefix_admins to create a prefix. +""" -# Model fields -from ...models import prefixes - -# Checking prefixes import re -# Responses +from api.scripts.utilities import DbUtils +from api.scripts.utilities import UserUtils +from api.models import prefixes + from rest_framework import status from rest_framework.response import Response -def POST_api_prefixes_create( - incoming -): - - # TODO: replace user/group looping with basic filtering - # on the model. Loops now are slower than a single - # filter call. - - # Instantiate any necessary imports. - db = DbUtils.DbUtils() - uu = UserUtils.UserUtils() - - # Define the bulk request. - bulk_request = incoming.data['POST_api_prefixes_create'] - - # Get all existing prefixes. - available_prefixes = list( - prefixes.objects.all().values_list( - 'prefix', - flat = True - ) - ) - - # Construct an array to return information about processing - # the request. - returning = [] - - # Since bulk_request is an array, go over each - # item in the array. - for creation_object in bulk_request: - - # Go over each prefix proposed. - for prfx in creation_object['prefixes']: - - # Create a list to hold information about errors. - errors = {} - - # Standardize the prefix name. - standardized = prfx['prefix'].upper() - - # TODO: abstract this error check to schema checker? - - # Check for each error. - - # Create a flag for if one of these checks fails. - error_check = False - - # Does the prefix follow the regex for prefixes? - if not re.match( - r"^[A-Z]{3,5}$", - standardized - ): - - error_check = True - - # Bad request because the prefix doesn't follow - # the naming rules. - errors['400_bad_request_malformed_prefix'] = db.messages( - parameters = { - 'prefix': standardized.upper() - } - )['400_bad_request_malformed_prefix'] - - # Has the prefix already been created? - if standardized in available_prefixes: - - error_check = True - - # Update the request status. - errors['409_prefix_conflict'] = db.messages( - parameters = { - 'prefix': standardized.upper() - } - )['409_prefix_conflict'] - - # Does the user exist? - if uu.check_user_exists(un = creation_object['owner_user']) is False: - - error_check = True - - # Bad request. - errors['404_user_not_found'] = db.messages( - parameters = { - 'username': creation_object['owner_user'] - } - )['404_user_not_found'] - - # Does the group exist? - if uu.check_group_exists(n = creation_object['owner_group']) is False: - - error_check = True - - # Bad request. - errors['404_group_not_found'] = db.messages( - parameters = { - 'group': creation_object['owner_group'] - } - )['404_group_not_found'] - - # Was the expiration date validly formatted and, if so, - # is it after right now? - if 'expiration_date' in prfx: - if db.check_expiration(dt_string = prfx['expiration_date']) is not None: - - error_check = True - - # Bad request. - errors['400_invalid_expiration_date'] = db.messages( - parameters = { - 'expiration_date': prfx['expiration_date'] - } - )['400_invalid_expiration_date'] - - # Did any check fail? - if error_check is False: - - # The prefix has not been created, so create it. - DbUtils.DbUtils().write_object( - p_app_label = 'api', - p_model_name = 'prefixes', - p_fields = ['created_by', 'description', 'owner_group', 'owner_user', 'prefix'], - p_data = { - 'created_by': uu.user_from_request( - rq = incoming - ).username, - 'description': prfx['description'], - 'owner_group': creation_object['owner_group'], - 'owner_user': creation_object['owner_user'], - 'prefix': standardized - } - ) - - # Created the prefix. - errors['201_prefix_create'] = db.messages( - parameters = { - 'prefix': standardized - } - )['201_prefix_create'] - - # Append the possible "errors". - returning.append(errors) - - # As this view is for a bulk operation, status 200 - # means that the request was successfully processed, - # but NOT necessarily each item in the request. - return( - Response( - status = status.HTTP_200_OK, - data = returning - ) - ) \ No newline at end of file +def POST_api_prefixes_create(request): + """Create a prefix + + Parameters + ---------- + request: rest_framework.request.Request + Django request object. + + Returns + ------- + rest_framework.response.Response + An HttpResponse that allows its data to be rendered into + arbitrary media types. + + """ + + # TODO: replace user/group looping with basic filtering + # on the model. Loops now are slower than a single + # filter call. + + # Instantiate any necessary imports. + db_utils = DbUtils.DbUtils() + user_utils = UserUtils.UserUtils() + + # Define the bulk request. + bulk_request = request.data['POST_api_prefixes_create'] + + # Get all existing prefixes. + available_prefixes = list( + prefixes.objects.all().values_list('prefix', flat = True)) + + # Construct an array to return information about processing + # the request. + returning = [] + + # Since bulk_request is an array, go over each + # item in the array. + for creation_object in bulk_request: + # Go over each prefix proposed. + for prfx in creation_object['prefixes']: + # Create a list to hold information about errors. + errors = {} + # Standardize the prefix name. + standardized = prfx['prefix'].upper() + # TODO: abstract this error check to schema checker? + # Check for each error. + # Create a flag for if one of these checks fails. + error_check = False + # Does the prefix follow the regex for prefixes? + if not re.match(r"^[A-Z]{3,5}$", standardized): + error_check = True + # Bad request because the prefix doesn't follow + # the naming rules. + errors['400_bad_request_malformed_prefix'] = db_utils.messages( + parameters = {'prefix': standardized.upper()} + )['400_bad_request_malformed_prefix'] + + # Has the prefix already been created? + if standardized in available_prefixes: + error_check = True + # Update the request status. + errors['409_prefix_conflict'] = db_utils.messages( + parameters = { + 'prefix': standardized.upper() + } + )['409_prefix_conflict'] + + # Does the user exist? + if user_utils.check_user_exists(un = creation_object['owner_user']) is False: + + error_check = True + + # Bad request. + errors['404_user_not_found'] = db_utils.messages( + parameters = {'username': creation_object['owner_user']} + )['404_user_not_found'] + + # Does the group exist? + if user_utils.check_group_exists(n = creation_object['owner_group']) is False: + error_check = True + # Bad request. + errors['404_group_not_found'] = db_utils.messages( + parameters = {'group': creation_object['owner_group']} + )['404_group_not_found'] + + # Was the expiration date validly formatted and, if so, + # is it after right now? + if 'expiration_date' in prfx: + if db_utils.check_expiration(dt_string = prfx['expiration_date']) is not None: + error_check = True + # Bad request. + errors['400_invalid_expiration_date'] = db_utils.messages( + parameters = { + 'expiration_date': prfx['expiration_date']} + )['400_invalid_expiration_date'] + # Did any check fail? + if error_check is False: + # The prefix has not been created, so create it. + DbUtils.DbUtils().write_object( + p_app_label = 'api', + p_model_name = 'prefixes', + p_fields = ['created_by', 'description', 'owner_group', 'owner_user', 'prefix'], + p_data = { + 'created_by': user_utils.user_from_request( + request = request + ).username, + 'description': prfx['description'], + 'owner_group': creation_object['owner_group'], + 'owner_user': creation_object['owner_user'], + 'prefix': standardized + } + ) + + # Created the prefix. + errors['201_prefix_create'] = db_utils.messages( + parameters = { + 'prefix': standardized + } + )['201_prefix_create'] + + # Append the possible "errors". + returning.append(errors) + + # As this view is for a bulk operation, status 200 + # means that the request was successfully processed, + # but NOT necessarily each item in the request. + return Response(status = status.HTTP_200_OK, data = returning) diff --git a/bco_api/api/scripts/method_specific/POST_api_prefixes_delete.py b/bco_api/api/scripts/method_specific/POST_api_prefixes_delete.py index ea8383ee..80e888b7 100755 --- a/bco_api/api/scripts/method_specific/POST_api_prefixes_delete.py +++ b/bco_api/api/scripts/method_specific/POST_api_prefixes_delete.py @@ -1,49 +1,47 @@ -# For getting objects out of the database. -from ..utilities import DbUtils - -# Checking that a user is in a group. -from ..utilities import UserUtils - -# Model fields -from ...models import prefixes - -# Responses +#!/usr/bin/env python3 +"""Delete a prefix + +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. +""" +from api.scripts.utilities import DbUtils +from api.models import prefixes from rest_framework import status from rest_framework.response import Response +def POST_api_prefixes_delete(request): + """Deletes a prefix + Parameters + ---------- + request: rest_framework.request.Request + Django request object. + Returns + ------- + rest_framework.response.Response + An HttpResponse that allows its data to be rendered into + arbitrary media types. + """ -def POST_api_prefixes_delete( - incoming -): - - # Instantiate any necessary imports. - db = DbUtils.DbUtils() - uu = UserUtils.UserUtils() + db_utils = DbUtils.DbUtils() - # Define the bulk request. - bulk_request = incoming.data['POST_api_prefixes_delete'] + bulk_request = request.data['POST_api_prefixes_delete'] # Get all existing prefixes. available_prefixes = list( - prefixes.objects.all().values_list( - 'prefix', - flat=True - ) - ) - - # Construct an array to return information about processing - # the request. + prefixes.objects.all().values_list('prefix', flat=True)) + returning = [] - # Since bulk_request is an array, go over each - # item in the array. for creation_object in bulk_request: # Create a list to hold information about errors. errors = {} - + # Standardize the prefix name. standardized = creation_object.upper() @@ -51,49 +49,27 @@ def POST_api_prefixes_delete( error_check = False if standardized not in available_prefixes: - - error_check = True - + error_check = True # Update the request status. - errors['404_missing_prefix'] = db.messages( - parameters={ - 'prefix': standardized - } - )['404_missing_prefix'] - - # Did any check fail? + errors['404_missing_prefix'] = db_utils.messages(parameters={ + 'prefix': standardized})['404_missing_prefix'] + if error_check is False: - # The prefix exists, so delete it. - # No need to use DB Utils here, # just delete straight up. - # Source: https://stackoverflow.com/a/3681691 - # Django *DOESN'T* want primary keys now... - - prefixed = prefixes.objects.get( - prefix=standardized - ) + prefixed = prefixes.objects.get(prefix=standardized) prefixed.delete() - # Deleted the prefix. - errors['200_OK_prefix_delete'] = db.messages( - parameters={ - 'prefix': standardized - } - )['200_OK_prefix_delete'] - + errors['200_OK_prefix_delete'] = db_utils.messages(parameters={ + 'prefix': standardized})['200_OK_prefix_delete'] + # Append the possible "errors". - returning.append(errors) + returning.append(errors) # As this view is for a bulk operation, status 200 # means that the request was successfully processed, # but NOT necessarily each item in the request. - return ( - Response( - status=status.HTTP_200_OK, - data=returning - ) - ) + return Response(status=status.HTTP_200_OK, data=returning) diff --git a/bco_api/api/scripts/utilities/UserUtils.py b/bco_api/api/scripts/utilities/UserUtils.py index 5d4f5543..9e0f586a 100755 --- a/bco_api/api/scripts/utilities/UserUtils.py +++ b/bco_api/api/scripts/utilities/UserUtils.py @@ -387,12 +387,12 @@ def prefix_perms_for_user( return bco_specific - def user_from_request(self, rq): + def user_from_request(self, request): """Returns a user object from a request. Parameters ---------- - rq: rest_framework.request.Request + request: rest_framework.request.Request Django request object. Returns @@ -401,5 +401,5 @@ def user_from_request(self, rq): """ user_id = Token.objects.get( - key=rq.META.get('HTTP_AUTHORIZATION').split(' ')[1]).user_id + key=request.META.get('HTTP_AUTHORIZATION').split(' ')[1]).user_id return User.objects.get(id=user_id) diff --git a/bco_api/api/views.py b/bco_api/api/views.py index 09fe0061..66a718d7 100755 --- a/bco_api/api/views.py +++ b/bco_api/api/views.py @@ -898,7 +898,7 @@ class ApiPrefixesCreate(APIView): { "description": "Just another prefix.", "expiration_date": "2023-01-01-01-01-01", - "prefix": "othER" + "prefix": "othER" } ] } @@ -954,9 +954,7 @@ class ApiPrefixesDelete(APIView): ```JSON { "POST_api_prefixes_delete": [ - "PRFX", - "OTR", - "GLY", + "OTHER", "TESTR" ] } @@ -974,8 +972,10 @@ class ApiPrefixesDelete(APIView): description="Provide a list of prefixes to delete.", required=['prefixes'], properties={ - 'prefixes': openapi.Schema(type=openapi.TYPE_STRING, - description='Any prefix in the API.'), + 'prefixes': openapi.Schema( + type=openapi.TYPE_ARRAY, + description='Any prefix in the API.', + items=openapi.Items(type=openapi.TYPE_STRING)), } ) From 092d862a72e5aeb540537cd01dd807f0280d3259 Mon Sep 17 00:00:00 2001 From: Hadley King Date: Thu, 3 Feb 2022 17:35:48 -0500 Subject: [PATCH 4/5] Linting & doc updates for POST_api_prefixes_modify Changes to be committed: modified: bco_api/api/scripts/method_specific/POST_api_prefixes_modify.py modified: bco_api/api/views.py --- .../POST_api_prefixes_modify.py | 67 ++++++------ bco_api/api/views.py | 102 +++++++++++++----- 2 files changed, 110 insertions(+), 59 deletions(-) diff --git a/bco_api/api/scripts/method_specific/POST_api_prefixes_modify.py b/bco_api/api/scripts/method_specific/POST_api_prefixes_modify.py index 2a13ab5f..1b615539 100755 --- a/bco_api/api/scripts/method_specific/POST_api_prefixes_modify.py +++ b/bco_api/api/scripts/method_specific/POST_api_prefixes_modify.py @@ -1,37 +1,40 @@ -# For getting objects out of the database. -from api.scripts.utilities import DbUtils +#!/usr/bin/env python3 +"""Modify a Prefix -# Checking that a user is in a group. -from api.scripts.utilities import UserUtils +Modify a prefix which already exists. -# Model fields +The requestor *must* be in the group prefix_admins to modify a prefix. +""" +from api.scripts.utilities import DbUtils +from api.scripts.utilities import UserUtils from api.models import prefixes - -# Responses from rest_framework import status from rest_framework.response import Response -def POST_api_prefixes_modify( - incoming -): - - # Instantiate any necessary imports. - db = DbUtils.DbUtils() - uu = UserUtils.UserUtils() +def POST_api_prefixes_modify(request): + """Modify a Prefix - # Define the bulk request. - bulk_request = incoming.data['POST_api_prefixes_modify'] + Parameters + ---------- + request: rest_framework.request.Request + Django request object. - # Get all existing prefixes. + Returns + ------- + rest_framework.response.Response + An HttpResponse that allows its data to be rendered into + arbitrary media types. + """ + # Instantiate any necessary imports. + db_utils = DbUtils.DbUtils() + user_utils = UserUtils.UserUtils() + + bulk_request = request.data['POST_api_prefixes_modify'] available_prefixes = list( - prefixes.objects.all().values_list( - 'prefix', - flat = True - ) - ) + prefixes.objects.all().values_list('prefix', flat = True)) # Construct an array to return information about processing # the request. @@ -59,31 +62,31 @@ def POST_api_prefixes_modify( # Update the request status. # Bad request. - errors['404_missing_prefix'] = db.messages( + errors['404_missing_prefix'] = db_utils.messages( parameters = { 'prefix': standardized } )['404_missing_prefix'] # Does the user exist? - if uu.check_user_exists(un = creation_object['owner_user']) is False: + if user_utils.check_user_exists(un = creation_object['owner_user']) is False: error_check = True # Bad request. - errors['404_user_not_found'] = db.messages( + errors['404_user_not_found'] = db_utils.messages( parameters = { 'username': creation_object['owner_user'] } )['404_user_not_found'] # Does the group exist? - if uu.check_group_exists(n = creation_object['owner_group']) is False: + if user_utils.check_group_exists(n = creation_object['owner_group']) is False: error_check = True # Bad request. - errors['404_group_not_found'] = db.messages( + errors['404_group_not_found'] = db_utils.messages( parameters = { 'group': creation_object['owner_group'] } @@ -92,12 +95,12 @@ def POST_api_prefixes_modify( # Was the expiration date validly formatted and, if so, # is it after right now? if 'expiration_date' in prfx: - if db.check_expiration(dt_string = prfx['expiration_date']) is not None: + if db_utils.check_expiration(dt_string = prfx['expiration_date']) is not None: error_check = True # Bad request. - errors['400_invalid_expiration_date'] = db.messages( + errors['400_invalid_expiration_date'] = db_utils.messages( parameters = { 'expiration_date': prfx['expiration_date'] } @@ -112,8 +115,8 @@ def POST_api_prefixes_modify( p_model_name = 'prefixes', p_fields = ['created_by', 'description', 'owner_group', 'owner_user', 'prefix'], p_data = { - 'created_by': uu.user_from_request( - rq = incoming + 'created_by': user_utils.user_from_request( + request = request ).username, 'description': prfx['description'], 'owner_group': creation_object['owner_group'], @@ -123,7 +126,7 @@ def POST_api_prefixes_modify( ) # Created the prefix. - errors['201_prefix_modify'] = db.messages( + errors['201_prefix_modify'] = db_utils.messages( parameters = { 'prefix': standardized } diff --git a/bco_api/api/views.py b/bco_api/api/views.py index 66a718d7..d5a03b7d 100755 --- a/bco_api/api/views.py +++ b/bco_api/api/views.py @@ -604,15 +604,20 @@ class ApiObjectsDraftsPublish(APIView): 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.'), - 'draft_id' : openapi.Schema(type=openapi.TYPE_STRING, description='BCO Object Draft ID.'), - 'object_id' : openapi.Schema(type=openapi.TYPE_STRING, description='BCO Object ID.'), - 'delete_draft': openapi.Schema(type=openapi.TYPE_BOOLEAN, description='Whether or not to delete the draft. False by default.'), - } - ) + type=openapi.TYPE_OBJECT, + required=['draft_id', 'prefix'], + properties={ + 'prefix': openapi.Schema(type=openapi.TYPE_STRING, + description='BCO Prefix to publish with.'), + 'draft_id': openapi.Schema(type=openapi.TYPE_STRING, + description='BCO Object Draft ID.'), + 'object_id': openapi.Schema(type=openapi.TYPE_STRING, + description='BCO Object ID.'), + 'delete_draft': openapi.Schema(type=openapi.TYPE_BOOLEAN, + description='Whether or not to delete the draft.' + ' False by default.'), + } + ) request_body = openapi.Schema( type=openapi.TYPE_OBJECT, @@ -620,10 +625,12 @@ class ApiObjectsDraftsPublish(APIView): description="Parameters that are supported when setting publishing BCOs.", required=['POST_api_objects_drafts_publish'], properties={ - 'POST_api_objects_drafts_publish': openapi.Schema(type=openapi.TYPE_ARRAY, - items=POST_api_objects_drafts_publish_schema, - description='BCO drafts to publish.'), - }) + 'POST_api_objects_drafts_publish': openapi.Schema( + type=openapi.TYPE_ARRAY, + items=POST_api_objects_drafts_publish_schema, + description='BCO drafts to publish.') + } + ) @swagger_auto_schema(request_body=request_body, responses={ 200: "BCO Publication is successful.", @@ -996,7 +1003,7 @@ class ApiPrefixesModify(APIView): -------------------- - # Modify a prefix which already exists. + Modify a prefix which already exists. The requestor *must* be in the group prefix_admins to modify a prefix. @@ -1015,7 +1022,7 @@ class ApiPrefixesModify(APIView): { "description": "Just another prefix description here as well.", "expiration_date": "2025-01-01-01-01-01", - "prefix": "othER" + "prefix": "othER" } ] } @@ -1027,21 +1034,62 @@ class ApiPrefixesModify(APIView): # Permissions - prefix admins only permission_classes = [RequestorInPrefixAdminsGroup] + prefixes_object_schema = openapi.Schema( + type=openapi.TYPE_OBJECT, + required=[], + properties={ + '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.' + ), + 'expiration_date': openapi.Schema( + type=openapi.TYPE_STRING, + description='The datetime at which this prefix expires in the' + ' format YYYY-MM-DD-HH-MM-SS.'), + 'prefix': openapi.Schema( + type=openapi.TYPE_STRING, + description='Any prefix which satsifies the naming standard') + } + + + ) + POST_api_prefixes_modify_schema = openapi.Schema( + type=openapi.TYPE_OBJECT, + required=[], + properties={ + 'owner_group': openapi.Schema( + type=openapi.TYPE_STRING, + description='Which group should own the prefix. *The' + ' requestor does not have to be in the owner group to' + ' assign this.*'), + 'owner_user': openapi.Schema( + type=openapi.TYPE_STRING, + description='Which user should own the prefix. *The requestor' + ' does not have to be owner_user but owner_user must be in' + ' owner_group*.'), + 'prefixes': openapi.Schema( + type=openapi.TYPE_ARRAY, + items=prefixes_object_schema, + description='Any prefix which satsifies the naming standard') + } + ) # TODO: Need to get the schema that is being sent here from FE request_body = openapi.Schema( - type=openapi.TYPE_OBJECT, - title="Prefix Modification Schema", - description="Several parameters are required to modify a prefix.", - required=['prefix'], - properties={ - '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.'), - 'expiration_date': openapi.Schema(type=openapi.TYPE_STRING, description='The datetime at which this prefix expires in the format YYYY-MM-DD-HH-MM-SS.'), - 'owner_group': openapi.Schema(type=openapi.TYPE_STRING, description='Which group should own the prefix. *The requestor does not have to be in the owner group to assign this.*'), - 'owner_user': openapi.Schema(type=openapi.TYPE_STRING, description='Which user should own the prefix. *The requestor does not have to be owner_user but owner_user must be in owner_group*.'), - 'prefix': openapi.Schema(type=openapi.TYPE_STRING, description='Any prefix which satsifies the naming standard (see link...)'), - }) - + type=openapi.TYPE_OBJECT, + title="Prefix Modification Schema", + description="Several parameters are required to modify a prefix.", + required=['POST_api_prefixes_modify'], + properties={ + 'POST_api_prefixes_modify': openapi.Schema( + type=openapi.TYPE_ARRAY, + items=POST_api_prefixes_modify_schema, + description='' + ) + }) # TODO: ADD LINK FOR PREFIX DOCUMENTATION + @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.", From 23585f4b8bb47ee15675053fdee92f4319125f38 Mon Sep 17 00:00:00 2001 From: Hadley King Date: Thu, 3 Feb 2022 17:53:35 -0500 Subject: [PATCH 5/5] Linting and docs for prefix token functions Changes to be committed: modified: bco_api/api/scripts/method_specific/POST_api_prefixes_create.py modified: bco_api/api/scripts/method_specific/POST_api_prefixes_token.py modified: bco_api/api/scripts/method_specific/POST_api_prefixes_token_flat.py modified: bco_api/api/views.py --- .../POST_api_prefixes_create.py | 1 - .../POST_api_prefixes_token.py | 63 +++++++++---------- .../POST_api_prefixes_token_flat.py | 56 ++++++++--------- bco_api/api/views.py | 15 ++--- 4 files changed, 62 insertions(+), 73 deletions(-) diff --git a/bco_api/api/scripts/method_specific/POST_api_prefixes_create.py b/bco_api/api/scripts/method_specific/POST_api_prefixes_create.py index f711b196..eb56bb18 100755 --- a/bco_api/api/scripts/method_specific/POST_api_prefixes_create.py +++ b/bco_api/api/scripts/method_specific/POST_api_prefixes_create.py @@ -31,7 +31,6 @@ def POST_api_prefixes_create(request): rest_framework.response.Response An HttpResponse that allows its data to be rendered into arbitrary media types. - """ # TODO: replace user/group looping with basic filtering diff --git a/bco_api/api/scripts/method_specific/POST_api_prefixes_token.py b/bco_api/api/scripts/method_specific/POST_api_prefixes_token.py index 4d1403a6..5772b84a 100644 --- a/bco_api/api/scripts/method_specific/POST_api_prefixes_token.py +++ b/bco_api/api/scripts/method_specific/POST_api_prefixes_token.py @@ -1,36 +1,35 @@ -# User utilities -from ..utilities import UserUtils - -# Responses -from rest_framework import status -from rest_framework.response import Response - - +#!/usr/bin/env python3 +"""Get Prefixes for a Token +Get all available prefixes and their associated permissions for a given token. +The word 'Token' must be included in the header. +The token has already been validated, +so the user is guaranteed to exist. -def POST_api_prefixes_token( - request -): - - # Instantiate any necessary imports. - uu = UserUtils.UserUtils() - - # The token has already been validated, - # so the user is guaranteed to exist. - - # A little expensive, but use the utility - # we already have. Default will return flattened list of permissions - prefixes = uu.prefix_perms_for_user( - user_object = uu.user_from_request( - rq = request - ).username, - flatten = False - ) +A little expensive, but use the utility +we already have. Default will return flattened list of permissions. +""" +from api.scripts.utilities import UserUtils +from rest_framework import status +from rest_framework.response import Response - return( - Response( - status = status.HTTP_200_OK, - data = prefixes - ) - ) \ No newline at end of file +def POST_api_prefixes_token(request): + """Get Prefixes for a Token + + Parameters + ---------- + request: rest_framework.request.Request + Django request object. + + Returns + ------- + rest_framework.response.Response + An HttpResponse that allows its data to be rendered into + arbitrary media types. + """ + + prefixes = UserUtils.UserUtils().prefix_perms_for_user( + user_object = UserUtils.UserUtils().user_from_request( + request = request).username, flatten = False) + return Response(status = status.HTTP_200_OK, data = prefixes) diff --git a/bco_api/api/scripts/method_specific/POST_api_prefixes_token_flat.py b/bco_api/api/scripts/method_specific/POST_api_prefixes_token_flat.py index f6953754..443c4e5d 100644 --- a/bco_api/api/scripts/method_specific/POST_api_prefixes_token_flat.py +++ b/bco_api/api/scripts/method_specific/POST_api_prefixes_token_flat.py @@ -1,38 +1,34 @@ -# User utilities -from ..utilities import UserUtils +#!/usr/bin/env python3 +"""Get Prefixes for a Token, flat list -# Responses +Get all available prefixes and their associated permissions for a given token. +The word 'Token' must be included in the header. The token has already been +validated, so the user is guaranteed to exist. + +A little expensive, but use the utility we already have. Default will return +flattened list of permissions. +""" +from api.scripts.utilities import UserUtils from rest_framework import status from rest_framework.response import Response +def POST_api_prefixes_token_flat(request): + """Get Prefixes for a Token + Parameters + ---------- + request: rest_framework.request.Request + Django request object. + Returns + ------- + rest_framework.response.Response + An HttpResponse that allows its data to be rendered into + arbitrary media types. + """ -def POST_api_prefixes_token_flat( - request -): - - # Instantiate any necessary imports. - uu = UserUtils.UserUtils() - - # The token has already been validated, - # so the user is guaranteed to exist. - - # A little expensive, but use the utility - # we already have. Default will return flattened list of permissions - prefixes = uu.prefix_perms_for_user( - user_object = uu.user_from_request( - rq = request - ).username, - flatten = True - ) - - # We only need the permissions that are specific - # to the bco model. + prefixes = UserUtils.UserUtils().prefix_perms_for_user( + user_object = UserUtils.UserUtils().user_from_request( + request = request).username,flatten = True) - return( - Response( - status = status.HTTP_200_OK, - data = prefixes - ) - ) \ No newline at end of file + return Response(status = status.HTTP_200_OK, data = prefixes) diff --git a/bco_api/api/views.py b/bco_api/api/views.py index d5a03b7d..4b9638be 100755 --- a/bco_api/api/views.py +++ b/bco_api/api/views.py @@ -1166,12 +1166,11 @@ def post(self, request) -> Response: class ApiPrefixesToken(APIView): """ - Get Prefixes for a Token + Get list of prefixes -------------------- - # Get all available prefixes and their associated permissions for a given token. - + 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'. @@ -1194,16 +1193,12 @@ def post(self, request) -> Response: class ApiPrefixesTokenFlat(APIView): """ - Get Prefixes for a Token in Flat Format + Get a flat list of prefixes -------------------- - # Get all available prefixes and their associated permissions for a given token in flat format. - - # TODO: What does this do? Appears to flatten the prefixes (not sure what for) - # Answer (Chris, 1/22): These may be easier for a requestor to parse rapidly on a web page. - - The word 'Token' must be included in the header. + Get all available prefixes and their associated permissions for a given + token in flat format. The word 'Token' must be included in the header. For example: 'Token 627626823549f787c3ec763ff687169206626149'. """