forked from YokaiRick/akkoma
allow users to disable their own account
This commit is contained in:
parent
dd5865535e
commit
eb84de0143
16 changed files with 167 additions and 51 deletions
|
@ -343,7 +343,8 @@
|
|||
config :pleroma, Pleroma.Jobs,
|
||||
federator_incoming: [max_jobs: 50],
|
||||
federator_outgoing: [max_jobs: 50],
|
||||
mailer: [max_jobs: 10]
|
||||
mailer: [max_jobs: 10],
|
||||
user: [max_jobs: 10]
|
||||
|
||||
config :auto_linker,
|
||||
opts: [
|
||||
|
|
|
@ -37,6 +37,10 @@ defmodule Mix.Tasks.Pleroma.User do
|
|||
|
||||
mix pleroma.user toggle_activated NICKNAME
|
||||
|
||||
## Disable or enable the user's account.
|
||||
|
||||
mix pleroma.user toggle_disabled NICKNAME
|
||||
|
||||
## Unsubscribe local users from user's account and deactivate it
|
||||
|
||||
mix pleroma.user unsubscribe NICKNAME
|
||||
|
@ -170,6 +174,20 @@ def run(["toggle_activated", nickname]) do
|
|||
end
|
||||
end
|
||||
|
||||
def run(["toggle_disabled", nickname]) do
|
||||
Common.start_pleroma()
|
||||
|
||||
case User.get_by_nickname(nickname) do
|
||||
%User{} = user ->
|
||||
{:ok, user} = User.disable(user, !user.info.disabled)
|
||||
status = if(user.info.disabled, do: "ON", else: "OFF")
|
||||
Mix.shell().info("Disabled status of #{nickname}: #{status}")
|
||||
|
||||
_ ->
|
||||
Mix.shell().error("No user #{nickname}")
|
||||
end
|
||||
end
|
||||
|
||||
def run(["reset_password", nickname]) do
|
||||
Common.start_pleroma()
|
||||
|
||||
|
|
|
@ -42,7 +42,10 @@ def get_by_ap_id(ap_id) do
|
|||
end
|
||||
|
||||
def get_by_id(id) do
|
||||
Repo.get(Activity, id)
|
||||
Activity
|
||||
|> where([a], a.id == ^id)
|
||||
|> restrict_disabled_users()
|
||||
|> Repo.one()
|
||||
end
|
||||
|
||||
def by_object_ap_id(ap_id) do
|
||||
|
@ -92,6 +95,7 @@ def get_all_create_by_object_ap_id(ap_id) do
|
|||
|
||||
def get_create_by_object_ap_id(ap_id) when is_binary(ap_id) do
|
||||
create_by_object_ap_id(ap_id)
|
||||
|> restrict_disabled_users()
|
||||
|> Repo.one()
|
||||
end
|
||||
|
||||
|
@ -123,4 +127,14 @@ def all_by_actor_and_id(actor, status_ids) do
|
|||
|> where([s], s.actor == ^actor)
|
||||
|> Repo.all()
|
||||
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
|
||||
|
|
|
@ -41,7 +41,6 @@ defmodule Pleroma.Gopher.Server.ProtocolHandler do
|
|||
alias Pleroma.Activity
|
||||
alias Pleroma.HTML
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Repo
|
||||
|
||||
def start_link(ref, socket, transport, opts) do
|
||||
pid = spawn_link(__MODULE__, :init, [ref, socket, transport, opts])
|
||||
|
@ -110,7 +109,7 @@ def response("/main/all") do
|
|||
end
|
||||
|
||||
def response("/notices/" <> id) do
|
||||
with %Activity{} = activity <- Repo.get(Activity, id),
|
||||
with %Activity{} = activity <- Activity.get_by_id(id),
|
||||
true <- Visibility.is_public?(activity) do
|
||||
activities =
|
||||
ActivityPub.fetch_activities_for_context(activity.data["context"])
|
||||
|
|
|
@ -36,22 +36,22 @@ defp restrict_since(query, %{"since_id" => since_id}) do
|
|||
defp restrict_since(query, _), do: query
|
||||
|
||||
def for_user(user, opts \\ %{}) do
|
||||
query =
|
||||
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
|
||||
limit: 20,
|
||||
where:
|
||||
fragment(
|
||||
"? not in (SELECT ap_id FROM users WHERE info->'disabled' @> 'true')",
|
||||
activity.actor
|
||||
)
|
||||
)
|
||||
|
||||
query =
|
||||
query
|
||||
|> restrict_since(opts)
|
||||
|> restrict_max(opts)
|
||||
|
||||
Repo.all(query)
|
||||
|> Repo.all()
|
||||
end
|
||||
|
||||
def set_read_up_to(%{id: user_id} = _user, id) do
|
||||
|
|
|
@ -108,10 +108,8 @@ def ap_followers(%User{} = user) do
|
|||
end
|
||||
|
||||
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,
|
||||
|
@ -120,6 +118,23 @@ def user_info(%User{} = user) do
|
|||
}
|
||||
end
|
||||
|
||||
defp restrict_disabled(query) do
|
||||
from(u in query,
|
||||
where: not fragment("? \\? 'disabled' AND ?->'disabled' @> 'true'", u.info, u.info)
|
||||
)
|
||||
end
|
||||
|
||||
def following_count(%User{following: []}), do: 0
|
||||
|
||||
def following_count(%User{following: following, id: id}) do
|
||||
from(u in User,
|
||||
where: u.follower_address in ^following,
|
||||
where: u.id != ^id
|
||||
)
|
||||
|> restrict_disabled()
|
||||
|> Repo.aggregate(:count, :id)
|
||||
end
|
||||
|
||||
def remote_user_creation(params) do
|
||||
params =
|
||||
params
|
||||
|
@ -545,6 +560,7 @@ def get_followers_query(%User{id: id, follower_address: follower_address}, nil)
|
|||
where: fragment("? <@ ?", ^[follower_address], u.following),
|
||||
where: u.id != ^id
|
||||
)
|
||||
|> restrict_disabled()
|
||||
end
|
||||
|
||||
def get_followers_query(user, page) do
|
||||
|
@ -572,6 +588,7 @@ def get_friends_query(%User{id: id, following: following}, nil) do
|
|||
where: u.follower_address in ^following,
|
||||
where: u.id != ^id
|
||||
)
|
||||
|> restrict_disabled()
|
||||
end
|
||||
|
||||
def get_friends_query(user, page) do
|
||||
|
@ -681,11 +698,10 @@ def update_note_count(%User{} = user) do
|
|||
|
||||
info_cng = User.Info.set_note_count(user.info, note_count)
|
||||
|
||||
cng =
|
||||
change(user)
|
||||
user
|
||||
|> change()
|
||||
|> put_embed(:info, info_cng)
|
||||
|
||||
update_and_set_cache(cng)
|
||||
|> update_and_set_cache()
|
||||
end
|
||||
|
||||
def update_follower_count(%User{} = user) do
|
||||
|
@ -694,6 +710,7 @@ def update_follower_count(%User{} = user) do
|
|||
|> where([u], ^user.follower_address in u.following)
|
||||
|> where([u], u.id != ^user.id)
|
||||
|> select([u], %{count: count(u.id)})
|
||||
|> restrict_disabled()
|
||||
|
||||
User
|
||||
|> where(id: ^user.id)
|
||||
|
@ -860,6 +877,7 @@ defp fts_search_subquery(term, query \\ User) do
|
|||
^processed_query
|
||||
)
|
||||
)
|
||||
|> restrict_disabled()
|
||||
end
|
||||
|
||||
defp trigram_search_subquery(term) do
|
||||
|
@ -876,6 +894,7 @@ defp trigram_search_subquery(term) do
|
|||
},
|
||||
where: fragment("trim(? || ' ' || coalesce(?, '')) % ?", u.nickname, u.name, ^term)
|
||||
)
|
||||
|> restrict_disabled()
|
||||
end
|
||||
|
||||
defp boost_search_results(results, nil), do: results
|
||||
|
@ -1062,11 +1081,10 @@ def moderator_user_query do
|
|||
def deactivate(%User{} = user, status \\ true) do
|
||||
info_cng = User.Info.set_activation_status(user.info, status)
|
||||
|
||||
cng =
|
||||
change(user)
|
||||
user
|
||||
|> change()
|
||||
|> put_embed(:info, info_cng)
|
||||
|
||||
update_and_set_cache(cng)
|
||||
|> update_and_set_cache()
|
||||
end
|
||||
|
||||
def delete(%User{} = user) do
|
||||
|
@ -1100,6 +1118,26 @@ def delete(%User{} = user) do
|
|||
{:ok, user}
|
||||
end
|
||||
|
||||
def disable_async(user, status \\ true) do
|
||||
Pleroma.Jobs.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
|
||||
|
|
|
@ -36,6 +36,7 @@ defmodule Pleroma.User.Info do
|
|||
field(:hide_follows, :boolean, default: false)
|
||||
field(:pinned_activities, {:array, :string}, default: [])
|
||||
field(:flavour, :string, default: nil)
|
||||
field(:disabled, :boolean, default: false)
|
||||
|
||||
# Found in the wild
|
||||
# ap_id -> Where is this used?
|
||||
|
@ -54,6 +55,14 @@ def set_activation_status(info, deactivated) do
|
|||
|> validate_required([:deactivated])
|
||||
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
|
||||
|
|
|
@ -703,6 +703,7 @@ def fetch_activities_query(recipients, opts \\ %{}) do
|
|||
|> restrict_replies(opts)
|
||||
|> restrict_reblogs(opts)
|
||||
|> restrict_pinned(opts)
|
||||
|> Activity.restrict_disabled_users()
|
||||
end
|
||||
|
||||
def fetch_activities(recipients, opts \\ %{}) do
|
||||
|
|
|
@ -44,6 +44,16 @@ def user_create(
|
|||
|> json(user.nickname)
|
||||
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)
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do
|
|||
|
||||
# This is a hack for twidere.
|
||||
def get_by_id_or_ap_id(id) do
|
||||
activity = Repo.get(Activity, id) || Activity.get_create_by_object_ap_id(id)
|
||||
activity = Activity.get_by_id(id) || Activity.get_create_by_object_ap_id(id)
|
||||
|
||||
activity &&
|
||||
if activity.data["type"] == "Create" do
|
||||
|
@ -30,7 +30,7 @@ def get_by_id_or_ap_id(id) do
|
|||
def get_replied_to_activity(""), do: nil
|
||||
|
||||
def get_replied_to_activity(id) when not is_nil(id) do
|
||||
Repo.get(Activity, id)
|
||||
Activity.get_by_id(id)
|
||||
end
|
||||
|
||||
def get_replied_to_activity(_), do: nil
|
||||
|
|
|
@ -307,7 +307,7 @@ def dm_timeline(%{assigns: %{user: user}} = conn, params) do
|
|||
end
|
||||
|
||||
def get_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do
|
||||
with %Activity{} = activity <- Repo.get(Activity, id),
|
||||
with %Activity{} = activity <- Activity.get_by_id(id),
|
||||
true <- Visibility.visible_for_user?(activity, user) do
|
||||
conn
|
||||
|> put_view(StatusView)
|
||||
|
@ -316,7 +316,7 @@ def get_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do
|
|||
end
|
||||
|
||||
def get_context(%{assigns: %{user: user}} = conn, %{"id" => id}) do
|
||||
with %Activity{} = activity <- Repo.get(Activity, id),
|
||||
with %Activity{} = activity <- Activity.get_by_id(id),
|
||||
activities <-
|
||||
ActivityPub.fetch_activities_for_context(activity.data["context"], %{
|
||||
"blocking_user" => user,
|
||||
|
@ -448,7 +448,7 @@ def unpin_status(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do
|
|||
end
|
||||
|
||||
def bookmark_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do
|
||||
with %Activity{} = activity <- Repo.get(Activity, id),
|
||||
with %Activity{} = activity <- Activity.get_by_id(id),
|
||||
%User{} = user <- User.get_by_nickname(user.nickname),
|
||||
true <- Visibility.visible_for_user?(activity, user),
|
||||
{:ok, user} <- User.bookmark(user, activity.data["object"]["id"]) do
|
||||
|
@ -459,7 +459,7 @@ def bookmark_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do
|
|||
end
|
||||
|
||||
def unbookmark_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do
|
||||
with %Activity{} = activity <- Repo.get(Activity, id),
|
||||
with %Activity{} = activity <- Activity.get_by_id(id),
|
||||
%User{} = user <- User.get_by_nickname(user.nickname),
|
||||
true <- Visibility.visible_for_user?(activity, user),
|
||||
{:ok, user} <- User.unbookmark(user, activity.data["object"]["id"]) do
|
||||
|
@ -583,7 +583,7 @@ def upload(%{assigns: %{user: user}} = conn, %{"file" => file} = data) do
|
|||
end
|
||||
|
||||
def favourited_by(conn, %{"id" => id}) do
|
||||
with %Activity{data: %{"object" => %{"likes" => likes}}} <- Repo.get(Activity, id) do
|
||||
with %Activity{data: %{"object" => %{"likes" => likes}}} <- Activity.get_by_id(id) do
|
||||
q = from(u in User, where: u.ap_id in ^likes)
|
||||
users = Repo.all(q)
|
||||
|
||||
|
@ -596,7 +596,7 @@ def favourited_by(conn, %{"id" => id}) do
|
|||
end
|
||||
|
||||
def reblogged_by(conn, %{"id" => id}) do
|
||||
with %Activity{data: %{"object" => %{"announcements" => announces}}} <- Repo.get(Activity, id) do
|
||||
with %Activity{data: %{"object" => %{"announcements" => announces}}} <- Activity.get_by_id(id) do
|
||||
q = from(u in User, where: u.ap_id in ^announces)
|
||||
users = Repo.all(q)
|
||||
|
||||
|
|
|
@ -143,6 +143,7 @@ defmodule Pleroma.Web.Router do
|
|||
get("/users/search", AdminAPIController, :search_users)
|
||||
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)
|
||||
|
@ -183,6 +184,7 @@ defmodule Pleroma.Web.Router do
|
|||
|
||||
post("/change_password", UtilController, :change_password)
|
||||
post("/delete_account", UtilController, :delete_account)
|
||||
post("/disable_account", UtilController, :disable_account)
|
||||
end
|
||||
|
||||
scope [] do
|
||||
|
|
|
@ -311,6 +311,17 @@ def delete_account(%{assigns: %{user: user}} = conn, params) do
|
|||
end
|
||||
end
|
||||
|
||||
def disable_account(%{assigns: %{user: user}} = conn, params) do
|
||||
case CommonAPI.Utils.confirm_current_password(user, params["password"]) do
|
||||
{:ok, user} ->
|
||||
User.disable_async(user)
|
||||
json(conn, %{status: "success"})
|
||||
|
||||
{:error, msg} ->
|
||||
json(conn, %{error: msg})
|
||||
end
|
||||
end
|
||||
|
||||
def captcha(conn, _params) do
|
||||
json(conn, Pleroma.Captcha.new())
|
||||
end
|
||||
|
|
|
@ -21,7 +21,7 @@ def create_status(%User{} = user, %{"status" => _} = data) do
|
|||
end
|
||||
|
||||
def delete(%User{} = user, id) do
|
||||
with %Activity{data: %{"type" => _type}} <- Repo.get(Activity, id),
|
||||
with %Activity{data: %{"type" => _type}} <- Activity.get_by_id(id),
|
||||
{:ok, activity} <- CommonAPI.delete(id, user) do
|
||||
{:ok, activity}
|
||||
end
|
||||
|
@ -232,21 +232,27 @@ def password_reset(nickname_or_email) do
|
|||
def get_user(user \\ nil, params) do
|
||||
case params do
|
||||
%{"user_id" => user_id} ->
|
||||
case target = User.get_cached_by_nickname_or_id(user_id) do
|
||||
case User.get_cached_by_nickname_or_id(user_id) do
|
||||
nil ->
|
||||
{:error, "No user with such user_id"}
|
||||
|
||||
_ ->
|
||||
{:ok, target}
|
||||
%User{info: %{disabled: true}} ->
|
||||
{:error, "User has been disabled"}
|
||||
|
||||
user ->
|
||||
{:ok, user}
|
||||
end
|
||||
|
||||
%{"screen_name" => nickname} ->
|
||||
case target = Repo.get_by(User, nickname: nickname) do
|
||||
case User.get_by_nickname(nickname) do
|
||||
nil ->
|
||||
{:error, "No user with such screen_name"}
|
||||
|
||||
_ ->
|
||||
{:ok, target}
|
||||
%User{info: %{disabled: true}} ->
|
||||
{:error, "User has been disabled"}
|
||||
|
||||
user ->
|
||||
{:ok, user}
|
||||
end
|
||||
|
||||
_ ->
|
||||
|
|
|
@ -269,7 +269,7 @@ def unfollow(%{assigns: %{user: user}} = conn, params) do
|
|||
end
|
||||
|
||||
def fetch_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do
|
||||
with %Activity{} = activity <- Repo.get(Activity, id),
|
||||
with %Activity{} = activity <- Activity.get_by_id(id),
|
||||
true <- Visibility.visible_for_user?(activity, user) do
|
||||
conn
|
||||
|> put_view(ActivityView)
|
||||
|
@ -341,7 +341,7 @@ def upload_json(%{assigns: %{user: user}} = conn, %{"media" => media}) do
|
|||
end
|
||||
|
||||
def get_by_id_or_ap_id(id) do
|
||||
activity = Repo.get(Activity, id) || Activity.get_create_by_object_ap_id(id)
|
||||
activity = Activity.get_by_id(id) || Activity.get_create_by_object_ap_id(id)
|
||||
|
||||
if activity.data["type"] == "Create" do
|
||||
activity
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
defmodule Pleroma.Repo.Migrations.UsersAddDisabledIndex do
|
||||
use Ecto.Migration
|
||||
|
||||
def change do
|
||||
create(index(:users, ["(info->'disabled')"], name: :users_disabled_index, using: :gin))
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue