Merge branch 'issue/1878' into 'develop'
[akkoma] / test / web / admin_api / controllers / admin_api_controller_test.exs
index 321840a8c31ff34222ca991ca3459ba6073a4859..6082441ee5e8e032494da8b8810d08ca2be22e0e 100644 (file)
@@ -9,18 +9,16 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
   import ExUnit.CaptureLog
   import Mock
   import Pleroma.Factory
+  import Swoosh.TestAssertions
 
   alias Pleroma.Activity
   alias Pleroma.Config
-  alias Pleroma.ConfigDB
   alias Pleroma.HTML
   alias Pleroma.MFA
   alias Pleroma.ModerationLog
   alias Pleroma.Repo
-  alias Pleroma.ReportNote
   alias Pleroma.Tests.ObanHelpers
   alias Pleroma.User
-  alias Pleroma.UserInviteToken
   alias Pleroma.Web
   alias Pleroma.Web.ActivityPub.Relay
   alias Pleroma.Web.CommonAPI
@@ -44,6 +42,16 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
     {:ok, %{admin: admin, token: token, conn: conn}}
   end
 
+  test "with valid `admin_token` query parameter, skips OAuth scopes check" do
+    clear_config([:admin_token], "password123")
+
+    user = insert(:user)
+
+    conn = get(build_conn(), "/api/pleroma/admin/users/#{user.nickname}?admin_token=password123")
+
+    assert json_response(conn, 200)
+  end
+
   describe "with [:auth, :enforce_oauth_admin_scope_usage]," do
     setup do: clear_config([:auth, :enforce_oauth_admin_scope_usage], true)
 
@@ -340,7 +348,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
         "tags" => [],
         "avatar" => User.avatar_url(user) |> MediaProxy.url(),
         "display_name" => HTML.strip_tags(user.name || user.nickname),
-        "confirmation_pending" => false
+        "confirmation_pending" => false,
+        "url" => user.ap_id
       }
 
       assert expected == json_response(conn, 200)
@@ -588,122 +597,6 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
     end
   end
 
-  describe "POST /api/pleroma/admin/email_invite, with valid config" do
-    setup do: clear_config([:instance, :registrations_open], false)
-    setup do: clear_config([:instance, :invites_enabled], true)
-
-    test "sends invitation and returns 204", %{admin: admin, conn: conn} do
-      recipient_email = "foo@bar.com"
-      recipient_name = "J. D."
-
-      conn =
-        post(
-          conn,
-          "/api/pleroma/admin/users/email_invite?email=#{recipient_email}&name=#{recipient_name}"
-        )
-
-      assert json_response(conn, :no_content)
-
-      token_record = List.last(Repo.all(Pleroma.UserInviteToken))
-      assert token_record
-      refute token_record.used
-
-      notify_email = Config.get([:instance, :notify_email])
-      instance_name = Config.get([:instance, :name])
-
-      email =
-        Pleroma.Emails.UserEmail.user_invitation_email(
-          admin,
-          token_record,
-          recipient_email,
-          recipient_name
-        )
-
-      Swoosh.TestAssertions.assert_email_sent(
-        from: {instance_name, notify_email},
-        to: {recipient_name, recipient_email},
-        html_body: email.html_body
-      )
-    end
-
-    test "it returns 403 if requested by a non-admin" do
-      non_admin_user = insert(:user)
-      token = insert(:oauth_token, user: non_admin_user)
-
-      conn =
-        build_conn()
-        |> assign(:user, non_admin_user)
-        |> assign(:token, token)
-        |> post("/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD")
-
-      assert json_response(conn, :forbidden)
-    end
-
-    test "email with +", %{conn: conn, admin: admin} do
-      recipient_email = "foo+bar@baz.com"
-
-      conn
-      |> put_req_header("content-type", "application/json;charset=utf-8")
-      |> post("/api/pleroma/admin/users/email_invite", %{email: recipient_email})
-      |> json_response(:no_content)
-
-      token_record =
-        Pleroma.UserInviteToken
-        |> Repo.all()
-        |> List.last()
-
-      assert token_record
-      refute token_record.used
-
-      notify_email = Config.get([:instance, :notify_email])
-      instance_name = Config.get([:instance, :name])
-
-      email =
-        Pleroma.Emails.UserEmail.user_invitation_email(
-          admin,
-          token_record,
-          recipient_email
-        )
-
-      Swoosh.TestAssertions.assert_email_sent(
-        from: {instance_name, notify_email},
-        to: recipient_email,
-        html_body: email.html_body
-      )
-    end
-  end
-
-  describe "POST /api/pleroma/admin/users/email_invite, with invalid config" do
-    setup do: clear_config([:instance, :registrations_open])
-    setup do: clear_config([:instance, :invites_enabled])
-
-    test "it returns 500 if `invites_enabled` is not enabled", %{conn: conn} do
-      Config.put([:instance, :registrations_open], false)
-      Config.put([:instance, :invites_enabled], false)
-
-      conn = post(conn, "/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD")
-
-      assert json_response(conn, :bad_request) ==
-               %{
-                 "error" =>
-                   "To send invites you need to set the `invites_enabled` option to true."
-               }
-    end
-
-    test "it returns 500 if `registrations_open` is enabled", %{conn: conn} do
-      Config.put([:instance, :registrations_open], true)
-      Config.put([:instance, :invites_enabled], true)
-
-      conn = post(conn, "/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD")
-
-      assert json_response(conn, :bad_request) ==
-               %{
-                 "error" =>
-                   "To send invites you need to set the `registrations_open` option to false."
-               }
-    end
-  end
-
   test "/api/pleroma/admin/users/:nickname/password_reset", %{conn: conn} do
     user = insert(:user)
 
@@ -733,7 +626,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
             "tags" => [],
             "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
             "display_name" => HTML.strip_tags(admin.name || admin.nickname),
-            "confirmation_pending" => false
+            "confirmation_pending" => false,
+            "url" => admin.ap_id
           },
           %{
             "deactivated" => user.deactivated,
@@ -744,7 +638,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
             "tags" => ["foo", "bar"],
             "avatar" => User.avatar_url(user) |> MediaProxy.url(),
             "display_name" => HTML.strip_tags(user.name || user.nickname),
-            "confirmation_pending" => false
+            "confirmation_pending" => false,
+            "url" => user.ap_id
           }
         ]
         |> Enum.sort_by(& &1["nickname"])
@@ -757,8 +652,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
     end
 
     test "pagination works correctly with service users", %{conn: conn} do
-      service1 = insert(:user, ap_id: Web.base_url() <> "/relay")
-      service2 = insert(:user, ap_id: Web.base_url() <> "/internal/fetch")
+      service1 = User.get_or_create_service_actor_by_ap_id(Web.base_url() <> "/meido", "meido")
+
       insert_list(25, :user)
 
       assert %{"count" => 26, "page_size" => 10, "users" => users1} =
@@ -767,8 +662,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
                |> json_response(200)
 
       assert Enum.count(users1) == 10
-      assert service1 not in [users1]
-      assert service2 not in [users1]
+      assert service1 not in users1
 
       assert %{"count" => 26, "page_size" => 10, "users" => users2} =
                conn
@@ -776,8 +670,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
                |> json_response(200)
 
       assert Enum.count(users2) == 10
-      assert service1 not in [users2]
-      assert service2 not in [users2]
+      assert service1 not in users2
 
       assert %{"count" => 26, "page_size" => 10, "users" => users3} =
                conn
@@ -785,8 +678,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
                |> json_response(200)
 
       assert Enum.count(users3) == 6
-      assert service1 not in [users3]
-      assert service2 not in [users3]
+      assert service1 not in users3
     end
 
     test "renders empty array for the second page", %{conn: conn} do
@@ -819,7 +711,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
                    "tags" => [],
                    "avatar" => User.avatar_url(user) |> MediaProxy.url(),
                    "display_name" => HTML.strip_tags(user.name || user.nickname),
-                   "confirmation_pending" => false
+                   "confirmation_pending" => false,
+                   "url" => user.ap_id
                  }
                ]
              }
@@ -844,7 +737,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
                    "tags" => [],
                    "avatar" => User.avatar_url(user) |> MediaProxy.url(),
                    "display_name" => HTML.strip_tags(user.name || user.nickname),
-                   "confirmation_pending" => false
+                   "confirmation_pending" => false,
+                   "url" => user.ap_id
                  }
                ]
              }
@@ -869,7 +763,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
                    "tags" => [],
                    "avatar" => User.avatar_url(user) |> MediaProxy.url(),
                    "display_name" => HTML.strip_tags(user.name || user.nickname),
-                   "confirmation_pending" => false
+                   "confirmation_pending" => false,
+                   "url" => user.ap_id
                  }
                ]
              }
@@ -894,7 +789,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
                    "tags" => [],
                    "avatar" => User.avatar_url(user) |> MediaProxy.url(),
                    "display_name" => HTML.strip_tags(user.name || user.nickname),
-                   "confirmation_pending" => false
+                   "confirmation_pending" => false,
+                   "url" => user.ap_id
                  }
                ]
              }
@@ -919,7 +815,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
                    "tags" => [],
                    "avatar" => User.avatar_url(user) |> MediaProxy.url(),
                    "display_name" => HTML.strip_tags(user.name || user.nickname),
-                   "confirmation_pending" => false
+                   "confirmation_pending" => false,
+                   "url" => user.ap_id
                  }
                ]
              }
@@ -944,7 +841,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
                    "tags" => [],
                    "avatar" => User.avatar_url(user) |> MediaProxy.url(),
                    "display_name" => HTML.strip_tags(user.name || user.nickname),
-                   "confirmation_pending" => false
+                   "confirmation_pending" => false,
+                   "url" => user.ap_id
                  }
                ]
              }
@@ -964,7 +862,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
                    "tags" => [],
                    "avatar" => User.avatar_url(user2) |> MediaProxy.url(),
                    "display_name" => HTML.strip_tags(user2.name || user2.nickname),
-                   "confirmation_pending" => false
+                   "confirmation_pending" => false,
+                   "url" => user2.ap_id
                  }
                ]
              }
@@ -996,7 +895,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
                    "tags" => [],
                    "avatar" => User.avatar_url(user) |> MediaProxy.url(),
                    "display_name" => HTML.strip_tags(user.name || user.nickname),
-                   "confirmation_pending" => false
+                   "confirmation_pending" => false,
+                   "url" => user.ap_id
                  }
                ]
              }
@@ -1021,7 +921,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
             "tags" => [],
             "avatar" => User.avatar_url(user) |> MediaProxy.url(),
             "display_name" => HTML.strip_tags(user.name || user.nickname),
