pleroma/lib/pleroma/web/admin_api/controllers/user_controller.ex

373 lines
9.2 KiB
Elixir
Raw Normal View History

2020-09-21 12:01:03 +00:00
# Pleroma: A lightweight social networking server
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
2020-09-21 12:01:03 +00:00
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.AdminAPI.UserController do
use Pleroma.Web, :controller
import Pleroma.Web.ControllerHelper,
only: [fetch_integer_param: 3]
alias Pleroma.ModerationLog
alias Pleroma.User
alias Pleroma.Web.ActivityPub.Builder
alias Pleroma.Web.ActivityPub.Pipeline
alias Pleroma.Web.AdminAPI
alias Pleroma.Web.AdminAPI.Search
2020-10-22 09:04:23 +00:00
alias Pleroma.Web.Plugs.OAuthScopesPlug
2020-09-21 12:01:03 +00:00
@users_page_size 50
plug(Pleroma.Web.ApiSpec.CastAndValidate, replace_params: false)
2020-09-21 12:01:03 +00:00
plug(
OAuthScopesPlug,
%{scopes: ["admin:read:accounts"]}
when action in [:index, :show]
2020-09-21 12:01:03 +00:00
)
plug(
OAuthScopesPlug,
%{scopes: ["admin:write:accounts"]}
2020-09-21 12:01:03 +00:00
when action in [
:delete,
:create,
:toggle_activation,
:activate,
:deactivate,
:approve,
:suggest,
:unsuggest
2020-09-21 12:01:03 +00:00
]
)
plug(
OAuthScopesPlug,
%{scopes: ["admin:write:follows"]}
2020-09-21 12:01:03 +00:00
when action in [:follow, :unfollow]
)
action_fallback(AdminAPI.FallbackController)
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.Admin.UserOperation
def delete(%{private: %{open_api_spex: %{params: %{nickname: nickname}}}} = conn, _) do
conn
|> do_deletes([nickname])
2020-09-21 12:01:03 +00:00
end
def delete(
%{
private: %{open_api_spex: %{body_params: %{nicknames: nicknames}}}
} = conn,
_
) do
conn
|> do_deletes(nicknames)
end
defp do_deletes(%{assigns: %{user: admin}} = conn, nicknames) when is_list(nicknames) do
2020-09-21 12:01:03 +00:00
users = Enum.map(nicknames, &User.get_cached_by_nickname/1)
Enum.each(users, fn user ->
{:ok, delete_data, _} = Builder.delete(admin, user.ap_id)
Pipeline.common_pipeline(delete_data, local: true)
end)
ModerationLog.insert_log(%{
actor: admin,
subject: users,
action: "delete"
})
json(conn, nicknames)
end
def follow(
%{
assigns: %{user: admin},
private: %{
open_api_spex: %{
body_params: %{
follower: follower_nick,
followed: followed_nick
}
}
}
} = conn,
_
) do
2020-09-21 12:01:03 +00:00
with %User{} = follower <- User.get_cached_by_nickname(follower_nick),
%User{} = followed <- User.get_cached_by_nickname(followed_nick) do
User.follow(follower, followed)
ModerationLog.insert_log(%{
actor: admin,
followed: followed,
follower: follower,
action: "follow"
})
end
json(conn, "ok")
end
def unfollow(
%{
assigns: %{user: admin},
private: %{
open_api_spex: %{
body_params: %{
follower: follower_nick,
followed: followed_nick
}
}
}
} = conn,
_
) do
2020-09-21 12:01:03 +00:00
with %User{} = follower <- User.get_cached_by_nickname(follower_nick),
%User{} = followed <- User.get_cached_by_nickname(followed_nick) do
User.unfollow(follower, followed)
ModerationLog.insert_log(%{
actor: admin,
followed: followed,
follower: follower,
action: "unfollow"
})
end
json(conn, "ok")
end
def create(
%{
assigns: %{user: admin},
private: %{open_api_spex: %{body_params: %{users: users}}}
} = conn,
_
) do
2020-09-21 12:01:03 +00:00
changesets =
users
|> Enum.map(fn %{nickname: nickname, email: email, password: password} ->
2020-09-21 12:01:03 +00:00
user_data = %{
nickname: nickname,
name: nickname,
email: email,
password: password,
password_confirmation: password,
bio: "."
}
User.register_changeset(%User{}, user_data, need_confirmation: false)
end)
|> Enum.reduce(Ecto.Multi.new(), fn changeset, multi ->
Ecto.Multi.insert(multi, Ecto.UUID.generate(), changeset)
end)
case Pleroma.Repo.transaction(changesets) do
{:ok, users_map} ->
users =
users_map
2020-09-21 12:01:03 +00:00
|> Map.values()
|> Enum.map(fn user ->
{:ok, user} = User.post_register_action(user)
user
end)
ModerationLog.insert_log(%{
actor: admin,
subjects: users,
2020-09-21 12:01:03 +00:00
action: "create"
})
render(conn, "created_many.json", users: users)
2020-09-21 12:01:03 +00:00
{:error, id, changeset, _} ->
changesets =
2020-09-21 12:01:03 +00:00
Enum.map(changesets.operations, fn
{^id, {:changeset, _current_changeset, _}} ->
changeset
2020-09-21 12:01:03 +00:00
{_, {:changeset, current_changeset, _}} ->
current_changeset
2020-09-21 12:01:03 +00:00
end)
conn
|> put_status(:conflict)
|> render("create_errors.json", changesets: changesets)
2020-09-21 12:01:03 +00:00
end
end
def show(
%{
assigns: %{user: admin},
private: %{open_api_spex: %{params: %{nickname: nickname}}}
} = conn,
_
) do
2020-09-21 12:01:03 +00:00
with %User{} = user <- User.get_cached_by_nickname_or_id(nickname, for: admin) do
render(conn, "show.json", %{user: user})
2020-09-21 12:01:03 +00:00
else
_ -> {:error, :not_found}
end
end
def toggle_activation(
%{assigns: %{user: admin}, private: %{open_api_spex: %{params: %{nickname: nickname}}}} =
conn,
_
) do
2020-09-21 12:01:03 +00:00
user = User.get_cached_by_nickname(nickname)
{:ok, updated_user} = User.set_activation(user, !user.is_active)
2020-09-21 12:01:03 +00:00
action = if !user.is_active, do: "activate", else: "deactivate"
2020-09-21 12:01:03 +00:00
ModerationLog.insert_log(%{
actor: admin,
subject: [user],
action: action
})
render(conn, "show.json", user: updated_user)
2020-09-21 12:01:03 +00:00
end
def activate(
%{
assigns: %{user: admin},
private: %{open_api_spex: %{body_params: %{nicknames: nicknames}}}
} = conn,
_
) do
2020-09-21 12:01:03 +00:00
users = Enum.map(nicknames, &User.get_cached_by_nickname/1)
{:ok, updated_users} = User.set_activation(users, true)
2020-09-21 12:01:03 +00:00
ModerationLog.insert_log(%{
actor: admin,
subject: users,
action: "activate"
})
Pleroma.Web.AdminAPI.UserController: dialyzer errors lib/pleroma/web/admin_api/controllers/user_controller.ex:205:no_return Function activate/2 has no local return. ________________________________________________________________________________ lib/pleroma/web/admin_api/controllers/user_controller.ex:215:call The function call will not succeed. Keyword.values( _updated_users :: %Pleroma.User{ :__meta__ => _, :accepts_chat_messages => _, :actor_type => _, :allow_following_move => _, :also_known_as => _, :ap_id => _, :avatar => _, :background => _, :banner => _, :bio => _, :birthday => _, :blocked_users => _, :blockee_blocks => _, :blocker_blocks => _, :blocker_users => _, :blocks => _, :confirmation_token => _, :default_scope => _, :deliveries => _, :disclose_client => _, :domain_blocks => _, :email => _, :email_notifications => _, :emoji => _, :endorsed_users => _, :endorsee_endorsements => _, :endorser_endorsements => _, :endorser_users => _, :featured_address => _, :fields => _, :follower_address => _, :follower_count => _, :following_address => _, :following_count => _, :hide_favorites => _, :hide_followers => _, :hide_followers_count => _, :hide_follows => _, :hide_follows_count => _, :id => _, :inbox => _, :incoming_relationships => _, :inserted_at => _, :invisible => _, :is_active => _, :is_admin => _, :is_approved => _, :is_confirmed => _, :is_discoverable => _, :is_locked => _, :is_moderator => _, :is_suggested => _, :keys => _, :language => _, :last_active_at => _, :last_digest_emailed_at => _, :last_refreshed_at => _, :last_status_at => _, :local => _, :mascot => _, :multi_factor_authentication_settings => _, :muted_notifications => _, :muted_reblogs => _, :muted_users => _, :mutee_mutes => _, :muter_mutes => _, :muter_users => _, :mutes => _, :name => _, :nickname => _, :no_rich_text => _, :note_count => _, :notification_muted_users => _, :notification_mutee_mutes => _, :notification_muter_mutes => _, :notification_muter_users => _, :notification_settings => _, :notifications => _, :outgoing_relationships => _, :password => _, :password_confirmation => _, :password_hash => _, :password_reset_pending => _, :pinned_objects => _, :pleroma_settings_store => _, :public_key => _, :raw_bio => _, :raw_fields => _, :reblog_muted_users => _, :reblog_mutee_mutes => _, :reblog_muter_mutes => _, :reblog_muter_users => _, :registration_reason => _, :registrations => _, :search_rank => _, :search_type => _, :shared_inbox => _, :show_birthday => _, :show_role => _, :skip_thread_containment => _, :subscribee_subscriptions => _, :subscribee_users => _, :subscriber_subscriptions => _, :subscriber_users => _, :subscribers => _, :tags => _, :updated_at => _, :uri => _ } ) will never return since the success typing is: ([any()]) :: [any()] and the contract is (t()) :: [value()] ________________________________________________________________________________ lib/pleroma/web/admin_api/controllers/user_controller.ex:218:no_return Function deactivate/2 has no local return. ________________________________________________________________________________ lib/pleroma/web/admin_api/controllers/user_controller.ex:228:call The function call will not succeed. Keyword.values( _updated_users :: %Pleroma.User{ :__meta__ => _, :accepts_chat_messages => _, :actor_type => _, :allow_following_move => _, :also_known_as => _, :ap_id => _, :avatar => _, :background => _, :banner => _, :bio => _, :birthday => _, :blocked_users => _, :blockee_blocks => _, :blocker_blocks => _, :blocker_users => _, :blocks => _, :confirmation_token => _, :default_scope => _, :deliveries => _, :disclose_client => _, :domain_blocks => _, :email => _, :email_notifications => _, :emoji => _, :endorsed_users => _, :endorsee_endorsements => _, :endorser_endorsements => _, :endorser_users => _, :featured_address => _, :fields => _, :follower_address => _, :follower_count => _, :following_address => _, :following_count => _, :hide_favorites => _, :hide_followers => _, :hide_followers_count => _, :hide_follows => _, :hide_follows_count => _, :id => _, :inbox => _, :incoming_relationships => _, :inserted_at => _, :invisible => _, :is_active => _, :is_admin => _, :is_approved => _, :is_confirmed => _, :is_discoverable => _, :is_locked => _, :is_moderator => _, :is_suggested => _, :keys => _, :language => _, :last_active_at => _, :last_digest_emailed_at => _, :last_refreshed_at => _, :last_status_at => _, :local => _, :mascot => _, :multi_factor_authentication_settings => _, :muted_notifications => _, :muted_reblogs => _, :muted_users => _, :mutee_mutes => _, :muter_mutes => _, :muter_users => _, :mutes => _, :name => _, :nickname => _, :no_rich_text => _, :note_count => _, :notification_muted_users => _, :notification_mutee_mutes => _, :notification_muter_mutes => _, :notification_muter_users => _, :notification_settings => _, :notifications => _, :outgoing_relationships => _, :password => _, :password_confirmation => _, :password_hash => _, :password_reset_pending => _, :pinned_objects => _, :pleroma_settings_store => _, :public_key => _, :raw_bio => _, :raw_fields => _, :reblog_muted_users => _, :reblog_mutee_mutes => _, :reblog_muter_mutes => _, :reblog_muter_users => _, :registration_reason => _, :registrations => _, :search_rank => _, :search_type => _, :shared_inbox => _, :show_birthday => _, :show_role => _, :skip_thread_containment => _, :subscribee_subscriptions => _, :subscribee_users => _, :subscriber_subscriptions => _, :subscriber_users => _, :subscribers => _, :tags => _, :updated_at => _, :uri => _ } ) will never return since the success typing is: ([any()]) :: [any()] and the contract is (t()) :: [value()]
2024-01-28 21:58:23 +00:00
render(conn, "index.json", users: updated_users)
2020-09-21 12:01:03 +00:00
end
def deactivate(
%{
assigns: %{user: admin},
private: %{open_api_spex: %{body_params: %{nicknames: nicknames}}}
} = conn,
_
) do
2020-09-21 12:01:03 +00:00
users = Enum.map(nicknames, &User.get_cached_by_nickname/1)
{:ok, updated_users} = User.set_activation(users, false)
2020-09-21 12:01:03 +00:00
ModerationLog.insert_log(%{
actor: admin,
subject: users,
action: "deactivate"
})
Pleroma.Web.AdminAPI.UserController: dialyzer errors lib/pleroma/web/admin_api/controllers/user_controller.ex:205:no_return Function activate/2 has no local return. ________________________________________________________________________________ lib/pleroma/web/admin_api/controllers/user_controller.ex:215:call The function call will not succeed. Keyword.values( _updated_users :: %Pleroma.User{ :__meta__ => _, :accepts_chat_messages => _, :actor_type => _, :allow_following_move => _, :also_known_as => _, :ap_id => _, :avatar => _, :background => _, :banner => _, :bio => _, :birthday => _, :blocked_users => _, :blockee_blocks => _, :blocker_blocks => _, :blocker_users => _, :blocks => _, :confirmation_token => _, :default_scope => _, :deliveries => _, :disclose_client => _, :domain_blocks => _, :email => _, :email_notifications => _, :emoji => _, :endorsed_users => _, :endorsee_endorsements => _, :endorser_endorsements => _, :endorser_users => _, :featured_address => _, :fields => _, :follower_address => _, :follower_count => _, :following_address => _, :following_count => _, :hide_favorites => _, :hide_followers => _, :hide_followers_count => _, :hide_follows => _, :hide_follows_count => _, :id => _, :inbox => _, :incoming_relationships => _, :inserted_at => _, :invisible => _, :is_active => _, :is_admin => _, :is_approved => _, :is_confirmed => _, :is_discoverable => _, :is_locked => _, :is_moderator => _, :is_suggested => _, :keys => _, :language => _, :last_active_at => _, :last_digest_emailed_at => _, :last_refreshed_at => _, :last_status_at => _, :local => _, :mascot => _, :multi_factor_authentication_settings => _, :muted_notifications => _, :muted_reblogs => _, :muted_users => _, :mutee_mutes => _, :muter_mutes => _, :muter_users => _, :mutes => _, :name => _, :nickname => _, :no_rich_text => _, :note_count => _, :notification_muted_users => _, :notification_mutee_mutes => _, :notification_muter_mutes => _, :notification_muter_users => _, :notification_settings => _, :notifications => _, :outgoing_relationships => _, :password => _, :password_confirmation => _, :password_hash => _, :password_reset_pending => _, :pinned_objects => _, :pleroma_settings_store => _, :public_key => _, :raw_bio => _, :raw_fields => _, :reblog_muted_users => _, :reblog_mutee_mutes => _, :reblog_muter_mutes => _, :reblog_muter_users => _, :registration_reason => _, :registrations => _, :search_rank => _, :search_type => _, :shared_inbox => _, :show_birthday => _, :show_role => _, :skip_thread_containment => _, :subscribee_subscriptions => _, :subscribee_users => _, :subscriber_subscriptions => _, :subscriber_users => _, :subscribers => _, :tags => _, :updated_at => _, :uri => _ } ) will never return since the success typing is: ([any()]) :: [any()] and the contract is (t()) :: [value()] ________________________________________________________________________________ lib/pleroma/web/admin_api/controllers/user_controller.ex:218:no_return Function deactivate/2 has no local return. ________________________________________________________________________________ lib/pleroma/web/admin_api/controllers/user_controller.ex:228:call The function call will not succeed. Keyword.values( _updated_users :: %Pleroma.User{ :__meta__ => _, :accepts_chat_messages => _, :actor_type => _, :allow_following_move => _, :also_known_as => _, :ap_id => _, :avatar => _, :background => _, :banner => _, :bio => _, :birthday => _, :blocked_users => _, :blockee_blocks => _, :blocker_blocks => _, :blocker_users => _, :blocks => _, :confirmation_token => _, :default_scope => _, :deliveries => _, :disclose_client => _, :domain_blocks => _, :email => _, :email_notifications => _, :emoji => _, :endorsed_users => _, :endorsee_endorsements => _, :endorser_endorsements => _, :endorser_users => _, :featured_address => _, :fields => _, :follower_address => _, :follower_count => _, :following_address => _, :following_count => _, :hide_favorites => _, :hide_followers => _, :hide_followers_count => _, :hide_follows => _, :hide_follows_count => _, :id => _, :inbox => _, :incoming_relationships => _, :inserted_at => _, :invisible => _, :is_active => _, :is_admin => _, :is_approved => _, :is_confirmed => _, :is_discoverable => _, :is_locked => _, :is_moderator => _, :is_suggested => _, :keys => _, :language => _, :last_active_at => _, :last_digest_emailed_at => _, :last_refreshed_at => _, :last_status_at => _, :local => _, :mascot => _, :multi_factor_authentication_settings => _, :muted_notifications => _, :muted_reblogs => _, :muted_users => _, :mutee_mutes => _, :muter_mutes => _, :muter_users => _, :mutes => _, :name => _, :nickname => _, :no_rich_text => _, :note_count => _, :notification_muted_users => _, :notification_mutee_mutes => _, :notification_muter_mutes => _, :notification_muter_users => _, :notification_settings => _, :notifications => _, :outgoing_relationships => _, :password => _, :password_confirmation => _, :password_hash => _, :password_reset_pending => _, :pinned_objects => _, :pleroma_settings_store => _, :public_key => _, :raw_bio => _, :raw_fields => _, :reblog_muted_users => _, :reblog_mutee_mutes => _, :reblog_muter_mutes => _, :reblog_muter_users => _, :registration_reason => _, :registrations => _, :search_rank => _, :search_type => _, :shared_inbox => _, :show_birthday => _, :show_role => _, :skip_thread_containment => _, :subscribee_subscriptions => _, :subscribee_users => _, :subscriber_subscriptions => _, :subscriber_users => _, :subscribers => _, :tags => _, :updated_at => _, :uri => _ } ) will never return since the success typing is: ([any()]) :: [any()] and the contract is (t()) :: [value()]
2024-01-28 21:58:23 +00:00
render(conn, "index.json", users: updated_users)
2020-09-21 12:01:03 +00:00
end
def approve(
%{
assigns: %{user: admin},
private: %{open_api_spex: %{body_params: %{nicknames: nicknames}}}
} = conn,
_
) do
2020-09-21 12:01:03 +00:00
users = Enum.map(nicknames, &User.get_cached_by_nickname/1)
{:ok, updated_users} = User.approve(users)
ModerationLog.insert_log(%{
actor: admin,
subject: users,
action: "approve"
})
render(conn, "index.json", users: updated_users)
2020-09-21 12:01:03 +00:00
end
def suggest(
%{
assigns: %{user: admin},
private: %{open_api_spex: %{body_params: %{nicknames: nicknames}}}
} = conn,
_
) do
users = Enum.map(nicknames, &User.get_cached_by_nickname/1)
{:ok, updated_users} = User.set_suggestion(users, true)
ModerationLog.insert_log(%{
actor: admin,
subject: users,
action: "add_suggestion"
})
render(conn, "index.json", users: updated_users)
end
def unsuggest(
%{
assigns: %{user: admin},
private: %{open_api_spex: %{body_params: %{nicknames: nicknames}}}
} = conn,
_
) do
users = Enum.map(nicknames, &User.get_cached_by_nickname/1)
{:ok, updated_users} = User.set_suggestion(users, false)
ModerationLog.insert_log(%{
actor: admin,
subject: users,
action: "remove_suggestion"
})
render(conn, "index.json", users: updated_users)
end
def index(%{private: %{open_api_spex: %{params: params}}} = conn, _) do
2020-09-21 12:01:03 +00:00
{page, page_size} = page_params(params)
filters = maybe_parse_filters(params[:filters])
2020-09-21 12:01:03 +00:00
search_params =
%{
query: params[:query],
2020-09-21 12:01:03 +00:00
page: page,
page_size: page_size,
tags: params[:tags],
name: params[:name],
email: params[:email],
actor_types: params[:actor_types]
2020-09-21 12:01:03 +00:00
}
|> Map.merge(filters)
with {:ok, users, count} <- Search.user(search_params) do
render(conn, "index.json", users: users, count: count, page_size: page_size)
2020-09-21 12:01:03 +00:00
end
end
2020-09-25 06:39:49 +00:00
@filters ~w(local external active deactivated need_approval unconfirmed is_admin is_moderator)
2020-09-21 12:01:03 +00:00
@spec maybe_parse_filters(String.t()) :: %{required(String.t()) => true} | %{}
defp maybe_parse_filters(filters) when is_nil(filters) or filters == "", do: %{}
defp maybe_parse_filters(filters) do
filters
|> String.split(",")
|> Enum.filter(&Enum.member?(@filters, &1))
|> Map.new(&{String.to_existing_atom(&1), true})
end
defp page_params(params) do
{
fetch_integer_param(params, :page, 1),
fetch_integer_param(params, :page_size, @users_page_size)
2020-09-21 12:01:03 +00:00
}
end
end