mirror of
https://github.com/sissbruecker/linkding.git
synced 2025-08-07 10:58:25 +02:00

* 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
372 lines
15 KiB
Python
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)
|