diff --git a/CHANGELOG.md b/CHANGELOG.md index 84936edb9..4d8778ab5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -95,3 +95,4 @@ Please add a _short_ line describing the PR you make, if the PR implements a spe - Bug: Check for timestamp `0000-00-00 00:00:00` added and invite deleted ([#1163](https://github.com/ScilifelabDataCentre/dds_web/pull/1163)) - Add documentation of status codes in `api/project.py` ([#1164](https://github.com/ScilifelabDataCentre/dds_web/pull/1164)) - Add ability to switch to using TOTP and back to HOTP for MFA ([#936](https://github.com/scilifelabdatacentre/dds_web/issues/936)) +- Bug: Do not remove the bucket when emptying the project ([#1172](https://github.com/ScilifelabDataCentre/dds_web/pull/1172)) diff --git a/dds_web/api/api_s3_connector.py b/dds_web/api/api_s3_connector.py index 08400bcde..af7dbe99a 100644 --- a/dds_web/api/api_s3_connector.py +++ b/dds_web/api/api_s3_connector.py @@ -72,16 +72,18 @@ def get_s3_info(self): ) @bucket_must_exists - def remove_bucket(self, *args, **kwargs): - """Removes all contents from the project specific s3 bucket.""" + def remove_bucket_contents(self, delete_bucket=False, *_, **__): + """Removed all contents within a project specific s3 bucket.""" # Get bucket object bucket = self.resource.Bucket(self.project.bucket) # Delete objects first bucket.objects.all().delete() - # Delete bucket - bucket.delete() + # Delete bucket if chosen + if delete_bucket: + bucket.delete() + bucket = None @bucket_must_exists diff --git a/dds_web/api/project.py b/dds_web/api/project.py index 5a09dc5a1..7a1aac301 100644 --- a/dds_web/api/project.py +++ b/dds_web/api/project.py @@ -281,7 +281,7 @@ def delete_project(self, project: models.Project, current_time: datetime.datetim try: # Deletes files (also commits session in the function - possibly refactor later) - RemoveContents().delete_project_contents(project=project) + RemoveContents().delete_project_contents(project=project, delete_bucket=True) self.rm_project_user_keys(project=project) # Delete metadata from project row @@ -319,7 +319,7 @@ def archive_project( try: # Deletes files (also commits session in the function - possibly refactor later) - RemoveContents().delete_project_contents(project=project) + RemoveContents().delete_project_contents(project=project, delete_bucket=True) delete_message = f"\nAll files in {project.public_id} deleted" self.rm_project_user_keys(project=project) @@ -545,12 +545,12 @@ def delete(self): return {"removed": True} @staticmethod - def delete_project_contents(project): + def delete_project_contents(project, delete_bucket=False): """Remove project contents""" # Delete from cloud with ApiS3Connector(project=project) as s3conn: try: - s3conn.remove_bucket() + s3conn.remove_bucket_contents(delete_bucket=delete_bucket) except botocore.client.ClientError as err: raise DeletionError(message=str(err), project=project.public_id) from err diff --git a/tests/test_files_new.py b/tests/test_files_new.py index c3003f8de..806f6f67a 100644 --- a/tests/test_files_new.py +++ b/tests/test_files_new.py @@ -847,3 +847,72 @@ def test_new_file_wrong_status(client): assert response.status_code == http.HTTPStatus.BAD_REQUEST assert "Project not in right status to upload/modify files" in response.json.get("message") + + +def test_delete_contents_and_upload_again(client, boto3_session): + """Upload and then delete all project contents""" + + project_1 = project_row(project_id="file_testing_project") + assert project_1 + assert project_1.current_status == "In Progress" + + a_completely_new_file = FIRST_NEW_FILE.copy() + a_completely_new_file["name"] = "a_completely_new_file" + a_completely_new_file["name_in_bucket"] = "a_completely_new_file" + + # Check that files have been added to db + file_in_db = ( + db.session.query(models.File) + .filter(models.File.name == a_completely_new_file["name"]) + .first() + ) + assert not file_in_db + + # Create new file in db + response = client.post( + tests.DDSEndpoint.FILE_NEW, + headers=tests.UserAuth(tests.USER_CREDENTIALS["unitadmin"]).token(client), + query_string={"project": "file_testing_project"}, + json=a_completely_new_file, + ) + + # Check that files have been added to db + assert response.status_code == http.HTTPStatus.OK + file_in_db = ( + db.session.query(models.File) + .filter(models.File.name == a_completely_new_file["name"]) + .first() + ) + assert file_in_db + + # Try to remove all contents on empty project + response = client.delete( + tests.DDSEndpoint.REMOVE_PROJ_CONT, + headers=tests.UserAuth(tests.USER_CREDENTIALS["unitadmin"]).token(client), + query_string={"project": "file_testing_project"}, + ) + + assert response.status_code == http.HTTPStatus.OK + file_in_db = ( + db.session.query(models.File) + .filter(models.File.name == a_completely_new_file["name"]) + .first() + ) + assert not file_in_db + + # Create new file in db + response = client.post( + tests.DDSEndpoint.FILE_NEW, + headers=tests.UserAuth(tests.USER_CREDENTIALS["unitadmin"]).token(client), + query_string={"project": "file_testing_project"}, + json=a_completely_new_file, + ) + + # Check that files have been added to db + assert response.status_code == http.HTTPStatus.OK + file_in_db = ( + db.session.query(models.File) + .filter(models.File.name == a_completely_new_file["name"]) + .first() + ) + assert file_in_db