diff --git a/bookwyrm/templates/user/user.html b/bookwyrm/templates/user/user.html index 814e306a0..42b0ffbb5 100755 --- a/bookwyrm/templates/user/user.html +++ b/bookwyrm/templates/user/user.html @@ -70,10 +70,52 @@

{% trans "User Activity" %}

{% if user.local %}
- - - {% trans "RSS feed" %} - +
{% endif %} diff --git a/bookwyrm/tests/views/test_rss_feed.py b/bookwyrm/tests/views/test_rss_feed.py index 8b3ecf583..cfbec3360 100644 --- a/bookwyrm/tests/views/test_rss_feed.py +++ b/bookwyrm/tests/views/test_rss_feed.py @@ -82,3 +82,48 @@ class RssFeedView(TestCase): self.assertEqual(result.status_code, 200) self.assertIn(b"a sickening sense", result.content) + + def test_rss_comment_only(self, *_): + """load an rss feed""" + models.Comment.objects.create( + content="comment test content", + user=self.local_user, + book=self.book, + ) + view = rss_feed.RssCommentsOnlyFeed() + request = self.factory.get("/user/rss_user/rss") + request.user = self.local_user + result = view(request, username=self.local_user.username) + self.assertEqual(result.status_code, 200) + self.assertIn(b"Example Edition", result.content) + + def test_rss_review_only(self, *_): + """load an rss feed""" + models.Review.objects.create( + name="Review name", + content="test content", + rating=3, + user=self.local_user, + book=self.book, + ) + view = rss_feed.RssReviewsOnlyFeed() + request = self.factory.get("/user/rss_user/rss") + request.user = self.local_user + result = view(request, username=self.local_user.username) + self.assertEqual(result.status_code, 200) + + def test_rss_quotation_only(self, *_): + """load an rss feed""" + models.Quotation.objects.create( + quote="a sickening sense", + content="test content", + user=self.local_user, + book=self.book, + ) + view = rss_feed.RssQuotesOnlyFeed() + request = self.factory.get("/user/rss_user/rss") + request.user = self.local_user + result = view(request, username=self.local_user.username) + self.assertEqual(result.status_code, 200) + + self.assertIn(b"a sickening sense", result.content) diff --git a/bookwyrm/urls.py b/bookwyrm/urls.py index f78b32afc..73bdd3755 100644 --- a/bookwyrm/urls.py +++ b/bookwyrm/urls.py @@ -424,6 +424,21 @@ urlpatterns = [ re_path(rf"{USER_PATH}/?$", views.User.as_view(), name="user-feed"), re_path(rf"^@(?P{regex.USERNAME})$", views.user_redirect), re_path(rf"{USER_PATH}/rss/?$", views.rss_feed.RssFeed(), name="user-rss"), + re_path( + rf"{USER_PATH}/rss-reviews/?$", + views.rss_feed.RssReviewsOnlyFeed(), + name="user-reviews-rss", + ), + re_path( + rf"{USER_PATH}/rss-quotes/?$", + views.rss_feed.RssQuotesOnlyFeed(), + name="user-quotes-rss", + ), + re_path( + rf"{USER_PATH}/rss-comments/?$", + views.rss_feed.RssCommentsOnlyFeed(), + name="user-comments-rss", + ), re_path( rf"{USER_PATH}/(?P(followers|following))(.json)?/?$", views.Relationships.as_view(), diff --git a/bookwyrm/views/__init__.py b/bookwyrm/views/__init__.py index c56c60915..353275c46 100644 --- a/bookwyrm/views/__init__.py +++ b/bookwyrm/views/__init__.py @@ -137,7 +137,12 @@ from .outbox import Outbox from .reading import ReadThrough, delete_readthrough, delete_progressupdate from .reading import ReadingStatus from .report import Report -from .rss_feed import RssFeed +from .rss_feed import ( + RssFeed, + RssReviewsOnlyFeed, + RssQuotesOnlyFeed, + RssCommentsOnlyFeed, +) from .search import Search from .setup import InstanceConfig, CreateAdmin from .status import CreateStatus, EditStatus, DeleteStatus, update_progress diff --git a/bookwyrm/views/rss_feed.py b/bookwyrm/views/rss_feed.py index 1e9d57460..82a7b3dce 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 ..models import Review, Quotation, Comment from .helpers import get_user_from_username @@ -42,3 +43,117 @@ class RssFeed(Feed): def item_link(self, item): """link to the status""" return item.local_path + + +class RssReviewsOnlyFeed(Feed): + """serialize user's reviews in rss feed""" + + description_template = "rss/content.html" + + def item_title(self, item): + """render the item title""" + if hasattr(item, "pure_name") and item.pure_name: + return item.pure_name + title_template = get_template("snippets/status/header_content.html") + title = title_template.render({"status": item}) + template = get_template("rss/title.html") + return template.render({"user": item.user, "item_title": title}).strip() + + def get_object(self, request, username): # pylint: disable=arguments-differ + """the user who's posts get serialized""" + return get_user_from_username(request.user, username) + + def link(self, obj): + """link to the user's profile""" + return obj.local_path + + def title(self, obj): + """title of the rss feed entry""" + return _(f"Reviews from {obj.display_name}") + + def items(self, obj): + """the user's activity feed""" + return Review.objects.filter( + user=obj, + privacy__in=["public", "unlisted"], + )[:10] + + def item_link(self, item): + """link to the status""" + return item.local_path + + +class RssQuotesOnlyFeed(Feed): + """serialize user's quotes in rss feed""" + + description_template = "rss/content.html" + + def item_title(self, item): + """render the item title""" + if hasattr(item, "pure_name") and item.pure_name: + return item.pure_name + title_template = get_template("snippets/status/header_content.html") + title = title_template.render({"status": item}) + template = get_template("rss/title.html") + return template.render({"user": item.user, "item_title": title}).strip() + + def get_object(self, request, username): # pylint: disable=arguments-differ + """the user who's posts get serialized""" + return get_user_from_username(request.user, username) + + def link(self, obj): + """link to the user's profile""" + return obj.local_path + + def title(self, obj): + """title of the rss feed entry""" + return _(f"Quotes from {obj.display_name}") + + def items(self, obj): + """the user's activity feed""" + return Quotation.objects.filter( + user=obj, + privacy__in=["public", "unlisted"], + )[:10] + + def item_link(self, item): + """link to the status""" + return item.local_path + + +class RssCommentsOnlyFeed(Feed): + """serialize user's quotes in rss feed""" + + description_template = "rss/content.html" + + def item_title(self, item): + """render the item title""" + if hasattr(item, "pure_name") and item.pure_name: + return item.pure_name + title_template = get_template("snippets/status/header_content.html") + title = title_template.render({"status": item}) + template = get_template("rss/title.html") + return template.render({"user": item.user, "item_title": title}).strip() + + def get_object(self, request, username): # pylint: disable=arguments-differ + """the user who's posts get serialized""" + return get_user_from_username(request.user, username) + + def link(self, obj): + """link to the user's profile""" + return obj.local_path + + def title(self, obj): + """title of the rss feed entry""" + return _(f"Comments from {obj.display_name}") + + def items(self, obj): + """the user's activity feed""" + return Comment.objects.filter( + user=obj, + privacy__in=["public", "unlisted"], + )[:10] + + def item_link(self, item): + """link to the status""" + return item.local_path