diff --git a/bookmarks/services/assets.py b/bookmarks/services/assets.py index a6e745d..ac5d843 100644 --- a/bookmarks/services/assets.py +++ b/bookmarks/services/assets.py @@ -94,13 +94,28 @@ def upload_asset(bookmark: Bookmark, upload_file: UploadedFile): gzip=False, ) name, extension = os.path.splitext(upload_file.name) - filename = _generate_asset_filename(asset, name, extension.lstrip(".")) - filepath = os.path.join(settings.LD_ASSET_FOLDER, filename) - with open(filepath, "wb") as f: - for chunk in upload_file.chunks(): - f.write(chunk) - asset.file = filename - asset.file_size = upload_file.size + + # automatically gzip the file if it is not already gzipped + if upload_file.content_type != "application/gzip": + filename = _generate_asset_filename( + asset, name, extension.lstrip(".") + ".gz" + ) + filepath = os.path.join(settings.LD_ASSET_FOLDER, filename) + with gzip.open(filepath, "wb", compresslevel=9) as f: + for chunk in upload_file.chunks(): + f.write(chunk) + asset.gzip = True + asset.file = filename + asset.file_size = os.path.getsize(filepath) + else: + filename = _generate_asset_filename(asset, name, extension.lstrip(".")) + filepath = os.path.join(settings.LD_ASSET_FOLDER, filename) + with open(filepath, "wb") as f: + for chunk in upload_file.chunks(): + f.write(chunk) + asset.file = filename + asset.file_size = upload_file.size + asset.save() asset.bookmark.date_modified = timezone.now() diff --git a/bookmarks/tests/helpers.py b/bookmarks/tests/helpers.py index 7db175b..cd15c2e 100644 --- a/bookmarks/tests/helpers.py +++ b/bookmarks/tests/helpers.py @@ -236,8 +236,17 @@ class BookmarkFactoryMixin: def read_asset_file(self, asset: BookmarkAsset): filepath = os.path.join(settings.LD_ASSET_FOLDER, asset.file) - with open(filepath, "rb") as f: - return f.read() + + if asset.gzip: + with gzip.open(filepath, "rb") as f: + return f.read() + else: + with open(filepath, "rb") as f: + return f.read() + + def get_asset_filesize(self, asset: BookmarkAsset): + filepath = os.path.join(settings.LD_ASSET_FOLDER, asset.file) + return os.path.getsize(filepath) if os.path.exists(filepath) else 0 def has_asset_file(self, asset: BookmarkAsset): filepath = os.path.join(settings.LD_ASSET_FOLDER, asset.file) diff --git a/bookmarks/tests/test_assets_service.py b/bookmarks/tests/test_assets_service.py index 97029fa..5eb3ccc 100644 --- a/bookmarks/tests/test_assets_service.py +++ b/bookmarks/tests/test_assets_service.py @@ -207,11 +207,10 @@ class AssetServiceTestCase(TestCase, BookmarkFactoryMixin): # verify file name self.assertTrue(saved_file_name.startswith("upload_")) - self.assertTrue(saved_file_name.endswith("_test_file.txt")) + self.assertTrue(saved_file_name.endswith("_test_file.txt.gz")) # file should contain the correct content - with open(os.path.join(self.assets_dir, saved_file_name), "rb") as file: - self.assertEqual(file.read(), file_content) + self.assertEqual(self.read_asset_file(asset), file_content) # should create asset self.assertIsNotNone(asset.id) @@ -221,6 +220,45 @@ class AssetServiceTestCase(TestCase, BookmarkFactoryMixin): self.assertEqual(asset.display_name, upload_file.name) self.assertEqual(asset.status, BookmarkAsset.STATUS_COMPLETE) self.assertEqual(asset.file, saved_file_name) + self.assertEqual(asset.file_size, self.get_asset_filesize(asset)) + self.assertTrue(asset.gzip) + + # should update bookmark modified date + bookmark.refresh_from_db() + self.assertGreater(bookmark.date_modified, initial_modified) + + @disable_logging + def test_upload_gzip_asset(self): + initial_modified = timezone.datetime( + 2025, 1, 1, 0, 0, 0, tzinfo=datetime.timezone.utc + ) + bookmark = self.setup_bookmark(modified=initial_modified) + file_content = gzip.compress(b"test content") + upload_file = SimpleUploadedFile( + "test_file.html.gz", file_content, content_type="application/gzip" + ) + + asset = assets.upload_asset(bookmark, upload_file) + + # should create file in asset folder + saved_file_name = self.get_saved_snapshot_file() + self.assertIsNotNone(upload_file) + + # verify file name + self.assertTrue(saved_file_name.startswith("upload_")) + self.assertTrue(saved_file_name.endswith("_test_file.html.gz")) + + # file should contain the correct content + self.assertEqual(self.read_asset_file(asset), file_content) + + # should create asset + self.assertIsNotNone(asset.id) + self.assertEqual(asset.bookmark, bookmark) + self.assertEqual(asset.asset_type, BookmarkAsset.TYPE_UPLOAD) + self.assertEqual(asset.content_type, "application/gzip") + self.assertEqual(asset.display_name, upload_file.name) + self.assertEqual(asset.status, BookmarkAsset.STATUS_COMPLETE) + self.assertEqual(asset.file, saved_file_name) self.assertEqual(asset.file_size, len(file_content)) self.assertFalse(asset.gzip) @@ -245,7 +283,7 @@ class AssetServiceTestCase(TestCase, BookmarkFactoryMixin): self.assertEqual(192, len(saved_file)) self.assertTrue(saved_file.startswith("upload_")) - self.assertTrue(saved_file.endswith("aaaa.txt")) + self.assertTrue(saved_file.endswith("aaaa.txt.gz")) @disable_logging def test_upload_asset_failure(self): diff --git a/bookmarks/tests/test_bookmark_assets_api.py b/bookmarks/tests/test_bookmark_assets_api.py index 0517e58..284e8dc 100644 --- a/bookmarks/tests/test_bookmark_assets_api.py +++ b/bookmarks/tests/test_bookmark_assets_api.py @@ -253,8 +253,8 @@ class BookmarkAssetsApiTestCase(LinkdingApiTestCase, BookmarkFactoryMixin): self.assertEqual(asset.display_name, file_name) self.assertEqual(asset.asset_type, BookmarkAsset.TYPE_UPLOAD) self.assertEqual(asset.content_type, "text/plain") - self.assertEqual(asset.file_size, len(file_content)) - self.assertFalse(asset.gzip) + self.assertEqual(asset.file_size, self.get_asset_filesize(asset)) + self.assertTrue(asset.gzip) content = self.read_asset_file(asset) self.assertEqual(content, file_content)