Skip to content

Commit

Permalink
Implement delete attachment action (#94)
Browse files Browse the repository at this point in the history
  • Loading branch information
4c0n authored Oct 25, 2024
1 parent 2afc9f2 commit f63cc45
Show file tree
Hide file tree
Showing 2 changed files with 126 additions and 2 deletions.
33 changes: 33 additions & 0 deletions meldingen_core/actions/attachment.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,3 +117,36 @@ async def __call__(self, melding_id: int, token: str) -> Collection[A_co]:
await self._verify_token(melding_id, token)

return await self._attachment_repository.find_by_melding(melding_id)


class DeleteAttachmentAction(Generic[A, A_co, M, M_co]):
_verify_token: TokenVerifier[M, M_co]
_attachment_repository: BaseAttachmentRepository[A, A_co]
_filesystem: Filesystem

def __init__(
self,
token_verifier: TokenVerifier[M, M_co],
attachment_repository: BaseAttachmentRepository[A, A_co],
filesystem: Filesystem,
):
self._verify_token = token_verifier
self._attachment_repository = attachment_repository
self._filesystem = filesystem

async def __call__(self, melding_id: int, attachment_id: int, token: str) -> None:
melding = await self._verify_token(melding_id, token)

attachment = await self._attachment_repository.retrieve(attachment_id)
if attachment is None:
raise NotFoundException("Attachment not found")

if attachment.melding != melding:
raise NotFoundException(f"Melding with id {melding_id} does not have attachment with id {attachment_id}")

try:
await self._filesystem.delete(attachment.file_path)
except filesystem.NotFoundException as exception:
raise NotFoundException("File not found") from exception

await self._attachment_repository.delete(attachment_id)
95 changes: 93 additions & 2 deletions tests/test_actions/test_attachment.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@
from plugfs import filesystem
from plugfs.filesystem import File, Filesystem

from meldingen_core.actions.attachment import DownloadAttachmentAction, ListAttachmentsAction, UploadAttachmentAction
from meldingen_core.actions.attachment import (
DeleteAttachmentAction,
DownloadAttachmentAction,
ListAttachmentsAction,
UploadAttachmentAction,
)
from meldingen_core.exceptions import NotFoundException
from meldingen_core.factories import BaseAttachmentFactory
from meldingen_core.models import Attachment, Melding
Expand Down Expand Up @@ -68,7 +73,6 @@ async def test_attachment_not_found(self) -> None:

@pytest.mark.anyio
async def test_attachment_does_not_belong_to_melding(self) -> None:
melding = Melding(text="text")
attachment = Attachment("bla", Melding(text="some text"))

attachment_repository = Mock(BaseAttachmentRepository)
Expand Down Expand Up @@ -153,3 +157,90 @@ async def test_can_list_attachments(self) -> None:
assert repo_attachments == attachments
token_verifier.assert_awaited_once()
repository.find_by_melding.assert_awaited_once_with(melding_id)


class TestDeleteAttachmentAction:
@pytest.mark.anyio
async def test_attachment_not_found(self) -> None:
attachment_repository = Mock(BaseAttachmentRepository)
attachment_repository.retrieve.return_value = None

action: DeleteAttachmentAction[Attachment, Attachment, Melding, Melding] = DeleteAttachmentAction(
AsyncMock(TokenVerifier),
attachment_repository,
Mock(Filesystem),
)

with pytest.raises(NotFoundException) as exception_info:
await action(123, 456, "supersecrettoken")

assert str(exception_info.value) == "Attachment not found"

@pytest.mark.anyio
async def test_attachment_does_not_belong_to_melding(self) -> None:
attachment = Attachment("bla", Melding(text="some text"))

attachment_repository = Mock(BaseAttachmentRepository)
attachment_repository.retrieve.return_value = attachment

action: DeleteAttachmentAction[Attachment, Attachment, Melding, Melding] = DeleteAttachmentAction(
AsyncMock(TokenVerifier),
attachment_repository,
Mock(Filesystem),
)

with pytest.raises(NotFoundException) as exception_info:
await action(123, 456, "supersecrettoken")

assert str(exception_info.value) == "Melding with id 123 does not have attachment with id 456"

@pytest.mark.anyio
async def test_file_not_found(self) -> None:
melding = Melding(text="text")
token_verifier = AsyncMock(TokenVerifier)
token_verifier.return_value = melding

attachment = Attachment("bla", melding)
attachment.file_path = "/path/to/file.ext"

attachment_repository = Mock(BaseAttachmentRepository)
attachment_repository.retrieve.return_value = attachment

filesystem_mock = Mock(Filesystem)
filesystem_mock.delete.side_effect = filesystem.NotFoundException

action: DeleteAttachmentAction[Attachment, Attachment, Melding, Melding] = DeleteAttachmentAction(
token_verifier,
attachment_repository,
filesystem_mock,
)

with pytest.raises(NotFoundException) as exception_info:
await action(123, 456, "supersecrettoken")

assert str(exception_info.value) == "File not found"

@pytest.mark.anyio
async def test_delete_attachment(self) -> None:
melding = Melding(text="text")
token_verifier = AsyncMock(TokenVerifier)
token_verifier.return_value = melding

attachment = Attachment("bla", melding)
attachment.file_path = "/path/to/file.ext"

attachment_repository = Mock(BaseAttachmentRepository)
attachment_repository.retrieve.return_value = attachment

filesystem_mock = Mock(Filesystem)

action: DeleteAttachmentAction[Attachment, Attachment, Melding, Melding] = DeleteAttachmentAction(
token_verifier,
attachment_repository,
filesystem_mock,
)

await action(123, 456, "supersecrettoken")

filesystem_mock.delete.assert_awaited_once_with(attachment.file_path)
attachment_repository.delete.assert_awaited_once_with(456)

0 comments on commit f63cc45

Please sign in to comment.