Repository: sissbruecker/linkding

Issue:
[New feature] Add a link to public RSS from public bookmarks page
Hello! This is my first issue.

I recently set up a public page with shared bookmarks and invited friends to follow my public RSS, but then I realized that the public RSS URL is only available in settings. I think it should be possible for a user looking at a public bookmarks page to discover the RSS link.

How about adding a `<link rel="alternate" type="application/rss+xml"` to the public bookmarks page if one is available? A RSS icon somewhere in page body would also help with discoverability.

I'm assuming that the public bookmarks page and public bookmarks RSS are always both enabled or both disabled. Does that sound correct?

(I might take a stab at adding it next week if it sounds ok? maybe good first commit for me?)


Discussion:
Both the public bookmarks page and the RSS feed are always accessible.

Adding a `<link>` would be OK. Adding a visible link (anchor) to the UI should be opt-in, in general I try to avoid adding any additional clutter to the bookmark view unless users enable that feature explicitly.
Any idea when this would be merged? I want to link my shared links page to my blog, and let audience subscribe to its RSS feed.

In the meantime, could you let me know of the exact address of the RSS feeds, please?



Patch:
diff --git a/bookmarks/templates/bookmarks/head.html b/bookmarks/templates/bookmarks/head.html
index b28a1caf..c83d16e2 100644
--- a/bookmarks/templates/bookmarks/head.html
+++ b/bookmarks/templates/bookmarks/head.html
@@ -36,5 +36,8 @@
   {% if not request.global_settings.enable_link_prefetch %}
     <meta name="turbo-prefetch" content="false">
   {% endif %}
+  {% if rss_feed_url %}
+    <link rel="alternate" type="application/rss+xml" href="{{ rss_feed_url }}" />
+  {% endif %}
   <script src="{% static "bundle.js" %}?v={{ app_version }}"></script>
 </head>
diff --git a/bookmarks/views/bookmarks.py b/bookmarks/views/bookmarks.py
index 5c110bdc..585e439e 100644
--- a/bookmarks/views/bookmarks.py
+++ b/bookmarks/views/bookmarks.py
@@ -104,6 +104,7 @@ def shared(request):
             "tag_cloud": tag_cloud,
             "details": bookmark_details,
             "users": users,
+            "rss_feed_url": reverse("bookmarks:feeds.public_shared"),
         },
     )
 


Test patch:
diff --git a/bookmarks/tests/test_bookmark_archived_view.py b/bookmarks/tests/test_bookmark_archived_view.py
index 040a5f8c..e6d92fb7 100644
--- a/bookmarks/tests/test_bookmark_archived_view.py
+++ b/bookmarks/tests/test_bookmark_archived_view.py
@@ -503,3 +503,10 @@ def test_turbo_frame_details_modal_renders_details_modal_update(self):
         self.assertIsNotNone(soup.select_one("turbo-frame#details-modal"))
         self.assertIsNone(soup.select_one("#bookmark-list-container"))
         self.assertIsNone(soup.select_one("#tag-cloud-container"))
+
+    def test_does_not_include_rss_feed(self):
+        response = self.client.get(reverse("bookmarks:archived"))
+        soup = self.make_soup(response.content.decode())
+
+        feed = soup.select_one('head link[type="application/rss+xml"]')
+        self.assertIsNone(feed)
diff --git a/bookmarks/tests/test_bookmark_index_view.py b/bookmarks/tests/test_bookmark_index_view.py
index 8a0c680c..ff7ed70a 100644
--- a/bookmarks/tests/test_bookmark_index_view.py
+++ b/bookmarks/tests/test_bookmark_index_view.py
@@ -481,3 +481,10 @@ def test_turbo_frame_details_modal_renders_details_modal_update(self):
         self.assertIsNotNone(soup.select_one("turbo-frame#details-modal"))
         self.assertIsNone(soup.select_one("#bookmark-list-container"))
         self.assertIsNone(soup.select_one("#tag-cloud-container"))
+
+    def test_does_not_include_rss_feed(self):
+        response = self.client.get(reverse("bookmarks:index"))
+        soup = self.make_soup(response.content.decode())
+
+        feed = soup.select_one('head link[type="application/rss+xml"]')
+        self.assertIsNone(feed)
diff --git a/bookmarks/tests/test_bookmark_shared_view.py b/bookmarks/tests/test_bookmark_shared_view.py
index c54886bd..85a83a00 100644
--- a/bookmarks/tests/test_bookmark_shared_view.py
+++ b/bookmarks/tests/test_bookmark_shared_view.py
@@ -593,3 +593,11 @@ def test_turbo_frame_details_modal_renders_details_modal_update(self):
         self.assertIsNotNone(soup.select_one("turbo-frame#details-modal"))
         self.assertIsNone(soup.select_one("#bookmark-list-container"))
         self.assertIsNone(soup.select_one("#tag-cloud-container"))
+
+    def test_includes_public_shared_rss_feed(self):
+        response = self.client.get(reverse("bookmarks:shared"))
+        soup = self.make_soup(response.content.decode())
+
+        feed = soup.select_one('head link[type="application/rss+xml"]')
+        self.assertIsNotNone(feed)
+        self.assertEqual(feed.attrs["href"], reverse("bookmarks:feeds.public_shared"))