-            "confirmation_pending" => false
+            "confirmation_pending" => false,
+            "url" => user.ap_id
           },
           %{
             "deactivated" => admin.deactivated,
@@ -1032,7 +933,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
             "tags" => [],
             "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
             "display_name" => HTML.strip_tags(admin.name || admin.nickname),
-            "confirmation_pending" => false
+            "confirmation_pending" => false,
+            "url" => admin.ap_id
           },
           %{
             "deactivated" => false,
@@ -1043,7 +945,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
             "tags" => [],
             "avatar" => User.avatar_url(old_admin) |> MediaProxy.url(),
             "display_name" => HTML.strip_tags(old_admin.name || old_admin.nickname),
-            "confirmation_pending" => false
+            "confirmation_pending" => false,
+            "url" => old_admin.ap_id
           }
         ]
         |> Enum.sort_by(& &1["nickname"])
@@ -1073,7 +976,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
             "tags" => [],
             "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
             "display_name" => HTML.strip_tags(admin.name || admin.nickname),
-            "confirmation_pending" => false
+            "confirmation_pending" => false,
+            "url" => admin.ap_id
           },
           %{
             "deactivated" => false,
@@ -1084,7 +988,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
             "tags" => [],
             "avatar" => User.avatar_url(second_admin) |> MediaProxy.url(),
             "display_name" => HTML.strip_tags(second_admin.name || second_admin.nickname),
-            "confirmation_pending" => false
+            "confirmation_pending" => false,
+            "url" => second_admin.ap_id
           }
         ]
         |> Enum.sort_by(& &1["nickname"])
@@ -1116,7 +1021,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
                    "tags" => [],
                    "avatar" => User.avatar_url(moderator) |> MediaProxy.url(),
                    "display_name" => HTML.strip_tags(moderator.name || moderator.nickname),
-                   "confirmation_pending" => false
+                   "confirmation_pending" => false,
+                   "url" => moderator.ap_id
                  }
                ]
              }
@@ -1141,7 +1047,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
             "tags" => ["first"],
             "avatar" => User.avatar_url(user1) |> MediaProxy.url(),
             "display_name" => HTML.strip_tags(user1.name || user1.nickname),
-            "confirmation_pending" => false
+            "confirmation_pending" => false,
+            "url" => user1.ap_id
           },
           %{
             "deactivated" => false,
@@ -1152,7 +1059,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
             "tags" => ["second"],
             "avatar" => User.avatar_url(user2) |> MediaProxy.url(),
             "display_name" => HTML.strip_tags(user2.name || user2.nickname),
-            "confirmation_pending" => false
+            "confirmation_pending" => false,
+            "url" => user2.ap_id
           }
         ]
         |> Enum.sort_by(& &1["nickname"])
@@ -1191,7 +1099,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
                    "tags" => [],
                    "avatar" => User.avatar_url(user) |> MediaProxy.url(),
                    "display_name" => HTML.strip_tags(user.name || user.nickname),
-                   "confirmation_pending" => false
+                   "confirmation_pending" => false,
+                   "url" => user.ap_id
                  }
                ]
              }
@@ -1215,7 +1124,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
                    "tags" => [],
                    "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
                    "display_name" => HTML.strip_tags(admin.name || admin.nickname),
-                   "confirmation_pending" => false
+                   "confirmation_pending" => false,
+                   "url" => admin.ap_id
                  }
                ]
              }
@@ -1277,7 +1187,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
                "tags" => [],
                "avatar" => User.avatar_url(user) |> MediaProxy.url(),
                "display_name" => HTML.strip_tags(user.name || user.nickname),
-               "confirmation_pending" => false
+               "confirmation_pending" => false,
+               "url" => user.ap_id
              }
 
     log_entry = Repo.one(ModerationLog)
@@ -1318,1751 +1229,196 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
     end
   end
 
-  describe "POST /api/pleroma/admin/users/invite_token" do
-    test "without options", %{conn: conn} do
-      conn = post(conn, "/api/pleroma/admin/users/invite_token")
-
-      invite_json = json_response(conn, 200)
-      invite = UserInviteToken.find_by_token!(invite_json["token"])
-      refute invite.used
-      refute invite.expires_at
-      refute invite.max_use
-      assert invite.invite_type == "one_time"
-    end
-
-    test "with expires_at", %{conn: conn} do
-      conn =
-        post(conn, "/api/pleroma/admin/users/invite_token", %{
-          "expires_at" => Date.to_string(Date.utc_today())
-        })
+  describe "GET /api/pleroma/admin/restart" do
+    setup do: clear_config(:configurable_from_database, true)
 
-      invite_json = json_response(conn, 200)
-      invite = UserInviteToken.find_by_token!(invite_json["token"])
+    test "pleroma restarts", %{conn: conn} do
+      capture_log(fn ->
+        assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{}
+      end) =~ "pleroma restarted"
 
-      refute invite.used
-      assert invite.expires_at == Date.utc_today()
-      refute invite.max_use
-      assert invite.invite_type == "date_limited"
+      refute Restarter.Pleroma.need_reboot?()
     end
+  end
 
-    test "with max_use", %{conn: conn} do
-      conn = post(conn, "/api/pleroma/admin/users/invite_token", %{"max_use" => 150})
+  test "need_reboot flag", %{conn: conn} do
+    assert conn
+           |> get("/api/pleroma/admin/need_reboot")
+           |> json_response(200) == %{"need_reboot" => false}
 
-      invite_json = json_response(conn, 200)
-      invite = UserInviteToken.find_by_token!(invite_json["token"])
-      refute invite.used
-      refute invite.expires_at
-      assert invite.max_use == 150
-      assert invite.invite_type == "reusable"
-    end
+    Restarter.Pleroma.need_reboot()
 
-    test "with max use and expires_at", %{conn: conn} do
-      conn =
-        post(conn, "/api/pleroma/admin/users/invite_token", %{
-          "max_use" => 150,
-          "expires_at" => Date.to_string(Date.utc_today())
-        })
+    assert conn
+           |> get("/api/pleroma/admin/need_reboot")
+           |> json_response(200) == %{"need_reboot" => true}
 
-      invite_json = json_response(conn, 200)
-      invite = UserInviteToken.find_by_token!(invite_json["token"])
-      refute invite.used
-      assert invite.expires_at == Date.utc_today()
-      assert invite.max_use == 150
-      assert invite.invite_type == "reusable_date_limited"
-    end
+    on_exit(fn -> Restarter.Pleroma.refresh() end)
   end
 
-  describe "GET /api/pleroma/admin/users/invites" do
-    test "no invites", %{conn: conn} do
-      conn = get(conn, "/api/pleroma/admin/users/invites")
-
-      assert json_response(conn, 200) == %{"invites" => []}
-    end
+  describe "GET /api/pleroma/admin/users/:nickname/statuses" do
+    setup do
+      user = insert(:user)
 
-    test "with invite", %{conn: conn} do
-      {:ok, invite} = UserInviteToken.create_invite()
+      date1 = (DateTime.to_unix(DateTime.utc_now()) + 2000) |> DateTime.from_unix!()
+      date2 = (DateTime.to_unix(DateTime.utc_now()) + 1000) |> DateTime.from_unix!()
+      date3 = (DateTime.to_unix(DateTime.utc_now()) + 3000) |> DateTime.from_unix!()
 
-      conn = get(conn, "/api/pleroma/admin/users/invites")
+      insert(:note_activity, user: user, published: date1)
+      insert(:note_activity, user: user, published: date2)
+      insert(:note_activity, user: user, published: date3)
 
-      assert json_response(conn, 200) == %{
-               "invites" => [
-                 %{
-                   "expires_at" => nil,
-                   "id" => invite.id,
-                   "invite_type" => "one_time",
-                   "max_use" => nil,
-                   "token" => invite.token,
-                   "used" => false,
-                   "uses" => 0
-                 }
-               ]
-             }
+      %{user: user}
     end
-  end
 
-  describe "POST /api/pleroma/admin/users/revoke_invite" do
-    test "with token", %{conn: conn} do
-      {:ok, invite} = UserInviteToken.create_invite()
-
-      conn = post(conn, "/api/pleroma/admin/users/revoke_invite", %{"token" => invite.token})
+    test "renders user's statuses", %{conn: conn, user: user} do
+      conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
 
-      assert json_response(conn, 200) == %{
-               "expires_at" => nil,
-               "id" => invite.id,
-               "invite_type" => "one_time",
-               "max_use" => nil,
-               "token" => invite.token,
-               "used" => true,
-               "uses" => 0
-             }
+      assert json_response(conn, 200) |> length() == 3
     end
 
-    test "with invalid token", %{conn: conn} do
-      conn = post(conn, "/api/pleroma/admin/users/revoke_invite", %{"token" => "foo"})
+    test "renders user's statuses with a limit", %{conn: conn, user: user} do
+      conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=2")
 
-      assert json_response(conn, :not_found) == %{"error" => "Not found"}
+      assert json_response(conn, 200) |> length() == 2
     end
-  end
 
-  describe "GET /api/pleroma/admin/reports/:id" do
-    test "returns report by its id", %{conn: conn} do
-      [reporter, target_user] = insert_pair(:user)
-      activity = insert(:note_activity, user: target_user)
+    test "doesn't return private statuses by default", %{conn: conn, user: user} do
+      {:ok, _private_status} = CommonAPI.post(user, %{status: "private", visibility: "private"})
 
-      {:ok, %{id: report_id}} =
-        CommonAPI.report(reporter, %{
-          account_id: target_user.id,
-          comment: "I feel offended",
-          status_ids: [activity.id]
-        })
+      {:ok, _public_status} = CommonAPI.post(user, %{status: "public", visibility: "public"})
 
-      response =
-        conn
-        |> get("/api/pleroma/admin/reports/#{report_id}")
-        |> json_response(:ok)
+      conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
 
-      assert response["id"] == report_id
+      assert json_response(conn, 200) |> length() == 4
     end
 
-    test "returns 404 when report id is invalid", %{conn: conn} do
-      conn = get(conn, "/api/pleroma/admin/reports/test")
-
-      assert json_response(conn, :not_found) == %{"error" => "Not found"}
-    end
-  end
+    test "returns private statuses with godmode on", %{conn: conn, user: user} do
+      {:ok, _private_status} = CommonAPI.post(user, %{status: "private", visibility: "private"})
 
-  describe "PATCH /api/pleroma/admin/reports" do
-    setup do
-      [reporter, target_user] = insert_pair(:user)
-      activity = insert(:note_activity, user: target_user)
-
-      {:ok, %{id: report_id}} =
-        CommonAPI.report(reporter, %{
-          account_id: target_user.id,
-          comment: "I feel offended",
-          status_ids: [activity.id]
-        })
+      {:ok, _public_status} = CommonAPI.post(user, %{status: "public", visibility: "public"})
 
-      {:ok, %{id: second_report_id}} =
-        CommonAPI.report(reporter, %{
-          account_id: target_user.id,
-          comment: "I feel very offended",
-          status_ids: [activity.id]
-        })
+      conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?godmode=true")
 
