upload: Stop requiring callers pass in the file size.

This can be calculated because we have the contents.
This commit is contained in:
Alex Vandiver 2024-06-20 17:52:55 +00:00 committed by Tim Abbott
parent 58a9fe9af1
commit f52a93bc14
12 changed files with 25 additions and 59 deletions

View File

@ -1,4 +1,3 @@
import os
from datetime import timedelta from datetime import timedelta
from typing import Any, Dict, List, Mapping, Type, Union from typing import Any, Dict, List, Mapping, Type, Union
@ -145,10 +144,8 @@ class Command(ZulipBaseCommand):
# Create an attachment in the database for set_storage_space_used_statistic. # Create an attachment in the database for set_storage_space_used_statistic.
IMAGE_FILE_PATH = static_path("images/test-images/checkbox.png") IMAGE_FILE_PATH = static_path("images/test-images/checkbox.png")
file_info = os.stat(IMAGE_FILE_PATH)
file_size = file_info.st_size
with open(IMAGE_FILE_PATH, "rb") as fp: with open(IMAGE_FILE_PATH, "rb") as fp:
upload_message_attachment_from_request(UploadedFile(fp), shylock, file_size) upload_message_attachment_from_request(UploadedFile(fp), shylock)
FixtureData: TypeAlias = Mapping[Union[str, int, None], List[int]] FixtureData: TypeAlias = Mapping[Union[str, int, None], List[int]]

View File

