Merge remote-tracking branch 'upstream/develop' into fix-prameter-name-of-accounts-update-credentials
This commit is contained in:
commit
a0f101ee80
432 changed files with 20793 additions and 14802 deletions
323
lib/pleroma/web/mastodon_api/controllers/account_controller.ex
Normal file
323
lib/pleroma/web/mastodon_api/controllers/account_controller.ex
Normal file
|
|
@ -0,0 +1,323 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.MastodonAPI.AccountController do
|
||||
use Pleroma.Web, :controller
|
||||
|
||||
import Pleroma.Web.ControllerHelper,
|
||||
only: [add_link_headers: 2, truthy_param?: 1, assign_account_by_id: 2, json_response: 3]
|
||||
|
||||
alias Pleroma.Emoji
|
||||
alias Pleroma.Plugs.RateLimiter
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||
alias Pleroma.Web.CommonAPI
|
||||
alias Pleroma.Web.MastodonAPI.ListView
|
||||
alias Pleroma.Web.MastodonAPI.MastodonAPI
|
||||
alias Pleroma.Web.MastodonAPI.StatusView
|
||||
alias Pleroma.Web.OAuth.Token
|
||||
alias Pleroma.Web.TwitterAPI.TwitterAPI
|
||||
|
||||
@relations [:follow, :unfollow]
|
||||
@needs_account ~W(followers following lists follow unfollow mute unmute block unblock)a
|
||||
|
||||
plug(RateLimiter, {:relations_id_action, params: ["id", "uri"]} when action in @relations)
|
||||
plug(RateLimiter, :relations_actions when action in @relations)
|
||||
plug(RateLimiter, :app_account_creation when action == :create)
|
||||
plug(:assign_account_by_id when action in @needs_account)
|
||||
|
||||
action_fallback(Pleroma.Web.MastodonAPI.FallbackController)
|
||||
|
||||
@doc "POST /api/v1/accounts"
|
||||
def create(
|
||||
%{assigns: %{app: app}} = conn,
|
||||
%{"username" => nickname, "email" => _, "password" => _, "agreement" => true} = params
|
||||
) do
|
||||
params =
|
||||
params
|
||||
|> Map.take([
|
||||
"email",
|
||||
"captcha_solution",
|
||||
"captcha_token",
|
||||
"captcha_answer_data",
|
||||
"token",
|
||||
"password"
|
||||
])
|
||||
|> Map.put("nickname", nickname)
|
||||
|> Map.put("fullname", params["fullname"] || nickname)
|
||||
|> Map.put("bio", params["bio"] || "")
|
||||
|> Map.put("confirm", params["password"])
|
||||
|
||||
with {:ok, user} <- TwitterAPI.register_user(params, need_confirmation: true),
|
||||
{:ok, token} <- Token.create_token(app, user, %{scopes: app.scopes}) do
|
||||
json(conn, %{
|
||||
token_type: "Bearer",
|
||||
access_token: token.token,
|
||||
scope: app.scopes,
|
||||
created_at: Token.Utils.format_created_at(token)
|
||||
})
|
||||
else
|
||||
{:error, errors} -> json_response(conn, :bad_request, errors)
|
||||
end
|
||||
end
|
||||
|
||||
def create(%{assigns: %{app: _app}} = conn, _) do
|
||||
render_error(conn, :bad_request, "Missing parameters")
|
||||
end
|
||||
|
||||
def create(conn, _) do
|
||||
render_error(conn, :forbidden, "Invalid credentials")
|
||||
end
|
||||
|
||||
@doc "GET /api/v1/accounts/verify_credentials"
|
||||
def verify_credentials(%{assigns: %{user: user}} = conn, _) do
|
||||
chat_token = Phoenix.Token.sign(conn, "user socket", user.id)
|
||||
|
||||
render(conn, "show.json",
|
||||
user: user,
|
||||
for: user,
|
||||
with_pleroma_settings: true,
|
||||
with_chat_token: chat_token
|
||||
)
|
||||
end
|
||||
|
||||
@doc "PATCH /api/v1/accounts/update_credentials"
|
||||
def update_credentials(%{assigns: %{user: original_user}} = conn, params) do
|
||||
user = original_user
|
||||
|
||||
user_params =
|
||||
%{}
|
||||
|> add_if_present(params, "display_name", :name)
|
||||
|> add_if_present(params, "note", :bio, fn value -> {:ok, User.parse_bio(value, user)} end)
|
||||
|> add_if_present(params, "avatar", :avatar, fn value ->
|
||||
with %Plug.Upload{} <- value,
|
||||
{:ok, object} <- ActivityPub.upload(value, type: :avatar) do
|
||||
{:ok, object.data}
|
||||
end
|
||||
end)
|
||||
|
||||
emojis_text = (user_params["display_name"] || "") <> (user_params["note"] || "")
|
||||
|
||||
user_info_emojis =
|
||||
user.info
|
||||
|> Map.get(:emoji, [])
|
||||
|> Enum.concat(Emoji.Formatter.get_emoji_map(emojis_text))
|
||||
|> Enum.dedup()
|
||||
|
||||
params =
|
||||
if Map.has_key?(params, "fields_attributes") do
|
||||
Map.update!(params, "fields_attributes", fn fields ->
|
||||
fields
|
||||
|> normalize_fields_attributes()
|
||||
|> Enum.filter(fn %{"name" => n} -> n != "" end)
|
||||
end)
|
||||
else
|
||||
params
|
||||
end
|
||||
|
||||
info_params =
|
||||
[
|
||||
:no_rich_text,
|
||||
:locked,
|
||||
:hide_followers_count,
|
||||
:hide_follows_count,
|
||||
:hide_followers,
|
||||
:hide_follows,
|
||||
:hide_favorites,
|
||||
:show_role,
|
||||
:skip_thread_containment,
|
||||
:discoverable
|
||||
]
|
||||
|> Enum.reduce(%{}, fn key, acc ->
|
||||
add_if_present(acc, params, to_string(key), key, &{:ok, truthy_param?(&1)})
|
||||
end)
|
||||
|> add_if_present(params, "default_scope", :default_scope)
|
||||
|> add_if_present(params, "fields_attributes", :fields, fn fields ->
|
||||
fields = Enum.map(fields, fn f -> Map.update!(f, "value", &AutoLinker.link(&1)) end)
|
||||
|
||||
{:ok, fields}
|
||||
end)
|
||||
|> add_if_present(params, "fields_attributes", :raw_fields)
|
||||
|> add_if_present(params, "pleroma_settings_store", :pleroma_settings_store, fn value ->
|
||||
{:ok, Map.merge(user.info.pleroma_settings_store, value)}
|
||||
end)
|
||||
|> add_if_present(params, "header", :banner, fn value ->
|
||||
with %Plug.Upload{} <- value,
|
||||
{:ok, object} <- ActivityPub.upload(value, type: :banner) do
|
||||
{:ok, object.data}
|
||||
end
|
||||
end)
|
||||
|> add_if_present(params, "pleroma_background_image", :background, fn value ->
|
||||
with %Plug.Upload{} <- value,
|
||||
{:ok, object} <- ActivityPub.upload(value, type: :background) do
|
||||
{:ok, object.data}
|
||||
end
|
||||
end)
|
||||
|> Map.put(:emoji, user_info_emojis)
|
||||
|
||||
changeset =
|
||||
user
|
||||
|> User.update_changeset(user_params)
|
||||
|> User.change_info(&User.Info.profile_update(&1, info_params))
|
||||
|
||||
with {:ok, user} <- User.update_and_set_cache(changeset) do
|
||||
if original_user != user, do: CommonAPI.update(user)
|
||||
|
||||
render(conn, "show.json", user: user, for: user, with_pleroma_settings: true)
|
||||
else
|
||||
_e -> render_error(conn, :forbidden, "Invalid request")
|
||||
end
|
||||
end
|
||||
|
||||
defp add_if_present(map, params, params_field, map_field, value_function \\ &{:ok, &1}) do
|
||||
with true <- Map.has_key?(params, params_field),
|
||||
{:ok, new_value} <- value_function.(params[params_field]) do
|
||||
Map.put(map, map_field, new_value)
|
||||
else
|
||||
_ -> map
|
||||
end
|
||||
end
|
||||
|
||||
defp normalize_fields_attributes(fields) do
|
||||
if Enum.all?(fields, &is_tuple/1) do
|
||||
Enum.map(fields, fn {_, v} -> v end)
|
||||
else
|
||||
fields
|
||||
end
|
||||
end
|
||||
|
||||
@doc "GET /api/v1/accounts/relationships"
|
||||
def relationships(%{assigns: %{user: user}} = conn, %{"id" => id}) do
|
||||
targets = User.get_all_by_ids(List.wrap(id))
|
||||
|
||||
render(conn, "relationships.json", user: user, targets: targets)
|
||||
end
|
||||
|
||||
# Instead of returning a 400 when no "id" params is present, Mastodon returns an empty array.
|
||||
def relationships(%{assigns: %{user: _user}} = conn, _), do: json(conn, [])
|
||||
|
||||
@doc "GET /api/v1/accounts/:id"
|
||||
def show(%{assigns: %{user: for_user}} = conn, %{"id" => nickname_or_id}) do
|
||||
with %User{} = user <- User.get_cached_by_nickname_or_id(nickname_or_id, for: for_user),
|
||||
true <- User.auth_active?(user) || user.id == for_user.id || User.superuser?(for_user) do
|
||||
render(conn, "show.json", user: user, for: for_user)
|
||||
else
|
||||
_e -> render_error(conn, :not_found, "Can't find user")
|
||||
end
|
||||
end
|
||||
|
||||
@doc "GET /api/v1/accounts/:id/statuses"
|
||||
def 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 = Map.put(params, "tag", params["tagged"])
|
||||
activities = ActivityPub.fetch_user_activities(user, reading_user, params)
|
||||
|
||||
conn
|
||||
|> add_link_headers(activities)
|
||||
|> put_view(StatusView)
|
||||
|> render("index.json", activities: activities, for: reading_user, as: :activity)
|
||||
end
|
||||
end
|
||||
|
||||
@doc "GET /api/v1/accounts/:id/followers"
|
||||
def followers(%{assigns: %{user: for_user, account: user}} = conn, params) do
|
||||
followers =
|
||||
cond do
|
||||
for_user && user.id == for_user.id -> MastodonAPI.get_followers(user, params)
|
||||
user.info.hide_followers -> []
|
||||
true -> MastodonAPI.get_followers(user, params)
|
||||
end
|
||||
|
||||
conn
|
||||
|> add_link_headers(followers)
|
||||
|> render("index.json", for: for_user, users: followers, as: :user)
|
||||
end
|
||||
|
||||
@doc "GET /api/v1/accounts/:id/following"
|
||||
def following(%{assigns: %{user: for_user, account: user}} = conn, params) do
|
||||
followers =
|
||||
cond do
|
||||
for_user && user.id == for_user.id -> MastodonAPI.get_friends(user, params)
|
||||
user.info.hide_follows -> []
|
||||
true -> MastodonAPI.get_friends(user, params)
|
||||
end
|
||||
|
||||
conn
|
||||
|> add_link_headers(followers)
|
||||
|> render("index.json", for: for_user, users: followers, as: :user)
|
||||
end
|
||||
|
||||
@doc "GET /api/v1/accounts/:id/lists"
|
||||
def lists(%{assigns: %{user: user, account: account}} = conn, _params) do
|
||||
lists = Pleroma.List.get_lists_account_belongs(user, account)
|
||||
|
||||
conn
|
||||
|> put_view(ListView)
|
||||
|> render("index.json", lists: lists)
|
||||
end
|
||||
|
||||
@doc "POST /api/v1/accounts/:id/follow"
|
||||
def follow(%{assigns: %{user: %{id: id}, account: %{id: id}}}, _params) do
|
||||
{:error, :not_found}
|
||||
end
|
||||
|
||||
def follow(%{assigns: %{user: follower, account: followed}} = conn, _params) do
|
||||
with {:ok, follower} <- MastodonAPI.follow(follower, followed, conn.params) do
|
||||
render(conn, "relationship.json", user: follower, target: followed)
|
||||
else
|
||||
{:error, message} -> json_response(conn, :forbidden, %{error: message})
|
||||
end
|
||||
end
|
||||
|
||||
@doc "POST /api/v1/accounts/:id/unfollow"
|
||||
def unfollow(%{assigns: %{user: %{id: id}, account: %{id: id}}}, _params) do
|
||||
{:error, :not_found}
|
||||
end
|
||||
|
||||
def unfollow(%{assigns: %{user: follower, account: followed}} = conn, _params) do
|
||||
with {:ok, follower} <- CommonAPI.unfollow(follower, followed) do
|
||||
render(conn, "relationship.json", user: follower, target: followed)
|
||||
end
|
||||
end
|
||||
|
||||
@doc "POST /api/v1/accounts/:id/mute"
|
||||
def mute(%{assigns: %{user: muter, account: muted}} = conn, params) do
|
||||
notifications? = params |> Map.get("notifications", true) |> truthy_param?()
|
||||
|
||||
with {:ok, muter} <- User.mute(muter, muted, notifications?) do
|
||||
render(conn, "relationship.json", user: muter, target: muted)
|
||||
else
|
||||
{:error, message} -> json_response(conn, :forbidden, %{error: message})
|
||||
end
|
||||
end
|
||||
|
||||
@doc "POST /api/v1/accounts/:id/unmute"
|
||||
def unmute(%{assigns: %{user: muter, account: muted}} = conn, _params) do
|
||||
with {:ok, muter} <- User.unmute(muter, muted) do
|
||||
render(conn, "relationship.json", user: muter, target: muted)
|
||||
else
|
||||
{:error, message} -> json_response(conn, :forbidden, %{error: message})
|
||||
end
|
||||
end
|
||||
|
||||
@doc "POST /api/v1/accounts/:id/block"
|
||||
def block(%{assigns: %{user: blocker, account: blocked}} = conn, _params) do
|
||||
with {:ok, blocker} <- User.block(blocker, blocked),
|
||||
{:ok, _activity} <- ActivityPub.block(blocker, blocked) do
|
||||
render(conn, "relationship.json", user: blocker, target: blocked)
|
||||
else
|
||||
{:error, message} -> json_response(conn, :forbidden, %{error: message})
|
||||
end
|
||||
end
|
||||
|
||||
@doc "POST /api/v1/accounts/:id/unblock"
|
||||
def unblock(%{assigns: %{user: blocker, account: blocked}} = conn, _params) do
|
||||
with {:ok, blocker} <- User.unblock(blocker, blocked),
|
||||
{:ok, _activity} <- ActivityPub.unblock(blocker, blocked) do
|
||||
render(conn, "relationship.json", user: blocker, target: blocked)
|
||||
else
|
||||
{:error, message} -> json_response(conn, :forbidden, %{error: message})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.MastodonAPI.ConversationController do
|
||||
use Pleroma.Web, :controller
|
||||
|
||||
import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2]
|
||||
|
||||
alias Pleroma.Conversation.Participation
|
||||
alias Pleroma.Repo
|
||||
|
||||
action_fallback(Pleroma.Web.MastodonAPI.FallbackController)
|
||||
|
||||
@doc "GET /api/v1/conversations"
|
||||
def index(%{assigns: %{user: user}} = conn, params) do
|
||||
participations = Participation.for_user_with_last_activity_id(user, params)
|
||||
|
||||
conn
|
||||
|> add_link_headers(participations)
|
||||
|> render("participations.json", participations: participations, for: user)
|
||||
end
|
||||
|
||||
@doc "POST /api/v1/conversations/:id/read"
|
||||
def read(%{assigns: %{user: user}} = conn, %{"id" => participation_id}) do
|
||||
with %Participation{} = participation <-
|
||||
Repo.get_by(Participation, id: participation_id, user_id: user.id),
|
||||
{:ok, participation} <- Participation.mark_as_read(participation) do
|
||||
render(conn, "participation.json", participation: participation, for: user)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.MastodonAPI.DomainBlockController do
|
||||
use Pleroma.Web, :controller
|
||||
|
||||
alias Pleroma.User
|
||||
|
||||
@doc "GET /api/v1/domain_blocks"
|
||||
def index(%{assigns: %{user: %{info: info}}} = conn, _) do
|
||||
json(conn, Map.get(info, :domain_blocks, []))
|
||||
end
|
||||
|
||||
@doc "POST /api/v1/domain_blocks"
|
||||
def create(%{assigns: %{user: blocker}} = conn, %{"domain" => domain}) do
|
||||
User.block_domain(blocker, domain)
|
||||
json(conn, %{})
|
||||
end
|
||||
|
||||
@doc "DELETE /api/v1/domain_blocks"
|
||||
def delete(%{assigns: %{user: blocker}} = conn, %{"domain" => domain}) do
|
||||
User.unblock_domain(blocker, domain)
|
||||
json(conn, %{})
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.MastodonAPI.FallbackController do
|
||||
use Pleroma.Web, :controller
|
||||
|
||||
def call(conn, {:error, %Ecto.Changeset{} = changeset}) do
|
||||
error_message =
|
||||
changeset
|
||||
|> Ecto.Changeset.traverse_errors(fn {message, _opt} -> message end)
|
||||
|> Enum.map_join(", ", fn {_k, v} -> v end)
|
||||
|
||||
conn
|
||||
|> put_status(:unprocessable_entity)
|
||||
|> json(%{error: error_message})
|
||||
end
|
||||
|
||||
def call(conn, {:error, :not_found}) do
|
||||
render_error(conn, :not_found, "Record not found")
|
||||
end
|
||||
|
||||
def call(conn, {:error, error_message}) do
|
||||
conn
|
||||
|> put_status(:bad_request)
|
||||
|> json(%{error: error_message})
|
||||
end
|
||||
|
||||
def call(conn, _) do
|
||||
conn
|
||||
|> put_status(:internal_server_error)
|
||||
|> json(dgettext("errors", "Something went wrong"))
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.MastodonAPI.FilterController do
|
||||
use Pleroma.Web, :controller
|
||||
|
||||
alias Pleroma.Filter
|
||||
|
||||
@doc "GET /api/v1/filters"
|
||||
def index(%{assigns: %{user: user}} = conn, _) do
|
||||
filters = Filter.get_filters(user)
|
||||
|
||||
render(conn, "filters.json", filters: filters)
|
||||
end
|
||||
|
||||
@doc "POST /api/v1/filters"
|
||||
def create(
|
||||
%{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)
|
||||
|
||||
render(conn, "filter.json", filter: response)
|
||||
end
|
||||
|
||||
@doc "GET /api/v1/filters/:id"
|
||||
def show(%{assigns: %{user: user}} = conn, %{"id" => filter_id}) do
|
||||
filter = Filter.get(filter_id, user)
|
||||
|
||||
render(conn, "filter.json", filter: filter)
|
||||
end
|
||||
|
||||
@doc "PUT /api/v1/filters/:id"
|
||||
def update(
|
||||
%{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)
|
||||
render(conn, "filter.json", filter: response)
|
||||
end
|
||||
|
||||
@doc "DELETE /api/v1/filters/:id"
|
||||
def delete(%{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
|
||||
end
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.MastodonAPI.FollowRequestController do
|
||||
use Pleroma.Web, :controller
|
||||
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.CommonAPI
|
||||
|
||||
plug(:put_view, Pleroma.Web.MastodonAPI.AccountView)
|
||||
plug(:assign_follower when action != :index)
|
||||
|
||||
action_fallback(:errors)
|
||||
|
||||
@doc "GET /api/v1/follow_requests"
|
||||
def index(%{assigns: %{user: followed}} = conn, _params) do
|
||||
follow_requests = User.get_follow_requests(followed)
|
||||
|
||||
render(conn, "index.json", for: followed, users: follow_requests, as: :user)
|
||||
end
|
||||
|
||||
@doc "POST /api/v1/follow_requests/:id/authorize"
|
||||
def authorize(%{assigns: %{user: followed, follower: follower}} = conn, _params) do
|
||||
with {:ok, follower} <- CommonAPI.accept_follow_request(follower, followed) do
|
||||
render(conn, "relationship.json", user: followed, target: follower)
|
||||
end
|
||||
end
|
||||
|
||||
@doc "POST /api/v1/follow_requests/:id/reject"
|
||||
def reject(%{assigns: %{user: followed, follower: follower}} = conn, _params) do
|
||||
with {:ok, follower} <- CommonAPI.reject_follow_request(follower, followed) do
|
||||
render(conn, "relationship.json", user: followed, target: follower)
|
||||
end
|
||||
end
|
||||
|
||||
defp assign_follower(%{params: %{"id" => id}} = conn, _) do
|
||||
case User.get_cached_by_id(id) do
|
||||
%User{} = follower -> assign(conn, :follower, follower)
|
||||
nil -> Pleroma.Web.MastodonAPI.FallbackController.call(conn, {:error, :not_found}) |> halt()
|
||||
end
|
||||
end
|
||||
|
||||
defp errors(conn, {:error, message}) do
|
||||
conn
|
||||
|> put_status(:forbidden)
|
||||
|> json(%{error: message})
|
||||
end
|
||||
end
|
||||
84
lib/pleroma/web/mastodon_api/controllers/list_controller.ex
Normal file
84
lib/pleroma/web/mastodon_api/controllers/list_controller.ex
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.MastodonAPI.ListController do
|
||||
use Pleroma.Web, :controller
|
||||
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.MastodonAPI.AccountView
|
||||
|
||||
plug(:list_by_id_and_user when action not in [:index, :create])
|
||||
|
||||
action_fallback(Pleroma.Web.MastodonAPI.FallbackController)
|
||||
|
||||
# GET /api/v1/lists
|
||||
def index(%{assigns: %{user: user}} = conn, opts) do
|
||||
lists = Pleroma.List.for_user(user, opts)
|
||||
render(conn, "index.json", lists: lists)
|
||||
end
|
||||
|
||||
# POST /api/v1/lists
|
||||
def create(%{assigns: %{user: user}} = conn, %{"title" => title}) do
|
||||
with {:ok, %Pleroma.List{} = list} <- Pleroma.List.create(title, user) do
|
||||
render(conn, "show.json", list: list)
|
||||
end
|
||||
end
|
||||
|
||||
# GET /api/v1/lists/:id
|
||||
def show(%{assigns: %{list: list}} = conn, _) do
|
||||
render(conn, "show.json", list: list)
|
||||
end
|
||||
|
||||
# PUT /api/v1/lists/:id
|
||||
def update(%{assigns: %{list: list}} = conn, %{"title" => title}) do
|
||||
with {:ok, list} <- Pleroma.List.rename(list, title) do
|
||||
render(conn, "show.json", list: list)
|
||||
end
|
||||
end
|
||||
|
||||
# DELETE /api/v1/lists/:id
|
||||
def delete(%{assigns: %{list: list}} = conn, _) do
|
||||
with {:ok, _list} <- Pleroma.List.delete(list) do
|
||||
json(conn, %{})
|
||||
end
|
||||
end
|
||||
|
||||
# GET /api/v1/lists/:id/accounts
|
||||
def list_accounts(%{assigns: %{user: user, list: list}} = conn, _) do
|
||||
with {:ok, users} <- Pleroma.List.get_following(list) do
|
||||
conn
|
||||
|> put_view(AccountView)
|
||||
|> render("index.json", for: user, users: users, as: :user)
|
||||
end
|
||||
end
|
||||
|
||||
# POST /api/v1/lists/:id/accounts
|
||||
def add_to_list(%{assigns: %{list: list}} = conn, %{"account_ids" => account_ids}) do
|
||||
Enum.each(account_ids, fn account_id ->
|
||||
with %User{} = followed <- User.get_cached_by_id(account_id) do
|
||||
Pleroma.List.follow(list, followed)
|
||||
end
|
||||
end)
|
||||
|
||||
json(conn, %{})
|
||||
end
|
||||
|
||||
# DELETE /api/v1/lists/:id/accounts
|
||||
def remove_from_list(%{assigns: %{list: list}} = conn, %{"account_ids" => account_ids}) do
|
||||
Enum.each(account_ids, fn account_id ->
|
||||
with %User{} = followed <- User.get_cached_by_id(account_id) do
|
||||
Pleroma.List.unfollow(list, followed)
|
||||
end
|
||||
end)
|
||||
|
||||
json(conn, %{})
|
||||
end
|
||||
|
||||
defp list_by_id_and_user(%{assigns: %{user: user}, params: %{"id" => id}} = conn, _) do
|
||||
case Pleroma.List.get(id, user) do
|
||||
%Pleroma.List{} = list -> assign(conn, :list, list)
|
||||
nil -> conn |> render_error(:not_found, "List not found") |> halt()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,529 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
||||
use Pleroma.Web, :controller
|
||||
|
||||
import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2]
|
||||
|
||||
alias Pleroma.Activity
|
||||
alias Pleroma.Bookmark
|
||||
alias Pleroma.Config
|
||||
alias Pleroma.HTTP
|
||||
alias Pleroma.Object
|
||||
alias Pleroma.Pagination
|
||||
alias Pleroma.Plugs.RateLimiter
|
||||
alias Pleroma.Repo
|
||||
alias Pleroma.Stats
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web
|
||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||
alias Pleroma.Web.ActivityPub.Visibility
|
||||
alias Pleroma.Web.CommonAPI
|
||||
alias Pleroma.Web.MastodonAPI.AccountView
|
||||
alias Pleroma.Web.MastodonAPI.AppView
|
||||
alias Pleroma.Web.MastodonAPI.MastodonView
|
||||
alias Pleroma.Web.MastodonAPI.StatusView
|
||||
alias Pleroma.Web.MediaProxy
|
||||
alias Pleroma.Web.OAuth.App
|
||||
alias Pleroma.Web.OAuth.Authorization
|
||||
alias Pleroma.Web.OAuth.Scopes
|
||||
alias Pleroma.Web.OAuth.Token
|
||||
alias Pleroma.Web.TwitterAPI.TwitterAPI
|
||||
|
||||
require Logger
|
||||
|
||||
plug(RateLimiter, :password_reset when action == :password_reset)
|
||||
|
||||
@local_mastodon_name "Mastodon-Local"
|
||||
|
||||
action_fallback(Pleroma.Web.MastodonAPI.FallbackController)
|
||||
|
||||
def create_app(conn, params) do
|
||||
scopes = Scopes.fetch_scopes(params, ["read"])
|
||||
|
||||
app_attrs =
|
||||
params
|
||||
|> Map.drop(["scope", "scopes"])
|
||||
|> Map.put("scopes", scopes)
|
||||
|
||||
with cs <- App.register_changeset(%App{}, app_attrs),
|
||||
false <- cs.changes[:client_name] == @local_mastodon_name,
|
||||
{:ok, app} <- Repo.insert(cs) do
|
||||
conn
|
||||
|> put_view(AppView)
|
||||
|> render("show.json", %{app: app})
|
||||
end
|
||||
end
|
||||
|
||||
def verify_app_credentials(%{assigns: %{user: _user, token: token}} = conn, _) do
|
||||
with %Token{app: %App{} = app} <- Repo.preload(token, :app) do
|
||||
conn
|
||||
|> put_view(AppView)
|
||||
|> render("short.json", %{app: app})
|
||||
end
|
||||
end
|
||||
|
||||
@mastodon_api_level "2.7.2"
|
||||
|
||||
def masto_instance(conn, _params) do
|
||||
instance = Config.get(:instance)
|
||||
|
||||
response = %{
|
||||
uri: Web.base_url(),
|
||||
title: Keyword.get(instance, :name),
|
||||
description: Keyword.get(instance, :description),
|
||||
version: "#{@mastodon_api_level} (compatible; #{Pleroma.Application.named_version()})",
|
||||
email: Keyword.get(instance, :email),
|
||||
urls: %{
|
||||
streaming_api: Pleroma.Web.Endpoint.websocket_url()
|
||||
},
|
||||
stats: Stats.get_stats(),
|
||||
thumbnail: Web.base_url() <> "/instance/thumbnail.jpeg",
|
||||
languages: ["en"],
|
||||
registrations: Pleroma.Config.get([:instance, :registrations_open]),
|
||||
# Extra (not present in Mastodon):
|
||||
max_toot_chars: Keyword.get(instance, :limit),
|
||||
poll_limits: Keyword.get(instance, :poll_limits)
|
||||
}
|
||||
|
||||
json(conn, response)
|
||||
end
|
||||
|
||||
def peers(conn, _params) do
|
||||
json(conn, Stats.get_peers())
|
||||
end
|
||||
|
||||
defp mastodonized_emoji do
|
||||
Pleroma.Emoji.get_all()
|
||||
|> Enum.map(fn {shortcode, %Pleroma.Emoji{file: relative_url, tags: tags}} ->
|
||||
url = to_string(URI.merge(Web.base_url(), relative_url))
|
||||
|
||||
%{
|
||||
"shortcode" => shortcode,
|
||||
"static_url" => url,
|
||||
"visible_in_picker" => true,
|
||||
"url" => url,
|
||||
"tags" => tags,
|
||||
# Assuming that a comma is authorized in the category name
|
||||
"category" => (tags -- ["Custom"]) |> Enum.join(",")
|
||||
}
|
||||
end)
|
||||
end
|
||||
|
||||
def custom_emojis(conn, _params) do
|
||||
mastodon_emoji = mastodonized_emoji()
|
||||
json(conn, mastodon_emoji)
|
||||
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"]),
|
||||
true <- Visibility.visible_for_user?(activity, user) do
|
||||
conn
|
||||
|> put_view(StatusView)
|
||||
|> try_render("poll.json", %{object: object, for: user})
|
||||
else
|
||||
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} <- get_cached_vote_or_vote(user, object, choices) do
|
||||
conn
|
||||
|> put_view(StatusView)
|
||||
|> try_render("poll.json", %{object: object, for: user})
|
||||
else
|
||||
nil ->
|
||||
render_error(conn, :not_found, "Record not found")
|
||||
|
||||
false ->
|
||||
render_error(conn, :not_found, "Record not found")
|
||||
|
||||
{:error, message} ->
|
||||
conn
|
||||
|> put_status(:unprocessable_entity)
|
||||
|> json(%{error: message})
|
||||
end
|
||||
end
|
||||
|
||||
def update_media(
|
||||
%{assigns: %{user: user}} = conn,
|
||||
%{"id" => id, "description" => description} = _
|
||||
)
|
||||
when is_binary(description) do
|
||||
with %Object{} = object <- Repo.get(Object, id),
|
||||
true <- Object.authorize_mutation(object, user),
|
||||
{:ok, %Object{data: data}} <- Object.update_data(object, %{"name" => description}) do
|
||||
attachment_data = Map.put(data, "id", object.id)
|
||||
|
||||
conn
|
||||
|> put_view(StatusView)
|
||||
|> render("attachment.json", %{attachment: attachment_data})
|
||||
end
|
||||
end
|
||||
|
||||
def update_media(_conn, _data), do: {:error, :bad_request}
|
||||
|
||||
def upload(%{assigns: %{user: user}} = conn, %{"file" => file} = data) do
|
||||
with {:ok, object} <-
|
||||
ActivityPub.upload(
|
||||
file,
|
||||
actor: User.ap_id(user),
|
||||
description: Map.get(data, "description")
|
||||
) do
|
||||
attachment_data = Map.put(object.data, "id", object.id)
|
||||
|
||||
conn
|
||||
|> put_view(StatusView)
|
||||
|> render("attachment.json", %{attachment: attachment_data})
|
||||
end
|
||||
end
|
||||
|
||||
def follows(%{assigns: %{user: follower}} = conn, %{"uri" => uri}) do
|
||||
with {_, %User{} = followed} <- {:followed, User.get_cached_by_nickname(uri)},
|
||||
{_, true} <- {:followed, follower.id != followed.id},
|
||||
{:ok, follower, followed, _} <- CommonAPI.follow(follower, followed) do
|
||||
conn
|
||||
|> put_view(AccountView)
|
||||
|> render("show.json", %{user: followed, for: follower})
|
||||
else
|
||||
{:followed, _} ->
|
||||
{:error, :not_found}
|
||||
|
||||
{:error, message} ->
|
||||
conn
|
||||
|> put_status(:forbidden)
|
||||
|> json(%{error: message})
|
||||
end
|
||||
end
|
||||
|
||||
def mutes(%{assigns: %{user: user}} = conn, _) do
|
||||
with muted_accounts <- User.muted_users(user) do
|
||||
res = AccountView.render("index.json", users: muted_accounts, for: user, as: :user)
|
||||
json(conn, res)
|
||||
end
|
||||
end
|
||||
|
||||
def blocks(%{assigns: %{user: user}} = conn, _) do
|
||||
with blocked_accounts <- User.blocked_users(user) do
|
||||
res = AccountView.render("index.json", users: blocked_accounts, for: user, as: :user)
|
||||
json(conn, res)
|
||||
end
|
||||
end
|
||||
|
||||
def favourites(%{assigns: %{user: user}} = conn, params) do
|
||||
params =
|
||||
params
|
||||
|> Map.put("type", "Create")
|
||||
|> Map.put("favorited_by", user.ap_id)
|
||||
|> Map.put("blocking_user", user)
|
||||
|
||||
activities =
|
||||
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 bookmarks(%{assigns: %{user: user}} = conn, params) do
|
||||
user = User.get_cached_by_id(user.id)
|
||||
|
||||
bookmarks =
|
||||
Bookmark.for_user_query(user.id)
|
||||
|> Pagination.fetch_paginated(params)
|
||||
|
||||
activities =
|
||||
bookmarks
|
||||
|> Enum.map(fn b -> Map.put(b.activity, :bookmark, Map.delete(b, :activity)) end)
|
||||
|
||||
conn
|
||||
|> add_link_headers(bookmarks)
|
||||
|> put_view(StatusView)
|
||||
|> render("index.json", %{activities: activities, for: user, as: :activity})
|
||||
end
|
||||
|
||||
def index(%{assigns: %{user: user}} = conn, _params) do
|
||||
token = get_session(conn, :oauth_token)
|
||||
|
||||
if user && token do
|
||||
mastodon_emoji = mastodonized_emoji()
|
||||
|
||||
limit = Config.get([:instance, :limit])
|
||||
|
||||
accounts = Map.put(%{}, user.id, AccountView.render("show.json", %{user: user, for: user}))
|
||||
|
||||
initial_state =
|
||||
%{
|
||||
meta: %{
|
||||
streaming_api_base_url: Pleroma.Web.Endpoint.websocket_url(),
|
||||
access_token: token,
|
||||
locale: "en",
|
||||
domain: Pleroma.Web.Endpoint.host(),
|
||||
admin: "1",
|
||||
me: "#{user.id}",
|
||||
unfollow_modal: false,
|
||||
boost_modal: false,
|
||||
delete_modal: true,
|
||||
auto_play_gif: false,
|
||||
display_sensitive_media: false,
|
||||
reduce_motion: false,
|
||||
max_toot_chars: limit,
|
||||
mascot: User.get_mascot(user)["url"]
|
||||
},
|
||||
poll_limits: Config.get([:instance, :poll_limits]),
|
||||
rights: %{
|
||||
delete_others_notice: present?(user.info.is_moderator),
|
||||
admin: present?(user.info.is_admin)
|
||||
},
|
||||
compose: %{
|
||||
me: "#{user.id}",
|
||||
default_privacy: user.info.default_scope,
|
||||
default_sensitive: false,
|
||||
allow_content_types: Config.get([:instance, :allowed_post_formats])
|
||||
},
|
||||
media_attachments: %{
|
||||
accept_content_types: [
|
||||
".jpg",
|
||||
".jpeg",
|
||||
".png",
|
||||
".gif",
|
||||
".webm",
|
||||
".mp4",
|
||||
".m4v",
|
||||
"image\/jpeg",
|
||||
"image\/png",
|
||||
"image\/gif",
|
||||
"video\/webm",
|
||||
"video\/mp4"
|
||||
]
|
||||
},
|
||||
settings:
|
||||
user.info.settings ||
|
||||
%{
|
||||
onboarded: true,
|
||||
home: %{
|
||||
shows: %{
|
||||
reblog: true,
|
||||
reply: true
|
||||
}
|
||||
},
|
||||
notifications: %{
|
||||
alerts: %{
|
||||
follow: true,
|
||||
favourite: true,
|
||||
reblog: true,
|
||||
mention: true
|
||||
},
|
||||
shows: %{
|
||||
follow: true,
|
||||
favourite: true,
|
||||
reblog: true,
|
||||
mention: true
|
||||
},
|
||||
sounds: %{
|
||||
follow: true,
|
||||
favourite: true,
|
||||
reblog: true,
|
||||
mention: true
|
||||
}
|
||||
}
|
||||
},
|
||||
push_subscription: nil,
|
||||
accounts: accounts,
|
||||
custom_emojis: mastodon_emoji,
|
||||
char_limit: limit
|
||||
}
|
||||
|> Jason.encode!()
|
||||
|
||||
conn
|
||||
|> put_layout(false)
|
||||
|> put_view(MastodonView)
|
||||
|> render("index.html", %{initial_state: initial_state})
|
||||
else
|
||||
conn
|
||||
|> put_session(:return_to, conn.request_path)
|
||||
|> redirect(to: "/web/login")
|
||||
end
|
||||
end
|
||||
|
||||
def put_settings(%{assigns: %{user: user}} = conn, %{"data" => settings} = _params) do
|
||||
with {:ok, _} <- User.update_info(user, &User.Info.mastodon_settings_update(&1, settings)) do
|
||||
json(conn, %{})
|
||||
else
|
||||
e ->
|
||||
conn
|
||||
|> put_status(:internal_server_error)
|
||||
|> json(%{error: inspect(e)})
|
||||
end
|
||||
end
|
||||
|
||||
def login(%{assigns: %{user: %User{}}} = conn, _params) do
|
||||
redirect(conn, to: local_mastodon_root_path(conn))
|
||||
end
|
||||
|
||||
@doc "Local Mastodon FE login init action"
|
||||
def login(conn, %{"code" => auth_token}) do
|
||||
with {:ok, app} <- get_or_make_app(),
|
||||
{:ok, auth} <- Authorization.get_by_token(app, auth_token),
|
||||
{:ok, token} <- Token.exchange_token(app, auth) do
|
||||
conn
|
||||
|> put_session(:oauth_token, token.token)
|
||||
|> redirect(to: local_mastodon_root_path(conn))
|
||||
end
|
||||
end
|
||||
|
||||
@doc "Local Mastodon FE callback action"
|
||||
def login(conn, _) do
|
||||
with {:ok, app} <- get_or_make_app() do
|
||||
path =
|
||||
o_auth_path(conn, :authorize,
|
||||
response_type: "code",
|
||||
client_id: app.client_id,
|
||||
redirect_uri: ".",
|
||||
scope: Enum.join(app.scopes, " ")
|
||||
)
|
||||
|
||||
redirect(conn, to: path)
|
||||
end
|
||||
end
|
||||
|
||||
defp local_mastodon_root_path(conn) do
|
||||
case get_session(conn, :return_to) do
|
||||
nil ->
|
||||
mastodon_api_path(conn, :index, ["getting-started"])
|
||||
|
||||
return_to ->
|
||||
delete_session(conn, :return_to)
|
||||
return_to
|
||||
end
|
||||
end
|
||||
|
||||
@spec get_or_make_app() :: {:ok, App.t()} | {:error, Ecto.Changeset.t()}
|
||||
defp get_or_make_app do
|
||||
App.get_or_make(
|
||||
%{client_name: @local_mastodon_name, redirect_uris: "."},
|
||||
["read", "write", "follow", "push"]
|
||||
)
|
||||
end
|
||||
|
||||
def logout(conn, _) do
|
||||
conn
|
||||
|> clear_session
|
||||
|> redirect(to: "/")
|
||||
end
|
||||
|
||||
# Stubs for unimplemented mastodon api
|
||||
#
|
||||
def empty_array(conn, _) do
|
||||
Logger.debug("Unimplemented, returning an empty array")
|
||||
json(conn, [])
|
||||
end
|
||||
|
||||
def empty_object(conn, _) do
|
||||
Logger.debug("Unimplemented, returning an empty object")
|
||||
json(conn, %{})
|
||||
end
|
||||
|
||||
def suggestions(%{assigns: %{user: user}} = conn, _) do
|
||||
suggestions = Config.get(:suggestions)
|
||||
|
||||
if Keyword.get(suggestions, :enabled, false) do
|
||||
api = Keyword.get(suggestions, :third_party_engine, "")
|
||||
timeout = Keyword.get(suggestions, :timeout, 5000)
|
||||
limit = Keyword.get(suggestions, :limit, 23)
|
||||
|
||||
host = Config.get([Pleroma.Web.Endpoint, :url, :host])
|
||||
|
||||
user = user.nickname
|
||||
|
||||
url =
|
||||
api
|
||||
|> String.replace("{{host}}", host)
|
||||
|> String.replace("{{user}}", user)
|
||||
|
||||
with {:ok, %{status: 200, body: body}} <-
|
||||
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 ->
|
||||
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)
|
||||
|
||||
json(conn, data)
|
||||
else
|
||||
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 password_reset(conn, params) do
|
||||
nickname_or_email = params["email"] || params["nickname"]
|
||||
|
||||
with {:ok, _} <- TwitterAPI.password_reset(nickname_or_email) do
|
||||
conn
|
||||
|> put_status(:no_content)
|
||||
|> json("")
|
||||
else
|
||||
{:error, "unknown user"} ->
|
||||
send_resp(conn, :not_found, "")
|
||||
|
||||
{:error, _} ->
|
||||
send_resp(conn, :bad_request, "")
|
||||
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
|
||||
render_error(conn, :not_implemented, "Can't display this activity")
|
||||
end
|
||||
|
||||
defp present?(nil), do: false
|
||||
defp present?(false), do: false
|
||||
defp present?(_), do: true
|
||||
end
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.MastodonAPI.NotificationController do
|
||||
use Pleroma.Web, :controller
|
||||
|
||||
import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2]
|
||||
|
||||
alias Pleroma.Notification
|
||||
alias Pleroma.Web.MastodonAPI.MastodonAPI
|
||||
|
||||
# GET /api/v1/notifications
|
||||
def index(%{assigns: %{user: user}} = conn, params) do
|
||||
notifications = MastodonAPI.get_notifications(user, params)
|
||||
|
||||
conn
|
||||
|> add_link_headers(notifications)
|
||||
|> render("index.json", notifications: notifications, for: user)
|
||||
end
|
||||
|
||||
# GET /api/v1/notifications/:id
|
||||
def show(%{assigns: %{user: user}} = conn, %{"id" => id}) do
|
||||
with {:ok, notification} <- Notification.get(user, id) do
|
||||
render(conn, "show.json", notification: notification, for: user)
|
||||
else
|
||||
{:error, reason} ->
|
||||
conn
|
||||
|> put_status(:forbidden)
|
||||
|> json(%{"error" => reason})
|
||||
end
|
||||
end
|
||||
|
||||
# POST /api/v1/notifications/clear
|
||||
def clear(%{assigns: %{user: user}} = conn, _params) do
|
||||
Notification.clear(user)
|
||||
json(conn, %{})
|
||||
end
|
||||
|
||||
# POST /api/v1/notifications/dismiss
|
||||
def dismiss(%{assigns: %{user: user}} = conn, %{"id" => id} = _params) do
|
||||
with {:ok, _notif} <- Notification.dismiss(user, id) do
|
||||
json(conn, %{})
|
||||
else
|
||||
{:error, reason} ->
|
||||
conn
|
||||
|> put_status(:forbidden)
|
||||
|> json(%{"error" => reason})
|
||||
end
|
||||
end
|
||||
|
||||
# DELETE /api/v1/notifications/destroy_multiple
|
||||
def destroy_multiple(%{assigns: %{user: user}} = conn, %{"ids" => ids} = _params) do
|
||||
Notification.destroy_multiple(user, ids)
|
||||
json(conn, %{})
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.MastodonAPI.ReportController do
|
||||
use Pleroma.Web, :controller
|
||||
|
||||
action_fallback(Pleroma.Web.MastodonAPI.FallbackController)
|
||||
|
||||
@doc "POST /api/v1/reports"
|
||||
def create(%{assigns: %{user: user}} = conn, params) do
|
||||
with {:ok, activity} <- Pleroma.Web.CommonAPI.report(user, params) do
|
||||
render(conn, "show.json", activity: activity)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.MastodonAPI.ScheduledActivityController do
|
||||
use Pleroma.Web, :controller
|
||||
|
||||
import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2]
|
||||
|
||||
alias Pleroma.ScheduledActivity
|
||||
alias Pleroma.Web.MastodonAPI.MastodonAPI
|
||||
|
||||
plug(:assign_scheduled_activity when action != :index)
|
||||
|
||||
action_fallback(Pleroma.Web.MastodonAPI.FallbackController)
|
||||
|
||||
@doc "GET /api/v1/scheduled_statuses"
|
||||
def index(%{assigns: %{user: user}} = conn, params) do
|
||||
with scheduled_activities <- MastodonAPI.get_scheduled_activities(user, params) do
|
||||
conn
|
||||
|> add_link_headers(scheduled_activities)
|
||||
|> render("index.json", scheduled_activities: scheduled_activities)
|
||||
end
|
||||
end
|
||||
|
||||
@doc "GET /api/v1/scheduled_statuses/:id"
|
||||
def show(%{assigns: %{scheduled_activity: scheduled_activity}} = conn, _params) do
|
||||
render(conn, "show.json", scheduled_activity: scheduled_activity)
|
||||
end
|
||||
|
||||
@doc "PUT /api/v1/scheduled_statuses/:id"
|
||||
def update(%{assigns: %{scheduled_activity: scheduled_activity}} = conn, params) do
|
||||
with {:ok, scheduled_activity} <- ScheduledActivity.update(scheduled_activity, params) do
|
||||
render(conn, "show.json", scheduled_activity: scheduled_activity)
|
||||
end
|
||||
end
|
||||
|
||||
@doc "DELETE /api/v1/scheduled_statuses/:id"
|
||||
def delete(%{assigns: %{scheduled_activity: scheduled_activity}} = conn, _params) do
|
||||
with {:ok, scheduled_activity} <- ScheduledActivity.delete(scheduled_activity) do
|
||||
render(conn, "show.json", scheduled_activity: scheduled_activity)
|
||||
end
|
||||
end
|
||||
|
||||
defp assign_scheduled_activity(%{assigns: %{user: user}, params: %{"id" => id}} = conn, _) do
|
||||
case ScheduledActivity.get(user, id) do
|
||||
%ScheduledActivity{} = activity -> assign(conn, :scheduled_activity, activity)
|
||||
nil -> Pleroma.Web.MastodonAPI.FallbackController.call(conn, {:error, :not_found}) |> halt()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -19,9 +19,10 @@ defmodule Pleroma.Web.MastodonAPI.SearchController do
|
|||
|
||||
def account_search(%{assigns: %{user: user}} = conn, %{"q" => query} = params) do
|
||||
accounts = User.search(query, search_options(params, user))
|
||||
res = AccountView.render("accounts.json", users: accounts, for: user, as: :user)
|
||||
|
||||
json(conn, res)
|
||||
conn
|
||||
|> put_view(AccountView)
|
||||
|> render("index.json", users: accounts, for: user, as: :user)
|
||||
end
|
||||
|
||||
def search2(conn, params), do: do_search(:v2, conn, params)
|
||||
|
|
@ -71,7 +72,7 @@ defmodule Pleroma.Web.MastodonAPI.SearchController do
|
|||
|
||||
defp resource_search(_, "accounts", query, options) do
|
||||
accounts = with_fallback(fn -> User.search(query, options) end)
|
||||
AccountView.render("accounts.json", users: accounts, for: options[:for_user], as: :user)
|
||||
AccountView.render("index.json", users: accounts, for: options[:for_user], as: :user)
|
||||
end
|
||||
|
||||
defp resource_search(_, "statuses", query, options) do
|
||||
274
lib/pleroma/web/mastodon_api/controllers/status_controller.ex
Normal file
274
lib/pleroma/web/mastodon_api/controllers/status_controller.ex
Normal file
|
|
@ -0,0 +1,274 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# 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
|
||||
|
||||
def create(%{assigns: %{user: _user}} = conn, %{"media_ids" => _} = params) do
|
||||
create(conn, Map.put(params, "status", ""))
|
||||
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"
|
||||
@deprecated "https://github.com/tootsuite/mastodon/pull/11213"
|
||||
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("index.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("index.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
|
||||
|
|
@ -64,8 +64,6 @@ defmodule Pleroma.Web.MastodonAPI.SubscriptionController do
|
|||
end
|
||||
|
||||
def errors(conn, _) do
|
||||
conn
|
||||
|> put_status(:internal_server_error)
|
||||
|> json(dgettext("errors", "Something went wrong"))
|
||||
Pleroma.Web.MastodonAPI.FallbackController.call(conn, nil)
|
||||
end
|
||||
end
|
||||
136
lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex
Normal file
136
lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.MastodonAPI.TimelineController do
|
||||
use Pleroma.Web, :controller
|
||||
|
||||
import Pleroma.Web.ControllerHelper,
|
||||
only: [add_link_headers: 2, add_link_headers: 3, truthy_param?: 1]
|
||||
|
||||
alias Pleroma.Pagination
|
||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||
|
||||
plug(:put_view, Pleroma.Web.MastodonAPI.StatusView)
|
||||
|
||||
# GET /api/v1/timelines/home
|
||||
def home(%{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)
|
||||
|
||||
recipients = [user.ap_id | user.following]
|
||||
|
||||
activities =
|
||||
recipients
|
||||
|> ActivityPub.fetch_activities(params)
|
||||
|> Enum.reverse()
|
||||
|
||||
conn
|
||||
|> add_link_headers(activities)
|
||||
|> render("index.json", activities: activities, for: user, as: :activity)
|
||||
end
|
||||
|
||||
# GET /api/v1/timelines/direct
|
||||
def direct(%{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)
|
||||
|> render("index.json", activities: activities, for: user, as: :activity)
|
||||
end
|
||||
|
||||
# GET /api/v1/timelines/public
|
||||
def public(%{assigns: %{user: user}} = conn, params) do
|
||||
local_only = truthy_param?(params["local"])
|
||||
|
||||
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})
|
||||
|> render("index.json", activities: activities, for: user, as: :activity)
|
||||
end
|
||||
|
||||
# GET /api/v1/timelines/tag/:tag
|
||||
def hashtag(%{assigns: %{user: user}} = conn, params) do
|
||||
local_only = truthy_param?(params["local"])
|
||||
|
||||
tags =
|
||||
[params["tag"], params["any"]]
|
||||
|> List.flatten()
|
||||
|> Enum.uniq()
|
||||
|> Enum.filter(& &1)
|
||||
|> Enum.map(&String.downcase(&1))
|
||||
|
||||
tag_all =
|
||||
params
|
||||
|> Map.get("all", [])
|
||||
|> Enum.map(&String.downcase(&1))
|
||||
|
||||
tag_reject =
|
||||
params
|
||||
|> Map.get("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})
|
||||
|> render("index.json", activities: activities, for: user, as: :activity)
|
||||
end
|
||||
|
||||
# GET /api/v1/timelines/list/:list_id
|
||||
def list(%{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()
|
||||
|
||||
render(conn, "index.json", activities: activities, for: user, as: :activity)
|
||||
else
|
||||
_e -> render_error(conn, :forbidden, "Error.")
|
||||
end
|
||||
end
|
||||
end
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -11,15 +11,15 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
|
|||
alias Pleroma.Web.MastodonAPI.AccountView
|
||||
alias Pleroma.Web.MediaProxy
|
||||
|
||||
def render("accounts.json", %{users: users} = opts) do
|
||||
def render("index.json", %{users: users} = opts) do
|
||||
users
|
||||
|> render_many(AccountView, "account.json", opts)
|
||||
|> render_many(AccountView, "show.json", opts)
|
||||
|> Enum.filter(&Enum.any?/1)
|
||||
end
|
||||
|
||||
def render("account.json", %{user: user} = opts) do
|
||||
def render("show.json", %{user: user} = opts) do
|
||||
if User.visible_for?(user, opts[:for]),
|
||||
do: do_render("account.json", opts),
|
||||
do: do_render("show.json", opts),
|
||||
else: %{}
|
||||
end
|
||||
|
||||
|
|
@ -66,7 +66,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
|
|||
render_many(targets, AccountView, "relationship.json", user: user, as: :target)
|
||||
end
|
||||
|
||||
defp do_render("account.json", %{user: user} = opts) do
|
||||
defp do_render("show.json", %{user: user} = opts) do
|
||||
display_name = HTML.strip_tags(user.name || user.nickname)
|
||||
|
||||
image = User.avatar_url(user) |> MediaProxy.url()
|
||||
|
|
@ -74,10 +74,18 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
|
|||
user_info = User.get_cached_user_info(user)
|
||||
|
||||
following_count =
|
||||
((!user.info.hide_follows or opts[:for] == user) && user_info.following_count) || 0
|
||||
if !user.info.hide_follows_count or !user.info.hide_follows or opts[:for] == user do
|
||||
user_info.following_count
|
||||
else
|
||||
0
|
||||
end
|
||||
|
||||
followers_count =
|
||||
((!user.info.hide_followers or opts[:for] == user) && user_info.follower_count) || 0
|
||||
if !user.info.hide_followers_count or !user.info.hide_followers or opts[:for] == user do
|
||||
user_info.follower_count
|
||||
else
|
||||
0
|
||||
end
|
||||
|
||||
bot = (user.info.source_data["type"] || "Person") in ["Application", "Service"]
|
||||
|
||||
|
|
@ -108,6 +116,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
|
|||
bio = HTML.filter_tags(user.bio, User.html_filter_policy(opts[:for]))
|
||||
relationship = render("relationship.json", %{user: opts[:for], target: user})
|
||||
|
||||
discoverable = user.info.discoverable
|
||||
|
||||
%{
|
||||
id: to_string(user.id),
|
||||
username: username_from_nickname(user.nickname),
|
||||
|
|
@ -131,13 +141,17 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
|
|||
note: HTML.strip_tags((user.bio || "") |> String.replace("<br>", "\n")),
|
||||
sensitive: false,
|
||||
fields: raw_fields,
|
||||
pleroma: %{}
|
||||
pleroma: %{
|
||||
discoverable: discoverable
|
||||
}
|
||||
},
|
||||
|
||||
# Pleroma extension
|
||||
pleroma: %{
|
||||
confirmation_pending: user_info.confirmation_pending,
|
||||
tags: user.tags,
|
||||
hide_followers_count: user.info.hide_followers_count,
|
||||
hide_follows_count: user.info.hide_follows_count,
|
||||
hide_followers: user.info.hide_followers,
|
||||
hide_follows: user.info.hide_follows,
|
||||
hide_favorites: user.info.hide_favorites,
|
||||
|
|
@ -152,6 +166,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
|
|||
|> maybe_put_settings_store(user, opts[:for], opts)
|
||||
|> maybe_put_chat_token(user, opts[:for], opts)
|
||||
|> maybe_put_activation_status(user, opts[:for])
|
||||
|> maybe_put_follow_requests_count(user, opts[:for])
|
||||
end
|
||||
|
||||
defp username_from_nickname(string) when is_binary(string) do
|
||||
|
|
@ -160,6 +175,21 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
|
|||
|
||||
defp username_from_nickname(_), do: nil
|
||||
|
||||
defp maybe_put_follow_requests_count(
|
||||
data,
|
||||
%User{id: user_id} = user,
|
||||
%User{id: user_id}
|
||||
) do
|
||||
count =
|
||||
User.get_follow_requests(user)
|
||||
|> length()
|
||||
|
||||
data
|
||||
|> Kernel.put_in([:follow_requests_count], count)
|
||||
end
|
||||
|
||||
defp maybe_put_follow_requests_count(data, _, _), do: data
|
||||
|
||||
defp maybe_put_settings(
|
||||
data,
|
||||
%User{id: user_id} = user,
|
||||
|
|
|
|||
|
|
@ -11,6 +11,10 @@ defmodule Pleroma.Web.MastodonAPI.ConversationView do
|
|||
alias Pleroma.Web.MastodonAPI.AccountView
|
||||
alias Pleroma.Web.MastodonAPI.StatusView
|
||||
|
||||
def render("participations.json", %{participations: participations, for: user}) do
|
||||
render_many(participations, __MODULE__, "participation.json", as: :participation, for: user)
|
||||
end
|
||||
|
||||
def render("participation.json", %{participation: participation, for: user}) do
|
||||
participation = Repo.preload(participation, conversation: [], recipients: [])
|
||||
|
||||
|
|
@ -23,25 +27,14 @@ defmodule Pleroma.Web.MastodonAPI.ConversationView do
|
|||
end
|
||||
|
||||
activity = Activity.get_by_id_with_object(last_activity_id)
|
||||
|
||||
last_status = StatusView.render("status.json", %{activity: activity, for: user})
|
||||
|
||||
# Conversations return all users except the current user.
|
||||
users =
|
||||
participation.recipients
|
||||
|> Enum.reject(&(&1.id == user.id))
|
||||
|
||||
accounts =
|
||||
AccountView.render("accounts.json", %{
|
||||
users: users,
|
||||
as: :user
|
||||
})
|
||||
users = Enum.reject(participation.recipients, &(&1.id == user.id))
|
||||
|
||||
%{
|
||||
id: participation.id |> to_string(),
|
||||
accounts: accounts,
|
||||
accounts: render(AccountView, "index.json", users: users, as: :user),
|
||||
unread: !participation.read,
|
||||
last_status: last_status
|
||||
last_status: render(StatusView, "show.json", activity: activity, for: user)
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@ defmodule Pleroma.Web.MastodonAPI.ListView do
|
|||
use Pleroma.Web, :view
|
||||
alias Pleroma.Web.MastodonAPI.ListView
|
||||
|
||||
def render("lists.json", %{lists: lists} = opts) do
|
||||
render_many(lists, ListView, "list.json", opts)
|
||||
def render("index.json", %{lists: lists} = opts) do
|
||||
render_many(lists, ListView, "show.json", opts)
|
||||
end
|
||||
|
||||
def render("list.json", %{list: list}) do
|
||||
def render("show.json", %{list: list}) do
|
||||
%{
|
||||
id: to_string(list.id),
|
||||
title: list.title
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationView do
|
|||
alias Pleroma.Web.MastodonAPI.StatusView
|
||||
|
||||
def render("index.json", %{notifications: notifications, for: user}) do
|
||||
render_many(notifications, NotificationView, "show.json", %{for: user})
|
||||
safe_render_many(notifications, NotificationView, "show.json", %{for: user})
|
||||
end
|
||||
|
||||
def render("show.json", %{
|
||||
|
|
@ -29,7 +29,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationView do
|
|||
id: to_string(notification.id),
|
||||
type: mastodon_type,
|
||||
created_at: CommonAPI.Utils.to_masto_date(notification.inserted_at),
|
||||
account: AccountView.render("account.json", %{user: actor, for: user}),
|
||||
account: AccountView.render("show.json", %{user: actor, for: user}),
|
||||
pleroma: %{
|
||||
is_seen: notification.seen
|
||||
}
|
||||
|
|
@ -39,19 +39,19 @@ defmodule Pleroma.Web.MastodonAPI.NotificationView do
|
|||
"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" ->
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
defmodule Pleroma.Web.MastodonAPI.ReportView do
|
||||
use Pleroma.Web, :view
|
||||
|
||||
def render("report.json", %{activity: activity}) do
|
||||
def render("show.json", %{activity: activity}) do
|
||||
%{
|
||||
id: to_string(activity.id),
|
||||
action_taken: false
|
||||
|
|
|
|||
|
|
@ -7,11 +7,10 @@ defmodule Pleroma.Web.MastodonAPI.ScheduledActivityView do
|
|||
|
||||
alias Pleroma.ScheduledActivity
|
||||
alias Pleroma.Web.CommonAPI
|
||||
alias Pleroma.Web.MastodonAPI.ScheduledActivityView
|
||||
alias Pleroma.Web.MastodonAPI.StatusView
|
||||
|
||||
def render("index.json", %{scheduled_activities: scheduled_activities}) do
|
||||
render_many(scheduled_activities, ScheduledActivityView, "show.json")
|
||||
render_many(scheduled_activities, __MODULE__, "show.json")
|
||||
end
|
||||
|
||||
def render("show.json", %{scheduled_activity: %ScheduledActivity{} = scheduled_activity}) do
|
||||
|
|
@ -24,12 +23,8 @@ defmodule Pleroma.Web.MastodonAPI.ScheduledActivityView do
|
|||
end
|
||||
|
||||
defp with_media_attachments(data, %{params: %{"media_attachments" => media_attachments}}) do
|
||||
try do
|
||||
attachments = render_many(media_attachments, StatusView, "attachment.json", as: :attachment)
|
||||
Map.put(data, :media_attachments, attachments)
|
||||
rescue
|
||||
_ -> data
|
||||
end
|
||||
attachments = render_many(media_attachments, StatusView, "attachment.json", as: :attachment)
|
||||
Map.put(data, :media_attachments, attachments)
|
||||
end
|
||||
|
||||
defp with_media_attachments(data, _), do: data
|
||||
|
|
@ -45,13 +40,9 @@ defmodule Pleroma.Web.MastodonAPI.ScheduledActivityView do
|
|||
in_reply_to_id: params["in_reply_to_id"]
|
||||
}
|
||||
|
||||
data =
|
||||
if media_ids = params["media_ids"] do
|
||||
Map.put(data, :media_ids, media_ids)
|
||||
else
|
||||
data
|
||||
end
|
||||
|
||||
data
|
||||
case params["media_ids"] do
|
||||
nil -> data
|
||||
media_ids -> Map.put(data, :media_ids, media_ids)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
|
|||
require Pleroma.Constants
|
||||
|
||||
alias Pleroma.Activity
|
||||
alias Pleroma.ActivityExpiration
|
||||
alias Pleroma.Conversation
|
||||
alias Pleroma.Conversation.Participation
|
||||
alias Pleroma.HTML
|
||||
|
|
@ -72,19 +73,13 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
|
|||
|
||||
def render("index.json", opts) do
|
||||
replied_to_activities = get_replied_to_activities(opts.activities)
|
||||
parallel = unless is_nil(opts[:parallel]), do: opts[:parallel], else: true
|
||||
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),
|
||||
parallel
|
||||
)
|
||||
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"])
|
||||
|
|
@ -97,7 +92,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
|
|||
|> 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"] || [])
|
||||
|
||||
|
|
@ -113,7 +108,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
|
|||
id: to_string(activity.id),
|
||||
uri: activity_object.data["id"],
|
||||
url: activity_object.data["id"],
|
||||
account: AccountView.render("account.json", %{user: user, for: opts[:for]}),
|
||||
account: AccountView.render("show.json", %{user: user, for: opts[:for]}),
|
||||
in_reply_to_id: nil,
|
||||
in_reply_to_account_id: nil,
|
||||
reblog: reblogged,
|
||||
|
|
@ -145,7 +140,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
|
|||
}
|
||||
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"])
|
||||
|
|
@ -177,6 +172,15 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
|
|||
|
||||
bookmarked = Activity.get_bookmark(activity, opts[:for]) != nil
|
||||
|
||||
client_posted_this_activity = opts[:for] && user.id == opts[:for].id
|
||||
|
||||
expires_at =
|
||||
with true <- client_posted_this_activity,
|
||||
expiration when not is_nil(expiration) <-
|
||||
ActivityExpiration.get_by_activity_id(activity.id) do
|
||||
expiration.scheduled_at
|
||||
end
|
||||
|
||||
thread_muted? =
|
||||
case activity.thread_muted? do
|
||||
thread_muted? when is_boolean(thread_muted?) -> thread_muted?
|
||||
|
|
@ -254,7 +258,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
|
|||
id: to_string(activity.id),
|
||||
uri: object.data["id"],
|
||||
url: url,
|
||||
account: AccountView.render("account.json", %{user: user, for: opts[:for]}),
|
||||
account: AccountView.render("show.json", %{user: user, for: opts[:for]}),
|
||||
in_reply_to_id: reply_to && to_string(reply_to.id),
|
||||
in_reply_to_account_id: reply_to_user && to_string(reply_to_user.id),
|
||||
reblog: nil,
|
||||
|
|
@ -288,12 +292,14 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
|
|||
in_reply_to_account_acct: reply_to_user && reply_to_user.nickname,
|
||||
content: %{"text/plain" => content_plaintext},
|
||||
spoiler_text: %{"text/plain" => summary_plaintext},
|
||||
direct_conversation_id: direct_conversation_id
|
||||
expires_at: expires_at,
|
||||
direct_conversation_id: direct_conversation_id,
|
||||
thread_muted: thread_muted?
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def render("status.json", _) do
|
||||
def render("show.json", _) do
|
||||
nil
|
||||
end
|
||||
|
||||
|
|
@ -333,9 +339,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
|
|||
}
|
||||
end
|
||||
|
||||
def render("card.json", _) do
|
||||
nil
|
||||
end
|
||||
def render("card.json", _), do: nil
|
||||
|
||||
def render("attachment.json", %{attachment: attachment}) do
|
||||
[attachment_url | _] = attachment["url"]
|
||||
|
|
@ -364,6 +368,27 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
|
|||
}
|
||||
end
|
||||
|
||||
def render("listen.json", %{activity: %Activity{data: %{"type" => "Listen"}} = activity} = opts) do
|
||||
object = Object.normalize(activity)
|
||||
|
||||
user = get_user(activity.data["actor"])
|
||||
created_at = Utils.to_masto_date(activity.data["published"])
|
||||
|
||||
%{
|
||||
id: activity.id,
|
||||
account: AccountView.render("show.json", %{user: user, for: opts[:for]}),
|
||||
created_at: created_at,
|
||||
title: object.data["title"] |> HTML.strip_tags(),
|
||||
artist: object.data["artist"] |> HTML.strip_tags(),
|
||||
album: object.data["album"] |> HTML.strip_tags(),
|
||||
length: object.data["length"]
|
||||
}
|
||||
end
|
||||
|
||||
def render("listens.json", opts) do
|
||||
safe_render_many(opts.activities, StatusView, "listen.json", opts)
|
||||
end
|
||||
|
||||
def render("poll.json", %{object: object} = opts) do
|
||||
{multiple, options} =
|
||||
case object.data do
|
||||
|
|
@ -373,16 +398,27 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
|
|||
end
|
||||
|
||||
if options do
|
||||
end_time =
|
||||
(object.data["closed"] || object.data["endTime"])
|
||||
|> NaiveDateTime.from_iso8601!()
|
||||
{end_time, expired} =
|
||||
case object.data["closed"] || object.data["endTime"] do
|
||||
end_time when is_binary(end_time) ->
|
||||
end_time =
|
||||
(object.data["closed"] || object.data["endTime"])
|
||||
|> NaiveDateTime.from_iso8601!()
|
||||
|
||||
expired =
|
||||
end_time
|
||||
|> NaiveDateTime.compare(NaiveDateTime.utc_now())
|
||||
|> case do
|
||||
:lt -> true
|
||||
_ -> false
|
||||
expired =
|
||||
end_time
|
||||
|> NaiveDateTime.compare(NaiveDateTime.utc_now())
|
||||
|> case do
|
||||
:lt -> true
|
||||
_ -> false
|
||||
end
|
||||
|
||||
end_time = Utils.to_masto_date(end_time)
|
||||
|
||||
{end_time, expired}
|
||||
|
||||
_ ->
|
||||
{nil, false}
|
||||
end
|
||||
|
||||
voted =
|
||||
|
|
@ -409,7 +445,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
|
|||
# Mastodon uses separate ids for polls, but an object can't have
|
||||
# more than one poll embedded so object id is fine
|
||||
id: to_string(object.id),
|
||||
expires_at: Utils.to_masto_date(end_time),
|
||||
expires_at: end_time,
|
||||
expired: expired,
|
||||
multiple: multiple,
|
||||
votes_count: votes_count,
|
||||
|
|
@ -422,6 +458,20 @@ defmodule Pleroma.Web.MastodonAPI.StatusView 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)
|
||||
|
||||
|
|
@ -476,7 +526,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
|
|||
object_tags = for tag when is_binary(tag) <- object_tags, do: tag
|
||||
|
||||
Enum.reduce(object_tags, [], fn tag, tags ->
|
||||
tags ++ [%{name: tag, url: "/tag/#{tag}"}]
|
||||
tags ++ [%{name: tag, url: "/tag/#{URI.encode(tag)}"}]
|
||||
end)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ defmodule Pleroma.Web.MastodonAPI.WebsocketHandler do
|
|||
alias Pleroma.Repo
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.OAuth.Token
|
||||
alias Pleroma.Web.Streamer
|
||||
|
||||
@behaviour :cowboy_websocket
|
||||
|
||||
|
|
@ -24,7 +25,7 @@ defmodule Pleroma.Web.MastodonAPI.WebsocketHandler do
|
|||
]
|
||||
@anonymous_streams ["public", "public:local", "hashtag"]
|
||||
|
||||
# Handled by periodic keepalive in Pleroma.Web.Streamer.
|
||||
# Handled by periodic keepalive in Pleroma.Web.Streamer.Ping.
|
||||
@timeout :infinity
|
||||
|
||||
def init(%{qs: qs} = req, state) do
|
||||
|
|
@ -65,7 +66,7 @@ defmodule Pleroma.Web.MastodonAPI.WebsocketHandler do
|
|||
}, topic #{state.topic}"
|
||||
)
|
||||
|
||||
Pleroma.Web.Streamer.add_socket(state.topic, streamer_socket(state))
|
||||
Streamer.add_socket(state.topic, streamer_socket(state))
|
||||
{:ok, state}
|
||||
end
|
||||
|
||||
|
|
@ -80,7 +81,7 @@ defmodule Pleroma.Web.MastodonAPI.WebsocketHandler do
|
|||
}, topic #{state.topic || "?"}: #{inspect(reason)}"
|
||||
)
|
||||
|
||||
Pleroma.Web.Streamer.remove_socket(state.topic, streamer_socket(state))
|
||||
Streamer.remove_socket(state.topic, streamer_socket(state))
|
||||
:ok
|
||||
end
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue