diff --git a/lib/pleroma/web/feed/user_controller.ex b/lib/pleroma/web/feed/user_controller.ex
index 9ffb3b9be..e27f85929 100644
--- a/lib/pleroma/web/feed/user_controller.ex
+++ b/lib/pleroma/web/feed/user_controller.ex
@@ -40,6 +40,15 @@ def feed_redirect(conn, %{"nickname" => nickname}) do
end
def feed(conn, %{"nickname" => nickname} = params) do
+ format = get_format(conn)
+
+ format =
+ if format in ["rss", "atom"] do
+ format
+ else
+ "atom"
+ end
+
with {_, %User{} = user} <- {:fetch_user, User.get_cached_by_nickname(nickname)} do
activities =
%{
@@ -50,9 +59,9 @@ def feed(conn, %{"nickname" => nickname} = params) do
|> ActivityPub.fetch_public_activities()
conn
- |> put_resp_content_type("application/atom+xml")
+ |> put_resp_content_type("application/#{format}+xml")
|> put_view(FeedView)
- |> render("user.xml",
+ |> render("user.#{format}",
user: user,
activities: activities,
feed_config: Pleroma.Config.get([:feed])
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index e4e3ee704..3f36f6c1a 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -513,7 +513,7 @@ defmodule Pleroma.Web.Router do
end
pipeline :ostatus do
- plug(:accepts, ["html", "xml", "atom", "activity+json", "json"])
+ plug(:accepts, ["html", "xml", "rss", "atom", "activity+json", "json"])
plug(Pleroma.Plugs.StaticFEPlug)
end
diff --git a/lib/pleroma/web/templates/feed/feed/_activity.xml.eex b/lib/pleroma/web/templates/feed/feed/_activity.atom.eex
similarity index 100%
rename from lib/pleroma/web/templates/feed/feed/_activity.xml.eex
rename to lib/pleroma/web/templates/feed/feed/_activity.atom.eex
diff --git a/lib/pleroma/web/templates/feed/feed/_activity.rss.eex b/lib/pleroma/web/templates/feed/feed/_activity.rss.eex
new file mode 100644
index 000000000..a4dbed638
--- /dev/null
+++ b/lib/pleroma/web/templates/feed/feed/_activity.rss.eex
@@ -0,0 +1,49 @@
+-
+ http://activitystrea.ms/schema/1.0/note
+ http://activitystrea.ms/schema/1.0/post
+ <%= @data["id"] %>
+ <%= activity_title(@object, Keyword.get(@feed_config, :post_title, %{})) %>
+ <%= activity_content(@object) %>
+ <%= @data["published"] %>
+ <%= @data["published"] %>
+
+ <%= activity_context(@activity) %>
+
+ <%= activity_context(@activity) %>
+
+ <%= if @data["summary"] do %>
+ <%= @data["summary"] %>
+ <% end %>
+
+ <%= if @activity.local do %>
+ <%= @data["id"] %>
+ <% else %>
+ <%= @data["external_url"] %>
+ <% end %>
+
+ <%= for tag <- @data["tag"] || [] do %>
+
+ <% end %>
+
+ <%= for attachment <- @data["attachment"] || [] do %>
+ <%= attachment_href(attachment) %>
+ <% end %>
+
+ <%= if @data["inReplyTo"] do %>
+
+ <% end %>
+
+ <%= for id <- @activity.recipients do %>
+ <%= if id == Pleroma.Constants.as_public() do %>
+ http://activityschema.org/collection/public
+ <% else %>
+ <%= unless Regex.match?(~r/^#{Pleroma.Web.base_url()}.+followers$/, id) do %>
+ <%= id %>
+ <% end %>
+ <% end %>
+ <% end %>
+
+ <%= for {emoji, file} <- @data["emoji"] || %{} do %>
+ <%= file %>
+ <% end %>
+
diff --git a/lib/pleroma/web/templates/feed/feed/_author.xml.eex b/lib/pleroma/web/templates/feed/feed/_author.atom.eex
similarity index 100%
rename from lib/pleroma/web/templates/feed/feed/_author.xml.eex
rename to lib/pleroma/web/templates/feed/feed/_author.atom.eex
diff --git a/lib/pleroma/web/templates/feed/feed/_author.rss.eex b/lib/pleroma/web/templates/feed/feed/_author.rss.eex
new file mode 100644
index 000000000..526aeddcf
--- /dev/null
+++ b/lib/pleroma/web/templates/feed/feed/_author.rss.eex
@@ -0,0 +1,17 @@
+
+ <%= @user.ap_id %>
+ http://activitystrea.ms/schema/1.0/person
+ <%= @user.ap_id %>
+ <%= @user.nickname %>
+ <%= @user.name %>
+ <%= escape(@user.bio) %>
+ <%= escape(@user.bio) %>
+ <%= @user.nickname %>
+ <%= User.avatar_url(@user) %>
+ <%= if User.banner_url(@user) do %>
+ <%= User.banner_url(@user) %>
+ <% end %>
+ <%= if @user.local do %>
+ true
+ <% end %>
+
diff --git a/lib/pleroma/web/templates/feed/feed/user.xml.eex b/lib/pleroma/web/templates/feed/feed/user.atom.eex
similarity index 85%
rename from lib/pleroma/web/templates/feed/feed/user.xml.eex
rename to lib/pleroma/web/templates/feed/feed/user.atom.eex
index d274c08ae..c6acd848f 100644
--- a/lib/pleroma/web/templates/feed/feed/user.xml.eex
+++ b/lib/pleroma/web/templates/feed/feed/user.atom.eex
@@ -12,13 +12,13 @@
<%= logo(@user) %>
- <%= render @view_module, "_author.xml", assigns %>
+ <%= render @view_module, "_author.atom", assigns %>
<%= if last_activity(@activities) do %>
<% end %>
<%= for activity <- @activities do %>
- <%= render @view_module, "_activity.xml", Map.merge(assigns, prepare_activity(activity)) %>
+ <%= render @view_module, "_activity.atom", Map.merge(assigns, prepare_activity(activity)) %>
<% end %>
diff --git a/lib/pleroma/web/templates/feed/feed/user.rss.eex b/lib/pleroma/web/templates/feed/feed/user.rss.eex
new file mode 100644
index 000000000..d69120480
--- /dev/null
+++ b/lib/pleroma/web/templates/feed/feed/user.rss.eex
@@ -0,0 +1,20 @@
+
+
+
+ <%= user_feed_url(@conn, :feed, @user.nickname) <> ".rss" %>
+ <%= @user.nickname <> "'s timeline" %>
+ <%= most_recent_update(@activities, @user) %>
+ <%= logo(@user) %>
+ <%= '#{user_feed_url(@conn, :feed, @user.nickname)}.rss' %>
+
+ <%= render @view_module, "_author.rss", assigns %>
+
+ <%= if last_activity(@activities) do %>
+ <%= '#{user_feed_url(@conn, :feed, @user.nickname)}.rss?max_id=#{last_activity(@activities).id}' %>
+ <% end %>
+
+ <%= for activity <- @activities do %>
+ <%= render @view_module, "_activity.rss", Map.merge(assigns, prepare_activity(activity)) %>
+ <% end %>
+
+
diff --git a/test/web/feed/user_controller_test.exs b/test/web/feed/user_controller_test.exs
index fd59ca892..e3dfa88f1 100644
--- a/test/web/feed/user_controller_test.exs
+++ b/test/web/feed/user_controller_test.exs
@@ -19,7 +19,7 @@ defmodule Pleroma.Web.Feed.UserControllerTest do
describe "feed" do
clear_config([:feed])
- test "gets a feed", %{conn: conn} do
+ test "gets an atom feed", %{conn: conn} do
Config.put(
[:feed, :post_title],
%{max_length: 10, omission: "..."}
@@ -59,7 +59,7 @@ test "gets a feed", %{conn: conn} do
resp =
conn
- |> put_req_header("content-type", "application/atom+xml")
+ |> put_req_header("accept", "application/atom+xml")
|> get(user_feed_path(conn, :feed, user.nickname))
|> response(200)
@@ -73,7 +73,7 @@ test "gets a feed", %{conn: conn} do
resp =
conn
- |> put_req_header("content-type", "application/atom+xml")
+ |> put_req_header("accept", "application/atom+xml")
|> get("/users/#{user.nickname}/feed", %{"max_id" => note_activity2.id})
|> response(200)
@@ -85,10 +85,76 @@ test "gets a feed", %{conn: conn} do
assert activity_titles == ['This is...']
end
+ test "gets a rss feed", %{conn: conn} do
+ Pleroma.Config.put(
+ [:feed, :post_title],
+ %{max_length: 10, omission: "..."}
+ )
+
+ activity = insert(:note_activity)
+
+ note =
+ insert(:note,
+ data: %{
+ "content" => "This is :moominmamma: note ",
+ "attachment" => [
+ %{
+ "url" => [
+ %{"mediaType" => "image/png", "href" => "https://pleroma.gov/image.png"}
+ ]
+ }
+ ],
+ "inReplyTo" => activity.data["id"]
+ }
+ )
+
+ note_activity = insert(:note_activity, note: note)
+ user = User.get_cached_by_ap_id(note_activity.data["actor"])
+
+ note2 =
+ insert(:note,
+ user: user,
+ data: %{
+ "content" => "42 This is :moominmamma: note ",
+ "inReplyTo" => activity.data["id"]
+ }
+ )
+
+ note_activity2 = insert(:note_activity, note: note2)
+ object = Object.normalize(note_activity)
+
+ resp =
+ conn
+ |> put_req_header("accept", "application/rss+xml")
+ |> get("/users/#{user.nickname}/feed.rss")
+ |> response(200)
+
+ activity_titles =
+ resp
+ |> SweetXml.parse()
+ |> SweetXml.xpath(~x"//item/title/text()"l)
+
+ assert activity_titles == ['42 This...', 'This is...']
+ assert resp =~ object.data["content"]
+
+ resp =
+ conn
+ |> put_req_header("accept", "application/atom+xml")
+ |> get("/users/#{user.nickname}/feed.rss", %{"max_id" => note_activity2.id})
+ |> response(200)
+
+ activity_titles =
+ resp
+ |> SweetXml.parse()
+ |> SweetXml.xpath(~x"//item/title/text()"l)
+
+ assert activity_titles == ['This is...']
+ end
+
test "returns 404 for a missing feed", %{conn: conn} do
conn =
conn
- |> put_req_header("content-type", "application/atom+xml")
+ |> put_req_header("accept", "application/atom+xml")
|> get(user_feed_path(conn, :feed, "nonexisting"))
assert response(conn, 404)