Commit 34d3a90b authored by dtluna's avatar dtluna
Browse files

Replace ActivityRepresenter with StatusView and ObjectRepresenter with AttachmentView

parent 3d714f85
defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenter do
use Pleroma.Web.TwitterAPI.Representers.BaseRepresenter
alias Pleroma.Web.TwitterAPI.Representers.ObjectRepresenter
alias Pleroma.{Activity, User}
alias Pleroma.Web.TwitterAPI.{TwitterAPI, UserView, Utils}
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)
end
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
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]}),
"statusnet_html" => text,
"text" => text,
"is_local" => true,
"is_post_verb" => false,
"uri" => "tag:#{activity.data["id"]}:objectType=note",
"created_at" => created_at,
"retweeted_status" => retweeted_status,
"statusnet_conversation_id" => conversation_id(announced_activity),
"external_url" => activity.data["id"]
}
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
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" => true,
"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"]
}
end
def to_map(%Activity{data: %{"type" => "Follow", "published" => created_at, "object" => followed_id}} = activity, %{user: user} = opts) do
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]}),
"attentions" => [],
"statusnet_html" => text,
"text" => text,
"is_local" => true,
"is_post_verb" => false,
"created_at" => created_at,
"in_reply_to_status_id" => nil,
"external_url" => activity.data["id"]
}
end
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"] || [])
repeated = opts[:for] && opts[:for].ap_id in (object["announcements"] || [])
mentions = opts[:mentioned] || []
attentions = activity.data["to"]
|> 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)
%{
"id" => activity.id,
"user" => UserView.render("show.json", %{user: user, for: opts[:for]}),
"statusnet_html" => HtmlSanitizeEx.basic_html(content) |> Formatter.finmojifiy,
"text" => HtmlSanitizeEx.strip_tags(content),
"is_local" => true,
"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" => to_boolean(favorited),
"repeated" => to_boolean(repeated),
"external_url" => activity.data["id"],
"tags" => activity.data["object"]["tag"] || []
}
end
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
end
end
defp to_boolean(false) do
false
end
defp to_boolean(nil) do
false
end
defp to_boolean(_) do
true
end
end
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, options) do
object
|> to_map(options)
|> Poison.encode!
end
def enum_to_list(enum, options) do
mapping = fn (el) -> to_map(el, options) end
Enum.map(enum, mapping)
end
def to_map(object) do
to_map(object, %{})
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!
end
end
end
end
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.TwitterAPI.{UserView, Utils}
alias Pleroma.Web.OStatus
alias Pleroma.Formatter
......@@ -43,49 +42,6 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
end
end
def fetch_friend_statuses(user, opts \\ %{}) do
ActivityPub.fetch_activities([user.ap_id | user.following], opts)
|> activities_to_statuses(%{for: user})
end
def fetch_public_statuses(user, opts \\ %{}) do
opts = Map.put(opts, "local_only", true)
ActivityPub.fetch_public_activities(opts)
|> activities_to_statuses(%{for: user})
end
def fetch_public_and_external_statuses(user, opts \\ %{}) do
ActivityPub.fetch_public_activities(opts)
|> activities_to_statuses(%{for: user})
end
def fetch_user_statuses(user, opts \\ %{}) do
ActivityPub.fetch_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),
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) 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),
......@@ -104,7 +60,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
"type" => "Undo",
"actor" => follower.ap_id,
"object" => follow_activity.data["id"], # get latest Follow for these users
"published" => make_date()
"published" => Utils.make_date()
})
do
{ :ok, follower, unfollowed }
......@@ -121,8 +77,6 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
|> Map.put("object", object.data)
status = %{activity | data: new_data}
|> activity_to_status(%{for: user})
{:ok, status}
end
......@@ -134,8 +88,6 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
|> Map.put("object", object.data)
status = %{activity | data: new_data}
|> activity_to_status(%{for: user})
{:ok, status}
end
......@@ -147,8 +99,6 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
|> Map.put("object", object.data)
status = %{activity | data: new_data}
|> activity_to_status(%{for: user})
{:ok, status}
end
......@@ -238,47 +188,6 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
end
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, 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.data["to"] || [], fn (ap_id) ->
User.get_cached_by_ap_id(ap_id)
end)
|> Enum.filter(&(&1))
ActivityRepresenter.to_map(activity, Map.merge(opts, %{user: user, mentioned: mentioned_users}))
end
defp make_date do
DateTime.utc_now() |> DateTime.to_iso8601
end
def context_to_conversation_id(context) do
with %Object{id: id} <- Object.get_cached_by_ap_id(context) do
id
......
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.{StatusView, TwitterAPI, UserView}
alias Pleroma.{Web, Repo, Activity}
alias Pleroma.Web.ActivityPub.ActivityPub
alias Ecto.Changeset
......@@ -15,8 +14,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
if l > 0 && l < 5000 do
media_ids = extract_media_ids(status_data)
{:ok, activity} = TwitterAPI.create_status(user, Map.put(status_data, "media_ids", media_ids))
conn
|> json_reply(200, ActivityRepresenter.to_json(activity, %{user: user}))
render(conn, StatusView, "show.json", %{activity: activity})
else
empty_status_reply(conn)
end
......@@ -40,48 +38,36 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
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)
conn
|> json_reply(200, json)
def public_and_external_timeline(conn, params) do
activities = ActivityPub.fetch_public_activities(params)
render(conn, StatusView, "timeline.json", %{activities: activities})
end
def public_timeline(%{assigns: %{user: user}} = conn, params) do
statuses = TwitterAPI.fetch_public_statuses(user, params)
{:ok, json} = Poison.encode(statuses)
conn
|> json_reply(200, json)
def public_timeline(conn, params) do
params = Map.put(params, "local_only", true)
activities = ActivityPub.fetch_public_activities(params)
render(conn, StatusView, "timeline.json", %{activities: activities})
end
def friends_timeline(%{assigns: %{user: user}} = conn, params) do
statuses = TwitterAPI.fetch_friend_statuses(user, params)
{:ok, json} = Poison.encode(statuses)
conn
|> json_reply(200, json)
activities = ActivityPub.fetch_activities([user.ap_id | user.following], params)
render(conn, StatusView, "timeline.json", %{activities: activities})
end
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})
statuses = TwitterAPI.fetch_user_statuses(user, params)
conn
|> json_reply(200, statuses |> Poison.encode!)
activities = ActivityPub.fetch_activities([], params)
render(conn, StatusView, "timeline.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)
conn
|> json_reply(200, json)
activities = ActivityPub.fetch_activities([user.ap_id], params)
render(conn, StatusView, "timeline.json", %{activities: activities, for: user})
end
def follow(%{assigns: %{user: user}} = conn, params) do
......@@ -101,18 +87,20 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
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) do
render(conn, StatusView, "show.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)
do
render(conn, StatusView, "timeline.json", %{activities: activities, for: user})
else _e ->
json(conn, [])
end
end
def upload(conn, %{"media" => media}) do
......@@ -123,7 +111,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
end
def help_test(conn, _params) do
conn |> json_reply(200, Poison.encode!("ok"))
json(conn, "ok")
end
def upload_json(conn, %{"media" => media}) do
......@@ -133,35 +121,25 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
end
def config(conn, _params) do
response = %{
json(conn, %{
site: %{
name: Web.base_url,
server: Web.base_url,
textlimit: -1
}
}
|> Poison.encode!
conn
|> json_reply(200, response)
})
end
def favorite(%{assigns: %{user: user}} = conn, %{"id" => id}) do
activity = Repo.get(Activity, id)
{:ok, status} = TwitterAPI.favorite(user, activity)
response = Poison.encode!(status)
conn
|> json_reply(200, response)
{:ok, activity} = TwitterAPI.favorite(user, activity)
render(conn, StatusView, "show.json", %{activity: activity, for: user})
end
def unfavorite(%{assigns: %{user: user}} = conn, %{"id" => id}) do
activity = Repo.get(Activity, id)
{:ok, status} = TwitterAPI.unfavorite(user, activity)
response = Poison.encode!(status)
conn
|> json_reply(200, response)
{:ok, activity} = TwitterAPI.unfavorite(user, activity)
render(conn, StatusView, "show.json", %{activity: activity, for: user})
end
def retweet(%{assigns: %{user: user}} = conn, %{"id" => id}) do
......@@ -169,18 +147,13 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
if activity.data["actor"] == user.ap_id do
bad_request_reply(conn, "You cannot repeat your own notice.")
else
{:ok, status} = TwitterAPI.retweet(user, activity)
response = Poison.encode!(status)
conn
|> json_reply(200, response)
{:ok, activity} = TwitterAPI.retweet(user, activity)
render(conn, StatusView, "show.json", %{activity: activity, for: user})
end
end
def register(conn, params) do
with {:ok, user} <- TwitterAPI.register_user(params) do
render(conn, UserView, "show.json", %{user: user})
else
{:error, errors} ->
......
......@@ -89,4 +89,14 @@ defmodule Pleroma.Web.TwitterAPI.Utils do
""
end
end
def make_date do
DateTime.utc_now() |> DateTime.to_iso8601
end
def to_boolean(false), do: false
def to_boolean(nil), do: false
def to_boolean(_), do: true
end
defmodule Pleroma.Web.TwitterAPI.Representers.ObjectRepresenter do
use Pleroma.Web.TwitterAPI.Representers.BaseRepresenter
defmodule Pleroma.Web.TwitterAPI.AttachmentView do
use Pleroma.Web, :view
alias Pleroma.Object
def to_map(%Object{} = object, _opts) do
data = object.data
def render("show.json", %{attachment: %Object{data: data}}) do
url = List.first(data["url"])
%{
url: url["href"],
......@@ -12,9 +11,4 @@ defmodule Pleroma.Web.TwitterAPI.Representers.ObjectRepresenter do
oembed: false
}
end
# If we only get the naked data, wrap in an object
def to_map(%{} = data, opts) do
to_map(%Object{data: data}, opts)
end
end
defmodule Pleroma.Web.TwitterAPI.StatusView do
use Pleroma.Web, :view
alias Pleroma.{Activity, User, Utils}
alias Pleroma.Web.TwitterAPI.{AttachmentView, TwitterAPI, UserView, Utils}
def render(
"show.json",
%{
activity: %Activity{
data: %{"type" => "Announce", "id" => id, "object" => ap_id}
},
} = assigns) do
{activity, user} = render_activity(assigns)
[announced_activity = %Activity{}] = Activity.all_by_object_ap_id(ap_id)
text = "#{user.nickname} retweeted a status."
retweeted_status = render("show.json",
Map.merge(assigns, %{activity: announced_activity})
)
Map.merge(activity, %{
"retweeted_status" => retweeted_status,
"statusnet_html" => text,
"text" => text,
"uri" => "tag:#{id}:objectType=note"
})
end
def render(
"show.json",
%{activity: %Activity{
data: %{"type" => "Like", "id" => id, "object" => liked_id}
},
} = assigns) do
{activity, %User{nickname: nickname}} = render_activity(assigns)
text = "#{nickname} favorited a status."
[%Activity{id: liked_activity_id}] = Activity.all_by_object_ap_id(liked_id)
Map.merge(activity, %{
"in_reply_to_status_id" => liked_activity_id,
"statusnet_html" => text,
"text" => text,
"uri" => "tag#{id}:objectType=Favorite"
})
end
def render(
"show.json",
%{
activity: %Activity{
data: %{"type" => "Follow", "object" => followed_id}
}
} = assigns
) do
{activity, %User{nickname: follower_name}} = render_activity(assigns)
%User{nickname: followed_name} = User.get_cached_by_ap_id(followed_id)
text = "#{follower_name} started following #{followed_name}"
Map.merge(activity, %{
"statusnet_html" => text,
"text" => text