X-Git-Url: http://git.squeep.com/?a=blobdiff_plain;f=lib%2Fpleroma%2Fweb%2Fmastodon_api%2Fmastodon_api_controller.ex;h=c3c75bd9a5a6b6f654426c0785f8edf17fe52dd0;hb=47c20ab79635257f4a8dcd9886821d10276516a3;hp=891f9d81463932d97be4804cd61aab93a294082e;hpb=eac298083f809d2cf629640b02fc0ae33dc7b9d2;p=akkoma diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 891f9d814..c3c75bd9a 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -4,6 +4,9 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do use Pleroma.Web, :controller + + import Pleroma.Web.ControllerHelper, only: [json_response: 3] + alias Ecto.Changeset alias Pleroma.Activity alias Pleroma.Bookmark @@ -15,6 +18,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do alias Pleroma.Notification alias Pleroma.Object alias Pleroma.Pagination + alias Pleroma.Plugs.RateLimiter alias Pleroma.Repo alias Pleroma.ScheduledActivity alias Pleroma.Stats @@ -45,9 +49,36 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do import Ecto.Query require Logger + require Pleroma.Constants + + @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(Pleroma.Plugs.RateLimiter, :app_account_creation when action == :account_register) - plug(Pleroma.Plugs.RateLimiter, :search when action in [:search, :search2, :account_search]) + 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) + plug(RateLimiter, :account_confirmation_resend when action == :account_confirmation_resend) @local_mastodon_name "Mastodon-Local" @@ -160,16 +191,83 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do AccountView.render("account.json", %{user: user, for: user, with_pleroma_settings: true}) ) else - _e -> - conn - |> put_status(403) - |> json(%{error: "Invalid request"}) + _e -> render_error(conn, :forbidden, "Invalid request") + end + end + + def update_avatar(%{assigns: %{user: user}} = conn, %{"img" => ""}) do + change = Changeset.change(user, %{avatar: nil}) + {:ok, user} = User.update_and_set_cache(change) + CommonAPI.update(user) + + json(conn, %{url: nil}) + end + + def update_avatar(%{assigns: %{user: user}} = conn, params) do + {:ok, object} = ActivityPub.upload(params, type: :avatar) + change = Changeset.change(user, %{avatar: object.data}) + {:ok, user} = User.update_and_set_cache(change) + CommonAPI.update(user) + %{"url" => [%{"href" => href} | _]} = object.data + + json(conn, %{url: href}) + end + + def update_banner(%{assigns: %{user: user}} = conn, %{"banner" => ""}) do + with new_info <- %{"banner" => %{}}, + info_cng <- User.Info.profile_update(user.info, new_info), + changeset <- Ecto.Changeset.change(user) |> Ecto.Changeset.put_embed(:info, info_cng), + {:ok, user} <- User.update_and_set_cache(changeset) do + CommonAPI.update(user) + + json(conn, %{url: nil}) + end + end + + def update_banner(%{assigns: %{user: user}} = conn, params) do + with {:ok, object} <- ActivityPub.upload(%{"img" => params["banner"]}, type: :banner), + new_info <- %{"banner" => object.data}, + info_cng <- User.Info.profile_update(user.info, new_info), + changeset <- Ecto.Changeset.change(user) |> Ecto.Changeset.put_embed(:info, info_cng), + {:ok, user} <- User.update_and_set_cache(changeset) do + CommonAPI.update(user) + %{"url" => [%{"href" => href} | _]} = object.data + + json(conn, %{url: href}) + end + end + + def update_background(%{assigns: %{user: user}} = conn, %{"img" => ""}) do + with new_info <- %{"background" => %{}}, + info_cng <- User.Info.profile_update(user.info, new_info), + changeset <- Ecto.Changeset.change(user) |> Ecto.Changeset.put_embed(:info, info_cng), + {:ok, _user} <- User.update_and_set_cache(changeset) do + json(conn, %{url: nil}) + end + end + + def update_background(%{assigns: %{user: user}} = conn, params) do + with {:ok, object} <- ActivityPub.upload(params, type: :background), + new_info <- %{"background" => object.data}, + info_cng <- User.Info.profile_update(user.info, new_info), + changeset <- Ecto.Changeset.change(user) |> Ecto.Changeset.put_embed(:info, info_cng), + {:ok, _user} <- User.update_and_set_cache(changeset) do + %{"url" => [%{"href" => href} | _]} = object.data + + json(conn, %{url: href}) end end def verify_credentials(%{assigns: %{user: user}} = conn, _) do + chat_token = Phoenix.Token.sign(conn, "user socket", user.id) + account = - AccountView.render("account.json", %{user: user, for: user, with_pleroma_settings: true}) + AccountView.render("account.json", %{ + user: user, + for: user, + with_pleroma_settings: true, + with_chat_token: chat_token + }) json(conn, account) end @@ -188,10 +286,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do account = AccountView.render("account.json", %{user: user, for: for_user}) json(conn, account) else - _e -> - conn - |> put_status(404) - |> json(%{error: "Can't find user"}) + _e -> render_error(conn, :not_found, "Can't find user") end end @@ -235,7 +330,9 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do "static_url" => url, "visible_in_picker" => true, "url" => url, - "tags" => tags + "tags" => tags, + # Assuming that a comma is authorized in the category name + "category" => (tags -- ["Custom"]) |> Enum.join(",") } end) end @@ -338,6 +435,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do |> Map.put("local_only", local_only) |> Map.put("blocking_user", user) |> Map.put("muting_user", user) + |> Map.put("user", user) |> ActivityPub.fetch_public_activities() |> Enum.reverse() @@ -348,7 +446,11 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end def user_statuses(%{assigns: %{user: reading_user}} = conn, params) do - with %User{} = user <- User.get_cached_by_id(params["id"]) do + with %User{} = user <- User.get_cached_by_nickname_or_id(params["id"]) do + params = + params + |> Map.put("tag", params["tagged"]) + activities = ActivityPub.fetch_user_activities(user, reading_user, params) conn @@ -435,41 +537,44 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do |> put_view(StatusView) |> try_render("poll.json", %{object: object, for: user}) else - nil -> - conn - |> put_status(404) - |> json(%{error: "Record not found"}) - - false -> - conn - |> put_status(404) - |> json(%{error: "Record not found"}) + error when is_nil(error) or error == false -> + render_error(conn, :not_found, "Record not found") end end + defp get_cached_vote_or_vote(user, object, choices) do + idempotency_key = "polls:#{user.id}:#{object.data["id"]}" + + {_, res} = + Cachex.fetch(:idempotency_cache, idempotency_key, fn _ -> + case CommonAPI.vote(user, object, choices) do + {:error, _message} = res -> {:ignore, res} + res -> {:commit, res} + end + end) + + res + end + def poll_vote(%{assigns: %{user: user}} = conn, %{"id" => id, "choices" => choices}) do with %Object{} = object <- Object.get_by_id(id), true <- object.data["type"] == "Question", %Activity{} = activity <- Activity.get_create_by_object_ap_id(object.data["id"]), true <- Visibility.visible_for_user?(activity, user), - {:ok, _activities, object} <- CommonAPI.vote(user, object, choices) do + {:ok, _activities, object} <- get_cached_vote_or_vote(user, object, choices) do conn |> put_view(StatusView) |> try_render("poll.json", %{object: object, for: user}) else nil -> - conn - |> put_status(404) - |> json(%{error: "Record not found"}) + render_error(conn, :not_found, "Record not found") false -> - conn - |> put_status(404) - |> json(%{error: "Record not found"}) + render_error(conn, :not_found, "Record not found") {:error, message} -> conn - |> put_status(422) + |> put_status(:unprocessable_entity) |> json(%{error: message}) end end @@ -523,15 +628,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end end - def post_status(conn, %{"status" => "", "media_ids" => media_ids} = params) - when length(media_ids) > 0 do - params = - params - |> Map.put("status", ".") - - post_status(conn, params) - end - def post_status(%{assigns: %{user: user}} = conn, %{"status" => _} = params) do params = params @@ -549,18 +645,13 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do else params = Map.drop(params, ["scheduled_at"]) - case get_cached_status_or_post(conn, params) do - {:ignore, message} -> - conn - |> put_status(422) - |> json(%{error: message}) - + case CommonAPI.post(user, params) do {:error, message} -> conn - |> put_status(422) + |> put_status(:unprocessable_entity) |> json(%{error: message}) - {_, activity} -> + {:ok, activity} -> conn |> put_view(StatusView) |> try_render("status.json", %{activity: activity, for: user, as: :activity}) @@ -568,29 +659,11 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end end - defp get_cached_status_or_post(%{assigns: %{user: user}} = conn, params) do - idempotency_key = - case get_req_header(conn, "idempotency-key") do - [key] -> key - _ -> Ecto.UUID.generate() - end - - Cachex.fetch(:idempotency_cache, idempotency_key, fn _ -> - case CommonAPI.post(user, params) do - {:ok, activity} -> activity - {:error, message} -> {:ignore, message} - end - end) - end - def delete_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do with {:ok, %Activity{}} <- CommonAPI.delete(id, user) do json(conn, %{}) else - _e -> - conn - |> put_status(403) - |> json(%{error: "Can't delete this post"}) + _e -> render_error(conn, :forbidden, "Can't delete this post") end end @@ -635,11 +708,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do conn |> put_view(StatusView) |> try_render("status.json", %{activity: activity, for: user, as: :activity}) - else - {:error, reason} -> - conn - |> put_resp_content_type("application/json") - |> send_resp(:bad_request, Jason.encode!(%{"error" => reason})) end end @@ -680,11 +748,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do conn |> put_view(StatusView) |> try_render("status.json", %{activity: activity, for: user, as: :activity}) - else - {:error, reason} -> - conn - |> put_resp_content_type("application/json") - |> send_resp(:bad_request, Jason.encode!(%{"error" => reason})) end end @@ -715,8 +778,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do else {:error, reason} -> conn - |> put_resp_content_type("application/json") - |> send_resp(403, Jason.encode!(%{"error" => reason})) + |> put_status(:forbidden) + |> json(%{"error" => reason}) end end @@ -731,8 +794,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do else {:error, reason} -> conn - |> put_resp_content_type("application/json") - |> send_resp(403, Jason.encode!(%{"error" => reason})) + |> put_status(:forbidden) + |> json(%{"error" => reason}) end end @@ -810,9 +873,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do conn |> json(rendered) else - conn - |> put_resp_content_type("application/json") - |> send_resp(415, Jason.encode!(%{"error" => "mascots can only be images"})) + render_error(conn, :unsupported_media_type, "mascots can only be images") end end end @@ -825,24 +886,30 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end def favourited_by(%{assigns: %{user: user}} = conn, %{"id" => id}) do - with %Activity{data: %{"object" => object}} <- Repo.get(Activity, id), - %Object{data: %{"likes" => likes}} <- Object.normalize(object) do + with %Activity{} = activity <- Activity.get_by_id_with_object(id), + %Object{data: %{"likes" => likes}} <- Object.normalize(activity) do q = from(u in User, where: u.ap_id in ^likes) - users = Repo.all(q) + + users = + Repo.all(q) + |> Enum.filter(&(not User.blocks?(user, &1))) conn |> put_view(AccountView) - |> render(AccountView, "accounts.json", %{for: user, users: users, as: :user}) + |> render("accounts.json", %{for: user, users: users, as: :user}) else _ -> json(conn, []) end end def reblogged_by(%{assigns: %{user: user}} = conn, %{"id" => id}) do - with %Activity{data: %{"object" => object}} <- Repo.get(Activity, id), - %Object{data: %{"announcements" => announces}} <- Object.normalize(object) do + with %Activity{} = activity <- Activity.get_by_id_with_object(id), + %Object{data: %{"announcements" => announces}} <- Object.normalize(activity) do q = from(u in User, where: u.ap_id in ^announces) - users = Repo.all(q) + + users = + Repo.all(q) + |> Enum.filter(&(not User.blocks?(user, &1))) conn |> put_view(AccountView) @@ -878,6 +945,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do |> 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) @@ -941,8 +1009,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do else {:error, message} -> conn - |> put_resp_content_type("application/json") - |> send_resp(403, Jason.encode!(%{"error" => message})) + |> put_status(:forbidden) + |> json(%{error: message}) end end @@ -955,8 +1023,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do else {:error, message} -> conn - |> put_resp_content_type("application/json") - |> send_resp(403, Jason.encode!(%{"error" => message})) + |> put_status(:forbidden) + |> json(%{error: message}) end end @@ -973,8 +1041,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do {:error, message} -> conn - |> put_resp_content_type("application/json") - |> send_resp(403, Jason.encode!(%{"error" => message})) + |> put_status(:forbidden) + |> json(%{error: message}) end end @@ -991,8 +1059,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do {:error, message} -> conn - |> put_resp_content_type("application/json") - |> send_resp(403, Jason.encode!(%{"error" => message})) + |> put_status(:forbidden) + |> json(%{error: message}) end end @@ -1012,17 +1080,22 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end end - def mute(%{assigns: %{user: muter}} = conn, %{"id" => id}) do + def mute(%{assigns: %{user: muter}} = conn, %{"id" => id} = params) do + notifications = + if Map.has_key?(params, "notifications"), + do: params["notifications"] in [true, "True", "true", "1"], + else: true + with %User{} = muted <- User.get_cached_by_id(id), - {:ok, muter} <- User.mute(muter, muted) do + {:ok, muter} <- User.mute(muter, muted, notifications) do conn |> put_view(AccountView) |> render("relationship.json", %{user: muter, target: muted}) else {:error, message} -> conn - |> put_resp_content_type("application/json") - |> send_resp(403, Jason.encode!(%{"error" => message})) + |> put_status(:forbidden) + |> json(%{error: message}) end end @@ -1035,8 +1108,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do else {:error, message} -> conn - |> put_resp_content_type("application/json") - |> send_resp(403, Jason.encode!(%{"error" => message})) + |> put_status(:forbidden) + |> json(%{error: message}) end end @@ -1057,8 +1130,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do else {:error, message} -> conn - |> put_resp_content_type("application/json") - |> send_resp(403, Jason.encode!(%{"error" => message})) + |> put_status(:forbidden) + |> json(%{error: message}) end end @@ -1072,8 +1145,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do else {:error, message} -> conn - |> put_resp_content_type("application/json") - |> send_resp(403, Jason.encode!(%{"error" => message})) + |> put_status(:forbidden) + |> json(%{error: message}) end end @@ -1107,8 +1180,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do else {:error, message} -> conn - |> put_resp_content_type("application/json") - |> send_resp(403, Jason.encode!(%{"error" => message})) + |> put_status(:forbidden) + |> json(%{error: message}) end end @@ -1121,63 +1194,11 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do else {:error, message} -> conn - |> put_resp_content_type("application/json") - |> send_resp(403, Jason.encode!(%{"error" => message})) + |> put_status(:forbidden) + |> json(%{error: message}) end end - def search2(%{assigns: %{user: user}} = conn, %{"q" => query} = params) do - accounts = User.search(query, resolve: params["resolve"] == "true", for_user: user) - statuses = Activity.search(user, query) - tags_path = Web.base_url() <> "/tag/" - - tags = - query - |> String.split() - |> Enum.uniq() - |> Enum.filter(fn tag -> String.starts_with?(tag, "#") end) - |> Enum.map(fn tag -> String.slice(tag, 1..-1) end) - |> Enum.map(fn tag -> %{name: tag, url: tags_path <> tag} end) - - res = %{ - "accounts" => AccountView.render("accounts.json", users: accounts, for: user, as: :user), - "statuses" => - StatusView.render("index.json", activities: statuses, for: user, as: :activity), - "hashtags" => tags - } - - json(conn, res) - end - - def search(%{assigns: %{user: user}} = conn, %{"q" => query} = params) do - accounts = User.search(query, resolve: params["resolve"] == "true", for_user: user) - statuses = Activity.search(user, query) - - tags = - query - |> String.split() - |> Enum.uniq() - |> Enum.filter(fn tag -> String.starts_with?(tag, "#") end) - |> Enum.map(fn tag -> String.slice(tag, 1..-1) end) - - res = %{ - "accounts" => AccountView.render("accounts.json", users: accounts, for: user, as: :user), - "statuses" => - StatusView.render("index.json", activities: statuses, for: user, as: :activity), - "hashtags" => tags - } - - json(conn, res) - end - - def account_search(%{assigns: %{user: user}} = conn, %{"q" => query} = params) do - accounts = User.search(query, resolve: params["resolve"] == "true", for_user: user) - - res = AccountView.render("accounts.json", users: accounts, for: user, as: :user) - - json(conn, res) - end - def favourites(%{assigns: %{user: user}} = conn, params) do params = params @@ -1206,10 +1227,9 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do recipients = if for_user do - ["https://www.w3.org/ns/activitystreams#Public"] ++ - [for_user.ap_id | for_user.following] + [Pleroma.Constants.as_public()] ++ [for_user.ap_id | for_user.following] else - ["https://www.w3.org/ns/activitystreams#Public"] + [Pleroma.Constants.as_public()] end activities = @@ -1222,13 +1242,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do |> put_view(StatusView) |> render("index.json", %{activities: activities, for: for_user, as: :activity}) else - nil -> - {:error, :not_found} - - true -> - conn - |> put_status(403) - |> json(%{error: "Can't get favorites"}) + nil -> {:error, :not_found} + true -> render_error(conn, :forbidden, "Can't get favorites") end end @@ -1260,10 +1275,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do res = ListView.render("list.json", list: list) json(conn, res) else - _e -> - conn - |> put_status(404) - |> json(%{error: "Record not found"}) + _e -> render_error(conn, :not_found, "Record not found") end end @@ -1279,7 +1291,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do json(conn, %{}) else _e -> - json(conn, "error") + json(conn, dgettext("errors", "error")) end end @@ -1330,7 +1342,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do json(conn, res) else _e -> - json(conn, "error") + json(conn, dgettext("errors", "error")) end end @@ -1340,6 +1352,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do 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 @@ -1354,10 +1367,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do |> put_view(StatusView) |> render("index.json", %{activities: activities, for: user, as: :activity}) else - _e -> - conn - |> put_status(403) - |> json(%{error: "Error."}) + _e -> render_error(conn, :forbidden, "Error.") end end @@ -1476,8 +1486,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do else e -> conn - |> put_resp_content_type("application/json") - |> send_resp(500, Jason.encode!(%{"error" => inspect(e)})) + |> put_status(:internal_server_error) + |> json(%{error: inspect(e)}) end end @@ -1645,20 +1655,24 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do |> Enum.map_join(", ", fn {_k, v} -> v end) conn - |> put_status(422) + |> put_status(:unprocessable_entity) |> json(%{error: error_message}) end def errors(conn, {:error, :not_found}) do + render_error(conn, :not_found, "Record not found") + end + + def errors(conn, {:error, error_message}) do conn - |> put_status(404) - |> json(%{error: "Record not found"}) + |> put_status(:bad_request) + |> json(%{error: error_message}) end def errors(conn, _) do conn - |> put_status(500) - |> json("Something went wrong") + |> put_status(:internal_server_error) + |> json(dgettext("errors", "Something went wrong")) end def suggestions(%{assigns: %{user: user}} = conn, _) do @@ -1679,45 +1693,35 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do |> String.replace("{{user}}", user) with {:ok, %{status: 200, body: body}} <- - HTTP.get( - url, - [], - adapter: [ - recv_timeout: timeout, - pool: :default - ] - ), + HTTP.get(url, [], adapter: [recv_timeout: timeout, pool: :default]), {:ok, data} <- Jason.decode(body) do data = data |> Enum.slice(0, limit) |> Enum.map(fn x -> - Map.put( - x, - "id", - case User.get_or_fetch(x["acct"]) do - {:ok, %User{id: id}} -> id - _ -> 0 - end - ) - end) - |> Enum.map(fn x -> - Map.put(x, "avatar", MediaProxy.url(x["avatar"])) - end) - |> Enum.map(fn x -> - Map.put(x, "avatar_static", MediaProxy.url(x["avatar_static"])) + x + |> Map.put("id", fetch_suggestion_id(x)) + |> Map.put("avatar", MediaProxy.url(x["avatar"])) + |> Map.put("avatar_static", MediaProxy.url(x["avatar_static"])) end) - conn - |> json(data) + json(conn, data) else - e -> Logger.error("Could not retrieve suggestions at fetch #{url}, #{inspect(e)}") + e -> + Logger.error("Could not retrieve suggestions at fetch #{url}, #{inspect(e)}") end else json(conn, []) end end + defp fetch_suggestion_id(attrs) do + case User.get_or_fetch(attrs["acct"]) do + {:ok, %User{id: id}} -> id + _ -> 0 + 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 @@ -1778,21 +1782,17 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do else {:error, errors} -> conn - |> put_status(400) - |> json(Jason.encode!(errors)) + |> put_status(:bad_request) + |> json(errors) end end def account_register(%{assigns: %{app: _app}} = conn, _params) do - conn - |> put_status(400) - |> json(%{error: "Missing parameters"}) + render_error(conn, :bad_request, "Missing parameters") end def account_register(conn, _) do - conn - |> put_status(403) - |> json(%{error: "Invalid credentials"}) + render_error(conn, :forbidden, "Invalid credentials") end def conversations(%{assigns: %{user: user}} = conn, params) do @@ -1820,23 +1820,42 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end end - def try_render(conn, target, params) - when is_binary(target) do - res = render(conn, target, params) + def password_reset(conn, params) do + nickname_or_email = params["email"] || params["nickname"] - if res == nil do + with {:ok, _} <- TwitterAPI.password_reset(nickname_or_email) do conn - |> put_status(501) - |> json(%{error: "Can't display this activity"}) + |> put_status(:no_content) + |> json("") else - res + {:error, "unknown user"} -> + send_resp(conn, :not_found, "") + + {:error, _} -> + send_resp(conn, :bad_request, "") + end + end + + def account_confirmation_resend(conn, params) do + nickname_or_email = params["email"] || params["nickname"] + + with %User{} = user <- User.get_by_nickname_or_email(nickname_or_email), + {:ok, _} <- User.try_send_confirmation_email(user) do + conn + |> json_response(:no_content, "") + end + end + + def try_render(conn, target, params) + when is_binary(target) do + case render(conn, target, params) do + nil -> render_error(conn, :not_implemented, "Can't display this activity") + res -> res end end def try_render(conn, _, _) do - conn - |> put_status(501) - |> json(%{error: "Can't display this activity"}) + render_error(conn, :not_implemented, "Can't display this activity") end defp present?(nil), do: false