diff --git a/bookwyrm/templates/rss/edition.html b/bookwyrm/templates/rss/edition.html new file mode 100644 index 0000000000..db65b13336 --- /dev/null +++ b/bookwyrm/templates/rss/edition.html @@ -0,0 +1,10 @@ +{% load i18n %} +{% load shelf_tags %} +‘{{ obj.title }}’ {% if obj.author_text %} by {{obj.author_text}} {% endif %} +

{{ obj.description|default_if_none:obj.parent_work.description}}

+{% if obj.isbn_13 %}{% trans "ISBN 13:" %} {{ obj.isbn_13 }}
{% endif %} +{% if obj.oclc_number %}{% trans "OCLC Number:" %} {{ obj.oclc_number }}
{% endif %} +{% if obj.asin %}{% trans "ASIN:" %} {{ obj.asin }}
{% endif %} +{% if obj.aasin %}{% trans "Audible ASIN:" %} {{ obj.aasin }}
{% endif %} +{% if obj.isfdb %}{% trans "ISFDB ID:" %} {{ obj.isfdb }}
{% endif %} +{% if obj.goodreads_key %}{% trans "Goodreads:" %} {{ obj.goodreads_key }}{% endif %} diff --git a/bookwyrm/templates/shelf/shelf.html b/bookwyrm/templates/shelf/shelf.html index 71f4bc088e..f80009e662 100644 --- a/bookwyrm/templates/shelf/shelf.html +++ b/bookwyrm/templates/shelf/shelf.html @@ -12,6 +12,11 @@ {% include 'snippets/opengraph.html' with image=user.preview_image %} {% endblock %} + +{% block head_links %} + +{% endblock %} + {% block content %}

diff --git a/bookwyrm/tests/views/test_rss_feed.py b/bookwyrm/tests/views/test_rss_feed.py index 790efe51b6..2952315a98 100644 --- a/bookwyrm/tests/views/test_rss_feed.py +++ b/bookwyrm/tests/views/test_rss_feed.py @@ -132,3 +132,27 @@ def test_rss_quotation_only(self, *_): self.assertEqual(result.status_code, 200) self.assertIn(b"a sickening sense", result.content) + + def test_rss_shelf(self, *_): + """load the rss feed of a shelf""" + with patch( + "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" + ), patch("bookwyrm.activitystreams.add_book_statuses_task.delay"): + # make the shelf + shelf = models.Shelf.objects.create( + name="Test Shelf", identifier="test-shelf", user=self.local_user + ) + # put the shelf on the book + models.ShelfBook.objects.create( + book=self.book, + shelf=shelf, + user=self.local_user, + ) + view = rss_feed.RssShelfFeed() + request = self.factory.get("/user/books/test-shelf/rss") + request.user = self.local_user + result = view( + request, username=self.local_user.username, shelf_identifier="test-shelf" + ) + self.assertEqual(result.status_code, 200) + self.assertIn(b"Example Edition", result.content) diff --git a/bookwyrm/urls.py b/bookwyrm/urls.py index cd75eb0c02..9b29e1b2dc 100644 --- a/bookwyrm/urls.py +++ b/bookwyrm/urls.py @@ -577,11 +577,21 @@ views.Shelf.as_view(), name="shelf", ), + re_path( + rf"^{USER_PATH}/(shelf|books)/(?P[\w-]+)/rss/?$", + views.rss_feed.RssShelfFeed(), + name="shelf-rss", + ), re_path( rf"^{LOCAL_USER_PATH}/(books|shelf)/(?P[\w-]+)(.json)?/?$", views.Shelf.as_view(), name="shelf", ), + re_path( + rf"^{LOCAL_USER_PATH}/(books|shelf)/(?P[\w-]+)/rss/?$", + views.rss_feed.RssShelfFeed(), + name="shelf-rss", + ), re_path(r"^create-shelf/?$", views.create_shelf, name="shelf-create"), re_path(r"^delete-shelf/(?P\d+)/?$", views.delete_shelf), re_path(r"^shelve/?$", views.shelve), diff --git a/bookwyrm/views/rss_feed.py b/bookwyrm/views/rss_feed.py index 9f5e97d597..acf831708a 100644 --- a/bookwyrm/views/rss_feed.py +++ b/bookwyrm/views/rss_feed.py @@ -3,6 +3,7 @@ from django.contrib.syndication.views import Feed from django.template.loader import get_template from django.utils.translation import gettext_lazy as _ +from django.shortcuts import get_object_or_404 from ..models import Review, Quotation, Comment from .helpers import get_user_from_username @@ -177,3 +178,61 @@ def item_link(self, item): def item_pubdate(self, item): """publication date of the item""" return item.published_date + + +class RssShelfFeed(Feed): + """serialize a shelf activity in rss""" + + description_template = "rss/edition.html" + + def item_title(self, item): + """render the item title""" + authors = item.authors + if item.author_text: + authors.display_name = f"{item.author_text}:" + else: + authors.description = "" + template = get_template("rss/title.html") + return template.render({"user": authors, "item_title": item.title}).strip() + + def get_object( + self, request, shelf_identifier, username + ): # pylint: disable=arguments-differ + """the shelf that gets serialized""" + user = get_user_from_username(request.user, username) + # always get privacy, don't support rss over anything private + # get the SHELF of the object + shelf = get_object_or_404( + user.shelf_set, + identifier=shelf_identifier, + privacy__in=["public", "unlisted"], + ) + shelf.raise_visible_to_user(request.user) + return shelf + + def link(self, obj): + """link to the shelf""" + return obj.local_path + + def title(self, obj): + """title of the rss feed entry""" + return _(f"{obj.user.display_name}’s {obj.name} shelf") + + def items(self, obj): + """the user's activity feed""" + return obj.books.order_by("-shelfbook__shelved_date")[:10] + + def item_link(self, item): + """link to the status""" + return item.local_path + + def item_pubdate(self, item): + """publication date of the item""" + return item.published_date + + def description(self, obj): + """description of the shelf including the shelf name and user.""" + # if there's a description, lets add it. Not everyone puts a description in. + if desc := obj.description: + return _(f"{obj.user.display_name}’s {obj.name} shelf: {desc}") + return _(f"Books added to {obj.user.name}’s {obj.name} shelf")