1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
5 defmodule Pleroma.Web.Feed.FeedView do
11 alias Pleroma.Web.Gettext
12 alias Pleroma.Web.MediaProxy
14 require Pleroma.Constants
16 @days ~w(Mon Tue Wed Thu Fri Sat Sun)
17 @months ~w(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec)
19 def prepare_activity(activity, opts \\ []) do
20 object = Object.normalize(activity, fetch: false)
24 Pleroma.User.get_cached_by_ap_id(activity.actor)
30 data: Map.get(object, :data),
35 def most_recent_update(activities) do
36 with %{updated_at: updated_at} <- List.first(activities) do
37 to_rfc3339(updated_at)
41 def most_recent_update(activities, user, :atom) do
42 (List.first(activities) || user).updated_at
46 def most_recent_update(activities, user, :rss) do
47 (List.first(activities) || user).updated_at
52 case Pleroma.Config.get([:feed, :logo]) do
54 "#{Pleroma.Web.Endpoint.url()}/static/logo.svg"
57 "#{Pleroma.Web.Endpoint.url()}#{logo}"
63 user.nickname <> "@" <> Pleroma.Web.Endpoint.host()
72 def last_activity(activities), do: List.last(activities)
74 def activity_title(%{"content" => content} = data, opts \\ %{}) do
75 summary = Map.get(data, "summary", "")
79 summary != "" -> summary
80 content != "" -> activity_content(data)
85 |> Pleroma.Web.Metadata.Utils.scrub_html_and_truncate(opts[:max_length], opts[:omission])
86 |> HtmlEntities.encode()
89 def activity_description(data) do
90 content = activity_content(data)
91 summary = data["summary"]
94 content != "" -> escape(content)
95 summary != "" -> escape(summary)
96 true -> escape(data["type"])
100 def activity_content(%{"content" => content}) do
102 |> String.replace(~r/[\n\r]/, "")
105 def activity_content(_), do: ""
107 def activity_context(activity), do: escape(activity.data["context"])
109 def attachment_href(attachment) do
115 def attachment_type(attachment) do
118 |> Map.get("mediaType")
122 with %Object{data: %{"external_url" => external_url}} <- Object.get_cached_by_ap_id(id) do
135 @spec to_rfc3339(String.t() | NativeDateTime.t()) :: String.t()
136 def to_rfc3339(date) when is_binary(date) do
138 |> Timex.parse!("{ISO:Extended}")
142 def to_rfc3339(nd) do
144 |> Timex.to_datetime()
145 |> Timex.format!("{RFC3339}")
148 @spec to_rfc2822(String.t() | DateTime.t() | NativeDateTime.t()) :: String.t()
149 def to_rfc2822(datestr) when is_binary(datestr) do
151 |> Timex.parse!("{ISO:Extended}")
155 def to_rfc2822(%DateTime{} = date) do
157 |> DateTime.to_naive()
158 |> NaiveDateTime.to_erl()
159 |> rfc2822_from_erl()
162 def to_rfc2822(nd) do
164 |> Timex.to_datetime()
165 |> DateTime.to_naive()
166 |> NaiveDateTime.to_erl()
167 |> rfc2822_from_erl()
171 Builds a RFC2822 timestamp from an Erlang timestamp
172 [RFC2822 3.3 - Date and Time Specification](https://tools.ietf.org/html/rfc2822#section-3.3)
173 This function always assumes the Erlang timestamp is in Universal time, not Local time
175 def rfc2822_from_erl({{year, month, day} = date, {hour, minute, second}}) do
176 day_name = Enum.at(@days, :calendar.day_of_the_week(date) - 1)
177 month_name = Enum.at(@months, month - 1)
179 date_part = "#{day_name}, #{day} #{month_name} #{year}"
180 time_part = "#{pad(hour)}:#{pad(minute)}:#{pad(second)}"
182 date_part <> " " <> time_part <> " +0000"
187 |> Integer.to_string()
188 |> String.pad_leading(2, "0")