mirror of
https://github.com/sissbruecker/linkding.git
synced 2025-08-13 05:29:26 +02:00
Add option to share bookmarks publicly (#503)
* Make shared view public, add user profile fallback * Allow unauthenticated access to shared bookmarks API * Link shared bookmarks in unauthenticated layout * Add public sharing setting * Only show shared bookmarks link if there are publicly shared bookmarks * Disable public sharing if sharing is disabled * Show specific helper text when public sharing is enabled * Fix tests * Add more tests * Improve setting description
This commit is contained in:
@@ -76,11 +76,12 @@ class BookmarkFactoryMixin:
|
||||
tag.save()
|
||||
return tag
|
||||
|
||||
def setup_user(self, name: str = None, enable_sharing: bool = False):
|
||||
def setup_user(self, name: str = None, enable_sharing: bool = False, enable_public_sharing: bool = False):
|
||||
if not name:
|
||||
name = get_random_string(length=32)
|
||||
user = User.objects.create_user(name, 'user@example.com', 'password123')
|
||||
user.profile.enable_sharing = enable_sharing
|
||||
user.profile.enable_public_sharing = enable_public_sharing
|
||||
user.profile.save()
|
||||
return user
|
||||
|
||||
|
26
bookmarks/tests/test_anonymous_view.py
Normal file
26
bookmarks/tests/test_anonymous_view.py
Normal file
@@ -0,0 +1,26 @@
|
||||
from django.test import TestCase
|
||||
from django.urls import reverse
|
||||
|
||||
from bookmarks.tests.helpers import BookmarkFactoryMixin
|
||||
|
||||
|
||||
class AnonymousViewTestCase(TestCase, BookmarkFactoryMixin):
|
||||
def assertSharedBookmarksLinkCount(self, response, count):
|
||||
url = reverse('bookmarks:shared')
|
||||
self.assertContains(response, f'<a href="{url}" class="btn btn-link">Shared bookmarks</a>',
|
||||
count=count)
|
||||
|
||||
def test_publicly_shared_bookmarks_link(self):
|
||||
# should not render link if no public shares exist
|
||||
user = self.setup_user(enable_sharing=True)
|
||||
self.setup_bookmark(user=user, shared=True)
|
||||
|
||||
response = self.client.get(reverse('login'))
|
||||
self.assertSharedBookmarksLinkCount(response, 0)
|
||||
|
||||
# should render link if public shares exist
|
||||
user.profile.enable_public_sharing = True
|
||||
user.profile.save()
|
||||
|
||||
response = self.client.get(reverse('login'))
|
||||
self.assertSharedBookmarksLinkCount(response, 1)
|
@@ -75,7 +75,7 @@ class BookmarkNewViewTestCase(TestCase, BookmarkFactoryMixin):
|
||||
'placeholder=" " autofocus class="form-input" required '
|
||||
'id="id_url">',
|
||||
html)
|
||||
|
||||
|
||||
def test_should_prefill_title_from_url_parameter(self):
|
||||
response = self.client.get(reverse('bookmarks:new') + '?title=Example%20Title')
|
||||
html = response.content.decode()
|
||||
@@ -85,7 +85,7 @@ class BookmarkNewViewTestCase(TestCase, BookmarkFactoryMixin):
|
||||
'class="form-input" maxlength="512" autocomplete="off" '
|
||||
'id="id_title">',
|
||||
html)
|
||||
|
||||
|
||||
def test_should_prefill_description_from_url_parameter(self):
|
||||
response = self.client.get(reverse('bookmarks:new') + '?description=Example%20Site%20Description')
|
||||
html = response.content.decode()
|
||||
@@ -160,8 +160,32 @@ class BookmarkNewViewTestCase(TestCase, BookmarkFactoryMixin):
|
||||
</label>
|
||||
''', html, count=1)
|
||||
|
||||
def test_should_hide_notes_if_there_are_no_notes(self):
|
||||
bookmark = self.setup_bookmark()
|
||||
response = self.client.get(reverse('bookmarks:edit', args=[bookmark.id]))
|
||||
def test_should_show_respective_share_hint(self):
|
||||
self.user.profile.enable_sharing = True
|
||||
self.user.profile.save()
|
||||
|
||||
self.assertContains(response, '<details class="notes">', count=1)
|
||||
response = self.client.get(reverse('bookmarks:new'))
|
||||
html = response.content.decode()
|
||||
self.assertInHTML('''
|
||||
<div class="form-input-hint">
|
||||
Share this bookmark with other registered users.
|
||||
</div>
|
||||
''', html)
|
||||
|
||||
self.user.profile.enable_public_sharing = True
|
||||
self.user.profile.save()
|
||||
|
||||
response = self.client.get(reverse('bookmarks:new'))
|
||||
html = response.content.decode()
|
||||
self.assertInHTML('''
|
||||
<div class="form-input-hint">
|
||||
Share this bookmark with other registered users and anonymous users.
|
||||
</div>
|
||||
''', html)
|
||||
|
||||
|
||||
def test_should_hide_notes_if_there_are_no_notes(self):
|
||||
bookmark = self.setup_bookmark()
|
||||
response = self.client.get(reverse('bookmarks:edit', args=[bookmark.id]))
|
||||
|
||||
self.assertContains(response, '<details class="notes">', count=1)
|
||||
|
@@ -10,6 +10,8 @@ class BookmarkSearchTagTest(TestCase, BookmarkFactoryMixin):
|
||||
def render_template(self, url: str, tags: QuerySet[Tag] = Tag.objects.all()):
|
||||
rf = RequestFactory()
|
||||
request = rf.get(url)
|
||||
request.user = self.get_or_create_test_user()
|
||||
request.user_profile = self.get_or_create_test_user().profile
|
||||
filters = BookmarkFilters(request)
|
||||
context = RequestContext(request, {
|
||||
'request': request,
|
||||
|
@@ -10,7 +10,7 @@ from bookmarks.tests.helpers import BookmarkFactoryMixin
|
||||
|
||||
class BookmarkSharedViewTestCase(TestCase, BookmarkFactoryMixin):
|
||||
|
||||
def setUp(self) -> None:
|
||||
def authenticate(self) -> None:
|
||||
user = self.get_or_create_test_user()
|
||||
self.client.force_login(user)
|
||||
|
||||
@@ -65,6 +65,7 @@ class BookmarkSharedViewTestCase(TestCase, BookmarkFactoryMixin):
|
||||
''', html, count=0)
|
||||
|
||||
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)
|
||||
@@ -89,6 +90,7 @@ class BookmarkSharedViewTestCase(TestCase, BookmarkFactoryMixin):
|
||||
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)
|
||||
@@ -108,6 +110,7 @@ class BookmarkSharedViewTestCase(TestCase, BookmarkFactoryMixin):
|
||||
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),
|
||||
@@ -126,7 +129,29 @@ class BookmarkSharedViewTestCase(TestCase, BookmarkFactoryMixin):
|
||||
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'))
|
||||
|
||||
self.assertContains(response, '<ul class="bookmark-list">') # Should render list
|
||||
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)
|
||||
@@ -158,6 +183,7 @@ class BookmarkSharedViewTestCase(TestCase, BookmarkFactoryMixin):
|
||||
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)
|
||||
@@ -180,6 +206,7 @@ class BookmarkSharedViewTestCase(TestCase, BookmarkFactoryMixin):
|
||||
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)
|
||||
@@ -207,7 +234,32 @@ class BookmarkSharedViewTestCase(TestCase, BookmarkFactoryMixin):
|
||||
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(enable_sharing=True),
|
||||
self.setup_user(enable_sharing=True),
|
||||
@@ -226,30 +278,53 @@ class BookmarkSharedViewTestCase(TestCase, BookmarkFactoryMixin):
|
||||
self.assertVisibleUserOptions(response, expected_visible_users)
|
||||
self.assertInvisibleUserOptions(response, expected_invisible_users)
|
||||
|
||||
def test_should_list_only_users_with_publicly_shared_bookmarks_without_login(self):
|
||||
expected_visible_users = [
|
||||
self.setup_user(enable_sharing=True, enable_public_sharing=True),
|
||||
self.setup_user(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])
|
||||
|
||||
def test_should_open_bookmarks_in_new_page_by_default(self):
|
||||
visible_bookmarks = [
|
||||
self.setup_bookmark(shared=True),
|
||||
self.setup_bookmark(shared=True),
|
||||
self.setup_bookmark(shared=True)
|
||||
]
|
||||
expected_invisible_users = [
|
||||
self.setup_user(enable_sharing=True),
|
||||
self.setup_user(enable_sharing=True),
|
||||
]
|
||||
self.setup_bookmark(shared=True, user=expected_invisible_users[0])
|
||||
self.setup_bookmark(shared=True, user=expected_invisible_users[1])
|
||||
|
||||
response = self.client.get(reverse('bookmarks:shared'))
|
||||
response = self.client.get(reverse('bookmarks:shared'))
|
||||
self.assertVisibleUserOptions(response, expected_visible_users)
|
||||
self.assertInvisibleUserOptions(response, expected_invisible_users)
|
||||
|
||||
self.assertVisibleBookmarks(response, visible_bookmarks, '_blank')
|
||||
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'))
|
||||
|
||||
def test_should_open_bookmarks_in_same_page_if_specified_in_user_profile(self):
|
||||
user = self.get_or_create_test_user()
|
||||
user.profile.bookmark_link_target = UserProfile.BOOKMARK_LINK_TARGET_SELF
|
||||
user.profile.save()
|
||||
self.assertVisibleBookmarks(response, visible_bookmarks, '_blank')
|
||||
|
||||
visible_bookmarks = [
|
||||
self.setup_bookmark(shared=True),
|
||||
self.setup_bookmark(shared=True),
|
||||
self.setup_bookmark(shared=True)
|
||||
]
|
||||
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()
|
||||
|
||||
response = self.client.get(reverse('bookmarks:shared'))
|
||||
visible_bookmarks = [
|
||||
self.setup_bookmark(shared=True),
|
||||
self.setup_bookmark(shared=True),
|
||||
self.setup_bookmark(shared=True)
|
||||
]
|
||||
|
||||
self.assertVisibleBookmarks(response, visible_bookmarks, '_self')
|
||||
response = self.client.get(reverse('bookmarks:shared'))
|
||||
|
||||
self.assertVisibleBookmarks(response, visible_bookmarks, '_self')
|
||||
|
@@ -16,8 +16,6 @@ from bookmarks.tests.helpers import LinkdingApiTestCase, BookmarkFactoryMixin
|
||||
class BookmarksApiTestCase(LinkdingApiTestCase, BookmarkFactoryMixin):
|
||||
|
||||
def setUp(self) -> None:
|
||||
self.api_token = Token.objects.get_or_create(user=self.get_or_create_test_user())[0]
|
||||
self.client.credentials(HTTP_AUTHORIZATION='Token ' + self.api_token.key)
|
||||
self.tag1 = self.setup_tag()
|
||||
self.tag2 = self.setup_tag()
|
||||
self.bookmark1 = self.setup_bookmark(tags=[self.tag1, self.tag2], notes='Test notes')
|
||||
@@ -26,6 +24,10 @@ class BookmarksApiTestCase(LinkdingApiTestCase, BookmarkFactoryMixin):
|
||||
self.archived_bookmark1 = self.setup_bookmark(is_archived=True, tags=[self.tag1, self.tag2])
|
||||
self.archived_bookmark2 = self.setup_bookmark(is_archived=True)
|
||||
|
||||
def authenticate(self):
|
||||
self.api_token = Token.objects.get_or_create(user=self.get_or_create_test_user())[0]
|
||||
self.client.credentials(HTTP_AUTHORIZATION='Token ' + self.api_token.key)
|
||||
|
||||
def assertBookmarkListEqual(self, data_list, bookmarks):
|
||||
expectations = []
|
||||
for bookmark in bookmarks:
|
||||
@@ -53,24 +55,34 @@ class BookmarksApiTestCase(LinkdingApiTestCase, BookmarkFactoryMixin):
|
||||
self.assertCountEqual(data_list, expectations)
|
||||
|
||||
def test_list_bookmarks(self):
|
||||
self.authenticate()
|
||||
|
||||
response = self.get(reverse('bookmarks:bookmark-list'), expected_status_code=status.HTTP_200_OK)
|
||||
self.assertBookmarkListEqual(response.data['results'], [self.bookmark1, self.bookmark2, self.bookmark3])
|
||||
|
||||
def test_list_bookmarks_should_filter_by_query(self):
|
||||
self.authenticate()
|
||||
|
||||
response = self.get(reverse('bookmarks:bookmark-list') + '?q=#' + self.tag1.name,
|
||||
expected_status_code=status.HTTP_200_OK)
|
||||
self.assertBookmarkListEqual(response.data['results'], [self.bookmark1])
|
||||
|
||||
def test_list_archived_bookmarks_does_not_return_unarchived_bookmarks(self):
|
||||
self.authenticate()
|
||||
|
||||
response = self.get(reverse('bookmarks:bookmark-archived'), expected_status_code=status.HTTP_200_OK)
|
||||
self.assertBookmarkListEqual(response.data['results'], [self.archived_bookmark1, self.archived_bookmark2])
|
||||
|
||||
def test_list_archived_bookmarks_should_filter_by_query(self):
|
||||
self.authenticate()
|
||||
|
||||
response = self.get(reverse('bookmarks:bookmark-archived') + '?q=#' + self.tag1.name,
|
||||
expected_status_code=status.HTTP_200_OK)
|
||||
self.assertBookmarkListEqual(response.data['results'], [self.archived_bookmark1])
|
||||
|
||||
def test_list_shared_bookmarks(self):
|
||||
self.authenticate()
|
||||
|
||||
user1 = self.setup_user(enable_sharing=True)
|
||||
user2 = self.setup_user(enable_sharing=True)
|
||||
user3 = self.setup_user(enable_sharing=True)
|
||||
@@ -89,7 +101,23 @@ class BookmarksApiTestCase(LinkdingApiTestCase, BookmarkFactoryMixin):
|
||||
response = self.get(reverse('bookmarks:bookmark-shared'), expected_status_code=status.HTTP_200_OK)
|
||||
self.assertBookmarkListEqual(response.data['results'], shared_bookmarks)
|
||||
|
||||
def test_list_only_publicly_shared_bookmarks_when_not_logged_in(self):
|
||||
user1 = self.setup_user(enable_sharing=True, enable_public_sharing=True)
|
||||
user2 = self.setup_user(enable_sharing=True)
|
||||
|
||||
shared_bookmarks = [
|
||||
self.setup_bookmark(shared=True, user=user1),
|
||||
self.setup_bookmark(shared=True, user=user1)
|
||||
]
|
||||
self.setup_bookmark(shared=True, user=user2)
|
||||
self.setup_bookmark(shared=True, user=user2)
|
||||
|
||||
response = self.get(reverse('bookmarks:bookmark-shared'), expected_status_code=status.HTTP_200_OK)
|
||||
self.assertBookmarkListEqual(response.data['results'], shared_bookmarks)
|
||||
|
||||
def test_list_shared_bookmarks_should_filter_by_query_and_user(self):
|
||||
self.authenticate()
|
||||
|
||||
# Search by query
|
||||
user1 = self.setup_user(enable_sharing=True)
|
||||
user2 = self.setup_user(enable_sharing=True)
|
||||
@@ -131,6 +159,8 @@ class BookmarksApiTestCase(LinkdingApiTestCase, BookmarkFactoryMixin):
|
||||
self.assertBookmarkListEqual(response.data['results'], expected_bookmarks)
|
||||
|
||||
def test_create_bookmark(self):
|
||||
self.authenticate()
|
||||
|
||||
data = {
|
||||
'url': 'https://example.com/',
|
||||
'title': 'Test title',
|
||||
@@ -155,6 +185,8 @@ class BookmarksApiTestCase(LinkdingApiTestCase, BookmarkFactoryMixin):
|
||||
self.assertEqual(bookmark.tags.filter(name=data['tag_names'][1]).count(), 1)
|
||||
|
||||
def test_create_bookmark_with_same_url_updates_existing_bookmark(self):
|
||||
self.authenticate()
|
||||
|
||||
original_bookmark = self.setup_bookmark()
|
||||
data = {
|
||||
'url': original_bookmark.url,
|
||||
@@ -182,6 +214,8 @@ class BookmarksApiTestCase(LinkdingApiTestCase, BookmarkFactoryMixin):
|
||||
self.assertEqual(bookmark.tags.filter(name=data['tag_names'][1]).count(), 1)
|
||||
|
||||
def test_create_bookmark_replaces_whitespace_in_tag_names(self):
|
||||
self.authenticate()
|
||||
|
||||
data = {
|
||||
'url': 'https://example.com/',
|
||||
'title': 'Test title',
|
||||
@@ -194,10 +228,14 @@ class BookmarksApiTestCase(LinkdingApiTestCase, BookmarkFactoryMixin):
|
||||
self.assertListEqual(tag_names, ['tag-1', 'tag-2'])
|
||||
|
||||
def test_create_bookmark_minimal_payload(self):
|
||||
self.authenticate()
|
||||
|
||||
data = {'url': 'https://example.com/'}
|
||||
self.post(reverse('bookmarks:bookmark-list'), data, status.HTTP_201_CREATED)
|
||||
|
||||
def test_create_archived_bookmark(self):
|
||||
self.authenticate()
|
||||
|
||||
data = {
|
||||
'url': 'https://example.com/',
|
||||
'title': 'Test title',
|
||||
@@ -216,41 +254,55 @@ class BookmarksApiTestCase(LinkdingApiTestCase, BookmarkFactoryMixin):
|
||||
self.assertEqual(bookmark.tags.filter(name=data['tag_names'][1]).count(), 1)
|
||||
|
||||
def test_create_bookmark_is_not_archived_by_default(self):
|
||||
self.authenticate()
|
||||
|
||||
data = {'url': 'https://example.com/'}
|
||||
self.post(reverse('bookmarks:bookmark-list'), data, status.HTTP_201_CREATED)
|
||||
bookmark = Bookmark.objects.get(url=data['url'])
|
||||
self.assertFalse(bookmark.is_archived)
|
||||
|
||||
def test_create_unread_bookmark(self):
|
||||
self.authenticate()
|
||||
|
||||
data = {'url': 'https://example.com/', 'unread': True}
|
||||
self.post(reverse('bookmarks:bookmark-list'), data, status.HTTP_201_CREATED)
|
||||
bookmark = Bookmark.objects.get(url=data['url'])
|
||||
self.assertTrue(bookmark.unread)
|
||||
|
||||
def test_create_bookmark_is_not_unread_by_default(self):
|
||||
self.authenticate()
|
||||
|
||||
data = {'url': 'https://example.com/'}
|
||||
self.post(reverse('bookmarks:bookmark-list'), data, status.HTTP_201_CREATED)
|
||||
bookmark = Bookmark.objects.get(url=data['url'])
|
||||
self.assertFalse(bookmark.unread)
|
||||
|
||||
def test_create_shared_bookmark(self):
|
||||
self.authenticate()
|
||||
|
||||
data = {'url': 'https://example.com/', 'shared': True}
|
||||
self.post(reverse('bookmarks:bookmark-list'), data, status.HTTP_201_CREATED)
|
||||
bookmark = Bookmark.objects.get(url=data['url'])
|
||||
self.assertTrue(bookmark.shared)
|
||||
|
||||
def test_create_bookmark_is_not_shared_by_default(self):
|
||||
self.authenticate()
|
||||
|
||||
data = {'url': 'https://example.com/'}
|
||||
self.post(reverse('bookmarks:bookmark-list'), data, status.HTTP_201_CREATED)
|
||||
bookmark = Bookmark.objects.get(url=data['url'])
|
||||
self.assertFalse(bookmark.shared)
|
||||
|
||||
def test_get_bookmark(self):
|
||||
self.authenticate()
|
||||
|
||||
url = reverse('bookmarks:bookmark-detail', args=[self.bookmark1.id])
|
||||
response = self.get(url, expected_status_code=status.HTTP_200_OK)
|
||||
self.assertBookmarkListEqual([response.data], [self.bookmark1])
|
||||
|
||||
def test_update_bookmark(self):
|
||||
self.authenticate()
|
||||
|
||||
data = {'url': 'https://example.com/'}
|
||||
url = reverse('bookmarks:bookmark-detail', args=[self.bookmark1.id])
|
||||
self.put(url, data, expected_status_code=status.HTTP_200_OK)
|
||||
@@ -258,11 +310,15 @@ class BookmarksApiTestCase(LinkdingApiTestCase, BookmarkFactoryMixin):
|
||||
self.assertEqual(updated_bookmark.url, data['url'])
|
||||
|
||||
def test_update_bookmark_fails_without_required_fields(self):
|
||||
self.authenticate()
|
||||
|
||||
data = {'title': 'https://example.com/'}
|
||||
url = reverse('bookmarks:bookmark-detail', args=[self.bookmark1.id])
|
||||
self.put(url, data, expected_status_code=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
def test_update_bookmark_with_minimal_payload_clears_all_fields(self):
|
||||
self.authenticate()
|
||||
|
||||
data = {'url': 'https://example.com/'}
|
||||
url = reverse('bookmarks:bookmark-detail', args=[self.bookmark1.id])
|
||||
self.put(url, data, expected_status_code=status.HTTP_200_OK)
|
||||
@@ -274,6 +330,8 @@ class BookmarksApiTestCase(LinkdingApiTestCase, BookmarkFactoryMixin):
|
||||
self.assertEqual(updated_bookmark.tag_names, [])
|
||||
|
||||
def test_update_bookmark_unread_flag(self):
|
||||
self.authenticate()
|
||||
|
||||
data = {'url': 'https://example.com/', 'unread': True}
|
||||
url = reverse('bookmarks:bookmark-detail', args=[self.bookmark1.id])
|
||||
self.put(url, data, expected_status_code=status.HTTP_200_OK)
|
||||
@@ -281,6 +339,8 @@ class BookmarksApiTestCase(LinkdingApiTestCase, BookmarkFactoryMixin):
|
||||
self.assertEqual(updated_bookmark.unread, True)
|
||||
|
||||
def test_update_bookmark_shared_flag(self):
|
||||
self.authenticate()
|
||||
|
||||
data = {'url': 'https://example.com/', 'shared': True}
|
||||
url = reverse('bookmarks:bookmark-detail', args=[self.bookmark1.id])
|
||||
self.put(url, data, expected_status_code=status.HTTP_200_OK)
|
||||
@@ -288,6 +348,8 @@ class BookmarksApiTestCase(LinkdingApiTestCase, BookmarkFactoryMixin):
|
||||
self.assertEqual(updated_bookmark.shared, True)
|
||||
|
||||
def test_patch_bookmark(self):
|
||||
self.authenticate()
|
||||
|
||||
data = {'url': 'https://example.com'}
|
||||
url = reverse('bookmarks:bookmark-detail', args=[self.bookmark1.id])
|
||||
self.patch(url, data, expected_status_code=status.HTTP_200_OK)
|
||||
@@ -344,6 +406,8 @@ class BookmarksApiTestCase(LinkdingApiTestCase, BookmarkFactoryMixin):
|
||||
self.assertListEqual(tag_names, ['updated-tag-1', 'updated-tag-2'])
|
||||
|
||||
def test_patch_with_empty_payload_does_not_modify_bookmark(self):
|
||||
self.authenticate()
|
||||
|
||||
url = reverse('bookmarks:bookmark-detail', args=[self.bookmark1.id])
|
||||
self.patch(url, {}, expected_status_code=status.HTTP_200_OK)
|
||||
updated_bookmark = Bookmark.objects.get(id=self.bookmark1.id)
|
||||
@@ -353,23 +417,31 @@ class BookmarksApiTestCase(LinkdingApiTestCase, BookmarkFactoryMixin):
|
||||
self.assertListEqual(updated_bookmark.tag_names, self.bookmark1.tag_names)
|
||||
|
||||
def test_delete_bookmark(self):
|
||||
self.authenticate()
|
||||
|
||||
url = reverse('bookmarks:bookmark-detail', args=[self.bookmark1.id])
|
||||
self.delete(url, expected_status_code=status.HTTP_204_NO_CONTENT)
|
||||
self.assertEqual(len(Bookmark.objects.filter(id=self.bookmark1.id)), 0)
|
||||
|
||||
def test_archive(self):
|
||||
self.authenticate()
|
||||
|
||||
url = reverse('bookmarks:bookmark-archive', args=[self.bookmark1.id])
|
||||
self.post(url, expected_status_code=status.HTTP_204_NO_CONTENT)
|
||||
bookmark = Bookmark.objects.get(id=self.bookmark1.id)
|
||||
self.assertTrue(bookmark.is_archived)
|
||||
|
||||
def test_unarchive(self):
|
||||
self.authenticate()
|
||||
|
||||
url = reverse('bookmarks:bookmark-unarchive', args=[self.archived_bookmark1.id])
|
||||
self.post(url, expected_status_code=status.HTTP_204_NO_CONTENT)
|
||||
bookmark = Bookmark.objects.get(id=self.archived_bookmark1.id)
|
||||
self.assertFalse(bookmark.is_archived)
|
||||
|
||||
def test_check_returns_no_bookmark_if_url_is_not_bookmarked(self):
|
||||
self.authenticate()
|
||||
|
||||
url = reverse('bookmarks:bookmark-check')
|
||||
check_url = urllib.parse.quote_plus('https://example.com')
|
||||
response = self.get(f'{url}?url={check_url}', expected_status_code=status.HTTP_200_OK)
|
||||
@@ -378,6 +450,8 @@ class BookmarksApiTestCase(LinkdingApiTestCase, BookmarkFactoryMixin):
|
||||
self.assertIsNone(bookmark_data)
|
||||
|
||||
def test_check_returns_scraped_metadata_if_url_is_not_bookmarked(self):
|
||||
self.authenticate()
|
||||
|
||||
with patch.object(website_loader, 'load_website_metadata') as mock_load_website_metadata:
|
||||
expected_metadata = WebsiteMetadata(
|
||||
'https://example.com',
|
||||
@@ -397,6 +471,8 @@ class BookmarksApiTestCase(LinkdingApiTestCase, BookmarkFactoryMixin):
|
||||
self.assertIsNotNone(expected_metadata.description, metadata['description'])
|
||||
|
||||
def test_check_returns_bookmark_if_url_is_bookmarked(self):
|
||||
self.authenticate()
|
||||
|
||||
bookmark = self.setup_bookmark(url='https://example.com',
|
||||
title='Example title',
|
||||
description='Example description')
|
||||
@@ -413,6 +489,8 @@ class BookmarksApiTestCase(LinkdingApiTestCase, BookmarkFactoryMixin):
|
||||
self.assertEqual(bookmark.description, bookmark_data['description'])
|
||||
|
||||
def test_check_returns_existing_metadata_if_url_is_bookmarked(self):
|
||||
self.authenticate()
|
||||
|
||||
bookmark = self.setup_bookmark(url='https://example.com',
|
||||
website_title='Existing title',
|
||||
website_description='Existing description')
|
||||
@@ -430,6 +508,8 @@ class BookmarksApiTestCase(LinkdingApiTestCase, BookmarkFactoryMixin):
|
||||
self.assertIsNotNone(bookmark.website_description, metadata['description'])
|
||||
|
||||
def test_can_only_access_own_bookmarks(self):
|
||||
self.authenticate()
|
||||
|
||||
other_user = User.objects.create_user('otheruser', 'otheruser@example.com', 'password123')
|
||||
inaccessible_bookmark = self.setup_bookmark(user=other_user)
|
||||
inaccessible_shared_bookmark = self.setup_bookmark(user=other_user, shared=True)
|
||||
|
113
bookmarks/tests/test_bookmarks_api_permissions.py
Normal file
113
bookmarks/tests/test_bookmarks_api_permissions.py
Normal file
@@ -0,0 +1,113 @@
|
||||
import urllib.parse
|
||||
|
||||
from django.urls import reverse
|
||||
from rest_framework import status
|
||||
from rest_framework.authtoken.models import Token
|
||||
|
||||
from bookmarks.tests.helpers import LinkdingApiTestCase, BookmarkFactoryMixin
|
||||
|
||||
|
||||
class BookmarksApiPermissionsTestCase(LinkdingApiTestCase, BookmarkFactoryMixin):
|
||||
def authenticate(self) -> None:
|
||||
self.api_token = Token.objects.get_or_create(user=self.get_or_create_test_user())[0]
|
||||
self.client.credentials(HTTP_AUTHORIZATION='Token ' + self.api_token.key)
|
||||
|
||||
def test_list_bookmarks_requires_authentication(self):
|
||||
self.get(reverse('bookmarks:bookmark-list'), expected_status_code=status.HTTP_401_UNAUTHORIZED)
|
||||
|
||||
self.authenticate()
|
||||
self.get(reverse('bookmarks:bookmark-list'), expected_status_code=status.HTTP_200_OK)
|
||||
|
||||
def test_list_archived_bookmarks_requires_authentication(self):
|
||||
self.get(reverse('bookmarks:bookmark-archived'), expected_status_code=status.HTTP_401_UNAUTHORIZED)
|
||||
|
||||
self.authenticate()
|
||||
self.get(reverse('bookmarks:bookmark-archived'), expected_status_code=status.HTTP_200_OK)
|
||||
|
||||
def test_list_shared_bookmarks_does_not_require_authentication(self):
|
||||
self.get(reverse('bookmarks:bookmark-shared'), expected_status_code=status.HTTP_200_OK)
|
||||
|
||||
self.authenticate()
|
||||
self.get(reverse('bookmarks:bookmark-shared'), expected_status_code=status.HTTP_200_OK)
|
||||
|
||||
def test_create_bookmark_requires_authentication(self):
|
||||
data = {
|
||||
'url': 'https://example.com/',
|
||||
'title': 'Test title',
|
||||
'description': 'Test description',
|
||||
'notes': 'Test notes',
|
||||
'is_archived': False,
|
||||
'unread': False,
|
||||
'shared': False,
|
||||
'tag_names': ['tag1', 'tag2']
|
||||
}
|
||||
|
||||
self.post(reverse('bookmarks:bookmark-list'), data, status.HTTP_401_UNAUTHORIZED)
|
||||
|
||||
self.authenticate()
|
||||
self.post(reverse('bookmarks:bookmark-list'), data, status.HTTP_201_CREATED)
|
||||
|
||||
def test_get_bookmark_requires_authentication(self):
|
||||
bookmark = self.setup_bookmark()
|
||||
url = reverse('bookmarks:bookmark-detail', args=[bookmark.id])
|
||||
|
||||
self.get(url, expected_status_code=status.HTTP_401_UNAUTHORIZED)
|
||||
|
||||
self.authenticate()
|
||||
self.get(url, expected_status_code=status.HTTP_200_OK)
|
||||
|
||||
def test_update_bookmark_requires_authentication(self):
|
||||
bookmark = self.setup_bookmark()
|
||||
data = {'url': 'https://example.com/'}
|
||||
url = reverse('bookmarks:bookmark-detail', args=[bookmark.id])
|
||||
|
||||
self.put(url, data, expected_status_code=status.HTTP_401_UNAUTHORIZED)
|
||||
|
||||
self.authenticate()
|
||||
self.put(url, data, expected_status_code=status.HTTP_200_OK)
|
||||
|
||||
def test_patch_bookmark_requires_authentication(self):
|
||||
bookmark = self.setup_bookmark()
|
||||
data = {'url': 'https://example.com'}
|
||||
url = reverse('bookmarks:bookmark-detail', args=[bookmark.id])
|
||||
|
||||
self.patch(url, data, expected_status_code=status.HTTP_401_UNAUTHORIZED)
|
||||
|
||||
self.authenticate()
|
||||
self.patch(url, data, expected_status_code=status.HTTP_200_OK)
|
||||
|
||||
def test_delete_bookmark_requires_authentication(self):
|
||||
bookmark = self.setup_bookmark()
|
||||
url = reverse('bookmarks:bookmark-detail', args=[bookmark.id])
|
||||
|
||||
self.delete(url, expected_status_code=status.HTTP_401_UNAUTHORIZED)
|
||||
|
||||
self.authenticate()
|
||||
self.delete(url, expected_status_code=status.HTTP_204_NO_CONTENT)
|
||||
|
||||
def test_archive_requires_authentication(self):
|
||||
bookmark = self.setup_bookmark()
|
||||
url = reverse('bookmarks:bookmark-archive', args=[bookmark.id])
|
||||
|
||||
self.post(url, expected_status_code=status.HTTP_401_UNAUTHORIZED)
|
||||
|
||||
self.authenticate()
|
||||
self.post(url, expected_status_code=status.HTTP_204_NO_CONTENT)
|
||||
|
||||
def test_unarchive_requires_authentication(self):
|
||||
bookmark = self.setup_bookmark(is_archived=True)
|
||||
url = reverse('bookmarks:bookmark-unarchive', args=[bookmark.id])
|
||||
|
||||
self.post(url, expected_status_code=status.HTTP_401_UNAUTHORIZED)
|
||||
|
||||
self.authenticate()
|
||||
self.post(url, expected_status_code=status.HTTP_204_NO_CONTENT)
|
||||
|
||||
def test_check_requires_authentication(self):
|
||||
url = reverse('bookmarks:bookmark-check')
|
||||
check_url = urllib.parse.quote_plus('https://example.com')
|
||||
|
||||
self.get(f'{url}?url={check_url}', expected_status_code=status.HTTP_401_UNAUTHORIZED)
|
||||
|
||||
self.authenticate()
|
||||
self.get(f'{url}?url={check_url}', expected_status_code=status.HTTP_200_OK)
|
@@ -1,5 +1,7 @@
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from django.contrib.auth.models import AnonymousUser
|
||||
from django.core.paginator import Paginator
|
||||
from django.http import HttpResponse
|
||||
from django.template import Template, RequestContext
|
||||
from django.test import TestCase, RequestFactory
|
||||
from django.urls import reverse
|
||||
@@ -7,17 +9,23 @@ from django.utils import timezone, formats
|
||||
|
||||
from bookmarks.models import Bookmark, UserProfile, User
|
||||
from bookmarks.tests.helpers import BookmarkFactoryMixin
|
||||
from bookmarks.middlewares import UserProfileMiddleware
|
||||
|
||||
|
||||
class BookmarkListTagTest(TestCase, BookmarkFactoryMixin):
|
||||
|
||||
def assertBookmarksLink(self, html: str, bookmark: Bookmark, link_target: str = '_blank', unread: bool = False):
|
||||
def assertBookmarksLink(self, html: str, bookmark: Bookmark, link_target: str = '_blank'):
|
||||
unread = bookmark.unread
|
||||
favicon_img = f'<img src="/static/{bookmark.favicon_file}" alt="">' if bookmark.favicon_file else ''
|
||||
self.assertInHTML(
|
||||
f'''
|
||||
<a href="{bookmark.url}"
|
||||
target="{link_target}"
|
||||
rel="noopener"
|
||||
class="{'text-italic' if unread else ''}">{bookmark.resolved_title}</a>
|
||||
class="{'text-italic' if unread else ''}">
|
||||
{favicon_img}
|
||||
{bookmark.resolved_title}
|
||||
</a>
|
||||
''',
|
||||
html
|
||||
)
|
||||
@@ -130,22 +138,26 @@ class BookmarkListTagTest(TestCase, BookmarkFactoryMixin):
|
||||
</button>
|
||||
''', html, count=count)
|
||||
|
||||
def render_template(self, bookmarks: [Bookmark], template: Template, url: str = '/test') -> str:
|
||||
def render_template(self, bookmarks: [Bookmark], template: Template, url: str = '/test',
|
||||
user: User | AnonymousUser = None) -> str:
|
||||
rf = RequestFactory()
|
||||
request = rf.get(url)
|
||||
request.user = self.get_or_create_test_user()
|
||||
request.user = user or self.get_or_create_test_user()
|
||||
middleware = UserProfileMiddleware(lambda r: HttpResponse())
|
||||
middleware(request)
|
||||
paginator = Paginator(bookmarks, 10)
|
||||
page = paginator.page(1)
|
||||
|
||||
context = RequestContext(request, {'bookmarks': page, 'return_url': '/test'})
|
||||
return template.render(context)
|
||||
|
||||
def render_default_template(self, bookmarks: [Bookmark], url: str = '/test') -> str:
|
||||
def render_default_template(self, bookmarks: [Bookmark], url: str = '/test',
|
||||
user: User | AnonymousUser = None) -> str:
|
||||
template = Template(
|
||||
'{% load bookmarks %}'
|
||||
'{% bookmark_list bookmarks return_url %}'
|
||||
)
|
||||
return self.render_template(bookmarks, template, url)
|
||||
return self.render_template(bookmarks, template, url, user)
|
||||
|
||||
def render_template_with_link_target(self, bookmarks: [Bookmark], link_target: str) -> str:
|
||||
template = Template(
|
||||
@@ -211,11 +223,11 @@ class BookmarkListTagTest(TestCase, BookmarkFactoryMixin):
|
||||
def test_bookmark_link_target_should_respect_unread_flag(self):
|
||||
bookmark = self.setup_bookmark()
|
||||
html = self.render_template_with_link_target([bookmark], '_self')
|
||||
self.assertBookmarksLink(html, bookmark, link_target='_self', unread=False)
|
||||
self.assertBookmarksLink(html, bookmark, link_target='_self')
|
||||
|
||||
bookmark = self.setup_bookmark(unread=True)
|
||||
html = self.render_template_with_link_target([bookmark], '_self')
|
||||
self.assertBookmarksLink(html, bookmark, link_target='_self', unread=True)
|
||||
self.assertBookmarksLink(html, bookmark, link_target='_self')
|
||||
|
||||
def test_web_archive_link_target_should_be_blank_by_default(self):
|
||||
bookmark = self.setup_bookmark()
|
||||
@@ -402,3 +414,20 @@ class BookmarkListTagTest(TestCase, BookmarkFactoryMixin):
|
||||
html = self.render_default_template([bookmark])
|
||||
|
||||
self.assertNotesToggle(html, 0)
|
||||
|
||||
def test_with_anonymous_user(self):
|
||||
bookmark = self.setup_bookmark()
|
||||
bookmark.date_added = timezone.now() - relativedelta(days=8)
|
||||
bookmark.web_archive_snapshot_url = 'https://web.archive.org/web/20230531200136/https://example.com'
|
||||
bookmark.notes = '**Example:** `print("Hello world!")`'
|
||||
bookmark.favicon_file = 'https_example_com.png'
|
||||
bookmark.save()
|
||||
|
||||
html = self.render_default_template([bookmark], '/test', AnonymousUser())
|
||||
self.assertBookmarksLink(html, bookmark, link_target='_blank')
|
||||
self.assertWebArchiveLink(html, '1 week ago', bookmark.web_archive_snapshot_url, link_target='_blank')
|
||||
self.assertNoBookmarkActions(html, bookmark)
|
||||
self.assertShareInfo(html, bookmark)
|
||||
note_html = '<p><strong>Example:</strong> <code>print("Hello world!")</code></p>'
|
||||
self.assertNotes(html, note_html, 1)
|
||||
self.assertFaviconVisible(html, bookmark)
|
||||
|
@@ -1,13 +1,17 @@
|
||||
from django.core.paginator import Paginator
|
||||
from django.template import Template, RequestContext
|
||||
from django.test import SimpleTestCase, RequestFactory
|
||||
from django.test import TestCase, RequestFactory
|
||||
|
||||
from bookmarks.tests.helpers import BookmarkFactoryMixin
|
||||
|
||||
|
||||
class PaginationTagTest(SimpleTestCase):
|
||||
class PaginationTagTest(TestCase, BookmarkFactoryMixin):
|
||||
|
||||
def render_template(self, num_items: int, page_size: int, current_page: int, url: str = '/test') -> str:
|
||||
rf = RequestFactory()
|
||||
request = rf.get(url)
|
||||
request.user = self.get_or_create_test_user()
|
||||
request.user_profile = self.get_or_create_test_user().profile
|
||||
paginator = Paginator(range(0, num_items), page_size)
|
||||
page = paginator.page(current_page)
|
||||
|
||||
|
@@ -679,16 +679,26 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
||||
self.setup_bookmark(user=user4, shared=True, tags=[tag]),
|
||||
|
||||
# Should return shared bookmarks from all users
|
||||
query_set = queries.query_shared_bookmarks(None, self.profile, '')
|
||||
query_set = queries.query_shared_bookmarks(None, self.profile, '', False)
|
||||
self.assertQueryResult(query_set, [shared_bookmarks])
|
||||
|
||||
# Should respect search query
|
||||
query_set = queries.query_shared_bookmarks(None, self.profile, 'test title')
|
||||
query_set = queries.query_shared_bookmarks(None, self.profile, 'test title', False)
|
||||
self.assertQueryResult(query_set, [[shared_bookmarks[0]]])
|
||||
|
||||
query_set = queries.query_shared_bookmarks(None, self.profile, '#' + tag.name)
|
||||
query_set = queries.query_shared_bookmarks(None, self.profile, '#' + tag.name, False)
|
||||
self.assertQueryResult(query_set, [[shared_bookmarks[2]]])
|
||||
|
||||
def test_query_publicly_shared_bookmarks(self):
|
||||
user1 = self.setup_user(enable_sharing=True, enable_public_sharing=True)
|
||||
user2 = self.setup_user(enable_sharing=True)
|
||||
|
||||
bookmark1 = self.setup_bookmark(user=user1, shared=True)
|
||||
self.setup_bookmark(user=user2, shared=True)
|
||||
|
||||
query_set = queries.query_shared_bookmarks(None, self.profile, '', True)
|
||||
self.assertQueryResult(query_set, [[bookmark1]])
|
||||
|
||||
def test_query_shared_bookmark_tags(self):
|
||||
user1 = self.setup_user(enable_sharing=True)
|
||||
user2 = self.setup_user(enable_sharing=True)
|
||||
@@ -710,10 +720,24 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
||||
self.setup_bookmark(user=user3, shared=False, tags=[self.setup_tag(user=user3)]),
|
||||
self.setup_bookmark(user=user4, shared=True, tags=[self.setup_tag(user=user4)]),
|
||||
|
||||
query_set = queries.query_shared_bookmark_tags(None, self.profile, '')
|
||||
query_set = queries.query_shared_bookmark_tags(None, self.profile, '', False)
|
||||
|
||||
self.assertQueryResult(query_set, [shared_tags])
|
||||
|
||||
def test_query_publicly_shared_bookmark_tags(self):
|
||||
user1 = self.setup_user(enable_sharing=True, enable_public_sharing=True)
|
||||
user2 = self.setup_user(enable_sharing=True)
|
||||
|
||||
tag1 = self.setup_tag(user=user1)
|
||||
tag2 = self.setup_tag(user=user2)
|
||||
|
||||
self.setup_bookmark(user=user1, shared=True, tags=[tag1]),
|
||||
self.setup_bookmark(user=user2, shared=True, tags=[tag2]),
|
||||
|
||||
query_set = queries.query_shared_bookmark_tags(None, self.profile, '', True)
|
||||
|
||||
self.assertQueryResult(query_set, [[tag1]])
|
||||
|
||||
def test_query_shared_bookmark_users(self):
|
||||
users_with_shared_bookmarks = [
|
||||
self.setup_user(enable_sharing=True),
|
||||
@@ -735,9 +759,19 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
|
||||
self.setup_bookmark(user=users_without_shared_bookmarks[2], shared=True),
|
||||
|
||||
# Should return users with shared bookmarks
|
||||
query_set = queries.query_shared_bookmark_users(self.profile, '')
|
||||
query_set = queries.query_shared_bookmark_users(self.profile, '', False)
|
||||
self.assertQueryResult(query_set, [users_with_shared_bookmarks])
|
||||
|
||||
# Should respect search query
|
||||
query_set = queries.query_shared_bookmark_users(self.profile, 'test title')
|
||||
query_set = queries.query_shared_bookmark_users(self.profile, 'test title', False)
|
||||
self.assertQueryResult(query_set, [[users_with_shared_bookmarks[0]]])
|
||||
|
||||
def test_query_publicly_shared_bookmark_users(self):
|
||||
user1 = self.setup_user(enable_sharing=True, enable_public_sharing=True)
|
||||
user2 = self.setup_user(enable_sharing=True)
|
||||
|
||||
self.setup_bookmark(user=user1, shared=True)
|
||||
self.setup_bookmark(user=user2, shared=True)
|
||||
|
||||
query_set = queries.query_shared_bookmark_users(self.profile, '', True)
|
||||
self.assertQueryResult(query_set, [[user1]])
|
||||
|
@@ -27,6 +27,7 @@ class SettingsGeneralViewTestCase(TestCase, BookmarkFactoryMixin):
|
||||
'bookmark_link_target': UserProfile.BOOKMARK_LINK_TARGET_BLANK,
|
||||
'web_archive_integration': UserProfile.WEB_ARCHIVE_INTEGRATION_DISABLED,
|
||||
'enable_sharing': False,
|
||||
'enable_public_sharing': False,
|
||||
'enable_favicons': False,
|
||||
'tag_search': UserProfile.TAG_SEARCH_STRICT,
|
||||
'display_url': False,
|
||||
@@ -54,6 +55,7 @@ class SettingsGeneralViewTestCase(TestCase, BookmarkFactoryMixin):
|
||||
'bookmark_link_target': UserProfile.BOOKMARK_LINK_TARGET_SELF,
|
||||
'web_archive_integration': UserProfile.WEB_ARCHIVE_INTEGRATION_ENABLED,
|
||||
'enable_sharing': True,
|
||||
'enable_public_sharing': True,
|
||||
'enable_favicons': True,
|
||||
'tag_search': UserProfile.TAG_SEARCH_LAX,
|
||||
'display_url': True,
|
||||
@@ -70,6 +72,7 @@ class SettingsGeneralViewTestCase(TestCase, BookmarkFactoryMixin):
|
||||
self.assertEqual(self.user.profile.bookmark_link_target, form_data['bookmark_link_target'])
|
||||
self.assertEqual(self.user.profile.web_archive_integration, form_data['web_archive_integration'])
|
||||
self.assertEqual(self.user.profile.enable_sharing, form_data['enable_sharing'])
|
||||
self.assertEqual(self.user.profile.enable_public_sharing, form_data['enable_public_sharing'])
|
||||
self.assertEqual(self.user.profile.enable_favicons, form_data['enable_favicons'])
|
||||
self.assertEqual(self.user.profile.tag_search, form_data['tag_search'])
|
||||
self.assertEqual(self.user.profile.display_url, form_data['display_url'])
|
||||
|
@@ -1,20 +1,26 @@
|
||||
from typing import List
|
||||
|
||||
from django.contrib.auth.models import User, AnonymousUser
|
||||
from django.http import HttpResponse
|
||||
from django.template import Template, RequestContext
|
||||
from django.test import TestCase, RequestFactory
|
||||
|
||||
from bookmarks.middlewares import UserProfileMiddleware
|
||||
from bookmarks.models import Tag, UserProfile
|
||||
from bookmarks.tests.helpers import BookmarkFactoryMixin, HtmlTestMixin
|
||||
|
||||
|
||||
class TagCloudTagTest(TestCase, BookmarkFactoryMixin, HtmlTestMixin):
|
||||
def render_template(self, tags: List[Tag], selected_tags: List[Tag] = None, url: str = '/test'):
|
||||
def render_template(self, tags: List[Tag], selected_tags: List[Tag] = None, url: str = '/test',
|
||||
user: User | AnonymousUser = None):
|
||||
if not selected_tags:
|
||||
selected_tags = []
|
||||
|
||||
rf = RequestFactory()
|
||||
request = rf.get(url)
|
||||
request.user = self.get_or_create_test_user()
|
||||
request.user = user or self.get_or_create_test_user()
|
||||
middleware = UserProfileMiddleware(lambda r: HttpResponse())
|
||||
middleware(request)
|
||||
context = RequestContext(request, {
|
||||
'request': request,
|
||||
'tags': tags,
|
||||
@@ -209,3 +215,37 @@ class TagCloudTagTest(TestCase, BookmarkFactoryMixin, HtmlTestMixin):
|
||||
self.assertTagGroups(rendered_template, [
|
||||
['tag3', 'tag4', 'tag5']
|
||||
])
|
||||
|
||||
def test_with_anonymous_user(self):
|
||||
tags = [
|
||||
self.setup_tag(name='tag1'),
|
||||
self.setup_tag(name='tag2'),
|
||||
self.setup_tag(name='tag3'),
|
||||
self.setup_tag(name='tag4'),
|
||||
self.setup_tag(name='tag5'),
|
||||
]
|
||||
selected_tags = [
|
||||
tags[0],
|
||||
tags[1],
|
||||
]
|
||||
|
||||
rendered_template = self.render_template(tags, selected_tags, url='/test?q=%23tag1 %23tag2',
|
||||
user=AnonymousUser())
|
||||
|
||||
self.assertTagGroups(rendered_template, [
|
||||
['tag3', 'tag4', 'tag5']
|
||||
])
|
||||
self.assertNumSelectedTags(rendered_template, 2)
|
||||
self.assertInHTML('''
|
||||
<a href="?q=%23tag2"
|
||||
class="text-bold mr-2">
|
||||
<span>-tag1</span>
|
||||
</a>
|
||||
''', rendered_template)
|
||||
|
||||
self.assertInHTML('''
|
||||
<a href="?q=%23tag1"
|
||||
class="text-bold mr-2">
|
||||
<span>-tag2</span>
|
||||
</a>
|
||||
''', rendered_template)
|
||||
|
@@ -10,6 +10,8 @@ class UserSelectTagTest(TestCase, BookmarkFactoryMixin):
|
||||
def render_template(self, url: str, users: QuerySet[User] = User.objects.all()):
|
||||
rf = RequestFactory()
|
||||
request = rf.get(url)
|
||||
request.user = self.get_or_create_test_user()
|
||||
request.user_profile = self.get_or_create_test_user().profile
|
||||
filters = BookmarkFilters(request)
|
||||
context = RequestContext(request, {
|
||||
'request': request,
|
||||
|
Reference in New Issue
Block a user