defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
use Pleroma.Web, :controller
-
alias Ecto.Changeset
alias Pleroma.Activity
alias Pleroma.Config
alias Pleroma.Filter
alias Pleroma.Notification
alias Pleroma.Object
+ alias Pleroma.Object.Fetcher
+ alias Pleroma.Pagination
alias Pleroma.Repo
alias Pleroma.ScheduledActivity
alias Pleroma.Stats
defp add_link_headers(conn, method, activities, param \\ nil, params \\ %{}) do
params =
conn.params
- |> Map.drop(["since_id", "max_id"])
+ |> Map.drop(["since_id", "max_id", "min_id"])
|> Map.merge(params)
last = List.last(activities)
- first = List.first(activities)
if last do
- min = last.id
- max = first.id
+ max_id = last.id
+
+ limit =
+ params
+ |> Map.get("limit", "20")
+ |> String.to_integer()
+
+ min_id =
+ if length(activities) <= limit do
+ activities
+ |> List.first()
+ |> Map.get(:id)
+ else
+ activities
+ |> Enum.at(limit * -1)
+ |> Map.get(:id)
+ end
{next_url, prev_url} =
if param do
Pleroma.Web.Endpoint,
method,
param,
- Map.merge(params, %{max_id: min})
+ Map.merge(params, %{max_id: max_id})
),
mastodon_api_url(
Pleroma.Web.Endpoint,
method,
param,
- Map.merge(params, %{since_id: max})
+ Map.merge(params, %{min_id: min_id})
)
}
else
mastodon_api_url(
Pleroma.Web.Endpoint,
method,
- Map.merge(params, %{max_id: min})
+ Map.merge(params, %{max_id: max_id})
),
mastodon_api_url(
Pleroma.Web.Endpoint,
method,
- Map.merge(params, %{since_id: max})
+ Map.merge(params, %{min_id: min_id})
)
}
end
activities =
[user.ap_id]
|> ActivityPub.fetch_activities_query(params)
- |> Repo.all()
+ |> Pagination.fetch_paginated(params)
conn
|> add_link_headers(:dm_timeline, activities)
end
def bookmark_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do
- with %Activity{} = activity <- Activity.get_by_id(id),
+ with %Activity{} = activity <- Activity.get_by_id_with_object(id),
+ %Object{} = object <- Object.normalize(activity),
%User{} = user <- User.get_by_nickname(user.nickname),
true <- Visibility.visible_for_user?(activity, user),
- {:ok, user} <- User.bookmark(user, activity.data["object"]["id"]) do
+ {:ok, user} <- User.bookmark(user, object.data["id"]) do
conn
|> put_view(StatusView)
|> try_render("status.json", %{activity: activity, for: user, as: :activity})
end
def unbookmark_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do
- with %Activity{} = activity <- Activity.get_by_id(id),
+ with %Activity{} = activity <- Activity.get_by_id_with_object(id),
+ %Object{} = object <- Object.normalize(activity),
%User{} = user <- User.get_by_nickname(user.nickname),
true <- Visibility.visible_for_user?(activity, user),
- {:ok, user} <- User.unbookmark(user, activity.data["object"]["id"]) do
+ {:ok, user} <- User.unbookmark(user, object.data["id"]) do
conn
|> put_view(StatusView)
|> try_render("status.json", %{activity: activity, for: user, as: :activity})
end
def favourited_by(conn, %{"id" => id}) do
- with %Activity{data: %{"object" => %{"likes" => likes}}} <- Activity.get_by_id(id) do
+ with %Activity{data: %{"object" => object}} <- Repo.get(Activity, id),
+ %Object{data: %{"likes" => likes}} <- Object.normalize(object) do
q = from(u in User, where: u.ap_id in ^likes)
users = Repo.all(q)
end
def reblogged_by(conn, %{"id" => id}) do
- with %Activity{data: %{"object" => %{"announcements" => announces}}} <- Activity.get_by_id(id) do
+ with %Activity{data: %{"object" => object}} <- Repo.get(Activity, id),
+ %Object{data: %{"announcements" => announces}} <- Object.normalize(object) do
q = from(u in User, where: u.ap_id in ^announces)
users = Repo.all(q)
end
def follow(%{assigns: %{user: follower}} = conn, %{"id" => id}) do
- with %User{} = followed <- User.get_by_id(id),
+ with {_, %User{} = followed} <- {:followed, User.get_cached_by_id(id)},
+ {_, true} <- {:followed, follower.id != followed.id},
false <- User.following?(follower, followed),
{:ok, follower, followed, _} <- CommonAPI.follow(follower, followed) do
conn
|> put_view(AccountView)
|> render("relationship.json", %{user: follower, target: followed})
else
+ {:followed, _} ->
+ {:error, :not_found}
+
true ->
followed = User.get_cached_by_id(id)
end
def follow(%{assigns: %{user: follower}} = conn, %{"uri" => uri}) do
- with %User{} = followed <- User.get_by_nickname(uri),
+ with {_, %User{} = followed} <- {:followed, User.get_cached_by_nickname(uri)},
+ {_, true} <- {:followed, follower.id != followed.id},
{:ok, follower, followed, _} <- CommonAPI.follow(follower, followed) do
conn
|> put_view(AccountView)
|> render("account.json", %{user: followed, for: follower})
else
+ {:followed, _} ->
+ {:error, :not_found}
+
{:error, message} ->
conn
|> put_resp_content_type("application/json")
end
def unfollow(%{assigns: %{user: follower}} = conn, %{"id" => id}) do
- with %User{} = followed <- User.get_by_id(id),
+ with {_, %User{} = followed} <- {:followed, User.get_cached_by_id(id)},
+ {_, true} <- {:followed, follower.id != followed.id},
{:ok, follower} <- CommonAPI.unfollow(follower, followed) do
conn
|> put_view(AccountView)
|> render("relationship.json", %{user: follower, target: followed})
+ else
+ {:followed, _} ->
+ {:error, :not_found}
+
+ error ->
+ error
end
end
def status_search(user, query) do
fetched =
if Regex.match?(~r/https?:/, query) do
- with {:ok, object} <- ActivityPub.fetch_object_from_id(query),
+ with {:ok, object} <- Fetcher.fetch_object_from_id(query),
%Activity{} = activity <- Activity.get_create_by_object_ap_id(object.data["id"]),
true <- Visibility.visible_for_user?(activity, user) do
[activity]