Add bulk and single bookmark metadata refresh (#999)

* Add url create/edit query paramter to clear cache

* Add refresh bookmark metadata button in create/edit bookmark page

* Fix refresh bookmark metadata when editing existing bookmark

* Add bulk refresh metadata functionality

* Fix test cases for bulk view dropdown selection list

* Allow bulk metadata refresh when background tasks are disabled

* Move load preview image call on refresh metadata

* Update bookmark modified time on metadata refresh

* Rename function to align with convention

* Add tests for refresh task

* Add tests for bookmarks service refresh metadata

* Add tests for bookmarks api disable cache on check

* Remove bulk refresh metadata when background tasks disabled

* Refactor refresh metadata task

* Remove unnecessary call

* Fix testing mock name

* Abstract clearing metadata cache

* Add test to check if load page is called twice when cache disabled

* Remove refresh button for new bookmarks

* Remove strict disable cache is true check

* Refactor refresh metadata form logic into its own function

* move button and highlight changes

* polish and update tests

---------

Co-authored-by: Sascha Ißbrücker <sascha.issbruecker@gmail.com>
This commit is contained in:
Josh S
2025-03-22 06:34:10 -04:00
committed by GitHub
parent f1acb4f7c9
commit a23c357f2f
14 changed files with 300 additions and 10 deletions

View File

@@ -21,6 +21,7 @@ from bookmarks.services.bookmarks import (
share_bookmarks,
unshare_bookmarks,
enhance_with_website_metadata,
refresh_bookmarks_metadata,
)
from bookmarks.tests.helpers import BookmarkFactoryMixin
@@ -30,6 +31,21 @@ class BookmarkServiceTestCase(TestCase, BookmarkFactoryMixin):
def setUp(self) -> None:
self.get_or_create_test_user()
self.mock_schedule_refresh_metadata_patcher = patch(
"bookmarks.services.bookmarks.tasks.refresh_metadata"
)
self.mock_schedule_refresh_metadata = (
self.mock_schedule_refresh_metadata_patcher.start()
)
self.mock_load_preview_image_patcher = patch(
"bookmarks.services.bookmarks.tasks.load_preview_image"
)
self.mock_load_preview_image = self.mock_load_preview_image_patcher.start()
def tearDown(self):
self.mock_schedule_refresh_metadata_patcher.stop()
self.mock_load_preview_image_patcher.stop()
def test_create_should_not_update_website_metadata(self):
with patch.object(
website_loader, "load_website_metadata"
@@ -891,3 +907,70 @@ class BookmarkServiceTestCase(TestCase, BookmarkFactoryMixin):
self.assertEqual("", bookmark.title)
self.assertEqual("", bookmark.description)
def test_refresh_bookmarks_metadata(self):
bookmark1 = self.setup_bookmark()
bookmark2 = self.setup_bookmark()
bookmark3 = self.setup_bookmark()
refresh_bookmarks_metadata(
[bookmark1.id, bookmark2.id, bookmark3.id], self.get_or_create_test_user()
)
self.assertEqual(self.mock_schedule_refresh_metadata.call_count, 3)
self.assertEqual(self.mock_load_preview_image.call_count, 3)
def test_refresh_bookmarks_metadata_should_only_refresh_specified_bookmarks(self):
bookmark1 = self.setup_bookmark()
bookmark2 = self.setup_bookmark()
bookmark3 = self.setup_bookmark()
refresh_bookmarks_metadata(
[bookmark1.id, bookmark3.id], self.get_or_create_test_user()
)
self.assertEqual(self.mock_schedule_refresh_metadata.call_count, 2)
self.assertEqual(self.mock_load_preview_image.call_count, 2)
for call_args in self.mock_schedule_refresh_metadata.call_args_list:
args, kwargs = call_args
self.assertNotIn(bookmark2.id, args)
for call_args in self.mock_load_preview_image.call_args_list:
args, kwargs = call_args
self.assertNotIn(bookmark2.id, args)
def test_refresh_bookmarks_metadata_should_only_refresh_user_owned_bookmarks(self):
other_user = self.setup_user()
bookmark1 = self.setup_bookmark()
bookmark2 = self.setup_bookmark()
inaccessible_bookmark = self.setup_bookmark(user=other_user)
refresh_bookmarks_metadata(
[bookmark1.id, bookmark2.id, inaccessible_bookmark.id],
self.get_or_create_test_user(),
)
self.assertEqual(self.mock_schedule_refresh_metadata.call_count, 2)
self.assertEqual(self.mock_load_preview_image.call_count, 2)
for call_args in self.mock_schedule_refresh_metadata.call_args_list:
args, kwargs = call_args
self.assertNotIn(inaccessible_bookmark.id, args)
for call_args in self.mock_load_preview_image.call_args_list:
args, kwargs = call_args
self.assertNotIn(inaccessible_bookmark.id, args)
def test_refresh_bookmarks_metadata_should_accept_mix_of_int_and_string_ids(self):
bookmark1 = self.setup_bookmark()
bookmark2 = self.setup_bookmark()
bookmark3 = self.setup_bookmark()
refresh_bookmarks_metadata(
[str(bookmark1.id), str(bookmark2.id), bookmark3.id],
self.get_or_create_test_user(),
)
self.assertEqual(self.mock_schedule_refresh_metadata.call_count, 3)
self.assertEqual(self.mock_load_preview_image.call_count, 3)