-      %{
-        id: report_id,
-        second_report_id: second_report_id
-      }
+      assert json_response(conn, 200) |> length() == 5
     end
 
-    test "requires admin:write:reports scope", %{conn: conn, id: id, admin: admin} do
-      read_token = insert(:oauth_token, user: admin, scopes: ["admin:read"])
-      write_token = insert(:oauth_token, user: admin, scopes: ["admin:write:reports"])
+    test "excludes reblogs by default", %{conn: conn, user: user} do
+      other_user = insert(:user)
+      {:ok, activity} = CommonAPI.post(user, %{status: "."})
+      {:ok, %Activity{}} = CommonAPI.repeat(activity.id, other_user)
 
-      response =
-        conn
-        |> assign(:token, read_token)
-        |> patch("/api/pleroma/admin/reports", %{
-          "reports" => [%{"state" => "resolved", "id" => id}]
-        })
-        |> json_response(403)
+      conn_res = get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses")
+      assert json_response(conn_res, 200) |> length() == 0
 
-      assert response == %{
-               "error" => "Insufficient permissions: admin:write:reports."
-             }
+      conn_res =
+        get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses?with_reblogs=true")
 
-      conn
-      |> assign(:token, write_token)
-      |> patch("/api/pleroma/admin/reports", %{
-        "reports" => [%{"state" => "resolved", "id" => id}]
-      })
-      |> json_response(:no_content)
+      assert json_response(conn_res, 200) |> length() == 1
     end
+  end
 
-    test "mark report as resolved", %{conn: conn, id: id, admin: admin} do
-      conn
-      |> patch("/api/pleroma/admin/reports", %{
-        "reports" => [
-          %{"state" => "resolved", "id" => id}
-        ]
-      })
-      |> json_response(:no_content)
-
-      activity = Activity.get_by_id(id)
-      assert activity.data["state"] == "resolved"
-
-      log_entry = Repo.one(ModerationLog)
+  describe "GET /api/pleroma/admin/moderation_log" do
+    setup do
+      moderator = insert(:user, is_moderator: true)
 
-      assert ModerationLog.get_log_entry_message(log_entry) ==
-               "@#{admin.nickname} updated report ##{id} with 'resolved' state"
+      %{moderator: moderator}
     end
 
