diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d0d2f2..ddf1317 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +# [0.12.0](https://github.com/hawks-atlanta/proxy-python/compare/v0.11.0...v0.12.0) (2023-10-20) + + +### Features + +* move a file ([#68](https://github.com/hawks-atlanta/proxy-python/issues/68)) ([b0a585c](https://github.com/hawks-atlanta/proxy-python/commit/b0a585c89c8ae09a49fa0549858d73f51ea6976a)) + + + # [0.11.0](https://github.com/hawks-atlanta/proxy-python/compare/v0.10.0...v0.11.0) (2023-10-15) @@ -35,12 +44,3 @@ -## [0.8.1](https://github.com/hawks-atlanta/proxy-python/compare/v0.8.0...v0.8.1) (2023-10-14) - - -### Bug Fixes - -* **files:** Keep files extension ([#56](https://github.com/hawks-atlanta/proxy-python/issues/56)) ([624cc06](https://github.com/hawks-atlanta/proxy-python/commit/624cc06af6443602bc9b946c8fc7ee5376dbea2c)) - - - diff --git a/docs/spec.openapi.yaml b/docs/spec.openapi.yaml index 76e6b11..7514d5b 100644 --- a/docs/spec.openapi.yaml +++ b/docs/spec.openapi.yaml @@ -495,7 +495,7 @@ paths: schema: $ref: "#/components/schemas/statusResponse" - /file/shared-with-who: + /file/{fileUUID}/shared-with-who: get: tags: - Files diff --git a/src/controllers/files/__init__.py b/src/controllers/files/__init__.py index 2e94621..70f4c83 100644 --- a/src/controllers/files/__init__.py +++ b/src/controllers/files/__init__.py @@ -6,6 +6,7 @@ from .list_files._handler import list_files_handler from .download_file._handler import download_file_handler from .share_file._handler import share_handler +from .move_a_file._handler import file_move_handler FILES_HANDLERS = { "CHECK_STATE": check_state_handler, @@ -16,4 +17,5 @@ "FILE_LIST": list_files_handler, "DOWNLOAD_FILE": download_file_handler, "SHARE": share_handler, + "MOVE_FILE": file_move_handler, } diff --git a/src/controllers/files/move_a_file/_handler.py b/src/controllers/files/move_a_file/_handler.py new file mode 100644 index 0000000..39bd376 --- /dev/null +++ b/src/controllers/files/move_a_file/_handler.py @@ -0,0 +1,36 @@ +import json +from flask import request +from src.config.soap_client import soap_client +from src.lib.helpers import is_valid_uuid + + +def file_move_handler(token, file_uuid): + try: + data = json.loads(request.data) + target_directory_uuid = data.get("targetDirectoryUUID") + + not_valid_target_directory = not target_directory_uuid or not is_valid_uuid( + target_directory_uuid + ) + if not_valid_target_directory: + return {"msg": "The target directory is not valid or was not provided"}, 400 + + request_data = { + "token": token, + "fileUUID": file_uuid, + "targetDirectoryUUID": target_directory_uuid, + } + + response = soap_client.service.file_move(request_data) + + if response["error"] is True: + return {"msg": response["msg"]}, response["code"] + else: + return {"msg": "The file has been moved"}, 200 + + except ValueError: + return {"msg": "Not valid JSON data provided in the request"}, 400 + + except Exception as e: + print("[Exception] file_move_handler ->", e) + return {"msg": "There was an error moving the file"}, 500 diff --git a/src/controllers/files/move_a_file/_move_file_test.py b/src/controllers/files/move_a_file/_move_file_test.py new file mode 100644 index 0000000..b8ad768 --- /dev/null +++ b/src/controllers/files/move_a_file/_move_file_test.py @@ -0,0 +1,133 @@ +import json +from random import randbytes +from uuid import uuid4 + +from main import app +from src.config.soap_client import soap_client +from src.lib.faker import fake_username, fake_password + +# MOVE FILE TESTS +move_file_test_data = { + "username": fake_username(), + "password": fake_password(), + "file": { + "uuid": None, + "targetDirectoryUUID": None, + "name": "test.txt", + "content": randbytes(1024), + }, +} + + +def test_move_file_success(): + # Register a user + register_response = soap_client.service.account_register( + { + "username": move_file_test_data["username"], + "password": move_file_test_data["password"], + } + ) + assert register_response.error is False + + # Login with the user + login_response = soap_client.service.auth_login( + { + "username": move_file_test_data["username"], + "password": move_file_test_data["password"], + } + ) + assert login_response.error is False + token = login_response.auth.token + + # Create a new directory + new_directory_name = "test_directory" + create_dir_response = soap_client.service.file_new_dir( + { + "directoryName": new_directory_name, + "location": None, + "token": token, + } + ) + assert create_dir_response["code"] == 201 + directory_uuid = create_dir_response["fileUUID"] + move_file_test_data["file"]["targetDirectoryUUID"] = directory_uuid + + # Upload a file + create_file_response = soap_client.service.file_upload( + { + "token": token, + "fileName": move_file_test_data["file"]["name"], + "fileContent": move_file_test_data["file"]["content"], + "location": None, + } + ) + assert create_file_response.error is False + move_file_test_data["file"]["uuid"] = create_file_response.fileUUID + + # Move the file to the target directory + response = app.test_client().patch( + f"/file/{move_file_test_data['file']['uuid']}/move", + json={"targetDirectoryUUID": directory_uuid}, + headers={"Authorization": f"Bearer {token}"}, + ) + + json_response = json.loads(response.data) + assert response.status_code == 200 + assert json_response["msg"].startswith("The file has been moved") + + +def test_move_file_bad_request(): + # Login with the user + login_response = soap_client.service.auth_login( + { + "username": move_file_test_data["username"], + "password": move_file_test_data["password"], + } + ) + assert login_response.error is False + token = login_response.auth.token + + # Missing JSON data + response = app.test_client().patch( + f"/file/{move_file_test_data['file']['uuid']}/move", + headers={"Authorization": f"Bearer {token}"}, + ) + assert response.status_code == 400 + + # Not valid target directory UUID + response = app.test_client().patch( + f"/file/{move_file_test_data['file']['uuid']}/move", + json={"targetDirectoryUUID": "not_valid_uuid"}, + headers={"Authorization": f"Bearer {token}"}, + ) + assert response.status_code == 400 + + # Non existent file UUID + response = app.test_client().patch( + f"/file/{uuid4()}/move", + json={"targetDirectoryUUID": uuid4()}, + headers={"Authorization": f"Bearer {token}"}, + ) + assert response.status_code == 404 + + +def test_move_file_conflict(): + # Login with the user + login_response = soap_client.service.auth_login( + { + "username": move_file_test_data["username"], + "password": move_file_test_data["password"], + } + ) + assert login_response.error is False + token = login_response.auth.token + + # Try to move the file to the same directory + response = app.test_client().patch( + f"/file/{move_file_test_data['file']['uuid']}/move", + json={ + "targetDirectoryUUID": move_file_test_data["file"]["targetDirectoryUUID"] + }, + headers={"Authorization": f"Bearer {token}"}, + ) + assert response.status_code == 409 diff --git a/src/controllers/files/remove_file/_handler.py b/src/controllers/files/remove_file/_handler.py new file mode 100644 index 0000000..a404276 --- /dev/null +++ b/src/controllers/files/remove_file/_handler.py @@ -0,0 +1,16 @@ +from src.config.soap_client import soap_client + + +def remove_file_handler(token, file_uuid): + try: + request_data = {"fileUUID": file_uuid, "token": token} + response = soap_client.service.file_delete(request_data) + + if response["error"] is True: + return {"msg": response["msg"]}, response["code"] + else: + return {"msg": "File successfully deleted"}, 200 + + except Exception as e: + print("[Exception] remove_file_handler ->", e) + return {"msg": "There was an error deleting the file"}, 500 diff --git a/src/controllers/files/remove_file/_remove_file_test.py b/src/controllers/files/remove_file/_remove_file_test.py new file mode 100644 index 0000000..e69de29 diff --git a/src/controllers/files/shared_file/_handler.py b/src/controllers/files/shared_file/_handler.py new file mode 100644 index 0000000..c22716f --- /dev/null +++ b/src/controllers/files/shared_file/_handler.py @@ -0,0 +1,30 @@ +from src.config.soap_client import soap_client + + +def shared_files_handler(token): + try: + request_data = {"token": token} + response = soap_client.service.share_list(request_data) + + if response["error"] is True: + return {"msg": response["msg"]}, response["code"] + + files = [ + { + "name": file.name, + "size": file.size, + "isFile": file.isFile, + "extension": file.extension, + "uuid": file.uuid, + "ownerusername": file.ownerusername, + } + for file in response.files + ] + + return { + "files": files, + "msg": "List of shared files obtained", + }, 200 + except Exception as e: + print("[Exception] shared_files_handler ->", e) + return {"msg": "There was an error listing the shared files"}, 500 diff --git a/src/controllers/files/shared_with_who/_handler.py b/src/controllers/files/shared_with_who/_handler.py new file mode 100644 index 0000000..f4780ea --- /dev/null +++ b/src/controllers/files/shared_with_who/_handler.py @@ -0,0 +1,29 @@ +from src.config.soap_client import soap_client +from src.lib.helpers import is_valid_uuid + + +def shared_with_who_handler(token, file_uuid): + try: + if not is_valid_uuid(file_uuid): + return {"msg": "Not valid file UUID provided"}, 400 + + request_data = {"fileUUID": file_uuid, "token": token} + response = soap_client.service.share_list_with_who(request_data) + + if response.usernames is None: + return {"msg": response["msg"]}, response["code"] + + usernames = [ + { + "users": usernames, + } + for usernames in response.usernames + ] + + return { + "users": usernames, + "msg": "List of users the file is shared with", + }, 200 + except Exception as e: + print("[Exception] shared_with_who_handler ->", e) + return {"msg": "There was an error listing the shared with"}, 500 diff --git a/src/controllers/files/unshare_file/_handler.py b/src/controllers/files/unshare_file/_handler.py new file mode 100644 index 0000000..55b225b --- /dev/null +++ b/src/controllers/files/unshare_file/_handler.py @@ -0,0 +1,39 @@ +import json +from flask import request +from src.config.soap_client import soap_client +from src.lib.helpers import is_valid_uuid + + +def unshare_handler(token): + try: + data = json.loads(request.data) + fileUUID = data["fileUUID"] + otherUsername = data["otherUsername"] + + # Check if required fields are empty + empty_file_uuid = not fileUUID or len(fileUUID) == 0 + empty_other_username = not otherUsername or len(otherUsername) == 0 + if empty_file_uuid or empty_other_username: + return {"msg": "Required fields are missing in form data"}, 400 + + # Check if file UUID is valid + if not is_valid_uuid(fileUUID): + return {"msg": "Not valid file UUID provided"}, 400 + + request_data = { + "fileUUID": fileUUID, + "otherUsername": otherUsername, + "token": token, + } + response = soap_client.service.unshare_file(request_data) + + if response["error"] is True: + return {"msg": response["msg"]}, response["code"] + else: + return {"msg": "File unshared successfully"}, 200 + + except ValueError: + return {"msg": "Invalid JSON data provided in the request"}, 400 + + except Exception: + return {"msg": "There was an error unsharing the file"}, 500 diff --git a/src/controllers/files/unshare_file/_unshare_file_test.py b/src/controllers/files/unshare_file/_unshare_file_test.py new file mode 100644 index 0000000..e69de29 diff --git a/src/views/_file_views.py b/src/views/_file_views.py index de8bb99..8adbd56 100644 --- a/src/views/_file_views.py +++ b/src/views/_file_views.py @@ -52,3 +52,9 @@ def file_download(token, file_uuid): @auth_middlewares.token_required def file_share(token): return FILES_HANDLERS["SHARE"](token) + + +@views.route("/file//move", methods=["PATCH"]) +@auth_middlewares.token_required +def move_file(token, file_uuid): + return FILES_HANDLERS["MOVE_FILE"](token, file_uuid) diff --git a/version.json b/version.json index 2cd0808..239eb2a 100644 --- a/version.json +++ b/version.json @@ -1,3 +1,3 @@ { - "version": "0.11.0" + "version": "0.12.0" } \ No newline at end of file