+ def render("history.json", %{activity: %{data: %{"object" => _object}} = activity} = opts) do
+ object = Object.normalize(activity, fetch: false)
+
+ hashtags = Object.hashtags(object)
+
+ user = CommonAPI.get_user(activity.data["actor"])
+
+ past_history =
+ Object.Updater.history_for(object.data)
+ |> Map.get("orderedItems")
+ |> Enum.map(&Map.put(&1, "id", object.data["id"]))
+ |> Enum.map(&%Object{data: &1, id: object.id})
+
+ history =
+ [object | past_history]
+ # Mastodon expects the original to be at the first
+ |> Enum.reverse()
+ |> Enum.with_index()
+ |> Enum.map(fn {object, chrono_order} ->
+ %{
+ # The history is prepended every time there is a new edit.
+ # In chrono_order, the oldest item is always at 0, and so on.
+ # The chrono_order is an invariant kept between edits.
+ chrono_order: chrono_order,
+ object: object
+ }
+ end)
+
+ individual_opts =
+ opts
+ |> Map.put(:as, :item)
+ |> Map.put(:user, user)
+ |> Map.put(:hashtags, hashtags)
+
+ render_many(history, StatusView, "history_item.json", individual_opts)
+ end
+
+ def render(
+ "history_item.json",
+ %{
+ activity: activity,
+ user: user,
+ item: %{object: object, chrono_order: chrono_order},
+ hashtags: hashtags
+ } = opts
+ ) do
+ sensitive = object.data["sensitive"] || Enum.member?(hashtags, "nsfw")
+
+ attachment_data = object.data["attachment"] || []
+ attachments = render_many(attachment_data, StatusView, "attachment.json", as: :attachment)
+
+ created_at = Utils.to_masto_date(object.data["updated"] || object.data["published"])
+
+ content =
+ object
+ |> render_content()
+
+ content_html =
+ content
+ |> Activity.HTML.get_cached_scrubbed_html_for_activity(
+ User.html_filter_policy(opts[:for]),
+ activity,
+ "mastoapi:content:#{chrono_order}"
+ )
+
+ summary = object.data["summary"] || ""
+
+ %{
+ account:
+ AccountView.render("show.json", %{
+ user: user,
+ for: opts[:for]
+ }),
+ content: content_html,
+ sensitive: sensitive,
+ spoiler_text: summary,
+ created_at: created_at,
+ media_attachments: attachments,
+ emojis: build_emojis(object.data["emoji"]),
+ poll: render(PollView, "show.json", object: object, for: opts[:for])
+ }
+ end
+
+ def render("source.json", %{activity: %{data: %{"object" => _object}} = activity} = _opts) do
+ object = Object.normalize(activity, fetch: false)
+
+ %{
+ id: activity.id,
+ text: get_source_text(Map.get(object.data, "source", "")),
+ spoiler_text: Map.get(object.data, "summary", ""),
+ content_type: get_source_content_type(object.data["source"])
+ }
+ end
+