mirror of
https://github.com/ramvignesh-b/pi-ku.git
synced 2026-05-04 08:56:52 +00:00
feat: add PUT endpoint to update letters and manage associated images
This commit is contained in:
@@ -30,7 +30,7 @@ class LetterSerializer(serializers.ModelSerializer):
|
|||||||
"updated_at",
|
"updated_at",
|
||||||
"images",
|
"images",
|
||||||
] # user to be fetched from request
|
] # user to be fetched from request
|
||||||
read_only_fields = ["created_at", "updated_at"]
|
read_only_fields = ["public_id", "created_at", "updated_at"]
|
||||||
|
|
||||||
def validate(self, data):
|
def validate(self, data):
|
||||||
if (data.get("encrypted_content") or data.get("encrypted_metadata")) and not data.get("encrypted_dek"):
|
if (data.get("encrypted_content") or data.get("encrypted_metadata")) and not data.get("encrypted_dek"):
|
||||||
|
|||||||
@@ -68,6 +68,34 @@ class LetterAPITest(APITestCase):
|
|||||||
self.assertEqual(Letter.objects.get().type, "KEPT")
|
self.assertEqual(Letter.objects.get().type, "KEPT")
|
||||||
self.assertEqual(Letter.objects.get().user, self.user)
|
self.assertEqual(Letter.objects.get().user, self.user)
|
||||||
|
|
||||||
|
def test_update_draft_letter_with_public_id(self):
|
||||||
|
"""Test API can successfully update an existing letter with new values."""
|
||||||
|
letter = Letter.objects.create(
|
||||||
|
user=self.user,
|
||||||
|
type="KEPT",
|
||||||
|
status="DRAFT",
|
||||||
|
public_id="4281edcc-5459-4ff2-bb5e-669fb44e0757",
|
||||||
|
encrypted_content="enc_xyz==",
|
||||||
|
encrypted_metadata="enc_meta==",
|
||||||
|
encrypted_dek="enc_dek==",
|
||||||
|
)
|
||||||
|
payload = {
|
||||||
|
"public_id": letter.public_id,
|
||||||
|
"type": "KEPT",
|
||||||
|
"encrypted_content": "enc_abc==",
|
||||||
|
"encrypted_metadata": "enc_meta==",
|
||||||
|
"encrypted_dek": "enc_dek==",
|
||||||
|
}
|
||||||
|
response = self.client.put(self.url + letter.public_id + "/", payload)
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertEqual(Letter.objects.count(), 1)
|
||||||
|
self.assertEqual(Letter.objects.get().status, "DRAFT")
|
||||||
|
self.assertEqual(Letter.objects.get().type, "KEPT")
|
||||||
|
self.assertEqual(Letter.objects.get().user, self.user)
|
||||||
|
self.assertEqual(Letter.objects.get().encrypted_content, "enc_abc==")
|
||||||
|
self.assertEqual(Letter.objects.get().encrypted_metadata, "enc_meta==")
|
||||||
|
self.assertEqual(Letter.objects.get().encrypted_dek, "enc_dek==")
|
||||||
|
|
||||||
def test_encrypted_dek_is_required_when_storing_encrypted_content_and_metadata(self):
|
def test_encrypted_dek_is_required_when_storing_encrypted_content_and_metadata(self):
|
||||||
"""encrypted_dek is required when encrypted_content and encrypted_metadata are present"""
|
"""encrypted_dek is required when encrypted_content and encrypted_metadata are present"""
|
||||||
payload = {"type": "KEPT", "encrypted_content": "enc_xyz==", "encrypted_metadata": "enc_meta=="}
|
payload = {"type": "KEPT", "encrypted_content": "enc_xyz==", "encrypted_metadata": "enc_meta=="}
|
||||||
@@ -88,6 +116,7 @@ class LetterAPITest(APITestCase):
|
|||||||
image2 = SimpleUploadedFile("enc_img2.bin", b"encrypted_bytes_2", content_type="application/octet-stream")
|
image2 = SimpleUploadedFile("enc_img2.bin", b"encrypted_bytes_2", content_type="application/octet-stream")
|
||||||
|
|
||||||
payload = {
|
payload = {
|
||||||
|
"public_id": "4281edcc-5459-4ff2-bb5e-669fb44e0757",
|
||||||
"type": "SENT",
|
"type": "SENT",
|
||||||
"status": "SEALED",
|
"status": "SEALED",
|
||||||
"encrypted_content": "enc_content==",
|
"encrypted_content": "enc_content==",
|
||||||
@@ -96,12 +125,31 @@ class LetterAPITest(APITestCase):
|
|||||||
"image_files": [image1, image2],
|
"image_files": [image1, image2],
|
||||||
}
|
}
|
||||||
|
|
||||||
response = self.client.post(self.url, payload, format="multipart")
|
response = self.client.put(self.url + payload["public_id"] + "/", payload, format="multipart")
|
||||||
|
|
||||||
self.assertEqual(response.status_code, 201)
|
self.assertEqual(response.status_code, 201)
|
||||||
self.assertEqual(Letter.objects.count(), 1)
|
self.assertEqual(Letter.objects.count(), 1)
|
||||||
self.assertEqual(LetterImage.objects.count(), 2)
|
self.assertEqual(LetterImage.objects.count(), 2)
|
||||||
|
|
||||||
|
def test_cleanup_images_when_letter_is_updated(self):
|
||||||
|
letter = Letter.objects.create(user=self.user, type="KEPT", status="DRAFT")
|
||||||
|
LetterImage.objects.create(letter=letter, file_name="old1.bin", file=ContentFile(b"data", name="del.bin"))
|
||||||
|
LetterImage.objects.create(letter=letter, file_name="old2.bin", file=ContentFile(b"data", name="del.bin"))
|
||||||
|
|
||||||
|
response = self.client.put(
|
||||||
|
f"/api/letters/{letter.public_id}/",
|
||||||
|
data={
|
||||||
|
"encrypted_content": "new_enc==",
|
||||||
|
"encrypted_metadata": "new_meta==",
|
||||||
|
"encrypted_dek": "new_dek==",
|
||||||
|
"image_files": [ContentFile(b"data", name="new.bin")],
|
||||||
|
},
|
||||||
|
format="multipart",
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertEqual(LetterImage.objects.count(), 1)
|
||||||
|
|
||||||
|
|
||||||
class LetterImageModelTest(TestCase):
|
class LetterImageModelTest(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
|||||||
@@ -4,4 +4,5 @@ from .views import LetterView
|
|||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("", LetterView.as_view(), name="letter-list-create"),
|
path("", LetterView.as_view(), name="letter-list-create"),
|
||||||
|
path("<str:public_id>/", LetterView.as_view(), name="letter-create-retrieve-update-delete"),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
from rest_framework import generics
|
from rest_framework import generics
|
||||||
from rest_framework.permissions import IsAuthenticated
|
from rest_framework.permissions import IsAuthenticated
|
||||||
|
from rest_framework.response import Response
|
||||||
|
|
||||||
from letters.models import Letter, LetterImage
|
from letters.models import Letter, LetterImage
|
||||||
from letters.serializers import LetterSerializer
|
from letters.serializers import LetterSerializer
|
||||||
@@ -14,8 +15,16 @@ class LetterView(generics.ListCreateAPIView):
|
|||||||
"""return only letters of the authenticated user"""
|
"""return only letters of the authenticated user"""
|
||||||
return Letter.objects.filter(user=self.request.user)
|
return Letter.objects.filter(user=self.request.user)
|
||||||
|
|
||||||
def perform_create(self, serializer):
|
def put(self, request, public_id):
|
||||||
letter = serializer.save(user=self.request.user)
|
serializer = self.get_serializer(data=request.data)
|
||||||
image_files = self.request.FILES.getlist("image_files")
|
serializer.is_valid(raise_exception=True)
|
||||||
for image_file in image_files:
|
|
||||||
|
letter, created = Letter.objects.update_or_create(
|
||||||
|
public_id=public_id, user=request.user, defaults=serializer.validated_data
|
||||||
|
)
|
||||||
|
|
||||||
|
LetterImage.objects.filter(letter=letter).delete()
|
||||||
|
for image_file in request.FILES.getlist("image_files"):
|
||||||
LetterImage.objects.create(letter=letter, file=image_file, file_name=image_file.name)
|
LetterImage.objects.create(letter=letter, file=image_file, file_name=image_file.name)
|
||||||
|
|
||||||
|
return Response(serializer.data, status=201 if created else 200)
|
||||||
|
|||||||
Reference in New Issue
Block a user