-    test "closes report", %{conn: conn, id: id, admin: admin} do
-      conn
-      |> patch("/api/pleroma/admin/reports", %{
-        "reports" => [
-          %{"state" => "closed", "id" => id}
-        ]
+    test "returns the log", %{conn: conn, admin: admin} do
+      Repo.insert(%ModerationLog{
+        data: %{
+          actor: %{
+            "id" => admin.id,
+            "nickname" => admin.nickname,
+            "type" => "user"
+          },
+          action: "relay_follow",
+          target: "https://example.org/relay"
+        },
+        inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
       })
-      |> json_response(:no_content)
 
-      activity = Activity.get_by_id(id)
-      assert activity.data["state"] == "closed"
+      Repo.insert(%ModerationLog{
+        data: %{
+          actor: %{
+            "id" => admin.id,
+            "nickname" => admin.nickname,
+            "type" => "user"
+          },
+          action: "relay_unfollow",
+          target: "https://example.org/relay"
+        },
+        inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
+      })
 
-      log_entry = Repo.one(ModerationLog)
+      conn = get(conn, "/api/pleroma/admin/moderation_log")
 
-      assert ModerationLog.get_log_entry_message(log_entry) ==
-               "@#{admin.nickname} updated report ##{id} with 'closed' state"
-    end
+      response = json_response(conn, 200)
+      [first_entry, second_entry] = response["items"]
 
-    test "returns 400 when state is unknown", %{conn: conn, id: id} do
-      conn =
-        conn
-        |> patch("/api/pleroma/admin/reports", %{
-          "reports" => [
-            %{"state" => "test", "id" => id}
-          ]
-        })
+      assert response["total"] == 2
+      assert first_entry["data"]["action"] == "relay_unfollow"
 
-      assert hd(json_response(conn, :bad_request))["error"] == "Unsupported state"
-    end
+      assert first_entry["message"] ==
+               "@#{admin.nickname} unfollowed relay: https://example.org/relay"
 
-    test "returns 404 when report is not exist", %{conn: conn} do
-      conn =
-        conn
-        |> patch("/api/pleroma/admin/reports", %{
-          "reports" => [
-            %{"state" => "closed", "id" => "test"}
-          ]
-        })
+      assert second_entry["data"]["action"] == "relay_follow"
 
-      assert hd(json_response(conn, :bad_request))["error"] == "not_found"
+      assert second_entry["message"] ==
+               "@#{admin.nickname} followed relay: https://example.org/relay"
     end
 
-    test "updates state of multiple reports", %{
-      conn: conn,
-      id: id,
-      admin: admin,
-      second_report_id: second_report_id
-    } do
-      conn
-      |> patch("/api/pleroma/admin/reports", %{
-        "reports" => [
-          %{"state" => "resolved", "id" => id},
-          %{"state" => "closed", "id" => second_report_id}
-        ]
+    test "returns the log with pagination", %{conn: conn, admin: admin} do
+      Repo.insert(%ModerationLog{
+        data: %{
+          actor: %{
+            "id" => admin.id,
+            "nickname" => admin.nickname,
+            "type" => "user"
+          },
+          action: "relay_follow",
+          target: "https://example.org/relay"
+        },
+        inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
       })
-      |> json_response(:no_content)
 
-      activity = Activity.get_by_id(id)
-      second_activity = Activity.get_by_id(second_report_id)
-      assert activity.data["state"] == "resolved"
-      assert second_activity.data["state"] == "closed"
-
-      [first_log_entry, second_log_entry] = Repo.all(ModerationLog)
+      Repo.insert(%ModerationLog{
+        data: %{
+          actor: %{
+            "id" => admin.id,
+            "nickname" => admin.nickname,
+            "type" => "user"
+          },
+          action: "relay_unfollow",
+          target: "https://example.org/relay"
+        },
+        inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
+      })
 
-      assert ModerationLog.get_log_entry_message(first_log_entry) ==
-               "@#{admin.nickname} updated report ##{id} with 'resolved' state"
+      conn1 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=1")
 
-      assert ModerationLog.get_log_entry_message(second_log_entry) ==
-               "@#{admin.nickname} updated report ##{second_report_id} with 'closed' state"
-    end
-  end
+      response1 = json_response(conn1, 200)
+      [first_entry] = response1["items"]
 
-  describe "GET /api/pleroma/admin/reports" do
-    test "returns empty response when no reports created", %{conn: conn} do
-      response =
-        conn
-        |> get("/api/pleroma/admin/reports")
-        |> json_response(:ok)
+      assert response1["total"] == 2
+      assert response1["items"] |> length() == 1
+      assert first_entry["data"]["action"] == "relay_unfollow"
 
-      assert Enum.empty?(response["reports"])
-      assert response["total"] == 0
-    end
+      assert first_entry["message"] ==
+               "@#{admin.nickname} unfollowed relay: https://example.org/relay"
 
-    test "returns reports", %{conn: conn} do
-      [reporter, target_user] = insert_pair(:user)
-      activity = insert(:note_activity, user: target_user)
+      conn2 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=2")
 
-      {:ok, %{id: report_id}} =
-        CommonAPI.report(reporter, %{
-          account_id: target_user.id,
-          comment: "I feel offended",
-          status_ids: [activity.id]
-        })
+      response2 = json_response(conn2, 200)
+      [second_entry] = response2["items"]
 
-      response =
-        conn
-        |> get("/api/pleroma/admin/reports")
-        |> json_response(:ok)
+      assert response2["total"] == 2
+      assert response2["items"] |> length() == 1
+      assert second_entry["data"]["action"] == "relay_follow"
 
-      [report] = response["reports"]
-
-      assert length(response["reports"]) == 1
-      assert report["id"] == report_id
-
-      assert response["total"] == 1
-    end
-
-    test "returns reports with specified state", %{conn: conn} do
-      [reporter, target_user] = insert_pair(:user)
-      activity = insert(:note_activity, user: target_user)
-
-      {:ok, %{id: first_report_id}} =
-        CommonAPI.report(reporter, %{
-          account_id: target_user.id,
-          comment: "I feel offended",
-          status_ids: [activity.id]
-        })
-
-      {:ok, %{id: second_report_id}} =
-        CommonAPI.report(reporter, %{
-          account_id: target_user.id,
-          comment: "I don't like this user"
-        })
-
-      CommonAPI.update_report_state(second_report_id, "closed")
-
-      response =
-        conn
-        |> get("/api/pleroma/admin/reports", %{
-          "state" => "open"
-        })
-        |> json_response(:ok)
-
-      [open_report] = response["reports"]
-
-      assert length(response["reports"]) == 1
-      assert open_report["id"] == first_report_id
-
-      assert response["total"] == 1
-
-      response =
-        conn
-        |> get("/api/pleroma/admin/reports", %{
-          "state" => "closed"
-        })
-        |> json_response(:ok)
-
-      [closed_report] = response["reports"]
-
-      assert length(response["reports"]) == 1
-      assert closed_report["id"] == second_report_id
-
-      assert response["total"] == 1
-
-      response =
-        conn
-        |> get("/api/pleroma/admin/reports", %{
-          "state" => "resolved"
-        })
-        |> json_response(:ok)
-
-      assert Enum.empty?(response["reports"])
-      assert response["total"] == 0
-    end
-
-    test "returns 403 when requested by a non-admin" do
-      user = insert(:user)
-      token = insert(:oauth_token, user: user)
-
-      conn =
-        build_conn()
-        |> assign(:user, user)
-        |> assign(:token, token)
-        |> get("/api/pleroma/admin/reports")
-
-      assert json_response(conn, :forbidden) ==
-               %{"error" => "User is not an admin or OAuth admin scope is not granted."}
-    end
-
-    test "returns 403 when requested by anonymous" do
-      conn = get(build_conn(), "/api/pleroma/admin/reports")
-
-      assert json_response(conn, :forbidden) == %{"error" => "Invalid credentials."}
-    end
-  end
-
-  describe "GET /api/pleroma/admin/config" do
-    setup do: clear_config(:configurable_from_database, true)
-
-    test "when configuration from database is off", %{conn: conn} do
-      Config.put(:configurable_from_database, false)
-      conn = get(conn, "/api/pleroma/admin/config")
-
-      assert json_response(conn, 400) ==
-               %{
-                 "error" => "To use this endpoint you need to enable configuration from database."
-               }
-    end
-
-    test "with settings only in db", %{conn: conn} do
-      config1 = insert(:config)
-      config2 = insert(:config)
-
-      conn = get(conn, "/api/pleroma/admin/config", %{"only_db" => true})
-
-      %{
-        "configs" => [
-          %{
-            "group" => ":pleroma",
-            "key" => key1,
-            "value" => _
-          },
-          %{
-            "group" => ":pleroma",
-            "key" => key2,
-            "value" => _
-          }
-        ]
-      } = json_response(conn, 200)
-
-      assert key1 == config1.key
-      assert key2 == config2.key
-    end
-
-    test "db is added to settings that are in db", %{conn: conn} do
-      _config = insert(:config, key: ":instance", value: ConfigDB.to_binary(name: "Some name"))
-
-      %{"configs" => configs} =
-        conn
-        |> get("/api/pleroma/admin/config")
-        |> json_response(200)
-
-      [instance_config] =
-        Enum.filter(configs, fn %{"group" => group, "key" => key} ->
-          group == ":pleroma" and key == ":instance"
-        end)
-
-      assert instance_config["db"] == [":name"]
-    end
-
-    test "merged default setting with db settings", %{conn: conn} do
-      config1 = insert(:config)
-      config2 = insert(:config)
-
-      config3 =
-        insert(:config,
-          value: ConfigDB.to_binary(k1: :v1, k2: :v2)
-        )
-
-      %{"configs" => configs} =
-        conn
-        |> get("/api/pleroma/admin/config")
-        |> json_response(200)
-
-      assert length(configs) > 3
-
-      received_configs =
-        Enum.filter(configs, fn %{"group" => group, "key" => key} ->
-          group == ":pleroma" and key in [config1.key, config2.key, config3.key]
-        end)
-
-      assert length(received_configs) == 3
-
-      db_keys =
-        config3.value
-        |> ConfigDB.from_binary()
-        |> Keyword.keys()
-        |> ConfigDB.convert()
-
-      Enum.each(received_configs, fn %{"value" => value, "db" => db} ->
-        assert db in [[config1.key], [config2.key], db_keys]
-
-        assert value in [
-                 ConfigDB.from_binary_with_convert(config1.value),
-                 ConfigDB.from_binary_with_convert(config2.value),
-                 ConfigDB.from_binary_with_convert(config3.value)
-               ]
-      end)
-    end
-
-    test "subkeys with full update right merge", %{conn: conn} do
-      config1 =
-        insert(:config,
-          key: ":emoji",
-          value: ConfigDB.to_binary(groups: [a: 1, b: 2], key: [a: 1])
-        )
-
-      config2 =
-        insert(:config,
-          key: ":assets",
-          value: ConfigDB.to_binary(mascots: [a: 1, b: 2], key: [a: 1])
-        )
-
-      %{"configs" => configs} =
-        conn
-        |> get("/api/pleroma/admin/config")
-        |> json_response(200)
-
-      vals =
-        Enum.filter(configs, fn %{"group" => group, "key" => key} ->
-          group == ":pleroma" and key in [config1.key, config2.key]
-        end)
-
-      emoji = Enum.find(vals, fn %{"key" => key} -> key == ":emoji" end)
-      assets = Enum.find(vals, fn %{"key" => key} -> key == ":assets" end)
-
-      emoji_val = ConfigDB.transform_with_out_binary(emoji["value"])
-      assets_val = ConfigDB.transform_with_out_binary(assets["value"])
-
-      assert emoji_val[:groups] == [a: 1, b: 2]
-      assert assets_val[:mascots] == [a: 1, b: 2]
-    end
-  end
-
-  test "POST /api/pleroma/admin/config error", %{conn: conn} do
-    conn = post(conn, "/api/pleroma/admin/config", %{"configs" => []})
-
-    assert json_response(conn, 400) ==
-             %{"error" => "To use this endpoint you need to enable configuration from database."}
-  end
-
-  describe "POST /api/pleroma/admin/config" do
-    setup do
-      http = Application.get_env(:pleroma, :http)
-
-      on_exit(fn ->
-        Application.delete_env(:pleroma, :key1)
-        Application.delete_env(:pleroma, :key2)
-        Application.delete_env(:pleroma, :key3)
-        Application.delete_env(:pleroma, :key4)
-        Application.delete_env(:pleroma, :keyaa1)
-        Application.delete_env(:pleroma, :keyaa2)
-        Application.delete_env(:pleroma, Pleroma.Web.Endpoint.NotReal)
-        Application.delete_env(:pleroma, Pleroma.Captcha.NotReal)
-        Application.put_env(:pleroma, :http, http)
-        Application.put_env(:tesla, :adapter, Tesla.Mock)
-        Restarter.Pleroma.refresh()
-      end)
-    end
-
-    setup do: clear_config(:configurable_from_database, true)
-
-    @tag capture_log: true
-    test "create new config setting in db", %{conn: conn} do
-      ueberauth = Application.get_env(:ueberauth, Ueberauth)
-      on_exit(fn -> Application.put_env(:ueberauth, Ueberauth, ueberauth) end)
-
-      conn =
-        post(conn, "/api/pleroma/admin/config", %{
-          configs: [
-            %{group: ":pleroma", key: ":key1", value: "value1"},
-            %{
-              group: ":ueberauth",
-              key: "Ueberauth",
-              value: [%{"tuple" => [":consumer_secret", "aaaa"]}]
-            },
-            %{
-              group: ":pleroma",
-              key: ":key2",
-              value: %{
-                ":nested_1" => "nested_value1",
-                ":nested_2" => [
-                  %{":nested_22" => "nested_value222"},
-                  %{":nested_33" => %{":nested_44" => "nested_444"}}
-                ]
-              }
-            },
-            %{
-              group: ":pleroma",
-              key: ":key3",
-              value: [
-                %{"nested_3" => ":nested_3", "nested_33" => "nested_33"},
-                %{"nested_4" => true}
-              ]
-            },
-            %{
-              group: ":pleroma",
-              key: ":key4",
-              value: %{":nested_5" => ":upload", "endpoint" => "https://example.com"}
-            },
-            %{
-              group: ":idna",
-              key: ":key5",
-              value: %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]}
-            }
-          ]
-        })
-
-      assert json_response(conn, 200) == %{
-               "configs" => [
-                 %{
-                   "group" => ":pleroma",
-                   "key" => ":key1",
-                   "value" => "value1",
-                   "db" => [":key1"]
-                 },
-                 %{
-                   "group" => ":ueberauth",
-                   "key" => "Ueberauth",
-                   "value" => [%{"tuple" => [":consumer_secret", "aaaa"]}],
-                   "db" => [":consumer_secret"]
-                 },
-                 %{
-                   "group" => ":pleroma",
-                   "key" => ":key2",
-                   "value" => %{
-                     ":nested_1" => "nested_value1",
-                     ":nested_2" => [
-                       %{":nested_22" => "nested_value222"},
-                       %{":nested_33" => %{":nested_44" => "nested_444"}}
-                     ]
-                   },
-                   "db" => [":key2"]
-                 },
-                 %{
-                   "group" => ":pleroma",
-                   "key" => ":key3",
-                   "value" => [
-                     %{"nested_3" => ":nested_3", "nested_33" => "nested_33"},
-                     %{"nested_4" => true}
-                   ],
-                   "db" => [":key3"]
-                 },
-                 %{
-                   "group" => ":pleroma",
-                   "key" => ":key4",
-                   "value" => %{"endpoint" => "https://example.com", ":nested_5" => ":upload"},
-                   "db" => [":key4"]
-                 },
-                 %{
-                   "group" => ":idna",
-                   "key" => ":key5",
-                   "value" => %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]},
-                   "db" => [":key5"]
-                 }
-               ]
-             }
-
-      assert Application.get_env(:pleroma, :key1) == "value1"
-
-      assert Application.get_env(:pleroma, :key2) == %{
-               nested_1: "nested_value1",
-               nested_2: [
-                 %{nested_22: "nested_value222"},
-                 %{nested_33: %{nested_44: "nested_444"}}
-               ]
-             }
-
-      assert Application.get_env(:pleroma, :key3) == [
-               %{"nested_3" => :nested_3, "nested_33" => "nested_33"},
-               %{"nested_4" => true}
-             ]
-
-      assert Application.get_env(:pleroma, :key4) == %{
-               "endpoint" => "https://example.com",
-               nested_5: :upload
-             }
-
-      assert Application.get_env(:idna, :key5) == {"string", Pleroma.Captcha.NotReal, []}
-    end
-
-    test "save configs setting without explicit key", %{conn: conn} do
-      level = Application.get_env(:quack, :level)
-      meta = Application.get_env(:quack, :meta)
-      webhook_url = Application.get_env(:quack, :webhook_url)
-
-      on_exit(fn ->
-        Application.put_env(:quack, :level, level)
-        Application.put_env(:quack, :meta, meta)
-        Application.put_env(:quack, :webhook_url, webhook_url)
-      end)
-
-      conn =
-        post(conn, "/api/pleroma/admin/config", %{
-          configs: [
-            %{
-              group: ":quack",
-              key: ":level",
-              value: ":info"
-            },
-            %{
-              group: ":quack",
-              key: ":meta",
-              value: [":none"]
-            },
-            %{
-              group: ":quack",
-              key: ":webhook_url",
-              value: "https://hooks.slack.com/services/KEY"
-            }
-          ]
-        })
-
-      assert json_response(conn, 200) == %{
-               "configs" => [
-                 %{
-                   "group" => ":quack",
-                   "key" => ":level",
-                   "value" => ":info",
-                   "db" => [":level"]
-                 },
-                 %{
-                   "group" => ":quack",
-                   "key" => ":meta",
-                   "value" => [":none"],
-                   "db" => [":meta"]
-                 },
-                 %{
-                   "group" => ":quack",
-                   "key" => ":webhook_url",
-                   "value" => "https://hooks.slack.com/services/KEY",
-                   "db" => [":webhook_url"]
-                 }
-               ]
-             }
-
-      assert Application.get_env(:quack, :level) == :info
-      assert Application.get_env(:quack, :meta) == [:none]
-      assert Application.get_env(:quack, :webhook_url) == "https://hooks.slack.com/services/KEY"
-    end
-
-    test "saving config with partial update", %{conn: conn} do
-      config = insert(:config, key: ":key1", value: :erlang.term_to_binary(key1: 1, key2: 2))
-
-      conn =
-        post(conn, "/api/pleroma/admin/config", %{
-          configs: [
-            %{group: config.group, key: config.key, value: [%{"tuple" => [":key3", 3]}]}
-          ]
-        })
-
-      assert json_response(conn, 200) == %{
-               "configs" => [
-                 %{
-                   "group" => ":pleroma",
-                   "key" => ":key1",
-                   "value" => [
-                     %{"tuple" => [":key1", 1]},
-                     %{"tuple" => [":key2", 2]},
-                     %{"tuple" => [":key3", 3]}
-                   ],
-                   "db" => [":key1", ":key2", ":key3"]
-                 }
-               ]
-             }
-    end
-
-    test "saving config which need pleroma reboot", %{conn: conn} do
-      chat = Config.get(:chat)
-      on_exit(fn -> Config.put(:chat, chat) end)
-
-      assert post(
-               conn,
-               "/api/pleroma/admin/config",
-               %{
-                 configs: [
-                   %{group: ":pleroma", key: ":chat", value: [%{"tuple" => [":enabled", true]}]}
-                 ]
-               }
-             )
-             |> json_response(200) == %{
-               "configs" => [
-                 %{
-                   "db" => [":enabled"],
-                   "group" => ":pleroma",
-                   "key" => ":chat",
-                   "value" => [%{"tuple" => [":enabled", true]}]
-                 }
-               ],
-               "need_reboot" => true
-             }
-
-      configs =
-        conn
-        |> get("/api/pleroma/admin/config")
-        |> json_response(200)
-
-      assert configs["need_reboot"]
-
-      capture_log(fn ->
-        assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{}
-      end) =~ "pleroma restarted"
-
-      configs =
-        conn
-        |> get("/api/pleroma/admin/config")
-        |> json_response(200)
-
-      assert configs["need_reboot"] == false
-    end
-
-    test "update setting which need reboot, don't change reboot flag until reboot", %{conn: conn} do
-      chat = Config.get(:chat)
-      on_exit(fn -> Config.put(:chat, chat) end)
-
-      assert post(
-               conn,
-               "/api/pleroma/admin/config",
-               %{
-                 configs: [
-                   %{group: ":pleroma", key: ":chat", value: [%{"tuple" => [":enabled", true]}]}
-                 ]
-               }
-             )
-             |> json_response(200) == %{
-               "configs" => [
-                 %{
-                   "db" => [":enabled"],
-                   "group" => ":pleroma",
-                   "key" => ":chat",
-                   "value" => [%{"tuple" => [":enabled", true]}]
-                 }
-               ],
-               "need_reboot" => true
-             }
-
-      assert post(conn, "/api/pleroma/admin/config", %{
-               configs: [
-                 %{group: ":pleroma", key: ":key1", value: [%{"tuple" => [":key3", 3]}]}
-               ]
-             })
-             |> json_response(200) == %{
-               "configs" => [
-                 %{
-                   "group" => ":pleroma",
-                   "key" => ":key1",
-                   "value" => [
-                     %{"tuple" => [":key3", 3]}
-                   ],
-                   "db" => [":key3"]
-                 }
-               ],
-               "need_reboot" => true
-             }
-
-      capture_log(fn ->
-        assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{}
-      end) =~ "pleroma restarted"
-
-      configs =
-        conn
-        |> get("/api/pleroma/admin/config")
-        |> json_response(200)
-
-      assert configs["need_reboot"] == false
-    end
-
-    test "saving config with nested merge", %{conn: conn} do
-      config =
-        insert(:config, key: ":key1", value: :erlang.term_to_binary(key1: 1, key2: [k1: 1, k2: 2]))
-
-      conn =
-        post(conn, "/api/pleroma/admin/config", %{
-          configs: [
-            %{
-              group: config.group,
-              key: config.key,
-              value: [
-                %{"tuple" => [":key3", 3]},
-                %{
-                  "tuple" => [
-                    ":key2",
-                    [
-                      %{"tuple" => [":k2", 1]},
-                      %{"tuple" => [":k3", 3]}
-                    ]
-                  ]
-                }
-              ]
-            }
-          ]
-        })
-
-      assert json_response(conn, 200) == %{
-               "configs" => [
-                 %{
-                   "group" => ":pleroma",
-                   "key" => ":key1",
-                   "value" => [
-                     %{"tuple" => [":key1", 1]},
-                     %{"tuple" => [":key3", 3]},
-                     %{
-                       "tuple" => [
-                         ":key2",
-                         [
-                           %{"tuple" => [":k1", 1]},
-                           %{"tuple" => [":k2", 1]},
-                           %{"tuple" => [":k3", 3]}
-                         ]
-                       ]
-                     }
-                   ],
-                   "db" => [":key1", ":key3", ":key2"]
-                 }
-               ]
-             }
-    end
-
-    test "saving special atoms", %{conn: conn} do
-      conn =
-        post(conn, "/api/pleroma/admin/config", %{
-          "configs" => [
-            %{
-              "group" => ":pleroma",
-              "key" => ":key1",
-              "value" => [
-                %{
-                  "tuple" => [
-                    ":ssl_options",
-                    [%{"tuple" => [":versions", [":tlsv1", ":tlsv1.1", ":tlsv1.2"]]}]
-                  ]
-                }
-              ]
-            }
-          ]
-        })
-
-      assert json_response(conn, 200) == %{
-               "configs" => [
-                 %{
-                   "group" => ":pleroma",
-                   "key" => ":key1",
-                   "value" => [
-                     %{
-                       "tuple" => [
-                         ":ssl_options",
-                         [%{"tuple" => [":versions", [":tlsv1", ":tlsv1.1", ":tlsv1.2"]]}]
-                       ]
-                     }
-                   ],
-                   "db" => [":ssl_options"]
-                 }
-               ]
-             }
-
-      assert Application.get_env(:pleroma, :key1) == [
-               ssl_options: [versions: [:tlsv1, :"tlsv1.1", :"tlsv1.2"]]
-             ]
-    end
-
-    test "saving full setting if value is in full_key_update list", %{conn: conn} do
-      backends = Application.get_env(:logger, :backends)
-      on_exit(fn -> Application.put_env(:logger, :backends, backends) end)
-
-      config =
-        insert(:config,
-          group: ":logger",
-          key: ":backends",
-          value: :erlang.term_to_binary([])
-        )
-
-      Pleroma.Config.TransferTask.load_and_update_env([], false)
-
-      assert Application.get_env(:logger, :backends) == []
-
-      conn =
-        post(conn, "/api/pleroma/admin/config", %{
-          configs: [
-            %{
-              group: config.group,
-              key: config.key,
-              value: [":console"]
-            }
-          ]
-        })
-
-      assert json_response(conn, 200) == %{
-               "configs" => [
-                 %{
-                   "group" => ":logger",
-                   "key" => ":backends",
-                   "value" => [
-                     ":console"
-                   ],
-                   "db" => [":backends"]
-                 }
-               ]
-             }
-
-      assert Application.get_env(:logger, :backends) == [
-               :console
-             ]
-    end
-
-    test "saving full setting if value is not keyword", %{conn: conn} do
-      config =
-        insert(:config,
-          group: ":tesla",
-          key: ":adapter",
-          value: :erlang.term_to_binary(Tesla.Adapter.Hackey)
-        )
-
-      conn =
-        post(conn, "/api/pleroma/admin/config", %{
-          configs: [
-            %{group: config.group, key: config.key, value: "Tesla.Adapter.Httpc"}
-          ]
-        })
-
-      assert json_response(conn, 200) == %{
-               "configs" => [
-                 %{
-                   "group" => ":tesla",
-                   "key" => ":adapter",
-                   "value" => "Tesla.Adapter.Httpc",
-                   "db" => [":adapter"]
-                 }
-               ]
-             }
-    end
-
-    test "update config setting & delete with fallback to default value", %{
-      conn: conn,
-      admin: admin,
-      token: token
-    } do
-      ueberauth = Application.get_env(:ueberauth, Ueberauth)
-      config1 = insert(:config, key: ":keyaa1")
-      config2 = insert(:config, key: ":keyaa2")
-
-      config3 =
-        insert(:config,
-          group: ":ueberauth",
-          key: "Ueberauth"
-        )
-
-      conn =
-        post(conn, "/api/pleroma/admin/config", %{
-          configs: [
-            %{group: config1.group, key: config1.key, value: "another_value"},
-            %{group: config2.group, key: config2.key, value: "another_value"}
-          ]
-        })
-
-      assert json_response(conn, 200) == %{
-               "configs" => [
-                 %{
-                   "group" => ":pleroma",
-                   "key" => config1.key,
-                   "value" => "another_value",
-                   "db" => [":keyaa1"]
-                 },
-                 %{
-                   "group" => ":pleroma",
-                   "key" => config2.key,
-                   "value" => "another_value",
-                   "db" => [":keyaa2"]
-                 }
-               ]
-             }
-
-      assert Application.get_env(:pleroma, :keyaa1) == "another_value"
-      assert Application.get_env(:pleroma, :keyaa2) == "another_value"
-      assert Application.get_env(:ueberauth, Ueberauth) == ConfigDB.from_binary(config3.value)
-
-      conn =
-        build_conn()
-        |> assign(:user, admin)
-        |> assign(:token, token)
-        |> post("/api/pleroma/admin/config", %{
-          configs: [
-            %{group: config2.group, key: config2.key, delete: true},
-            %{
-              group: ":ueberauth",
-              key: "Ueberauth",
-              delete: true
-            }
-          ]
-        })
-
-      assert json_response(conn, 200) == %{
-               "configs" => []
-             }
-
-      assert Application.get_env(:ueberauth, Ueberauth) == ueberauth
-      refute Keyword.has_key?(Application.get_all_env(:pleroma), :keyaa2)
-    end
-
-    test "common config example", %{conn: conn} do
-      conn =
-        post(conn, "/api/pleroma/admin/config", %{
-          configs: [
-            %{
-              "group" => ":pleroma",
-              "key" => "Pleroma.Captcha.NotReal",
-              "value" => [
-                %{"tuple" => [":enabled", false]},
-                %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]},
-                %{"tuple" => [":seconds_valid", 60]},
-                %{"tuple" => [":path", ""]},
-                %{"tuple" => [":key1", nil]},
-                %{"tuple" => [":partial_chain", "&:hackney_connect.partial_chain/1"]},
-                %{"tuple" => [":regex1", "~r/https:\/\/example.com/"]},
-                %{"tuple" => [":regex2", "~r/https:\/\/example.com/u"]},
-                %{"tuple" => [":regex3", "~r/https:\/\/example.com/i"]},
-                %{"tuple" => [":regex4", "~r/https:\/\/example.com/s"]},
-                %{"tuple" => [":name", "Pleroma"]}
-              ]
-            }
-          ]
-        })
-
-      assert Config.get([Pleroma.Captcha.NotReal, :name]) == "Pleroma"
-
-      assert json_response(conn, 200) == %{
-               "configs" => [
-                 %{
-                   "group" => ":pleroma",
-                   "key" => "Pleroma.Captcha.NotReal",
-                   "value" => [
-                     %{"tuple" => [":enabled", false]},
-                     %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]},
-                     %{"tuple" => [":seconds_valid", 60]},
-                     %{"tuple" => [":path", ""]},
-                     %{"tuple" => [":key1", nil]},
-                     %{"tuple" => [":partial_chain", "&:hackney_connect.partial_chain/1"]},
-                     %{"tuple" => [":regex1", "~r/https:\\/\\/example.com/"]},
-                     %{"tuple" => [":regex2", "~r/https:\\/\\/example.com/u"]},
-                     %{"tuple" => [":regex3", "~r/https:\\/\\/example.com/i"]},
-                     %{"tuple" => [":regex4", "~r/https:\\/\\/example.com/s"]},
-                     %{"tuple" => [":name", "Pleroma"]}
-                   ],
-                   "db" => [
-                     ":enabled",
-                     ":method",
-                     ":seconds_valid",
-                     ":path",
-                     ":key1",
-                     ":partial_chain",
-                     ":regex1",
-                     ":regex2",
-                     ":regex3",
-                     ":regex4",
-                     ":name"
-                   ]
-                 }
-               ]
-             }
-    end
-
-    test "tuples with more than two values", %{conn: conn} do
-      conn =
-        post(conn, "/api/pleroma/admin/config", %{
-          configs: [
-            %{
-              "group" => ":pleroma",
-              "key" => "Pleroma.Web.Endpoint.NotReal",
-              "value" => [
-                %{
-                  "tuple" => [
-                    ":http",
-                    [
-                      %{
-                        "tuple" => [
-                          ":key2",
-                          [
-                            %{
-                              "tuple" => [
-                                ":_",
-                                [
-                                  %{
-                                    "tuple" => [
-                                      "/api/v1/streaming",
-                                      "Pleroma.Web.MastodonAPI.WebsocketHandler",
-                                      []
-                                    ]
-                                  },
-                                  %{
-                                    "tuple" => [
-                                      "/websocket",
-                                      "Phoenix.Endpoint.CowboyWebSocket",
-                                      %{
-                                        "tuple" => [
-                                          "Phoenix.Transports.WebSocket",
-                                          %{
-                                            "tuple" => [
-                                              "Pleroma.Web.Endpoint",
-                                              "Pleroma.Web.UserSocket",
-                                              []
-                                            ]
-                                          }
-                                        ]
-                                      }
-                                    ]
-                                  },
-                                  %{
-                                    "tuple" => [
-                                      ":_",
-                                      "Phoenix.Endpoint.Cowboy2Handler",
-                                      %{"tuple" => ["Pleroma.Web.Endpoint", []]}
-                                    ]
-                                  }
-                                ]
-                              ]
-                            }
-                          ]
-                        ]
-                      }
-                    ]
-                  ]
-                }
-              ]
-            }
-          ]
-        })
-
-      assert json_response(conn, 200) == %{
-               "configs" => [
-                 %{
-                   "group" => ":pleroma",
-                   "key" => "Pleroma.Web.Endpoint.NotReal",
-                   "value" => [
-                     %{
-                       "tuple" => [
-                         ":http",
-                         [
-                           %{
-                             "tuple" => [
-                               ":key2",
-                               [
-                                 %{
-                                   "tuple" => [
-                                     ":_",
-                                     [
-                                       %{
-                                         "tuple" => [
-                                           "/api/v1/streaming",
-                                           "Pleroma.Web.MastodonAPI.WebsocketHandler",
-                                           []
-                                         ]
-                                       },
-                                       %{
-                                         "tuple" => [
-                                           "/websocket",
-                                           "Phoenix.Endpoint.CowboyWebSocket",
-                                           %{
-                                             "tuple" => [
-                                               "Phoenix.Transports.WebSocket",
-                                               %{
-                                                 "tuple" => [
-                                                   "Pleroma.Web.Endpoint",
-                                                   "Pleroma.Web.UserSocket",
-                                                   []
-                                                 ]
-                                               }
-                                             ]
-                                           }
-                                         ]
-                                       },
-                                       %{
-                                         "tuple" => [
-                                           ":_",
-                                           "Phoenix.Endpoint.Cowboy2Handler",
-                                           %{"tuple" => ["Pleroma.Web.Endpoint", []]}
-                                         ]
-                                       }
-                                     ]
-                                   ]
-                                 }
-                               ]
-                             ]
-                           }
-                         ]
-                       ]
-                     }
-                   ],
-                   "db" => [":http"]
-                 }
-               ]
-             }
-    end
-
-    test "settings with nesting map", %{conn: conn} do
-      conn =
-        post(conn, "/api/pleroma/admin/config", %{
-          configs: [
-            %{
-              "group" => ":pleroma",
-              "key" => ":key1",
-              "value" => [
-                %{"tuple" => [":key2", "some_val"]},
-                %{
-                  "tuple" => [
-                    ":key3",
-                    %{
-                      ":max_options" => 20,
-                      ":max_option_chars" => 200,
-                      ":min_expiration" => 0,
-                      ":max_expiration" => 31_536_000,
-                      "nested" => %{
-                        ":max_options" => 20,
-                        ":max_option_chars" => 200,
-                        ":min_expiration" => 0,
-                        ":max_expiration" => 31_536_000
-                      }
-                    }
-                  ]
-                }
-              ]
-            }
-          ]
-        })
-
-      assert json_response(conn, 200) ==
-               %{
-                 "configs" => [
-                   %{
-                     "group" => ":pleroma",
-                     "key" => ":key1",
-                     "value" => [
-                       %{"tuple" => [":key2", "some_val"]},
-                       %{
-                         "tuple" => [
-                           ":key3",
-                           %{
-                             ":max_expiration" => 31_536_000,
-                             ":max_option_chars" => 200,
-                             ":max_options" => 20,
-                             ":min_expiration" => 0,
-                             "nested" => %{
-                               ":max_expiration" => 31_536_000,
-                               ":max_option_chars" => 200,
-                               ":max_options" => 20,
-                               ":min_expiration" => 0
-                             }
-                           }
-                         ]
-                       }
-                     ],
-                     "db" => [":key2", ":key3"]
-                   }
-                 ]
-               }
-    end
-
-    test "value as map", %{conn: conn} do
-      conn =
-        post(conn, "/api/pleroma/admin/config", %{
-          configs: [
-            %{
-              "group" => ":pleroma",
-              "key" => ":key1",
-              "value" => %{"key" => "some_val"}
-            }
-          ]
-        })
-
-      assert json_response(conn, 200) ==
-               %{
-                 "configs" => [
-                   %{
-                     "group" => ":pleroma",
-                     "key" => ":key1",
-                     "value" => %{"key" => "some_val"},
-                     "db" => [":key1"]
-                   }
-                 ]
-               }
-    end
-
-    test "queues key as atom", %{conn: conn} do
-      conn =
-        post(conn, "/api/pleroma/admin/config", %{
-          configs: [
-            %{
-              "group" => ":oban",
-              "key" => ":queues",
-              "value" => [
-                %{"tuple" => [":federator_incoming", 50]},
-                %{"tuple" => [":federator_outgoing", 50]},
-                %{"tuple" => [":web_push", 50]},
-                %{"tuple" => [":mailer", 10]},
-                %{"tuple" => [":transmogrifier", 20]},
-                %{"tuple" => [":scheduled_activities", 10]},
-                %{"tuple" => [":background", 5]}
-              ]
-            }
-          ]
-        })
-
-      assert json_response(conn, 200) == %{
-               "configs" => [
-                 %{
-                   "group" => ":oban",
-                   "key" => ":queues",
-                   "value" => [
-                     %{"tuple" => [":federator_incoming", 50]},
-                     %{"tuple" => [":federator_outgoing", 50]},
-                     %{"tuple" => [":web_push", 50]},
-                     %{"tuple" => [":mailer", 10]},
-                     %{"tuple" => [":transmogrifier", 20]},
-                     %{"tuple" => [":scheduled_activities", 10]},
-                     %{"tuple" => [":background", 5]}
-                   ],
-                   "db" => [
-                     ":federator_incoming",
-                     ":federator_outgoing",
-                     ":web_push",
-                     ":mailer",
-                     ":transmogrifier",
-                     ":scheduled_activities",
-                     ":background"
-                   ]
-                 }
-               ]
-             }
-    end
-
-    test "delete part of settings by atom subkeys", %{conn: conn} do
-      config =
-        insert(:config,
-          key: ":keyaa1",
-          value: :erlang.term_to_binary(subkey1: "val1", subkey2: "val2", subkey3: "val3")
-        )
-
-      conn =
-        post(conn, "/api/pleroma/admin/config", %{
-          configs: [
-            %{
-              group: config.group,
-              key: config.key,
-              subkeys: [":subkey1", ":subkey3"],
-              delete: true
-            }
-          ]
-        })
-
-      assert json_response(conn, 200) == %{
-               "configs" => [
-                 %{
-                   "group" => ":pleroma",
-                   "key" => ":keyaa1",
-                   "value" => [%{"tuple" => [":subkey2", "val2"]}],
-                   "db" => [":subkey2"]
-                 }
-               ]
-             }
-    end
-
-    test "proxy tuple localhost", %{conn: conn} do
-      conn =
-        post(conn, "/api/pleroma/admin/config", %{
-          configs: [
-            %{
-              group: ":pleroma",
-              key: ":http",
-              value: [
-                %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]}
-              ]
-            }
-          ]
-        })
-
-      assert %{
-               "configs" => [
-                 %{
-                   "group" => ":pleroma",
-                   "key" => ":http",
-                   "value" => value,
-                   "db" => db
-                 }
-               ]
-             } = json_response(conn, 200)
-
-      assert %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]} in value
-      assert ":proxy_url" in db
-    end
-
-    test "proxy tuple domain", %{conn: conn} do
-      conn =
-        post(conn, "/api/pleroma/admin/config", %{
-          configs: [
-            %{
-              group: ":pleroma",
-              key: ":http",
-              value: [
-                %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]}
-              ]
-            }
-          ]
-        })
-
-      assert %{
-               "configs" => [
-                 %{
-                   "group" => ":pleroma",
-                   "key" => ":http",
-                   "value" => value,
-                   "db" => db
-                 }
-               ]
-             } = json_response(conn, 200)
-
-      assert %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]} in value
-      assert ":proxy_url" in db
-    end
-
-    test "proxy tuple ip", %{conn: conn} do
-      conn =
-        post(conn, "/api/pleroma/admin/config", %{
-          configs: [
-            %{
-              group: ":pleroma",
-              key: ":http",
-              value: [
-                %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]}
-              ]
-            }
-          ]
-        })
-
-      assert %{
-               "configs" => [
-                 %{
-                   "group" => ":pleroma",
-                   "key" => ":http",
-                   "value" => value,
-                   "db" => db
-                 }
-               ]
-             } = json_response(conn, 200)
-
-      assert %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]} in value
-      assert ":proxy_url" in db
-    end
-
-    @tag capture_log: true
-    test "doesn't set keys not in the whitelist", %{conn: conn} do
-      clear_config(:database_config_whitelist, [
-        {:pleroma, :key1},
-        {:pleroma, :key2},
-        {:pleroma, Pleroma.Captcha.NotReal},
-        {:not_real}
-      ])
-
-      post(conn, "/api/pleroma/admin/config", %{
-        configs: [
-          %{group: ":pleroma", key: ":key1", value: "value1"},
-          %{group: ":pleroma", key: ":key2", value: "value2"},
-          %{group: ":pleroma", key: ":key3", value: "value3"},
-          %{group: ":pleroma", key: "Pleroma.Web.Endpoint.NotReal", value: "value4"},
-          %{group: ":pleroma", key: "Pleroma.Captcha.NotReal", value: "value5"},
-          %{group: ":not_real", key: ":anything", value: "value6"}
-        ]
-      })
-
-      assert Application.get_env(:pleroma, :key1) == "value1"
-      assert Application.get_env(:pleroma, :key2) == "value2"
-      assert Application.get_env(:pleroma, :key3) == nil
-      assert Application.get_env(:pleroma, Pleroma.Web.Endpoint.NotReal) == nil
-      assert Application.get_env(:pleroma, Pleroma.Captcha.NotReal) == "value5"
-      assert Application.get_env(:not_real, :anything) == "value6"
-    end
-  end
-
-  describe "GET /api/pleroma/admin/restart" do
-    setup do: clear_config(:configurable_from_database, true)
-
-    test "pleroma restarts", %{conn: conn} do
-      capture_log(fn ->
-        assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{}
-      end) =~ "pleroma restarted"
-
-      refute Restarter.Pleroma.need_reboot?()
-    end
-  end
-
-  test "need_reboot flag", %{conn: conn} do
-    assert conn
-           |> get("/api/pleroma/admin/need_reboot")
-           |> json_response(200) == %{"need_reboot" => false}
-
-    Restarter.Pleroma.need_reboot()
-
-    assert conn
-           |> get("/api/pleroma/admin/need_reboot")
-           |> json_response(200) == %{"need_reboot" => true}
-
-    on_exit(fn -> Restarter.Pleroma.refresh() end)
-  end
-
-  describe "GET /api/pleroma/admin/users/:nickname/statuses" do
-    setup do
-      user = insert(:user)
-
-      date1 = (DateTime.to_unix(DateTime.utc_now()) + 2000) |> DateTime.from_unix!()
-      date2 = (DateTime.to_unix(DateTime.utc_now()) + 1000) |> DateTime.from_unix!()
-      date3 = (DateTime.to_unix(DateTime.utc_now()) + 3000) |> DateTime.from_unix!()
-
-      insert(:note_activity, user: user, published: date1)
-      insert(:note_activity, user: user, published: date2)
-      insert(:note_activity, user: user, published: date3)
-
-      %{user: user}
-    end
-
-    test "renders user's statuses", %{conn: conn, user: user} do
-      conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
-
-      assert json_response(conn, 200) |> length() == 3
-    end
-
-    test "renders user's statuses with a limit", %{conn: conn, user: user} do
-      conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=2")
-
-      assert json_response(conn, 200) |> length() == 2
-    end
-
-    test "doesn't return private statuses by default", %{conn: conn, user: user} do
-      {:ok, _private_status} = CommonAPI.post(user, %{status: "private", visibility: "private"})
-
-      {:ok, _public_status} = CommonAPI.post(user, %{status: "public", visibility: "public"})
-
-      conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
-
-      assert json_response(conn, 200) |> length() == 4
-    end
-
-    test "returns private statuses with godmode on", %{conn: conn, user: user} do
-      {:ok, _private_status} = CommonAPI.post(user, %{status: "private", visibility: "private"})
-
-      {:ok, _public_status} = CommonAPI.post(user, %{status: "public", visibility: "public"})
-
-      conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?godmode=true")
-
-      assert json_response(conn, 200) |> length() == 5
-    end
-
-    test "excludes reblogs by default", %{conn: conn, user: user} do
-      other_user = insert(:user)
-      {:ok, activity} = CommonAPI.post(user, %{status: "."})
-      {:ok, %Activity{}} = CommonAPI.repeat(activity.id, other_user)
-
-      conn_res = get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses")
-      assert json_response(conn_res, 200) |> length() == 0
-
-      conn_res =
-        get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses?with_reblogs=true")
-
-      assert json_response(conn_res, 200) |> length() == 1
-    end
-  end
-
-  describe "GET /api/pleroma/admin/moderation_log" do
-    setup do
-      moderator = insert(:user, is_moderator: true)
-
-      %{moderator: moderator}
-    end
-
-    test "returns the log", %{conn: conn, admin: admin} do
-      Repo.insert(%ModerationLog{
-        data: %{
-          actor: %{
-            "id" => admin.id,
-            "nickname" => admin.nickname,
-            "type" => "user"
-          },
-          action: "relay_follow",
-          target: "https://example.org/relay"
-        },
-        inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
-      })
-
-      Repo.insert(%ModerationLog{
-        data: %{
-          actor: %{
-            "id" => admin.id,
-            "nickname" => admin.nickname,
-            "type" => "user"
-          },
-          action: "relay_unfollow",
-          target: "https://example.org/relay"
-        },
-        inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
-      })
-
-      conn = get(conn, "/api/pleroma/admin/moderation_log")
-
-      response = json_response(conn, 200)
-      [first_entry, second_entry] = response["items"]
-
-      assert response["total"] == 2
-      assert first_entry["data"]["action"] == "relay_unfollow"
-
-      assert first_entry["message"] ==
-               "@#{admin.nickname} unfollowed relay: https://example.org/relay"
-
-      assert second_entry["data"]["action"] == "relay_follow"
-
-      assert second_entry["message"] ==
-               "@#{admin.nickname} followed relay: https://example.org/relay"
-    end
-
-    test "returns the log with pagination", %{conn: conn, admin: admin} do
-      Repo.insert(%ModerationLog{
-        data: %{
-          actor: %{
-            "id" => admin.id,
-            "nickname" => admin.nickname,
-            "type" => "user"
-          },
-          action: "relay_follow",
-          target: "https://example.org/relay"
-        },
-        inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
-      })
-
-      Repo.insert(%ModerationLog{
-        data: %{
-          actor: %{
-            "id" => admin.id,
-            "nickname" => admin.nickname,
-            "type" => "user"
-          },
-          action: "relay_unfollow",
-          target: "https://example.org/relay"
-        },
-        inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
-      })
-
-      conn1 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=1")
-
-      response1 = json_response(conn1, 200)
-      [first_entry] = response1["items"]
-
-      assert response1["total"] == 2
-      assert response1["items"] |> length() == 1
-      assert first_entry["data"]["action"] == "relay_unfollow"
-
-      assert first_entry["message"] ==
-               "@#{admin.nickname} unfollowed relay: https://example.org/relay"
-
-      conn2 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=2")
-
-      response2 = json_response(conn2, 200)
-      [second_entry] = response2["items"]
-
-      assert response2["total"] == 2
-      assert response2["items"] |> length() == 1
-      assert second_entry["data"]["action"] == "relay_follow"
-
-      assert second_entry["message"] ==
-               "@#{admin.nickname} followed relay: https://example.org/relay"
-    end
+      assert second_entry["message"] ==
+               "@#{admin.nickname} followed relay: https://example.org/relay"
+    end
 
     test "filters log by date", %{conn: conn, admin: admin} do
       first_date = "2017-08-15T15:47:06Z"
