admin_api_controller_test.exs 116 KB
Newer Older
kaniini's avatar
kaniini committed
1
# Pleroma: A lightweight social networking server
2
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
kaniini's avatar
kaniini committed
3 4
# SPDX-License-Identifier: AGPL-3.0-only

5 6
defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
  use Pleroma.Web.ConnCase
7
  use Oban.Testing, repo: Pleroma.Repo
8

Alexander Strizhakov's avatar
Alexander Strizhakov committed
9 10 11
  import Pleroma.Factory
  import ExUnit.CaptureLog

Sergey Suprunenko's avatar
Sergey Suprunenko committed
12
  alias Pleroma.Activity
Alexander Strizhakov's avatar
Alexander Strizhakov committed
13
  alias Pleroma.Config
14
  alias Pleroma.ConfigDB
Maxim Filippov's avatar
Maxim Filippov committed
15
  alias Pleroma.HTML
Maxim Filippov's avatar
Maxim Filippov committed
16 17
  alias Pleroma.ModerationLog
  alias Pleroma.Repo
18
  alias Pleroma.ReportNote
19
  alias Pleroma.Tests.ObanHelpers
Haelwenn's avatar
Haelwenn committed
20
  alias Pleroma.User
21
  alias Pleroma.UserInviteToken
22
  alias Pleroma.Web.ActivityPub.Relay
Sergey Suprunenko's avatar
Sergey Suprunenko committed
23
  alias Pleroma.Web.CommonAPI
24
  alias Pleroma.Web.MastodonAPI.StatusView
25
  alias Pleroma.Web.MediaProxy
26

27 28 29 30 31 32
  setup_all do
    Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)

    :ok
  end

33 34 35 36 37 38 39 40 41 42
  setup do
    admin = insert(:user, is_admin: true)
    token = insert(:oauth_admin_token, user: admin)

    conn =
      build_conn()
      |> assign(:user, admin)
      |> assign(:token, token)

    {:ok, %{admin: admin, token: token, conn: conn}}
43 44 45 46
  end

  describe "with [:auth, :enforce_oauth_admin_scope_usage]," do
    clear_config([:auth, :enforce_oauth_admin_scope_usage]) do
Alexander Strizhakov's avatar
Alexander Strizhakov committed
47
      Config.put([:auth, :enforce_oauth_admin_scope_usage], true)
48 49
    end

50 51
    test "GET /api/pleroma/admin/users/:nickname requires admin:read:accounts or broader scope",
         %{admin: admin} do
52
      user = insert(:user)
53
      url = "/api/pleroma/admin/users/#{user.nickname}"
54 55 56 57 58 59 60 61 62 63 64 65 66 67

      good_token1 = insert(:oauth_token, user: admin, scopes: ["admin"])
      good_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read"])
      good_token3 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts"])

      bad_token1 = insert(:oauth_token, user: admin, scopes: ["read:accounts"])
      bad_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts:partial"])
      bad_token3 = nil

      for good_token <- [good_token1, good_token2, good_token3] do
        conn =
          build_conn()
          |> assign(:user, admin)
          |> assign(:token, good_token)
68
          |> get(url)
69 70 71 72

        assert json_response(conn, 200)
      end

73 74 75 76 77 78 79 80 81 82
      for good_token <- [good_token1, good_token2, good_token3] do
        conn =
          build_conn()
          |> assign(:user, nil)
          |> assign(:token, good_token)
          |> get(url)

        assert json_response(conn, :forbidden)
      end

83 84 85 86 87
      for bad_token <- [bad_token1, bad_token2, bad_token3] do
        conn =
          build_conn()
          |> assign(:user, admin)
          |> assign(:token, bad_token)
88
          |> get(url)
89 90 91 92 93 94

        assert json_response(conn, :forbidden)
      end
    end
  end

95 96
  describe "unless [:auth, :enforce_oauth_admin_scope_usage]," do
    clear_config([:auth, :enforce_oauth_admin_scope_usage]) do
Alexander Strizhakov's avatar
Alexander Strizhakov committed
97
      Config.put([:auth, :enforce_oauth_admin_scope_usage], false)
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
    end

    test "GET /api/pleroma/admin/users/:nickname requires " <>
           "read:accounts or admin:read:accounts or broader scope",
         %{admin: admin} do
      user = insert(:user)
      url = "/api/pleroma/admin/users/#{user.nickname}"

      good_token1 = insert(:oauth_token, user: admin, scopes: ["admin"])
      good_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read"])
      good_token3 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts"])
      good_token4 = insert(:oauth_token, user: admin, scopes: ["read:accounts"])
      good_token5 = insert(:oauth_token, user: admin, scopes: ["read"])

      good_tokens = [good_token1, good_token2, good_token3, good_token4, good_token5]

      bad_token1 = insert(:oauth_token, user: admin, scopes: ["read:accounts:partial"])
      bad_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts:partial"])
      bad_token3 = nil

      for good_token <- good_tokens do
        conn =
          build_conn()
          |> assign(:user, admin)
          |> assign(:token, good_token)
          |> get(url)

        assert json_response(conn, 200)
      end

      for good_token <- good_tokens do
        conn =
          build_conn()
          |> assign(:user, nil)
          |> assign(:token, good_token)
          |> get(url)

        assert json_response(conn, :forbidden)
      end

      for bad_token <- [bad_token1, bad_token2, bad_token3] do
        conn =
          build_conn()
          |> assign(:user, admin)
          |> assign(:token, bad_token)
          |> get(url)

        assert json_response(conn, :forbidden)
      end
    end
  end

