diff --git a/src/api/specs/WorkflowsAPI.yaml b/src/api/specs/WorkflowsAPI.yaml index 5aa52528..0efda5dc 100644 --- a/src/api/specs/WorkflowsAPI.yaml +++ b/src/api/specs/WorkflowsAPI.yaml @@ -199,6 +199,43 @@ paths: application/json: schema: $ref: '#/components/schemas/RespError' + delete: + tags: + - Groups + summary: Delete a group + description: Delete a group and all of the objects that belong to them + parameters: + - name: group_id + in: path + required: true + schema: + $ref: '#/components/schemas/ID' + operationId: deleteGroup + responses: + '200': + description: Delete group. + content: + application/json: + schema: + $ref: '#/components/schemas/RespString' + '401': + description: Not authorized. Invalid or Expired Token. + content: + application/json: + schema: + $ref: '#/components/schemas/RespError' + '403': + description: Cannot remove a user to this group. + content: + application/json: + schema: + $ref: '#/components/schemas/RespError' + '404': + description: Group does not exist. + content: + application/json: + schema: + $ref: '#/components/schemas/RespError' '/v3/workflows/groups/{group_id}/users': get: diff --git a/src/api/src/backend/views/Groups.py b/src/api/src/backend/views/Groups.py index a6e7b25e..803bb4d1 100644 --- a/src/api/src/backend/views/Groups.py +++ b/src/api/src/backend/views/Groups.py @@ -1,6 +1,5 @@ -import os - from django.forms import model_to_dict +from django.db import DatabaseError, IntegrityError, OperationalError from backend.views.RestrictedAPIView import RestrictedAPIView from backend.views.http.requests import GroupCreateRequest @@ -10,6 +9,7 @@ from backend.models import Group, GroupUser from backend.helpers import resource_url_builder from backend.services.GroupService import service as group_service +from backend.utils import logger # TODO Rollbacks on failture class Groups(RestrictedAPIView): @@ -50,22 +50,44 @@ def list(self, request): groups.append(user.group) return ModelListResponse(groups) + + def delete(self, request, group_id): + try: + # Get the group + group = group_service.get(group_id, request.tenant_id) + if group == None: + return NotFound(f"No group found with id '{group_id}'") + + if request.username != group.owner: + return Forbidden(message="Groups can only be delete by the group owner") + + group.delete() + + return BaseResponse(result=f"Group {group_id} successfully delete") + + except (DatabaseError, IntegrityError, OperationalError) as e: + logger.exception(e.__cause__) + return ServerError(message=e.__cause__) + except Exception as e: + logger.exception(str(e)) + return ServerError(str(e)) + def post(self, request, **_): - prepared_request = self.prepare(GroupCreateRequest) + try: + prepared_request = self.prepare(GroupCreateRequest) - if not prepared_request.is_valid: - return prepared_request.failure_view + if not prepared_request.is_valid: + return prepared_request.failure_view - body = prepared_request.body + body = prepared_request.body - # Check that id of the group is unique - exists = Group.objects.filter( - id=body.id, tenant_id=request.tenant_id).exists() - if exists: - return Conflict(f"A Group already exists with the id '{body.id}'") + # Check that id of the group is unique + exists = Group.objects.filter( + id=body.id, tenant_id=request.tenant_id).exists() + if exists: + return Conflict(f"A Group already exists with the id '{body.id}'") - try: # Save the Group object to the database group = Group.objects.create( id=body.id, owner=request.username, tenant_id=request.tenant_id) @@ -76,12 +98,10 @@ def post(self, request, **_): username=request.username, is_admin=True ) - except Exception as e: - return ServerError(message=str(e)) - # Create group users for each username passed in the request - for user in body.users: - try: + + # Create group users for each username passed in the request + for user in body.users: # Do not create a group user for the requesting user if user.username != request.username: GroupUser.objects.create( @@ -89,9 +109,14 @@ def post(self, request, **_): username=user.username, is_admin=user.is_admin ) - except Exception as e: - return BadRequest(message=str(e)) - return ResourceURLResponse( - url=resource_url_builder(request.url, group.id)) + return ResourceURLResponse( + url=resource_url_builder(request.url, group.id)) + + except (DatabaseError, IntegrityError, OperationalError) as e: + logger.exception(e.__cause__) + return ServerError(message=e.__cause__) + except Exception as e: + logger.exception(str(e)) + return ServerError(str(e)) \ No newline at end of file diff --git a/src/api/src/backend/views/http/responses/BaseResponse.py b/src/api/src/backend/views/http/responses/BaseResponse.py index d7637d5f..9031eae7 100644 --- a/src/api/src/backend/views/http/responses/BaseResponse.py +++ b/src/api/src/backend/views/http/responses/BaseResponse.py @@ -10,7 +10,7 @@ def __init__(self, status: int = 200, success: bool = True, message: str = "Success", - result: Union[dict, List[dict]] = None, + result: Union[dict, List[dict], str] = None, metadata: dict = {} ): # Conform to the tapis response object schema