Files
linkding/bookmarks/tests/test_bookmark_shared_view.py
Sascha Ißbrücker 0975914a86 Add sort option to bookmark list (#522)
* Rename BookmarkFilters to BookmarkSearch

* Refactor queries to accept BookmarkSearch

* Sort query by data added and title

* Ensure pagination respects search parameters

* Ensure tag cloud respects search parameters

* Ensure user select respects search parameters

* Ensure return url respects search options

* Fix passing search options to user select

* Fix BookmarkSearch initialization

* Extract common search form logic

* Ensure partial update respects search options

* Add sort UI

* Use custom ICU collation when sorting with SQLite

* Support sort in API
2023-09-01 22:48:21 +02:00

372 lines
15 KiB
Python

import urllib.parse
from typing import List
from django.contrib.auth.models import User
from django.test import TestCase
from django.urls import reverse
from bookmarks.models import Bookmark, Tag, UserProfile
from bookmarks.tests.helpers import BookmarkFactoryMixin, collapse_whitespace
class BookmarkSharedViewTestCase(TestCase, BookmarkFactoryMixin):
def authenticate(self) -> None:
user = self.get_or_create_test_user()
self.client.force_login(user)
def assertBookmarkCount(self, html: str, bookmark: Bookmark, count: int, link_target: str = '_blank'):
self.assertInHTML(
f'<a href="{bookmark.url}" target="{link_target}" rel="noopener">{bookmark.resolved_title}</a>',
html, count=count
)
def assertVisibleBookmarks(self, response, bookmarks: List[Bookmark], link_target: str = '_blank'):
html = response.content.decode()
self.assertContains(response, '<li ld-bookmark-item class="shared">', count=len(bookmarks))
for bookmark in bookmarks:
self.assertBookmarkCount(html, bookmark, 1, link_target)
def assertInvisibleBookmarks(self, response, bookmarks: List[Bookmark], link_target: str = '_blank'):
html = response.content.decode()
for bookmark in bookmarks:
self.assertBookmarkCount(html, bookmark, 0, link_target)
def assertVisibleTags(self, response, tags: [Tag]):
self.assertContains(response, 'data-is-tag-item', count=len(tags))
for tag in tags:
self.assertContains(response, tag.name)
def assertInvisibleTags(self, response, tags: [Tag]):
for tag in tags:
self.assertNotContains(response, tag.name)
def assertVisibleUserOptions(self, response, users: List[User]):
html = response.content.decode()
user_options = [
'<option value="" selected="">Everyone</option>'
]
for user in users:
user_options.append(f'<option value="{user.username}">{user.username}</option>')
user_select_html = f'''
<select name="user" class="form-select" required="" id="id_user">
{''.join(user_options)}
</select>
'''
self.assertInHTML(user_select_html, html)
def assertEditLink(self, response, url):
html = response.content.decode()
self.assertInHTML(f'''
<a href="{url}">Edit</a>
''', html)
def test_should_list_shared_bookmarks_from_all_users_that_have_sharing_enabled(self):
self.authenticate()
user1 = self.setup_user(enable_sharing=True)
user2 = self.setup_user(enable_sharing=True)
user3 = self.setup_user(enable_sharing=True)
user4 = self.setup_user(enable_sharing=False)
visible_bookmarks = [
self.setup_bookmark(shared=True, user=user1),
self.setup_bookmark(shared=True, user=user2),
self.setup_bookmark(shared=True, user=user3),
]
invisible_bookmarks = [
self.setup_bookmark(shared=False, user=user1),
self.setup_bookmark(shared=False, user=user2),
self.setup_bookmark(shared=False, user=user3),
self.setup_bookmark(shared=True, user=user4),
]
response = self.client.get(reverse('bookmarks:shared'))
html = collapse_whitespace(response.content.decode())
# Should render list
self.assertIn('<ul class="bookmark-list" data-bookmarks-total="3">', html)
self.assertVisibleBookmarks(response, visible_bookmarks)
self.assertInvisibleBookmarks(response, invisible_bookmarks)
def test_should_list_shared_bookmarks_from_selected_user(self):
self.authenticate()
user1 = self.setup_user(enable_sharing=True)
user2 = self.setup_user(enable_sharing=True)
user3 = self.setup_user(enable_sharing=True)
visible_bookmarks = [
self.setup_bookmark(shared=True, user=user1),
]
invisible_bookmarks = [
self.setup_bookmark(shared=True, user=user2),
self.setup_bookmark(shared=True, user=user3),
]
url = reverse('bookmarks:shared') + '?user=' + user1.username
response = self.client.get(url)
self.assertVisibleBookmarks(response, visible_bookmarks)
self.assertInvisibleBookmarks(response, invisible_bookmarks)
def test_should_list_bookmarks_matching_query(self):
self.authenticate()
user = self.setup_user(enable_sharing=True)
visible_bookmarks = [
self.setup_bookmark(shared=True, title='searchvalue', user=user),
self.setup_bookmark(shared=True, title='searchvalue', user=user),
self.setup_bookmark(shared=True, title='searchvalue', user=user)
]
invisible_bookmarks = [
self.setup_bookmark(shared=True, user=user),
self.setup_bookmark(shared=True, user=user),
self.setup_bookmark(shared=True, user=user)
]
response = self.client.get(reverse('bookmarks:shared') + '?q=searchvalue')
html = collapse_whitespace(response.content.decode())
# Should render list
self.assertIn('<ul class="bookmark-list" data-bookmarks-total="3">', html)
self.assertVisibleBookmarks(response, visible_bookmarks)
self.assertInvisibleBookmarks(response, invisible_bookmarks)
def test_should_list_only_publicly_shared_bookmarks_without_login(self):
user1 = self.setup_user(enable_sharing=True, enable_public_sharing=True)
user2 = self.setup_user(enable_sharing=True)
visible_bookmarks = [
self.setup_bookmark(shared=True, user=user1),
self.setup_bookmark(shared=True, user=user1),
self.setup_bookmark(shared=True, user=user1),
]
invisible_bookmarks = [
self.setup_bookmark(shared=True, user=user2),
self.setup_bookmark(shared=True, user=user2),
self.setup_bookmark(shared=True, user=user2),
]
response = self.client.get(reverse('bookmarks:shared'))
html = collapse_whitespace(response.content.decode())
# Should render list
self.assertIn('<ul class="bookmark-list" data-bookmarks-total="3">', html)
self.assertVisibleBookmarks(response, visible_bookmarks)
self.assertInvisibleBookmarks(response, invisible_bookmarks)
def test_should_list_tags_for_shared_bookmarks_from_all_users_that_have_sharing_enabled(self):
self.authenticate()
user1 = self.setup_user(enable_sharing=True)
user2 = self.setup_user(enable_sharing=True)
user3 = self.setup_user(enable_sharing=True)
user4 = self.setup_user(enable_sharing=False)
visible_tags = [
self.setup_tag(user=user1),
self.setup_tag(user=user2),
self.setup_tag(user=user3),
]
invisible_tags = [
self.setup_tag(user=user1),
self.setup_tag(user=user2),
self.setup_tag(user=user3),
self.setup_tag(user=user4),
]
self.setup_bookmark(shared=True, user=user1, tags=[visible_tags[0]])
self.setup_bookmark(shared=True, user=user2, tags=[visible_tags[1]])
self.setup_bookmark(shared=True, user=user3, tags=[visible_tags[2]])
self.setup_bookmark(shared=False, user=user1, tags=[invisible_tags[0]])
self.setup_bookmark(shared=False, user=user2, tags=[invisible_tags[1]])
self.setup_bookmark(shared=False, user=user3, tags=[invisible_tags[2]])
self.setup_bookmark(shared=True, user=user4, tags=[invisible_tags[3]])
response = self.client.get(reverse('bookmarks:shared'))
self.assertVisibleTags(response, visible_tags)
self.assertInvisibleTags(response, invisible_tags)
def test_should_list_tags_for_shared_bookmarks_from_selected_user(self):
self.authenticate()
user1 = self.setup_user(enable_sharing=True)
user2 = self.setup_user(enable_sharing=True)
user3 = self.setup_user(enable_sharing=True)
visible_tags = [
self.setup_tag(user=user1),
]
invisible_tags = [
self.setup_tag(user=user2),
self.setup_tag(user=user3),
]
self.setup_bookmark(shared=True, user=user1, tags=[visible_tags[0]])
self.setup_bookmark(shared=True, user=user2, tags=[invisible_tags[0]])
self.setup_bookmark(shared=True, user=user3, tags=[invisible_tags[1]])
url = reverse('bookmarks:shared') + '?user=' + user1.username
response = self.client.get(url)
self.assertVisibleTags(response, visible_tags)
self.assertInvisibleTags(response, invisible_tags)
def test_should_list_tags_for_bookmarks_matching_query(self):
self.authenticate()
user1 = self.setup_user(enable_sharing=True)
user2 = self.setup_user(enable_sharing=True)
user3 = self.setup_user(enable_sharing=True)
visible_tags = [
self.setup_tag(user=user1),
self.setup_tag(user=user2),
self.setup_tag(user=user3),
]
invisible_tags = [
self.setup_tag(user=user1),
self.setup_tag(user=user2),
self.setup_tag(user=user3),
]
self.setup_bookmark(shared=True, user=user1, title='searchvalue', tags=[visible_tags[0]])
self.setup_bookmark(shared=True, user=user2, title='searchvalue', tags=[visible_tags[1]])
self.setup_bookmark(shared=True, user=user3, title='searchvalue', tags=[visible_tags[2]])
self.setup_bookmark(shared=True, user=user1, tags=[invisible_tags[0]])
self.setup_bookmark(shared=True, user=user2, tags=[invisible_tags[1]])
self.setup_bookmark(shared=True, user=user3, tags=[invisible_tags[2]])
response = self.client.get(reverse('bookmarks:shared') + '?q=searchvalue')
self.assertVisibleTags(response, visible_tags)
self.assertInvisibleTags(response, invisible_tags)
def test_should_list_only_tags_for_publicly_shared_bookmarks_without_login(self):
user1 = self.setup_user(enable_sharing=True, enable_public_sharing=True)
user2 = self.setup_user(enable_sharing=True)
visible_tags = [
self.setup_tag(user=user1),
self.setup_tag(user=user1),
]
invisible_tags = [
self.setup_tag(user=user2),
self.setup_tag(user=user2),
]
self.setup_bookmark(shared=True, user=user1, tags=[visible_tags[0]])
self.setup_bookmark(shared=True, user=user1, tags=[visible_tags[1]])
self.setup_bookmark(shared=True, user=user2, tags=[invisible_tags[0]])
self.setup_bookmark(shared=True, user=user2, tags=[invisible_tags[1]])
response = self.client.get(reverse('bookmarks:shared'))
self.assertVisibleTags(response, visible_tags)
self.assertInvisibleTags(response, invisible_tags)
def test_should_list_users_with_shared_bookmarks_if_sharing_is_enabled(self):
self.authenticate()
expected_visible_users = [
self.setup_user(name='user_a', enable_sharing=True),
self.setup_user(name='user_b', enable_sharing=True),
]
self.setup_bookmark(shared=True, user=expected_visible_users[0])
self.setup_bookmark(shared=True, user=expected_visible_users[1])
self.setup_bookmark(shared=False, user=self.setup_user(enable_sharing=True))
self.setup_bookmark(shared=True, user=self.setup_user(enable_sharing=False))
response = self.client.get(reverse('bookmarks:shared'))
self.assertVisibleUserOptions(response, expected_visible_users)
def test_should_list_only_users_with_publicly_shared_bookmarks_without_login(self):
# users with public sharing enabled
expected_visible_users = [
self.setup_user(name='user_a', enable_sharing=True, enable_public_sharing=True),
self.setup_user(name='user_b', enable_sharing=True, enable_public_sharing=True),
]
self.setup_bookmark(shared=True, user=expected_visible_users[0])
self.setup_bookmark(shared=True, user=expected_visible_users[1])
# users with public sharing disabled
self.setup_bookmark(shared=True, user=self.setup_user(enable_sharing=True))
self.setup_bookmark(shared=True, user=self.setup_user(enable_sharing=True))
response = self.client.get(reverse('bookmarks:shared'))
self.assertVisibleUserOptions(response, expected_visible_users)
def test_should_open_bookmarks_in_new_page_by_default(self):
self.authenticate()
user = self.get_or_create_test_user()
user.profile.enable_sharing = True
user.profile.save()
visible_bookmarks = [
self.setup_bookmark(shared=True),
self.setup_bookmark(shared=True),
self.setup_bookmark(shared=True)
]
response = self.client.get(reverse('bookmarks:shared'))
self.assertVisibleBookmarks(response, visible_bookmarks, '_blank')
def test_should_open_bookmarks_in_same_page_if_specified_in_user_profile(self):
self.authenticate()
user = self.get_or_create_test_user()
user.profile.enable_sharing = True
user.profile.bookmark_link_target = UserProfile.BOOKMARK_LINK_TARGET_SELF
user.profile.save()
visible_bookmarks = [
self.setup_bookmark(shared=True),
self.setup_bookmark(shared=True),
self.setup_bookmark(shared=True)
]
response = self.client.get(reverse('bookmarks:shared'))
self.assertVisibleBookmarks(response, visible_bookmarks, '_self')
def test_edit_link_return_url_respects_search_options(self):
self.authenticate()
user = self.get_or_create_test_user()
user.profile.enable_sharing = True
user.profile.save()
bookmark = self.setup_bookmark(title='foo', shared=True, user=user)
edit_url = reverse('bookmarks:edit', args=[bookmark.id])
base_url = reverse('bookmarks:shared')
# without query params
return_url = urllib.parse.quote(base_url)
url = f'{edit_url}?return_url={return_url}'
response = self.client.get(base_url)
self.assertEditLink(response, url)
# with query
url_params = '?q=foo'
return_url = urllib.parse.quote(base_url + url_params)
url = f'{edit_url}?return_url={return_url}'
response = self.client.get(base_url + url_params)
self.assertEditLink(response, url)
# with query and user
url_params = f'?q=foo&user={user.username}'
return_url = urllib.parse.quote(base_url + url_params)
url = f'{edit_url}?return_url={return_url}'
response = self.client.get(base_url + url_params)
self.assertEditLink(response, url)
# with query and sort and page
url_params = '?q=foo&sort=title_asc&page=2'
return_url = urllib.parse.quote(base_url + url_params)
url = f'{edit_url}?return_url={return_url}'
response = self.client.get(base_url + url_params)
self.assertEditLink(response, url)