initial_timeout: 30,
max_retries: 5
- config :pleroma, Pleroma.Jobs,
- federator_incoming: [max_jobs: 50],
- federator_outgoing: [max_jobs: 50],
- mailer: [max_jobs: 10],
- user: [max_jobs: 10]
+ config :pleroma_job_queue, :queues,
+ federator_incoming: 50,
+ federator_outgoing: 50,
+ web_push: 50,
+ mailer: 10,
+ transmogrifier: 20,
- scheduled_activities: 10
++ scheduled_activities: 10,
++ user: 10
+
+ config :pleroma, :fetch_initial_posts,
+ enabled: false,
+ pages: 5
config :auto_linker,
opts: [
)
end
+ def get_by_ap_id_with_object(ap_id) do
+ Repo.one(
+ from(
+ activity in Activity,
+ where: fragment("(?)->>'id' = ?", activity.data, ^to_string(ap_id)),
+ left_join: o in Object,
+ on:
+ fragment(
+ "(?->>'id') = COALESCE(?->'object'->>'id', ?->>'object')",
+ o.data,
+ activity.data,
+ activity.data
+ ),
+ preload: [object: o]
+ )
+ )
+ end
+
def get_by_id(id) do
- Repo.get(Activity, id)
+ Activity
+ |> where([a], a.id == ^id)
+ |> restrict_disabled_users()
+ |> Repo.one()
end
+ def get_by_id_with_object(id) do
+ from(activity in Activity,
+ where: activity.id == ^id,
+ inner_join: o in Object,
+ on:
+ fragment(
+ "(?->>'id') = COALESCE(?->'object'->>'id', ?->>'object')",
+ o.data,
+ activity.data,
+ activity.data
+ ),
+ preload: [object: o]
+ )
+ |> Repo.one()
+ end
+
def by_object_ap_id(ap_id) do
from(
activity in Activity,
|> Repo.all()
end
+ def increase_replies_count(id) do
+ Activity
+ |> where(id: ^id)
+ |> update([a],
+ set: [
+ data:
+ fragment(
+ """
+ jsonb_set(?, '{object, repliesCount}',
+ (coalesce((?->'object'->>'repliesCount')::int, 0) + 1)::varchar::jsonb, true)
+ """,
+ a.data,
+ a.data
+ )
+ ]
+ )
+ |> Repo.update_all([])
+ |> case do
+ {1, [activity]} -> activity
+ _ -> {:error, "Not found"}
+ end
+ end
+
+ def decrease_replies_count(id) do
+ Activity
+ |> where(id: ^id)
+ |> update([a],
+ set: [
+ data:
+ fragment(
+ """
+ jsonb_set(?, '{object, repliesCount}',
+ (greatest(0, (?->'object'->>'repliesCount')::int - 1))::varchar::jsonb, true)
+ """,
+ a.data,
+ a.data
+ )
+ ]
+ )
+ |> Repo.update_all([])
+ |> case do
+ {1, [activity]} -> activity
+ _ -> {:error, "Not found"}
+ end
+ end
++
+ def restrict_disabled_users(query) do
+ from(activity in query,
+ where:
+ fragment(
+ "? not in (SELECT ap_id FROM users WHERE info->'disabled' @> 'true')",
+ activity.actor
+ )
+ )
+ end
end
timestamps()
end
- # TODO: Make generic and unify (see activity_pub.ex)
- defp restrict_max(query, %{"max_id" => max_id}) do
- from(activity in query, where: activity.id < ^max_id)
- end
-
- defp restrict_max(query, _), do: query
-
- defp restrict_since(query, %{"since_id" => since_id}) do
- from(activity in query, where: activity.id > ^since_id)
+ def changeset(%Notification{} = notification, attrs) do
+ notification
+ |> cast(attrs, [:seen])
end
- defp restrict_since(query, _), do: query
-
- def for_user(user, opts \\ %{}) do
- from(
- n in Notification,
- where: n.user_id == ^user.id,
- order_by: [desc: n.id],
- join: activity in assoc(n, :activity),
- preload: [activity: activity],
- limit: 20,
- where:
+ def for_user_query(user) do
+ Notification
+ |> where(user_id: ^user.id)
++ |> where(
++ [n, a],
++ fragment(
++ "? not in (SELECT ap_id FROM users WHERE info->'disabled' @> 'true')",
++ a.actor
++ )
++ )
+ |> join(:inner, [n], activity in assoc(n, :activity))
+ |> join(:left, [n, a], object in Object,
+ on:
fragment(
- "? not in (SELECT ap_id FROM users WHERE info->'disabled' @> 'true')",
- activity.actor
+ "(?->>'id') = COALESCE((? -> 'object'::text) ->> 'id'::text)",
+ object.data,
+ a.data
)
)
- |> restrict_since(opts)
- |> restrict_max(opts)
- |> Repo.all()
+ |> preload([n, a, o], activity: {a, object: o})
+ end
+
+ def for_user(user, opts \\ %{}) do
+ user
+ |> for_user_query()
+ |> Pagination.fetch_paginated(opts)
end
def set_read_up_to(%{id: user_id} = _user, id) do
"#{Web.base_url()}/users/#{nickname}"
end
- def ap_followers(%User{} = user) do
- "#{ap_id(user)}/followers"
- end
+ def ap_followers(%User{follower_address: fa}) when is_binary(fa), do: fa
+ def ap_followers(%User{} = user), do: "#{ap_id(user)}/followers"
def user_info(%User{} = user) do
- oneself = if user.local, do: 1, else: 0
-
%{
- following_count: length(user.following) - oneself,
+ following_count: following_count(user),
note_count: user.info.note_count,
follower_count: user.info.follower_count,
locked: user.info.locked,
},
where: fragment("trim(? || ' ' || coalesce(?, '')) % ?", u.nickname, u.name, ^term)
)
+ |> restrict_disabled()
end
- defp boost_search_results(results, nil), do: results
-
- defp boost_search_results(results, for_user) do
- friends_ids = get_friends_ids(for_user)
- followers_ids = get_followers_ids(for_user)
-
- Enum.map(
- results,
- fn u ->
- search_rank_coef =
- cond do
- u.id in friends_ids ->
- 1.2
-
- u.id in followers_ids ->
- 1.1
-
- true ->
- 1
- end
-
- Map.put(u, :search_rank, u.search_rank * search_rank_coef)
- end
- )
- |> Enum.sort_by(&(-&1.search_rank))
- end
-
def blocks_import(%User{} = blocker, blocked_identifiers) when is_list(blocked_identifiers) do
Enum.map(
blocked_identifiers,
def deactivate(%User{} = user, status \\ true) do
info_cng = User.Info.set_activation_status(user.info, status)
- cng =
- change(user)
- |> put_embed(:info, info_cng)
-
- update_and_set_cache(cng)
+ user
+ |> change()
+ |> put_embed(:info, info_cng)
+ |> update_and_set_cache()
end
+ def update_notification_settings(%User{} = user, settings \\ %{}) do
+ info_changeset = User.Info.update_notification_settings(user.info, settings)
+
+ change(user)
+ |> put_embed(:info, info_changeset)
+ |> update_and_set_cache()
+ end
+
def delete(%User{} = user) do
{:ok, user} = User.deactivate(user)
{:ok, user}
end
- Pleroma.Jobs.enqueue(:user, __MODULE__, [:disable_async, user, status])
+ def disable_async(user, status \\ true) do
++ PleromaJobQueue.enqueue(:user, __MODULE__, [:disable_async, user, status])
+ end
+
+ def disable(%User{} = user, status \\ true) do
+ with {:ok, user} <- User.deactivate(user, status),
+ info_cng <- User.Info.set_disabled_status(user.info, status),
+ {:ok, user} <-
+ user
+ |> change()
+ |> put_embed(:info, info_cng)
+ |> update_and_set_cache(),
+ {:ok, friends} <- User.get_friends(user) do
+ Enum.each(friends, &update_follower_count(&1))
+ {:ok, user}
+ end
+ end
+
+ def perform(:disable_async, user, status), do: disable(user, status)
+
def html_filter_policy(%User{info: %{no_rich_text: true}}) do
Pleroma.HTML.Scrubber.TwitterText
end
field(:hide_follows, :boolean, default: false)
field(:pinned_activities, {:array, :string}, default: [])
field(:flavour, :string, default: nil)
+ field(:disabled, :boolean, default: false)
+ field(:notification_settings, :map,
+ default: %{"remote" => true, "local" => true, "followers" => true, "follows" => true}
+ )
+
# Found in the wild
# ap_id -> Where is this used?
# bio -> Where is this used?
|> validate_required([:deactivated])
end
+ def update_notification_settings(info, settings) do
+ notification_settings =
+ info.notification_settings
+ |> Map.merge(settings)
+ |> Map.take(["remote", "local", "followers", "follows"])
+
+ params = %{notification_settings: notification_settings}
+
+ info
+ |> cast(params, [:notification_settings])
+ |> validate_required([:notification_settings])
+ end
+
+ def set_disabled_status(info, disabled) do
+ params = %{disabled: disabled}
+
+ info
+ |> cast(params, [:disabled])
+ |> validate_required([:disabled])
+ end
+
def add_to_note_count(info, number) do
set_note_count(info, info.note_count + number)
end
|> restrict_replies(opts)
|> restrict_reblogs(opts)
|> restrict_pinned(opts)
+ |> restrict_muted_reblogs(opts)
+ |> Activity.restrict_disabled_users()
end
def fetch_activities(recipients, opts \\ %{}) do
|> json(user.nickname)
end
+ def user_show(conn, %{"nickname" => nickname}) do
+ with %User{} = user <- User.get_by_nickname(nickname) do
+ conn
+ |> json(AccountView.render("show.json", %{user: user}))
+ else
+ _ -> {:error, :not_found}
+ end
+ end
+
+ def user_toggle_disabled(conn, %{"nickname" => nickname}) do
+ user = User.get_by_nickname(nickname)
+
+ {:ok, updated_user} = User.disable(user, !user.info.disabled)
+
+ conn
+ |> put_view(AccountView)
+ |> render("show.json", %{user: updated_user})
+ end
+
def user_toggle_activation(conn, %{"nickname" => nickname}) do
user = User.get_by_nickname(nickname)
scope "/api/pleroma/admin", Pleroma.Web.AdminAPI do
pipe_through([:admin_api, :oauth_write])
+ post("/user/follow", AdminAPIController, :user_follow)
+ post("/user/unfollow", AdminAPIController, :user_unfollow)
+
get("/users", AdminAPIController, :list_users)
- get("/users/search", AdminAPIController, :search_users)
+ get("/users/:nickname", AdminAPIController, :user_show)
+
delete("/user", AdminAPIController, :user_delete)
patch("/users/:nickname/toggle_activation", AdminAPIController, :user_toggle_activation)
+ patch("/users/:nickname/toggle_disabled", AdminAPIController, :user_toggle_disabled)
post("/user", AdminAPIController, :user_create)
put("/users/tag", AdminAPIController, :tag_users)
delete("/users/tag", AdminAPIController, :untag_users)
post("/change_password", UtilController, :change_password)
post("/delete_account", UtilController, :delete_account)
+ put("/notification_settings", UtilController, :update_notificaton_settings)
+ post("/disable_account", UtilController, :disable_account)
end
scope [] do