150
  describe "DELETE /api/pleroma/admin/users" do
151
    test "single user", %{admin: admin, conn: conn} do
152 153 154
      user = insert(:user)

      conn =
155
        conn
156
        |> put_req_header("accept", "application/json")
Sachin Joshi's avatar
Sachin Joshi committed
157
        |> delete("/api/pleroma/admin/users?nickname=#{user.nickname}")
158

Maxim Filippov's avatar
Maxim Filippov committed
159 160 161
      log_entry = Repo.one(ModerationLog)

      assert ModerationLog.get_log_entry_message(log_entry) ==
162
               "@#{admin.nickname} deleted users: @#{user.nickname}"
Maxim Filippov's avatar
Maxim Filippov committed
163

164 165 166
      assert json_response(conn, 200) == user.nickname
    end

167
    test "multiple users", %{admin: admin, conn: conn} do
168 169 170 171
      user_one = insert(:user)
      user_two = insert(:user)

      conn =
172
        conn
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
        |> put_req_header("accept", "application/json")
        |> delete("/api/pleroma/admin/users", %{
          nicknames: [user_one.nickname, user_two.nickname]
        })

      log_entry = Repo.one(ModerationLog)

      assert ModerationLog.get_log_entry_message(log_entry) ==
               "@#{admin.nickname} deleted users: @#{user_one.nickname}, @#{user_two.nickname}"

      response = json_response(conn, 200)
      assert response -- [user_one.nickname, user_two.nickname] == []
    end
  end

  describe "/api/pleroma/admin/users" do
189
    test "Create", %{conn: conn} do
190
      conn =
191
        conn
192
        |> put_req_header("accept", "application/json")
Sachin Joshi's avatar
Sachin Joshi committed
193
        |> post("/api/pleroma/admin/users", %{
194 195 196 197 198
          "users" => [
            %{
              "nickname" => "lain",
              "email" => "lain@example.org",
              "password" => "test"
199 200 201 202 203
            },
            %{
              "nickname" => "lain2",
              "email" => "lain2@example.org",
              "password" => "test"
204 205
            }
          ]
206 207
        })

208 209
      response = json_response(conn, 200) |> Enum.map(&Map.get(&1, "type"))
      assert response == ["success", "success"]
Maxim Filippov's avatar
Maxim Filippov committed
210 211 212

      log_entry = Repo.one(ModerationLog)

Maxim Filippov's avatar
Maxim Filippov committed
213
      assert ["lain", "lain2"] -- Enum.map(log_entry.data["subjects"], & &1["nickname"]) == []
214 215
    end

216
    test "Cannot create user with existing email", %{conn: conn} do
217 218 219
      user = insert(:user)

      conn =
220
        conn
221 222 223 224 225 226 227 228 229 230 231
        |> put_req_header("accept", "application/json")
        |> post("/api/pleroma/admin/users", %{
          "users" => [
            %{
              "nickname" => "lain",
              "email" => user.email,
              "password" => "test"
            }
          ]
        })

232
      assert json_response(conn, 409) == [
233 234 235 236 237 238 239 240 241 242 243 244
               %{
                 "code" => 409,
                 "data" => %{
                   "email" => user.email,
                   "nickname" => "lain"
                 },
                 "error" => "email has already been taken",
                 "type" => "error"
               }
             ]
    end

245
    test "Cannot create user with existing nickname", %{conn: conn} do
246 247 248
      user = insert(:user)

      conn =
249
        conn
250 251 252 253 254 255 256 257 258 259 260
        |> put_req_header("accept", "application/json")
        |> post("/api/pleroma/admin/users", %{
          "users" => [
            %{
              "nickname" => user.nickname,
              "email" => "someuser@plerama.social",
              "password" => "test"
            }
          ]
        })

261
      assert json_response(conn, 409) == [
262 263 264 265 266 267 268 269 270 271
               %{
                 "code" => 409,
                 "data" => %{
                   "email" => "someuser@plerama.social",
                   "nickname" => user.nickname
                 },
                 "error" => "nickname has already been taken",
                 "type" => "error"
               }
             ]
272
    end
273

274
    test "Multiple user creation works in transaction", %{conn: conn} do
275 276 277
      user = insert(:user)

      conn =
278
        conn
279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316
        |> put_req_header("accept", "application/json")
        |> post("/api/pleroma/admin/users", %{
          "users" => [
            %{
              "nickname" => "newuser",
              "email" => "newuser@pleroma.social",
              "password" => "test"
            },
            %{
              "nickname" => "lain",
              "email" => user.email,
              "password" => "test"
            }
          ]
        })

      assert json_response(conn, 409) == [
               %{
                 "code" => 409,
                 "data" => %{
                   "email" => user.email,
                   "nickname" => "lain"
                 },
                 "error" => "email has already been taken",
                 "type" => "error"
               },
               %{
                 "code" => 409,
                 "data" => %{
                   "email" => "newuser@pleroma.social",
                   "nickname" => "newuser"
                 },
                 "error" => "",
                 "type" => "error"
               }
             ]

      assert User.get_by_nickname("newuser") === nil
317 318 319
    end
  end

320 321 322 323
  describe "/api/pleroma/admin/users/:nickname" do
    test "Show", %{conn: conn} do
      user = insert(:user)

324
      conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}")
325 326 327 328 329 330 331

      expected = %{
        "deactivated" => false,
        "id" => to_string(user.id),
        "local" => true,
        "nickname" => user.nickname,
        "roles" => %{"admin" => false, "moderator" => false},
332 333
        "tags" => [],
        "avatar" => User.avatar_url(user) |> MediaProxy.url(),
Maxim Filippov's avatar
Maxim Filippov committed
334 335
        "display_name" => HTML.strip_tags(user.name || user.nickname),
        "confirmation_pending" => false
336 337 338 339 340 341 342 343
      }

      assert expected == json_response(conn, 200)
    end

    test "when the user doesn't exist", %{conn: conn} do
      user = build(:user)

344
      conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}")
345 346 347 348 349

      assert "Not found" == json_response(conn, 404)
    end
  end

Sachin Joshi's avatar
Sachin Joshi committed
350
  describe "/api/pleroma/admin/users/follow" do
351
    test "allows to force-follow another user", %{admin: admin, conn: conn} do
352 353 354
      user = insert(:user)
      follower = insert(:user)

355
      conn
356
      |> put_req_header("accept", "application/json")
Sachin Joshi's avatar
Sachin Joshi committed
357
      |> post("/api/pleroma/admin/users/follow", %{
358 359 360
        "follower" => follower.nickname,
        "followed" => user.nickname
      })
361

minibikini's avatar
minibikini committed
362 363
      user = User.get_cached_by_id(user.id)
      follower = User.get_cached_by_id(follower.id)
364 365

      assert User.following?(follower, user)
Maxim Filippov's avatar
Maxim Filippov committed
366 367 368 369 370

      log_entry = Repo.one(ModerationLog)

      assert ModerationLog.get_log_entry_message(log_entry) ==
               "@#{admin.nickname} made @#{follower.nickname} follow @#{user.nickname}"
371 372 373
    end
  end

Sachin Joshi's avatar
Sachin Joshi committed
374
  describe "/api/pleroma/admin/users/unfollow" do
375
    test "allows to force-unfollow another user", %{admin: admin, conn: conn} do
376 377 378 379 380
      user = insert(:user)
      follower = insert(:user)

      User.follow(follower, user)

381
      conn
382
      |> put_req_header("accept", "application/json")
Sachin Joshi's avatar
Sachin Joshi committed
383
      |> post("/api/pleroma/admin/users/unfollow", %{
384 385 386
        "follower" => follower.nickname,
        "followed" => user.nickname
      })
387

minibikini's avatar
minibikini committed
388 389
      user = User.get_cached_by_id(user.id)
      follower = User.get_cached_by_id(follower.id)
390 391

      refute User.following?(follower, user)
Maxim Filippov's avatar
Maxim Filippov committed
392 393 394 395 396

      log_entry = Repo.one(ModerationLog)

      assert ModerationLog.get_log_entry_message(log_entry) ==
               "@#{admin.nickname} made @#{follower.nickname} unfollow @#{user.nickname}"
397 398 399
    end
  end

400
  describe "PUT /api/pleroma/admin/users/tag" do
401
    setup %{conn: conn} do
402 403 404 405 406
      user1 = insert(:user, %{tags: ["x"]})
      user2 = insert(:user, %{tags: ["y"]})
      user3 = insert(:user, %{tags: ["unchanged"]})

      conn =
407
        conn
408
        |> put_req_header("accept", "application/json")
Ivan Tashkinov's avatar
Ivan Tashkinov committed
409
        |> put(
410 411
          "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <>
            "#{user2.nickname}&tags[]=foo&tags[]=bar"
Ivan Tashkinov's avatar
Ivan Tashkinov committed
412
        )
413

414
      %{conn: conn, user1: user1, user2: user2, user3: user3}
415 416
    end

Ivan Tashkinov's avatar
Ivan Tashkinov committed
417 418
    test "it appends specified tags to users with specified nicknames", %{
      conn: conn,
Maxim Filippov's avatar
Maxim Filippov committed
419
      admin: admin,
Ivan Tashkinov's avatar
Ivan Tashkinov committed
420 421 422
      user1: user1,
      user2: user2
    } do
423
      assert json_response(conn, :no_content)
minibikini's avatar
minibikini committed
424 425
      assert User.get_cached_by_id(user1.id).tags == ["x", "foo", "bar"]
      assert User.get_cached_by_id(user2.id).tags == ["y", "foo", "bar"]
Maxim Filippov's avatar
Maxim Filippov committed
426 427 428 429 430 431 432 433 434 435 436 437

      log_entry = Repo.one(ModerationLog)

      users =
        [user1.nickname, user2.nickname]
        |> Enum.map(&"@#{&1}")
        |> Enum.join(", ")

      tags = ["foo", "bar"] |> Enum.join(", ")

      assert ModerationLog.get_log_entry_message(log_entry) ==
               "@#{admin.nickname} added tags: #{tags} to users: #{users}"
438 439 440 441
    end

    test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do
      assert json_response(conn, :no_content)
minibikini's avatar
minibikini committed
442
      assert User.get_cached_by_id(user3.id).tags == ["unchanged"]
443 444 445
    end
  end

446
  describe "DELETE /api/pleroma/admin/users/tag" do
447
    setup %{conn: conn} do
448 449 450 451 452
      user1 = insert(:user, %{tags: ["x"]})
      user2 = insert(:user, %{tags: ["y", "z"]})
      user3 = insert(:user, %{tags: ["unchanged"]})

      conn =
453
        conn
454
        |> put_req_header("accept", "application/json")
455
        |> delete(
456 457
          "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <>
            "#{user2.nickname}&tags[]=x&tags[]=z"
Ivan Tashkinov's avatar
Ivan Tashkinov committed
458
        )
459

460
      %{conn: conn, user1: user1, user2: user2, user3: user3}
461 462
    end

Ivan Tashkinov's avatar
Ivan Tashkinov committed
463 464
    test "it removes specified tags from users with specified nicknames", %{
      conn: conn,
Maxim Filippov's avatar
Maxim Filippov committed
465
      admin: admin,
Ivan Tashkinov's avatar
Ivan Tashkinov committed
466 467 468
      user1: user1,
      user2: user2
    } do
469
      assert json_response(conn, :no_content)
minibikini's avatar
minibikini committed
470 471
      assert User.get_cached_by_id(user1.id).tags == []
      assert User.get_cached_by_id(user2.id).tags == ["y"]
Maxim Filippov's avatar
Maxim Filippov committed
472 473 474 475 476 477 478 479 480 481 482 483

      log_entry = Repo.one(ModerationLog)

      users =
        [user1.nickname, user2.nickname]
        |> Enum.map(&"@#{&1}")
        |> Enum.join(", ")

      tags = ["x", "z"] |> Enum.join(", ")

      assert ModerationLog.get_log_entry_message(log_entry) ==
               "@#{admin.nickname} removed tags: #{tags} from users: #{users}"
484 485 486 487
    end

    test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do
      assert json_response(conn, :no_content)
minibikini's avatar
minibikini committed
488
      assert User.get_cached_by_id(user3.id).tags == ["unchanged"]
489 490 491
    end
  end

Sachin Joshi's avatar
Sachin Joshi committed
492
  describe "/api/pleroma/admin/users/:nickname/permission_group" do
493
    test "GET is giving user_info", %{admin: admin, conn: conn} do
494
      conn =
495
        conn
496
        |> put_req_header("accept", "application/json")
Sachin Joshi's avatar
Sachin Joshi committed
497
        |> get("/api/pleroma/admin/users/#{admin.nickname}/permission_group/")
498

lain's avatar
lain committed
499 500 501 502
      assert json_response(conn, 200) == %{
               "is_admin" => true,
               "is_moderator" => false
             }
503 504
    end

505
    test "/:right POST, can add to a permission group", %{admin: admin, conn: conn} do
506 507 508
      user = insert(:user)

      conn =
509
        conn
510
        |> put_req_header("accept", "application/json")
Sachin Joshi's avatar
Sachin Joshi committed
511
        |> post("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin")
512

lain's avatar
lain committed
513 514 515
      assert json_response(conn, 200) == %{
               "is_admin" => true
             }
Maxim Filippov's avatar
Maxim Filippov committed
516 517 518 519 520

      log_entry = Repo.one(ModerationLog)

      assert ModerationLog.get_log_entry_message(log_entry) ==
               "@#{admin.nickname} made @#{user.nickname} admin"
521 522
    end

523
    test "/:right POST, can add to a permission group (multiple)", %{admin: admin, conn: conn} do
524 525
      user_one = insert(:user)
      user_two = insert(:user)
526 527

      conn =
528
        conn
529
        |> put_req_header("accept", "application/json")
530 531 532
        |> post("/api/pleroma/admin/users/permission_group/admin", %{
          nicknames: [user_one.nickname, user_two.nickname]
        })
533

534
      assert json_response(conn, 200) == %{"is_admin" => true}
Maxim Filippov's avatar
Maxim Filippov committed
535 536 537 538

      log_entry = Repo.one(ModerationLog)

      assert ModerationLog.get_log_entry_message(log_entry) ==
539
               "@#{admin.nickname} made @#{user_one.nickname}, @#{user_two.nickname} admin"
540 541
    end

542
    test "/:right DELETE, can remove from a permission group", %{admin: admin, conn: conn} do
543
      user = insert(:user, is_admin: true)
544 545

      conn =
546
        conn
547
        |> put_req_header("accept", "application/json")
Maxim Filippov's avatar
Maxim Filippov committed
548
        |> delete("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin")
549

550
      assert json_response(conn, 200) == %{"is_admin" => false}
Maxim Filippov's avatar
Maxim Filippov committed
551 552 553 554

      log_entry = Repo.one(ModerationLog)

      assert ModerationLog.get_log_entry_message(log_entry) ==