@ -327,7 +327,6 @@ def extract_and_upload_attachments(message: EmailMessage, realm: Realm, sender:
if isinstance(attachment, bytes): if isinstance(attachment, bytes):
upload_url = upload_message_attachment( upload_url = upload_message_attachment(
filename, filename,
len(attachment),
content_type, content_type,
attachment, attachment,
sender, sender,

View File

@ -124,7 +124,6 @@ def sanitize_name(value: str) -> str:
def upload_message_attachment( def upload_message_attachment(
uploaded_file_name: str, uploaded_file_name: str,
uploaded_file_size: int,
content_type: str, content_type: str,
file_data: bytes, file_data: bytes,
user_profile: UserProfile, user_profile: UserProfile,
@ -146,7 +145,7 @@ def upload_message_attachment(
path_id, path_id,
user_profile, user_profile,
target_realm, target_realm,
uploaded_file_size, len(file_data),
content_type, content_type,
) )
return f"/user_uploads/{path_id}" return f"/user_uploads/{path_id}"
@ -175,11 +174,11 @@ def claim_attachment(
def upload_message_attachment_from_request( def upload_message_attachment_from_request(
user_file: UploadedFile, user_profile: UserProfile, user_file_size: int user_file: UploadedFile, user_profile: UserProfile
) -> str: ) -> str:
uploaded_file_name, content_type = get_file_info(user_file) uploaded_file_name, content_type = get_file_info(user_file)
return upload_message_attachment( return upload_message_attachment(
uploaded_file_name, user_file_size, content_type, user_file.read(), user_profile uploaded_file_name, content_type, user_file.read(), user_profile
) )

View File

@ -350,9 +350,7 @@ def deactivate_own_user() -> Dict[str, object]:
@openapi_param_value_generator(["/attachments/{attachment_id}:delete"]) @openapi_param_value_generator(["/attachments/{attachment_id}:delete"])
def remove_attachment() -> Dict[str, object]: def remove_attachment() -> Dict[str, object]:
user_profile = helpers.example_user("iago") user_profile = helpers.example_user("iago")
url = upload_message_attachment( url = upload_message_attachment("dummy.txt", "text/plain", b"zulip!", user_profile)
"dummy.txt", len(b"zulip!"), "text/plain", b"zulip!", user_profile
)
attachment_id = url.replace("/user_uploads/", "").split("/")[0] attachment_id = url.replace("/user_uploads/", "").split("/")[0]
return {"attachment_id": attachment_id} return {"attachment_id": attachment_id}

View File

@ -601,7 +601,6 @@ class TestEmailMirrorMessagesWithAttachments(ZulipTestCase):
process_message(incoming_valid_message) process_message(incoming_valid_message)
upload_message_attachment.assert_called_with( upload_message_attachment.assert_called_with(
"image.png", "image.png",
len(image_bytes),
"image/png", "image/png",
image_bytes, image_bytes,
get_system_bot(settings.EMAIL_GATEWAY_BOT, stream.realm_id), get_system_bot(settings.EMAIL_GATEWAY_BOT, stream.realm_id),
@ -728,7 +727,6 @@ class TestEmailMirrorMessagesWithAttachments(ZulipTestCase):
process_message(incoming_valid_message) process_message(incoming_valid_message)
upload_message_attachment.assert_called_with( upload_message_attachment.assert_called_with(
utf8_filename, utf8_filename,
len(image_bytes),
"image/png", "image/png",
image_bytes, image_bytes,
get_system_bot(settings.EMAIL_GATEWAY_BOT, stream.realm_id), get_system_bot(settings.EMAIL_GATEWAY_BOT, stream.realm_id),
@ -775,7 +773,6 @@ class TestEmailMirrorMessagesWithAttachments(ZulipTestCase):
process_message(incoming_valid_message) process_message(incoming_valid_message)
upload_message_attachment.assert_called_with( upload_message_attachment.assert_called_with(
"image.png", "image.png",
len(image_bytes),
"image/png", "image/png",
image_bytes, image_bytes,
get_system_bot(settings.EMAIL_GATEWAY_BOT, stream.realm_id), get_system_bot(settings.EMAIL_GATEWAY_BOT, stream.realm_id),

View File

@ -164,9 +164,7 @@ class ExportFile(ZulipTestCase):
self, user_profile: UserProfile, *, emoji_name: str = "whatever" self, user_profile: UserProfile, *, emoji_name: str = "whatever"
) -> None: ) -> None:
message = most_recent_message(user_profile) message = most_recent_message(user_profile)
url = upload_message_attachment( url = upload_message_attachment("dummy.txt", "text/plain", b"zulip!", user_profile)
"dummy.txt", len(b"zulip!"), "text/plain", b"zulip!", user_profile
)
attachment_path_id = url.replace("/user_uploads/", "") attachment_path_id = url.replace("/user_uploads/", "")
claim_attachment( claim_attachment(
path_id=attachment_path_id, path_id=attachment_path_id,
@ -383,9 +381,7 @@ class RealmImportExportTest(ExportFile):
# We create an attachment tied to a personal message. That means it shouldn't be # We create an attachment tied to a personal message. That means it shouldn't be
# included in a public export, as it's private data. # included in a public export, as it's private data.
personal_message_id = self.send_personal_message(user_profile, self.example_user("othello")) personal_message_id = self.send_personal_message(user_profile, self.example_user("othello"))
url = upload_message_attachment( url = upload_message_attachment("dummy.txt", "text/plain", b"zulip!", user_profile)
"dummy.txt", len(b"zulip!"), "text/plain", b"zulip!", user_profile
)
attachment_path_id = url.replace("/user_uploads/", "") attachment_path_id = url.replace("/user_uploads/", "")
attachment = claim_attachment( attachment = claim_attachment(
path_id=attachment_path_id, path_id=attachment_path_id,

View File

@ -2162,9 +2162,7 @@ class ScrubRealmTest(ZulipTestCase):
path_ids = [] path_ids = []
for n in range(1, 4): for n in range(1, 4):
content = f"content{n}".encode() content = f"content{n}".encode()
url = upload_message_attachment( url = upload_message_attachment(f"dummy{n}.txt", "text/plain", content, hamlet)
f"dummy{n}.txt", len(content), "text/plain", content, hamlet
)
base = "/user_uploads/" base = "/user_uploads/"
self.assertEqual(base, url[: len(base)]) self.assertEqual(base, url[: len(base)])
path_id = re.sub(r"/user_uploads/", "", url) path_id = re.sub(r"/user_uploads/", "", url)
@ -2239,9 +2237,7 @@ class ScrubRealmTest(ZulipTestCase):
file_paths = [] file_paths = []
for n, owner in enumerate([iago, othello, hamlet, cordelia, king]): for n, owner in enumerate([iago, othello, hamlet, cordelia, king]):
content = f"content{n}".encode() content = f"content{n}".encode()
url = upload_message_attachment( url = upload_message_attachment(f"dummy{n}.txt", "text/plain", content, owner)
f"dummy{n}.txt", len(content), "text/plain", content, owner
)
base = "/user_uploads/" base = "/user_uploads/"
self.assertEqual(base, url[: len(base)]) self.assertEqual(base, url[: len(base)])
file_path = os.path.join(settings.LOCAL_FILES_DIR, re.sub(r"/user_uploads/", "", url)) file_path = os.path.join(settings.LOCAL_FILES_DIR, re.sub(r"/user_uploads/", "", url))

View File

@ -67,8 +67,8 @@ class TransferUploadsToS3Test(ZulipTestCase):
hamlet = self.example_user("hamlet") hamlet = self.example_user("hamlet")
othello = self.example_user("othello") othello = self.example_user("othello")
upload_message_attachment("dummy1.txt", len(b"zulip1!"), "text/plain", b"zulip1!", hamlet) upload_message_attachment("dummy1.txt", "text/plain", b"zulip1!", hamlet)
upload_message_attachment("dummy2.txt", len(b"zulip2!"), "text/plain", b"zulip2!", othello) upload_message_attachment("dummy2.txt", "text/plain", b"zulip2!", othello)
with self.assertLogs(level="INFO"): with self.assertLogs(level="INFO"):
transfer_message_files_to_s3(1) transfer_message_files_to_s3(1)

View File

@ -1836,14 +1836,14 @@ class UploadSpaceTests(UploadSerializeMixin, ZulipTestCase):
self.assertEqual(0, cache_get(get_realm_used_upload_space_cache_key(self.realm.id))[0]) self.assertEqual(0, cache_get(get_realm_used_upload_space_cache_key(self.realm.id))[0])
data = b"zulip!" data = b"zulip!"
upload_message_attachment("dummy.txt", len(data), "text/plain", data, self.user_profile) upload_message_attachment("dummy.txt", "text/plain", data, self.user_profile)
# notify_attachment_update function calls currently_used_upload_space_bytes which # notify_attachment_update function calls currently_used_upload_space_bytes which
# updates the cache. # updates the cache.
self.assert_length(data, cache_get(get_realm_used_upload_space_cache_key(self.realm.id))[0]) self.assert_length(data, cache_get(get_realm_used_upload_space_cache_key(self.realm.id))[0])
self.assert_length(data, self.realm.currently_used_upload_space_bytes()) self.assert_length(data, self.realm.currently_used_upload_space_bytes())
data2 = b"more-data!" data2 = b"more-data!"
upload_message_attachment("dummy2.txt", len(data2), "text/plain", data2, self.user_profile) upload_message_attachment("dummy2.txt", "text/plain", data2, self.user_profile)
self.assertEqual( self.assertEqual(
len(data) + len(data2), len(data) + len(data2),
cache_get(get_realm_used_upload_space_cache_key(self.realm.id))[0], cache_get(get_realm_used_upload_space_cache_key(self.realm.id))[0],
@ -1876,7 +1876,7 @@ class UploadSpaceTests(UploadSerializeMixin, ZulipTestCase):
self.assert_length(data2, self.realm.currently_used_upload_space_bytes()) self.assert_length(data2, self.realm.currently_used_upload_space_bytes())
data3 = b"even-more-data!" data3 = b"even-more-data!"
upload_message_attachment("dummy3.txt", len(data3), "text/plain", data3, self.user_profile) upload_message_attachment("dummy3.txt", "text/plain", data3, self.user_profile)
self.assertEqual(len(data2) + len(data3), self.realm.currently_used_upload_space_bytes()) self.assertEqual(len(data2) + len(data3), self.realm.currently_used_upload_space_bytes())

View File

@ -30,9 +30,7 @@ from zerver.models.users import get_system_bot
class LocalStorageTest(UploadSerializeMixin, ZulipTestCase): class LocalStorageTest(UploadSerializeMixin, ZulipTestCase):
def test_upload_message_attachment(self) -> None: def test_upload_message_attachment(self) -> None:
user_profile = self.example_user("hamlet") user_profile = self.example_user("hamlet")
url = upload_message_attachment( url = upload_message_attachment("dummy.txt", "text/plain", b"zulip!", user_profile)
"dummy.txt", len(b"zulip!"), "text/plain", b"zulip!", user_profile
)
base = "/user_uploads/" base = "/user_uploads/"
self.assertEqual(base, url[: len(base)]) self.assertEqual(base, url[: len(base)])
@ -47,9 +45,7 @@ class LocalStorageTest(UploadSerializeMixin, ZulipTestCase):
def test_save_attachment_contents(self) -> None: def test_save_attachment_contents(self) -> None:
user_profile = self.example_user("hamlet") user_profile = self.example_user("hamlet")
url = upload_message_attachment( url = upload_message_attachment("dummy.txt", "text/plain", b"zulip!", user_profile)
"dummy.txt", len(b"zulip!"), "text/plain", b"zulip!", user_profile
)
path_id = re.sub(r"/user_uploads/", "", url) path_id = re.sub(r"/user_uploads/", "", url)
output = BytesIO() output = BytesIO()
@ -68,7 +64,7 @@ class LocalStorageTest(UploadSerializeMixin, ZulipTestCase):
self.assertEqual(user_profile.realm, internal_realm) self.assertEqual(user_profile.realm, internal_realm)
url = upload_message_attachment( url = upload_message_attachment(
"dummy.txt", len(b"zulip!"), "text/plain", b"zulip!", user_profile, zulip_realm "dummy.txt", "text/plain", b"zulip!", user_profile, zulip_realm
) )
# Ensure the correct realm id of the target realm is used instead of the bot's realm. # Ensure the correct realm id of the target realm is used instead of the bot's realm.
self.assertTrue(url.startswith(f"/user_uploads/{zulip_realm.id}/")) self.assertTrue(url.startswith(f"/user_uploads/{zulip_realm.id}/"))
@ -96,9 +92,7 @@ class LocalStorageTest(UploadSerializeMixin, ZulipTestCase):
user_profile = self.example_user("hamlet") user_profile = self.example_user("hamlet")
path_ids = [] path_ids = []
for n in range(1, 1005): for n in range(1, 1005):
url = upload_message_attachment( url = upload_message_attachment("dummy.txt", "text/plain", b"zulip!", user_profile)
"dummy.txt", len(b"zulip!"), "text/plain", b"zulip!", user_profile
)
base = "/user_uploads/" base = "/user_uploads/"
self.assertEqual(base, url[: len(base)]) self.assertEqual(base, url[: len(base)])
path_id = re.sub(r"/user_uploads/", "", url) path_id = re.sub(r"/user_uploads/", "", url)

View File

@ -46,9 +46,7 @@ class S3Test(ZulipTestCase):
bucket = create_s3_buckets(settings.S3_AUTH_UPLOADS_BUCKET)[0] bucket = create_s3_buckets(settings.S3_AUTH_UPLOADS_BUCKET)[0]
user_profile = self.example_user("hamlet") user_profile = self.example_user("hamlet")
url = upload_message_attachment( url = upload_message_attachment("dummy.txt", "text/plain", b"zulip!", user_profile)
"dummy.txt", len(b"zulip!"), "text/plain", b"zulip!", user_profile
)
base = "/user_uploads/" base = "/user_uploads/"
self.assertEqual(base, url[: len(base)]) self.assertEqual(base, url[: len(base)])
@ -67,9 +65,7 @@ class S3Test(ZulipTestCase):
def test_save_attachment_contents(self) -> None: def test_save_attachment_contents(self) -> None:
create_s3_buckets(settings.S3_AUTH_UPLOADS_BUCKET) create_s3_buckets(settings.S3_AUTH_UPLOADS_BUCKET)
user_profile = self.example_user("hamlet") user_profile = self.example_user("hamlet")
url = upload_message_attachment( url = upload_message_attachment("dummy.txt", "text/plain", b"zulip!", user_profile)
"dummy.txt", len(b"zulip!"), "text/plain", b"zulip!", user_profile
)
path_id = re.sub(r"/user_uploads/", "", url) path_id = re.sub(r"/user_uploads/", "", url)
output = BytesIO() output = BytesIO()
@ -90,7 +86,7 @@ class S3Test(ZulipTestCase):
self.assertEqual(user_profile.realm, internal_realm) self.assertEqual(user_profile.realm, internal_realm)
url = upload_message_attachment( url = upload_message_attachment(
"dummy.txt", len(b"zulip!"), "text/plain", b"zulip!", user_profile, zulip_realm "dummy.txt", "text/plain", b"zulip!", user_profile, zulip_realm
) )
# Ensure the correct realm id of the target realm is used instead of the bot's realm. # Ensure the correct realm id of the target realm is used instead of the bot's realm.
self.assertTrue(url.startswith(f"/user_uploads/{zulip_realm.id}/")) self.assertTrue(url.startswith(f"/user_uploads/{zulip_realm.id}/"))
@ -100,9 +96,7 @@ class S3Test(ZulipTestCase):
bucket = create_s3_buckets(settings.S3_AUTH_UPLOADS_BUCKET)[0] bucket = create_s3_buckets(settings.S3_AUTH_UPLOADS_BUCKET)[0]
user_profile = self.example_user("hamlet") user_profile = self.example_user("hamlet")
url = upload_message_attachment( url = upload_message_attachment("dummy.txt", "text/plain", b"zulip!", user_profile)
"dummy.txt", len(b"zulip!"), "text/plain", b"zulip!", user_profile
)
path_id = re.sub(r"/user_uploads/", "", url) path_id = re.sub(r"/user_uploads/", "", url)
self.assertIsNotNone(bucket.Object(path_id).get()) self.assertIsNotNone(bucket.Object(path_id).get())
@ -117,9 +111,7 @@ class S3Test(ZulipTestCase):
user_profile = self.example_user("hamlet") user_profile = self.example_user("hamlet")
path_ids = [] path_ids = []
for n in range(1, 5): for n in range(1, 5):
url = upload_message_attachment( url = upload_message_attachment("dummy.txt", "text/plain", b"zulip!", user_profile)
"dummy.txt", len(b"zulip!"), "text/plain", b"zulip!", user_profile
)
path_id = re.sub(r"/user_uploads/", "", url) path_id = re.sub(r"/user_uploads/", "", url)
self.assertIsNotNone(bucket.Object(path_id).get()) self.assertIsNotNone(bucket.Object(path_id).get())
path_ids.append(path_id) path_ids.append(path_id)
@ -152,9 +144,7 @@ class S3Test(ZulipTestCase):
user_profile = self.example_user("hamlet") user_profile = self.example_user("hamlet")
path_ids = [] path_ids = []
for n in range(1, 5): for n in range(1, 5):
url = upload_message_attachment( url = upload_message_attachment("dummy.txt", "text/plain", b"zulip!", user_profile)
"dummy.txt", len(b"zulip!"), "text/plain", b"zulip!", user_profile
)
path_ids.append(re.sub(r"/user_uploads/", "", url)) path_ids.append(re.sub(r"/user_uploads/", "", url))
found_paths = [r[0] for r in all_message_attachments()] found_paths = [r[0] for r in all_message_attachments()]
self.assertEqual(sorted(found_paths), sorted(path_ids)) self.assertEqual(sorted(found_paths), sorted(path_ids))

View File

@ -320,5 +320,5 @@ def upload_file_backend(request: HttpRequest, user_profile: UserProfile) -> Http
) )
check_upload_within_quota(user_profile.realm, file_size) check_upload_within_quota(user_profile.realm, file_size)
uri = upload_message_attachment_from_request(user_file, user_profile, file_size) uri = upload_message_attachment_from_request(user_file, user_profile)
return json_success(request, data={"uri": uri}) return json_success(request, data={"uri": uri})