X-Git-Url: http://git.squeep.com/?a=blobdiff_plain;f=lib%2Fpleroma%2Fweb%2Fmastodon_api%2Fviews%2Fstatus_view.ex;h=6836d331a7ae89c5d2e58102f68ae55a26c5f698;hb=4cab98b7bfc2117055c97a36369759047083cef9;hp=a9f607aa5dd8b38d8da006471cc847eb18bf50c6;hpb=56956de6fa1818d52e870fe719e6e20a0e408a30;p=akkoma diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index a9f607aa5..6836d331a 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -7,6 +7,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do alias Pleroma.Activity alias Pleroma.HTML + alias Pleroma.Object alias Pleroma.Repo alias Pleroma.User alias Pleroma.Web.CommonAPI @@ -15,12 +16,15 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do alias Pleroma.Web.MastodonAPI.StatusView alias Pleroma.Web.MediaProxy + import Pleroma.Web.ActivityPub.Visibility, only: [get_visibility: 1] + # TODO: Add cached version. defp get_replied_to_activities(activities) do activities |> Enum.map(fn - %{data: %{"type" => "Create", "object" => %{"inReplyTo" => in_reply_to}}} -> - in_reply_to != "" && in_reply_to + %{data: %{"type" => "Create", "object" => object}} -> + object = Object.normalize(object) + object.data["inReplyTo"] != "" && object.data["inReplyTo"] _ -> nil @@ -29,7 +33,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do |> Activity.create_by_object_ap_id() |> Repo.all() |> Enum.reduce(%{}, fn activity, acc -> - Map.put(acc, activity.data["object"]["id"], activity) + object = Object.normalize(activity) + Map.put(acc, object.data["id"], activity) end) end @@ -55,8 +60,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do defp get_context_id(_), do: nil defp reblogged?(activity, user) do - object = activity.data["object"] || %{} - present?(user && user.ap_id in (object["announcements"] || [])) + object = Object.normalize(activity) || %{} + present?(user && user.ap_id in (object.data["announcements"] || [])) end def render("index.json", opts) do @@ -72,14 +77,23 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do def render( "status.json", - %{activity: %{data: %{"type" => "Announce", "object" => object}} = activity} = opts + %{activity: %{data: %{"type" => "Announce", "object" => _object}} = activity} = opts ) do user = get_user(activity.data["actor"]) created_at = Utils.to_masto_date(activity.data["published"]) + activity_object = Object.normalize(activity) + + reblogged_activity = + Activity.create_by_object_ap_id(activity_object.data["id"]) + |> Activity.with_preloaded_bookmark(opts[:for]) + |> Repo.one() - reblogged_activity = Activity.get_create_by_object_ap_id(object) reblogged = render("status.json", Map.put(opts, :activity, reblogged_activity)) + favorited = opts[:for] && opts[:for].ap_id in (activity_object.data["likes"] || []) + + bookmarked = Activity.get_bookmark(reblogged_activity, opts[:for]) != nil + mentions = activity.recipients |> Enum.map(fn ap_id -> User.get_cached_by_ap_id(ap_id) end) @@ -88,8 +102,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do %{ id: to_string(activity.id), - uri: object, - url: object, + uri: activity_object.data["id"], + url: activity_object.data["id"], account: AccountView.render("account.json", %{user: user}), in_reply_to_id: nil, in_reply_to_account_id: nil, @@ -100,8 +114,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do replies_count: 0, favourites_count: 0, reblogged: reblogged?(reblogged_activity, opts[:for]), - favourited: false, - bookmarked: false, + favourited: present?(favorited), + bookmarked: present?(bookmarked), muted: false, pinned: pinned?(activity, user), sensitive: false, @@ -122,14 +136,16 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do } end - def render("status.json", %{activity: %{data: %{"object" => object}} = activity} = opts) do + def render("status.json", %{activity: %{data: %{"object" => _object}} = activity} = opts) do + object = Object.normalize(activity) + user = get_user(activity.data["actor"]) - like_count = object["like_count"] || 0 - announcement_count = object["announcement_count"] || 0 + like_count = object.data["like_count"] || 0 + announcement_count = object.data["announcement_count"] || 0 - tags = object["tag"] || [] - sensitive = object["sensitive"] || Enum.member?(tags, "nsfw") + tags = object.data["tag"] || [] + sensitive = object.data["sensitive"] || Enum.member?(tags, "nsfw") mentions = activity.recipients @@ -137,15 +153,23 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do |> Enum.filter(& &1) |> Enum.map(fn user -> AccountView.render("mention.json", %{user: user}) end) - favorited = opts[:for] && opts[:for].ap_id in (object["likes"] || []) - bookmarked = opts[:for] && object["id"] in opts[:for].bookmarks + favorited = opts[:for] && opts[:for].ap_id in (object.data["likes"] || []) + + bookmarked = Activity.get_bookmark(activity, opts[:for]) != nil - attachment_data = object["attachment"] || [] + thread_muted? = + case activity.thread_muted? do + thread_muted? when is_boolean(thread_muted?) -> thread_muted? + nil -> CommonAPI.thread_muted?(user, activity) + end + + attachment_data = object.data["attachment"] || [] attachments = render_many(attachment_data, StatusView, "attachment.json", as: :attachment) - created_at = Utils.to_masto_date(object["published"]) + created_at = Utils.to_masto_date(object.data["published"]) reply_to = get_reply_to(activity, opts) + reply_to_user = reply_to && get_user(reply_to.data["actor"]) content = @@ -167,7 +191,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do "mastoapi:content" ) - summary = object["summary"] || "" + summary = object.data["summary"] || "" summary_html = summary @@ -190,12 +214,12 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do if user.local do Pleroma.Web.Router.Helpers.o_status_url(Pleroma.Web.Endpoint, :notice, activity) else - object["external_url"] || object["id"] + object.data["external_url"] || object.data["id"] end %{ id: to_string(activity.id), - uri: object["id"], + uri: object.data["id"], url: url, account: AccountView.render("account.json", %{user: user}), in_reply_to_id: reply_to && to_string(reply_to.id), @@ -205,17 +229,18 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do content: content_html, created_at: created_at, reblogs_count: announcement_count, - replies_count: object["repliesCount"] || 0, + replies_count: object.data["repliesCount"] || 0, favourites_count: like_count, reblogged: reblogged?(activity, opts[:for]), favourited: present?(favorited), bookmarked: present?(bookmarked), - muted: CommonAPI.thread_muted?(user, activity) || User.mutes?(opts[:for], user), + muted: thread_muted? || User.mutes?(opts[:for], user), pinned: pinned?(activity, user), sensitive: sensitive, spoiler_text: summary_html, visibility: get_visibility(object), media_attachments: attachments, + poll: render("poll.json", %{object: object, for: opts[:for]}), mentions: mentions, tags: build_tags(tags), application: %{ @@ -223,10 +248,11 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do website: nil }, language: nil, - emojis: build_emojis(activity.data["object"]["emoji"]), + emojis: build_emojis(object.data["emoji"]), pleroma: %{ local: activity.local, conversation_id: get_context_id(activity), + in_reply_to_account_acct: reply_to_user && reply_to_user.nickname, content: %{"text/plain" => content_plaintext}, spoiler_text: %{"text/plain" => summary_plaintext} } @@ -265,8 +291,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do provider_url: page_url_data.scheme <> "://" <> page_url_data.host, url: page_url, image: image_url |> MediaProxy.url(), - title: rich_media[:title], - description: rich_media[:description], + title: rich_media[:title] || "", + description: rich_media[:description] || "", pleroma: %{ opengraph: rich_media } @@ -304,64 +330,102 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do } end - def get_reply_to(activity, %{replied_to_activities: replied_to_activities}) do - with nil <- replied_to_activities[activity.data["object"]["inReplyTo"]] do - # If user didn't participate in the thread - Activity.get_in_reply_to_activity(activity) - end - end + def render("poll.json", %{object: object} = opts) do + {multiple, options} = + case object.data do + %{"anyOf" => options} when is_list(options) -> {true, options} + %{"oneOf" => options} when is_list(options) -> {false, options} + _ -> {nil, nil} + end - def get_reply_to(%{data: %{"object" => object}}, _) do - if object["inReplyTo"] && object["inReplyTo"] != "" do - Activity.get_create_by_object_ap_id(object["inReplyTo"]) + if options do + end_time = + (object.data["closed"] || object.data["endTime"]) + |> NaiveDateTime.from_iso8601!() + + expired = + end_time + |> NaiveDateTime.compare(NaiveDateTime.utc_now()) + |> case do + :lt -> true + _ -> false + end + + voted = + if opts[:for] do + existing_votes = + Pleroma.Web.ActivityPub.Utils.get_existing_votes(opts[:for].ap_id, object) + + existing_votes != [] or opts[:for].ap_id == object.data["actor"] + else + false + end + + {options, votes_count} = + Enum.map_reduce(options, 0, fn %{"name" => name} = option, count -> + current_count = option["replies"]["totalItems"] || 0 + + {%{ + title: HTML.strip_tags(name), + votes_count: current_count + }, current_count + count} + end) + + %{ + # Mastodon uses separate ids for polls, but an object can't have + # more than one poll embedded so object id is fine + id: object.id, + expires_at: Utils.to_masto_date(end_time), + expired: expired, + multiple: multiple, + votes_count: votes_count, + options: options, + voted: voted, + emojis: build_emojis(object.data["emoji"]) + } else nil end end - def get_visibility(object) do - public = "https://www.w3.org/ns/activitystreams#Public" - to = object["to"] || [] - cc = object["cc"] || [] - - cond do - public in to -> - "public" - - public in cc -> - "unlisted" + def get_reply_to(activity, %{replied_to_activities: replied_to_activities}) do + object = Object.normalize(activity) - # this should use the sql for the object's activity - Enum.any?(to, &String.contains?(&1, "/followers")) -> - "private" + with nil <- replied_to_activities[object.data["inReplyTo"]] do + # If user didn't participate in the thread + Activity.get_in_reply_to_activity(activity) + end + end - length(cc) > 0 -> - "private" + def get_reply_to(%{data: %{"object" => _object}} = activity, _) do + object = Object.normalize(activity) - true -> - "direct" + if object.data["inReplyTo"] && object.data["inReplyTo"] != "" do + Activity.get_create_by_object_ap_id(object.data["inReplyTo"]) + else + nil end end - def render_content(%{"type" => "Video"} = object) do - with name when not is_nil(name) and name != "" <- object["name"] do - "
#{object["content"]}" + def render_content(%{data: %{"type" => "Video"}} = object) do + with name when not is_nil(name) and name != "" <- object.data["name"] do + "#{object.data["content"]}" else - _ -> object["content"] || "" + _ -> object.data["content"] || "" end end - def render_content(%{"type" => object_type} = object) + def render_content(%{data: %{"type" => object_type}} = object) when object_type in ["Article", "Page"] do - with summary when not is_nil(summary) and summary != "" <- object["name"], - url when is_bitstring(url) <- object["url"] do - "#{object["content"]}" + with summary when not is_nil(summary) and summary != "" <- object.data["name"], + url when is_bitstring(url) <- object.data["url"] do + "#{object.data["content"]}" else - _ -> object["content"] || "" + _ -> object.data["content"] || "" end end - def render_content(object), do: object["content"] || "" + def render_content(object), do: object.data["content"] || "" @doc """ Builds a dictionary tags.