X-Git-Url: http://git.squeep.com/?a=blobdiff_plain;f=lib%2Fpleroma%2Fweb%2Fmastodon_api%2Fcontrollers%2Fmastodon_api_controller.ex;h=5904b1f666add96083f6be189ed753707c6f9c22;hb=68bf99baf21b4728faab6641ed8dbdafa79d5fb6;hp=28d0e58f38f5a814ec1d6acac4360b4a487d3337;hpb=eed774d058bfac2d36fd79faa915394a97baa6db;p=akkoma 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 28d0e58f3..5904b1f66 100644 --- a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex @@ -6,7 +6,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do use Pleroma.Web, :controller import Pleroma.Web.ControllerHelper, - only: [json_response: 3, add_link_headers: 2, add_link_headers: 3] + only: [json_response: 3, add_link_headers: 2, truthy_param?: 1] alias Ecto.Changeset alias Pleroma.Activity @@ -14,13 +14,11 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do alias Pleroma.Config alias Pleroma.Conversation.Participation alias Pleroma.Emoji - alias Pleroma.Filter alias Pleroma.HTTP alias Pleroma.Object alias Pleroma.Pagination alias Pleroma.Plugs.RateLimiter alias Pleroma.Repo - alias Pleroma.ScheduledActivity alias Pleroma.Stats alias Pleroma.User alias Pleroma.Web @@ -30,12 +28,10 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do alias Pleroma.Web.MastodonAPI.AccountView alias Pleroma.Web.MastodonAPI.AppView alias Pleroma.Web.MastodonAPI.ConversationView - alias Pleroma.Web.MastodonAPI.FilterView alias Pleroma.Web.MastodonAPI.ListView alias Pleroma.Web.MastodonAPI.MastodonAPI alias Pleroma.Web.MastodonAPI.MastodonView alias Pleroma.Web.MastodonAPI.ReportView - alias Pleroma.Web.MastodonAPI.ScheduledActivityView alias Pleroma.Web.MastodonAPI.StatusView alias Pleroma.Web.MediaProxy alias Pleroma.Web.OAuth.App @@ -44,7 +40,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do alias Pleroma.Web.OAuth.Token alias Pleroma.Web.TwitterAPI.TwitterAPI - alias Pleroma.Web.ControllerHelper import Ecto.Query require Logger @@ -52,28 +47,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) @@ -156,7 +135,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do ] |> Enum.reduce(%{}, fn key, acc -> add_if_present(acc, params, to_string(key), key, fn value -> - {:ok, ControllerHelper.truthy_param?(value)} + {:ok, truthy_param?(value)} end) end) |> add_if_present(params, "default_scope", :default_scope) @@ -344,43 +323,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do json(conn, mastodon_emoji) end - def home_timeline(%{assigns: %{user: user}} = conn, params) do - params = - params - |> Map.put("type", ["Create", "Announce"]) - |> Map.put("blocking_user", user) - |> Map.put("muting_user", user) - |> Map.put("user", user) - - activities = - [user.ap_id | user.following] - |> ActivityPub.fetch_activities(params) - |> Enum.reverse() - - conn - |> add_link_headers(activities) - |> put_view(StatusView) - |> render("index.json", %{activities: activities, for: user, as: :activity}) - end - - def public_timeline(%{assigns: %{user: user}} = conn, params) do - local_only = params["local"] in [true, "True", "true", "1"] - - activities = - params - |> Map.put("type", ["Create", "Announce"]) - |> Map.put("local_only", local_only) - |> Map.put("blocking_user", user) - |> Map.put("muting_user", user) - |> ActivityPub.fetch_public_activities() - |> Enum.reverse() - - conn - |> add_link_headers(activities, %{"local" => local_only}) - |> put_view(StatusView) - |> render("index.json", %{activities: activities, for: user, as: :activity}) - end - def user_statuses(%{assigns: %{user: reading_user}} = conn, params) do with %User{} = user <- User.get_cached_by_nickname_or_id(params["id"], for: reading_user) do params = @@ -400,82 +342,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end end - def dm_timeline(%{assigns: %{user: user}} = conn, params) do - params = - params - |> Map.put("type", "Create") - |> Map.put("blocking_user", user) - |> Map.put("user", user) - |> Map.put(:visibility, "direct") - - activities = - [user.ap_id] - |> ActivityPub.fetch_activities_query(params) - |> Pagination.fetch_paginated(params) - - conn - |> add_link_headers(activities) - |> put_view(StatusView) - |> render("index.json", %{activities: activities, for: user, as: :activity}) - 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"]), @@ -526,192 +392,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end end - def scheduled_statuses(%{assigns: %{user: user}} = conn, params) do - with scheduled_activities <- MastodonAPI.get_scheduled_activities(user, params) do - conn - |> add_link_headers(scheduled_activities) - |> put_view(ScheduledActivityView) - |> render("index.json", %{scheduled_activities: scheduled_activities}) - end - end - - def show_scheduled_status(%{assigns: %{user: user}} = conn, %{"id" => scheduled_activity_id}) do - with %ScheduledActivity{} = scheduled_activity <- - ScheduledActivity.get(user, scheduled_activity_id) do - conn - |> put_view(ScheduledActivityView) - |> render("show.json", %{scheduled_activity: scheduled_activity}) - else - _ -> {:error, :not_found} - end - end - - def update_scheduled_status( - %{assigns: %{user: user}} = conn, - %{"id" => scheduled_activity_id} = params - ) do - with %ScheduledActivity{} = scheduled_activity <- - ScheduledActivity.get(user, scheduled_activity_id), - {:ok, scheduled_activity} <- ScheduledActivity.update(scheduled_activity, params) do - conn - |> put_view(ScheduledActivityView) - |> render("show.json", %{scheduled_activity: scheduled_activity}) - else - nil -> {:error, :not_found} - error -> error - end - end - - def delete_scheduled_status(%{assigns: %{user: user}} = conn, %{"id" => scheduled_activity_id}) do - with %ScheduledActivity{} = scheduled_activity <- - ScheduledActivity.get(user, scheduled_activity_id), - {:ok, scheduled_activity} <- ScheduledActivity.delete(scheduled_activity) do - conn - |> put_view(ScheduledActivityView) - |> render("show.json", %{scheduled_activity: scheduled_activity}) - else - nil -> {:error, :not_found} - error -> error - 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) @@ -783,83 +463,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController 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 hashtag_timeline(%{assigns: %{user: user}} = conn, params) do - local_only = params["local"] in [true, "True", "true", "1"] - - tags = - [params["tag"], params["any"]] - |> List.flatten() - |> Enum.uniq() - |> Enum.filter(& &1) - |> Enum.map(&String.downcase(&1)) - - tag_all = - params["all"] || - [] - |> Enum.map(&String.downcase(&1)) - - tag_reject = - params["none"] || - [] - |> Enum.map(&String.downcase(&1)) - - activities = - params - |> Map.put("type", "Create") - |> Map.put("local_only", local_only) - |> Map.put("blocking_user", user) - |> Map.put("muting_user", user) - |> Map.put("user", user) - |> Map.put("tag", tags) - |> Map.put("tag_all", tag_all) - |> Map.put("tag_reject", tag_reject) - |> ActivityPub.fetch_public_activities() - |> Enum.reverse() - - conn - |> add_link_headers(activities, %{"local" => local_only}) - |> put_view(StatusView) - |> render("index.json", %{activities: activities, for: user, as: :activity}) - 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 @@ -1059,20 +662,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end end - def domain_blocks(%{assigns: %{user: %{info: info}}} = conn, _) do - json(conn, info.domain_blocks || []) - end - - def block_domain(%{assigns: %{user: blocker}} = conn, %{"domain" => domain}) do - User.block_domain(blocker, domain) - json(conn, %{}) - end - - def unblock_domain(%{assigns: %{user: blocker}} = conn, %{"domain" => domain}) do - User.unblock_domain(blocker, domain) - json(conn, %{}) - end - def subscribe(%{assigns: %{user: user}} = conn, %{"id" => id}) do with %User{} = subscription_target <- User.get_cached_by_id(id), {:ok, subscription_target} = User.subscribe(user, subscription_target) do @@ -1172,31 +761,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do json(conn, res) end - def list_timeline(%{assigns: %{user: user}} = conn, %{"list_id" => id} = params) do - with %Pleroma.List{title: _title, following: following} <- Pleroma.List.get(id, user) do - params = - params - |> Map.put("type", "Create") - |> Map.put("blocking_user", user) - |> Map.put("user", user) - |> Map.put("muting_user", user) - - # we must filter the following list for the user to avoid leaking statuses the user - # does not actually have permission to see (for more info, peruse security issue #270). - activities = - following - |> Enum.filter(fn x -> x in user.following end) - |> ActivityPub.fetch_activities_bounded(following, params) - |> Enum.reverse() - - conn - |> put_view(StatusView) - |> render("index.json", %{activities: activities, for: user, as: :activity}) - else - _e -> render_error(conn, :forbidden, "Error.") - end - end - def index(%{assigns: %{user: user}} = conn, _params) do token = get_session(conn, :oauth_token) @@ -1409,65 +973,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do json(conn, %{}) end - def get_filters(%{assigns: %{user: user}} = conn, _) do - filters = Filter.get_filters(user) - res = FilterView.render("filters.json", filters: filters) - json(conn, res) - end - - def create_filter( - %{assigns: %{user: user}} = conn, - %{"phrase" => phrase, "context" => context} = params - ) do - query = %Filter{ - user_id: user.id, - phrase: phrase, - context: context, - hide: Map.get(params, "irreversible", false), - whole_word: Map.get(params, "boolean", true) - # expires_at - } - - {:ok, response} = Filter.create(query) - res = FilterView.render("filter.json", filter: response) - json(conn, res) - end - - def get_filter(%{assigns: %{user: user}} = conn, %{"id" => filter_id}) do - filter = Filter.get(filter_id, user) - res = FilterView.render("filter.json", filter: filter) - json(conn, res) - end - - def update_filter( - %{assigns: %{user: user}} = conn, - %{"phrase" => phrase, "context" => context, "id" => filter_id} = params - ) do - query = %Filter{ - user_id: user.id, - filter_id: filter_id, - phrase: phrase, - context: context, - hide: Map.get(params, "irreversible", nil), - whole_word: Map.get(params, "boolean", true) - # expires_at - } - - {:ok, response} = Filter.update(query) - res = FilterView.render("filter.json", filter: response) - json(conn, res) - end - - def delete_filter(%{assigns: %{user: user}} = conn, %{"id" => filter_id}) do - query = %Filter{ - user_id: user.id, - filter_id: filter_id - } - - {:ok, _} = Filter.delete(query) - json(conn, %{}) - end - def suggestions(%{assigns: %{user: user}} = conn, _) do suggestions = Config.get(:suggestions) @@ -1515,22 +1020,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController 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} ->