diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d42a4cfe..7d1ae3160 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -59,6 +59,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Fixed lowercase HTTP HEAD method in the Media Proxy Preview code - Removed useless notification call on Delete activities - Improved performance for filtering out deactivated and invisible users +- RSS and Atom feeds for users work again - TwitterCard meta tags conformance ### Removed diff --git a/lib/pleroma/web/feed/feed_view.ex b/lib/pleroma/web/feed/feed_view.ex index 35a5f9482..449659f4b 100644 --- a/lib/pleroma/web/feed/feed_view.ex +++ b/lib/pleroma/web/feed/feed_view.ex @@ -14,14 +14,8 @@ defmodule Pleroma.Web.Feed.FeedView do require Pleroma.Constants - @spec pub_date(String.t() | DateTime.t()) :: String.t() - def pub_date(date) when is_binary(date) do - date - |> Timex.parse!("{ISO:Extended}") - |> pub_date - end - - def pub_date(%DateTime{} = date), do: Timex.format!(date, "{RFC822}") + @days ~w(Mon Tue Wed Thu Fri Sat Sun) + @months ~w(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec) def prepare_activity(activity, opts \\ []) do object = Object.normalize(activity, fetch: false) @@ -41,13 +35,18 @@ defmodule Pleroma.Web.Feed.FeedView do def most_recent_update(activities) do with %{updated_at: updated_at} <- List.first(activities) do - NaiveDateTime.to_iso8601(updated_at) + to_rfc3339(updated_at) end end - def most_recent_update(activities, user) do + def most_recent_update(activities, user, :atom) do (List.first(activities) || user).updated_at - |> NaiveDateTime.to_iso8601() + |> to_rfc3339() + end + + def most_recent_update(activities, user, :rss) do + (List.first(activities) || user).updated_at + |> to_rfc2822() end def feed_logo do @@ -61,6 +60,10 @@ defmodule Pleroma.Web.Feed.FeedView do |> MediaProxy.url() end + def email(user) do + user.nickname <> "@" <> Pleroma.Web.Endpoint.host() + end + def logo(user) do user |> User.avatar_url() @@ -69,18 +72,34 @@ defmodule Pleroma.Web.Feed.FeedView do def last_activity(activities), do: List.last(activities) - def activity_title(%{"content" => content}, opts \\ %{}) do - content + def activity_title(%{"content" => content, "summary" => summary} = data, opts \\ %{}) do + title = + cond do + summary != "" -> summary + content != "" -> activity_content(data) + true -> "a post" + end + + title |> Pleroma.Web.Metadata.Utils.scrub_html() |> Pleroma.Emoji.Formatter.demojify() |> Formatter.truncate(opts[:max_length], opts[:omission]) - |> escape() + end + + def activity_description(data) do + content = activity_content(data) + summary = data["summary"] + + cond do + content != "" -> escape(content) + summary != "" -> escape(summary) + true -> escape(data["type"]) + end end def activity_content(%{"content" => content}) do content |> String.replace(~r/[\n\r]/, "") - |> escape() end def activity_content(_), do: "" @@ -112,4 +131,60 @@ defmodule Pleroma.Web.Feed.FeedView do |> html_escape() |> safe_to_string() end + + @spec to_rfc3339(String.t() | NativeDateTime.t()) :: String.t() + def to_rfc3339(date) when is_binary(date) do + date + |> Timex.parse!("{ISO:Extended}") + |> to_rfc3339() + end + + def to_rfc3339(nd) do + nd + |> Timex.to_datetime() + |> Timex.format!("{RFC3339}") + end + + @spec to_rfc2822(String.t() | DateTime.t() | NativeDateTime.t()) :: String.t() + def to_rfc2822(datestr) when is_binary(datestr) do + datestr + |> Timex.parse!("{ISO:Extended}") + |> to_rfc2822() + end + + def to_rfc2822(%DateTime{} = date) do + date + |> DateTime.to_naive() + |> NaiveDateTime.to_erl() + |> rfc2822_from_erl() + end + + def to_rfc2822(nd) do + nd + |> Timex.to_datetime() + |> DateTime.to_naive() + |> NaiveDateTime.to_erl() + |> rfc2822_from_erl() + end + + @doc """ + Builds a RFC2822 timestamp from an Erlang timestamp + [RFC2822 3.3 - Date and Time Specification](https://tools.ietf.org/html/rfc2822#section-3.3) + This function always assumes the Erlang timestamp is in Universal time, not Local time + """ + def rfc2822_from_erl({{year, month, day} = date, {hour, minute, second}}) do + day_name = Enum.at(@days, :calendar.day_of_the_week(date) - 1) + month_name = Enum.at(@months, month - 1) + + date_part = "#{day_name}, #{day} #{month_name} #{year}" + time_part = "#{pad(hour)}:#{pad(minute)}:#{pad(second)}" + + date_part <> " " <> time_part <> " +0000" + end + + defp pad(num) do + num + |> Integer.to_string() + |> String.pad_leading(2, "0") + end end diff --git a/lib/pleroma/web/templates/feed/feed/_activity.atom.eex b/lib/pleroma/web/templates/feed/feed/_activity.atom.eex index 57bd92468..260338772 100644 --- a/lib/pleroma/web/templates/feed/feed/_activity.atom.eex +++ b/lib/pleroma/web/templates/feed/feed/_activity.atom.eex @@ -3,15 +3,15 @@ http://activitystrea.ms/schema/1.0/post <%= @data["id"] %> <%= activity_title(@data, Keyword.get(@feed_config, :post_title, %{})) %> - <%= activity_content(@data) %> - <%= @activity.data["published"] %> - <%= @activity.data["published"] %> + <%= activity_description(@data) %> + <%= to_rfc3339(@activity.data["published"]) %> + <%= to_rfc3339(@activity.data["published"]) %> <%= activity_context(@activity) %> - <%= if @data["summary"] do %> + <%= if @data["summary"] != "" do %> <%= escape(@data["summary"]) %> <% end %> diff --git a/lib/pleroma/web/templates/feed/feed/_activity.rss.eex b/lib/pleroma/web/templates/feed/feed/_activity.rss.eex index 279f2171d..5c8f35fe4 100644 --- a/lib/pleroma/web/templates/feed/feed/_activity.rss.eex +++ b/lib/pleroma/web/templates/feed/feed/_activity.rss.eex @@ -3,17 +3,12 @@ http://activitystrea.ms/schema/1.0/post <%= @data["id"] %> <%= activity_title(@data, Keyword.get(@feed_config, :post_title, %{})) %> - <%= activity_content(@data) %> - <%= @activity.data["published"] %> - <%= @activity.data["published"] %> + <%= activity_description(@data) %> + <%= to_rfc2822(@activity.data["published"]) %> <%= activity_context(@activity) %> - <%= if @data["summary"] do %> - <%= escape(@data["summary"]) %> - <% end %> - <%= if @activity.local do %> <%= @data["id"] %> <% else %> @@ -27,7 +22,7 @@ <% end %> <%= for attachment <- @data["attachment"] || [] do %> - <%= attachment_href(attachment) %> + <% end %> <%= if @data["inReplyTo"] do %> diff --git a/lib/pleroma/web/templates/feed/feed/_author.atom.eex b/lib/pleroma/web/templates/feed/feed/_author.atom.eex index 25cbffada..90be8a559 100644 --- a/lib/pleroma/web/templates/feed/feed/_author.atom.eex +++ b/lib/pleroma/web/templates/feed/feed/_author.atom.eex @@ -1,17 +1,14 @@ - <%= @user.ap_id %> - http://activitystrea.ms/schema/1.0/person <%= @user.ap_id %> + <%= @user.nickname %> + http://activitystrea.ms/schema/1.0/person + <%= @user.name %> + <%= User.avatar_url(@user) %> + <%= @user.ap_id %> + <%= to_rfc3339(@user.inserted_at) %> + <%= to_rfc3339(@user.updated_at) %> + <%= @user.ap_id %> <%= @user.nickname %> <%= @user.name %> <%= escape(@user.bio) %> - <%= escape(@user.bio) %> - <%= @user.nickname %> - - <%= if User.banner_url(@user) do %> - - <% end %> - <%= if @user.local do %> - true - <% end %> diff --git a/lib/pleroma/web/templates/feed/feed/_author.rss.eex b/lib/pleroma/web/templates/feed/feed/_author.rss.eex index 526aeddcf..22477e6b1 100644 --- a/lib/pleroma/web/templates/feed/feed/_author.rss.eex +++ b/lib/pleroma/web/templates/feed/feed/_author.rss.eex @@ -1,17 +1,10 @@ - - <%= @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 %> - +<%= "#{email(@user)} (#{escape(@user.name)})" %> +http://activitystrea.ms/schema/1.0/person +<%= @user.name %> +<%= User.avatar_url(@user) %> +<%= @user.ap_id %> +<%= to_rfc3339(@user.inserted_at) %> +<%= to_rfc3339(@user.updated_at) %> +<%= @user.nickname %> +<%= @user.name %> +<%= escape(@user.bio) %> diff --git a/lib/pleroma/web/templates/feed/feed/_tag_activity.atom.eex b/lib/pleroma/web/templates/feed/feed/_tag_activity.atom.eex index 7e2e587e1..25980c1e4 100644 --- a/lib/pleroma/web/templates/feed/feed/_tag_activity.atom.eex +++ b/lib/pleroma/web/templates/feed/feed/_tag_activity.atom.eex @@ -1,12 +1,22 @@ - http://activitystrea.ms/schema/1.0/note - http://activitystrea.ms/schema/1.0/post + http://activitystrea.ms/schema/1.0/note + http://activitystrea.ms/schema/1.0/post <%= render Phoenix.Controller.view_module(@conn), "_tag_author.atom", assigns %> - <%= @data["id"] %> - <%= activity_title(@data, Keyword.get(@feed_config, :post_title, %{})) %> - <%= activity_content(@data) %> + <%= @data["id"] %> + <%= activity_title(@data, Keyword.get(@feed_config, :post_title, %{})) %> + <%= activity_description(@data) %> + <%= to_rfc3339(@activity.data["published"]) %> + <%= to_rfc3339(@activity.data["published"]) %> + + <%= activity_context(@activity) %> + + + + <%= if @data["summary"] != "" do %> + <%= @data["summary"] %> + <% end %> <%= if @activity.local do %> @@ -15,37 +25,25 @@ <% end %> - <%= @activity.data["published"] %> - <%= @activity.data["published"] %> - - - <%= activity_context(@activity) %> - - - - <%= if @data["summary"] do %> - <%= @data["summary"] %> - <% end %> - - <%= for id <- @activity.recipients do %> - <%= if id == Pleroma.Constants.as_public() do %> + <%= for id <- @activity.recipients do %> + <%= if id == Pleroma.Constants.as_public() do %> + + <% else %> + <%= unless Regex.match?(~r/^#{Pleroma.Web.Endpoint.url()}.+followers$/, id) do %> - <% else %> - <%= unless Regex.match?(~r/^#{Pleroma.Web.Endpoint.url()}.+followers$/, id) do %> - - <% end %> + ostatus:object-type="http://activitystrea.ms/schema/1.0/person" + href="<%= id %>" /> <% end %> <% end %> + <% end %> - <%= for tag <- Pleroma.Object.hashtags(@object) do %> - - <% end %> + <%= for tag <- Pleroma.Object.hashtags(@object) do %> + + <% end %> - <%= for {emoji, file} <- @data["emoji"] || %{} do %> - - <% end %> + <%= for {emoji, file} <- @data["emoji"] || %{} do %> + + <% end %> diff --git a/lib/pleroma/web/templates/feed/feed/_tag_activity.xml.eex b/lib/pleroma/web/templates/feed/feed/_tag_activity.xml.eex index 2334e24a2..d582c83e8 100644 --- a/lib/pleroma/web/templates/feed/feed/_tag_activity.xml.eex +++ b/lib/pleroma/web/templates/feed/feed/_tag_activity.xml.eex @@ -4,9 +4,9 @@ <%= activity_context(@activity) %> <%= activity_context(@activity) %> - <%= pub_date(@activity.data["published"]) %> + <%= to_rfc2822(@activity.data["published"]) %> - <%= activity_content(@data) %> + <%= activity_description(@data) %> <%= for attachment <- @data["attachment"] || [] do %> <% end %> diff --git a/lib/pleroma/web/templates/feed/feed/_tag_author.atom.eex b/lib/pleroma/web/templates/feed/feed/_tag_author.atom.eex index 997c4936e..71c696832 100644 --- a/lib/pleroma/web/templates/feed/feed/_tag_author.atom.eex +++ b/lib/pleroma/web/templates/feed/feed/_tag_author.atom.eex @@ -1,18 +1,14 @@ - http://activitystrea.ms/schema/1.0/person - <%= @actor.ap_id %> - <%= @actor.ap_id %> - <%= @actor.nickname %> - <%= escape(@actor.bio) %> - - <%= if User.banner_url(@actor) do %> - - <% end %> - <%= if @actor.local do %> - true - <% end %> - - <%= @actor.nickname %> - <%= @actor.name %> - <%= escape(@actor.bio) %> + <%= @actor.ap_id %> + <%= @actor.nickname %> + http://activitystrea.ms/schema/1.0/person + <%= @actor.name %> + <%= User.avatar_url(@actor) %> + <%= @actor.ap_id %> + <%= to_rfc3339(@actor.inserted_at) %> + <%= to_rfc3339(@actor.updated_at) %> + <%= @actor.ap_id %> + <%= @actor.nickname %> + <%= @actor.name %> + <%= escape(@actor.bio) %> diff --git a/lib/pleroma/web/templates/feed/feed/tag.atom.eex b/lib/pleroma/web/templates/feed/feed/tag.atom.eex index 8c551feaf..14b0ee594 100644 --- a/lib/pleroma/web/templates/feed/feed/tag.atom.eex +++ b/lib/pleroma/web/templates/feed/feed/tag.atom.eex @@ -1,22 +1,20 @@ + - + <%= Routes.tag_feed_url(@conn, :feed, @tag) <> ".atom" %> + #<%= @tag %> + <%= Gettext.dpgettext("static_pages", "tag feed description", "These are public toots tagged with #%{tag}. You can interact with them if you have an account anywhere in the fediverse.", tag: @tag) %> + <%= feed_logo() %> + <%= most_recent_update(@activities) %> + - <%= '#{Routes.tag_feed_url(@conn, :feed, @tag)}.rss' %> - #<%= @tag %> - - <%= Gettext.dpgettext("static_pages", "tag feed description", "These are public toots tagged with #%{tag}. You can interact with them if you have an account anywhere in the fediverse.", tag: @tag) %> - <%= feed_logo() %> - <%= most_recent_update(@activities) %> - - <%= for activity <- @activities do %> - <%= render Phoenix.Controller.view_module(@conn), "_tag_activity.atom", Map.merge(assigns, prepare_activity(activity, actor: true)) %> - <% end %> + <%= for activity <- @activities do %> + <%= render Phoenix.Controller.view_module(@conn), "_tag_activity.atom", Map.merge(assigns, prepare_activity(activity, actor: true)) %> + <% end %> diff --git a/lib/pleroma/web/templates/feed/feed/tag.rss.eex b/lib/pleroma/web/templates/feed/feed/tag.rss.eex index 86466d367..27dde5627 100644 --- a/lib/pleroma/web/templates/feed/feed/tag.rss.eex +++ b/lib/pleroma/web/templates/feed/feed/tag.rss.eex @@ -1,8 +1,9 @@ - + - #<%= @tag %> <%= Gettext.dpgettext("static_pages", "tag feed description", "These are public toots tagged with #%{tag}. You can interact with them if you have an account anywhere in the fediverse.", tag: @tag) %> <%= '#{Routes.tag_feed_url(@conn, :feed, @tag)}.rss' %> diff --git a/lib/pleroma/web/templates/feed/feed/user.atom.eex b/lib/pleroma/web/templates/feed/feed/user.atom.eex index 97a7535ab..e36bfc66c 100644 --- a/lib/pleroma/web/templates/feed/feed/user.atom.eex +++ b/lib/pleroma/web/templates/feed/feed/user.atom.eex @@ -8,7 +8,8 @@ <%= Routes.user_feed_url(@conn, :feed, @user.nickname) <> ".atom" %> <%= @user.nickname <> "'s timeline" %> - <%= most_recent_update(@activities, @user) %> + <%= escape(@user.bio) %> + <%= most_recent_update(@activities, @user, :atom) %> <%= logo(@user) %> diff --git a/lib/pleroma/web/templates/feed/feed/user.rss.eex b/lib/pleroma/web/templates/feed/feed/user.rss.eex index a9fee244c..fae3fcf3d 100644 --- a/lib/pleroma/web/templates/feed/feed/user.rss.eex +++ b/lib/pleroma/web/templates/feed/feed/user.rss.eex @@ -1,11 +1,21 @@ - + - <%= Routes.user_feed_url(@conn, :feed, @user.nickname) <> ".rss" %> <%= @user.nickname <> "'s timeline" %> - <%= most_recent_update(@activities, @user) %> - <%= logo(@user) %> <%= '#{Routes.user_feed_url(@conn, :feed, @user.nickname)}.rss' %> + " + rel="self" type="application/rss+xml" /> + <%= escape(@user.bio) %> + + <%= logo(@user) %> + <%= @user.nickname <> "'s timeline" %> + <%= '#{Routes.user_feed_url(@conn, :feed, @user.nickname)}.rss' %> + <%= render Phoenix.Controller.view_module(@conn), "_author.rss", assigns %> diff --git a/test/pleroma/web/feed/tag_controller_test.exs b/test/pleroma/web/feed/tag_controller_test.exs index 1bd2b157c..58ab8f137 100644 --- a/test/pleroma/web/feed/tag_controller_test.exs +++ b/test/pleroma/web/feed/tag_controller_test.exs @@ -63,7 +63,6 @@ defmodule Pleroma.Web.Feed.TagControllerTest do ] assert xpath(xml, ~x"//feed/entry/author/name/text()"ls) == [user.nickname, user.nickname] - assert xpath(xml, ~x"//feed/entry/author/id/text()"ls) == [user.ap_id, user.ap_id] conn = conn @@ -138,8 +137,8 @@ defmodule Pleroma.Web.Feed.TagControllerTest do ] assert xpath(xml, ~x"//channel/item/pubDate/text()"sl) == [ - FeedView.pub_date(activity2.data["published"]), - FeedView.pub_date(activity1.data["published"]) + FeedView.to_rfc2822(activity2.data["published"]), + FeedView.to_rfc2822(activity1.data["published"]) ] assert xpath(xml, ~x"//channel/item/enclosure/@url"sl) == [ diff --git a/test/pleroma/web/feed/user_controller_test.exs b/test/pleroma/web/feed/user_controller_test.exs index 38cde3315..de32d3d4b 100644 --- a/test/pleroma/web/feed/user_controller_test.exs +++ b/test/pleroma/web/feed/user_controller_test.exs @@ -74,7 +74,7 @@ defmodule Pleroma.Web.Feed.UserControllerTest do |> SweetXml.parse() |> SweetXml.xpath(~x"//entry/title/text()"l) - assert activity_titles == ['42 & Thi...', 'This & t...'] + assert activity_titles == ['2hu', '2hu & as'] assert resp =~ FeedView.escape(object.data["content"]) assert resp =~ FeedView.escape(object.data["summary"]) assert resp =~ FeedView.escape(object.data["context"]) @@ -90,7 +90,7 @@ defmodule Pleroma.Web.Feed.UserControllerTest do |> SweetXml.parse() |> SweetXml.xpath(~x"//entry/title/text()"l) - assert activity_titles == ['This & t...'] + assert activity_titles == ['2hu & as'] end test "gets a rss feed", %{conn: conn, user: user, object: object, max_id: max_id} do @@ -105,7 +105,7 @@ defmodule Pleroma.Web.Feed.UserControllerTest do |> SweetXml.parse() |> SweetXml.xpath(~x"//item/title/text()"l) - assert activity_titles == ['42 & Thi...', 'This & t...'] + assert activity_titles == ['2hu', '2hu & as'] assert resp =~ FeedView.escape(object.data["content"]) assert resp =~ FeedView.escape(object.data["summary"]) assert resp =~ FeedView.escape(object.data["context"]) @@ -121,7 +121,7 @@ defmodule Pleroma.Web.Feed.UserControllerTest do |> SweetXml.parse() |> SweetXml.xpath(~x"//item/title/text()"l) - assert activity_titles == ['This & t...'] + assert activity_titles == ['2hu & as'] end test "returns 404 for a missing feed", %{conn: conn} do