From 4c3d0c69a99cb01049fc5ea463322422e94fff40 Mon Sep 17 00:00:00 2001 From: rowan04 Date: Thu, 16 Jan 2025 12:55:11 +0000 Subject: [PATCH] Add patch endpoint for attachment metadata #27 --- object_storage_api/repositories/attachment.py | 25 +++++++++++++++++++ object_storage_api/routers/attachment.py | 20 ++++++++++++++- object_storage_api/schemas/attachment.py | 8 ++++++ object_storage_api/services/attachment.py | 20 +++++++++++++++ 4 files changed, 72 insertions(+), 1 deletion(-) diff --git a/object_storage_api/repositories/attachment.py b/object_storage_api/repositories/attachment.py index 4e53674..b257211 100644 --- a/object_storage_api/repositories/attachment.py +++ b/object_storage_api/repositories/attachment.py @@ -84,3 +84,28 @@ def list(self, entity_id: Optional[str], session: Optional[ClientSession] = None attachments = self._attachments_collection.find(query, session=session) return [AttachmentOut(**attachment) for attachment in attachments] + + def update(self, attachment_id: str, attachment: AttachmentIn, session: ClientSession = None) -> AttachmentOut: + """ + Updates an attachment by its ID in a MongoDB database. + + :param attachment_id: The ID of the attachment to update. + :param attachment: The attachment containing the update data. + :param session: PyMongo ClientSession to use for database operations. + :return: The updated attachment. + :raises InvalidObjectIdError: If the supplied `attachment_id` is invalid. + """ + + logger.info("Updating attachment metadata with ID: %s", attachment_id) + + try: + attachment_id = CustomObjectId(attachment_id) + self._attachments_collection.update_one( + {"_id": attachment_id}, {"$set": attachment.model_dump(by_alias=True)}, session=session + ) + except InvalidObjectIdError as exc: + exc.status_code = 404 + exc.response_detail = "Attachment not found" + raise exc + + return self.get(attachment_id=str(attachment_id), session=session) diff --git a/object_storage_api/routers/attachment.py b/object_storage_api/routers/attachment.py index 7caa908..11b286a 100644 --- a/object_storage_api/routers/attachment.py +++ b/object_storage_api/routers/attachment.py @@ -6,10 +6,11 @@ import logging from typing import Annotated, Optional -from fastapi import APIRouter, Depends, Query, status +from fastapi import APIRouter, Depends, Path, Query, status from object_storage_api.schemas.attachment import ( AttachmentMetadataSchema, + AttachmentPatchMetadataSchema, AttachmentPostResponseSchema, AttachmentPostSchema, ) @@ -55,3 +56,20 @@ def get_attachments( logger.debug("Entity ID filter: '%s'", entity_id) return attachment_service.list(entity_id) + + +@router.patch( + path="/{attachment_id}", + summary="Update an attachment partially by ID", + response_description="Attachment updated successfully", +) +def partial_update_attachment( + attachment: AttachmentPatchMetadataSchema, + attachment_id: Annotated[str, Path(description="ID of the attachment to update")], + attachment_service: AttachmentServiceDep, +) -> AttachmentMetadataSchema: + # pylint: disable=missing-function-docstring + logger.info("Partially updating attachment with ID: %s", attachment_id) + logger.debug("Attachment data: %s", attachment) + + return attachment_service.update(attachment_id, attachment) diff --git a/object_storage_api/schemas/attachment.py b/object_storage_api/schemas/attachment.py index 8302fcd..2fd412c 100644 --- a/object_storage_api/schemas/attachment.py +++ b/object_storage_api/schemas/attachment.py @@ -9,6 +9,14 @@ from object_storage_api.schemas.mixins import CreatedModifiedSchemaMixin +class AttachmentPatchMetadataSchema(BaseModel): + """Schema model for an attachment update request.""" + + title: Optional[str] = Field(default=None, description="Title of the attachment") + description: Optional[str] = Field(default=None, description="Description of the attachment") + file_name: Optional[str] = Field(default=None, description="File name of the attachment") + + class AttachmentPostSchema(BaseModel): """ Schema model for an attachment creation request. diff --git a/object_storage_api/services/attachment.py b/object_storage_api/services/attachment.py index 6883857..421b694 100644 --- a/object_storage_api/services/attachment.py +++ b/object_storage_api/services/attachment.py @@ -14,6 +14,7 @@ from object_storage_api.repositories.attachment import AttachmentRepo from object_storage_api.schemas.attachment import ( AttachmentMetadataSchema, + AttachmentPatchMetadataSchema, AttachmentPostResponseSchema, AttachmentPostSchema, ) @@ -78,3 +79,22 @@ def list(self, entity_id: Optional[str] = None) -> list[AttachmentMetadataSchema attachments = self._attachment_repository.list(entity_id) return [AttachmentMetadataSchema(**attachment.model_dump()) for attachment in attachments] + + def update(self, attachment_id: str, attachment: AttachmentPatchMetadataSchema) -> AttachmentMetadataSchema: + """ + Update an attachment by its ID. + + :param attachment_id: The ID of the attachment to update. + :param attachment: The attachment containing the fields to be updated. + :return: The updated attachment. + """ + + stored_attachment = self._attachment_repository.get(attachment_id=attachment_id) + update_data = attachment.model_dump(exclude_unset=True) + + updated_attachment = self._attachment_repository.update( + attachment_id=attachment_id, + attachment=AttachmentIn(**{**stored_attachment.model_dump(), **update_data}), + ) + + return AttachmentMetadataSchema(**updated_attachment.model_dump())