Maxim Filippov's avatar
Maxim Filippov committed
555
               "@#{admin.nickname} revoked admin role from @#{user.nickname}"
556 557
    end

558 559 560 561
    test "/:right DELETE, can remove from a permission group (multiple)", %{
      admin: admin,
      conn: conn
    } do
562 563
      user_one = insert(:user, is_admin: true)
      user_two = insert(:user, is_admin: true)
564 565

      conn =
566
        conn
567
        |> put_req_header("accept", "application/json")
568 569 570
        |> delete("/api/pleroma/admin/users/permission_group/admin", %{
          nicknames: [user_one.nickname, user_two.nickname]
        })
571

572
      assert json_response(conn, 200) == %{"is_admin" => false}
Maxim Filippov's avatar
Maxim Filippov committed
573 574 575 576

      log_entry = Repo.one(ModerationLog)

      assert ModerationLog.get_log_entry_message(log_entry) ==
577 578 579
               "@#{admin.nickname} revoked admin role from @#{user_one.nickname}, @#{
                 user_two.nickname
               }"
580 581 582
    end
  end

Ivan Tashkinov's avatar
Ivan Tashkinov committed
583
  describe "POST /api/pleroma/admin/email_invite, with valid config" do
584
    clear_config([:instance, :registrations_open]) do
Alexander Strizhakov's avatar
Alexander Strizhakov committed
585
      Config.put([:instance, :registrations_open], false)
586
    end
587

588
    clear_config([:instance, :invites_enabled]) do
Alexander Strizhakov's avatar
Alexander Strizhakov committed
589
      Config.put([:instance, :invites_enabled], true)
590 591
    end

592
    test "sends invitation and returns 204", %{admin: admin, conn: conn} do
593 594 595 596
      recipient_email = "foo@bar.com"
      recipient_name = "J. D."

      conn =
597 598
        post(
          conn,
Sachin Joshi's avatar
Sachin Joshi committed
599 600
          "/api/pleroma/admin/users/email_invite?email=#{recipient_email}&name=#{recipient_name}"
        )
601 602 603

      assert json_response(conn, :no_content)

604
      token_record = List.last(Repo.all(Pleroma.UserInviteToken))
Ivan Tashkinov's avatar
Ivan Tashkinov committed
605 606 607
      assert token_record
      refute token_record.used

Alexander Strizhakov's avatar
Alexander Strizhakov committed
608 609
      notify_email = Config.get([:instance, :notify_email])
      instance_name = Config.get([:instance, :name])
610 611

      email =
Alexander Strizhakov's avatar
Alexander Strizhakov committed
612
        Pleroma.Emails.UserEmail.user_invitation_email(
613
          admin,
Ivan Tashkinov's avatar
Ivan Tashkinov committed
614 615 616 617
          token_record,
          recipient_email,
          recipient_name
        )
618 619 620 621 622

      Swoosh.TestAssertions.assert_email_sent(
        from: {instance_name, notify_email},
        to: {recipient_name, recipient_email},
        html_body: email.html_body
Ivan Tashkinov's avatar
Ivan Tashkinov committed
623 624 625
      )
    end

626
    test "it returns 403 if requested by a non-admin" do
Ivan Tashkinov's avatar
Ivan Tashkinov committed
627
      non_admin_user = insert(:user)
628
      token = insert(:oauth_token, user: non_admin_user)
Ivan Tashkinov's avatar
Ivan Tashkinov committed
629 630

      conn =
631
        build_conn()
Ivan Tashkinov's avatar
Ivan Tashkinov committed
632
        |> assign(:user, non_admin_user)
633
        |> assign(:token, token)
Sachin Joshi's avatar
Sachin Joshi committed
634
        |> post("/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD")
Ivan Tashkinov's avatar
Ivan Tashkinov committed
635 636 637 638 639

      assert json_response(conn, :forbidden)
    end
  end

Sachin Joshi's avatar
Sachin Joshi committed
640
  describe "POST /api/pleroma/admin/users/email_invite, with invalid config" do
641 642 643
    clear_config([:instance, :registrations_open])
    clear_config([:instance, :invites_enabled])

644
    test "it returns 500 if `invites_enabled` is not enabled", %{conn: conn} do
Alexander Strizhakov's avatar
Alexander Strizhakov committed
645 646
      Config.put([:instance, :registrations_open], false)
      Config.put([:instance, :invites_enabled], false)
Ivan Tashkinov's avatar
Ivan Tashkinov committed
647

648
      conn = post(conn, "/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD")
Ivan Tashkinov's avatar
Ivan Tashkinov committed
649 650 651 652

      assert json_response(conn, :internal_server_error)
    end

653
    test "it returns 500 if `registrations_open` is enabled", %{conn: conn} do
Alexander Strizhakov's avatar
Alexander Strizhakov committed
654 655
      Config.put([:instance, :registrations_open], true)
      Config.put([:instance, :invites_enabled], true)
Ivan Tashkinov's avatar
Ivan Tashkinov committed
656

657
      conn = post(conn, "/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD")
Ivan Tashkinov's avatar
Ivan Tashkinov committed
658 659

      assert json_response(conn, :internal_server_error)
