import datetime import email import urllib.parse from django.test import TestCase from django.urls import reverse from bookmarks.tests.helpers import BookmarkFactoryMixin from bookmarks.models import FeedToken, User from bookmarks.feeds import sanitize def rfc2822_date(date): if not isinstance(date, datetime.datetime): date = datetime.datetime.combine(date, datetime.time()) return email.utils.format_datetime(date) class FeedsTestCase(TestCase, BookmarkFactoryMixin): def setUp(self) -> None: user = self.get_or_create_test_user() self.client.force_login(user) self.token = FeedToken.objects.get_or_create(user=user)[0] def test_all_returns_404_for_unknown_feed_token(self): response = self.client.get(reverse("bookmarks:feeds.all", args=["foo"])) self.assertEqual(response.status_code, 404) def test_all_metadata(self): feed_url = reverse("bookmarks:feeds.all", args=[self.token.key]) response = self.client.get(feed_url) self.assertEqual(response.status_code, 200) self.assertContains(response, "All bookmarks") self.assertContains(response, "All bookmarks") self.assertContains(response, f"http://testserver{feed_url}") self.assertContains( response, f'' ) def test_all_returns_all_unarchived_bookmarks(self): bookmarks = [ self.setup_bookmark(description="test description"), self.setup_bookmark(website_description="test website description"), self.setup_bookmark(unread=True, description="test description"), ] self.setup_bookmark(is_archived=True) self.setup_bookmark(is_archived=True) self.setup_bookmark(is_archived=True) response = self.client.get( reverse("bookmarks:feeds.all", args=[self.token.key]) ) self.assertEqual(response.status_code, 200) self.assertContains(response, "", count=len(bookmarks)) for bookmark in bookmarks: expected_item = ( "" f"{bookmark.resolved_title}" f"{bookmark.url}" f"{bookmark.resolved_description}" f"{rfc2822_date(bookmark.date_added)}" f"{bookmark.url}" "" ) self.assertContains(response, expected_item, count=1) def test_all_with_query(self): tag1 = self.setup_tag() bookmark1 = self.setup_bookmark() bookmark2 = self.setup_bookmark(tags=[tag1]) bookmark3 = self.setup_bookmark(tags=[tag1]) self.setup_bookmark() self.setup_bookmark() self.setup_bookmark() feed_url = reverse("bookmarks:feeds.all", args=[self.token.key]) url = feed_url + f"?q={bookmark1.title}" response = self.client.get(url) self.assertEqual(response.status_code, 200) self.assertContains(response, "", count=1) self.assertContains(response, f"{bookmark1.url}", count=1) url = feed_url + "?q=" + urllib.parse.quote("#" + tag1.name) response = self.client.get(url) self.assertEqual(response.status_code, 200) self.assertContains(response, "", count=2) self.assertContains(response, f"{bookmark2.url}", count=1) self.assertContains(response, f"{bookmark3.url}", count=1) url = feed_url + "?q=" + urllib.parse.quote(f"#{tag1.name} {bookmark2.title}") response = self.client.get(url) self.assertEqual(response.status_code, 200) self.assertContains(response, "", count=1) self.assertContains(response, f"{bookmark2.url}", count=1) def test_all_returns_only_user_owned_bookmarks(self): other_user = User.objects.create_user( "otheruser", "otheruser@example.com", "password123" ) self.setup_bookmark(unread=True, user=other_user) self.setup_bookmark(unread=True, user=other_user) self.setup_bookmark(unread=True, user=other_user) response = self.client.get( reverse("bookmarks:feeds.all", args=[self.token.key]) ) self.assertEqual(response.status_code, 200) self.assertContains(response, "", count=0) def test_strip_control_characters(self): self.setup_bookmark( title="test\n\r\t\0\x08title", description="test\n\r\t\0\x08description" ) response = self.client.get( reverse("bookmarks:feeds.all", args=[self.token.key]) ) self.assertEqual(response.status_code, 200) self.assertContains(response, "", count=1) self.assertContains(response, f"test\n\r\ttitle", count=1) self.assertContains( response, f"test\n\r\tdescription", count=1 ) def test_sanitize_with_none_text(self): self.assertEqual("", sanitize(None)) def test_unread_returns_404_for_unknown_feed_token(self): response = self.client.get(reverse("bookmarks:feeds.unread", args=["foo"])) self.assertEqual(response.status_code, 404) def test_unread_metadata(self): feed_url = reverse("bookmarks:feeds.unread", args=[self.token.key]) response = self.client.get(feed_url) self.assertEqual(response.status_code, 200) self.assertContains(response, "Unread bookmarks") self.assertContains(response, "All unread bookmarks") self.assertContains(response, f"http://testserver{feed_url}") self.assertContains( response, f'' ) def test_unread_returns_unread_and_unarchived_bookmarks(self): self.setup_bookmark(unread=False) self.setup_bookmark(unread=False) self.setup_bookmark(unread=False) self.setup_bookmark(unread=True, is_archived=True) self.setup_bookmark(unread=True, is_archived=True) self.setup_bookmark(unread=False, is_archived=True) unread_bookmarks = [ self.setup_bookmark(unread=True, description="test description"), self.setup_bookmark( unread=True, website_description="test website description" ), self.setup_bookmark(unread=True, description="test description"), ] response = self.client.get( reverse("bookmarks:feeds.unread", args=[self.token.key]) ) self.assertEqual(response.status_code, 200) self.assertContains(response, "", count=len(unread_bookmarks)) for bookmark in unread_bookmarks: expected_item = ( "" f"{bookmark.resolved_title}" f"{bookmark.url}" f"{bookmark.resolved_description}" f"{rfc2822_date(bookmark.date_added)}" f"{bookmark.url}" "" ) self.assertContains(response, expected_item, count=1) def test_unread_with_query(self): tag1 = self.setup_tag() bookmark1 = self.setup_bookmark(unread=True) bookmark2 = self.setup_bookmark(unread=True, tags=[tag1]) bookmark3 = self.setup_bookmark(unread=True, tags=[tag1]) self.setup_bookmark(unread=True) self.setup_bookmark(unread=True) self.setup_bookmark(unread=True) feed_url = reverse("bookmarks:feeds.unread", args=[self.token.key]) url = feed_url + f"?q={bookmark1.title}" response = self.client.get(url) self.assertEqual(response.status_code, 200) self.assertContains(response, "", count=1) self.assertContains(response, f"{bookmark1.url}", count=1) url = feed_url + "?q=" + urllib.parse.quote("#" + tag1.name) response = self.client.get(url) self.assertEqual(response.status_code, 200) self.assertContains(response, "", count=2) self.assertContains(response, f"{bookmark2.url}", count=1) self.assertContains(response, f"{bookmark3.url}", count=1) url = feed_url + "?q=" + urllib.parse.quote(f"#{tag1.name} {bookmark2.title}") response = self.client.get(url) self.assertEqual(response.status_code, 200) self.assertContains(response, "", count=1) self.assertContains(response, f"{bookmark2.url}", count=1) def test_unread_returns_only_user_owned_bookmarks(self): other_user = User.objects.create_user( "otheruser", "otheruser@example.com", "password123" ) self.setup_bookmark(unread=True, user=other_user) self.setup_bookmark(unread=True, user=other_user) self.setup_bookmark(unread=True, user=other_user) response = self.client.get( reverse("bookmarks:feeds.unread", args=[self.token.key]) ) self.assertEqual(response.status_code, 200) self.assertContains(response, "", count=0) def test_shared_returns_404_for_unknown_feed_token(self): response = self.client.get(reverse("bookmarks:feeds.shared", args=["foo"])) self.assertEqual(response.status_code, 404) def test_shared_metadata(self): feed_url = reverse("bookmarks:feeds.shared", args=[self.token.key]) response = self.client.get(feed_url) self.assertEqual(response.status_code, 200) self.assertContains(response, "Shared bookmarks") self.assertContains(response, "All shared bookmarks") self.assertContains(response, f"http://testserver{feed_url}") self.assertContains( response, f'' ) def test_shared_returns_shared_bookmarks_only(self): user1 = self.setup_user(enable_sharing=True) user2 = self.setup_user(enable_sharing=False) self.setup_bookmark() self.setup_bookmark(shared=False, user=user1) self.setup_bookmark(shared=True, user=user2) shared_bookmarks = [ self.setup_bookmark(shared=True, user=user1, description="test"), self.setup_bookmark(shared=True, user=user1, description="test"), self.setup_bookmark(shared=True, user=user1, description="test"), ] response = self.client.get( reverse("bookmarks:feeds.shared", args=[self.token.key]) ) self.assertEqual(response.status_code, 200) self.assertContains(response, "", count=len(shared_bookmarks)) for bookmark in shared_bookmarks: expected_item = ( "" f"{bookmark.resolved_title}" f"{bookmark.url}" f"{bookmark.resolved_description}" f"{rfc2822_date(bookmark.date_added)}" f"{bookmark.url}" "" ) self.assertContains(response, expected_item, count=1) def test_shared_with_query(self): user = self.setup_user(enable_sharing=True) tag1 = self.setup_tag(user=user) bookmark1 = self.setup_bookmark(shared=True, user=user) bookmark2 = self.setup_bookmark(shared=True, tags=[tag1], user=user) bookmark3 = self.setup_bookmark(shared=True, tags=[tag1], user=user) self.setup_bookmark(shared=True, user=user) self.setup_bookmark(shared=True, user=user) self.setup_bookmark(shared=True, user=user) feed_url = reverse("bookmarks:feeds.shared", args=[self.token.key]) url = feed_url + f"?q={bookmark1.title}" response = self.client.get(url) self.assertEqual(response.status_code, 200) self.assertContains(response, "", count=1) self.assertContains(response, f"{bookmark1.url}", count=1) url = feed_url + "?q=" + urllib.parse.quote("#" + tag1.name) response = self.client.get(url) self.assertEqual(response.status_code, 200) self.assertContains(response, "", count=2) self.assertContains(response, f"{bookmark2.url}", count=1) self.assertContains(response, f"{bookmark3.url}", count=1) url = feed_url + "?q=" + urllib.parse.quote(f"#{tag1.name} {bookmark2.title}") response = self.client.get(url) self.assertEqual(response.status_code, 200) self.assertContains(response, "", count=1) self.assertContains(response, f"{bookmark2.url}", count=1) def test_public_shared_does_not_require_auth(self): response = self.client.get(reverse("bookmarks:feeds.public_shared")) self.assertEqual(response.status_code, 200) def test_public_shared_metadata(self): feed_url = reverse("bookmarks:feeds.public_shared") response = self.client.get(feed_url) self.assertEqual(response.status_code, 200) self.assertContains(response, "Public shared bookmarks") self.assertContains( response, "All public shared bookmarks" ) self.assertContains(response, f"http://testserver{feed_url}") self.assertContains( response, f'' ) def test_public_shared_returns_publicly_shared_bookmarks_only(self): user1 = self.setup_user(enable_sharing=True, enable_public_sharing=True) user2 = self.setup_user(enable_sharing=True) user3 = self.setup_user(enable_sharing=False) self.setup_bookmark() self.setup_bookmark(shared=False, user=user1) self.setup_bookmark(shared=False, user=user2) self.setup_bookmark(shared=True, user=user2) self.setup_bookmark(shared=True, user=user3) public_shared_bookmarks = [ self.setup_bookmark(shared=True, user=user1, description="test"), self.setup_bookmark(shared=True, user=user1, description="test"), self.setup_bookmark(shared=True, user=user1, description="test"), ] response = self.client.get(reverse("bookmarks:feeds.public_shared")) self.assertEqual(response.status_code, 200) self.assertContains(response, "", count=len(public_shared_bookmarks)) for bookmark in public_shared_bookmarks: expected_item = ( "" f"{bookmark.resolved_title}" f"{bookmark.url}" f"{bookmark.resolved_description}" f"{rfc2822_date(bookmark.date_added)}" f"{bookmark.url}" "" ) self.assertContains(response, expected_item, count=1) def test_public_shared_with_query(self): user = self.setup_user(enable_sharing=True, enable_public_sharing=True) tag1 = self.setup_tag(user=user) bookmark1 = self.setup_bookmark(shared=True, user=user) bookmark2 = self.setup_bookmark(shared=True, tags=[tag1], user=user) bookmark3 = self.setup_bookmark(shared=True, tags=[tag1], user=user) self.setup_bookmark(shared=True, user=user) self.setup_bookmark(shared=True, user=user) self.setup_bookmark(shared=True, user=user) feed_url = reverse("bookmarks:feeds.shared", args=[self.token.key]) url = feed_url + f"?q={bookmark1.title}" response = self.client.get(url) self.assertEqual(response.status_code, 200) self.assertContains(response, "", count=1) self.assertContains(response, f"{bookmark1.url}", count=1) url = feed_url + "?q=" + urllib.parse.quote("#" + tag1.name) response = self.client.get(url) self.assertEqual(response.status_code, 200) self.assertContains(response, "", count=2) self.assertContains(response, f"{bookmark2.url}", count=1) self.assertContains(response, f"{bookmark3.url}", count=1) url = feed_url + "?q=" + urllib.parse.quote(f"#{tag1.name} {bookmark2.title}") response = self.client.get(url) self.assertEqual(response.status_code, 200) self.assertContains(response, "", count=1) self.assertContains(response, f"{bookmark2.url}", count=1)