@@ -3169,6 +1525,15 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
     end
   end
 
+  test "gets a remote users when [:instance, :limit_to_local_content] is set to :unauthenticated",
+       %{conn: conn} do
+    clear_config(Pleroma.Config.get([:instance, :limit_to_local_content]), :unauthenticated)
+    user = insert(:user, %{local: false, nickname: "u@peer1.com"})
+    conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials")
+
+    assert json_response(conn, 200)
+  end
+
   describe "GET /users/:nickname/credentials" do
     test "gets the user credentials", %{conn: conn} do
       user = insert(:user)
@@ -3191,8 +1556,12 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
   end
 
   describe "PATCH /users/:nickname/credentials" do
-    test "changes password and email", %{conn: conn, admin: admin} do
+    setup do
       user = insert(:user)
+      [user: user]
+    end
+
+    test "changes password and email", %{conn: conn, admin: admin, user: user} do
       assert user.password_reset_pending == false
 
       conn =
@@ -3222,9 +1591,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
                "@#{admin.nickname} forced password reset for users: @#{user.nickname}"
     end
 
-    test "returns 403 if requested by a non-admin" do
-      user = insert(:user)
-
+    test "returns 403 if requested by a non-admin", %{user: user} do
       conn =
         build_conn()
         |> assign(:user, user)
