alias Pleroma.Emoji
alias Pleroma.Filter
alias Pleroma.HTTP
- alias Pleroma.Notification
alias Pleroma.Object
alias Pleroma.Pagination
alias Pleroma.Plugs.RateLimiter
alias Pleroma.Web.MastodonAPI.ListView
alias Pleroma.Web.MastodonAPI.MastodonAPI
alias Pleroma.Web.MastodonAPI.MastodonView
- alias Pleroma.Web.MastodonAPI.NotificationView
alias Pleroma.Web.MastodonAPI.ReportView
alias Pleroma.Web.MastodonAPI.ScheduledActivityView
alias Pleroma.Web.MastodonAPI.StatusView
alias Pleroma.Web.OAuth.Authorization
alias Pleroma.Web.OAuth.Scopes
alias Pleroma.Web.OAuth.Token
+ alias Pleroma.Web.RichMedia
alias Pleroma.Web.TwitterAPI.TwitterAPI
alias Pleroma.Web.ControllerHelper
end)
|> Map.put(:emoji, user_info_emojis)
- info_cng = User.Info.profile_update(user.info, info_params)
+ changeset =
+ user
+ |> User.update_changeset(user_params)
+ |> User.change_info(&User.Info.profile_update(&1, info_params))
- with changeset <- User.update_changeset(user, user_params),
- changeset <- Changeset.put_embed(changeset, :info, info_cng),
- {:ok, user} <- User.update_and_set_cache(changeset) do
- if original_user != user do
- CommonAPI.update(user)
- end
+ with {:ok, user} <- User.update_and_set_cache(changeset) do
+ if original_user != user, do: CommonAPI.update(user)
json(
conn,
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 <- Changeset.change(user) |> Changeset.put_embed(:info, info_cng),
- {:ok, user} <- User.update_and_set_cache(changeset) do
- CommonAPI.update(user)
+ new_info = %{"banner" => %{}}
+ with {:ok, user} <- User.update_info(user, &User.Info.profile_update(&1, new_info)) 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 <- Changeset.change(user) |> Changeset.put_embed(:info, info_cng),
- {:ok, user} <- User.update_and_set_cache(changeset) do
+ {:ok, user} <- User.update_info(user, &User.Info.profile_update(&1, new_info)) do
CommonAPI.update(user)
%{"url" => [%{"href" => href} | _]} = object.data
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 <- Changeset.change(user) |> Changeset.put_embed(:info, info_cng),
- {:ok, _user} <- User.update_and_set_cache(changeset) do
+ new_info = %{"background" => %{}}
+
+ with {:ok, _user} <- User.update_info(user, &User.Info.profile_update(&1, new_info)) 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 <- Changeset.change(user) |> Changeset.put_embed(:info, info_cng),
- {:ok, _user} <- User.update_and_set_cache(changeset) do
+ {:ok, _user} <- User.update_info(user, &User.Info.profile_update(&1, new_info)) do
%{"url" => [%{"href" => href} | _]} = object.data
json(conn, %{url: href})
grouped_activities <- Enum.group_by(activities, fn %{id: id} -> id < activity.id end) do
result = %{
ancestors:
- StatusView.render(
- "index.json",
+ StatusView.render("index.json",
for: user,
activities: grouped_activities[true] || [],
as: :activity
|> Enum.reverse(),
# credo:disable-for-previous-line Credo.Check.Refactor.PipeChainStart
descendants:
- StatusView.render(
- "index.json",
+ StatusView.render("index.json",
for: user,
activities: grouped_activities[false] || [],
as: :activity
end
end
- def notifications(%{assigns: %{user: user}} = conn, params) do
- notifications = MastodonAPI.get_notifications(user, params)
-
- conn
- |> add_link_headers(notifications)
- |> put_view(NotificationView)
- |> render("index.json", %{notifications: notifications, for: user})
- end
-
- def get_notification(%{assigns: %{user: user}} = conn, %{"id" => id} = _params) do
- with {:ok, notification} <- Notification.get(user, id) do
- conn
- |> put_view(NotificationView)
- |> render("show.json", %{notification: notification, for: user})
- else
- {:error, reason} ->
- conn
- |> put_status(:forbidden)
- |> json(%{"error" => reason})
- end
- end
-
- def clear_notifications(%{assigns: %{user: user}} = conn, _params) do
- Notification.clear(user)
- json(conn, %{})
- end
-
- def dismiss_notification(%{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
-
- def destroy_multiple(%{assigns: %{user: user}} = conn, %{"ids" => ids} = _params) do
- Notification.destroy_multiple(user, ids)
- json(conn, %{})
- end
-
def relationships(%{assigns: %{user: user}} = conn, %{"id" => id}) do
- id = List.wrap(id)
- q = from(u in User, where: u.id in ^id)
- targets = Repo.all(q)
+ targets = User.get_all_by_ids(List.wrap(id))
conn
|> put_view(AccountView)
# 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, [])
- def update_media(%{assigns: %{user: user}} = conn, data) do
- with %Object{} = object <- Repo.get(Object, data["id"]),
+ 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),
- true <- is_binary(data["description"]),
- description <- data["description"] do
- new_data = %{object.data | "name" => description}
-
- {:ok, _} =
- object
- |> Object.change(%{data: new_data})
- |> Repo.update()
-
- attachment_data = Map.put(new_data, "id", object.id)
+ {:ok, %Object{data: data}} <- Object.update_data(object, %{"name" => description}) do
+ attachment_data = Map.put(data, "id", object.id)
conn
|> put_view(StatusView)
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(
def set_mascot(%{assigns: %{user: user}} = conn, %{"file" => file}) do
with {:ok, object} <- ActivityPub.upload(file, actor: User.ap_id(user)),
%{} = attachment_data <- Map.put(object.data, "id", object.id),
- %{type: type} = rendered <-
+ # Reject if not an image
+ %{type: "image"} = rendered <-
StatusView.render("attachment.json", %{attachment: attachment_data}) do
- # Reject if not an image
- if type == "image" do
- # Sure!
- # Save to the user's info
- info_changeset = User.Info.mascot_update(user.info, rendered)
-
- user_changeset =
- user
- |> Changeset.change()
- |> Changeset.put_embed(:info, info_changeset)
+ # Sure!
+ # Save to the user's info
+ {:ok, _user} = User.update_info(user, &User.Info.mascot_update(&1, rendered))
- {:ok, _user} = User.update_and_set_cache(user_changeset)
-
- conn
- |> json(rendered)
- else
- render_error(conn, :unsupported_media_type, "mascots can only be images")
- end
+ json(conn, rendered)
+ else
+ %{type: _} -> render_error(conn, :unsupported_media_type, "mascots can only be images")
end
end
def get_mascot(%{assigns: %{user: user}} = conn, _params) do
mascot = User.get_mascot(user)
- conn
- |> json(mascot)
+ json(conn, mascot)
end
def favourited_by(%{assigns: %{user: user}} = conn, %{"id" => id}) do
end
def follow_requests(%{assigns: %{user: followed}} = conn, _params) do
- with {:ok, follow_requests} <- User.get_follow_requests(followed) do
- conn
- |> put_view(AccountView)
- |> render("accounts.json", %{for: followed, users: follow_requests, as: :user})
- end
+ follow_requests = User.get_follow_requests(followed)
+
+ conn
+ |> put_view(AccountView)
+ |> render("accounts.json", %{for: followed, users: follow_requests, as: :user})
end
def authorize_follow_request(%{assigns: %{user: followed}} = conn, %{"id" => id}) do
|> put_view(AccountView)
|> render("relationship.json", %{user: user, target: subscription_target})
else
- {:error, message} ->
- conn
- |> put_status(:forbidden)
- |> json(%{error: message})
+ nil -> {:error, :not_found}
+ e -> e
end
end
|> put_view(AccountView)
|> render("relationship.json", %{user: user, target: subscription_target})
else
- {:error, message} ->
- conn
- |> put_status(:forbidden)
- |> json(%{error: message})
+ nil -> {:error, :not_found}
+ e -> e
end
end
def account_lists(%{assigns: %{user: user}} = conn, %{"id" => account_id}) do
lists = Pleroma.List.get_lists_account_belongs(user, account_id)
- res = ListView.render("lists.json", lists: lists)
- json(conn, res)
+
+ conn
+ |> put_view(ListView)
+ |> render("index.json", %{lists: lists})
end
def list_timeline(%{assigns: %{user: user}} = conn, %{"list_id" => id} = params) do
end
def put_settings(%{assigns: %{user: user}} = conn, %{"data" => settings} = _params) do
- info_cng = User.Info.mastodon_settings_update(user.info, settings)
-
- with changeset <- Changeset.change(user),
- changeset <- Changeset.put_embed(changeset, :info, info_cng),
- {:ok, _user} <- User.update_and_set_cache(changeset) do
+ with {:ok, _} <- User.update_info(user, &User.Info.mastodon_settings_update(&1, settings)) do
json(conn, %{})
else
e ->
@doc "Local Mastodon FE login init action"
def login(conn, %{"code" => auth_token}) do
with {:ok, app} <- get_or_make_app(),
- %Authorization{} = auth <- Repo.get_by(Authorization, token: auth_token, app_id: app.id),
+ {:ok, auth} <- Authorization.get_by_token(app, auth_token),
{:ok, token} <- Token.exchange_token(app, auth) do
conn
|> put_session(:oauth_token, token.token)
def login(conn, _) do
with {:ok, app} <- get_or_make_app() do
path =
- o_auth_path(
- conn,
- :authorize,
+ o_auth_path(conn, :authorize,
response_type: "code",
client_id: app.client_id,
redirect_uri: ".",
end
end
+ @spec get_or_make_app() :: {:ok, App.t()} | {:error, Ecto.Changeset.t()}
defp get_or_make_app do
- find_attrs = %{client_name: @local_mastodon_name, redirect_uris: "."}
- scopes = ["read", "write", "follow", "push"]
-
- with %App{} = app <- Repo.get_by(App, find_attrs) do
- {:ok, app} =
- if app.scopes == scopes do
- {:ok, app}
- else
- app
- |> Changeset.change(%{scopes: scopes})
- |> Repo.update()
- end
-
- {:ok, app}
- else
- _e ->
- cs =
- App.register_changeset(
- %App{},
- Map.put(find_attrs, :scopes, scopes)
- )
-
- Repo.insert(cs)
- end
+ App.get_or_make(
+ %{client_name: @local_mastodon_name, redirect_uris: "."},
+ ["read", "write", "follow", "push"]
+ )
end
def logout(conn, _) do
|> redirect(to: "/")
end
- def relationship_noop(%{assigns: %{user: user}} = conn, %{"id" => id}) do
- Logger.debug("Unimplemented, returning unmodified relationship")
-
- with %User{} = target <- User.get_cached_by_id(id) do
- conn
- |> put_view(AccountView)
- |> render("relationship.json", %{user: user, target: target})
- end
- 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 get_filters(%{assigns: %{user: user}} = conn, _) do
filters = Filter.get_filters(user)
res = FilterView.render("filters.json", filters: filters)
end
end
- def status_card(%{assigns: %{user: user}} = conn, %{"id" => status_id}) do
- with %Activity{} = activity <- Activity.get_by_id(status_id),
+ def status_card(%{assigns: %{user: user}} = conn, %{"id" => id}) do
+ with %Activity{} = activity <- Activity.get_by_id(id),
true <- Visibility.visible_for_user?(activity, user) do
- data =
- StatusView.render(
- "card.json",
- Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity)
- )
+ data = RichMedia.Helpers.fetch_data_for_activity(activity)
- json(conn, data)
+ conn
+ |> put_view(StatusView)
+ |> render("card.json", data)
else
- _e ->
- %{}
+ _e -> {:error, :not_found}
end
end
end
end
- def account_register(%{assigns: %{app: _app}} = conn, _params) do
+ def account_register(%{assigns: %{app: _app}} = conn, _) do
render_error(conn, :bad_request, "Missing parameters")
end
end
end
- def try_render(conn, target, params)
- when is_binary(target) do
+ defp 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
+ defp try_render(conn, _, _) do
render_error(conn, :not_implemented, "Can't display this activity")
end