From 3f0783c0a50c99ba4697829f9571b57d8b08f5de Mon Sep 17 00:00:00 2001 From: faried nawaz Date: Mon, 14 Nov 2022 01:50:52 +0500 Subject: [PATCH] fix atom and rss feeds for users and tags Changes: - make the XML closer to spec (RSS does not pass w3c's validator, but works) - fix dates (RFC3339 for Atom, doc says RFC822 for RSS but RFC1123 is closer) - fix attachment/enclosure links (but see below) - set feed item title to post's "summary" if present - pruned several elements that validators did not like - examples: ap_enabled, user banner urls. Specs: - https://www.rssboard.org/rss-specification - https://validator.w3.org/feed/docs/atom.html - https://www.intertwingly.net/wiki/pie/Rss20AndAtom10Compared Validators: - https://validator.w3.org/feed/ - https://rssatom.com/feedvalidator.php Attachment/enclosure links should have a "length" field (mandatory according to the spec). This is not present in the object's data map. --- lib/pleroma/web/feed/feed_view.ex | 71 +++++++++++++++++-- .../templates/feed/feed/_activity.atom.eex | 8 +-- .../web/templates/feed/feed/_activity.rss.eex | 11 +-- .../web/templates/feed/feed/_author.atom.eex | 19 +++-- .../web/templates/feed/feed/_author.rss.eex | 27 +++---- .../feed/feed/_tag_activity.atom.eex | 64 ++++++++--------- .../templates/feed/feed/_tag_author.atom.eex | 28 ++++---- .../web/templates/feed/feed/tag.atom.eex | 32 ++++----- .../web/templates/feed/feed/user.atom.eex | 4 +- .../web/templates/feed/feed/user.rss.eex | 17 +++-- 10 files changed, 162 insertions(+), 119 deletions(-) diff --git a/lib/pleroma/web/feed/feed_view.ex b/lib/pleroma/web/feed/feed_view.ex index 35a5f9482..323ede90a 100644 --- a/lib/pleroma/web/feed/feed_view.ex +++ b/lib/pleroma/web/feed/feed_view.ex @@ -21,7 +21,7 @@ def pub_date(date) when is_binary(date) do |> pub_date end - def pub_date(%DateTime{} = date), do: Timex.format!(date, "{RFC822}") + def pub_date(%DateTime{} = date), do: to_rfc1123(date) def prepare_activity(activity, opts \\ []) do object = Object.normalize(activity, fetch: false) @@ -41,13 +41,18 @@ def prepare_activity(activity, opts \\ []) 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_rfc1123() end def feed_logo do @@ -61,6 +66,10 @@ def feed_logo 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 +78,35 @@ def logo(user) 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 +138,35 @@ def escape(html) 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_rfc1123(String.t() | DateTime.t() | NativeDateTime.t()) :: String.t() + def to_rfc1123(datestr) when is_binary(datestr) do + datestr + |> Timex.parse!("{ISO:Extended}") + |> to_rfc1123() + end + + def to_rfc1123(%DateTime{} = date) do + date + |> Timex.format!("{RFC1123}") + end + + def to_rfc1123(nd) do + nd + |> Timex.to_datetime() + |> Timex.format!("{RFC1123}") + 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..7a7e494c0 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_rfc1123(@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_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..4955996c9 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)}.rss' %> - #<%= @tag %> + <%= 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) %> + - <%= 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/user.atom.eex b/lib/pleroma/web/templates/feed/feed/user.atom.eex index 97a7535ab..a0148d768 100644 --- a/lib/pleroma/web/templates/feed/feed/user.atom.eex +++ b/lib/pleroma/web/templates/feed/feed/user.atom.eex @@ -1,14 +1,14 @@ <%= 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..80ad8b161 100644 --- a/lib/pleroma/web/templates/feed/feed/user.rss.eex +++ b/lib/pleroma/web/templates/feed/feed/user.rss.eex @@ -1,11 +1,20 @@ - + - <%= 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 %>