@@ -3236,6 +1603,31 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
 
       assert json_response(conn, :forbidden)
     end
+
+    test "changes actor type from permitted list", %{conn: conn, user: user} do
+      assert user.actor_type == "Person"
+
+      assert patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
+               "actor_type" => "Service"
+             })
+             |> json_response(200) == %{"status" => "success"}
+
+      updated_user = User.get_by_id(user.id)
+
+      assert updated_user.actor_type == "Service"
+
+      assert patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
+               "actor_type" => "Application"
+             })
+             |> json_response(400) == %{"errors" => %{"actor_type" => "is invalid"}}
+    end
+
+    test "update non existing user", %{conn: conn} do
+      assert patch(conn, "/api/pleroma/admin/users/non-existing/credentials", %{
+               "password" => "new_password"
+             })
+             |> json_response(404) == %{"error" => "Not found"}
+    end
   end
 
   describe "PATCH /users/:nickname/force_password_reset" do
@@ -3254,57 +1646,6 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
     end
   end
 
-  describe "relays" do
-    test "POST /relay", %{conn: conn, admin: admin} do
-      conn =
-        post(conn, "/api/pleroma/admin/relay", %{
-          relay_url: "http://mastodon.example.org/users/admin"
-        })
-
-      assert json_response(conn, 200) == "http://mastodon.example.org/users/admin"
-
-      log_entry = Repo.one(ModerationLog)
-
-      assert ModerationLog.get_log_entry_message(log_entry) ==
-               "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin"
-    end
-
-    test "GET /relay", %{conn: conn} do
-      relay_user = Pleroma.Web.ActivityPub.Relay.get_actor()
-
-      ["http://mastodon.example.org/users/admin", "https://mstdn.io/users/mayuutann"]
-      |> Enum.each(fn ap_id ->
-        {:ok, user} = User.get_or_fetch_by_ap_id(ap_id)
-        User.follow(relay_user, user)
-      end)
-
-      conn = get(conn, "/api/pleroma/admin/relay")
-
-      assert json_response(conn, 200)["relays"] -- ["mastodon.example.org", "mstdn.io"] == []
-    end
-
-    test "DELETE /relay", %{conn: conn, admin: admin} do
-      post(conn, "/api/pleroma/admin/relay", %{
-        relay_url: "http://mastodon.example.org/users/admin"
-      })
-
-      conn =
-        delete(conn, "/api/pleroma/admin/relay", %{
-          relay_url: "http://mastodon.example.org/users/admin"
-        })
-
-      assert json_response(conn, 200) == "http://mastodon.example.org/users/admin"
-
-      [log_entry_one, log_entry_two] = Repo.all(ModerationLog)
-
-      assert ModerationLog.get_log_entry_message(log_entry_one) ==
-               "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin"
-
-      assert ModerationLog.get_log_entry_message(log_entry_two) ==
-               "@#{admin.nickname} unfollowed relay: http://mastodon.example.org/users/admin"
-    end
-  end
-
   describe "instances" do
     test "GET /instances/:instance/statuses", %{conn: conn} do
       user = insert(:user, local: false, nickname: "archaeme@archae.me")
