diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex index 0b1bc473a..202d648e1 100644 --- a/lib/pleroma/web/twitter_api/twitter_api.ex +++ b/lib/pleroma/web/twitter_api/twitter_api.ex @@ -4,28 +4,23 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.TwitterAPI.Representers.{ActivityRepresenter, UserRepresenter} alias Pleroma.Web.OStatus + alias Pleroma.Formatter import Ecto.Query + import Pleroma.Web.TwitterAPI.Utils - def to_for_user_and_mentions(user, mentions) do + def to_for_user_and_mentions(user, mentions, inReplyTo) do default_to = [ User.ap_followers(user), "https://www.w3.org/ns/activitystreams#Public" ] - default_to ++ Enum.map(mentions, fn ({_, %{ap_id: ap_id}}) -> ap_id end) - end - - def format_input(text, mentions) do - HtmlSanitizeEx.strip_tags(text) - |> String.replace("\n", "
") - |> add_user_links(mentions) - end - - def attachments_from_ids(ids) do - Enum.map(ids || [], fn (media_id) -> - Repo.get(Object, media_id).data - end) + to = default_to ++ Enum.map(mentions, fn ({_, %{ap_id: ap_id}}) -> ap_id end) + if inReplyTo do + Enum.uniq([inReplyTo.data["actor"] | to]) + else + to + end end def get_replied_to_activity(id) when not is_nil(id) do @@ -34,62 +29,16 @@ def get_replied_to_activity(id) when not is_nil(id) do def get_replied_to_activity(_), do: nil - def add_attachments(text, attachments) do - attachment_text = Enum.map(attachments, fn - (%{"url" => [%{"href" => href} | _]}) -> - "#{href}" - _ -> "" - end) - Enum.join([text | attachment_text], "
") - end - def create_status(%User{} = user, %{"status" => status} = data) do - attachments = attachments_from_ids(data["media_ids"]) - context = Utils.generate_context_id - mentions = parse_mentions(status) - content_html = status - |> format_input(mentions) - |> add_attachments(attachments) - - to = to_for_user_and_mentions(user, mentions) - date = make_date() - - inReplyTo = get_replied_to_activity(data["in_reply_to_status_id"]) - - # Wire up reply info. - [to, context, object, additional] = - if inReplyTo do - context = inReplyTo.data["context"] - to = to ++ [inReplyTo.data["actor"]] - - object = %{ - "type" => "Note", - "to" => to, - "content" => content_html, - "published" => date, - "context" => context, - "attachment" => attachments, - "actor" => user.ap_id, - "inReplyTo" => inReplyTo.data["object"]["id"], - "inReplyToStatusId" => inReplyTo.id, - } - additional = %{} - - [to, context, object, additional] - else - object = %{ - "type" => "Note", - "to" => to, - "content" => content_html, - "published" => date, - "context" => context, - "attachment" => attachments, - "actor" => user.ap_id - } - [to, context, object, %{}] + with attachments <- attachments_from_ids(data["media_ids"]), + mentions <- parse_mentions(status), + inReplyTo <- get_replied_to_activity(data["in_reply_to_status_id"]), + to <- to_for_user_and_mentions(user, mentions, inReplyTo), + content_html <- make_content_html(status, mentions, attachments), + context <- make_context(inReplyTo), + object <- make_note_data(user.ap_id, to, context, content_html, attachments, inReplyTo) do + ActivityPub.create(to, user, context, object) end - - ActivityPub.create(to, user, context, object, additional, data) end def fetch_friend_statuses(user, opts \\ %{}) do @@ -243,24 +192,6 @@ def parse_mentions(text) do |> Enum.filter(fn ({_match, user}) -> user end) end - def add_user_links(text, mentions) do - mentions = mentions - |> Enum.sort_by(fn ({name, _}) -> -String.length(name) end) - |> Enum.map(fn({name, user}) -> {name, user, Ecto.UUID.generate} end) - - # This replaces the mention with a unique reference first so it doesn't - # contain parts of other replaced mentions. There probably is a better - # solution for this... - step_one = mentions - |> Enum.reduce(text, fn ({match, _user, uuid}, text) -> - String.replace(text, match, uuid) - end) - - Enum.reduce(mentions, step_one, fn ({match, %User{ap_id: ap_id}, uuid}, text) -> - String.replace(text, uuid, "#{match}") - end) - end - def register_user(params) do params = %{ nickname: params["nickname"], diff --git a/lib/pleroma/web/twitter_api/utils.ex b/lib/pleroma/web/twitter_api/utils.ex new file mode 100644 index 000000000..6f5c9f727 --- /dev/null +++ b/lib/pleroma/web/twitter_api/utils.ex @@ -0,0 +1,72 @@ +defmodule Pleroma.Web.TwitterAPI.Utils do + alias Pleroma.{Repo, Object, Formatter, User, Activity} + alias Pleroma.Web.ActivityPub.Utils + + def attachments_from_ids(ids) do + Enum.map(ids || [], fn (media_id) -> + Repo.get(Object, media_id).data + end) + end + + def add_attachments(text, attachments) do + attachment_text = Enum.map(attachments, fn + (%{"url" => [%{"href" => href} | _]}) -> + "#{href}" + _ -> "" + end) + Enum.join([text | attachment_text], "
") + end + + def format_input(text, mentions) do + HtmlSanitizeEx.strip_tags(text) + |> Formatter.linkify + |> String.replace("\n", "
") + |> add_user_links(mentions) + end + + def add_user_links(text, mentions) do + mentions = mentions + |> Enum.sort_by(fn ({name, _}) -> -String.length(name) end) + |> Enum.map(fn({name, user}) -> {name, user, Ecto.UUID.generate} end) + + # This replaces the mention with a unique reference first so it doesn't + # contain parts of other replaced mentions. There probably is a better + # solution for this... + step_one = mentions + |> Enum.reduce(text, fn ({match, _user, uuid}, text) -> + String.replace(text, match, uuid) + end) + + Enum.reduce(mentions, step_one, fn ({match, %User{ap_id: ap_id}, uuid}, text) -> + String.replace(text, uuid, "#{match}") + end) + end + + def make_content_html(status, mentions, attachments) do + status + |> format_input(mentions) + |> add_attachments(attachments) + end + + def make_context(%Activity{data: %{"context" => context}}), do: context + def make_context(_), do: Utils.generate_context_id + + def make_note_data(actor, to, context, content_html, attachments, inReplyTo) do + object = %{ + "type" => "Note", + "to" => to, + "content" => content_html, + "context" => context, + "attachment" => attachments, + "actor" => actor + } + + if inReplyTo do + object + |> Map.put("inReplyTo", inReplyTo.data["object"]["id"]) + |> Map.put("inReplyToStatusId", inReplyTo.id) + else + object + end + end +end diff --git a/test/web/twitter_api/twitter_api_test.exs b/test/web/twitter_api/twitter_api_test.exs index d70ef88f3..e20960228 100644 --- a/test/web/twitter_api/twitter_api_test.exs +++ b/test/web/twitter_api/twitter_api_test.exs @@ -2,6 +2,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do use Pleroma.DataCase alias Pleroma.Builders.{UserBuilder, ActivityBuilder} alias Pleroma.Web.TwitterAPI.TwitterAPI + alias Pleroma.Web.TwitterAPI.Utils alias Pleroma.{Activity, User, Object, Repo} alias Pleroma.Web.TwitterAPI.Representers.{ActivityRepresenter, UserRepresenter} alias Pleroma.Web.ActivityPub.ActivityPub @@ -261,7 +262,7 @@ test "it adds user links to an existing text" do mentions = TwitterAPI.parse_mentions(text) expected_text = "@gsimg According to @archaeme, that is @daggsy. Also hello @archaeme@archae.me" - assert TwitterAPI.add_user_links(text, mentions) == expected_text + assert Utils.add_user_links(text, mentions) == expected_text end test "it favorites a status, returns the updated status" do