🏷️(backend) add content-type to uploaded files

All the uploaded files had the content-type set
to `application/octet-stream`. It create issues
when the file is downloaded from the frontend
because the browser doesn't know how to handle
the file.
We now determine the content-type of the file
and set it to the file object.
This commit is contained in:
Anthony LC
2025-01-15 15:58:46 +01:00
committed by Anthony LC
parent b8be010389
commit 5b4b100e90
6 changed files with 35 additions and 12 deletions

View File

@@ -388,6 +388,7 @@ class FileUploadSerializer(serializers.Serializer):
raise serializers.ValidationError("Could not determine file extension.")
self.context["expected_extension"] = extension
self.context["content_type"] = magic_mime_type
return file
@@ -395,6 +396,7 @@ class FileUploadSerializer(serializers.Serializer):
"""Override validate to add the computed extension to validated_data."""
attrs["expected_extension"] = self.context["expected_extension"]
attrs["is_unsafe"] = self.context["is_unsafe"]
attrs["content_type"] = self.context["content_type"]
return attrs

View File

@@ -605,7 +605,10 @@ class DocumentViewSet(
key = f"{document.key_base}/{ATTACHMENTS_FOLDER:s}/{file_id!s}.{extension:s}"
# Prepare metadata for storage
extra_args = {"Metadata": {"owner": str(request.user.id)}}
extra_args = {
"Metadata": {"owner": str(request.user.id)},
"ContentType": serializer.validated_data["content_type"],
}
if serializer.validated_data["is_unsafe"]:
extra_args["Metadata"]["is_unsafe"] = "true"

View File

@@ -64,12 +64,22 @@ def test_api_documents_attachment_upload_anonymous_success():
assert response.status_code == 201
pattern = re.compile(rf"^/media/{document.id!s}/attachments/(.*)\.png")
match = pattern.search(response.json()["file"])
file_path = response.json()["file"]
match = pattern.search(file_path)
file_id = match.group(1)
# Validate that file_id is a valid UUID
uuid.UUID(file_id)
# Now, check the metadata of the uploaded file
key = file_path.replace("/media", "")
file_head = default_storage.connection.meta.client.head_object(
Bucket=default_storage.bucket_name, Key=key
)
assert file_head["Metadata"] == {"owner": "None"}
assert file_head["ContentType"] == "image/png"
@pytest.mark.parametrize(
"reach, role",
@@ -206,6 +216,7 @@ def test_api_documents_attachment_upload_success(via, role, mock_user_teams):
Bucket=default_storage.bucket_name, Key=key
)
assert file_head["Metadata"] == {"owner": str(user.id)}
assert file_head["ContentType"] == "image/png"
def test_api_documents_attachment_upload_invalid(client):
@@ -247,16 +258,18 @@ def test_api_documents_attachment_upload_size_limit_exceeded(settings):
@pytest.mark.parametrize(
"name,content,extension",
"name,content,extension,content_type",
[
("test.exe", b"text", "exe"),
("test", b"text", "txt"),
("test.aaaaaa", b"test", "txt"),
("test.txt", PIXEL, "txt"),
("test.py", b"#!/usr/bin/python", "py"),
("test.exe", b"text", "exe", "text/plain"),
("test", b"text", "txt", "text/plain"),
("test.aaaaaa", b"test", "txt", "text/plain"),
("test.txt", PIXEL, "txt", "image/png"),
("test.py", b"#!/usr/bin/python", "py", "text/plain"),
],
)
def test_api_documents_attachment_upload_fix_extension(name, content, extension):
def test_api_documents_attachment_upload_fix_extension(
name, content, extension, content_type
):
"""
A file with no extension or a wrong extension is accepted and the extension
is corrected in storage.
@@ -287,6 +300,7 @@ def test_api_documents_attachment_upload_fix_extension(name, content, extension)
Bucket=default_storage.bucket_name, Key=key
)
assert file_head["Metadata"] == {"owner": str(user.id), "is_unsafe": "true"}
assert file_head["ContentType"] == content_type
def test_api_documents_attachment_upload_empty_file():
@@ -335,3 +349,4 @@ def test_api_documents_attachment_upload_unsafe():
Bucket=default_storage.bucket_name, Key=key
)
assert file_head["Metadata"] == {"owner": str(user.id), "is_unsafe": "true"}
assert file_head["ContentType"] == "application/octet-stream"