@@ -3391,116 +1732,9 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
                "@#{admin.nickname} re-sent confirmation email for users: @#{first_user.nickname}, @#{
                  second_user.nickname
                }"
-    end
-  end
-
-  describe "POST /reports/:id/notes" do
-    setup %{conn: conn, admin: admin} do
-      [reporter, target_user] = insert_pair(:user)
-      activity = insert(:note_activity, user: target_user)
-
-      {:ok, %{id: report_id}} =
-        CommonAPI.report(reporter, %{
-          account_id: target_user.id,
-          comment: "I feel offended",
-          status_ids: [activity.id]
-        })
-
-      post(conn, "/api/pleroma/admin/reports/#{report_id}/notes", %{
-        content: "this is disgusting!"
-      })
-
-      post(conn, "/api/pleroma/admin/reports/#{report_id}/notes", %{
-        content: "this is disgusting2!"
-      })
-
-      %{
-        admin_id: admin.id,
-        report_id: report_id
-      }
-    end
-
-    test "it creates report note", %{admin_id: admin_id, report_id: report_id} do
-      [note, _] = Repo.all(ReportNote)
-
-      assert %{
-               activity_id: ^report_id,
-               content: "this is disgusting!",
-               user_id: ^admin_id
-             } = note
-    end
-
-    test "it returns reports with notes", %{conn: conn, admin: admin} do
-      conn = get(conn, "/api/pleroma/admin/reports")
-
-      response = json_response(conn, 200)
-      notes = hd(response["reports"])["notes"]
-      [note, _] = notes
-
-      assert note["user"]["nickname"] == admin.nickname
-      assert note["content"] == "this is disgusting!"
-      assert note["created_at"]
-      assert response["total"] == 1
-    end
-
-    test "it deletes the note", %{conn: conn, report_id: report_id} do
-      assert ReportNote |> Repo.all() |> length() == 2
-
-      [note, _] = Repo.all(ReportNote)
-
-      delete(conn, "/api/pleroma/admin/reports/#{report_id}/notes/#{note.id}")
-
-      assert ReportNote |> Repo.all() |> length() == 1
-    end
-  end
-
-  describe "GET /api/pleroma/admin/config/descriptions" do
-    test "structure", %{conn: conn} do
-      admin = insert(:user, is_admin: true)
-
-      conn =
-        assign(conn, :user, admin)
-        |> get("/api/pleroma/admin/config/descriptions")
-
-      assert [child | _others] = json_response(conn, 200)
-
-      assert child["children"]
-      assert child["key"]
-      assert String.starts_with?(child["group"], ":")
-      assert child["description"]
-    end
-
-    test "filters by database configuration whitelist", %{conn: conn} do
-      clear_config(:database_config_whitelist, [
-        {:pleroma, :instance},
-        {:pleroma, :activitypub},
-        {:pleroma, Pleroma.Upload},
-        {:esshd}
-      ])
-
-      admin = insert(:user, is_admin: true)
-
-      conn =
-        assign(conn, :user, admin)
-        |> get("/api/pleroma/admin/config/descriptions")
-
-      children = json_response(conn, 200)
-
-      assert length(children) == 4
 
