Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F85829548
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Authored By
Unknown
Size
12 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex
index a8154859a..96ddcc480 100644
--- a/lib/pleroma/activity.ex
+++ b/lib/pleroma/activity.ex
@@ -1,46 +1,51 @@
defmodule Pleroma.Activity do
use Ecto.Schema
alias Pleroma.{Repo, Activity, Notification}
import Ecto.Query
schema "activities" do
field :data, :map
field :local, :boolean, default: true
field :actor, :string
field :recipients, {:array, :string}
has_many :notifications, Notification, on_delete: :delete_all
timestamps()
end
def get_by_ap_id(ap_id) do
Repo.one(from activity in Activity,
where: fragment("(?)->>'id' = ?", activity.data, ^to_string(ap_id)))
end
# TODO:
# Go through these and fix them everywhere.
# Wrong name, only returns create activities
def all_by_object_ap_id_q(ap_id) do
from activity in Activity,
where: fragment("coalesce((?)->'object'->>'id', (?)->>'object') = ?", activity.data, activity.data, ^to_string(ap_id)),
where: fragment("(?)->>'type' = 'Create'", activity.data)
end
# Wrong name, returns all.
def all_non_create_by_object_ap_id_q(ap_id) do
from activity in Activity,
where: fragment("coalesce((?)->'object'->>'id', (?)->>'object') = ?", activity.data, activity.data, ^to_string(ap_id))
end
# Wrong name plz fix thx
def all_by_object_ap_id(ap_id) do
Repo.all(all_by_object_ap_id_q(ap_id))
end
+ def create_activity_by_object_id_query(ap_ids) do
+ from activity in Activity,
+ where: fragment("coalesce((?)->'object'->>'id', (?)->>'object') = ANY(?)", activity.data, activity.data, ^ap_ids),
+ where: fragment("(?)->>'type' = 'Create'", activity.data)
+ end
+
def get_create_activity_by_object_ap_id(ap_id) do
- Repo.one(from activity in Activity,
- where: fragment("coalesce((?)->'object'->>'id', (?)->>'object') = ?", activity.data, activity.data, ^to_string(ap_id)),
- where: fragment("(?)->>'type' = 'Create'", activity.data))
+ create_activity_by_object_id_query([ap_id])
+ |> Repo.one
end
end
diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex
index 822a6800c..a4539d47e 100644
--- a/lib/pleroma/web/mastodon_api/views/status_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/status_view.ex
@@ -1,153 +1,177 @@
defmodule Pleroma.Web.MastodonAPI.StatusView do
use Pleroma.Web, :view
alias Pleroma.Web.MastodonAPI.{AccountView, StatusView}
alias Pleroma.{User, Activity}
alias Pleroma.Web.CommonAPI.Utils
alias Pleroma.Web.MediaProxy
+ alias Pleroma.Repo
+
+ # TODO: Add cached version.
+ defp get_replied_to_activities(activities) do
+ activities
+ |> Enum.map(fn
+ (%{data: %{"type" => "Create", "object" => %{"inReplyTo" => inReplyTo}}}) ->
+ (inReplyTo != "") && inReplyTo
+ _ -> nil
+ end)
+ |> Enum.filter(&(&1))
+ |> Activity.create_activity_by_object_id_query()
+ |> Repo.all
+ |> Enum.reduce(%{}, fn(activity, acc) -> Map.put(acc,activity.data["object"]["id"], activity) end)
+ end
def render("index.json", opts) do
- render_many(opts.activities, StatusView, "status.json", opts)
+ replied_to_activities = get_replied_to_activities(opts.activities)
+ render_many(opts.activities, StatusView, "status.json", Map.put(opts, :replied_to_activities, replied_to_activities))
end
def render("status.json", %{activity: %{data: %{"type" => "Announce", "object" => object}} = activity} = opts) do
user = User.get_cached_by_ap_id(activity.data["actor"])
created_at = Utils.to_masto_date(activity.data["published"])
reblogged = Activity.get_create_activity_by_object_ap_id(object)
reblogged = render("status.json", Map.put(opts, :activity, reblogged))
mentions = activity.recipients
|> Enum.map(fn (ap_id) -> User.get_cached_by_ap_id(ap_id) end)
|> Enum.filter(&(&1))
|> Enum.map(fn (user) -> AccountView.render("mention.json", %{user: user}) end)
%{
id: to_string(activity.id),
uri: object,
url: nil, # TODO: This might be wrong, check with mastodon.
account: AccountView.render("account.json", %{user: user}),
in_reply_to_id: nil,
in_reply_to_account_id: nil,
reblog: reblogged,
content: reblogged[:content],
created_at: created_at,
reblogs_count: 0,
favourites_count: 0,
reblogged: false,
favourited: false,
muted: false,
sensitive: false,
spoiler_text: "",
visibility: "public",
media_attachments: [],
mentions: mentions,
tags: [],
application: %{
name: "Web",
website: nil
},
language: nil,
emojis: []
}
end
+ def get_reply_to(activity, %{replied_to_activities: replied_to_activities}) do
+ id = activity.data["object"]["inReplyTo"]
+ replied_to_activities[activity.data["object"]["inReplyTo"]]
+ end
+
+ def get_reply_to(%{data: %{"object" => object}}, _) do
+ if object["inReplyTo"] && object["inReplyTo"] != "" do
+ Activity.get_create_activity_by_object_ap_id(object["inReplyTo"])
+ else
+ nil
+ end
+ end
+
def render("status.json", %{activity: %{data: %{"object" => object}} = activity} = opts) do
user = User.get_cached_by_ap_id(activity.data["actor"])
like_count = object["like_count"] || 0
announcement_count = object["announcement_count"] || 0
tags = object["tag"] || []
sensitive = object["sensitive"] || Enum.member?(tags, "nsfw")
mentions = activity.recipients
|> Enum.map(fn (ap_id) -> User.get_cached_by_ap_id(ap_id) end)
|> Enum.filter(&(&1))
|> Enum.map(fn (user) -> AccountView.render("mention.json", %{user: user}) end)
repeated = opts[:for] && opts[:for].ap_id in (object["announcements"] || [])
favorited = opts[:for] && opts[:for].ap_id in (object["likes"] || [])
attachments = render_many(object["attachment"] || [], StatusView, "attachment.json", as: :attachment)
created_at = Utils.to_masto_date(object["published"])
- # TODO: Add cached version.
- reply_to = if object["inReplyTo"] && object["inReplyTo"] != "" do
- Activity.get_create_activity_by_object_ap_id(object["inReplyTo"])
- else
- nil
- end
+ reply_to = get_reply_to(activity, opts)
reply_to_user = reply_to && User.get_cached_by_ap_id(reply_to.data["actor"])
emojis = (activity.data["object"]["emoji"] || [])
|> Enum.map(fn {name, url} ->
name = HtmlSanitizeEx.strip_tags(name)
url = HtmlSanitizeEx.strip_tags(url)
%{ shortcode: name, url: url, static_url: url }
end)
%{
id: to_string(activity.id),
uri: object["id"],
url: object["external_url"] || object["id"],
account: AccountView.render("account.json", %{user: user}),
in_reply_to_id: reply_to && reply_to.id,
in_reply_to_account_id: reply_to_user && reply_to_user.id,
reblog: nil,
content: HtmlSanitizeEx.basic_html(object["content"]),
created_at: created_at,
reblogs_count: announcement_count,
favourites_count: like_count,
reblogged: !!repeated,
favourited: !!favorited,
muted: false,
sensitive: sensitive,
spoiler_text: object["summary"] || "",
visibility: get_visibility(object),
media_attachments: attachments |> Enum.take(4),
mentions: mentions,
tags: [], # fix,
application: %{
name: "Web",
website: nil
},
language: nil,
emojis: emojis
}
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"
Enum.any?(to, &(String.contains?(&1, "/followers"))) -> "private"
true -> "direct"
end
end
def render("attachment.json", %{attachment: attachment}) do
[%{"mediaType" => media_type, "href" => href} | _] = attachment["url"]
type = cond do
String.contains?(media_type, "image") -> "image"
String.contains?(media_type, "video") -> "video"
String.contains?(media_type, "audio") -> "audio"
true -> "unknown"
end
<< hash_id::signed-32, _rest::binary >> = :crypto.hash(:md5, href)
%{
id: to_string(attachment["id"] || hash_id),
url: MediaProxy.url(href),
remote_url: href,
preview_url: MediaProxy.url(href),
text_url: href,
type: type
}
end
end
diff --git a/test/web/mastodon_api/status_view_test.exs b/test/web/mastodon_api/status_view_test.exs
index b08127639..74f5b7133 100644
--- a/test/web/mastodon_api/status_view_test.exs
+++ b/test/web/mastodon_api/status_view_test.exs
@@ -1,118 +1,124 @@
defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
use Pleroma.DataCase
alias Pleroma.Web.MastodonAPI.{StatusView, AccountView}
alias Pleroma.User
alias Pleroma.Web.OStatus
alias Pleroma.Web.CommonAPI
import Pleroma.Factory
test "a note activity" do
note = insert(:note_activity)
user = User.get_cached_by_ap_id(note.data["actor"])
status = StatusView.render("status.json", %{activity: note})
created_at = (note.data["object"]["published"] || "")
|> String.replace(~r/\.\d+Z/, ".000Z")
expected = %{
id: to_string(note.id),
uri: note.data["object"]["id"],
url: note.data["object"]["id"],
account: AccountView.render("account.json", %{user: user}),
in_reply_to_id: nil,
in_reply_to_account_id: nil,
reblog: nil,
content: HtmlSanitizeEx.basic_html(note.data["object"]["content"]),
created_at: created_at,
reblogs_count: 0,
favourites_count: 0,
reblogged: false,
favourited: false,
muted: false,
sensitive: false,
spoiler_text: note.data["object"]["summary"],
visibility: "public",
media_attachments: [],
mentions: [],
tags: [],
application: %{
name: "Web",
website: nil
},
language: nil,
emojis: [
%{
shortcode: "2hu",
url: "corndog.png",
static_url: "corndog.png"
}
]
}
assert status == expected
end
test "a reply" do
note = insert(:note_activity)
user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{"status" => "he", "in_reply_to_status_id" => note.id})
- assert activity.data["object"]["inReplyTo"] == note.data["object"]["id"]
+ status = StatusView.render("status.json", %{activity: activity})
+
+ assert status.in_reply_to_id == note.id
+
+ [status] = StatusView.render("index.json", %{activities: [activity], as: :activity})
+
+ assert status.in_reply_to_id == note.id
end
test "contains mentions" do
incoming = File.read!("test/fixtures/incoming_reply_mastodon.xml")
# a user with this ap id might be in the cache.
recipient = "https://pleroma.soykaf.com/users/lain"
user = insert(:user, %{ap_id: recipient})
{:ok, [activity]} = OStatus.handle_incoming(incoming)
status = StatusView.render("status.json", %{activity: activity})
assert status.mentions == [AccountView.render("mention.json", %{user: user})]
end
test "attachments" do
object = %{
"type" => "Image",
"url" => [
%{
"mediaType" => "image/png",
"href" => "someurl"
}
],
"uuid" => 6
}
expected = %{
id: "1638338801",
type: "image",
url: "someurl",
remote_url: "someurl",
preview_url: "someurl",
text_url: "someurl"
}
assert expected == StatusView.render("attachment.json", %{attachment: object})
# If theres a "id", use that instead of the generated one
object = Map.put(object, "id", 2)
assert %{id: "2"} = StatusView.render("attachment.json", %{attachment: object})
end
test "a reblog" do
user = insert(:user)
activity = insert(:note_activity)
{:ok, reblog, _} = CommonAPI.repeat(activity.id, user)
represented = StatusView.render("status.json", %{for: user, activity: reblog})
assert represented[:id] == to_string(reblog.id)
assert represented[:reblog][:id] == to_string(activity.id)
assert represented[:emojis] == []
end
end
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, Oct 31, 9:03 PM (15 h, 5 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1801823
Default Alt Text
(12 KB)
Attached To
Mode
rPUBE pleroma-upstream
Attached
Detach File
Event Timeline