660 661 662
    end
  end

663
  test "/api/pleroma/admin/users/:nickname/password_reset", %{conn: conn} do
lain's avatar
lain committed
664
    user = insert(:user)
665 666

    conn =
667
      conn
668
      |> put_req_header("accept", "application/json")
Sachin Joshi's avatar
Sachin Joshi committed
669
      |> get("/api/pleroma/admin/users/#{user.nickname}/password_reset")
670

671 672 673
    resp = json_response(conn, 200)

    assert Regex.match?(~r/(http:\/\/|https:\/\/)/, resp["link"])
674
  end
Maxim Filippov's avatar
Maxim Filippov committed
675

Maxim Filippov's avatar
Maxim Filippov committed
676
  describe "GET /api/pleroma/admin/users" do
Alexander Strizhakov's avatar
Alexander Strizhakov committed
677 678 679
    test "renders users array for the first page", %{conn: conn, admin: admin} do
      user = insert(:user, local: false, tags: ["foo", "bar"])
      conn = get(conn, "/api/pleroma/admin/users?page=1")
Maxim Filippov's avatar
Maxim Filippov committed
680

Maksim's avatar
Maksim committed
681 682 683
      users =
        [
          %{
684
            "deactivated" => admin.deactivated,
Maksim's avatar
Maksim committed
685 686 687 688
            "id" => admin.id,
            "nickname" => admin.nickname,
            "roles" => %{"admin" => true, "moderator" => false},
            "local" => true,
689 690
            "tags" => [],
            "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
Maxim Filippov's avatar
Maxim Filippov committed
691 692
            "display_name" => HTML.strip_tags(admin.name || admin.nickname),
            "confirmation_pending" => false
Maksim's avatar
Maksim committed
693 694
          },
          %{
695
            "deactivated" => user.deactivated,
Maksim's avatar
Maksim committed
696 697 698 699
            "id" => user.id,
            "nickname" => user.nickname,
            "roles" => %{"admin" => false, "moderator" => false},
            "local" => false,
700 701
            "tags" => ["foo", "bar"],
            "avatar" => User.avatar_url(user) |> MediaProxy.url(),
Maxim Filippov's avatar
Maxim Filippov committed
702 703
            "display_name" => HTML.strip_tags(user.name || user.nickname),
            "confirmation_pending" => false
Maksim's avatar
Maksim committed
704 705 706 707
          }
        ]
        |> Enum.sort_by(& &1["nickname"])

Maxim Filippov's avatar
Maxim Filippov committed
708
      assert json_response(conn, 200) == %{
Maxim Filippov's avatar
Maxim Filippov committed
709
               "count" => 2,
Maxim Filippov's avatar
Maxim Filippov committed
710
               "page_size" => 50,
Maksim's avatar
Maksim committed
711
               "users" => users
Maxim Filippov's avatar
Maxim Filippov committed
712 713 714
             }
    end

Alexander Strizhakov's avatar
Alexander Strizhakov committed
715
    test "renders empty array for the second page", %{conn: conn} do
Maxim Filippov's avatar
Maxim Filippov committed
716
      insert(:user)
Maxim Filippov's avatar
Maxim Filippov committed
717

Alexander Strizhakov's avatar
Alexander Strizhakov committed
718
      conn = get(conn, "/api/pleroma/admin/users?page=2")
Maxim Filippov's avatar
Maxim Filippov committed
719 720

      assert json_response(conn, 200) == %{
Maxim Filippov's avatar
Maxim Filippov committed
721
               "count" => 2,
Maxim Filippov's avatar
Maxim Filippov committed
722 723 724 725
               "page_size" => 50,
               "users" => []
             }
    end
Maxim Filippov's avatar
Maxim Filippov committed
726

Alexander Strizhakov's avatar
Alexander Strizhakov committed
727
    test "regular search", %{conn: conn} do
728
      user = insert(:user, nickname: "bob")
Maxim Filippov's avatar
Maxim Filippov committed
729

Alexander Strizhakov's avatar
Alexander Strizhakov committed
730
      conn = get(conn, "/api/pleroma/admin/users?query=bo")
731 732

      assert json_response(conn, 200) == %{
733 734 735 736
               "count" => 1,
               "page_size" => 50,
               "users" => [
                 %{
737
                   "deactivated" => user.deactivated,
738
                   "id" => user.id,
739
                   "nickname" => user.nickname,
740
                   "roles" => %{"admin" => false, "moderator" => false},
Maxim Filippov's avatar
Maxim Filippov committed
741
                   "local" => true,
742 743
                   "tags" => [],
                   "avatar" => User.avatar_url(user) |> MediaProxy.url(),
Maxim Filippov's avatar
Maxim Filippov committed
744 745
                   "display_name" => HTML.strip_tags(user.name || user.nickname),
                   "confirmation_pending" => false
746 747 748
                 }
               ]
             }
749 750
    end

