diff --git a/lib/pleroma/bbs/handler.ex b/lib/pleroma/bbs/handler.ex
index 0a381f592..fa838a4e4 100644
--- a/lib/pleroma/bbs/handler.ex
+++ b/lib/pleroma/bbs/handler.ex
@@ -42,7 +42,7 @@ defp loop(state) do
end
def puts_activity(activity) do
- status = Pleroma.Web.MastodonAPI.StatusView.render("status.json", %{activity: activity})
+ status = Pleroma.Web.MastodonAPI.StatusView.render("show.json", %{activity: activity})
IO.puts("-- #{status.id} by #{status.account.display_name} (#{status.account.acct})")
IO.puts(HtmlSanitizeEx.strip_tags(status.content))
IO.puts("")
diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex
index 90aef99f7..21da8a7ff 100644
--- a/lib/pleroma/web/admin_api/admin_api_controller.ex
+++ b/lib/pleroma/web/admin_api/admin_api_controller.ex
@@ -513,7 +513,7 @@ def report_respond(%{assigns: %{user: user}} = conn, %{"id" => id} = params) do
conn
|> put_view(StatusView)
- |> render("status.json", %{activity: activity})
+ |> render("show.json", %{activity: activity})
else
true ->
{:param_cast, nil}
@@ -537,7 +537,7 @@ def status_update(%{assigns: %{user: admin}} = conn, %{"id" => id} = params) do
conn
|> put_view(StatusView)
- |> render("status.json", %{activity: activity})
+ |> render("show.json", %{activity: activity})
end
end
diff --git a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex
index e4ae63231..82bba43e5 100644
--- a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex
@@ -51,28 +51,12 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
@rate_limited_relations_actions ~w(follow unfollow)a
- @rate_limited_status_actions ~w(reblog_status unreblog_status fav_status unfav_status
- post_status delete_status)a
-
- plug(
- RateLimiter,
- {:status_id_action, bucket_name: "status_id_action:reblog_unreblog", params: ["id"]}
- when action in ~w(reblog_status unreblog_status)a
- )
-
- plug(
- RateLimiter,
- {:status_id_action, bucket_name: "status_id_action:fav_unfav", params: ["id"]}
- when action in ~w(fav_status unfav_status)a
- )
-
plug(
RateLimiter,
{:relations_id_action, params: ["id", "uri"]} when action in @rate_limited_relations_actions
)
plug(RateLimiter, :relations_actions when action in @rate_limited_relations_actions)
- plug(RateLimiter, :statuses_actions when action in @rate_limited_status_actions)
plug(RateLimiter, :app_account_creation when action == :account_register)
plug(RateLimiter, :search when action in [:search, :search2, :account_search])
plug(RateLimiter, :password_reset when action == :password_reset)
@@ -362,63 +346,6 @@ def user_statuses(%{assigns: %{user: reading_user}} = conn, params) do
end
end
- def get_statuses(%{assigns: %{user: user}} = conn, %{"ids" => ids}) do
- limit = 100
-
- activities =
- ids
- |> Enum.take(limit)
- |> Activity.all_by_ids_with_object()
- |> Enum.filter(&Visibility.visible_for_user?(&1, user))
-
- conn
- |> put_view(StatusView)
- |> render("index.json", activities: activities, for: user, as: :activity)
- end
-
- def get_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do
- with %Activity{} = activity <- Activity.get_by_id_with_object(id),
- true <- Visibility.visible_for_user?(activity, user) do
- conn
- |> put_view(StatusView)
- |> try_render("status.json", %{activity: activity, for: user})
- end
- end
-
- def get_context(%{assigns: %{user: user}} = conn, %{"id" => id}) do
- with %Activity{} = activity <- Activity.get_by_id(id),
- activities <-
- ActivityPub.fetch_activities_for_context(activity.data["context"], %{
- "blocking_user" => user,
- "user" => user,
- "exclude_id" => activity.id
- }),
- grouped_activities <- Enum.group_by(activities, fn %{id: id} -> id < activity.id end) do
- result = %{
- ancestors:
- StatusView.render(
- "index.json",
- for: user,
- activities: grouped_activities[true] || [],
- as: :activity
- )
- |> Enum.reverse(),
- # credo:disable-for-previous-line Credo.Check.Refactor.PipeChainStart
- descendants:
- StatusView.render(
- "index.json",
- for: user,
- activities: grouped_activities[false] || [],
- as: :activity
- )
- |> Enum.reverse()
- # credo:disable-for-previous-line Credo.Check.Refactor.PipeChainStart
- }
-
- json(conn, result)
- end
- end
-
def get_poll(%{assigns: %{user: user}} = conn, %{"id" => id}) do
with %Object{} = object <- Object.get_by_id_and_maybe_refetch(id, interval: 60),
%Activity{} = activity <- Activity.get_create_by_object_ap_id(object.data["id"]),
@@ -518,143 +445,6 @@ def delete_scheduled_status(%{assigns: %{user: user}} = conn, %{"id" => schedule
end
end
- def post_status(
- %{assigns: %{user: user}} = conn,
- %{"status" => _, "scheduled_at" => scheduled_at} = params
- ) do
- if ScheduledActivity.far_enough?(scheduled_at) do
- with {:ok, scheduled_activity} <-
- ScheduledActivity.create(user, %{"params" => params, "scheduled_at" => scheduled_at}) do
- conn
- |> put_view(ScheduledActivityView)
- |> render("show.json", %{scheduled_activity: scheduled_activity})
- end
- else
- post_status(conn, Map.drop(params, ["scheduled_at"]))
- end
- end
-
- def post_status(%{assigns: %{user: user}} = conn, %{"status" => _} = params) do
- case CommonAPI.post(user, params) do
- {:ok, activity} ->
- conn
- |> put_view(StatusView)
- |> try_render("status.json", %{
- activity: activity,
- for: user,
- as: :activity,
- with_direct_conversation_id: true
- })
-
- {:error, message} ->
- conn
- |> put_status(:unprocessable_entity)
- |> json(%{error: message})
- end
- end
-
- def delete_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do
- with {:ok, %Activity{}} <- CommonAPI.delete(id, user) do
- json(conn, %{})
- else
- _e -> render_error(conn, :forbidden, "Can't delete this post")
- end
- end
-
- def reblog_status(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do
- with {:ok, announce, _activity} <- CommonAPI.repeat(ap_id_or_id, user),
- %Activity{} = announce <- Activity.normalize(announce.data) do
- conn
- |> put_view(StatusView)
- |> try_render("status.json", %{activity: announce, for: user, as: :activity})
- end
- end
-
- def unreblog_status(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do
- with {:ok, _unannounce, %{data: %{"id" => id}}} <- CommonAPI.unrepeat(ap_id_or_id, user),
- %Activity{} = activity <- Activity.get_create_by_object_ap_id_with_object(id) do
- conn
- |> put_view(StatusView)
- |> try_render("status.json", %{activity: activity, for: user, as: :activity})
- end
- end
-
- def fav_status(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do
- with {:ok, _fav, %{data: %{"id" => id}}} <- CommonAPI.favorite(ap_id_or_id, user),
- %Activity{} = activity <- Activity.get_create_by_object_ap_id(id) do
- conn
- |> put_view(StatusView)
- |> try_render("status.json", %{activity: activity, for: user, as: :activity})
- end
- end
-
- def unfav_status(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do
- with {:ok, _, _, %{data: %{"id" => id}}} <- CommonAPI.unfavorite(ap_id_or_id, user),
- %Activity{} = activity <- Activity.get_create_by_object_ap_id(id) do
- conn
- |> put_view(StatusView)
- |> try_render("status.json", %{activity: activity, for: user, as: :activity})
- end
- end
-
- def pin_status(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do
- with {:ok, activity} <- CommonAPI.pin(ap_id_or_id, user) do
- conn
- |> put_view(StatusView)
- |> try_render("status.json", %{activity: activity, for: user, as: :activity})
- end
- end
-
- def unpin_status(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do
- with {:ok, activity} <- CommonAPI.unpin(ap_id_or_id, user) do
- conn
- |> put_view(StatusView)
- |> try_render("status.json", %{activity: activity, for: user, as: :activity})
- end
- end
-
- def bookmark_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do
- with %Activity{} = activity <- Activity.get_by_id_with_object(id),
- %User{} = user <- User.get_cached_by_nickname(user.nickname),
- true <- Visibility.visible_for_user?(activity, user),
- {:ok, _bookmark} <- Bookmark.create(user.id, activity.id) do
- conn
- |> put_view(StatusView)
- |> try_render("status.json", %{activity: activity, for: user, as: :activity})
- end
- end
-
- def unbookmark_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do
- with %Activity{} = activity <- Activity.get_by_id_with_object(id),
- %User{} = user <- User.get_cached_by_nickname(user.nickname),
- true <- Visibility.visible_for_user?(activity, user),
- {:ok, _bookmark} <- Bookmark.destroy(user.id, activity.id) do
- conn
- |> put_view(StatusView)
- |> try_render("status.json", %{activity: activity, for: user, as: :activity})
- end
- end
-
- def mute_conversation(%{assigns: %{user: user}} = conn, %{"id" => id}) do
- activity = Activity.get_by_id(id)
-
- with {:ok, activity} <- CommonAPI.add_mute(user, activity) do
- conn
- |> put_view(StatusView)
- |> try_render("status.json", %{activity: activity, for: user, as: :activity})
- end
- end
-
- def unmute_conversation(%{assigns: %{user: user}} = conn, %{"id" => id}) do
- activity = Activity.get_by_id(id)
-
- with {:ok, activity} <- CommonAPI.remove_mute(user, activity) do
- conn
- |> put_view(StatusView)
- |> try_render("status.json", %{activity: activity, for: user, as: :activity})
- end
- end
-
def relationships(%{assigns: %{user: user}} = conn, %{"id" => id}) do
id = List.wrap(id)
q = from(u in User, where: u.id in ^id)
@@ -726,44 +516,6 @@ def get_mascot(%{assigns: %{user: user}} = conn, _params) do
|> json(mascot)
end
- def favourited_by(%{assigns: %{user: user}} = conn, %{"id" => id}) do
- with %Activity{} = activity <- Activity.get_by_id_with_object(id),
- {:visible, true} <- {:visible, Visibility.visible_for_user?(activity, user)},
- %Object{data: %{"likes" => likes}} <- Object.normalize(activity) do
- q = from(u in User, where: u.ap_id in ^likes)
-
- users =
- Repo.all(q)
- |> Enum.filter(&(not User.blocks?(user, &1)))
-
- conn
- |> put_view(AccountView)
- |> render("accounts.json", %{for: user, users: users, as: :user})
- else
- {:visible, false} -> {:error, :not_found}
- _ -> json(conn, [])
- end
- end
-
- def reblogged_by(%{assigns: %{user: user}} = conn, %{"id" => id}) do
- with %Activity{} = activity <- Activity.get_by_id_with_object(id),
- {:visible, true} <- {:visible, Visibility.visible_for_user?(activity, user)},
- %Object{data: %{"announcements" => announces}} <- Object.normalize(activity) do
- q = from(u in User, where: u.ap_id in ^announces)
-
- users =
- Repo.all(q)
- |> Enum.filter(&(not User.blocks?(user, &1)))
-
- conn
- |> put_view(AccountView)
- |> render("accounts.json", %{for: user, users: users, as: :user})
- else
- {:visible, false} -> {:error, :not_found}
- _ -> json(conn, [])
- end
- end
-
def followers(%{assigns: %{user: for_user}} = conn, %{"id" => id} = params) do
with %User{} = user <- User.get_cached_by_id(id),
followers <- MastodonAPI.get_followers(user, params) do
@@ -1394,22 +1146,6 @@ defp fetch_suggestion_id(attrs) do
end
end
- def status_card(%{assigns: %{user: user}} = conn, %{"id" => status_id}) do
- with %Activity{} = activity <- Activity.get_by_id(status_id),
- true <- Visibility.visible_for_user?(activity, user) do
- data =
- StatusView.render(
- "card.json",
- Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity)
- )
-
- json(conn, data)
- else
- _e ->
- %{}
- end
- end
-
def reports(%{assigns: %{user: user}} = conn, params) do
case CommonAPI.report(user, params) do
{:ok, activity} ->
diff --git a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex
new file mode 100644
index 000000000..f7da10289
--- /dev/null
+++ b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex
@@ -0,0 +1,269 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.MastodonAPI.StatusController do
+ use Pleroma.Web, :controller
+
+ import Pleroma.Web.MastodonAPI.MastodonAPIController, only: [try_render: 3]
+
+ require Ecto.Query
+
+ alias Pleroma.Activity
+ alias Pleroma.Bookmark
+ alias Pleroma.Object
+ alias Pleroma.Plugs.RateLimiter
+ alias Pleroma.Repo
+ alias Pleroma.ScheduledActivity
+ alias Pleroma.User
+ alias Pleroma.Web.ActivityPub.ActivityPub
+ alias Pleroma.Web.ActivityPub.Visibility
+ alias Pleroma.Web.CommonAPI
+ alias Pleroma.Web.MastodonAPI.AccountView
+ alias Pleroma.Web.MastodonAPI.ScheduledActivityView
+
+ @rate_limited_status_actions ~w(reblog unreblog favourite unfavourite create delete)a
+
+ plug(
+ RateLimiter,
+ {:status_id_action, bucket_name: "status_id_action:reblog_unreblog", params: ["id"]}
+ when action in ~w(reblog unreblog)a
+ )
+
+ plug(
+ RateLimiter,
+ {:status_id_action, bucket_name: "status_id_action:fav_unfav", params: ["id"]}
+ when action in ~w(favourite unfavourite)a
+ )
+
+ plug(RateLimiter, :statuses_actions when action in @rate_limited_status_actions)
+
+ action_fallback(Pleroma.Web.MastodonAPI.FallbackController)
+
+ @doc """
+ GET `/api/v1/statuses?ids[]=1&ids[]=2`
+
+ `ids` query param is required
+ """
+ def index(%{assigns: %{user: user}} = conn, %{"ids" => ids}) do
+ limit = 100
+
+ activities =
+ ids
+ |> Enum.take(limit)
+ |> Activity.all_by_ids_with_object()
+ |> Enum.filter(&Visibility.visible_for_user?(&1, user))
+
+ render(conn, "index.json", activities: activities, for: user, as: :activity)
+ end
+
+ @doc """
+ POST /api/v1/statuses
+
+ Creates a scheduled status when `scheduled_at` param is present and it's far enough
+ """
+ def create(
+ %{assigns: %{user: user}} = conn,
+ %{"status" => _, "scheduled_at" => scheduled_at} = params
+ ) do
+ params = Map.put(params, "in_reply_to_status_id", params["in_reply_to_id"])
+
+ if ScheduledActivity.far_enough?(scheduled_at) do
+ with {:ok, scheduled_activity} <-
+ ScheduledActivity.create(user, %{"params" => params, "scheduled_at" => scheduled_at}) do
+ conn
+ |> put_view(ScheduledActivityView)
+ |> render("show.json", scheduled_activity: scheduled_activity)
+ end
+ else
+ create(conn, Map.drop(params, ["scheduled_at"]))
+ end
+ end
+
+ @doc """
+ POST /api/v1/statuses
+
+ Creates a regular status
+ """
+ def create(%{assigns: %{user: user}} = conn, %{"status" => _} = params) do
+ params = Map.put(params, "in_reply_to_status_id", params["in_reply_to_id"])
+
+ with {:ok, activity} <- CommonAPI.post(user, params) do
+ try_render(conn, "show.json",
+ activity: activity,
+ for: user,
+ as: :activity,
+ with_direct_conversation_id: true
+ )
+ else
+ {:error, message} ->
+ conn
+ |> put_status(:unprocessable_entity)
+ |> json(%{error: message})
+ end
+ end
+
+ @doc "GET /api/v1/statuses/:id"
+ def show(%{assigns: %{user: user}} = conn, %{"id" => id}) do
+ with %Activity{} = activity <- Activity.get_by_id_with_object(id),
+ true <- Visibility.visible_for_user?(activity, user) do
+ try_render(conn, "show.json", activity: activity, for: user)
+ end
+ end
+
+ @doc "DELETE /api/v1/statuses/:id"
+ def delete(%{assigns: %{user: user}} = conn, %{"id" => id}) do
+ with {:ok, %Activity{}} <- CommonAPI.delete(id, user) do
+ json(conn, %{})
+ else
+ _e -> render_error(conn, :forbidden, "Can't delete this post")
+ end
+ end
+
+ @doc "POST /api/v1/statuses/:id/reblog"
+ def reblog(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do
+ with {:ok, announce, _activity} <- CommonAPI.repeat(ap_id_or_id, user),
+ %Activity{} = announce <- Activity.normalize(announce.data) do
+ try_render(conn, "show.json", %{activity: announce, for: user, as: :activity})
+ end
+ end
+
+ @doc "POST /api/v1/statuses/:id/unreblog"
+ def unreblog(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do
+ with {:ok, _unannounce, %{data: %{"id" => id}}} <- CommonAPI.unrepeat(ap_id_or_id, user),
+ %Activity{} = activity <- Activity.get_create_by_object_ap_id_with_object(id) do
+ try_render(conn, "show.json", %{activity: activity, for: user, as: :activity})
+ end
+ end
+
+ @doc "POST /api/v1/statuses/:id/favourite"
+ def favourite(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do
+ with {:ok, _fav, %{data: %{"id" => id}}} <- CommonAPI.favorite(ap_id_or_id, user),
+ %Activity{} = activity <- Activity.get_create_by_object_ap_id(id) do
+ try_render(conn, "show.json", activity: activity, for: user, as: :activity)
+ end
+ end
+
+ @doc "POST /api/v1/statuses/:id/unfavourite"
+ def unfavourite(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do
+ with {:ok, _, _, %{data: %{"id" => id}}} <- CommonAPI.unfavorite(ap_id_or_id, user),
+ %Activity{} = activity <- Activity.get_create_by_object_ap_id(id) do
+ try_render(conn, "show.json", activity: activity, for: user, as: :activity)
+ end
+ end
+
+ @doc "POST /api/v1/statuses/:id/pin"
+ def pin(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do
+ with {:ok, activity} <- CommonAPI.pin(ap_id_or_id, user) do
+ try_render(conn, "show.json", activity: activity, for: user, as: :activity)
+ end
+ end
+
+ @doc "POST /api/v1/statuses/:id/unpin"
+ def unpin(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do
+ with {:ok, activity} <- CommonAPI.unpin(ap_id_or_id, user) do
+ try_render(conn, "show.json", activity: activity, for: user, as: :activity)
+ end
+ end
+
+ @doc "POST /api/v1/statuses/:id/bookmark"
+ def bookmark(%{assigns: %{user: user}} = conn, %{"id" => id}) do
+ with %Activity{} = activity <- Activity.get_by_id_with_object(id),
+ %User{} = user <- User.get_cached_by_nickname(user.nickname),
+ true <- Visibility.visible_for_user?(activity, user),
+ {:ok, _bookmark} <- Bookmark.create(user.id, activity.id) do
+ try_render(conn, "show.json", activity: activity, for: user, as: :activity)
+ end
+ end
+
+ @doc "POST /api/v1/statuses/:id/unbookmark"
+ def unbookmark(%{assigns: %{user: user}} = conn, %{"id" => id}) do
+ with %Activity{} = activity <- Activity.get_by_id_with_object(id),
+ %User{} = user <- User.get_cached_by_nickname(user.nickname),
+ true <- Visibility.visible_for_user?(activity, user),
+ {:ok, _bookmark} <- Bookmark.destroy(user.id, activity.id) do
+ try_render(conn, "show.json", activity: activity, for: user, as: :activity)
+ end
+ end
+
+ @doc "POST /api/v1/statuses/:id/mute"
+ def mute_conversation(%{assigns: %{user: user}} = conn, %{"id" => id}) do
+ with %Activity{} = activity <- Activity.get_by_id(id),
+ {:ok, activity} <- CommonAPI.add_mute(user, activity) do
+ try_render(conn, "show.json", activity: activity, for: user, as: :activity)
+ end
+ end
+
+ @doc "POST /api/v1/statuses/:id/unmute"
+ def unmute_conversation(%{assigns: %{user: user}} = conn, %{"id" => id}) do
+ with %Activity{} = activity <- Activity.get_by_id(id),
+ {:ok, activity} <- CommonAPI.remove_mute(user, activity) do
+ try_render(conn, "show.json", activity: activity, for: user, as: :activity)
+ end
+ end
+
+ @doc "GET /api/v1/statuses/:id/card"
+ def card(%{assigns: %{user: user}} = conn, %{"id" => status_id}) do
+ with %Activity{} = activity <- Activity.get_by_id(status_id),
+ true <- Visibility.visible_for_user?(activity, user) do
+ data = Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity)
+ render(conn, "card.json", data)
+ else
+ _ -> render_error(conn, :not_found, "Record not found")
+ end
+ end
+
+ @doc "GET /api/v1/statuses/:id/favourited_by"
+ def favourited_by(%{assigns: %{user: user}} = conn, %{"id" => id}) do
+ with %Activity{} = activity <- Activity.get_by_id_with_object(id),
+ {:visible, true} <- {:visible, Visibility.visible_for_user?(activity, user)},
+ %Object{data: %{"likes" => likes}} <- Object.normalize(activity) do
+ users =
+ User
+ |> Ecto.Query.where([u], u.ap_id in ^likes)
+ |> Repo.all()
+ |> Enum.filter(&(not User.blocks?(user, &1)))
+
+ conn
+ |> put_view(AccountView)
+ |> render("accounts.json", for: user, users: users, as: :user)
+ else
+ {:visible, false} -> {:error, :not_found}
+ _ -> json(conn, [])
+ end
+ end
+
+ @doc "GET /api/v1/statuses/:id/reblogged_by"
+ def reblogged_by(%{assigns: %{user: user}} = conn, %{"id" => id}) do
+ with %Activity{} = activity <- Activity.get_by_id_with_object(id),
+ {:visible, true} <- {:visible, Visibility.visible_for_user?(activity, user)},
+ %Object{data: %{"announcements" => announces}} <- Object.normalize(activity) do
+ users =
+ User
+ |> Ecto.Query.where([u], u.ap_id in ^announces)
+ |> Repo.all()
+ |> Enum.filter(&(not User.blocks?(user, &1)))
+
+ conn
+ |> put_view(AccountView)
+ |> render("accounts.json", for: user, users: users, as: :user)
+ else
+ {:visible, false} -> {:error, :not_found}
+ _ -> json(conn, [])
+ end
+ end
+
+ @doc "GET /api/v1/statuses/:id/context"
+ def context(%{assigns: %{user: user}} = conn, %{"id" => id}) do
+ with %Activity{} = activity <- Activity.get_by_id(id) do
+ activities =
+ ActivityPub.fetch_activities_for_context(activity.data["context"], %{
+ "blocking_user" => user,
+ "user" => user,
+ "exclude_id" => activity.id
+ })
+
+ render(conn, "context.json", activity: activity, activities: activities, user: user)
+ end
+ end
+end
diff --git a/lib/pleroma/web/mastodon_api/views/conversation_view.ex b/lib/pleroma/web/mastodon_api/views/conversation_view.ex
index 40acc07b3..4aeb79d81 100644
--- a/lib/pleroma/web/mastodon_api/views/conversation_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/conversation_view.ex
@@ -24,7 +24,7 @@ def render("participation.json", %{participation: participation, for: user}) do
activity = Activity.get_by_id_with_object(last_activity_id)
- last_status = StatusView.render("status.json", %{activity: activity, for: user})
+ last_status = StatusView.render("show.json", %{activity: activity, for: user})
# Conversations return all users except the current user.
users =
diff --git a/lib/pleroma/web/mastodon_api/views/notification_view.ex b/lib/pleroma/web/mastodon_api/views/notification_view.ex
index ec8eadcaa..05110a192 100644
--- a/lib/pleroma/web/mastodon_api/views/notification_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/notification_view.ex
@@ -39,19 +39,19 @@ def render("show.json", %{
"mention" ->
response
|> Map.merge(%{
- status: StatusView.render("status.json", %{activity: activity, for: user})
+ status: StatusView.render("show.json", %{activity: activity, for: user})
})
"favourite" ->
response
|> Map.merge(%{
- status: StatusView.render("status.json", %{activity: parent_activity, for: user})
+ status: StatusView.render("show.json", %{activity: parent_activity, for: user})
})
"reblog" ->
response
|> Map.merge(%{
- status: StatusView.render("status.json", %{activity: parent_activity, for: user})
+ status: StatusView.render("show.json", %{activity: parent_activity, for: user})
})
"follow" ->
diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex
index ef796cddd..715d40766 100644
--- a/lib/pleroma/web/mastodon_api/views/status_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/status_view.ex
@@ -73,17 +73,13 @@ defp reblogged?(activity, user) do
def render("index.json", opts) do
replied_to_activities = get_replied_to_activities(opts.activities)
+ opts = Map.put(opts, :replied_to_activities, replied_to_activities)
- opts.activities
- |> safe_render_many(
- StatusView,
- "status.json",
- Map.put(opts, :replied_to_activities, replied_to_activities)
- )
+ safe_render_many(opts.activities, StatusView, "show.json", opts)
end
def render(
- "status.json",
+ "show.json",
%{activity: %{data: %{"type" => "Announce", "object" => _object}} = activity} = opts
) do
user = get_user(activity.data["actor"])
@@ -96,7 +92,7 @@ def render(
|> Activity.with_set_thread_muted_field(opts[:for])
|> Repo.one()
- reblogged = render("status.json", Map.put(opts, :activity, reblogged_activity))
+ reblogged = render("show.json", Map.put(opts, :activity, reblogged_activity))
favorited = opts[:for] && opts[:for].ap_id in (activity_object.data["likes"] || [])
@@ -144,7 +140,7 @@ def render(
}
end
- def render("status.json", %{activity: %{data: %{"object" => _object}} = activity} = opts) do
+ def render("show.json", %{activity: %{data: %{"object" => _object}} = activity} = opts) do
object = Object.normalize(activity)
user = get_user(activity.data["actor"])
@@ -303,7 +299,7 @@ def render("status.json", %{activity: %{data: %{"object" => _object}} = activity
}
end
- def render("status.json", _) do
+ def render("show.json", _) do
nil
end
@@ -443,6 +439,20 @@ def render("poll.json", %{object: object} = opts) do
end
end
+ def render("context.json", %{activity: activity, activities: activities, user: user}) do
+ %{ancestors: ancestors, descendants: descendants} =
+ activities
+ |> Enum.reverse()
+ |> Enum.group_by(fn %{id: id} -> if id < activity.id, do: :ancestors, else: :descendants end)
+ |> Map.put_new(:ancestors, [])
+ |> Map.put_new(:descendants, [])
+
+ %{
+ ancestors: render("index.json", for: user, activities: ancestors, as: :activity),
+ descendants: render("index.json", for: user, activities: descendants, as: :activity)
+ }
+ end
+
def get_reply_to(activity, %{replied_to_activities: replied_to_activities}) do
object = Object.normalize(activity)
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index 5b744e898..8bf55631e 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -363,19 +363,19 @@ defmodule Pleroma.Web.Router do
patch("/accounts/update_credentials", MastodonAPIController, :update_credentials)
- post("/statuses", MastodonAPIController, :post_status)
- delete("/statuses/:id", MastodonAPIController, :delete_status)
+ post("/statuses", StatusController, :create)
+ delete("/statuses/:id", StatusController, :delete)
- post("/statuses/:id/reblog", MastodonAPIController, :reblog_status)
- post("/statuses/:id/unreblog", MastodonAPIController, :unreblog_status)
- post("/statuses/:id/favourite", MastodonAPIController, :fav_status)
- post("/statuses/:id/unfavourite", MastodonAPIController, :unfav_status)
- post("/statuses/:id/pin", MastodonAPIController, :pin_status)
- post("/statuses/:id/unpin", MastodonAPIController, :unpin_status)
- post("/statuses/:id/bookmark", MastodonAPIController, :bookmark_status)
- post("/statuses/:id/unbookmark", MastodonAPIController, :unbookmark_status)
- post("/statuses/:id/mute", MastodonAPIController, :mute_conversation)
- post("/statuses/:id/unmute", MastodonAPIController, :unmute_conversation)
+ post("/statuses/:id/reblog", StatusController, :reblog)
+ post("/statuses/:id/unreblog", StatusController, :unreblog)
+ post("/statuses/:id/favourite", StatusController, :favourite)
+ post("/statuses/:id/unfavourite", StatusController, :unfavourite)
+ post("/statuses/:id/pin", StatusController, :pin)
+ post("/statuses/:id/unpin", StatusController, :unpin)
+ post("/statuses/:id/bookmark", StatusController, :bookmark)
+ post("/statuses/:id/unbookmark", StatusController, :unbookmark)
+ post("/statuses/:id/mute", StatusController, :mute_conversation)
+ post("/statuses/:id/unmute", StatusController, :unmute_conversation)
put("/scheduled_statuses/:id", MastodonAPIController, :update_scheduled_status)
delete("/scheduled_statuses/:id", MastodonAPIController, :delete_scheduled_status)
@@ -456,10 +456,10 @@ defmodule Pleroma.Web.Router do
get("/apps/verify_credentials", MastodonAPIController, :verify_app_credentials)
get("/custom_emojis", MastodonAPIController, :custom_emojis)
- get("/statuses/:id/card", MastodonAPIController, :status_card)
+ get("/statuses/:id/card", StatusController, :card)
- get("/statuses/:id/favourited_by", MastodonAPIController, :favourited_by)
- get("/statuses/:id/reblogged_by", MastodonAPIController, :reblogged_by)
+ get("/statuses/:id/favourited_by", StatusController, :favourited_by)
+ get("/statuses/:id/reblogged_by", StatusController, :reblogged_by)
get("/trends", MastodonAPIController, :empty_array)
@@ -478,9 +478,9 @@ defmodule Pleroma.Web.Router do
get("/timelines/tag/:tag", TimelineController, :hashtag)
get("/timelines/list/:list_id", TimelineController, :list)
- get("/statuses", MastodonAPIController, :get_statuses)
- get("/statuses/:id", MastodonAPIController, :get_status)
- get("/statuses/:id/context", MastodonAPIController, :get_context)
+ get("/statuses", StatusController, :index)
+ get("/statuses/:id", StatusController, :show)
+ get("/statuses/:id/context", StatusController, :context)
get("/polls/:id", MastodonAPIController, :get_poll)
diff --git a/lib/pleroma/web/views/streamer_view.ex b/lib/pleroma/web/views/streamer_view.ex
index b13030fa0..a9f14d09a 100644
--- a/lib/pleroma/web/views/streamer_view.ex
+++ b/lib/pleroma/web/views/streamer_view.ex
@@ -16,7 +16,7 @@ def render("update.json", %Activity{} = activity, %User{} = user) do
event: "update",
payload:
Pleroma.Web.MastodonAPI.StatusView.render(
- "status.json",
+ "show.json",
activity: activity,
for: user
)
@@ -43,7 +43,7 @@ def render("update.json", %Activity{} = activity) do
event: "update",
payload:
Pleroma.Web.MastodonAPI.StatusView.render(
- "status.json",
+ "show.json",
activity: activity
)
|> Jason.encode!()
diff --git a/test/integration/mastodon_websocket_test.exs b/test/integration/mastodon_websocket_test.exs
index ed7ce8fe0..63fce07bb 100644
--- a/test/integration/mastodon_websocket_test.exs
+++ b/test/integration/mastodon_websocket_test.exs
@@ -68,7 +68,7 @@ test "receives well formatted events" do
assert {:ok, json} = Jason.decode(json["payload"])
view_json =
- Pleroma.Web.MastodonAPI.StatusView.render("status.json", activity: activity, for: nil)
+ Pleroma.Web.MastodonAPI.StatusView.render("show.json", activity: activity, for: nil)
|> Jason.encode!()
|> Jason.decode!()
diff --git a/test/web/admin_api/views/report_view_test.exs b/test/web/admin_api/views/report_view_test.exs
index 40df01101..35b6947a0 100644
--- a/test/web/admin_api/views/report_view_test.exs
+++ b/test/web/admin_api/views/report_view_test.exs
@@ -61,7 +61,7 @@ test "includes reported statuses" do
AccountView.render("account.json", %{user: other_user}),
Pleroma.Web.AdminAPI.AccountView.render("show.json", %{user: other_user})
),
- statuses: [StatusView.render("status.json", %{activity: activity})],
+ statuses: [StatusView.render("show.json", %{activity: activity})],
state: "open",
id: report_activity.id
}
diff --git a/test/web/mastodon_api/controllers/status_controller_test.exs b/test/web/mastodon_api/controllers/status_controller_test.exs
new file mode 100644
index 000000000..14c7bd6d9
--- /dev/null
+++ b/test/web/mastodon_api/controllers/status_controller_test.exs
@@ -0,0 +1,1077 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
+ use Pleroma.Web.ConnCase
+
+ alias Pleroma.Activity
+ alias Pleroma.ActivityExpiration
+ alias Pleroma.Config
+ alias Pleroma.Object
+ alias Pleroma.User
+ alias Pleroma.Web.CommonAPI
+
+ import Pleroma.Factory
+
+ describe "posting statuses" do
+ setup do
+ user = insert(:user)
+
+ conn =
+ build_conn()
+ |> assign(:user, user)
+
+ [conn: conn]
+ end
+
+ test "posting a status", %{conn: conn} do
+ idempotency_key = "Pikachu rocks!"
+
+ conn_one =
+ conn
+ |> put_req_header("idempotency-key", idempotency_key)
+ |> post("/api/v1/statuses", %{
+ "status" => "cofe",
+ "spoiler_text" => "2hu",
+ "sensitive" => "false"
+ })
+
+ {:ok, ttl} = Cachex.ttl(:idempotency_cache, idempotency_key)
+ # Six hours
+ assert ttl > :timer.seconds(6 * 60 * 60 - 1)
+
+ assert %{"content" => "cofe", "id" => id, "spoiler_text" => "2hu", "sensitive" => false} =
+ json_response(conn_one, 200)
+
+ assert Activity.get_by_id(id)
+
+ conn_two =
+ conn
+ |> put_req_header("idempotency-key", idempotency_key)
+ |> post("/api/v1/statuses", %{
+ "status" => "cofe",
+ "spoiler_text" => "2hu",
+ "sensitive" => "false"
+ })
+
+ assert %{"id" => second_id} = json_response(conn_two, 200)
+ assert id == second_id
+
+ conn_three =
+ conn
+ |> post("/api/v1/statuses", %{
+ "status" => "cofe",
+ "spoiler_text" => "2hu",
+ "sensitive" => "false"
+ })
+
+ assert %{"id" => third_id} = json_response(conn_three, 200)
+ refute id == third_id
+
+ # An activity that will expire:
+ # 2 hours
+ expires_in = 120 * 60
+
+ conn_four =
+ conn
+ |> post("api/v1/statuses", %{
+ "status" => "oolong",
+ "expires_in" => expires_in
+ })
+
+ assert fourth_response = %{"id" => fourth_id} = json_response(conn_four, 200)
+ assert activity = Activity.get_by_id(fourth_id)
+ assert expiration = ActivityExpiration.get_by_activity_id(fourth_id)
+
+ estimated_expires_at =
+ NaiveDateTime.utc_now()
+ |> NaiveDateTime.add(expires_in)
+ |> NaiveDateTime.truncate(:second)
+
+ # This assert will fail if the test takes longer than a minute. I sure hope it never does:
+ assert abs(NaiveDateTime.diff(expiration.scheduled_at, estimated_expires_at, :second)) < 60
+
+ assert fourth_response["pleroma"]["expires_at"] ==
+ NaiveDateTime.to_iso8601(expiration.scheduled_at)
+ end
+
+ test "replying to a status", %{conn: conn} do
+ user = insert(:user)
+ {:ok, replied_to} = CommonAPI.post(user, %{"status" => "cofe"})
+
+ conn =
+ conn
+ |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => replied_to.id})
+
+ assert %{"content" => "xD", "id" => id} = json_response(conn, 200)
+
+ activity = Activity.get_by_id(id)
+
+ assert activity.data["context"] == replied_to.data["context"]
+ assert Activity.get_in_reply_to_activity(activity).id == replied_to.id
+ end
+
+ test "replying to a direct message with visibility other than direct", %{conn: conn} do
+ user = insert(:user)
+ {:ok, replied_to} = CommonAPI.post(user, %{"status" => "suya..", "visibility" => "direct"})
+
+ Enum.each(["public", "private", "unlisted"], fn visibility ->
+ conn =
+ conn
+ |> post("/api/v1/statuses", %{
+ "status" => "@#{user.nickname} hey",
+ "in_reply_to_id" => replied_to.id,
+ "visibility" => visibility
+ })
+
+ assert json_response(conn, 422) == %{"error" => "The message visibility must be direct"}
+ end)
+ end
+
+ test "posting a status with an invalid in_reply_to_id", %{conn: conn} do
+ conn =
+ conn
+ |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => ""})
+
+ assert %{"content" => "xD", "id" => id} = json_response(conn, 200)
+ assert Activity.get_by_id(id)
+ end
+
+ test "posting a sensitive status", %{conn: conn} do
+ conn =
+ conn
+ |> post("/api/v1/statuses", %{"status" => "cofe", "sensitive" => true})
+
+ assert %{"content" => "cofe", "id" => id, "sensitive" => true} = json_response(conn, 200)
+ assert Activity.get_by_id(id)
+ end
+
+ test "posting a fake status", %{conn: conn} do
+ real_conn =
+ conn
+ |> post("/api/v1/statuses", %{
+ "status" =>
+ "\"Tenshi Eating a Corndog\" is a much discussed concept on /jp/. The significance of it is disputed, so I will focus on one core concept: the symbolism behind it"
+ })
+
+ real_status = json_response(real_conn, 200)
+
+ assert real_status
+ assert Object.get_by_ap_id(real_status["uri"])
+
+ real_status =
+ real_status
+ |> Map.put("id", nil)
+ |> Map.put("url", nil)
+ |> Map.put("uri", nil)
+ |> Map.put("created_at", nil)
+ |> Kernel.put_in(["pleroma", "conversation_id"], nil)
+
+ fake_conn =
+ conn
+ |> post("/api/v1/statuses", %{
+ "status" =>
+ "\"Tenshi Eating a Corndog\" is a much discussed concept on /jp/. The significance of it is disputed, so I will focus on one core concept: the symbolism behind it",
+ "preview" => true
+ })
+
+ fake_status = json_response(fake_conn, 200)
+
+ assert fake_status
+ refute Object.get_by_ap_id(fake_status["uri"])
+
+ fake_status =
+ fake_status
+ |> Map.put("id", nil)
+ |> Map.put("url", nil)
+ |> Map.put("uri", nil)
+ |> Map.put("created_at", nil)
+ |> Kernel.put_in(["pleroma", "conversation_id"], nil)
+
+ assert real_status == fake_status
+ end
+
+ test "posting a status with OGP link preview", %{conn: conn} do
+ Tesla.Mock.mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
+ Config.put([:rich_media, :enabled], true)
+
+ conn =
+ conn
+ |> post("/api/v1/statuses", %{
+ "status" => "https://example.com/ogp"
+ })
+
+ assert %{"id" => id, "card" => %{"title" => "The Rock"}} = json_response(conn, 200)
+ assert Activity.get_by_id(id)
+ end
+
+ test "posting a direct status", %{conn: conn} do
+ user2 = insert(:user)
+ content = "direct cofe @#{user2.nickname}"
+
+ conn =
+ conn
+ |> post("api/v1/statuses", %{"status" => content, "visibility" => "direct"})
+
+ assert %{"id" => id} = response = json_response(conn, 200)
+ assert response["visibility"] == "direct"
+ assert response["pleroma"]["direct_conversation_id"]
+ assert activity = Activity.get_by_id(id)
+ assert activity.recipients == [user2.ap_id, conn.assigns[:user].ap_id]
+ assert activity.data["to"] == [user2.ap_id]
+ assert activity.data["cc"] == []
+ end
+ end
+
+ describe "posting polls" do
+ test "posting a poll", %{conn: conn} do
+ user = insert(:user)
+ time = NaiveDateTime.utc_now()
+
+ conn =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/statuses", %{
+ "status" => "Who is the #bestgrill?",
+ "poll" => %{"options" => ["Rei", "Asuka", "Misato"], "expires_in" => 420}
+ })
+
+ response = json_response(conn, 200)
+
+ assert Enum.all?(response["poll"]["options"], fn %{"title" => title} ->
+ title in ["Rei", "Asuka", "Misato"]
+ end)
+
+ assert NaiveDateTime.diff(NaiveDateTime.from_iso8601!(response["poll"]["expires_at"]), time) in 420..430
+ refute response["poll"]["expred"]
+ end
+
+ test "option limit is enforced", %{conn: conn} do
+ user = insert(:user)
+ limit = Config.get([:instance, :poll_limits, :max_options])
+
+ conn =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/statuses", %{
+ "status" => "desu~",
+ "poll" => %{"options" => Enum.map(0..limit, fn _ -> "desu" end), "expires_in" => 1}
+ })
+
+ %{"error" => error} = json_response(conn, 422)
+ assert error == "Poll can't contain more than #{limit} options"
+ end
+
+ test "option character limit is enforced", %{conn: conn} do
+ user = insert(:user)
+ limit = Config.get([:instance, :poll_limits, :max_option_chars])
+
+ conn =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/statuses", %{
+ "status" => "...",
+ "poll" => %{
+ "options" => [Enum.reduce(0..limit, "", fn _, acc -> acc <> "." end)],
+ "expires_in" => 1
+ }
+ })
+
+ %{"error" => error} = json_response(conn, 422)
+ assert error == "Poll options cannot be longer than #{limit} characters each"
+ end
+
+ test "minimal date limit is enforced", %{conn: conn} do
+ user = insert(:user)
+ limit = Config.get([:instance, :poll_limits, :min_expiration])
+
+ conn =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/statuses", %{
+ "status" => "imagine arbitrary limits",
+ "poll" => %{
+ "options" => ["this post was made by pleroma gang"],
+ "expires_in" => limit - 1
+ }
+ })
+
+ %{"error" => error} = json_response(conn, 422)
+ assert error == "Expiration date is too soon"
+ end
+
+ test "maximum date limit is enforced", %{conn: conn} do
+ user = insert(:user)
+ limit = Config.get([:instance, :poll_limits, :max_expiration])
+
+ conn =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/statuses", %{
+ "status" => "imagine arbitrary limits",
+ "poll" => %{
+ "options" => ["this post was made by pleroma gang"],
+ "expires_in" => limit + 1
+ }
+ })
+
+ %{"error" => error} = json_response(conn, 422)
+ assert error == "Expiration date is too far in the future"
+ end
+ end
+
+ test "get a status", %{conn: conn} do
+ activity = insert(:note_activity)
+
+ conn =
+ conn
+ |> get("/api/v1/statuses/#{activity.id}")
+
+ assert %{"id" => id} = json_response(conn, 200)
+ assert id == to_string(activity.id)
+ end
+
+ test "get statuses by IDs", %{conn: conn} do
+ %{id: id1} = insert(:note_activity)
+ %{id: id2} = insert(:note_activity)
+
+ query_string = "ids[]=#{id1}&ids[]=#{id2}"
+ conn = get(conn, "/api/v1/statuses/?#{query_string}")
+
+ assert [%{"id" => ^id1}, %{"id" => ^id2}] = Enum.sort_by(json_response(conn, :ok), & &1["id"])
+ end
+
+ describe "deleting a status" do
+ test "when you created it", %{conn: conn} do
+ activity = insert(:note_activity)
+ author = User.get_cached_by_ap_id(activity.data["actor"])
+
+ conn =
+ conn
+ |> assign(:user, author)
+ |> delete("/api/v1/statuses/#{activity.id}")
+
+ assert %{} = json_response(conn, 200)
+
+ refute Activity.get_by_id(activity.id)
+ end
+
+ test "when you didn't create it", %{conn: conn} do
+ activity = insert(:note_activity)
+ user = insert(:user)
+
+ conn =
+ conn
+ |> assign(:user, user)
+ |> delete("/api/v1/statuses/#{activity.id}")
+
+ assert %{"error" => _} = json_response(conn, 403)
+
+ assert Activity.get_by_id(activity.id) == activity
+ end
+
+ test "when you're an admin or moderator", %{conn: conn} do
+ activity1 = insert(:note_activity)
+ activity2 = insert(:note_activity)
+ admin = insert(:user, info: %{is_admin: true})
+ moderator = insert(:user, info: %{is_moderator: true})
+
+ res_conn =
+ conn
+ |> assign(:user, admin)
+ |> delete("/api/v1/statuses/#{activity1.id}")
+
+ assert %{} = json_response(res_conn, 200)
+
+ res_conn =
+ conn
+ |> assign(:user, moderator)
+ |> delete("/api/v1/statuses/#{activity2.id}")
+
+ assert %{} = json_response(res_conn, 200)
+
+ refute Activity.get_by_id(activity1.id)
+ refute Activity.get_by_id(activity2.id)
+ end
+ end
+
+ describe "reblogging" do
+ test "reblogs and returns the reblogged status", %{conn: conn} do
+ activity = insert(:note_activity)
+ user = insert(:user)
+
+ conn =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/statuses/#{activity.id}/reblog")
+
+ assert %{
+ "reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1},
+ "reblogged" => true
+ } = json_response(conn, 200)
+
+ assert to_string(activity.id) == id
+ end
+
+ test "reblogged status for another user", %{conn: conn} do
+ activity = insert(:note_activity)
+ user1 = insert(:user)
+ user2 = insert(:user)
+ user3 = insert(:user)
+ CommonAPI.favorite(activity.id, user2)
+ {:ok, _bookmark} = Pleroma.Bookmark.create(user2.id, activity.id)
+ {:ok, reblog_activity1, _object} = CommonAPI.repeat(activity.id, user1)
+ {:ok, _, _object} = CommonAPI.repeat(activity.id, user2)
+
+ conn_res =
+ conn
+ |> assign(:user, user3)
+ |> get("/api/v1/statuses/#{reblog_activity1.id}")
+
+ assert %{
+ "reblog" => %{"id" => id, "reblogged" => false, "reblogs_count" => 2},
+ "reblogged" => false,
+ "favourited" => false,
+ "bookmarked" => false
+ } = json_response(conn_res, 200)
+
+ conn_res =
+ conn
+ |> assign(:user, user2)
+ |> get("/api/v1/statuses/#{reblog_activity1.id}")
+
+ assert %{
+ "reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 2},
+ "reblogged" => true,
+ "favourited" => true,
+ "bookmarked" => true
+ } = json_response(conn_res, 200)
+
+ assert to_string(activity.id) == id
+ end
+
+ test "returns 400 error when activity is not exist", %{conn: conn} do
+ user = insert(:user)
+
+ conn =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/statuses/foo/reblog")
+
+ assert json_response(conn, 400) == %{"error" => "Could not repeat"}
+ end
+ end
+
+ describe "unreblogging" do
+ test "unreblogs and returns the unreblogged status", %{conn: conn} do
+ activity = insert(:note_activity)
+ user = insert(:user)
+
+ {:ok, _, _} = CommonAPI.repeat(activity.id, user)
+
+ conn =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/statuses/#{activity.id}/unreblog")
+
+ assert %{"id" => id, "reblogged" => false, "reblogs_count" => 0} = json_response(conn, 200)
+
+ assert to_string(activity.id) == id
+ end
+
+ test "returns 400 error when activity is not exist", %{conn: conn} do
+ user = insert(:user)
+
+ conn =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/statuses/foo/unreblog")
+
+ assert json_response(conn, 400) == %{"error" => "Could not unrepeat"}
+ end
+ end
+
+ describe "favoriting" do
+ test "favs a status and returns it", %{conn: conn} do
+ activity = insert(:note_activity)
+ user = insert(:user)
+
+ conn =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/statuses/#{activity.id}/favourite")
+
+ assert %{"id" => id, "favourites_count" => 1, "favourited" => true} =
+ json_response(conn, 200)
+
+ assert to_string(activity.id) == id
+ end
+
+ test "returns 400 error for a wrong id", %{conn: conn} do
+ user = insert(:user)
+
+ conn =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/statuses/1/favourite")
+
+ assert json_response(conn, 400) == %{"error" => "Could not favorite"}
+ end
+ end
+
+ describe "unfavoriting" do
+ test "unfavorites a status and returns it", %{conn: conn} do
+ activity = insert(:note_activity)
+ user = insert(:user)
+
+ {:ok, _, _} = CommonAPI.favorite(activity.id, user)
+
+ conn =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/statuses/#{activity.id}/unfavourite")
+
+ assert %{"id" => id, "favourites_count" => 0, "favourited" => false} =
+ json_response(conn, 200)
+
+ assert to_string(activity.id) == id
+ end
+
+ test "returns 400 error for a wrong id", %{conn: conn} do
+ user = insert(:user)
+
+ conn =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/statuses/1/unfavourite")
+
+ assert json_response(conn, 400) == %{"error" => "Could not unfavorite"}
+ end
+ end
+
+ describe "pinned statuses" do
+ setup do
+ user = insert(:user)
+ {:ok, activity} = CommonAPI.post(user, %{"status" => "HI!!!"})
+
+ [user: user, activity: activity]
+ end
+
+ clear_config([:instance, :max_pinned_statuses]) do
+ Config.put([:instance, :max_pinned_statuses], 1)
+ end
+
+ test "pin status", %{conn: conn, user: user, activity: activity} do
+ id_str = to_string(activity.id)
+
+ assert %{"id" => ^id_str, "pinned" => true} =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/statuses/#{activity.id}/pin")
+ |> json_response(200)
+
+ assert [%{"id" => ^id_str, "pinned" => true}] =
+ conn
+ |> assign(:user, user)
+ |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
+ |> json_response(200)
+ end
+
+ test "/pin: returns 400 error when activity is not public", %{conn: conn, user: user} do
+ {:ok, dm} = CommonAPI.post(user, %{"status" => "test", "visibility" => "direct"})
+
+ conn =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/statuses/#{dm.id}/pin")
+
+ assert json_response(conn, 400) == %{"error" => "Could not pin"}
+ end
+
+ test "unpin status", %{conn: conn, user: user, activity: activity} do
+ {:ok, _} = CommonAPI.pin(activity.id, user)
+
+ id_str = to_string(activity.id)
+ user = refresh_record(user)
+
+ assert %{"id" => ^id_str, "pinned" => false} =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/statuses/#{activity.id}/unpin")
+ |> json_response(200)
+
+ assert [] =
+ conn
+ |> assign(:user, user)
+ |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
+ |> json_response(200)
+ end
+
+ test "/unpin: returns 400 error when activity is not exist", %{conn: conn, user: user} do
+ conn =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/statuses/1/unpin")
+
+ assert json_response(conn, 400) == %{"error" => "Could not unpin"}
+ end
+
+ test "max pinned statuses", %{conn: conn, user: user, activity: activity_one} do
+ {:ok, activity_two} = CommonAPI.post(user, %{"status" => "HI!!!"})
+
+ id_str_one = to_string(activity_one.id)
+
+ assert %{"id" => ^id_str_one, "pinned" => true} =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/statuses/#{id_str_one}/pin")
+ |> json_response(200)
+
+ user = refresh_record(user)
+
+ assert %{"error" => "You have already pinned the maximum number of statuses"} =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/statuses/#{activity_two.id}/pin")
+ |> json_response(400)
+ end
+ end
+
+ describe "cards" do
+ setup do
+ Config.put([:rich_media, :enabled], true)
+
+ user = insert(:user)
+ %{user: user}
+ end
+
+ test "returns rich-media card", %{conn: conn, user: user} do
+ Tesla.Mock.mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
+
+ {:ok, activity} = CommonAPI.post(user, %{"status" => "https://example.com/ogp"})
+
+ card_data = %{
+ "image" => "http://ia.media-imdb.com/images/rock.jpg",
+ "provider_name" => "example.com",
+ "provider_url" => "https://example.com",
+ "title" => "The Rock",
+ "type" => "link",
+ "url" => "https://example.com/ogp",
+ "description" =>
+ "Directed by Michael Bay. With Sean Connery, Nicolas Cage, Ed Harris, John Spencer.",
+ "pleroma" => %{
+ "opengraph" => %{
+ "image" => "http://ia.media-imdb.com/images/rock.jpg",
+ "title" => "The Rock",
+ "type" => "video.movie",
+ "url" => "https://example.com/ogp",
+ "description" =>
+ "Directed by Michael Bay. With Sean Connery, Nicolas Cage, Ed Harris, John Spencer."
+ }
+ }
+ }
+
+ response =
+ conn
+ |> get("/api/v1/statuses/#{activity.id}/card")
+ |> json_response(200)
+
+ assert response == card_data
+
+ # works with private posts
+ {:ok, activity} =
+ CommonAPI.post(user, %{"status" => "https://example.com/ogp", "visibility" => "direct"})
+
+ response_two =
+ conn
+ |> assign(:user, user)
+ |> get("/api/v1/statuses/#{activity.id}/card")
+ |> json_response(200)
+
+ assert response_two == card_data
+ end
+
+ test "replaces missing description with an empty string", %{conn: conn, user: user} do
+ Tesla.Mock.mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
+
+ {:ok, activity} =
+ CommonAPI.post(user, %{"status" => "https://example.com/ogp-missing-data"})
+
+ response =
+ conn
+ |> get("/api/v1/statuses/#{activity.id}/card")
+ |> json_response(:ok)
+
+ assert response == %{
+ "type" => "link",
+ "title" => "Pleroma",
+ "description" => "",
+ "image" => nil,
+ "provider_name" => "example.com",
+ "provider_url" => "https://example.com",
+ "url" => "https://example.com/ogp-missing-data",
+ "pleroma" => %{
+ "opengraph" => %{
+ "title" => "Pleroma",
+ "type" => "website",
+ "url" => "https://example.com/ogp-missing-data"
+ }
+ }
+ }
+ end
+ end
+
+ test "bookmarks" do
+ user = insert(:user)
+ for_user = insert(:user)
+
+ {:ok, activity1} =
+ CommonAPI.post(user, %{
+ "status" => "heweoo?"
+ })
+
+ {:ok, activity2} =
+ CommonAPI.post(user, %{
+ "status" => "heweoo!"
+ })
+
+ response1 =
+ build_conn()
+ |> assign(:user, for_user)
+ |> post("/api/v1/statuses/#{activity1.id}/bookmark")
+
+ assert json_response(response1, 200)["bookmarked"] == true
+
+ response2 =
+ build_conn()
+ |> assign(:user, for_user)
+ |> post("/api/v1/statuses/#{activity2.id}/bookmark")
+
+ assert json_response(response2, 200)["bookmarked"] == true
+
+ bookmarks =
+ build_conn()
+ |> assign(:user, for_user)
+ |> get("/api/v1/bookmarks")
+
+ assert [json_response(response2, 200), json_response(response1, 200)] ==
+ json_response(bookmarks, 200)
+
+ response1 =
+ build_conn()
+ |> assign(:user, for_user)
+ |> post("/api/v1/statuses/#{activity1.id}/unbookmark")
+
+ assert json_response(response1, 200)["bookmarked"] == false
+
+ bookmarks =
+ build_conn()
+ |> assign(:user, for_user)
+ |> get("/api/v1/bookmarks")
+
+ assert [json_response(response2, 200)] == json_response(bookmarks, 200)
+ end
+
+ describe "conversation muting" do
+ setup do
+ post_user = insert(:user)
+ user = insert(:user)
+
+ {:ok, activity} = CommonAPI.post(post_user, %{"status" => "HIE"})
+
+ [user: user, activity: activity]
+ end
+
+ test "mute conversation", %{conn: conn, user: user, activity: activity} do
+ id_str = to_string(activity.id)
+
+ assert %{"id" => ^id_str, "muted" => true} =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/statuses/#{activity.id}/mute")
+ |> json_response(200)
+ end
+
+ test "cannot mute already muted conversation", %{conn: conn, user: user, activity: activity} do
+ {:ok, _} = CommonAPI.add_mute(user, activity)
+
+ conn =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/statuses/#{activity.id}/mute")
+
+ assert json_response(conn, 400) == %{"error" => "conversation is already muted"}
+ end
+
+ test "unmute conversation", %{conn: conn, user: user, activity: activity} do
+ {:ok, _} = CommonAPI.add_mute(user, activity)
+
+ id_str = to_string(activity.id)
+ user = refresh_record(user)
+
+ assert %{"id" => ^id_str, "muted" => false} =
+ conn
+ |> assign(:user, user)
+ |> post("/api/v1/statuses/#{activity.id}/unmute")
+ |> json_response(200)
+ end
+ end
+
+ test "Repeated posts that are replies incorrectly have in_reply_to_id null", %{conn: conn} do
+ user1 = insert(:user)
+ user2 = insert(:user)
+ user3 = insert(:user)
+
+ {:ok, replied_to} = CommonAPI.post(user1, %{"status" => "cofe"})
+
+ # Reply to status from another user
+ conn1 =
+ conn
+ |> assign(:user, user2)
+ |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => replied_to.id})
+
+ assert %{"content" => "xD", "id" => id} = json_response(conn1, 200)
+
+ activity = Activity.get_by_id_with_object(id)
+
+ assert Object.normalize(activity).data["inReplyTo"] == Object.normalize(replied_to).data["id"]
+ assert Activity.get_in_reply_to_activity(activity).id == replied_to.id
+
+ # Reblog from the third user
+ conn2 =
+ conn
+ |> assign(:user, user3)
+ |> post("/api/v1/statuses/#{activity.id}/reblog")
+
+ assert %{"reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1}} =
+ json_response(conn2, 200)
+
+ assert to_string(activity.id) == id
+
+ # Getting third user status
+ conn3 =
+ conn
+ |> assign(:user, user3)
+ |> get("api/v1/timelines/home")
+
+ [reblogged_activity] = json_response(conn3, 200)
+
+ assert reblogged_activity["reblog"]["in_reply_to_id"] == replied_to.id
+
+ replied_to_user = User.get_by_ap_id(replied_to.data["actor"])
+ assert reblogged_activity["reblog"]["in_reply_to_account_id"] == replied_to_user.id
+ end
+
+ describe "GET /api/v1/statuses/:id/favourited_by" do
+ setup do
+ user = insert(:user)
+ {:ok, activity} = CommonAPI.post(user, %{"status" => "test"})
+
+ conn =
+ build_conn()
+ |> assign(:user, user)
+
+ [conn: conn, activity: activity, user: user]
+ end
+
+ test "returns users who have favorited the status", %{conn: conn, activity: activity} do
+ other_user = insert(:user)
+ {:ok, _, _} = CommonAPI.favorite(activity.id, other_user)
+
+ response =
+ conn
+ |> get("/api/v1/statuses/#{activity.id}/favourited_by")
+ |> json_response(:ok)
+
+ [%{"id" => id}] = response
+
+ assert id == other_user.id
+ end
+
+ test "returns empty array when status has not been favorited yet", %{
+ conn: conn,
+ activity: activity
+ } do
+ response =
+ conn
+ |> get("/api/v1/statuses/#{activity.id}/favourited_by")
+ |> json_response(:ok)
+
+ assert Enum.empty?(response)
+ end
+
+ test "does not return users who have favorited the status but are blocked", %{
+ conn: %{assigns: %{user: user}} = conn,
+ activity: activity
+ } do
+ other_user = insert(:user)
+ {:ok, user} = User.block(user, other_user)
+
+ {:ok, _, _} = CommonAPI.favorite(activity.id, other_user)
+
+ response =
+ conn
+ |> assign(:user, user)
+ |> get("/api/v1/statuses/#{activity.id}/favourited_by")
+ |> json_response(:ok)
+
+ assert Enum.empty?(response)
+ end
+
+ test "does not fail on an unauthenticated request", %{conn: conn, activity: activity} do
+ other_user = insert(:user)
+ {:ok, _, _} = CommonAPI.favorite(activity.id, other_user)
+
+ response =
+ conn
+ |> assign(:user, nil)
+ |> get("/api/v1/statuses/#{activity.id}/favourited_by")
+ |> json_response(:ok)
+
+ [%{"id" => id}] = response
+ assert id == other_user.id
+ end
+
+ test "requires authentification for private posts", %{conn: conn, user: user} do
+ other_user = insert(:user)
+
+ {:ok, activity} =
+ CommonAPI.post(user, %{
+ "status" => "@#{other_user.nickname} wanna get some #cofe together?",
+ "visibility" => "direct"
+ })
+
+ {:ok, _, _} = CommonAPI.favorite(activity.id, other_user)
+
+ conn
+ |> assign(:user, nil)
+ |> get("/api/v1/statuses/#{activity.id}/favourited_by")
+ |> json_response(404)
+
+ response =
+ build_conn()
+ |> assign(:user, other_user)
+ |> get("/api/v1/statuses/#{activity.id}/favourited_by")
+ |> json_response(200)
+
+ [%{"id" => id}] = response
+ assert id == other_user.id
+ end
+ end
+
+ describe "GET /api/v1/statuses/:id/reblogged_by" do
+ setup do
+ user = insert(:user)
+ {:ok, activity} = CommonAPI.post(user, %{"status" => "test"})
+
+ conn =
+ build_conn()
+ |> assign(:user, user)
+
+ [conn: conn, activity: activity, user: user]
+ end
+
+ test "returns users who have reblogged the status", %{conn: conn, activity: activity} do
+ other_user = insert(:user)
+ {:ok, _, _} = CommonAPI.repeat(activity.id, other_user)
+
+ response =
+ conn
+ |> get("/api/v1/statuses/#{activity.id}/reblogged_by")
+ |> json_response(:ok)
+
+ [%{"id" => id}] = response
+
+ assert id == other_user.id
+ end
+
+ test "returns empty array when status has not been reblogged yet", %{
+ conn: conn,
+ activity: activity
+ } do
+ response =
+ conn
+ |> get("/api/v1/statuses/#{activity.id}/reblogged_by")
+ |> json_response(:ok)
+
+ assert Enum.empty?(response)
+ end
+
+ test "does not return users who have reblogged the status but are blocked", %{
+ conn: %{assigns: %{user: user}} = conn,
+ activity: activity
+ } do
+ other_user = insert(:user)
+ {:ok, user} = User.block(user, other_user)
+
+ {:ok, _, _} = CommonAPI.repeat(activity.id, other_user)
+
+ response =
+ conn
+ |> assign(:user, user)
+ |> get("/api/v1/statuses/#{activity.id}/reblogged_by")
+ |> json_response(:ok)
+
+ assert Enum.empty?(response)
+ end
+
+ test "does not fail on an unauthenticated request", %{conn: conn, activity: activity} do
+ other_user = insert(:user)
+ {:ok, _, _} = CommonAPI.repeat(activity.id, other_user)
+
+ response =
+ conn
+ |> assign(:user, nil)
+ |> get("/api/v1/statuses/#{activity.id}/reblogged_by")
+ |> json_response(:ok)
+
+ [%{"id" => id}] = response
+ assert id == other_user.id
+ end
+
+ test "requires authentification for private posts", %{conn: conn, user: user} do
+ other_user = insert(:user)
+
+ {:ok, activity} =
+ CommonAPI.post(user, %{
+ "status" => "@#{other_user.nickname} wanna get some #cofe together?",
+ "visibility" => "direct"
+ })
+
+ conn
+ |> assign(:user, nil)
+ |> get("/api/v1/statuses/#{activity.id}/reblogged_by")
+ |> json_response(404)
+
+ response =
+ build_conn()
+ |> assign(:user, other_user)
+ |> get("/api/v1/statuses/#{activity.id}/reblogged_by")
+ |> json_response(200)
+
+ assert [] == response
+ end
+ end
+
+ test "context" do
+ user = insert(:user)
+
+ {:ok, %{id: id1}} = CommonAPI.post(user, %{"status" => "1"})
+ {:ok, %{id: id2}} = CommonAPI.post(user, %{"status" => "2", "in_reply_to_status_id" => id1})
+ {:ok, %{id: id3}} = CommonAPI.post(user, %{"status" => "3", "in_reply_to_status_id" => id2})
+ {:ok, %{id: id4}} = CommonAPI.post(user, %{"status" => "4", "in_reply_to_status_id" => id3})
+ {:ok, %{id: id5}} = CommonAPI.post(user, %{"status" => "5", "in_reply_to_status_id" => id4})
+
+ response =
+ build_conn()
+ |> assign(:user, nil)
+ |> get("/api/v1/statuses/#{id3}/context")
+ |> json_response(:ok)
+
+ assert %{
+ "ancestors" => [%{"id" => ^id1}, %{"id" => ^id2}],
+ "descendants" => [%{"id" => ^id4}, %{"id" => ^id5}]
+ } = response
+ end
+end
diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs
index 7f7a89516..6435ad7a9 100644
--- a/test/web/mastodon_api/mastodon_api_controller_test.exs
+++ b/test/web/mastodon_api/mastodon_api_controller_test.exs
@@ -7,7 +7,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
alias Ecto.Changeset
alias Pleroma.Activity
- alias Pleroma.ActivityExpiration
alias Pleroma.Config
alias Pleroma.Notification
alias Pleroma.Object
@@ -37,312 +36,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
clear_config([:instance, :public])
clear_config([:rich_media, :enabled])
- describe "posting statuses" do
- setup do
- user = insert(:user)
-
- conn =
- build_conn()
- |> assign(:user, user)
-
- [conn: conn]
- end
-
- test "posting a status", %{conn: conn} do
- idempotency_key = "Pikachu rocks!"
-
- conn_one =
- conn
- |> put_req_header("idempotency-key", idempotency_key)
- |> post("/api/v1/statuses", %{
- "status" => "cofe",
- "spoiler_text" => "2hu",
- "sensitive" => "false"
- })
-
- {:ok, ttl} = Cachex.ttl(:idempotency_cache, idempotency_key)
- # Six hours
- assert ttl > :timer.seconds(6 * 60 * 60 - 1)
-
- assert %{"content" => "cofe", "id" => id, "spoiler_text" => "2hu", "sensitive" => false} =
- json_response(conn_one, 200)
-
- assert Activity.get_by_id(id)
-
- conn_two =
- conn
- |> put_req_header("idempotency-key", idempotency_key)
- |> post("/api/v1/statuses", %{
- "status" => "cofe",
- "spoiler_text" => "2hu",
- "sensitive" => "false"
- })
-
- assert %{"id" => second_id} = json_response(conn_two, 200)
- assert id == second_id
-
- conn_three =
- conn
- |> post("/api/v1/statuses", %{
- "status" => "cofe",
- "spoiler_text" => "2hu",
- "sensitive" => "false"
- })
-
- assert %{"id" => third_id} = json_response(conn_three, 200)
- refute id == third_id
-
- # An activity that will expire:
- # 2 hours
- expires_in = 120 * 60
-
- conn_four =
- conn
- |> post("api/v1/statuses", %{
- "status" => "oolong",
- "expires_in" => expires_in
- })
-
- assert fourth_response = %{"id" => fourth_id} = json_response(conn_four, 200)
- assert activity = Activity.get_by_id(fourth_id)
- assert expiration = ActivityExpiration.get_by_activity_id(fourth_id)
-
- estimated_expires_at =
- NaiveDateTime.utc_now()
- |> NaiveDateTime.add(expires_in)
- |> NaiveDateTime.truncate(:second)
-
- # This assert will fail if the test takes longer than a minute. I sure hope it never does:
- assert abs(NaiveDateTime.diff(expiration.scheduled_at, estimated_expires_at, :second)) < 60
-
- assert fourth_response["pleroma"]["expires_at"] ==
- NaiveDateTime.to_iso8601(expiration.scheduled_at)
- end
-
- test "replying to a status", %{conn: conn} do
- user = insert(:user)
- {:ok, replied_to} = CommonAPI.post(user, %{"status" => "cofe"})
-
- conn =
- conn
- |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => replied_to.id})
-
- assert %{"content" => "xD", "id" => id} = json_response(conn, 200)
-
- activity = Activity.get_by_id(id)
-
- assert activity.data["context"] == replied_to.data["context"]
- assert Activity.get_in_reply_to_activity(activity).id == replied_to.id
- end
-
- test "replying to a direct message with visibility other than direct", %{conn: conn} do
- user = insert(:user)
- {:ok, replied_to} = CommonAPI.post(user, %{"status" => "suya..", "visibility" => "direct"})
-
- Enum.each(["public", "private", "unlisted"], fn visibility ->
- conn =
- conn
- |> post("/api/v1/statuses", %{
- "status" => "@#{user.nickname} hey",
- "in_reply_to_id" => replied_to.id,
- "visibility" => visibility
- })
-
- assert json_response(conn, 422) == %{"error" => "The message visibility must be direct"}
- end)
- end
-
- test "posting a status with an invalid in_reply_to_id", %{conn: conn} do
- conn =
- conn
- |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => ""})
-
- assert %{"content" => "xD", "id" => id} = json_response(conn, 200)
- assert Activity.get_by_id(id)
- end
-
- test "posting a sensitive status", %{conn: conn} do
- conn =
- conn
- |> post("/api/v1/statuses", %{"status" => "cofe", "sensitive" => true})
-
- assert %{"content" => "cofe", "id" => id, "sensitive" => true} = json_response(conn, 200)
- assert Activity.get_by_id(id)
- end
-
- test "posting a fake status", %{conn: conn} do
- real_conn =
- conn
- |> post("/api/v1/statuses", %{
- "status" =>
- "\"Tenshi Eating a Corndog\" is a much discussed concept on /jp/. The significance of it is disputed, so I will focus on one core concept: the symbolism behind it"
- })
-
- real_status = json_response(real_conn, 200)
-
- assert real_status
- assert Object.get_by_ap_id(real_status["uri"])
-
- real_status =
- real_status
- |> Map.put("id", nil)
- |> Map.put("url", nil)
- |> Map.put("uri", nil)
- |> Map.put("created_at", nil)
- |> Kernel.put_in(["pleroma", "conversation_id"], nil)
-
- fake_conn =
- conn
- |> post("/api/v1/statuses", %{
- "status" =>
- "\"Tenshi Eating a Corndog\" is a much discussed concept on /jp/. The significance of it is disputed, so I will focus on one core concept: the symbolism behind it",
- "preview" => true
- })
-
- fake_status = json_response(fake_conn, 200)
-
- assert fake_status
- refute Object.get_by_ap_id(fake_status["uri"])
-
- fake_status =
- fake_status
- |> Map.put("id", nil)
- |> Map.put("url", nil)
- |> Map.put("uri", nil)
- |> Map.put("created_at", nil)
- |> Kernel.put_in(["pleroma", "conversation_id"], nil)
-
- assert real_status == fake_status
- end
-
- test "posting a status with OGP link preview", %{conn: conn} do
- Config.put([:rich_media, :enabled], true)
-
- conn =
- conn
- |> post("/api/v1/statuses", %{
- "status" => "https://example.com/ogp"
- })
-
- assert %{"id" => id, "card" => %{"title" => "The Rock"}} = json_response(conn, 200)
- assert Activity.get_by_id(id)
- end
-
- test "posting a direct status", %{conn: conn} do
- user2 = insert(:user)
- content = "direct cofe @#{user2.nickname}"
-
- conn =
- conn
- |> post("api/v1/statuses", %{"status" => content, "visibility" => "direct"})
-
- assert %{"id" => id} = response = json_response(conn, 200)
- assert response["visibility"] == "direct"
- assert response["pleroma"]["direct_conversation_id"]
- assert activity = Activity.get_by_id(id)
- assert activity.recipients == [user2.ap_id, conn.assigns[:user].ap_id]
- assert activity.data["to"] == [user2.ap_id]
- assert activity.data["cc"] == []
- end
- end
-
- describe "posting polls" do
- test "posting a poll", %{conn: conn} do
- user = insert(:user)
- time = NaiveDateTime.utc_now()
-
- conn =
- conn
- |> assign(:user, user)
- |> post("/api/v1/statuses", %{
- "status" => "Who is the #bestgrill?",
- "poll" => %{"options" => ["Rei", "Asuka", "Misato"], "expires_in" => 420}
- })
-
- response = json_response(conn, 200)
-
- assert Enum.all?(response["poll"]["options"], fn %{"title" => title} ->
- title in ["Rei", "Asuka", "Misato"]
- end)
-
- assert NaiveDateTime.diff(NaiveDateTime.from_iso8601!(response["poll"]["expires_at"]), time) in 420..430
- refute response["poll"]["expred"]
- end
-
- test "option limit is enforced", %{conn: conn} do
- user = insert(:user)
- limit = Config.get([:instance, :poll_limits, :max_options])
-
- conn =
- conn
- |> assign(:user, user)
- |> post("/api/v1/statuses", %{
- "status" => "desu~",
- "poll" => %{"options" => Enum.map(0..limit, fn _ -> "desu" end), "expires_in" => 1}
- })
-
- %{"error" => error} = json_response(conn, 422)
- assert error == "Poll can't contain more than #{limit} options"
- end
-
- test "option character limit is enforced", %{conn: conn} do
- user = insert(:user)
- limit = Config.get([:instance, :poll_limits, :max_option_chars])
-
- conn =
- conn
- |> assign(:user, user)
- |> post("/api/v1/statuses", %{
- "status" => "...",
- "poll" => %{
- "options" => [Enum.reduce(0..limit, "", fn _, acc -> acc <> "." end)],
- "expires_in" => 1
- }
- })
-
- %{"error" => error} = json_response(conn, 422)
- assert error == "Poll options cannot be longer than #{limit} characters each"
- end
-
- test "minimal date limit is enforced", %{conn: conn} do
- user = insert(:user)
- limit = Config.get([:instance, :poll_limits, :min_expiration])
-
- conn =
- conn
- |> assign(:user, user)
- |> post("/api/v1/statuses", %{
- "status" => "imagine arbitrary limits",
- "poll" => %{
- "options" => ["this post was made by pleroma gang"],
- "expires_in" => limit - 1
- }
- })
-
- %{"error" => error} = json_response(conn, 422)
- assert error == "Expiration date is too soon"
- end
-
- test "maximum date limit is enforced", %{conn: conn} do
- user = insert(:user)
- limit = Config.get([:instance, :poll_limits, :max_expiration])
-
- conn =
- conn
- |> assign(:user, user)
- |> post("/api/v1/statuses", %{
- "status" => "imagine arbitrary limits",
- "poll" => %{
- "options" => ["this post was made by pleroma gang"],
- "expires_in" => limit + 1
- }
- })
-
- %{"error" => error} = json_response(conn, 422)
- assert error == "Expiration date is too far in the future"
- end
- end
-
test "Conversations", %{conn: conn} do
user_one = insert(:user)
user_two = insert(:user)
@@ -575,81 +268,6 @@ test "creates an oauth app", %{conn: conn} do
assert expected == json_response(conn, 200)
end
- test "get a status", %{conn: conn} do
- activity = insert(:note_activity)
-
- conn =
- conn
- |> get("/api/v1/statuses/#{activity.id}")
-
- assert %{"id" => id} = json_response(conn, 200)
- assert id == to_string(activity.id)
- end
-
- test "get statuses by IDs", %{conn: conn} do
- %{id: id1} = insert(:note_activity)
- %{id: id2} = insert(:note_activity)
-
- query_string = "ids[]=#{id1}&ids[]=#{id2}"
- conn = get(conn, "/api/v1/statuses/?#{query_string}")
-
- assert [%{"id" => ^id1}, %{"id" => ^id2}] = Enum.sort_by(json_response(conn, :ok), & &1["id"])
- end
-
- describe "deleting a status" do
- test "when you created it", %{conn: conn} do
- activity = insert(:note_activity)
- author = User.get_cached_by_ap_id(activity.data["actor"])
-
- conn =
- conn
- |> assign(:user, author)
- |> delete("/api/v1/statuses/#{activity.id}")
-
- assert %{} = json_response(conn, 200)
-
- refute Activity.get_by_id(activity.id)
- end
-
- test "when you didn't create it", %{conn: conn} do
- activity = insert(:note_activity)
- user = insert(:user)
-
- conn =
- conn
- |> assign(:user, user)
- |> delete("/api/v1/statuses/#{activity.id}")
-
- assert %{"error" => _} = json_response(conn, 403)
-
- assert Activity.get_by_id(activity.id) == activity
- end
-
- test "when you're an admin or moderator", %{conn: conn} do
- activity1 = insert(:note_activity)
- activity2 = insert(:note_activity)
- admin = insert(:user, info: %{is_admin: true})
- moderator = insert(:user, info: %{is_moderator: true})
-
- res_conn =
- conn
- |> assign(:user, admin)
- |> delete("/api/v1/statuses/#{activity1.id}")
-
- assert %{} = json_response(res_conn, 200)
-
- res_conn =
- conn
- |> assign(:user, moderator)
- |> delete("/api/v1/statuses/#{activity2.id}")
-
- assert %{} = json_response(res_conn, 200)
-
- refute Activity.get_by_id(activity1.id)
- refute Activity.get_by_id(activity2.id)
- end
- end
-
describe "filters" do
test "creating a filter", %{conn: conn} do
user = insert(:user)
@@ -778,160 +396,6 @@ test "delete a filter", %{conn: conn} do
end
end
- describe "reblogging" do
- test "reblogs and returns the reblogged status", %{conn: conn} do
- activity = insert(:note_activity)
- user = insert(:user)
-
- conn =
- conn
- |> assign(:user, user)
- |> post("/api/v1/statuses/#{activity.id}/reblog")
-
- assert %{
- "reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1},
- "reblogged" => true
- } = json_response(conn, 200)
-
- assert to_string(activity.id) == id
- end
-
- test "reblogged status for another user", %{conn: conn} do
- activity = insert(:note_activity)
- user1 = insert(:user)
- user2 = insert(:user)
- user3 = insert(:user)
- CommonAPI.favorite(activity.id, user2)
- {:ok, _bookmark} = Pleroma.Bookmark.create(user2.id, activity.id)
- {:ok, reblog_activity1, _object} = CommonAPI.repeat(activity.id, user1)
- {:ok, _, _object} = CommonAPI.repeat(activity.id, user2)
-
- conn_res =
- conn
- |> assign(:user, user3)
- |> get("/api/v1/statuses/#{reblog_activity1.id}")
-
- assert %{
- "reblog" => %{"id" => id, "reblogged" => false, "reblogs_count" => 2},
- "reblogged" => false,
- "favourited" => false,
- "bookmarked" => false
- } = json_response(conn_res, 200)
-
- conn_res =
- conn
- |> assign(:user, user2)
- |> get("/api/v1/statuses/#{reblog_activity1.id}")
-
- assert %{
- "reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 2},
- "reblogged" => true,
- "favourited" => true,
- "bookmarked" => true
- } = json_response(conn_res, 200)
-
- assert to_string(activity.id) == id
- end
-
- test "returns 400 error when activity is not exist", %{conn: conn} do
- user = insert(:user)
-
- conn =
- conn
- |> assign(:user, user)
- |> post("/api/v1/statuses/foo/reblog")
-
- assert json_response(conn, 400) == %{"error" => "Could not repeat"}
- end
- end
-
- describe "unreblogging" do
- test "unreblogs and returns the unreblogged status", %{conn: conn} do
- activity = insert(:note_activity)
- user = insert(:user)
-
- {:ok, _, _} = CommonAPI.repeat(activity.id, user)
-
- conn =
- conn
- |> assign(:user, user)
- |> post("/api/v1/statuses/#{activity.id}/unreblog")
-
- assert %{"id" => id, "reblogged" => false, "reblogs_count" => 0} = json_response(conn, 200)
-
- assert to_string(activity.id) == id
- end
-
- test "returns 400 error when activity is not exist", %{conn: conn} do
- user = insert(:user)
-
- conn =
- conn
- |> assign(:user, user)
- |> post("/api/v1/statuses/foo/unreblog")
-
- assert json_response(conn, 400) == %{"error" => "Could not unrepeat"}
- end
- end
-
- describe "favoriting" do
- test "favs a status and returns it", %{conn: conn} do
- activity = insert(:note_activity)
- user = insert(:user)
-
- conn =
- conn
- |> assign(:user, user)
- |> post("/api/v1/statuses/#{activity.id}/favourite")
-
- assert %{"id" => id, "favourites_count" => 1, "favourited" => true} =
- json_response(conn, 200)
-
- assert to_string(activity.id) == id
- end
-
- test "returns 400 error for a wrong id", %{conn: conn} do
- user = insert(:user)
-
- conn =
- conn
- |> assign(:user, user)
- |> post("/api/v1/statuses/1/favourite")
-
- assert json_response(conn, 400) == %{"error" => "Could not favorite"}
- end
- end
-
- describe "unfavoriting" do
- test "unfavorites a status and returns it", %{conn: conn} do
- activity = insert(:note_activity)
- user = insert(:user)
-
- {:ok, _, _} = CommonAPI.favorite(activity.id, user)
-
- conn =
- conn
- |> assign(:user, user)
- |> post("/api/v1/statuses/#{activity.id}/unfavourite")
-
- assert %{"id" => id, "favourites_count" => 0, "favourited" => false} =
- json_response(conn, 200)
-
- assert to_string(activity.id) == id
- end
-
- test "returns 400 error for a wrong id", %{conn: conn} do
- user = insert(:user)
-
- conn =
- conn
- |> assign(:user, user)
- |> post("/api/v1/statuses/1/unfavourite")
-
- assert json_response(conn, 400) == %{"error" => "Could not unfavorite"}
- end
- end
-
describe "user timelines" do
test "gets a users statuses", %{conn: conn} do
user_one = insert(:user)
@@ -2098,10 +1562,6 @@ test "put settings", %{conn: conn} do
[user: user, activity: activity]
end
- clear_config([:instance, :max_pinned_statuses]) do
- Config.put([:instance, :max_pinned_statuses], 1)
- end
-
test "returns pinned statuses", %{conn: conn, user: user, activity: activity} do
{:ok, _} = CommonAPI.pin(activity.id, user)
@@ -2115,257 +1575,6 @@ test "returns pinned statuses", %{conn: conn, user: user, activity: activity} do
assert [%{"id" => ^id_str, "pinned" => true}] = result
end
-
- test "pin status", %{conn: conn, user: user, activity: activity} do
- id_str = to_string(activity.id)
-
- assert %{"id" => ^id_str, "pinned" => true} =
- conn
- |> assign(:user, user)
- |> post("/api/v1/statuses/#{activity.id}/pin")
- |> json_response(200)
-
- assert [%{"id" => ^id_str, "pinned" => true}] =
- conn
- |> assign(:user, user)
- |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
- |> json_response(200)
- end
-
- test "/pin: returns 400 error when activity is not public", %{conn: conn, user: user} do
- {:ok, dm} = CommonAPI.post(user, %{"status" => "test", "visibility" => "direct"})
-
- conn =
- conn
- |> assign(:user, user)
- |> post("/api/v1/statuses/#{dm.id}/pin")
-
- assert json_response(conn, 400) == %{"error" => "Could not pin"}
- end
-
- test "unpin status", %{conn: conn, user: user, activity: activity} do
- {:ok, _} = CommonAPI.pin(activity.id, user)
-
- id_str = to_string(activity.id)
- user = refresh_record(user)
-
- assert %{"id" => ^id_str, "pinned" => false} =
- conn
- |> assign(:user, user)
- |> post("/api/v1/statuses/#{activity.id}/unpin")
- |> json_response(200)
-
- assert [] =
- conn
- |> assign(:user, user)
- |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
- |> json_response(200)
- end
-
- test "/unpin: returns 400 error when activity is not exist", %{conn: conn, user: user} do
- conn =
- conn
- |> assign(:user, user)
- |> post("/api/v1/statuses/1/unpin")
-
- assert json_response(conn, 400) == %{"error" => "Could not unpin"}
- end
-
- test "max pinned statuses", %{conn: conn, user: user, activity: activity_one} do
- {:ok, activity_two} = CommonAPI.post(user, %{"status" => "HI!!!"})
-
- id_str_one = to_string(activity_one.id)
-
- assert %{"id" => ^id_str_one, "pinned" => true} =
- conn
- |> assign(:user, user)
- |> post("/api/v1/statuses/#{id_str_one}/pin")
- |> json_response(200)
-
- user = refresh_record(user)
-
- assert %{"error" => "You have already pinned the maximum number of statuses"} =
- conn
- |> assign(:user, user)
- |> post("/api/v1/statuses/#{activity_two.id}/pin")
- |> json_response(400)
- end
- end
-
- describe "cards" do
- setup do
- Config.put([:rich_media, :enabled], true)
-
- user = insert(:user)
- %{user: user}
- end
-
- test "returns rich-media card", %{conn: conn, user: user} do
- {:ok, activity} = CommonAPI.post(user, %{"status" => "https://example.com/ogp"})
-
- card_data = %{
- "image" => "http://ia.media-imdb.com/images/rock.jpg",
- "provider_name" => "example.com",
- "provider_url" => "https://example.com",
- "title" => "The Rock",
- "type" => "link",
- "url" => "https://example.com/ogp",
- "description" =>
- "Directed by Michael Bay. With Sean Connery, Nicolas Cage, Ed Harris, John Spencer.",
- "pleroma" => %{
- "opengraph" => %{
- "image" => "http://ia.media-imdb.com/images/rock.jpg",
- "title" => "The Rock",
- "type" => "video.movie",
- "url" => "https://example.com/ogp",
- "description" =>
- "Directed by Michael Bay. With Sean Connery, Nicolas Cage, Ed Harris, John Spencer."
- }
- }
- }
-
- response =
- conn
- |> get("/api/v1/statuses/#{activity.id}/card")
- |> json_response(200)
-
- assert response == card_data
-
- # works with private posts
- {:ok, activity} =
- CommonAPI.post(user, %{"status" => "https://example.com/ogp", "visibility" => "direct"})
-
- response_two =
- conn
- |> assign(:user, user)
- |> get("/api/v1/statuses/#{activity.id}/card")
- |> json_response(200)
-
- assert response_two == card_data
- end
-
- test "replaces missing description with an empty string", %{conn: conn, user: user} do
- {:ok, activity} =
- CommonAPI.post(user, %{"status" => "https://example.com/ogp-missing-data"})
-
- response =
- conn
- |> get("/api/v1/statuses/#{activity.id}/card")
- |> json_response(:ok)
-
- assert response == %{
- "type" => "link",
- "title" => "Pleroma",
- "description" => "",
- "image" => nil,
- "provider_name" => "example.com",
- "provider_url" => "https://example.com",
- "url" => "https://example.com/ogp-missing-data",
- "pleroma" => %{
- "opengraph" => %{
- "title" => "Pleroma",
- "type" => "website",
- "url" => "https://example.com/ogp-missing-data"
- }
- }
- }
- end
- end
-
- test "bookmarks" do
- user = insert(:user)
- for_user = insert(:user)
-
- {:ok, activity1} =
- CommonAPI.post(user, %{
- "status" => "heweoo?"
- })
-
- {:ok, activity2} =
- CommonAPI.post(user, %{
- "status" => "heweoo!"
- })
-
- response1 =
- build_conn()
- |> assign(:user, for_user)
- |> post("/api/v1/statuses/#{activity1.id}/bookmark")
-
- assert json_response(response1, 200)["bookmarked"] == true
-
- response2 =
- build_conn()
- |> assign(:user, for_user)
- |> post("/api/v1/statuses/#{activity2.id}/bookmark")
-
- assert json_response(response2, 200)["bookmarked"] == true
-
- bookmarks =
- build_conn()
- |> assign(:user, for_user)
- |> get("/api/v1/bookmarks")
-
- assert [json_response(response2, 200), json_response(response1, 200)] ==
- json_response(bookmarks, 200)
-
- response1 =
- build_conn()
- |> assign(:user, for_user)
- |> post("/api/v1/statuses/#{activity1.id}/unbookmark")
-
- assert json_response(response1, 200)["bookmarked"] == false
-
- bookmarks =
- build_conn()
- |> assign(:user, for_user)
- |> get("/api/v1/bookmarks")
-
- assert [json_response(response2, 200)] == json_response(bookmarks, 200)
- end
-
- describe "conversation muting" do
- setup do
- post_user = insert(:user)
- user = insert(:user)
-
- {:ok, activity} = CommonAPI.post(post_user, %{"status" => "HIE"})
-
- [user: user, activity: activity]
- end
-
- test "mute conversation", %{conn: conn, user: user, activity: activity} do
- id_str = to_string(activity.id)
-
- assert %{"id" => ^id_str, "muted" => true} =
- conn
- |> assign(:user, user)
- |> post("/api/v1/statuses/#{activity.id}/mute")
- |> json_response(200)
- end
-
- test "cannot mute already muted conversation", %{conn: conn, user: user, activity: activity} do
- {:ok, _} = CommonAPI.add_mute(user, activity)
-
- conn =
- conn
- |> assign(:user, user)
- |> post("/api/v1/statuses/#{activity.id}/mute")
-
- assert json_response(conn, 400) == %{"error" => "conversation is already muted"}
- end
-
- test "unmute conversation", %{conn: conn, user: user, activity: activity} do
- {:ok, _} = CommonAPI.add_mute(user, activity)
-
- id_str = to_string(activity.id)
- user = refresh_record(user)
-
- assert %{"id" => ^id_str, "muted" => false} =
- conn
- |> assign(:user, user)
- |> post("/api/v1/statuses/#{activity.id}/unmute")
- |> json_response(200)
- end
end
describe "reports" do
@@ -2811,51 +2020,6 @@ test "deletes a scheduled activity", %{conn: conn} do
end
end
- test "Repeated posts that are replies incorrectly have in_reply_to_id null", %{conn: conn} do
- user1 = insert(:user)
- user2 = insert(:user)
- user3 = insert(:user)
-
- {:ok, replied_to} = CommonAPI.post(user1, %{"status" => "cofe"})
-
- # Reply to status from another user
- conn1 =
- conn
- |> assign(:user, user2)
- |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => replied_to.id})
-
- assert %{"content" => "xD", "id" => id} = json_response(conn1, 200)
-
- activity = Activity.get_by_id_with_object(id)
-
- assert Object.normalize(activity).data["inReplyTo"] == Object.normalize(replied_to).data["id"]
- assert Activity.get_in_reply_to_activity(activity).id == replied_to.id
-
- # Reblog from the third user
- conn2 =
- conn
- |> assign(:user, user3)
- |> post("/api/v1/statuses/#{activity.id}/reblog")
-
- assert %{"reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1}} =
- json_response(conn2, 200)
-
- assert to_string(activity.id) == id
-
- # Getting third user status
- conn3 =
- conn
- |> assign(:user, user3)
- |> get("api/v1/timelines/home")
-
- [reblogged_activity] = json_response(conn3, 200)
-
- assert reblogged_activity["reblog"]["in_reply_to_id"] == replied_to.id
-
- replied_to_user = User.get_by_ap_id(replied_to.data["actor"])
- assert reblogged_activity["reblog"]["in_reply_to_account_id"] == replied_to_user.id
- end
-
describe "create account by app" do
test "Account registration via Application", %{conn: conn} do
conn =
@@ -3135,197 +2299,6 @@ test "returns 404 when poll is private and not available for user", %{conn: conn
end
end
- describe "GET /api/v1/statuses/:id/favourited_by" do
- setup do
- user = insert(:user)
- {:ok, activity} = CommonAPI.post(user, %{"status" => "test"})
-
- conn =
- build_conn()
- |> assign(:user, user)
-
- [conn: conn, activity: activity, user: user]
- end
-
- test "returns users who have favorited the status", %{conn: conn, activity: activity} do
- other_user = insert(:user)
- {:ok, _, _} = CommonAPI.favorite(activity.id, other_user)
-
- response =
- conn
- |> get("/api/v1/statuses/#{activity.id}/favourited_by")
- |> json_response(:ok)
-
- [%{"id" => id}] = response
-
- assert id == other_user.id
- end
-
- test "returns empty array when status has not been favorited yet", %{
- conn: conn,
- activity: activity
- } do
- response =
- conn
- |> get("/api/v1/statuses/#{activity.id}/favourited_by")
- |> json_response(:ok)
-
- assert Enum.empty?(response)
- end
-
- test "does not return users who have favorited the status but are blocked", %{
- conn: %{assigns: %{user: user}} = conn,
- activity: activity
- } do
- other_user = insert(:user)
- {:ok, user} = User.block(user, other_user)
-
- {:ok, _, _} = CommonAPI.favorite(activity.id, other_user)
-
- response =
- conn
- |> assign(:user, user)
- |> get("/api/v1/statuses/#{activity.id}/favourited_by")
- |> json_response(:ok)
-
- assert Enum.empty?(response)
- end
-
- test "does not fail on an unauthenticated request", %{conn: conn, activity: activity} do
- other_user = insert(:user)
- {:ok, _, _} = CommonAPI.favorite(activity.id, other_user)
-
- response =
- conn
- |> assign(:user, nil)
- |> get("/api/v1/statuses/#{activity.id}/favourited_by")
- |> json_response(:ok)
-
- [%{"id" => id}] = response
- assert id == other_user.id
- end
-
- test "requires authentification for private posts", %{conn: conn, user: user} do
- other_user = insert(:user)
-
- {:ok, activity} =
- CommonAPI.post(user, %{
- "status" => "@#{other_user.nickname} wanna get some #cofe together?",
- "visibility" => "direct"
- })
-
- {:ok, _, _} = CommonAPI.favorite(activity.id, other_user)
-
- conn
- |> assign(:user, nil)
- |> get("/api/v1/statuses/#{activity.id}/favourited_by")
- |> json_response(404)
-
- response =
- build_conn()
- |> assign(:user, other_user)
- |> get("/api/v1/statuses/#{activity.id}/favourited_by")
- |> json_response(200)
-
- [%{"id" => id}] = response
- assert id == other_user.id
- end
- end
-
- describe "GET /api/v1/statuses/:id/reblogged_by" do
- setup do
- user = insert(:user)
- {:ok, activity} = CommonAPI.post(user, %{"status" => "test"})
-
- conn =
- build_conn()
- |> assign(:user, user)
-
- [conn: conn, activity: activity, user: user]
- end
-
- test "returns users who have reblogged the status", %{conn: conn, activity: activity} do
- other_user = insert(:user)
- {:ok, _, _} = CommonAPI.repeat(activity.id, other_user)
-
- response =
- conn
- |> get("/api/v1/statuses/#{activity.id}/reblogged_by")
- |> json_response(:ok)
-
- [%{"id" => id}] = response
-
- assert id == other_user.id
- end
-
- test "returns empty array when status has not been reblogged yet", %{
- conn: conn,
- activity: activity
- } do
- response =
- conn
- |> get("/api/v1/statuses/#{activity.id}/reblogged_by")
- |> json_response(:ok)
-
- assert Enum.empty?(response)
- end
-
- test "does not return users who have reblogged the status but are blocked", %{
- conn: %{assigns: %{user: user}} = conn,
- activity: activity
- } do
- other_user = insert(:user)
- {:ok, user} = User.block(user, other_user)
-
- {:ok, _, _} = CommonAPI.repeat(activity.id, other_user)
-
- response =
- conn
- |> assign(:user, user)
- |> get("/api/v1/statuses/#{activity.id}/reblogged_by")
- |> json_response(:ok)
-
- assert Enum.empty?(response)
- end
-
- test "does not fail on an unauthenticated request", %{conn: conn, activity: activity} do
- other_user = insert(:user)
- {:ok, _, _} = CommonAPI.repeat(activity.id, other_user)
-
- response =
- conn
- |> assign(:user, nil)
- |> get("/api/v1/statuses/#{activity.id}/reblogged_by")
- |> json_response(:ok)
-
- [%{"id" => id}] = response
- assert id == other_user.id
- end
-
- test "requires authentification for private posts", %{conn: conn, user: user} do
- other_user = insert(:user)
-
- {:ok, activity} =
- CommonAPI.post(user, %{
- "status" => "@#{other_user.nickname} wanna get some #cofe together?",
- "visibility" => "direct"
- })
-
- conn
- |> assign(:user, nil)
- |> get("/api/v1/statuses/#{activity.id}/reblogged_by")
- |> json_response(404)
-
- response =
- build_conn()
- |> assign(:user, other_user)
- |> get("/api/v1/statuses/#{activity.id}/reblogged_by")
- |> json_response(200)
-
- assert [] == response
- end
- end
-
describe "POST /auth/password, with valid parameters" do
setup %{conn: conn} do
user = insert(:user)
diff --git a/test/web/mastodon_api/views/notification_view_test.exs b/test/web/mastodon_api/views/notification_view_test.exs
index 9231aaec8..86268fcfa 100644
--- a/test/web/mastodon_api/views/notification_view_test.exs
+++ b/test/web/mastodon_api/views/notification_view_test.exs
@@ -28,7 +28,7 @@ test "Mention notification" do
pleroma: %{is_seen: false},
type: "mention",
account: AccountView.render("account.json", %{user: user, for: mentioned_user}),
- status: StatusView.render("status.json", %{activity: activity, for: mentioned_user}),
+ status: StatusView.render("show.json", %{activity: activity, for: mentioned_user}),
created_at: Utils.to_masto_date(notification.inserted_at)
}
@@ -51,7 +51,7 @@ test "Favourite notification" do
pleroma: %{is_seen: false},
type: "favourite",
account: AccountView.render("account.json", %{user: another_user, for: user}),
- status: StatusView.render("status.json", %{activity: create_activity, for: user}),
+ status: StatusView.render("show.json", %{activity: create_activity, for: user}),
created_at: Utils.to_masto_date(notification.inserted_at)
}
@@ -73,7 +73,7 @@ test "Reblog notification" do
pleroma: %{is_seen: false},
type: "reblog",
account: AccountView.render("account.json", %{user: another_user, for: user}),
- status: StatusView.render("status.json", %{activity: reblog_activity, for: user}),
+ status: StatusView.render("show.json", %{activity: reblog_activity, for: user}),
created_at: Utils.to_masto_date(notification.inserted_at)
}
diff --git a/test/web/mastodon_api/views/status_view_test.exs b/test/web/mastodon_api/views/status_view_test.exs
index 51f8434fa..c17d0ef95 100644
--- a/test/web/mastodon_api/views/status_view_test.exs
+++ b/test/web/mastodon_api/views/status_view_test.exs
@@ -29,7 +29,7 @@ test "returns the direct conversation id when given the `with_conversation_id` o
{:ok, activity} = CommonAPI.post(user, %{"status" => "Hey @shp!", "visibility" => "direct"})
status =
- StatusView.render("status.json",
+ StatusView.render("show.json",
activity: activity,
with_direct_conversation_id: true,
for: user
@@ -46,7 +46,7 @@ test "returns a temporary ap_id based user for activities missing db users" do
Repo.delete(user)
Cachex.clear(:user_cache)
- %{account: ms_user} = StatusView.render("status.json", activity: activity)
+ %{account: ms_user} = StatusView.render("show.json", activity: activity)
assert ms_user.acct == "erroruser@example.com"
end
@@ -63,7 +63,7 @@ test "tries to get a user by nickname if fetching by ap_id doesn't work" do
Cachex.clear(:user_cache)
- result = StatusView.render("status.json", activity: activity)
+ result = StatusView.render("show.json", activity: activity)
assert result[:account][:id] == to_string(user.id)
end
@@ -81,7 +81,7 @@ test "a note with null content" do
User.get_cached_by_ap_id(note.data["actor"])
- status = StatusView.render("status.json", %{activity: note})
+ status = StatusView.render("show.json", %{activity: note})
assert status.content == ""
end
@@ -93,7 +93,7 @@ test "a note activity" do
convo_id = Utils.context_to_conversation_id(object_data["context"])
- status = StatusView.render("status.json", %{activity: note})
+ status = StatusView.render("show.json", %{activity: note})
created_at =
(object_data["published"] || "")
@@ -165,11 +165,11 @@ test "tells if the message is muted for some reason" do
{:ok, user} = User.mute(user, other_user)
{:ok, activity} = CommonAPI.post(other_user, %{"status" => "test"})
- status = StatusView.render("status.json", %{activity: activity})
+ status = StatusView.render("show.json", %{activity: activity})
assert status.muted == false
- status = StatusView.render("status.json", %{activity: activity, for: user})
+ status = StatusView.render("show.json", %{activity: activity, for: user})
assert status.muted == true
end
@@ -181,13 +181,13 @@ test "tells if the message is thread muted" do
{:ok, user} = User.mute(user, other_user)
{:ok, activity} = CommonAPI.post(other_user, %{"status" => "test"})
- status = StatusView.render("status.json", %{activity: activity, for: user})
+ status = StatusView.render("show.json", %{activity: activity, for: user})
assert status.pleroma.thread_muted == false
{:ok, activity} = CommonAPI.add_mute(user, activity)
- status = StatusView.render("status.json", %{activity: activity, for: user})
+ status = StatusView.render("show.json", %{activity: activity, for: user})
assert status.pleroma.thread_muted == true
end
@@ -196,11 +196,11 @@ test "tells if the status is bookmarked" do
user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{"status" => "Cute girls doing cute things"})
- status = StatusView.render("status.json", %{activity: activity})
+ status = StatusView.render("show.json", %{activity: activity})
assert status.bookmarked == false
- status = StatusView.render("status.json", %{activity: activity, for: user})
+ status = StatusView.render("show.json", %{activity: activity, for: user})
assert status.bookmarked == false
@@ -208,7 +208,7 @@ test "tells if the status is bookmarked" do
activity = Activity.get_by_id_with_object(activity.id)
- status = StatusView.render("status.json", %{activity: activity, for: user})
+ status = StatusView.render("show.json", %{activity: activity, for: user})
assert status.bookmarked == true
end
@@ -220,7 +220,7 @@ test "a reply" do
{:ok, activity} =
CommonAPI.post(user, %{"status" => "he", "in_reply_to_status_id" => note.id})
- status = StatusView.render("status.json", %{activity: activity})
+ status = StatusView.render("show.json", %{activity: activity})
assert status.in_reply_to_id == to_string(note.id)
@@ -237,7 +237,7 @@ test "contains mentions" do
{:ok, [activity]} = OStatus.handle_incoming(incoming)
- status = StatusView.render("status.json", %{activity: activity})
+ status = StatusView.render("show.json", %{activity: activity})
assert status.mentions ==
Enum.map([user], fn u -> AccountView.render("mention.json", %{user: u}) end)
@@ -263,7 +263,7 @@ test "create mentions from the 'to' field" do
assert length(activity.recipients) == 3
- %{mentions: [mention] = mentions} = StatusView.render("status.json", %{activity: activity})
+ %{mentions: [mention] = mentions} = StatusView.render("show.json", %{activity: activity})
assert length(mentions) == 1
assert mention.url == recipient_ap_id
@@ -300,7 +300,7 @@ test "create mentions from the 'tag' field" do
assert length(activity.recipients) == 3
- %{mentions: [mention] = mentions} = StatusView.render("status.json", %{activity: activity})
+ %{mentions: [mention] = mentions} = StatusView.render("show.json", %{activity: activity})
assert length(mentions) == 1
assert mention.url == recipient.ap_id
@@ -340,7 +340,7 @@ test "put the url advertised in the Activity in to the url attribute" do
id = "https://wedistribute.org/wp-json/pterotype/v1/object/85810"
[activity] = Activity.search(nil, id)
- status = StatusView.render("status.json", %{activity: activity})
+ status = StatusView.render("show.json", %{activity: activity})
assert status.uri == id
assert status.url == "https://wedistribute.org/2019/07/mastodon-drops-ostatus/"
@@ -352,7 +352,7 @@ test "a reblog" do
{:ok, reblog, _} = CommonAPI.repeat(activity.id, user)
- represented = StatusView.render("status.json", %{for: user, activity: reblog})
+ represented = StatusView.render("show.json", %{for: user, activity: reblog})
assert represented[:id] == to_string(reblog.id)
assert represented[:reblog][:id] == to_string(activity.id)
@@ -369,7 +369,7 @@ test "a peertube video" do
%Activity{} = activity = Activity.get_create_by_object_ap_id(object.data["id"])
- represented = StatusView.render("status.json", %{for: user, activity: activity})
+ represented = StatusView.render("show.json", %{for: user, activity: activity})
assert represented[:id] == to_string(activity.id)
assert length(represented[:media_attachments]) == 1
@@ -570,7 +570,7 @@ test "embeds a relationship in the account" do
"status" => "drink more water"
})
- result = StatusView.render("status.json", %{activity: activity, for: other_user})
+ result = StatusView.render("show.json", %{activity: activity, for: other_user})
assert result[:account][:pleroma][:relationship] ==
AccountView.render("relationship.json", %{user: other_user, target: user})
@@ -587,7 +587,7 @@ test "embeds a relationship in the account in reposts" do
{:ok, activity, _object} = CommonAPI.repeat(activity.id, other_user)
- result = StatusView.render("status.json", %{activity: activity, for: user})
+ result = StatusView.render("show.json", %{activity: activity, for: user})
assert result[:account][:pleroma][:relationship] ==
AccountView.render("relationship.json", %{user: user, target: other_user})
@@ -604,7 +604,7 @@ test "visibility/list" do
{:ok, activity} =
CommonAPI.post(user, %{"status" => "foobar", "visibility" => "list:#{list.id}"})
- status = StatusView.render("status.json", activity: activity)
+ status = StatusView.render("show.json", activity: activity)
assert status.visibility == "list"
end