aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEgor Kislitsyn <egor@kislitsyn.com>2019-03-04 19:55:11 +0700
committerEgor Kislitsyn <egor@kislitsyn.com>2019-03-04 19:55:11 +0700
commiteb84de01439c4ee25f59390e5be4ffa7f36e01b8 (patch)
tree63c935841bf4063278baff298e00724a2db46794
parentdd5865535eb16f535ff996eb3dec5e947a905268 (diff)
downloadpleroma-eb84de01439c4ee25f59390e5be4ffa7f36e01b8.tar.gz
allow users to disable their own account
-rw-r--r--config/config.exs3
-rw-r--r--lib/mix/tasks/pleroma/user.ex20
-rw-r--r--lib/pleroma/activity.ex16
-rw-r--r--lib/pleroma/gopher/server.ex3
-rw-r--r--lib/pleroma/notification.ex32
-rw-r--r--lib/pleroma/user.ex64
-rw-r--r--lib/pleroma/user/info.ex9
-rw-r--r--lib/pleroma/web/activity_pub/activity_pub.ex1
-rw-r--r--lib/pleroma/web/admin_api/admin_api_controller.ex10
-rw-r--r--lib/pleroma/web/common_api/utils.ex4
-rw-r--r--lib/pleroma/web/mastodon_api/mastodon_api_controller.ex12
-rw-r--r--lib/pleroma/web/router.ex2
-rw-r--r--lib/pleroma/web/twitter_api/controllers/util_controller.ex11
-rw-r--r--lib/pleroma/web/twitter_api/twitter_api.ex20
-rw-r--r--lib/pleroma/web/twitter_api/twitter_api_controller.ex4
-rw-r--r--priv/repo/migrations/20190228121252_users_add_disabled_index.exs7
16 files changed, 167 insertions, 51 deletions
diff --git a/config/config.exs b/config/config.exs
index a620e7451..d9ed43dda 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -343,7 +343,8 @@ config :pleroma, Pleroma.Web.Federator.RetryQueue,
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: [
diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex
index 037e44716..297332bc4 100644
--- a/lib/mix/tasks/pleroma/user.ex
+++ b/lib/mix/tasks/pleroma/user.ex
@@ -23,7 +23,7 @@ defmodule Mix.Tasks.Pleroma.User do
- `--password PASSWORD` - the user's password
- `--moderator`/`--no-moderator` - whether the user is a moderator
- `--admin`/`--no-admin` - whether the user is an admin
- - `-y`, `--assume-yes`/`--no-assume-yes` - whether to assume yes to all questions
+ - `-y`, `--assume-yes`/`--no-assume-yes` - whether to assume yes to all questions
## Generate an invite link.
@@ -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 @@ defmodule Mix.Tasks.Pleroma.User 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()
diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex
index 66854dc2d..c466bff7f 100644
--- a/lib/pleroma/activity.ex
+++ b/lib/pleroma/activity.ex
@@ -42,7 +42,10 @@ defmodule Pleroma.Activity 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 @@ defmodule Pleroma.Activity 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 @@ defmodule Pleroma.Activity 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
diff --git a/lib/pleroma/gopher/server.ex b/lib/pleroma/gopher/server.ex
index ba9614029..24190574e 100644
--- a/lib/pleroma/gopher/server.ex
+++ b/lib/pleroma/gopher/server.ex
@@ -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 @@ defmodule Pleroma.Gopher.Server.ProtocolHandler 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"])
diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex
index c88512567..0f9f74b1e 100644
--- a/lib/pleroma/notification.ex
+++ b/lib/pleroma/notification.ex
@@ -36,22 +36,22 @@ defmodule Pleroma.Notification 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
- )
-
- query =
- query
- |> restrict_since(opts)
- |> restrict_max(opts)
-
- Repo.all(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,
+ where:
+ fragment(
+ "? not in (SELECT ap_id FROM users WHERE info->'disabled' @> 'true')",
+ activity.actor
+ )
+ )
+ |> restrict_since(opts)
+ |> restrict_max(opts)
+ |> Repo.all()
end
def set_read_up_to(%{id: user_id} = _user, id) do
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index 50e7e7ccd..f02051174 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -108,10 +108,8 @@ defmodule Pleroma.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 @@ defmodule Pleroma.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 @@ defmodule Pleroma.User do
where: fragment("? <@ ?", ^[follower_address], u.following),
where: u.id != ^id
)
+ |> restrict_disabled()
end
def get_followers_query(user, page) do
@@ -572,6 +588,7 @@ defmodule Pleroma.User 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 @@ defmodule Pleroma.User do
info_cng = User.Info.set_note_count(user.info, note_count)
- 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_follower_count(%User{} = user) do
@@ -694,6 +710,7 @@ defmodule Pleroma.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 @@ defmodule Pleroma.User do
^processed_query
)
)
+ |> restrict_disabled()
end
defp trigram_search_subquery(term) do
@@ -876,6 +894,7 @@ defmodule Pleroma.User 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 @@ defmodule Pleroma.User do
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 delete(%User{} = user) do
@@ -1100,6 +1118,26 @@ defmodule Pleroma.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
diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex
index 818b64645..1ec356ba9 100644
--- a/lib/pleroma/user/info.ex
+++ b/lib/pleroma/user/info.ex
@@ -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 @@ defmodule Pleroma.User.Info 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
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index 783491b67..aa20990f3 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -703,6 +703,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|> restrict_replies(opts)
|> restrict_reblogs(opts)
|> restrict_pinned(opts)
+ |> Activity.restrict_disabled_users()
end
def fetch_activities(recipients, opts \\ %{}) do
diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex
index aae02cab8..1b94f0609 100644
--- a/lib/pleroma/web/admin_api/admin_api_controller.ex
+++ b/lib/pleroma/web/admin_api/admin_api_controller.ex
@@ -44,6 +44,16 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|> 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)
diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex
index e4b9102c5..60d1185d3 100644
--- a/lib/pleroma/web/common_api/utils.ex
+++ b/lib/pleroma/web/common_api/utils.ex
@@ -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 @@ defmodule Pleroma.Web.CommonAPI.Utils 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
diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
index 056be49b0..00a0f1351 100644
--- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
+++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
@@ -307,7 +307,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController 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 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController 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 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController 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 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController 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 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController 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 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController 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)
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index 6fcb46878..5033b5446 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -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
diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex
index e2fdedb25..0006d53e8 100644
--- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex
+++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex
@@ -311,6 +311,17 @@ defmodule Pleroma.Web.TwitterAPI.UtilController 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
diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex
index ab6470d78..615a34be9 100644
--- a/lib/pleroma/web/twitter_api/twitter_api.ex
+++ b/lib/pleroma/web/twitter_api/twitter_api.ex
@@ -21,7 +21,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI 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 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI 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
_ ->
diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex
index de7b9f24c..0769f8698 100644
--- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex
+++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex
@@ -269,7 +269,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller 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 @@ defmodule Pleroma.Web.TwitterAPI.Controller 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
diff --git a/priv/repo/migrations/20190228121252_users_add_disabled_index.exs b/priv/repo/migrations/20190228121252_users_add_disabled_index.exs
new file mode 100644
index 000000000..7b921d3e7
--- /dev/null
+++ b/priv/repo/migrations/20190228121252_users_add_disabled_index.exs
@@ -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