Alexander Strizhakov's avatar
Alexander Strizhakov committed
751 752 753 754 755 756 757 758 759 760 761
    test "search by domain", %{conn: conn} do
      user = insert(:user, nickname: "nickname@domain.com")
      insert(:user)

      conn = get(conn, "/api/pleroma/admin/users?query=domain.com")

      assert json_response(conn, 200) == %{
               "count" => 1,
               "page_size" => 50,
               "users" => [
                 %{
762
                   "deactivated" => user.deactivated,
Alexander Strizhakov's avatar
Alexander Strizhakov committed
763 764 765 766
                   "id" => user.id,
                   "nickname" => user.nickname,
                   "roles" => %{"admin" => false, "moderator" => false},
                   "local" => true,
767 768
                   "tags" => [],
                   "avatar" => User.avatar_url(user) |> MediaProxy.url(),
Maxim Filippov's avatar
Maxim Filippov committed
769 770
                   "display_name" => HTML.strip_tags(user.name || user.nickname),
                   "confirmation_pending" => false
Alexander Strizhakov's avatar
Alexander Strizhakov committed
771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786
                 }
               ]
             }
    end

    test "search by full nickname", %{conn: conn} do
      user = insert(:user, nickname: "nickname@domain.com")
      insert(:user)

      conn = get(conn, "/api/pleroma/admin/users?query=nickname@domain.com")

      assert json_response(conn, 200) == %{
               "count" => 1,
               "page_size" => 50,
               "users" => [
                 %{
787
                   "deactivated" => user.deactivated,
Alexander Strizhakov's avatar
Alexander Strizhakov committed
788 789 790 791
                   "id" => user.id,
                   "nickname" => user.nickname,
                   "roles" => %{"admin" => false, "moderator" => false},
                   "local" => true,
792 793
                   "tags" => [],
                   "avatar" => User.avatar_url(user) |> MediaProxy.url(),
Maxim Filippov's avatar
Maxim Filippov committed
794 795
                   "display_name" => HTML.strip_tags(user.name || user.nickname),
                   "confirmation_pending" => false
Alexander Strizhakov's avatar
Alexander Strizhakov committed
796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811
                 }
               ]
             }
    end

    test "search by display name", %{conn: conn} do
      user = insert(:user, name: "Display name")
      insert(:user)

      conn = get(conn, "/api/pleroma/admin/users?name=display")

      assert json_response(conn, 200) == %{
               "count" => 1,
               "page_size" => 50,
               "users" => [
                 %{
812
                   "deactivated" => user.deactivated,
Alexander Strizhakov's avatar
Alexander Strizhakov committed
813 814 815 816
                   "id" => user.id,
                   "nickname" => user.nickname,
                   "roles" => %{"admin" => false, "moderator" => false},
                   "local" => true,
817 818
                   "tags" => [],
                   "avatar" => User.avatar_url(user) |> MediaProxy.url(),
Maxim Filippov's avatar
Maxim Filippov committed
819 820
                   "display_name" => HTML.strip_tags(user.name || user.nickname),
                   "confirmation_pending" => false
Alexander Strizhakov's avatar
Alexander Strizhakov committed
821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836
                 }
               ]
             }
    end

    test "search by email", %{conn: conn} do
      user = insert(:user, email: "email@example.com")
      insert(:user)

      conn = get(conn, "/api/pleroma/admin/users?email=email@example.com")

      assert json_response(conn, 200) == %{
               "count" => 1,
               "page_size" => 50,
               "users" => [
                 %{
837
                   "deactivated" => user.deactivated,
Alexander Strizhakov's avatar
Alexander Strizhakov committed
838 839 840 841
                   "id" => user.id,
                   "nickname" => user.nickname,
                   "roles" => %{"admin" => false, "moderator" => false},
                   "local" => true,
842 843
                   "tags" => [],
                   "avatar" => User.avatar_url(user) |> MediaProxy.url(),
Maxim Filippov's avatar
Maxim Filippov committed
844 845
                   "display_name" => HTML.strip_tags(user.name || user.nickname),
                   "confirmation_pending" => false
Alexander Strizhakov's avatar
Alexander Strizhakov committed
846 847 848 849 850 851
                 }
               ]
             }
    end

    test "regular search with page size", %{conn: conn} do
852 853
      user = insert(:user, nickname: "aalice")
      user2 = insert(:user, nickname: "alice")
Maxim Filippov's avatar
Maxim Filippov committed
854

Alexander Strizhakov's avatar
Alexander Strizhakov committed
855
      conn1 = get(conn, "/api/pleroma/admin/users?query=a&page_size=1&page=1")
Maxim Filippov's avatar
Maxim Filippov committed
856

Alexander Strizhakov's avatar
Alexander Strizhakov committed
857
      assert json_response(conn1, 200) == %{
Maxim Filippov's avatar
Maxim Filippov committed
858 859 860 861
               "count" => 2,
               "page_size" => 1,
               "users" => [
                 %{
862
                   "deactivated" => user.deactivated,
Maxim Filippov's avatar
Maxim Filippov committed
863
                   "id" => user.id,
864
                   "nickname" => user.nickname,
865
                   "roles" => %{"admin" => false, "moderator" => false},
Maxim Filippov's avatar
Maxim Filippov committed
866
                   "local" => true,
867 868
                   "tags" => [],
                   "avatar" => User.avatar_url(user) |> MediaProxy.url(),
Maxim Filippov's avatar
Maxim Filippov committed
869 870
                   "display_name" => HTML.strip_tags(user.name || user.nickname),
                   "confirmation_pending" => false
Maxim Filippov's avatar
Maxim Filippov committed
871 872 873 874
                 }
               ]
             }

