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
alias Pleroma.Web.ControllerHelper
import Ecto.Query
require Logger
+ plug(
+ Pleroma.Plugs.RateLimitPlug,
+ %{
+ max_requests: Config.get([:app_account_creation, :max_requests]),
+ interval: Config.get([:app_account_creation, :interval])
+ }
+ when action in [:account_register]
+ )
+
@httpoison Application.get_env(:pleroma, :httpoison)
@local_mastodon_name "Mastodon-Local"
action_fallback(:errors)
def create_app(conn, params) do
- scopes = ControllerHelper.oauth_scopes(params, ["read"])
+ scopes = Scopes.fetch_scopes(params, ["read"])
app_attrs =
params
end
end
+ def update_avatar(%{assigns: %{user: user}} = conn, %{"img" => ""}) do
+ change = Changeset.change(user, %{avatar: nil})
+ {:ok, user} = User.update_and_set_cache(change)
+ CommonAPI.update(user)
+
+ json(conn, %{url: nil})
+ end
+
+ def update_avatar(%{assigns: %{user: user}} = conn, params) do
+ {:ok, object} = ActivityPub.upload(params, type: :avatar)
+ change = Changeset.change(user, %{avatar: object.data})
+ {:ok, user} = User.update_and_set_cache(change)
+ CommonAPI.update(user)
+ %{"url" => [%{"href" => href} | _]} = object.data
+
+ json(conn, %{url: href})
+ end
+
+ def update_banner(%{assigns: %{user: user}} = conn, %{"banner" => ""}) do
+ with new_info <- %{"banner" => %{}},
+ info_cng <- User.Info.profile_update(user.info, new_info),
+ changeset <- Ecto.Changeset.change(user) |> Ecto.Changeset.put_embed(:info, info_cng),
+ {:ok, user} <- User.update_and_set_cache(changeset) do
+ CommonAPI.update(user)
+
+ json(conn, %{url: nil})
+ end
+ end
+
+ def update_banner(%{assigns: %{user: user}} = conn, params) do
+ with {:ok, object} <- ActivityPub.upload(%{"img" => params["banner"]}, type: :banner),
+ new_info <- %{"banner" => object.data},
+ info_cng <- User.Info.profile_update(user.info, new_info),
+ changeset <- Ecto.Changeset.change(user) |> Ecto.Changeset.put_embed(:info, info_cng),
+ {:ok, user} <- User.update_and_set_cache(changeset) do
+ CommonAPI.update(user)
+ %{"url" => [%{"href" => href} | _]} = object.data
+
+ json(conn, %{url: href})
+ end
+ end
+
+ def update_background(%{assigns: %{user: user}} = conn, %{"img" => ""}) do
+ with new_info <- %{"background" => %{}},
+ info_cng <- User.Info.profile_update(user.info, new_info),
+ changeset <- Ecto.Changeset.change(user) |> Ecto.Changeset.put_embed(:info, info_cng),
+ {:ok, _user} <- User.update_and_set_cache(changeset) do
+ json(conn, %{url: nil})
+ end
+ end
+
+ def update_background(%{assigns: %{user: user}} = conn, params) do
+ with {:ok, object} <- ActivityPub.upload(params, type: :background),
+ new_info <- %{"background" => object.data},
+ info_cng <- User.Info.profile_update(user.info, new_info),
+ changeset <- Ecto.Changeset.change(user) |> Ecto.Changeset.put_embed(:info, info_cng),
+ {:ok, _user} <- User.update_and_set_cache(changeset) do
+ %{"url" => [%{"href" => href} | _]} = object.data
+
+ json(conn, %{url: href})
+ end
+ end
+
def verify_credentials(%{assigns: %{user: user}} = conn, _) do
account = AccountView.render("account.json", %{user: user, for: user})
json(conn, account)
end
end
- @mastodon_api_level "2.6.5"
+ @mastodon_api_level "2.7.2"
def masto_instance(conn, _params) do
instance = Config.get(:instance)
activities =
[user.ap_id | user.following]
|> ActivityPub.fetch_activities(params)
- |> ActivityPub.contain_timeline(user)
|> Enum.reverse()
conn
end
end
+ 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 <-
+ 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
+ |> Ecto.Changeset.change()
+ |> Ecto.Changeset.put_embed(:info, info_changeset)
+
+ {:ok, _user} = User.update_and_set_cache(user_changeset)
+
+ conn
+ |> json(rendered)
+ else
+ conn
+ |> put_resp_content_type("application/json")
+ |> send_resp(415, Jason.encode!(%{"error" => "mascots can only be images"}))
+ end
+ end
+ end
+
+ def get_mascot(%{assigns: %{user: user}} = conn, _params) do
+ mascot = User.get_mascot(user)
+
+ conn
+ |> json(mascot)
+ end
+
def favourited_by(%{assigns: %{user: user}} = conn, %{"id" => id}) do
with %Activity{data: %{"object" => object}} <- Repo.get(Activity, id),
%Object{data: %{"likes" => likes}} <- Object.normalize(object) do
end
end
+ def status_search_query_with_gin(q, query) do
+ from([a, o] in q,
+ where:
+ fragment(
+ "to_tsvector('english', ?->>'content') @@ plainto_tsquery('english', ?)",
+ o.data,
+ ^query
+ ),
+ order_by: [desc: :id]
+ )
+ end
+
+ def status_search_query_with_rum(q, query) do
+ from([a, o] in q,
+ where:
+ fragment(
+ "? @@ plainto_tsquery('english', ?)",
+ o.fts_content,
+ ^query
+ ),
+ order_by: [fragment("? <=> now()::date", o.inserted_at)]
+ )
+ end
+
def status_search(user, query) do
fetched =
if Regex.match?(~r/https?:/, query) do
end || []
q =
- from(
- [a, o] in Activity.with_preloaded_object(Activity),
+ from([a, o] in Activity.with_preloaded_object(Activity),
where: fragment("?->>'type' = 'Create'", a.data),
where: "https://www.w3.org/ns/activitystreams#Public" in a.recipients,
- where:
- fragment(
- "to_tsvector('english', ?->>'content') @@ plainto_tsquery('english', ?)",
- o.data,
- ^query
- ),
- limit: 20,
- order_by: [desc: :id]
+ limit: 20
)
+ q =
+ if Pleroma.Config.get([:database, :rum_enabled]) do
+ status_search_query_with_rum(q, query)
+ else
+ status_search_query_with_gin(q, query)
+ end
+
Repo.all(q) ++ fetched
end
accounts
|> Enum.each(fn account_id ->
with %Pleroma.List{} = list <- Pleroma.List.get(id, user),
- %User{} = followed <- Pleroma.User.get_cached_by_id(account_id) do
+ %User{} = followed <- User.get_cached_by_id(account_id) do
Pleroma.List.unfollow(list, followed)
end
end)
display_sensitive_media: false,
reduce_motion: false,
max_toot_chars: limit,
- mascot: "/images/pleroma-fox-tan-smol.png"
+ mascot: User.get_mascot(user)["url"]
},
rights: %{
delete_others_notice: present?(user.info.is_moderator),
user_id: user.id,
phrase: phrase,
context: context,
- hide: Map.get(params, "irreversible", nil),
+ hide: Map.get(params, "irreversible", false),
whole_word: Map.get(params, "boolean", true)
# expires_at
}
end
end
+ def account_register(
+ %{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} ->
+ conn
+ |> put_status(400)
+ |> json(Jason.encode!(errors))
+ end
+ end
+
+ def account_register(%{assigns: %{app: _app}} = conn, _params) do
+ conn
+ |> put_status(400)
+ |> json(%{error: "Missing parameters"})
+ end
+
+ def account_register(conn, _) do
+ conn
+ |> put_status(403)
+ |> json(%{error: "Invalid credentials"})
+ end
+
def conversations(%{assigns: %{user: user}} = conn, params) do
participations = Participation.for_user_with_last_activity_id(user, params)