diff --git a/docs/features.rst b/docs/features.rst index aa0306e..93e0295 100644 --- a/docs/features.rst +++ b/docs/features.rst @@ -16,6 +16,7 @@ Currently, it supports: * Post visibilities, including a local-only option * A home timeline, a local timeline, and a federated timeline * Profile pages with bios, icons, and header images +* RSS feeds for users' public posts * Hashtag linking and searching * Searching for users by exact handle * Multiple domain support @@ -34,7 +35,6 @@ Features planned for releases up to 1.0: * Moderation flagging system and queue * IP and email domain banning * Mastodon-compatible client API for use with apps -* RSS feeds for users' public posts Features that may make it into 1.0, or might be further out: diff --git a/takahe/urls.py b/takahe/urls.py index 0e995c4..59f14ba 100644 --- a/takahe/urls.py +++ b/takahe/urls.py @@ -120,6 +120,7 @@ urlpatterns = [ path("@/", identity.ViewIdentity.as_view()), path("@/inbox/", activitypub.Inbox.as_view()), path("@/action/", identity.ActionIdentity.as_view()), + path("@/rss/", identity.IdentityFeed()), # Posts path("compose/", compose.Compose.as_view(), name="compose"), path( diff --git a/users/views/identity.py b/users/views/identity.py index 1f75a0a..6cfcff9 100644 --- a/users/views/identity.py +++ b/users/views/identity.py @@ -2,6 +2,7 @@ import string from django import forms from django.contrib.auth.decorators import login_required +from django.contrib.syndication.views import Feed from django.core import validators from django.http import Http404, JsonResponse from django.shortcuts import redirect @@ -89,6 +90,47 @@ class ViewIdentity(ListView): return context +class IdentityFeed(Feed): + """ + Serves a local user's Public posts as an RSS feed + """ + + def get_object(self, request, handle): + return by_handle_or_404( + request, + handle, + local=True, + ) + + def title(self, identity: Identity): + return identity.name + + def description(self, identity: Identity): + return f"Public posts from @{identity.handle}" + + def link(self, identity: Identity): + return identity.absolute_profile_uri() + + def items(self, identity: Identity): + return ( + identity.posts.filter( + visibility=Post.Visibilities.public, + ) + .select_related("author") + .prefetch_related("attachments") + .order_by("-created") + ) + + def item_description(self, item: Post): + return item.safe_content_remote() + + def item_link(self, item: Post): + return item.absolute_object_uri() + + def item_pubdate(self, item: Post): + return item.published + + @method_decorator(identity_required, name="dispatch") class ActionIdentity(View): def post(self, request, handle):