- Pleroma API: Healthcheck endpoint
- Admin API: Endpoints for listing/revoking invite tokens
- Admin API: Endpoints for making users follow/unfollow each other
+- Admin API: added filters (role, tags, email, name) for users endpoint
- Mastodon API: [Scheduled statuses](https://docs.joinmastodon.org/api/rest/scheduled-statuses/)
- Mastodon API: `/api/v1/notifications/destroy_multiple` (glitch-soc extension)
- Mastodon API: `/api/v1/pleroma/accounts/:id/favourites` (API extension)
- Method `GET`
- Query Params:
- - *optional* `query`: **string** search term
+ - *optional* `query`: **string** search term (e.g. nickname, domain, nickname@domain)
- *optional* `filters`: **string** comma-separated string of filters:
- `local`: only local users
- `external`: only external users
- `active`: only active users
- `deactivated`: only deactivated users
+ - `is_admin`: users with admin role
+ - `is_moderator`: users with moderator role
- *optional* `page`: **integer** page number
- *optional* `page_size`: **integer** number of users per page (default is `50`)
-- Example: `https://mypleroma.org/api/pleroma/admin/users?query=john&filters=local,active&page=1&page_size=10`
+ - *optional* `tags`: **[string]** tags list
+ - *optional* `name`: **string** user display name
+ - *optional* `email`: **string** user email
+- Example: `https://mypleroma.org/api/pleroma/admin/users?query=john&filters=local,active&page=1&page_size=10&tags[]=some_tag&tags[]=another_tag&name=display_name&email=email@example.com`
- Response:
```JSON
|> Repo.all()
end
+ def follow_requests_for_actor(%Pleroma.User{ap_id: ap_id}) do
+ from(
+ a in Activity,
+ where:
+ fragment(
+ "? ->> 'type' = 'Follow'",
+ a.data
+ ),
+ where:
+ fragment(
+ "? ->> 'state' = 'pending'",
+ a.data
+ ),
+ where:
+ fragment(
+ "coalesce((?)->'object'->>'id', (?)->>'object') = ?",
+ a.data,
+ a.data,
+ ^ap_id
+ )
+ )
+ end
+
@spec query_by_actor(actor()) :: Ecto.Query.t()
def query_by_actor(actor) do
from(a in Activity, where: a.actor == ^actor)
def update_stats do
peers =
from(
- u in Pleroma.User,
+ u in User,
select: fragment("distinct split_part(?, '@', 2)", u.nickname),
where: u.local != ^true
)
domain_count = Enum.count(peers)
status_query =
- from(u in User.local_user_query(), select: fragment("sum((?->>'note_count')::int)", u.info))
+ from(u in User.Query.build(%{local: true}),
+ select: fragment("sum((?->>'note_count')::int)", u.info)
+ )
status_count = Repo.one(status_query)
- user_count = Repo.aggregate(User.active_local_user_query(), :count, :id)
+
+ user_count = Repo.aggregate(User.Query.build(%{local: true, active: true}), :count, :id)
Agent.update(__MODULE__, fn _ ->
{peers, %{domain_count: domain_count, status_count: status_count, user_count: user_count}}
candidates = Pleroma.Config.get([:instance, :autofollowed_nicknames])
autofollowed_users =
- from(u in User,
- where: u.local == true,
- where: u.nickname in ^candidates
- )
+ User.Query.build(%{nickname: candidates, local: true})
|> Repo.all()
follow_all(user, autofollowed_users)
)
end
- def get_followers_query(%User{id: id, follower_address: follower_address}, nil) do
- from(
- u in User,
- where: fragment("? <@ ?", ^[follower_address], u.following),
- where: u.id != ^id
- )
+ @spec get_followers_query(User.t(), pos_integer() | nil) :: Ecto.Query.t()
+ def get_followers_query(%User{} = user, nil) do
+ User.Query.build(%{followers: user})
end
def get_followers_query(user, page) do
from(u in get_followers_query(user, nil))
- |> paginate(page, 20)
+ |> User.Query.paginate(page, 20)
end
+ @spec get_followers_query(User.t()) :: Ecto.Query.t()
def get_followers_query(user), do: get_followers_query(user, nil)
def get_followers(user, page \\ nil) do
Repo.all(from(u in q, select: u.id))
end
- def get_friends_query(%User{id: id, following: following}, nil) do
- from(
- u in User,
- where: u.follower_address in ^following,
- where: u.id != ^id
- )
+ @spec get_friends_query(User.t(), pos_integer() | nil) :: Ecto.Query.t()
+ def get_friends_query(%User{} = user, nil) do
+ User.Query.build(%{friends: user})
end
def get_friends_query(user, page) do
from(u in get_friends_query(user, nil))
- |> paginate(page, 20)
+ |> User.Query.paginate(page, 20)
end
+ @spec get_friends_query(User.t()) :: Ecto.Query.t()
def get_friends_query(user), do: get_friends_query(user, nil)
def get_friends(user, page \\ nil) do
Repo.all(from(u in q, select: u.id))
end
- def get_follow_requests_query(%User{} = user) do
- from(
- a in Activity,
- where:
- fragment(
- "? ->> 'type' = 'Follow'",
- a.data
- ),
- where:
- fragment(
- "? ->> 'state' = 'pending'",
- a.data
- ),
- where:
- fragment(
- "coalesce((?)->'object'->>'id', (?)->>'object') = ?",
- a.data,
- a.data,
- ^user.ap_id
- )
- )
- end
-
+ @spec get_follow_requests(User.t()) :: {:ok, [User.t()]}
def get_follow_requests(%User{} = user) do
users =
- user
- |> User.get_follow_requests_query()
+ Activity.follow_requests_for_actor(user)
|> join(:inner, [a], u in User, on: a.actor == u.ap_id)
|> where([a, u], not fragment("? @> ?", u.following, ^[user.follower_address]))
|> group_by([a, u], u.id)
def update_follower_count(%User{} = user) do
follower_count_query =
- User
- |> where([u], ^user.follower_address in u.following)
- |> where([u], u.id != ^user.id)
- |> select([u], %{count: count(u.id)})
+ User.Query.build(%{followers: user}) |> select([u], %{count: count(u.id)})
User
|> where(id: ^user.id)
end
end
- def get_users_from_set_query(ap_ids, false) do
- from(
- u in User,
- where: u.ap_id in ^ap_ids
- )
- end
-
- def get_users_from_set_query(ap_ids, true) do
- query = get_users_from_set_query(ap_ids, false)
-
- from(
- u in query,
- where: u.local == true
- )
- end
-
+ @spec get_users_from_set([String.t()], boolean()) :: [User.t()]
def get_users_from_set(ap_ids, local_only \\ true) do
- get_users_from_set_query(ap_ids, local_only)
+ criteria = %{ap_id: ap_ids}
+ criteria = if local_only, do: Map.put(criteria, :local, true), else: criteria
+
+ User.Query.build(criteria)
|> Repo.all()
end
+ @spec get_recipients_from_activity(Activity.t()) :: [User.t()]
def get_recipients_from_activity(%Activity{recipients: to}) do
- query =
- from(
- u in User,
- where: u.ap_id in ^to,
- or_where: fragment("? && ?", u.following, ^to)
- )
-
- query = from(u in query, where: u.local == true)
-
- Repo.all(query)
+ User.Query.build(%{recipients_from_activity: to, local: true})
+ |> Repo.all()
end
def search(query, resolve \\ false, for_user \\ nil) do
end
end
- def muted_users(user),
- do: Repo.all(from(u in User, where: u.ap_id in ^user.info.mutes))
+ @spec muted_users(User.t()) :: [User.t()]
+ def muted_users(user) do
+ User.Query.build(%{ap_id: user.info.mutes})
+ |> Repo.all()
+ end
- def blocked_users(user),
- do: Repo.all(from(u in User, where: u.ap_id in ^user.info.blocks))
+ @spec blocked_users(User.t()) :: [User.t()]
+ def blocked_users(user) do
+ User.Query.build(%{ap_id: user.info.blocks})
+ |> Repo.all()
+ end
- def subscribers(user),
- do: Repo.all(from(u in User, where: u.ap_id in ^user.info.subscribers))
+ @spec subscribers(User.t()) :: [User.t()]
+ def subscribers(user) do
+ User.Query.build(%{ap_id: user.info.subscribers})
+ |> Repo.all()
+ end
def block_domain(user, domain) do
info_cng =
update_and_set_cache(cng)
end
- def maybe_local_user_query(query, local) do
- if local, do: local_user_query(query), else: query
- end
-
- def local_user_query(query \\ User) do
- from(
- u in query,
- where: u.local == true,
- where: not is_nil(u.nickname)
- )
- end
-
- def maybe_external_user_query(query, external) do
- if external, do: external_user_query(query), else: query
- end
-
- def external_user_query(query \\ User) do
- from(
- u in query,
- where: u.local == false,
- where: not is_nil(u.nickname)
- )
- end
-
- def maybe_active_user_query(query, active) do
- if active, do: active_user_query(query), else: query
- end
-
- def active_user_query(query \\ User) do
- from(
- u in query,
- where: fragment("not (?->'deactivated' @> 'true')", u.info),
- where: not is_nil(u.nickname)
- )
- end
-
- def maybe_deactivated_user_query(query, deactivated) do
- if deactivated, do: deactivated_user_query(query), else: query
- end
-
- def deactivated_user_query(query \\ User) do
- from(
- u in query,
- where: fragment("(?->'deactivated' @> 'true')", u.info),
- where: not is_nil(u.nickname)
- )
- end
-
- def active_local_user_query do
- from(
- u in local_user_query(),
- where: fragment("not (?->'deactivated' @> 'true')", u.info)
- )
- end
-
- def moderator_user_query do
- from(
- u in User,
- where: u.local == true,
- where: fragment("?->'is_moderator' @> 'true'", u.info)
- )
- end
-
def deactivate(%User{} = user, status \\ true) do
info_cng = User.Info.set_activation_status(user.info, status)
def ap_enabled?(_), do: false
@doc "Gets or fetch a user by uri or nickname."
- @spec get_or_fetch(String.t()) :: User.t()
+ @spec get_or_fetch(String.t()) :: {:ok, User.t()} | {:error, String.t()}
def get_or_fetch("http" <> _host = uri), do: get_or_fetch_by_ap_id(uri)
def get_or_fetch(nickname), do: get_or_fetch_by_nickname(nickname)
}
end
+ @spec all_superusers() :: [User.t()]
def all_superusers do
- from(
- u in User,
- where: u.local == true,
- where: fragment("?->'is_admin' @> 'true' OR ?->'is_moderator' @> 'true'", u.info, u.info)
- )
+ User.Query.build(%{super_users: true, local: true})
|> Repo.all()
end
- defp paginate(query, page, page_size) do
- from(u in query,
- limit: ^page_size,
- offset: ^((page - 1) * page_size)
- )
- end
-
def showing_reblogs?(%User{} = user, %User{} = target) do
target.ap_id not in user.info.muted_reblogs
end
--- /dev/null
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.User.Query do
+ @moduledoc """
+ User query builder module. Builds query from new query or another user query.
+
+ ## Example:
+ query = Pleroma.User.Query(%{nickname: "nickname"})
+ another_query = Pleroma.User.Query.build(query, %{email: "email@example.com"})
+ Pleroma.Repo.all(query)
+ Pleroma.Repo.all(another_query)
+
+ Adding new rules:
+ - *ilike criteria*
+ - add field to @ilike_criteria list
+ - pass non empty string
+ - e.g. Pleroma.User.Query.build(%{nickname: "nickname"})
+ - *equal criteria*
+ - add field to @equal_criteria list
+ - pass non empty string
+ - e.g. Pleroma.User.Query.build(%{email: "email@example.com"})
+ - *contains criteria*
+ - add field to @containns_criteria list
+ - pass values list
+ - e.g. Pleroma.User.Query.build(%{ap_id: ["http://ap_id1", "http://ap_id2"]})
+ """
+ import Ecto.Query
+ import Pleroma.Web.AdminAPI.Search, only: [not_empty_string: 1]
+ alias Pleroma.User
+
+ @type criteria ::
+ %{
+ query: String.t(),
+ tags: [String.t()],
+ name: String.t(),
+ email: String.t(),
+ local: boolean(),
+ external: boolean(),
+ active: boolean(),
+ deactivated: boolean(),
+ is_admin: boolean(),
+ is_moderator: boolean(),
+ super_users: boolean(),
+ followers: User.t(),
+ friends: User.t(),
+ recipients_from_activity: [String.t()],
+ nickname: [String.t()],
+ ap_id: [String.t()]
+ }
+ | %{}
+
+ @ilike_criteria [:nickname, :name, :query]
+ @equal_criteria [:email]
+ @role_criteria [:is_admin, :is_moderator]
+ @contains_criteria [:ap_id, :nickname]
+
+ @spec build(criteria()) :: Query.t()
+ def build(query \\ base_query(), criteria) do
+ prepare_query(query, criteria)
+ end
+
+ @spec paginate(Ecto.Query.t(), pos_integer(), pos_integer()) :: Ecto.Query.t()
+ def paginate(query, page, page_size) do
+ from(u in query,
+ limit: ^page_size,
+ offset: ^((page - 1) * page_size)
+ )
+ end
+
+ defp base_query do
+ from(u in User)
+ end
+
+ defp prepare_query(query, criteria) do
+ Enum.reduce(criteria, query, &compose_query/2)
+ end
+
+ defp compose_query({key, value}, query)
+ when key in @ilike_criteria and not_empty_string(value) do
+ # hack for :query key
+ key = if key == :query, do: :nickname, else: key
+ where(query, [u], ilike(field(u, ^key), ^"%#{value}%"))
+ end
+
+ defp compose_query({key, value}, query)
+ when key in @equal_criteria and not_empty_string(value) do
+ where(query, [u], ^[{key, value}])
+ end
+
+ defp compose_query({key, values}, query) when key in @contains_criteria and is_list(values) do
+ where(query, [u], field(u, ^key) in ^values)
+ end
+
+ defp compose_query({:tags, tags}, query) when is_list(tags) and length(tags) > 0 do
+ Enum.reduce(tags, query, &prepare_tag_criteria/2)
+ end
+
+ defp compose_query({key, _}, query) when key in @role_criteria do
+ where(query, [u], fragment("(?->? @> 'true')", u.info, ^to_string(key)))
+ end
+
+ defp compose_query({:super_users, _}, query) do
+ where(
+ query,
+ [u],
+ fragment("?->'is_admin' @> 'true' OR ?->'is_moderator' @> 'true'", u.info, u.info)
+ )
+ end
+
+ defp compose_query({:local, _}, query), do: location_query(query, true)
+
+ defp compose_query({:external, _}, query), do: location_query(query, false)
+
+ defp compose_query({:active, _}, query) do
+ where(query, [u], fragment("not (?->'deactivated' @> 'true')", u.info))
+ |> where([u], not is_nil(u.nickname))
+ end
+
+ defp compose_query({:deactivated, _}, query) do
+ where(query, [u], fragment("?->'deactivated' @> 'true'", u.info))
+ |> where([u], not is_nil(u.nickname))
+ end
+
+ defp compose_query({:followers, %User{id: id, follower_address: follower_address}}, query) do
+ where(query, [u], fragment("? <@ ?", ^[follower_address], u.following))
+ |> where([u], u.id != ^id)
+ end
+
+ defp compose_query({:friends, %User{id: id, following: following}}, query) do
+ where(query, [u], u.follower_address in ^following)
+ |> where([u], u.id != ^id)
+ end
+
+ defp compose_query({:recipients_from_activity, to}, query) do
+ where(query, [u], u.ap_id in ^to or fragment("? && ?", u.following, ^to))
+ end
+
+ defp compose_query(_unsupported_param, query), do: query
+
+ defp prepare_tag_criteria(tag, query) do
+ or_where(query, [u], fragment("? = any(?)", ^tag, u.tags))
+ end
+
+ defp location_query(query, local) do
+ where(query, [u], u.local == ^local)
+ |> where([u], not is_nil(u.nickname))
+ end
+end
search_params = %{
query: params["query"],
page: page,
- page_size: page_size
+ page_size: page_size,
+ tags: params["tags"],
+ name: params["name"],
+ email: params["email"]
}
with {:ok, users, count} <- Search.user(Map.merge(search_params, filters)),
)
end
- @filters ~w(local external active deactivated)
+ @filters ~w(local external active deactivated is_admin is_moderator)
+ @spec maybe_parse_filters(String.t()) :: %{required(String.t()) => true} | %{}
defp maybe_parse_filters(filters) when is_nil(filters) or filters == "", do: %{}
- @spec maybe_parse_filters(String.t()) :: %{required(String.t()) => true} | %{}
defp maybe_parse_filters(filters) do
filters
|> String.split(",")
@page_size 50
- def user(%{query: term} = params) when is_nil(term) or term == "" do
- query = maybe_filtered_query(params)
+ defmacro not_empty_string(string) do
+ quote do
+ is_binary(unquote(string)) and unquote(string) != ""
+ end
+ end
+
+ @spec user(map()) :: {:ok, [User.t()], pos_integer()}
+ def user(params \\ %{}) do
+ query = User.Query.build(params) |> order_by([u], u.nickname)
paginated_query =
- maybe_filtered_query(params)
- |> paginate(params[:page] || 1, params[:page_size] || @page_size)
+ User.Query.paginate(query, params[:page] || 1, params[:page_size] || @page_size)
- count = query |> Repo.aggregate(:count, :id)
+ count = Repo.aggregate(query, :count, :id)
results = Repo.all(paginated_query)
{:ok, results, count}
end
-
- def user(%{query: term} = params) when is_binary(term) do
- search_query = from(u in maybe_filtered_query(params), where: ilike(u.nickname, ^"%#{term}%"))
-
- count = search_query |> Repo.aggregate(:count, :id)
-
- results =
- search_query
- |> paginate(params[:page] || 1, params[:page_size] || @page_size)
- |> Repo.all()
-
- {:ok, results, count}
- end
-
- defp maybe_filtered_query(params) do
- from(u in User, order_by: u.nickname)
- |> User.maybe_local_user_query(params[:local])
- |> User.maybe_external_user_query(params[:external])
- |> User.maybe_active_user_query(params[:active])
- |> User.maybe_deactivated_user_query(params[:deactivated])
- end
-
- defp paginate(query, page, page_size) do
- from(u in query,
- limit: ^page_size,
- offset: ^((page - 1) * page_size)
- )
- end
end
end
describe "GET /api/pleroma/admin/users" do
- test "renders users array for the first page" do
+ setup do
admin = insert(:user, info: %{is_admin: true})
- user = insert(:user, local: false, tags: ["foo", "bar"])
conn =
build_conn()
|> assign(:user, admin)
- |> get("/api/pleroma/admin/users?page=1")
+
+ {:ok, conn: conn, admin: admin}
+ end
+
+ test "renders users array for the first page", %{conn: conn, admin: admin} do
+ user = insert(:user, local: false, tags: ["foo", "bar"])
+ conn = get(conn, "/api/pleroma/admin/users?page=1")
assert json_response(conn, 200) == %{
"count" => 2,
}
end
- test "renders empty array for the second page" do
- admin = insert(:user, info: %{is_admin: true})
+ test "renders empty array for the second page", %{conn: conn} do
insert(:user)
- conn =
- build_conn()
- |> assign(:user, admin)
- |> get("/api/pleroma/admin/users?page=2")
+ conn = get(conn, "/api/pleroma/admin/users?page=2")
assert json_response(conn, 200) == %{
"count" => 2,
}
end
- test "regular search" do
- admin = insert(:user, info: %{is_admin: true})
+ test "regular search", %{conn: conn} do
user = insert(:user, nickname: "bob")
- conn =
- build_conn()
- |> assign(:user, admin)
- |> get("/api/pleroma/admin/users?query=bo")
+ conn = get(conn, "/api/pleroma/admin/users?query=bo")
assert json_response(conn, 200) == %{
"count" => 1,
}
end
- test "regular search with page size" do
- admin = insert(:user, info: %{is_admin: true})
+ test "search by domain", %{conn: conn} do
+ user = insert(:user, nickname: "nickname@domain.com")
+ insert(:user)
+
+ conn = get(conn, "/api/pleroma/admin/users?query=domain.com")
+
+ assert json_response(conn, 200) == %{
+ "count" => 1,
+ "page_size" => 50,
+ "users" => [
+ %{
+ "deactivated" => user.info.deactivated,
+ "id" => user.id,
+ "nickname" => user.nickname,
+ "roles" => %{"admin" => false, "moderator" => false},
+ "local" => true,
+ "tags" => []
+ }
+ ]
+ }
+ end
+
+ test "search by full nickname", %{conn: conn} do
+ user = insert(:user, nickname: "nickname@domain.com")
+ insert(:user)
+
+ conn = get(conn, "/api/pleroma/admin/users?query=nickname@domain.com")
+
+ assert json_response(conn, 200) == %{
+ "count" => 1,
+ "page_size" => 50,
+ "users" => [
+ %{
+ "deactivated" => user.info.deactivated,
+ "id" => user.id,
+ "nickname" => user.nickname,
+ "roles" => %{"admin" => false, "moderator" => false},
+ "local" => true,
+ "tags" => []
+ }
+ ]
+ }
+ end
+
+ test "search by display name", %{conn: conn} do
+ user = insert(:user, name: "Display name")
+ insert(:user)
+
+ conn = get(conn, "/api/pleroma/admin/users?name=display")
+
+ assert json_response(conn, 200) == %{
+ "count" => 1,
+ "page_size" => 50,
+ "users" => [
+ %{
+ "deactivated" => user.info.deactivated,
+ "id" => user.id,
+ "nickname" => user.nickname,
+ "roles" => %{"admin" => false, "moderator" => false},
+ "local" => true,
+ "tags" => []
+ }
+ ]
+ }
+ end
+
+ test "search by email", %{conn: conn} do
+ user = insert(:user, email: "email@example.com")
+ insert(:user)
+
+ conn = get(conn, "/api/pleroma/admin/users?email=email@example.com")
+
+ assert json_response(conn, 200) == %{
+ "count" => 1,
+ "page_size" => 50,
+ "users" => [
+ %{
+ "deactivated" => user.info.deactivated,
+ "id" => user.id,
+ "nickname" => user.nickname,
+ "roles" => %{"admin" => false, "moderator" => false},
+ "local" => true,
+ "tags" => []
+ }
+ ]
+ }
+ end
+
+ test "regular search with page size", %{conn: conn} do
user = insert(:user, nickname: "aalice")
user2 = insert(:user, nickname: "alice")
- conn =
- build_conn()
- |> assign(:user, admin)
- |> get("/api/pleroma/admin/users?query=a&page_size=1&page=1")
+ conn1 = get(conn, "/api/pleroma/admin/users?query=a&page_size=1&page=1")
- assert json_response(conn, 200) == %{
+ assert json_response(conn1, 200) == %{
"count" => 2,
"page_size" => 1,
"users" => [
]
}
- conn =
- build_conn()
- |> assign(:user, admin)
- |> get("/api/pleroma/admin/users?query=a&page_size=1&page=2")
+ conn2 = get(conn, "/api/pleroma/admin/users?query=a&page_size=1&page=2")
- assert json_response(conn, 200) == %{
+ assert json_response(conn2, 200) == %{
"count" => 2,
"page_size" => 1,
"users" => [
}
end
- test "only local users with no query" do
+ test "only local users with no query", %{admin: old_admin} do
admin = insert(:user, info: %{is_admin: true}, nickname: "john")
user = insert(:user, nickname: "bob")
|> get("/api/pleroma/admin/users?filters=local")
assert json_response(conn, 200) == %{
- "count" => 2,
+ "count" => 3,
"page_size" => 50,
"users" => [
%{
"roles" => %{"admin" => true, "moderator" => false},
"local" => true,
"tags" => []
+ },
+ %{
+ "deactivated" => false,
+ "id" => old_admin.id,
+ "local" => true,
+ "nickname" => old_admin.nickname,
+ "roles" => %{"admin" => true, "moderator" => false},
+ "tags" => []
+ }
+ ]
+ }
+ end
+
+ test "load only admins", %{conn: conn, admin: admin} do
+ second_admin = insert(:user, info: %{is_admin: true})
+ insert(:user)
+ insert(:user)
+
+ conn = get(conn, "/api/pleroma/admin/users?filters=is_admin")
+
+ assert json_response(conn, 200) == %{
+ "count" => 2,
+ "page_size" => 50,
+ "users" => [
+ %{
+ "deactivated" => false,
+ "id" => admin.id,
+ "nickname" => admin.nickname,
+ "roles" => %{"admin" => true, "moderator" => false},
+ "local" => admin.local,
+ "tags" => []
+ },
+ %{
+ "deactivated" => false,
+ "id" => second_admin.id,
+ "nickname" => second_admin.nickname,
+ "roles" => %{"admin" => true, "moderator" => false},
+ "local" => second_admin.local,
+ "tags" => []
+ }
+ ]
+ }
+ end
+
+ test "load only moderators", %{conn: conn} do
+ moderator = insert(:user, info: %{is_moderator: true})
+ insert(:user)
+ insert(:user)
+
+ conn = get(conn, "/api/pleroma/admin/users?filters=is_moderator")
+
+ assert json_response(conn, 200) == %{
+ "count" => 1,
+ "page_size" => 50,
+ "users" => [
+ %{
+ "deactivated" => false,
+ "id" => moderator.id,
+ "nickname" => moderator.nickname,
+ "roles" => %{"admin" => false, "moderator" => true},
+ "local" => moderator.local,
+ "tags" => []
+ }
+ ]
+ }
+ end
+
+ test "load users with tags list", %{conn: conn} do
+ user1 = insert(:user, tags: ["first"])
+ user2 = insert(:user, tags: ["second"])
+ insert(:user)
+ insert(:user)
+
+ conn = get(conn, "/api/pleroma/admin/users?tags[]=first&tags[]=second")
+
+ assert json_response(conn, 200) == %{
+ "count" => 2,
+ "page_size" => 50,
+ "users" => [
+ %{
+ "deactivated" => false,
+ "id" => user1.id,
+ "nickname" => user1.nickname,
+ "roles" => %{"admin" => false, "moderator" => false},
+ "local" => user1.local,
+ "tags" => ["first"]
+ },
+ %{
+ "deactivated" => false,
+ "id" => user2.id,
+ "nickname" => user2.nickname,
+ "roles" => %{"admin" => false, "moderator" => false},
+ "local" => user2.local,
+ "tags" => ["second"]
}
]
}
end
describe "GET /api/pleroma/admin/invite_token" do
- test "without options" do
+ setup do
admin = insert(:user, info: %{is_admin: true})
conn =
build_conn()
|> assign(:user, admin)
- |> get("/api/pleroma/admin/invite_token")
+
+ {:ok, conn: conn}
+ end
+
+ test "without options", %{conn: conn} do
+ conn = get(conn, "/api/pleroma/admin/invite_token")
token = json_response(conn, 200)
invite = UserInviteToken.find_by_token!(token)
assert invite.invite_type == "one_time"
end
- test "with expires_at" do
- admin = insert(:user, info: %{is_admin: true})
-
+ test "with expires_at", %{conn: conn} do
conn =
- build_conn()
- |> assign(:user, admin)
- |> get("/api/pleroma/admin/invite_token", %{
+ get(conn, "/api/pleroma/admin/invite_token", %{
"invite" => %{"expires_at" => Date.to_string(Date.utc_today())}
})
assert invite.invite_type == "date_limited"
end
- test "with max_use" do
- admin = insert(:user, info: %{is_admin: true})
-
+ test "with max_use", %{conn: conn} do
conn =
- build_conn()
- |> assign(:user, admin)
- |> get("/api/pleroma/admin/invite_token", %{
+ get(conn, "/api/pleroma/admin/invite_token", %{
"invite" => %{"max_use" => 150}
})
assert invite.invite_type == "reusable"
end
- test "with max use and expires_at" do
- admin = insert(:user, info: %{is_admin: true})
-
+ test "with max use and expires_at", %{conn: conn} do
conn =
- build_conn()
- |> assign(:user, admin)
- |> get("/api/pleroma/admin/invite_token", %{
+ get(conn, "/api/pleroma/admin/invite_token", %{
"invite" => %{"max_use" => 150, "expires_at" => Date.to_string(Date.utc_today())}
})
end
describe "GET /api/pleroma/admin/invites" do
- test "no invites" do
+ setup do
admin = insert(:user, info: %{is_admin: true})
conn =
build_conn()
|> assign(:user, admin)
- |> get("/api/pleroma/admin/invites")
+
+ {:ok, conn: conn}
+ end
+
+ test "no invites", %{conn: conn} do
+ conn = get(conn, "/api/pleroma/admin/invites")
assert json_response(conn, 200) == %{"invites" => []}
end
- test "with invite" do
- admin = insert(:user, info: %{is_admin: true})
+ test "with invite", %{conn: conn} do
{:ok, invite} = UserInviteToken.create_invite()
- conn =
- build_conn()
- |> assign(:user, admin)
- |> get("/api/pleroma/admin/invites")
+ conn = get(conn, "/api/pleroma/admin/invites")
assert json_response(conn, 200) == %{
"invites" => [
test "it returns specific user" do
insert(:user)
insert(:user)
- insert(:user, nickname: "bob", local: true, info: %{deactivated: false})
+ user = insert(:user, nickname: "bob", local: true, info: %{deactivated: false})
{:ok, _results, total_count} = Search.user(%{query: ""})
- {:ok, _results, count} =
+ {:ok, [^user], count} =
Search.user(%{
query: "Bo",
active: true,
assert total_count == 3
assert count == 1
end
+
+ test "it returns user by domain" do
+ insert(:user)
+ insert(:user)
+ user = insert(:user, nickname: "some@domain.com")
+
+ {:ok, _results, total} = Search.user()
+ {:ok, [^user], count} = Search.user(%{query: "domain.com"})
+ assert total == 3
+ assert count == 1
+ end
+
+ test "it return user by full nickname" do
+ insert(:user)
+ insert(:user)
+ user = insert(:user, nickname: "some@domain.com")
+
+ {:ok, _results, total} = Search.user()
+ {:ok, [^user], count} = Search.user(%{query: "some@domain.com"})
+ assert total == 3
+ assert count == 1
+ end
+
+ test "it returns admin user" do
+ admin = insert(:user, info: %{is_admin: true})
+ insert(:user)
+ insert(:user)
+
+ {:ok, _results, total} = Search.user()
+ {:ok, [^admin], count} = Search.user(%{is_admin: true})
+ assert total == 3
+ assert count == 1
+ end
+
+ test "it returns moderator user" do
+ moderator = insert(:user, info: %{is_moderator: true})
+ insert(:user)
+ insert(:user)
+
+ {:ok, _results, total} = Search.user()
+ {:ok, [^moderator], count} = Search.user(%{is_moderator: true})
+ assert total == 3
+ assert count == 1
+ end
+
+ test "it returns users with tags" do
+ user1 = insert(:user, tags: ["first"])
+ user2 = insert(:user, tags: ["second"])
+ insert(:user)
+ insert(:user)
+
+ {:ok, _results, total} = Search.user()
+ {:ok, users, count} = Search.user(%{tags: ["first", "second"]})
+ assert total == 4
+ assert count == 2
+ assert user1 in users
+ assert user2 in users
+ end
+
+ test "it returns user by display name" do
+ user = insert(:user, name: "Display name")
+ insert(:user)
+ insert(:user)
+
+ {:ok, _results, total} = Search.user()
+ {:ok, [^user], count} = Search.user(%{name: "display"})
+
+ assert total == 3
+ assert count == 1
+ end
+
+ test "it returns user by email" do
+ user = insert(:user, email: "some@example.com")
+ insert(:user)
+ insert(:user)
+
+ {:ok, _results, total} = Search.user()
+ {:ok, [^user], count} = Search.user(%{email: "some@example.com"})
+
+ assert total == 3
+ assert count == 1
+ end
end
end