-      assert Enum.count(children, fn c -> c["group"] == ":pleroma" end) == 3
-
-      instance = Enum.find(children, fn c -> c["key"] == ":instance" end)
-      assert instance["children"]
-
-      activitypub = Enum.find(children, fn c -> c["key"] == ":activitypub" end)
-      assert activitypub["children"]
-
-      web_endpoint = Enum.find(children, fn c -> c["key"] == "Pleroma.Upload" end)
-      assert web_endpoint["children"]
-
-      esshd = Enum.find(children, fn c -> c["group"] == ":esshd" end)
-      assert esshd["children"]
+      ObanHelpers.perform_all()
+      assert_email_sent(Pleroma.Emails.UserEmail.account_confirmation_email(first_user))
     end
   end
 
@@ -3521,190 +1755,25 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
       assert %{"direct" => 0, "private" => 0, "public" => 1, "unlisted" => 2} =
                response["status_visibility"]
     end
-  end
-
-  describe "POST /api/pleroma/admin/oauth_app" do
-    test "errors", %{conn: conn} do
-      response = conn |> post("/api/pleroma/admin/oauth_app", %{}) |> json_response(200)
-
-      assert response == %{"name" => "can't be blank", "redirect_uris" => "can't be blank"}
-    end
-
-    test "success", %{conn: conn} do
-      base_url = Web.base_url()
-      app_name = "Trusted app"
-
-      response =
-        conn
-        |> post("/api/pleroma/admin/oauth_app", %{
-          name: app_name,
-          redirect_uris: base_url
-        })
-        |> json_response(200)
-
-      assert %{
-               "client_id" => _,
-               "client_secret" => _,
-               "name" => ^app_name,
-               "redirect_uri" => ^base_url,
-               "trusted" => false
-             } = response
-    end
-
-    test "with trusted", %{conn: conn} do
-      base_url = Web.base_url()
-      app_name = "Trusted app"
-
-      response =
-        conn
-        |> post("/api/pleroma/admin/oauth_app", %{
-          name: app_name,
-          redirect_uris: base_url,
-          trusted: true
-        })
-        |> json_response(200)
-
-      assert %{
-               "client_id" => _,
-               "client_secret" => _,
-               "name" => ^app_name,
-               "redirect_uri" => ^base_url,
-               "trusted" => true
-             } = response
-    end
-  end
-
-  describe "GET /api/pleroma/admin/oauth_app" do
-    setup do
-      app = insert(:oauth_app)
-      {:ok, app: app}
-    end
-
-    test "list", %{conn: conn} do
-      response =
-        conn
-        |> get("/api/pleroma/admin/oauth_app")
-        |> json_response(200)
-
-      assert %{"apps" => apps, "count" => count, "page_size" => _} = response
-
-      assert length(apps) == count
-    end
-
-    test "with page size", %{conn: conn} do
-      insert(:oauth_app)
-      page_size = 1
-
-      response =
-        conn
-        |> get("/api/pleroma/admin/oauth_app", %{page_size: to_string(page_size)})
-        |> json_response(200)
-
-      assert %{"apps" => apps, "count" => _, "page_size" => ^page_size} = response
-
-      assert length(apps) == page_size
-    end
-
-    test "search by client name", %{conn: conn, app: app} do
-      response =
-        conn
-        |> get("/api/pleroma/admin/oauth_app", %{name: app.client_name})
-        |> json_response(200)
-
-      assert %{"apps" => [returned], "count" => _, "page_size" => _} = response
-
-      assert returned["client_id"] == app.client_id
-      assert returned["name"] == app.client_name
-    end
-
-    test "search by client id", %{conn: conn, app: app} do
-      response =
-        conn
-        |> get("/api/pleroma/admin/oauth_app", %{client_id: app.client_id})
-        |> json_response(200)
-
-      assert %{"apps" => [returned], "count" => _, "page_size" => _} = response
-
-      assert returned["client_id"] == app.client_id
-      assert returned["name"] == app.client_name
-    end
-
-    test "only trusted", %{conn: conn} do
-      app = insert(:oauth_app, trusted: true)
-
-      response =
-        conn
-        |> get("/api/pleroma/admin/oauth_app", %{trusted: true})
-        |> json_response(200)
-
-      assert %{"apps" => [returned], "count" => _, "page_size" => _} = response
-
-      assert returned["client_id"] == app.client_id
-      assert returned["name"] == app.client_name
-    end
-  end
-
-  describe "DELETE /api/pleroma/admin/oauth_app/:id" do
-    test "with id", %{conn: conn} do
-      app = insert(:oauth_app)
-
-      response =
-        conn
-        |> delete("/api/pleroma/admin/oauth_app/" <> to_string(app.id))
-        |> json_response(:no_content)
-
-      assert response == ""
-    end
-
-    test "with non existance id", %{conn: conn} do
-      response =
-        conn
-        |> delete("/api/pleroma/admin/oauth_app/0")
-        |> json_response(:bad_request)
-
-      assert response == ""
-    end
-  end
 
-  describe "PATCH /api/pleroma/admin/oauth_app/:id" do
-    test "with id", %{conn: conn} do
-      app = insert(:oauth_app)
+    test "by instance", %{conn: conn} do
+      admin = insert(:user, is_admin: true)
+      user1 = insert(:user)
+      instance2 = "instance2.tld"
+      user2 = insert(:user, %{ap_id: "https://#{instance2}/@actor"})
 
-      name = "another name"
-      url = "https://example.com"
-      scopes = ["admin"]
-      id = app.id
-      website = "http://website.com"
+      CommonAPI.post(user1, %{visibility: "public", status: "hey"})
+      CommonAPI.post(user2, %{visibility: "unlisted", status: "hey"})
+      CommonAPI.post(user2, %{visibility: "private", status: "hey"})
 
       response =
         conn
-        |> patch("/api/pleroma/admin/oauth_app/" <> to_string(app.id), %{
-          name: name,
-          trusted: true,
-          redirect_uris: url,
-          scopes: scopes,
-          website: website
-        })
+        |> assign(:user, admin)
+        |> get("/api/pleroma/admin/stats", instance: instance2)
         |> json_response(200)
 
-      assert %{
-               "client_id" => _,
-               "client_secret" => _,
-               "id" => ^id,
-               "name" => ^name,
-               "redirect_uri" => ^url,
-               "trusted" => true,
-               "website" => ^website
-             } = response
-    end
-
-    test "without id", %{conn: conn} do
-      response =
-        conn
-        |> patch("/api/pleroma/admin/oauth_app/0")
-        |> json_response(:bad_request)
-
-      assert response == ""
+      assert %{"direct" => 0, "private" => 1, "public" => 0, "unlisted" => 1} =
+               response["status_visibility"]
     end
   end
 end