aboutsummaryrefslogtreecommitdiff
path: root/lib/pleroma/web/twitter_api
diff options
context:
space:
mode:
Diffstat (limited to 'lib/pleroma/web/twitter_api')
-rw-r--r--lib/pleroma/web/twitter_api/controllers/util_controller.ex98
-rw-r--r--lib/pleroma/web/twitter_api/representers/activity_representer.ex87
-rw-r--r--lib/pleroma/web/twitter_api/representers/base_representer.ex16
-rw-r--r--lib/pleroma/web/twitter_api/representers/object_representer.ex1
-rw-r--r--lib/pleroma/web/twitter_api/twitter_api.ex227
-rw-r--r--lib/pleroma/web/twitter_api/twitter_api_controller.ex183
-rw-r--r--lib/pleroma/web/twitter_api/views/activity_view.ex268
-rw-r--r--lib/pleroma/web/twitter_api/views/notification_view.ex64
-rw-r--r--lib/pleroma/web/twitter_api/views/user_view.ex35
9 files changed, 677 insertions, 302 deletions
diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex
index 503719dbf..ea540b34c 100644
--- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex
+++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex
@@ -11,21 +11,21 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
def show_password_reset(conn, %{"token" => token}) do
with %{used: false} = token <- Repo.get_by(PasswordResetToken, %{token: token}),
- %User{} = user <- Repo.get(User, token.user_id) do
- render conn, "password_reset.html", %{
+ %User{} = user <- Repo.get(User, token.user_id) do
+ render(conn, "password_reset.html", %{
token: token,
user: user
- }
+ })
else
- _e -> render conn, "invalid_token.html"
+ _e -> render(conn, "invalid_token.html")
end
end
def password_reset(conn, %{"data" => data}) do
with {:ok, _} <- PasswordResetToken.reset_password(data["token"], data) do
- render conn, "password_reset_success.html"
+ render(conn, "password_reset_success.html")
else
- _e -> render conn, "password_reset_failed.html"
+ _e -> render(conn, "password_reset_failed.html")
end
end
@@ -34,14 +34,19 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
end
def remote_subscribe(conn, %{"nickname" => nick, "profile" => _}) do
- with %User{} = user <- User.get_cached_by_nickname(nick),
- avatar = User.avatar_url(user) do
+ with %User{} = user <- User.get_cached_by_nickname(nick), avatar = User.avatar_url(user) do
conn
|> render("subscribe.html", %{nickname: nick, avatar: avatar, error: false})
else
- _e -> render(conn, "subscribe.html", %{nickname: nick, avatar: nil, error: "Could not find user"})
+ _e ->
+ render(conn, "subscribe.html", %{
+ nickname: nick,
+ avatar: nil,
+ error: "Could not find user"
+ })
end
end
+
def remote_subscribe(conn, %{"user" => %{"nickname" => nick, "profile" => profile}}) do
with {:ok, %{"subscribe_address" => template}} <- WebFinger.finger(profile),
%User{ap_id: ap_id} <- User.get_cached_by_nickname(nick) do
@@ -49,7 +54,11 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
|> Phoenix.Controller.redirect(external: String.replace(template, "{uri}", ap_id))
else
_e ->
- render(conn, "subscribe.html", %{nickname: nick, avatar: nil, error: "Something went wrong."})
+ render(conn, "subscribe.html", %{
+ nickname: nick,
+ avatar: nil,
+ error: "Something went wrong."
+ })
end
end
@@ -64,17 +73,26 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
|> render("follow.html", %{error: err, acct: acct, avatar: avatar, name: name, id: id})
else
conn
- |> render("follow_login.html", %{error: false, acct: acct, avatar: avatar, name: name, id: id})
+ |> render("follow_login.html", %{
+ error: false,
+ acct: acct,
+ avatar: avatar,
+ name: name,
+ id: id
+ })
end
end
- def do_remote_follow(conn, %{"authorization" => %{"name" => username, "password" => password, "id" => id}}) do
+ def do_remote_follow(conn, %{
+ "authorization" => %{"name" => username, "password" => password, "id" => id}
+ }) do
followee = Repo.get(User, id)
avatar = User.avatar_url(followee)
name = followee.nickname
+
with %User{} = user <- User.get_cached_by_nickname(username),
true <- Pbkdf2.checkpw(password, user.password_hash),
- %User{} = followed <- Repo.get(User, id),
+ %User{} = _followed <- Repo.get(User, id),
{:ok, follower} <- User.follow(user, followee),
{:ok, _activity} <- ActivityPub.follow(follower, followee) do
conn
@@ -82,9 +100,15 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
else
_e ->
conn
- |> render("follow_login.html", %{error: "Wrong username or password", id: id, name: name, avatar: avatar})
+ |> render("follow_login.html", %{
+ error: "Wrong username or password",
+ id: id,
+ name: name,
+ avatar: avatar
+ })
end
end
+
def do_remote_follow(%{assigns: %{user: user}} = conn, %{"user" => %{"id" => id}}) do
with %User{} = followee <- Repo.get(User, id),
{:ok, follower} <- User.follow(user, followee),
@@ -93,9 +117,10 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
|> render("followed.html", %{error: false})
else
e ->
- Logger.debug("Remote follow failed with error #{inspect e}")
- conn
- |> render("followed.html", %{error: inspect(e)})
+ Logger.debug("Remote follow failed with error #{inspect(e)}")
+
+ conn
+ |> render("followed.html", %{error: inspect(e)})
end
end
@@ -107,60 +132,67 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
<config>
<site>
<name>#{Keyword.get(@instance, :name)}</name>
- <site>#{Web.base_url}</site>
+ <site>#{Web.base_url()}</site>
<textlimit>#{Keyword.get(@instance, :limit)}</textlimit>
<closed>#{!Keyword.get(@instance, :registrations_open)}</closed>
</site>
</config>
"""
+
conn
|> put_resp_content_type("application/xml")
|> send_resp(200, response)
+
_ ->
json(conn, %{
- site: %{
- name: Keyword.get(@instance, :name),
- server: Web.base_url,
- textlimit: to_string(Keyword.get(@instance, :limit)),
- closed: if(Keyword.get(@instance, :registrations_open), do: "0", else: "1")
- }
- })
+ site: %{
+ name: Keyword.get(@instance, :name),
+ server: Web.base_url(),
+ textlimit: to_string(Keyword.get(@instance, :limit)),
+ closed: if(Keyword.get(@instance, :registrations_open), do: "0", else: "1")
+ }
+ })
end
end
def version(conn, _params) do
version = Keyword.get(@instance, :version)
+
case get_format(conn) do
"xml" ->
response = "<version>#{version}</version>"
+
conn
|> put_resp_content_type("application/xml")
|> send_resp(200, response)
- _ -> json(conn, version)
+
+ _ ->
+ json(conn, version)
end
end
def emoji(conn, _params) do
- json conn, Enum.into(Formatter.get_custom_emoji(), %{})
+ json(conn, Enum.into(Formatter.get_custom_emoji(), %{}))
end
def follow_import(conn, %{"list" => %Plug.Upload{} = listfile}) do
follow_import(conn, %{"list" => File.read!(listfile.path)})
end
+
def follow_import(%{assigns: %{user: user}} = conn, %{"list" => list}) do
Task.start(fn ->
- String.split(list)
- |> Enum.map(fn nick ->
+ String.split(list)
+ |> Enum.map(fn account ->
with %User{} = follower <- User.get_cached_by_ap_id(user.ap_id),
- %User{} = followed <- User.get_or_fetch_by_nickname(nick),
- {:ok, follower} <- User.follow(follower, followed) do
+ %User{} = followed <- User.get_or_fetch(account),
+ {:ok, follower} <- User.follow(follower, followed) do
ActivityPub.follow(follower, followed)
else
- _e -> Logger.debug "follow_import: following #{nick} failed"
+ _e -> Logger.debug("follow_import: following #{account} failed")
end
end)
end)
- json conn, "job started"
+ json(conn, "job started")
end
end
diff --git a/lib/pleroma/web/twitter_api/representers/activity_representer.ex b/lib/pleroma/web/twitter_api/representers/activity_representer.ex
index 5199cef8e..9a4954de8 100644
--- a/lib/pleroma/web/twitter_api/representers/activity_representer.ex
+++ b/lib/pleroma/web/twitter_api/representers/activity_representer.ex
@@ -1,3 +1,5 @@
+# THIS MODULE IS DEPRECATED! DON'T USE IT!
+# USE THE Pleroma.Web.TwitterAPI.Views.ActivityView MODULE!
defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenter do
use Pleroma.Web.TwitterAPI.Representers.BaseRepresenter
alias Pleroma.Web.TwitterAPI.Representers.ObjectRepresenter
@@ -7,18 +9,22 @@ defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenter do
alias Pleroma.Formatter
defp user_by_ap_id(user_list, ap_id) do
- Enum.find(user_list, fn (%{ap_id: user_id}) -> ap_id == user_id end)
+ Enum.find(user_list, fn %{ap_id: user_id} -> ap_id == user_id end)
end
- def to_map(%Activity{data: %{"type" => "Announce", "actor" => actor, "published" => created_at}} = activity,
- %{users: users, announced_activity: announced_activity} = opts) do
+ def to_map(
+ %Activity{data: %{"type" => "Announce", "actor" => actor, "published" => created_at}} =
+ activity,
+ %{users: users, announced_activity: announced_activity} = opts
+ ) do
user = user_by_ap_id(users, actor)
- created_at = created_at |> Utils.date_to_asctime
+ created_at = created_at |> Utils.date_to_asctime()
text = "#{user.nickname} retweeted a status."
announced_user = user_by_ap_id(users, announced_activity.data["actor"])
retweeted_status = to_map(announced_activity, Map.merge(%{user: announced_user}, opts))
+
%{
"id" => activity.id,
"user" => UserView.render("show.json", %{user: user, for: opts[:for]}),
@@ -35,9 +41,11 @@ defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenter do
}
end
- def to_map(%Activity{data: %{"type" => "Like", "published" => created_at}} = activity,
- %{user: user, liked_activity: liked_activity} = opts) do
- created_at = created_at |> Utils.date_to_asctime
+ def to_map(
+ %Activity{data: %{"type" => "Like", "published" => created_at}} = activity,
+ %{user: user, liked_activity: liked_activity} = opts
+ ) do
+ created_at = created_at |> Utils.date_to_asctime()
text = "#{user.nickname} favorited a status."
@@ -56,12 +64,16 @@ defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenter do
}
end
- def to_map(%Activity{data: %{"type" => "Follow", "object" => followed_id}} = activity, %{user: user} = opts) do
- created_at = activity.data["published"] || (DateTime.to_iso8601(activity.inserted_at))
- created_at = created_at |> Utils.date_to_asctime
+ def to_map(
+ %Activity{data: %{"type" => "Follow", "object" => followed_id}} = activity,
+ %{user: user} = opts
+ ) do
+ created_at = activity.data["published"] || DateTime.to_iso8601(activity.inserted_at)
+ created_at = created_at |> Utils.date_to_asctime()
followed = User.get_cached_by_ap_id(followed_id)
text = "#{user.nickname} started following #{followed.nickname}"
+
%{
"id" => activity.id,
"user" => UserView.render("show.json", %{user: user, for: opts[:for]}),
@@ -79,10 +91,16 @@ defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenter do
# TODO:
# Make this more proper. Just a placeholder to not break the frontend.
- def to_map(%Activity{data: %{"type" => "Undo", "published" => created_at, "object" => undid_activity }} = activity, %{user: user} = opts) do
- created_at = created_at |> Utils.date_to_asctime
+ def to_map(
+ %Activity{
+ data: %{"type" => "Undo", "published" => created_at, "object" => undid_activity}
+ } = activity,
+ %{user: user} = opts
+ ) do
+ created_at = created_at |> Utils.date_to_asctime()
text = "#{user.nickname} undid the action at #{undid_activity}"
+
%{
"id" => activity.id,
"user" => UserView.render("show.json", %{user: user, for: opts[:for]}),
@@ -98,8 +116,12 @@ defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenter do
}
end
- def to_map(%Activity{data: %{"type" => "Delete", "published" => created_at, "object" => _ }} = activity, %{user: user} = opts) do
- created_at = created_at |> Utils.date_to_asctime
+ def to_map(
+ %Activity{data: %{"type" => "Delete", "published" => created_at, "object" => _}} =
+ activity,
+ %{user: user} = opts
+ ) do
+ created_at = created_at |> Utils.date_to_asctime()
%{
"id" => activity.id,
@@ -107,7 +129,7 @@ defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenter do
"user" => UserView.render("show.json", %{user: user, for: opts[:for]}),
"attentions" => [],
"statusnet_html" => "deleted notice {{tag",
- "text" => "deleted notice {{tag" ,
+ "text" => "deleted notice {{tag",
"is_local" => activity.local,
"is_post_verb" => false,
"created_at" => created_at,
@@ -117,8 +139,11 @@ defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenter do
}
end
- def to_map(%Activity{data: %{"object" => %{"content" => content} = object}} = activity, %{user: user} = opts) do
- created_at = object["published"] |> Utils.date_to_asctime
+ def to_map(
+ %Activity{data: %{"object" => %{"content" => content} = object}} = activity,
+ %{user: user} = opts
+ ) do
+ created_at = object["published"] |> Utils.date_to_asctime()
like_count = object["like_count"] || 0
announcement_count = object["announcement_count"] || 0
favorited = opts[:for] && opts[:for].ap_id in (object["likes"] || [])
@@ -126,10 +151,11 @@ defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenter do
mentions = opts[:mentioned] || []
- attentions = activity.recipients
- |> Enum.map(fn (ap_id) -> Enum.find(mentions, fn(user) -> ap_id == user.ap_id end) end)
- |> Enum.filter(&(&1))
- |> Enum.map(fn (user) -> UserView.render("show.json", %{user: user, for: opts[:for]}) end)
+ attentions =
+ activity.recipients
+ |> Enum.map(fn ap_id -> Enum.find(mentions, fn user -> ap_id == user.ap_id end) end)
+ |> Enum.filter(& &1)
+ |> Enum.map(fn user -> UserView.render("show.json", %{user: user, for: opts[:for]}) end)
conversation_id = conversation_id(activity)
@@ -139,13 +165,17 @@ defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenter do
tags = if possibly_sensitive, do: Enum.uniq(["nsfw" | tags]), else: tags
summary = activity.data["object"]["summary"]
- content = if !!summary and summary != "" do
- "<span>#{activity.data["object"]["summary"]}</span><br />#{content}</span>"
- else
- content
- end
- html = HtmlSanitizeEx.basic_html(content) |> Formatter.emojify(object["emoji"])
+ content =
+ if !!summary and summary != "" do
+ "<span>#{activity.data["object"]["summary"]}</span><br />#{content}</span>"
+ else
+ content
+ end
+
+ html =
+ HtmlSanitizeEx.basic_html(content)
+ |> Formatter.emojify(object["emoji"])
%{
"id" => activity.id,
@@ -174,7 +204,8 @@ defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenter do
def conversation_id(activity) do
with context when not is_nil(context) <- activity.data["context"] do
TwitterAPI.context_to_conversation_id(context)
- else _e -> nil
+ else
+ _e -> nil
end
end
diff --git a/lib/pleroma/web/twitter_api/representers/base_representer.ex b/lib/pleroma/web/twitter_api/representers/base_representer.ex
index a4ef245fc..f32a21d47 100644
--- a/lib/pleroma/web/twitter_api/representers/base_representer.ex
+++ b/lib/pleroma/web/twitter_api/representers/base_representer.ex
@@ -1,15 +1,18 @@
defmodule Pleroma.Web.TwitterAPI.Representers.BaseRepresenter do
defmacro __using__(_opts) do
quote do
- def to_json(object) do to_json(object, %{}) end
+ def to_json(object) do
+ to_json(object, %{})
+ end
+
def to_json(object, options) do
object
|> to_map(options)
- |> Poison.encode!
+ |> Jason.encode!()
end
def enum_to_list(enum, options) do
- mapping = fn (el) -> to_map(el, options) end
+ mapping = fn el -> to_map(el, options) end
Enum.map(enum, mapping)
end
@@ -17,11 +20,14 @@ defmodule Pleroma.Web.TwitterAPI.Representers.BaseRepresenter do
to_map(object, %{})
end
- def enum_to_json(enum) do enum_to_json(enum, %{}) end
+ def enum_to_json(enum) do
+ enum_to_json(enum, %{})
+ end
+
def enum_to_json(enum, options) do
enum
|> enum_to_list(options)
- |> Poison.encode!
+ |> Jason.encode!()
end
end
end
diff --git a/lib/pleroma/web/twitter_api/representers/object_representer.ex b/lib/pleroma/web/twitter_api/representers/object_representer.ex
index e2d653ba8..9af8a1691 100644
--- a/lib/pleroma/web/twitter_api/representers/object_representer.ex
+++ b/lib/pleroma/web/twitter_api/representers/object_representer.ex
@@ -4,6 +4,7 @@ defmodule Pleroma.Web.TwitterAPI.Representers.ObjectRepresenter do
def to_map(%Object{data: %{"url" => [url | _]}} = object, _opts) do
data = object.data
+
%{
url: url["href"] |> Pleroma.Web.MediaProxy.url(),
mimetype: url["mediaType"],
diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex
index 987a960bb..44ea40a4e 100644
--- a/lib/pleroma/web/twitter_api/twitter_api.ex
+++ b/lib/pleroma/web/twitter_api/twitter_api.ex
@@ -1,7 +1,6 @@
defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
alias Pleroma.{User, Activity, Repo, Object}
alias Pleroma.Web.ActivityPub.ActivityPub
- alias Pleroma.Web.TwitterAPI.Representers.ActivityRepresenter
alias Pleroma.Web.TwitterAPI.UserView
alias Pleroma.Web.{OStatus, CommonAPI}
import Ecto.Query
@@ -12,70 +11,10 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
CommonAPI.post(user, data)
end
- def fetch_friend_statuses(user, opts \\ %{}) do
- opts = opts
- |> Map.put("blocking_user", user)
- |> Map.put("user", user)
- |> Map.put("type", ["Create", "Announce", "Follow", "Like"])
-
- ActivityPub.fetch_activities([user.ap_id | user.following], opts)
- |> activities_to_statuses(%{for: user})
- end
-
- def fetch_public_statuses(user, opts \\ %{}) do
- opts = opts
- |> Map.put("local_only", true)
- |> Map.put("blocking_user", user)
- |> Map.put("type", ["Create", "Announce", "Follow"])
-
- ActivityPub.fetch_public_activities(opts)
- |> activities_to_statuses(%{for: user})
- end
-
- def fetch_public_and_external_statuses(user, opts \\ %{}) do
- opts = opts
- |> Map.put("blocking_user", user)
- |> Map.put("type", ["Create", "Announce", "Follow"])
-
- ActivityPub.fetch_public_activities(opts)
- |> activities_to_statuses(%{for: user})
- end
-
- def fetch_user_statuses(user, opts \\ %{}) do
- opts = opts
- |> Map.put("type", ["Create"])
- ActivityPub.fetch_public_activities(opts)
- |> activities_to_statuses(%{for: user})
- end
-
- def fetch_mentions(user, opts \\ %{}) do
- ActivityPub.fetch_activities([user.ap_id], opts)
- |> activities_to_statuses(%{for: user})
- end
-
- def fetch_conversation(user, id) do
- with context when is_binary(context) <- conversation_id_to_context(id),
- activities <- ActivityPub.fetch_activities_for_context(context, %{"blocking_user" => user, "user" => user}),
- statuses <- activities |> activities_to_statuses(%{for: user})
- do
- statuses
- else _e ->
- []
- end
- end
-
- def fetch_status(user, id) do
- with %Activity{} = activity <- Repo.get(Activity, id),
- true <- ActivityPub.visible_for_user?(activity, user) do
- activity_to_status(activity, %{for: user})
- end
- end
-
def follow(%User{} = follower, params) do
with {:ok, %User{} = followed} <- get_user(params),
{:ok, follower} <- User.follow(follower, followed),
- {:ok, activity} <- ActivityPub.follow(follower, followed)
- do
+ {:ok, activity} <- ActivityPub.follow(follower, followed) do
{:ok, follower, followed, activity}
else
err -> err
@@ -83,16 +22,17 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
end
def unfollow(%User{} = follower, params) do
- with { :ok, %User{} = unfollowed } <- get_user(params),
- { :ok, follower, follow_activity } <- User.unfollow(follower, unfollowed),
- { :ok, _activity } <- ActivityPub.insert(%{
- "type" => "Undo",
- "actor" => follower.ap_id,
- "object" => follow_activity.data["id"], # get latest Follow for these users
- "published" => make_date()
- })
- do
- { :ok, follower, unfollowed }
+ with {:ok, %User{} = unfollowed} <- get_user(params),
+ {:ok, follower, follow_activity} <- User.unfollow(follower, unfollowed),
+ {:ok, _activity} <-
+ ActivityPub.insert(%{
+ "type" => "Undo",
+ "actor" => follower.ap_id,
+ # get latest Follow for these users
+ "object" => follow_activity.data["id"],
+ "published" => make_date()
+ }) do
+ {:ok, follower, unfollowed}
else
err -> err
end
@@ -100,8 +40,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
def block(%User{} = blocker, params) do
with {:ok, %User{} = blocked} <- get_user(params),
- {:ok, blocker} <- User.block(blocker, blocked)
- do
+ {:ok, blocker} <- User.block(blocker, blocked) do
{:ok, blocker, blocked}
else
err -> err
@@ -110,8 +49,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
def unblock(%User{} = blocker, params) do
with {:ok, %User{} = blocked} <- get_user(params),
- {:ok, blocker} <- User.unblock(blocker, blocked)
- do
+ {:ok, blocker} <- User.unblock(blocker, blocked) do
{:ok, blocker, blocked}
else
err -> err
@@ -120,25 +58,22 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
def repeat(%User{} = user, ap_id_or_id) do
with {:ok, _announce, %{data: %{"id" => id}}} = CommonAPI.repeat(ap_id_or_id, user),
- %Activity{} = activity <- Activity.get_create_activity_by_object_ap_id(id),
- status <- activity_to_status(activity, %{for: user}) do
- {:ok, status}
+ %Activity{} = activity <- Activity.get_create_activity_by_object_ap_id(id) do
+ {:ok, activity}
end
end
def fav(%User{} = user, ap_id_or_id) do
with {:ok, _announce, %{data: %{"id" => id}}} = CommonAPI.favorite(ap_id_or_id, user),
- %Activity{} = activity <- Activity.get_create_activity_by_object_ap_id(id),
- status <- activity_to_status(activity, %{for: user}) do
- {:ok, status}
+ %Activity{} = activity <- Activity.get_create_activity_by_object_ap_id(id) do
+ {:ok, activity}
end
end
def unfav(%User{} = user, ap_id_or_id) do
with {:ok, %{data: %{"id" => id}}} = CommonAPI.unfavorite(ap_id_or_id, user),
- %Activity{} = activity <- Activity.get_create_activity_by_object_ap_id(id),
- status <- activity_to_status(activity, %{for: user}) do
- {:ok, status}
+ %Activity{} = activity <- Activity.get_create_activity_by_object_ap_id(id) do
+ {:ok, activity}
end
end
@@ -163,13 +98,15 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
<atom:link rel="enclosure" href="#{href}" type="#{type}"></atom:link>
</rsp>
"""
+
"json" ->
%{
media_id: object.id,
media_id_string: "#{object.id}}",
media_url: href,
size: 0
- } |> Poison.encode!
+ }
+ |> Jason.encode!()
end
end
@@ -189,9 +126,11 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
{:ok, user}
else
{:error, changeset} ->
- errors = Ecto.Changeset.traverse_errors(changeset, fn {msg, _opts} -> msg end)
- |> Poison.encode!
- {:error, %{error: errors}}
+ errors =
+ Ecto.Changeset.traverse_errors(changeset, fn {msg, _opts} -> msg end)
+ |> Jason.encode!()
+
+ {:error, %{error: errors}}
end
end
@@ -209,16 +148,20 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
case target = get_by_id_or_nickname(user_id) do
nil ->
{:error, "No user with such user_id"}
+
_ ->
{:ok, target}
end
+
%{"screen_name" => nickname} ->
case target = Repo.get_by(User, nickname: nickname) do
nil ->
{:error, "No user with such screen_name"}
+
_ ->
{:ok, target}
end
+
_ ->
if user do
{:ok, user}
@@ -229,6 +172,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
end
defp parse_int(string, default)
+
defp parse_int(string, default) when is_binary(string) do
with {n, _} <- Integer.parse(string) do
n
@@ -236,85 +180,54 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
_e -> default
end
end
+
defp parse_int(_, default), do: default
- def search(user, %{"q" => query} = params) do
+ def search(_user, %{"q" => query} = params) do
limit = parse_int(params["rpp"], 20)
page = parse_int(params["page"], 1)
offset = (page - 1) * limit
- q = from a in Activity,
- where: fragment("?->>'type' = 'Create'", a.data),
- where: fragment("to_tsvector('english', ?->'object'->>'content') @@ plainto_tsquery('english', ?)", a.data, ^query),
- limit: ^limit,
- offset: ^offset,
- order_by: [desc: :inserted_at] # this one isn't indexed so psql won't take the wrong index.
-
- activities = Repo.all(q)
- activities_to_statuses(activities, %{for: user})
- end
-
- defp activities_to_statuses(activities, opts) do
- Enum.map(activities, fn(activity) ->
- activity_to_status(activity, opts)
- end)
- end
-
- # For likes, fetch the liked activity, too.
- defp activity_to_status(%Activity{data: %{"type" => "Like"}} = activity, opts) do
- actor = get_in(activity.data, ["actor"])
- user = User.get_cached_by_ap_id(actor)
- [liked_activity] = Activity.all_by_object_ap_id(activity.data["object"])
-
- ActivityRepresenter.to_map(activity, Map.merge(opts, %{user: user, liked_activity: liked_activity}))
- end
-
- # For announces, fetch the announced activity and the user.
- defp activity_to_status(%Activity{data: %{"type" => "Announce"}} = activity, opts) do
- actor = get_in(activity.data, ["actor"])
- user = User.get_cached_by_ap_id(actor)
- [announced_activity] = Activity.all_by_object_ap_id(activity.data["object"])
- announced_actor = User.get_cached_by_ap_id(announced_activity.data["actor"])
-
- ActivityRepresenter.to_map(activity, Map.merge(opts, %{users: [user, announced_actor], announced_activity: announced_activity}))
- end
-
- defp activity_to_status(%Activity{data: %{"type" => "Delete"}} = activity, opts) do
- actor = get_in(activity.data, ["actor"])
- user = User.get_cached_by_ap_id(actor)
- ActivityRepresenter.to_map(activity, Map.merge(opts, %{user: user}))
- end
-
- defp activity_to_status(activity, opts) do
- actor = get_in(activity.data, ["actor"])
- user = User.get_cached_by_ap_id(actor)
- # mentioned_users = Repo.all(from user in User, where: user.ap_id in ^activity.data["to"])
- mentioned_users = Enum.map(activity.recipients || [], fn (ap_id) ->
- if ap_id do
- User.get_cached_by_ap_id(ap_id)
- else
- nil
- end
- end)
- |> Enum.filter(&(&1))
-
- ActivityRepresenter.to_map(activity, Map.merge(opts, %{user: user, mentioned: mentioned_users}))
+ q =
+ from(
+ a in Activity,
+ where: fragment("?->>'type' = 'Create'", a.data),
+ where: "https://www.w3.org/ns/activitystreams#Public" in a.recipients,
+ where:
+ fragment(
+ "to_tsvector('english', ?->'object'->>'content') @@ plainto_tsquery('english', ?)",
+ a.data,
+ ^query
+ ),
+ limit: ^limit,
+ offset: ^offset,
+ # this one isn't indexed so psql won't take the wrong index.
+ order_by: [desc: :inserted_at]
+ )
+
+ _activities = Repo.all(q)
end
defp make_date do
- DateTime.utc_now() |> DateTime.to_iso8601
+ DateTime.utc_now() |> DateTime.to_iso8601()
end
+ # DEPRECATED mostly, context objects are now created at insertion time.
def context_to_conversation_id(context) do
with %Object{id: id} <- Object.get_cached_by_ap_id(context) do
id
- else _e ->
+ else
+ _e ->
changeset = Object.context_mapping(context)
+
case Repo.insert(changeset) do
- {:ok, %{id: id}} -> id
+ {:ok, %{id: id}} ->
+ id
+
# This should be solved by an upsert, but it seems ecto
# has problems accessing the constraint inside the jsonb.
- {:error, _} -> Object.get_cached_by_ap_id(context).id
+ {:error, _} ->
+ Object.get_cached_by_ap_id(context).id
end
end
end
@@ -322,21 +235,25 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
def conversation_id_to_context(id) do
with %Object{data: %{"id" => context}} <- Repo.get(Object, id) do
context
- else _e ->
- {:error, "No such conversation"}
+ else
+ _e ->
+ {:error, "No such conversation"}
end
end
def get_external_profile(for_user, uri) do
- with {:ok, %User{} = user} <- OStatus.find_or_make_user(uri) do
+ with %User{} = user <- User.get_or_fetch(uri) do
spawn(fn ->
with url <- user.info["topic"],
- {:ok, %{body: body}} <- @httpoison.get(url, [], follow_redirect: true, timeout: 10000, recv_timeout: 20000) do
+ {:ok, %{body: body}} <-
+ @httpoison.get(url, [], follow_redirect: true, timeout: 10000, recv_timeout: 20000) do
OStatus.handle_incoming(body)
end
end)
+
{:ok, UserView.render("show.json", %{user: user, for: for_user})}
- else _e ->
+ else
+ _e ->
{:error, "Couldn't find user"}
end
end
diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex
index 848ec218f..960925f42 100644
--- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex
+++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex
@@ -1,9 +1,8 @@
defmodule Pleroma.Web.TwitterAPI.Controller do
use Pleroma.Web, :controller
- alias Pleroma.Web.TwitterAPI.{TwitterAPI, UserView}
- alias Pleroma.Web.TwitterAPI.Representers.ActivityRepresenter
+ alias Pleroma.Web.TwitterAPI.{TwitterAPI, UserView, ActivityView, NotificationView}
alias Pleroma.Web.CommonAPI
- alias Pleroma.{Repo, Activity, User}
+ alias Pleroma.{Repo, Activity, User, Notification}
alias Pleroma.Web.ActivityPub.ActivityPub
alias Ecto.Changeset
@@ -16,9 +15,10 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
def status_update(%{assigns: %{user: user}} = conn, %{"status" => _} = status_data) do
with media_ids <- extract_media_ids(status_data),
- {:ok, activity} <- TwitterAPI.create_status(user, Map.put(status_data, "media_ids", media_ids)) do
+ {:ok, activity} <-
+ TwitterAPI.create_status(user, Map.put(status_data, "media_ids", media_ids)) do
conn
- |> json(ActivityRepresenter.to_map(activity, %{user: user}))
+ |> json(ActivityView.render("activity.json", activity: activity, for: user))
else
_ -> empty_status_reply(conn)
end
@@ -35,43 +35,57 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
defp extract_media_ids(status_data) do
with media_ids when not is_nil(media_ids) <- status_data["media_ids"],
split_ids <- String.split(media_ids, ","),
- clean_ids <- Enum.reject(split_ids, fn (id) -> String.length(id) == 0 end)
- do
- clean_ids
- else _e -> []
+ clean_ids <- Enum.reject(split_ids, fn id -> String.length(id) == 0 end) do
+ clean_ids
+ else
+ _e -> []
end
end
def public_and_external_timeline(%{assigns: %{user: user}} = conn, params) do
- statuses = TwitterAPI.fetch_public_and_external_statuses(user, params)
- {:ok, json} = Poison.encode(statuses)
+ params =
+ params
+ |> Map.put("type", ["Create", "Announce"])
+ |> Map.put("blocking_user", user)
+
+ activities = ActivityPub.fetch_public_activities(params)
conn
- |> json_reply(200, json)
+ |> render(ActivityView, "index.json", %{activities: activities, for: user})
end
def public_timeline(%{assigns: %{user: user}} = conn, params) do
- statuses = TwitterAPI.fetch_public_statuses(user, params)
- {:ok, json} = Poison.encode(statuses)
+ params =
+ params
+ |> Map.put("type", ["Create", "Announce"])
+ |> Map.put("local_only", true)
+ |> Map.put("blocking_user", user)
+
+ activities = ActivityPub.fetch_public_activities(params)
conn
- |> json_reply(200, json)
+ |> render(ActivityView, "index.json", %{activities: activities, for: user})
end
def friends_timeline(%{assigns: %{user: user}} = conn, params) do
- statuses = TwitterAPI.fetch_friend_statuses(user, params)
- {:ok, json} = Poison.encode(statuses)
+ params =
+ params
+ |> Map.put("type", ["Create", "Announce", "Follow", "Like"])
+ |> Map.put("blocking_user", user)
+ |> Map.put("user", user)
+
+ activities = ActivityPub.fetch_activities([user.ap_id | user.following], params)
conn
- |> json_reply(200, json)
+ |> render(ActivityView, "index.json", %{activities: activities, for: user})
end
def show_user(conn, params) do
with {:ok, shown} <- TwitterAPI.get_user(params) do
if user = conn.assigns.user do
- render conn, UserView, "show.json", %{user: shown, for: user}
+ render(conn, UserView, "show.json", %{user: shown, for: user})
else
- render conn, UserView, "show.json", %{user: shown}
+ render(conn, UserView, "show.json", %{user: shown})
end
else
{:error, msg} ->
@@ -82,52 +96,69 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
def user_timeline(%{assigns: %{user: user}} = conn, params) do
case TwitterAPI.get_user(user, params) do
{:ok, target_user} ->
- params = Map.merge(params, %{"actor_id" => target_user.ap_id, "whole_db" => true})
- statuses = TwitterAPI.fetch_user_statuses(user, params)
+ params =
+ params
+ |> Map.put("type", ["Create", "Announce"])
+ |> Map.put("actor_id", target_user.ap_id)
+ |> Map.put("whole_db", true)
+
+ activities = ActivityPub.fetch_public_activities(params)
+
conn
- |> json_reply(200, statuses |> Poison.encode!)
+ |> render(ActivityView, "index.json", %{activities: activities, for: user})
+
{:error, msg} ->
bad_request_reply(conn, msg)
end
end
def mentions_timeline(%{assigns: %{user: user}} = conn, params) do
- statuses = TwitterAPI.fetch_mentions(user, params)
- {:ok, json} = Poison.encode(statuses)
+ activities = ActivityPub.fetch_activities([user.ap_id], params)
+
+ conn
+ |> render(ActivityView, "index.json", %{activities: activities, for: user})
+ end
+
+ def notifications(%{assigns: %{user: user}} = conn, params) do
+ notifications = Notification.for_user(user, params)
conn
- |> json_reply(200, json)
+ |> render(NotificationView, "notification.json", %{notifications: notifications, for: user})
end
def follow(%{assigns: %{user: user}} = conn, params) do
case TwitterAPI.follow(user, params) do
{:ok, user, followed, _activity} ->
render(conn, UserView, "show.json", %{user: followed, for: user})
- {:error, msg} -> forbidden_json_reply(conn, msg)
+
+ {:error, msg} ->
+ forbidden_json_reply(conn, msg)
end
end
def block(%{assigns: %{user: user}} = conn, params) do
case TwitterAPI.block(user, params) do
{:ok, user, blocked} ->
- render conn, UserView, "show.json", %{user: blocked, for: user}
- {:error, msg} -> forbidden_json_reply(conn, msg)
+ render(conn, UserView, "show.json", %{user: blocked, for: user})
+
+ {:error, msg} ->
+ forbidden_json_reply(conn, msg)
end
end
def unblock(%{assigns: %{user: user}} = conn, params) do
case TwitterAPI.unblock(user, params) do
{:ok, user, blocked} ->
- render conn, UserView, "show.json", %{user: blocked, for: user}
- {:error, msg} -> forbidden_json_reply(conn, msg)
+ render(conn, UserView, "show.json", %{user: blocked, for: user})
+
+ {:error, msg} ->
+ forbidden_json_reply(conn, msg)
end
end
def delete_post(%{assigns: %{user: user}} = conn, %{"id" => id}) do
with {:ok, delete} <- CommonAPI.delete(id, user) do
- json = ActivityRepresenter.to_json(delete, %{user: user, for: user})
- conn
- |> json_reply(200, json)
+ render(conn, ActivityView, "activity.json", %{activity: delete, for: user})
end
end
@@ -135,27 +166,36 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
case TwitterAPI.unfollow(user, params) do
{:ok, user, unfollowed} ->
render(conn, UserView, "show.json", %{user: unfollowed, for: user})
- {:error, msg} -> forbidden_json_reply(conn, msg)
+
+ {:error, msg} ->
+ forbidden_json_reply(conn, msg)
end
end
def fetch_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do
- response = Poison.encode!(TwitterAPI.fetch_status(user, id))
-
- conn
- |> json_reply(200, response)
+ with %Activity{} = activity <- Repo.get(Activity, id),
+ true <- ActivityPub.visible_for_user?(activity, user) do
+ render(conn, ActivityView, "activity.json", %{activity: activity, for: user})
+ end
end
def fetch_conversation(%{assigns: %{user: user}} = conn, %{"id" => id}) do
id = String.to_integer(id)
- response = Poison.encode!(TwitterAPI.fetch_conversation(user, id))
- conn
- |> json_reply(200, response)
+ with context when is_binary(context) <- TwitterAPI.conversation_id_to_context(id),
+ activities <-
+ ActivityPub.fetch_activities_for_context(context, %{
+ "blocking_user" => user,
+ "user" => user
+ }) do
+ conn
+ |> render(ActivityView, "index.json", %{activities: activities, for: user})
+ end
end
def upload(conn, %{"media" => media}) do
response = TwitterAPI.upload(media)
+
conn
|> put_resp_content_type("application/atom+xml")
|> send_resp(200, response)
@@ -163,12 +203,14 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
def upload_json(conn, %{"media" => media}) do
response = TwitterAPI.upload(media, "json")
+
conn
|> json_reply(200, response)
end
def get_by_id_or_ap_id(id) do
activity = Repo.get(Activity, id) || Activity.get_create_activity_by_object_ap_id(id)
+
if activity.data["type"] == "Create" do
activity
else
@@ -177,20 +219,20 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
end
def favorite(%{assigns: %{user: user}} = conn, %{"id" => id}) do
- with {:ok, status} <- TwitterAPI.fav(user, id) do
- json(conn, status)
+ with {:ok, activity} <- TwitterAPI.fav(user, id) do
+ render(conn, ActivityView, "activity.json", %{activity: activity, for: user})
end
end
def unfavorite(%{assigns: %{user: user}} = conn, %{"id" => id}) do
- with {:ok, status} <- TwitterAPI.unfav(user, id) do
- json(conn, status)
+ with {:ok, activity} <- TwitterAPI.unfav(user, id) do
+ render(conn, ActivityView, "activity.json", %{activity: activity, for: user})
end
end
def retweet(%{assigns: %{user: user}} = conn, %{"id" => id}) do
- with {:ok, status} <- TwitterAPI.repeat(user, id) do
- json(conn, status)
+ with {:ok, activity} <- TwitterAPI.repeat(user, id) do
+ render(conn, ActivityView, "activity.json", %{activity: activity, for: user})
end
end
@@ -199,8 +241,8 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
render(conn, UserView, "show.json", %{user: user})
else
{:error, errors} ->
- conn
- |> json_reply(400, Poison.encode!(errors))
+ conn
+ |> json_reply(400, Jason.encode!(errors))
end
end
@@ -219,8 +261,9 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
change <- User.info_changeset(user, %{info: new_info}),
{:ok, user} <- User.update_and_set_cache(change) do
CommonAPI.update(user)
- %{"url" => [ %{ "href" => href } | _ ]} = object.data
- response = %{ url: href } |> Poison.encode!
+ %{"url" => [%{"href" => href} | _]} = object.data
+ response = %{url: href} |> Jason.encode!()
+
conn
|> json_reply(200, response)
end
@@ -231,8 +274,9 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
new_info <- Map.put(user.info, "background", object.data),
change <- User.info_changeset(user, %{info: new_info}),
{:ok, _user} <- User.update_and_set_cache(change) do
- %{"url" => [ %{ "href" => href } | _ ]} = object.data
- response = %{ url: href } |> Poison.encode!
+ %{"url" => [%{"href" => href} | _]} = object.data
+ response = %{url: href} |> Jason.encode!()
+
conn
|> json_reply(200, response)
end
@@ -240,7 +284,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
def external_profile(%{assigns: %{user: current_user}} = conn, %{"profileurl" => uri}) do
with {:ok, user_map} <- TwitterAPI.get_external_profile(current_user, uri),
- response <- Poison.encode!(user_map) do
+ response <- Jason.encode!(user_map) do
conn
|> json_reply(200, response)
else
@@ -259,7 +303,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
changeset <- User.info_changeset(user, %{info: updated_info}),
{:ok, _user} <- User.update_and_set_cache(changeset) do
conn
- |> json_reply(200, Poison.encode!(mrn))
+ |> json_reply(200, Jason.encode!(mrn))
else
_e -> bad_request_reply(conn, "Can't update.")
end
@@ -285,9 +329,10 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
def friends_ids(%{assigns: %{user: user}} = conn, _params) do
with {:ok, friends} <- User.get_friends(user) do
- ids = friends
- |> Enum.map(fn x -> x.id end)
- |> Poison.encode!
+ ids =
+ friends
+ |> Enum.map(fn x -> x.id end)
+ |> Jason.encode!()
json(conn, ids)
else
@@ -296,15 +341,17 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
end
def empty_array(conn, _params) do
- json(conn, Poison.encode!([]))
+ json(conn, Jason.encode!([]))
end
def update_profile(%{assigns: %{user: user}} = conn, params) do
- params = if bio = params["description"] do
- Map.put(params, "bio", bio)
- else
- params
- end
+ params =
+ if bio = params["description"] do
+ bio_brs = Regex.replace(~r/\r?\n/, bio, "<br>")
+ Map.put(params, "bio", bio_brs)
+ else
+ params
+ end
with changeset <- User.update_changeset(user, params),
{:ok, user} <- User.update_and_set_cache(changeset) do
@@ -318,8 +365,10 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
end
def search(%{assigns: %{user: user}} = conn, %{"q" => _query} = params) do
+ activities = TwitterAPI.search(user, params)
+
conn
- |> json(TwitterAPI.search(user, params))
+ |> render(ActivityView, "index.json", %{activities: activities, for: user})
end
defp bad_request_reply(conn, error_message) do
@@ -339,6 +388,6 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
end
defp error_json(conn, error_message) do
- %{"error" => error_message, "request" => conn.request_path} |> Poison.encode!
+ %{"error" => error_message, "request" => conn.request_path} |> Jason.encode!()
end
end
diff --git a/lib/pleroma/web/twitter_api/views/activity_view.ex b/lib/pleroma/web/twitter_api/views/activity_view.ex
new file mode 100644
index 000000000..580d4648c
--- /dev/null
+++ b/lib/pleroma/web/twitter_api/views/activity_view.ex
@@ -0,0 +1,268 @@
+defmodule Pleroma.Web.TwitterAPI.ActivityView do
+ use Pleroma.Web, :view
+ alias Pleroma.Web.CommonAPI.Utils
+ alias Pleroma.User
+ alias Pleroma.Web.TwitterAPI.UserView
+ alias Pleroma.Web.TwitterAPI.ActivityView
+ alias Pleroma.Web.TwitterAPI.TwitterAPI
+ alias Pleroma.Web.TwitterAPI.Representers.ObjectRepresenter
+ alias Pleroma.Activity
+ alias Pleroma.Object
+ alias Pleroma.User
+ alias Pleroma.Repo
+ alias Pleroma.Formatter
+
+ import Ecto.Query
+
+ defp query_context_ids([]), do: []
+
+ defp query_context_ids(contexts) do
+ query = from(o in Object, where: fragment("(?)->>'id' = ANY(?)", o.data, ^contexts))
+
+ Repo.all(query)
+ end
+
+ defp query_users([]), do: []
+
+ defp query_users(user_ids) do
+ query = from(user in User, where: user.ap_id in ^user_ids)
+
+ Repo.all(query)
+ end
+
+ defp collect_context_ids(activities) do
+ _contexts =
+ activities
+ |> Enum.reject(& &1.data["context_id"])
+ |> Enum.map(fn %{data: data} ->
+ data["context"]
+ end)
+ |> Enum.filter(& &1)
+ |> query_context_ids()
+ |> Enum.reduce(%{}, fn %{data: %{"id" => ap_id}, id: id}, acc ->
+ Map.put(acc, ap_id, id)
+ end)
+ end
+
+ defp collect_users(activities) do
+ activities
+ |> Enum.map(fn activity ->
+ case activity.data do
+ data = %{"type" => "Follow"} ->
+ [data["actor"], data["object"]]
+
+ data ->
+ [data["actor"]]
+ end ++ activity.recipients
+ end)
+ |> List.flatten()
+ |> Enum.uniq()
+ |> query_users()
+ |> Enum.reduce(%{}, fn user, acc ->
+ Map.put(acc, user.ap_id, user)
+ end)
+ end
+
+ defp get_context_id(%{data: %{"context_id" => context_id}}, _) when not is_nil(context_id),
+ do: context_id
+
+ defp get_context_id(%{data: %{"context" => nil}}, _), do: nil
+
+ defp get_context_id(%{data: %{"context" => context}}, options) do
+ cond do
+ id = options[:context_ids][context] -> id
+ true -> TwitterAPI.context_to_conversation_id(context)
+ end
+ end
+
+ defp get_context_id(_, _), do: nil
+
+ defp get_user(ap_id, opts) do
+ cond do
+ user = opts[:users][ap_id] ->
+ user
+
+ String.ends_with?(ap_id, "/followers") ->
+ nil
+
+ ap_id == "https://www.w3.org/ns/activitystreams#Public" ->
+ nil
+
+ true ->
+ User.get_cached_by_ap_id(ap_id)
+ end
+ end
+
+ def render("index.json", opts) do
+ context_ids = collect_context_ids(opts.activities)
+ users = collect_users(opts.activities)
+
+ opts =
+ opts
+ |> Map.put(:context_ids, context_ids)
+ |> Map.put(:users, users)
+
+ render_many(
+ opts.activities,
+ ActivityView,
+ "activity.json",
+ opts
+ )
+ end
+
+ def render("activity.json", %{activity: %{data: %{"type" => "Delete"}} = activity} = opts) do
+ user = get_user(activity.data["actor"], opts)
+ created_at = activity.data["published"] |> Utils.date_to_asctime()
+
+ %{
+ "id" => activity.id,
+ "uri" => activity.data["object"],
+ "user" => UserView.render("show.json", %{user: user, for: opts[:for]}),
+ "attentions" => [],
+ "statusnet_html" => "deleted notice {{tag",
+ "text" => "deleted notice {{tag",
+ "is_local" => activity.local,
+ "is_post_verb" => false,
+ "created_at" => created_at,
+ "in_reply_to_status_id" => nil,
+ "external_url" => activity.data["id"],
+ "activity_type" => "delete"
+ }
+ end
+
+ def render("activity.json", %{activity: %{data: %{"type" => "Follow"}} = activity} = opts) do
+ user = get_user(activity.data["actor"], opts)
+ created_at = activity.data["published"] || DateTime.to_iso8601(activity.inserted_at)
+ created_at = created_at |> Utils.date_to_asctime()
+
+ followed = get_user(activity.data["object"], opts)
+ text = "#{user.nickname} started following #{followed.nickname}"
+
+ %{
+ "id" => activity.id,
+ "user" => UserView.render("show.json", %{user: user, for: opts[:for]}),
+ "attentions" => [],
+ "statusnet_html" => text,
+ "text" => text,
+ "is_local" => activity.local,
+ "is_post_verb" => false,
+ "created_at" => created_at,
+ "in_reply_to_status_id" => nil,
+ "external_url" => activity.data["id"],
+ "activity_type" => "follow"
+ }
+ end
+
+ def render("activity.json", %{activity: %{data: %{"type" => "Announce"}} = activity} = opts) do
+ user = get_user(activity.data["actor"], opts)
+ created_at = activity.data["published"] |> Utils.date_to_asctime()
+ announced_activity = Activity.get_create_activity_by_object_ap_id(activity.data["object"])
+
+ text = "#{user.nickname} retweeted a status."
+
+ retweeted_status = render("activity.json", Map.merge(opts, %{activity: announced_activity}))
+
+ %{
+ "id" => activity.id,
+ "user" => UserView.render("show.json", %{user: user, for: opts[:for]}),
+ "statusnet_html" => text,
+ "text" => text,
+ "is_local" => activity.local,
+ "is_post_verb" => false,
+ "uri" => "tag:#{activity.data["id"]}:objectType=note",
+ "created_at" => created_at,
+ "retweeted_status" => retweeted_status,
+ "statusnet_conversation_id" => get_context_id(announced_activity, opts),
+ "external_url" => activity.data["id"],
+ "activity_type" => "repeat"
+ }
+ end
+
+ def render("activity.json", %{activity: %{data: %{"type" => "Like"}} = activity} = opts) do
+ user = get_user(activity.data["actor"], opts)
+ liked_activity = Activity.get_create_activity_by_object_ap_id(activity.data["object"])
+
+ created_at =
+ activity.data["published"]
+ |> Utils.date_to_asctime()
+
+ text = "#{user.nickname} favorited a status."
+
+ %{
+ "id" => activity.id,
+ "user" => UserView.render("show.json", %{user: user, for: opts[:for]}),
+ "statusnet_html" => text,
+ "text" => text,
+ "is_local" => activity.local,
+ "is_post_verb" => false,
+ "uri" => "tag:#{activity.data["id"]}:objectType=Favourite",
+ "created_at" => created_at,
+ "in_reply_to_status_id" => liked_activity.id,
+ "external_url" => activity.data["id"],
+ "activity_type" => "like"
+ }
+ end
+
+ def render(
+ "activity.json",
+ %{activity: %{data: %{"type" => "Create", "object" => object}} = activity} = opts
+ ) do
+ user = get_user(activity.data["actor"], opts)
+
+ created_at = object["published"] |> Utils.date_to_asctime()
+ like_count = object["like_count"] || 0
+ announcement_count = object["announcement_count"] || 0
+ favorited = opts[:for] && opts[:for].ap_id in (object["likes"] || [])
+ repeated = opts[:for] && opts[:for].ap_id in (object["announcements"] || [])
+
+ attentions =
+ activity.recipients
+ |> Enum.map(fn ap_id -> get_user(ap_id, opts) end)
+ |> Enum.filter(& &1)
+ |> Enum.map(fn user -> UserView.render("show.json", %{user: user, for: opts[:for]}) end)
+
+ conversation_id = get_context_id(activity, opts)
+
+ tags = activity.data["object"]["tag"] || []
+ possibly_sensitive = activity.data["object"]["sensitive"] || Enum.member?(tags, "nsfw")
+
+ tags = if possibly_sensitive, do: Enum.uniq(["nsfw" | tags]), else: tags
+
+ summary = activity.data["object"]["summary"]
+ content = object["content"]
+
+ content =
+ if !!summary and summary != "" do
+ "<span>#{activity.data["object"]["summary"]}</span><br />#{content}</span>"
+ else
+ content
+ end
+
+ html =
+ HtmlSanitizeEx.basic_html(content)
+ |> Formatter.emojify(object["emoji"])
+
+ %{
+ "id" => activity.id,
+ "uri" => activity.data["object"]["id"],
+ "user" => UserView.render("show.json", %{user: user, for: opts[:for]}),
+ "statusnet_html" => html,
+ "text" => HtmlSanitizeEx.strip_tags(content),
+ "is_local" => activity.local,
+ "is_post_verb" => true,
+ "created_at" => created_at,
+ "in_reply_to_status_id" => object["inReplyToStatusId"],
+ "statusnet_conversation_id" => conversation_id,
+ "attachments" => (object["attachment"] || []) |> ObjectRepresenter.enum_to_list(opts),
+ "attentions" => attentions,
+ "fave_num" => like_count,
+ "repeat_num" => announcement_count,
+ "favorited" => !!favorited,
+ "repeated" => !!repeated,
+ "external_url" => object["external_url"] || object["id"],
+ "tags" => tags,
+ "activity_type" => "post",
+ "possibly_sensitive" => possibly_sensitive
+ }
+ end
+end
diff --git a/lib/pleroma/web/twitter_api/views/notification_view.ex b/lib/pleroma/web/twitter_api/views/notification_view.ex
new file mode 100644
index 000000000..9eeb3afdc
--- /dev/null
+++ b/lib/pleroma/web/twitter_api/views/notification_view.ex
@@ -0,0 +1,64 @@
+defmodule Pleroma.Web.TwitterAPI.NotificationView do
+ use Pleroma.Web, :view
+ alias Pleroma.{Notification, User}
+ alias Pleroma.Web.CommonAPI.Utils
+ alias Pleroma.Web.TwitterAPI.UserView
+ alias Pleroma.Web.TwitterAPI.ActivityView
+
+ defp get_user(ap_id, opts) do
+ cond do
+ user = opts[:users][ap_id] ->
+ user
+
+ String.ends_with?(ap_id, "/followers") ->
+ nil
+
+ ap_id == "https://www.w3.org/ns/activitystreams#Public" ->
+ nil
+
+ true ->
+ User.get_cached_by_ap_id(ap_id)
+ end
+ end
+
+ def render("notification.json", %{notifications: notifications, for: user}) do
+ render_many(
+ notifications,
+ Pleroma.Web.TwitterAPI.NotificationView,
+ "notification.json",
+ for: user
+ )
+ end
+
+ def render(
+ "notification.json",
+ %{
+ notification: %Notification{
+ id: id,
+ seen: seen,
+ activity: activity,
+ inserted_at: created_at
+ },
+ for: user
+ } = opts
+ ) do
+ ntype =
+ case activity.data["type"] do
+ "Create" -> "mention"
+ "Like" -> "like"
+ "Announce" -> "repeat"
+ "Follow" -> "follow"
+ end
+
+ from = get_user(activity.data["actor"], opts)
+
+ %{
+ "id" => id,
+ "ntype" => ntype,
+ "notice" => ActivityView.render("activity.json", %{activity: activity, for: user}),
+ "from_profile" => UserView.render("show.json", %{user: from, for: user}),
+ "is_seen" => if(seen, do: 1, else: 0),
+ "created_at" => created_at |> Utils.format_naive_asctime()
+ }
+ end
+end
diff --git a/lib/pleroma/web/twitter_api/views/user_view.ex b/lib/pleroma/web/twitter_api/views/user_view.ex
index 6fb07f052..31527caae 100644
--- a/lib/pleroma/web/twitter_api/views/user_view.ex
+++ b/lib/pleroma/web/twitter_api/views/user_view.ex
@@ -14,20 +14,22 @@ defmodule Pleroma.Web.TwitterAPI.UserView do
def render("user.json", %{user: user = %User{}} = assigns) do
image = User.avatar_url(user) |> MediaProxy.url()
- {following, follows_you, statusnet_blocking} = if assigns[:for] do
- {
- User.following?(assigns[:for], user),
- User.following?(user, assigns[:for]),
- User.blocks?(assigns[:for], user)
- }
- else
- {false, false, false}
- end
+
+ {following, follows_you, statusnet_blocking} =
+ if assigns[:for] do
+ {
+ User.following?(assigns[:for], user),
+ User.following?(user, assigns[:for]),
+ User.blocks?(assigns[:for], user)
+ }
+ else
+ {false, false, false}
+ end
user_info = User.get_cached_user_info(user)
data = %{
- "created_at" => user.inserted_at |> Utils.format_naive_asctime,
+ "created_at" => user.inserted_at |> Utils.format_naive_asctime(),
"description" => HtmlSanitizeEx.strip_tags(user.bio),
"favourites_count" => 0,
"followers_count" => user_info[:follower_count],
@@ -59,9 +61,14 @@ defmodule Pleroma.Web.TwitterAPI.UserView do
end
end
- def render("short.json", %{user: %User{
- nickname: nickname, id: id, ap_id: ap_id, name: name
- }}) do
+ def render("short.json", %{
+ user: %User{
+ nickname: nickname,
+ id: id,
+ ap_id: ap_id,
+ name: name
+ }
+ }) do
%{
"fullname" => name,
"id" => id,
@@ -71,6 +78,6 @@ defmodule Pleroma.Web.TwitterAPI.UserView do
}
end
- defp image_url(%{"url" => [ %{ "href" => href } | _ ]}), do: href
+ defp image_url(%{"url" => [%{"href" => href} | _]}), do: href
defp image_url(_), do: nil
end