Merge develop
authorAlexander Strizhakov <alex.strizhakov@gmail.com>
Wed, 8 May 2019 14:34:36 +0000 (14:34 +0000)
committerkaniini <nenolod@gmail.com>
Wed, 8 May 2019 14:34:36 +0000 (14:34 +0000)
Merge conflict in lib/pleroma/activity.ex

CHANGELOG.md
docs/api/admin_api.md
lib/pleroma/activity.ex
lib/pleroma/stats.ex
lib/pleroma/user.ex
lib/pleroma/user/query.ex [new file with mode: 0644]
lib/pleroma/web/admin_api/admin_api_controller.ex
lib/pleroma/web/admin_api/search.ex
test/web/admin_api/admin_api_controller_test.exs
test/web/admin_api/search_test.exs

index 210aae2e4e954cd6c65421a6d5ecfa2ab14000e6..b0a761c4adcb223b7fc2027b89d9926933c3de5d 100644 (file)
@@ -21,6 +21,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 - 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)
index 8befa8ea0033bd57d1edad482f7ebe3d81e01649..2657d124379732f0a26108d851f59d21a1eea14b 100644 (file)
@@ -8,15 +8,20 @@ Authentication is required and the user must be an admin.
 
 - 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
index 2b661edc1dc32b0e4f5c60db58eebaef3849f4a3..c121e800f6c206ca3bfd989282965d42ffd30029 100644 (file)
@@ -287,6 +287,29 @@ defmodule Pleroma.Activity do
     |> 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)
index 2e7d747df9c2a6b9a978a005937abbef1c9bc454..5b242927b07758063bcb36a2670866a365c05018 100644 (file)
@@ -34,7 +34,7 @@ defmodule Pleroma.Stats do
   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
       )
@@ -44,10 +44,13 @@ defmodule Pleroma.Stats do
     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}}
index b1adaad2f59bf61cdd2da511184f763034799dc4..427400aa17764bc548233af00531af39786c1d7c 100644 (file)
@@ -254,10 +254,7 @@ defmodule Pleroma.User do
     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)
@@ -576,19 +573,17 @@ defmodule Pleroma.User do
     )
   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
@@ -603,19 +598,17 @@ defmodule Pleroma.User 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
@@ -630,33 +623,10 @@ defmodule Pleroma.User 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)
@@ -729,10 +699,7 @@ defmodule Pleroma.User do
 
   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)
@@ -755,38 +722,19 @@ defmodule Pleroma.User do
     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
@@ -1048,14 +996,23 @@ defmodule Pleroma.User 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 =
@@ -1081,69 +1038,6 @@ defmodule Pleroma.User do
     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)
 
@@ -1306,7 +1200,7 @@ defmodule Pleroma.User do
   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)
 
@@ -1423,22 +1317,12 @@ defmodule Pleroma.User do
     }
   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
diff --git a/lib/pleroma/user/query.ex b/lib/pleroma/user/query.ex
new file mode 100644 (file)
index 0000000..2dfe5ce
--- /dev/null
@@ -0,0 +1,150 @@
+# 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
index 711f233a6d3d2b3b1bde7e9dd5a59eba1ed96b6d..b553d96a8e056666ccc2f97655fbc260da6f9642 100644 (file)
@@ -101,7 +101,10 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
     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)),
@@ -116,11 +119,11 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
            )
   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(",")
index 9a8e41c2a7b1d62251d67664e6c04906c24dbb22..ed919833e895c2c4d8b3867a71c07145b1ab99d4 100644 (file)
@@ -10,45 +10,23 @@ defmodule Pleroma.Web.AdminAPI.Search do
 
   @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
index b89c42327849a16cd7e50e4036e98f08bdd4baf7..f433f6be217e97f1ed2761d25fb394a3db4969f8 100644 (file)
@@ -419,14 +419,19 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
   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,
@@ -452,14 +457,10 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
              }
     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,
@@ -468,14 +469,10 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
              }
     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,
@@ -493,17 +490,101 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
              }
     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" => [
@@ -518,12 +599,9 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
                ]
              }
 
-      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" => [
@@ -566,7 +644,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
              }
     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")
 
@@ -578,7 +656,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
         |> get("/api/pleroma/admin/users?filters=local")
 
       assert json_response(conn, 200) == %{
-               "count" => 2,
+               "count" => 3,
                "page_size" => 50,
                "users" => [
                  %{
@@ -596,6 +674,100 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
                    "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"]
                  }
                ]
              }
@@ -651,13 +823,18 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
   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)
@@ -667,13 +844,9 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
       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())}
         })
 
@@ -686,13 +859,9 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
       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}
         })
 
@@ -704,13 +873,9 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
       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())}
         })
 
@@ -724,25 +889,26 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
   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" => [
index 3950996edf6cc629a772122d109c58ef66aacf84..501a8d007d1e1b7895121710e297bb00578462ac 100644 (file)
@@ -70,11 +70,11 @@ defmodule Pleroma.Web.AdminAPI.SearchTest do
     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,
@@ -84,5 +84,87 @@ defmodule Pleroma.Web.AdminAPI.SearchTest do
       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