Skip to content

Commit

Permalink
Merge branch 'model_refactor' into publish_draft
Browse files Browse the repository at this point in the history
  • Loading branch information
HadleyKing authored Apr 11, 2024
2 parents 9246ed6 + 407b18c commit b6971a6
Show file tree
Hide file tree
Showing 4 changed files with 13,422 additions and 0 deletions.
132 changes: 132 additions & 0 deletions biocompute/apis.py
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,138 @@ def post(self, request) -> Response:
status_code = response_status(accepted_requests, rejected_requests)
return Response(status=status_code, data=response_data)

class DraftsModifyApi(APIView):
"""Modify BCO Draft [Bulk Enabled]
API endpoint for modifying BioCompute Object (BCO) drafts, with support
for bulk operations.
This endpoint allows authenticated users to modify existing BCO drafts
individually or in bulk by submitting a list of BCO drafts. The operation
can be performed for one or more drafts in a single request. Each draft is
validated and processed independently, allowing for mixed response
statuses (HTTP_207_MULTI_STATUS) in the case of bulk submissions.
"""

permission_classes = [IsAuthenticated,]

@swagger_auto_schema(
operation_id="api_objects_drafts_modify",
request_body=openapi.Schema(
type=openapi.TYPE_ARRAY,
title="Modify BCO Draft Schema",
items=openapi.Schema(
type=openapi.TYPE_OBJECT,
required=[],
properties={
"authorized_users": openapi.Schema(
type=openapi.TYPE_ARRAY,
description="Users which can access the BCO draft.",
items=openapi.Schema(type=openapi.TYPE_STRING, example="tester")
),
"contents": openapi.Schema(
type=openapi.TYPE_OBJECT,
description="Contents of the BCO.",
example=BCO_000001
),
},
),
description="BCO Drafts to create.",
),
responses={
200: "All requests were accepted.",
207: "Some requests failed and some succeeded. Each object submitted"
" will have it's own response object with it's own status"
" code and message.\n",
400: "All requests were rejected.",
403: "Invalid token.",
},
tags=["BCO Management"],
)

def post(self, request) -> Response:
response_data = []
requester = request.user
data = request.data
rejected_requests = False
accepted_requests = False
if 'POST_api_objects_drafts_modify' in request.data:
data = legacy_api_converter(request.data)

for index, object in enumerate(data):
response_id = object.get("object_id", index)
modify_permitted = user_can_modify_bco(response_id, requester)

if modify_permitted is None:
response_data.append(response_constructor(
identifier=response_id,
status = "NOT FOUND",
code= 404,
message= f"Invalid BCO: {response_id}.",
))
rejected_requests = True
continue

if modify_permitted is False:
response_data.append(response_constructor(
identifier=response_id,
status = "FORBIDDEN",
code= 400,
message= f"User, {requester}, does not have draft permissions"\
+ f" for BCO {response_id}.",
))
rejected_requests = True
continue

bco = ModifyBcoDraftSerializer(data=object)

if bco.is_valid():
try:
bco.update(bco.validated_data)
response_data.append(response_constructor(
identifier=response_id,
status = "SUCCESS",
code= 200,
message= f"BCO {response_id} updated",
))
accepted_requests = True

except Exception as err:
response_data.append(response_constructor(
identifier=response_id,
status = "SERVER ERROR",
code= 500,
message= f"BCO {response_id} failed",
))

else:
response_data.append(response_constructor(
identifier=response_id,
status = "REJECTED",
code= 400,
message= f"BCO {response_id} rejected",
data=bco.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
)

class DraftRetrieveApi(APIView):
"""Get a draft object
Expand Down
1 change: 1 addition & 0 deletions biocompute/selectors.py
Original file line number Diff line number Diff line change
Expand Up @@ -246,3 +246,4 @@ def object_id_deconstructor(object_id=str) -> list:
deconstructed_object_id = object_id.split("/")
deconstructed_object_id.insert(0, object_id)
return deconstructed_object_id

73 changes: 73 additions & 0 deletions biocompute/services.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,78 @@ def update(self, validated_data):

return bco_instance

class ModifyBcoDraftSerializer(serializers.Serializer):
"""Serializer for modifying draft BioCompute Objects (BCO).
This serializer is used to validate and serialize data related to the
update of BCO drafts.
Attributes:
- contents (JSONField):
The contents of the BCO in JSON format.
- authorized_users (ListField):
A list of usernames authorized to access the BCO, besides the owner.
Methods:
- validate: Validates the incoming data for updating a BCO draft.
- update: Updates a BCO instance based on the validated data.
"""
contents = serializers.JSONField()
authorized_users = serializers.ListField(child=serializers.CharField(), required=False)

def validate(self, attrs):
"""BCO Modify Draft Validator
Parameters:
- attrs (dict):
The incoming data to be validated.
Returns:
- dict:
The validated data.
Raises:
- serializers.ValidationError: If any validation checks fail.
"""

errors = {}
request = self.context.get('request')

if 'authorized_users' in attrs:
for user in attrs['authorized_users']:
try:
User.objects.get(username=user)
except Exception as err:
errors['authorized_users'] =f"Invalid user: {user}"

if errors:
raise serializers.ValidationError(errors)

return attrs

@transaction.atomic
def update(self, validated_data):
"""
"""

authorized_usernames = validated_data.pop('authorized_users', [])
bco_instance = Bco.objects.get(
object_id = validated_data['contents']['object_id']
)
bco_instance.contents = validated_data['contents']
bco_instance.last_update=timezone.now()
bco_contents = deepcopy(bco_instance.contents)
etag = generate_etag(bco_contents)
bco_instance.contents['etag'] = etag
bco_instance.save()
if authorized_usernames:
authorized_users = User.objects.filter(
username__in=authorized_usernames
)
bco_instance.authorized_users.set(authorized_users)

return bco_instance

class BcoDraftSerializer(serializers.Serializer):
"""Serializer for drafting BioCompute Objects (BCO).
Expand Down Expand Up @@ -509,3 +581,4 @@ def delete_draft(bco_instance:Bco, user:User,):
bco_instance.save()

return "deleted"

Loading

0 comments on commit b6971a6

Please sign in to comment.