Alexander Strizhakov's avatar
Alexander Strizhakov committed
875
      conn2 = get(conn, "/api/pleroma/admin/users?query=a&page_size=1&page=2")
Maxim Filippov's avatar
Maxim Filippov committed
876

Alexander Strizhakov's avatar
Alexander Strizhakov committed
877
      assert json_response(conn2, 200) == %{
Maxim Filippov's avatar
Maxim Filippov committed
878 879 880 881
               "count" => 2,
               "page_size" => 1,
               "users" => [
                 %{
882
                   "deactivated" => user2.deactivated,
Maxim Filippov's avatar
Maxim Filippov committed
883
                   "id" => user2.id,
884
                   "nickname" => user2.nickname,
885
                   "roles" => %{"admin" => false, "moderator" => false},
Maxim Filippov's avatar
Maxim Filippov committed
886
                   "local" => true,
887 888
                   "tags" => [],
                   "avatar" => User.avatar_url(user2) |> MediaProxy.url(),
Maxim Filippov's avatar
Maxim Filippov committed
889 890
                   "display_name" => HTML.strip_tags(user2.name || user2.nickname),
                   "confirmation_pending" => false
Maxim Filippov's avatar
Maxim Filippov committed
891 892 893 894 895 896
                 }
               ]
             }
    end

    test "only local users" do
897
      admin = insert(:user, is_admin: true, nickname: "john")
898
      token = insert(:oauth_admin_token, user: admin)
Maxim Filippov's avatar
Maxim Filippov committed
899
      user = insert(:user, nickname: "bob")
900 901 902 903 904 905

      insert(:user, nickname: "bobb", local: false)

      conn =
        build_conn()
        |> assign(:user, admin)
906
        |> assign(:token, token)
907
        |> get("/api/pleroma/admin/users?query=bo&filters=local")
908 909

      assert json_response(conn, 200) == %{
910 911 912 913
               "count" => 1,
               "page_size" => 50,
               "users" => [
                 %{
914
                   "deactivated" => user.deactivated,
915
                   "id" => user.id,
916
                   "nickname" => user.nickname,
917
                   "roles" => %{"admin" => false, "moderator" => false},
Maxim Filippov's avatar
Maxim Filippov committed
918
                   "local" => true,
919 920
                   "tags" => [],
                   "avatar" => User.avatar_url(user) |> MediaProxy.url(),
Maxim Filippov's avatar
Maxim Filippov committed
921 922
                   "display_name" => HTML.strip_tags(user.name || user.nickname),
                   "confirmation_pending" => false
923 924 925
                 }
               ]
             }
926
    end
927

928
    test "only local users with no query", %{conn: conn, admin: old_admin} do
929
      admin = insert(:user, is_admin: true, nickname: "john")
930 931 932 933
      user = insert(:user, nickname: "bob")

      insert(:user, nickname: "bobb", local: false)

934
      conn = get(conn, "/api/pleroma/admin/users?filters=local")
935

Maksim's avatar
Maksim committed
936 937 938
      users =
        [
          %{
939
            "deactivated" => user.deactivated,
Maksim's avatar
Maksim committed
940 941 942 943
            "id" => user.id,
            "nickname" => user.nickname,
            "roles" => %{"admin" => false, "moderator" => false},
            "local" => true,
944 945
            "tags" => [],
            "avatar" => User.avatar_url(user) |> MediaProxy.url(),
Maxim Filippov's avatar
Maxim Filippov committed
946 947
            "display_name" => HTML.strip_tags(user.name || user.nickname),
            "confirmation_pending" => false
Maksim's avatar
Maksim committed
948 949
          },
          %{
950
            "deactivated" => admin.deactivated,
Maksim's avatar
Maksim committed
951 952 953 954
            "id" => admin.id,
            "nickname" => admin.nickname,
            "roles" => %{"admin" => true, "moderator" => false},
            "local" => true,
955 956
            "tags" => [],
            "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
Maxim Filippov's avatar
Maxim Filippov committed
957 958
            "display_name" => HTML.strip_tags(admin.name || admin.nickname),
            "confirmation_pending" => false
Maksim's avatar
Maksim committed
959 960 961 962 963 964 965
          },
          %{
            "deactivated" => false,
            "id" => old_admin.id,
            "local" => true,
            "nickname" => old_admin.nickname,
            "roles" => %{"admin" => true, "moderator" => false},
966 967
            "tags" => [],
            "avatar" => User.avatar_url(old_admin) |> MediaProxy.url(),
Maxim Filippov's avatar
Maxim Filippov committed
968 969
            "display_name" => HTML.strip_tags(old_admin.name || old_admin.nickname),
            "confirmation_pending" => false
Maksim's avatar
Maksim committed
970 971 972 973
          }
        ]
        |> Enum.sort_by(& &1["nickname"])

974
      assert json_response(conn, 200) == %{
Alexander Strizhakov's avatar
Alexander Strizhakov committed
975
               "count" => 3,
976
               "page_size" => 50,