logo

pleroma

My custom branche(s) on git.pleroma.social/pleroma/pleroma

admin_api_controller_test.exs (67028B)


  1. # Pleroma: A lightweight social networking server
  2. # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
  3. # SPDX-License-Identifier: AGPL-3.0-only
  4. defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
  5. use Pleroma.Web.ConnCase
  6. use Oban.Testing, repo: Pleroma.Repo
  7. import ExUnit.CaptureLog
  8. import Mock
  9. import Pleroma.Factory
  10. import Swoosh.TestAssertions
  11. alias Pleroma.Activity
  12. alias Pleroma.Config
  13. alias Pleroma.HTML
  14. alias Pleroma.MFA
  15. alias Pleroma.ModerationLog
  16. alias Pleroma.Repo
  17. alias Pleroma.Tests.ObanHelpers
  18. alias Pleroma.User
  19. alias Pleroma.Web
  20. alias Pleroma.Web.ActivityPub.Relay
  21. alias Pleroma.Web.CommonAPI
  22. alias Pleroma.Web.MediaProxy
  23. setup_all do
  24. Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
  25. :ok
  26. end
  27. setup do
  28. admin = insert(:user, is_admin: true)
  29. token = insert(:oauth_admin_token, user: admin)
  30. conn =
  31. build_conn()
  32. |> assign(:user, admin)
  33. |> assign(:token, token)
  34. {:ok, %{admin: admin, token: token, conn: conn}}
  35. end
  36. test "with valid `admin_token` query parameter, skips OAuth scopes check" do
  37. clear_config([:admin_token], "password123")
  38. user = insert(:user)
  39. conn = get(build_conn(), "/api/pleroma/admin/users/#{user.nickname}?admin_token=password123")
  40. assert json_response(conn, 200)
  41. end
  42. describe "with [:auth, :enforce_oauth_admin_scope_usage]," do
  43. setup do: clear_config([:auth, :enforce_oauth_admin_scope_usage], true)
  44. test "GET /api/pleroma/admin/users/:nickname requires admin:read:accounts or broader scope",
  45. %{admin: admin} do
  46. user = insert(:user)
  47. url = "/api/pleroma/admin/users/#{user.nickname}"
  48. good_token1 = insert(:oauth_token, user: admin, scopes: ["admin"])
  49. good_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read"])
  50. good_token3 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts"])
  51. bad_token1 = insert(:oauth_token, user: admin, scopes: ["read:accounts"])
  52. bad_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts:partial"])
  53. bad_token3 = nil
  54. for good_token <- [good_token1, good_token2, good_token3] do
  55. conn =
  56. build_conn()
  57. |> assign(:user, admin)
  58. |> assign(:token, good_token)
  59. |> get(url)
  60. assert json_response(conn, 200)
  61. end
  62. for good_token <- [good_token1, good_token2, good_token3] do
  63. conn =
  64. build_conn()
  65. |> assign(:user, nil)
  66. |> assign(:token, good_token)
  67. |> get(url)
  68. assert json_response(conn, :forbidden)
  69. end
  70. for bad_token <- [bad_token1, bad_token2, bad_token3] do
  71. conn =
  72. build_conn()
  73. |> assign(:user, admin)
  74. |> assign(:token, bad_token)
  75. |> get(url)
  76. assert json_response(conn, :forbidden)
  77. end
  78. end
  79. end
  80. describe "unless [:auth, :enforce_oauth_admin_scope_usage]," do
  81. setup do: clear_config([:auth, :enforce_oauth_admin_scope_usage], false)
  82. test "GET /api/pleroma/admin/users/:nickname requires " <>
  83. "read:accounts or admin:read:accounts or broader scope",
  84. %{admin: admin} do
  85. user = insert(:user)
  86. url = "/api/pleroma/admin/users/#{user.nickname}"
  87. good_token1 = insert(:oauth_token, user: admin, scopes: ["admin"])
  88. good_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read"])
  89. good_token3 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts"])
  90. good_token4 = insert(:oauth_token, user: admin, scopes: ["read:accounts"])
  91. good_token5 = insert(:oauth_token, user: admin, scopes: ["read"])
  92. good_tokens = [good_token1, good_token2, good_token3, good_token4, good_token5]
  93. bad_token1 = insert(:oauth_token, user: admin, scopes: ["read:accounts:partial"])
  94. bad_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts:partial"])
  95. bad_token3 = nil
  96. for good_token <- good_tokens do
  97. conn =
  98. build_conn()
  99. |> assign(:user, admin)
  100. |> assign(:token, good_token)
  101. |> get(url)
  102. assert json_response(conn, 200)
  103. end
  104. for good_token <- good_tokens do
  105. conn =
  106. build_conn()
  107. |> assign(:user, nil)
  108. |> assign(:token, good_token)
  109. |> get(url)
  110. assert json_response(conn, :forbidden)
  111. end
  112. for bad_token <- [bad_token1, bad_token2, bad_token3] do
  113. conn =
  114. build_conn()
  115. |> assign(:user, admin)
  116. |> assign(:token, bad_token)
  117. |> get(url)
  118. assert json_response(conn, :forbidden)
  119. end
  120. end
  121. end
  122. describe "DELETE /api/pleroma/admin/users" do
  123. test "single user", %{admin: admin, conn: conn} do
  124. clear_config([:instance, :federating], true)
  125. user =
  126. insert(:user,
  127. avatar: %{"url" => [%{"href" => "https://someurl"}]},
  128. banner: %{"url" => [%{"href" => "https://somebanner"}]},
  129. bio: "Hello world!",
  130. name: "A guy"
  131. )
  132. # Create some activities to check they got deleted later
  133. follower = insert(:user)
  134. {:ok, _} = CommonAPI.post(user, %{status: "test"})
  135. {:ok, _, _, _} = CommonAPI.follow(user, follower)
  136. {:ok, _, _, _} = CommonAPI.follow(follower, user)
  137. user = Repo.get(User, user.id)
  138. assert user.note_count == 1
  139. assert user.follower_count == 1
  140. assert user.following_count == 1
  141. refute user.deactivated
  142. with_mock Pleroma.Web.Federator,
  143. publish: fn _ -> nil end,
  144. perform: fn _, _ -> nil end do
  145. conn =
  146. conn
  147. |> put_req_header("accept", "application/json")
  148. |> delete("/api/pleroma/admin/users?nickname=#{user.nickname}")
  149. ObanHelpers.perform_all()
  150. assert User.get_by_nickname(user.nickname).deactivated
  151. log_entry = Repo.one(ModerationLog)
  152. assert ModerationLog.get_log_entry_message(log_entry) ==
  153. "@#{admin.nickname} deleted users: @#{user.nickname}"
  154. assert json_response(conn, 200) == [user.nickname]
  155. user = Repo.get(User, user.id)
  156. assert user.deactivated
  157. assert user.avatar == %{}
  158. assert user.banner == %{}
  159. assert user.note_count == 0
  160. assert user.follower_count == 0
  161. assert user.following_count == 0
  162. assert user.bio == ""
  163. assert user.name == nil
  164. assert called(Pleroma.Web.Federator.publish(:_))
  165. end
  166. end
  167. test "multiple users", %{admin: admin, conn: conn} do
  168. user_one = insert(:user)
  169. user_two = insert(:user)
  170. conn =
  171. conn
  172. |> put_req_header("accept", "application/json")
  173. |> delete("/api/pleroma/admin/users", %{
  174. nicknames: [user_one.nickname, user_two.nickname]
  175. })
  176. log_entry = Repo.one(ModerationLog)
  177. assert ModerationLog.get_log_entry_message(log_entry) ==
  178. "@#{admin.nickname} deleted users: @#{user_one.nickname}, @#{user_two.nickname}"
  179. response = json_response(conn, 200)
  180. assert response -- [user_one.nickname, user_two.nickname] == []
  181. end
  182. end
  183. describe "/api/pleroma/admin/users" do
  184. test "Create", %{conn: conn} do
  185. conn =
  186. conn
  187. |> put_req_header("accept", "application/json")
  188. |> post("/api/pleroma/admin/users", %{
  189. "users" => [
  190. %{
  191. "nickname" => "lain",
  192. "email" => "lain@example.org",
  193. "password" => "test"
  194. },
  195. %{
  196. "nickname" => "lain2",
  197. "email" => "lain2@example.org",
  198. "password" => "test"
  199. }
  200. ]
  201. })
  202. response = json_response(conn, 200) |> Enum.map(&Map.get(&1, "type"))
  203. assert response == ["success", "success"]
  204. log_entry = Repo.one(ModerationLog)
  205. assert ["lain", "lain2"] -- Enum.map(log_entry.data["subjects"], & &1["nickname"]) == []
  206. end
  207. test "Cannot create user with existing email", %{conn: conn} do
  208. user = insert(:user)
  209. conn =
  210. conn
  211. |> put_req_header("accept", "application/json")
  212. |> post("/api/pleroma/admin/users", %{
  213. "users" => [
  214. %{
  215. "nickname" => "lain",
  216. "email" => user.email,
  217. "password" => "test"
  218. }
  219. ]
  220. })
  221. assert json_response(conn, 409) == [
  222. %{
  223. "code" => 409,
  224. "data" => %{
  225. "email" => user.email,
  226. "nickname" => "lain"
  227. },
  228. "error" => "email has already been taken",
  229. "type" => "error"
  230. }
  231. ]
  232. end
  233. test "Cannot create user with existing nickname", %{conn: conn} do
  234. user = insert(:user)
  235. conn =
  236. conn
  237. |> put_req_header("accept", "application/json")
  238. |> post("/api/pleroma/admin/users", %{
  239. "users" => [
  240. %{
  241. "nickname" => user.nickname,
  242. "email" => "someuser@plerama.social",
  243. "password" => "test"
  244. }
  245. ]
  246. })
  247. assert json_response(conn, 409) == [
  248. %{
  249. "code" => 409,
  250. "data" => %{
  251. "email" => "someuser@plerama.social",
  252. "nickname" => user.nickname
  253. },
  254. "error" => "nickname has already been taken",
  255. "type" => "error"
  256. }
  257. ]
  258. end
  259. test "Multiple user creation works in transaction", %{conn: conn} do
  260. user = insert(:user)
  261. conn =
  262. conn
  263. |> put_req_header("accept", "application/json")
  264. |> post("/api/pleroma/admin/users", %{
  265. "users" => [
  266. %{
  267. "nickname" => "newuser",
  268. "email" => "newuser@pleroma.social",
  269. "password" => "test"
  270. },
  271. %{
  272. "nickname" => "lain",
  273. "email" => user.email,
  274. "password" => "test"
  275. }
  276. ]
  277. })
  278. assert json_response(conn, 409) == [
  279. %{
  280. "code" => 409,
  281. "data" => %{
  282. "email" => user.email,
  283. "nickname" => "lain"
  284. },
  285. "error" => "email has already been taken",
  286. "type" => "error"
  287. },
  288. %{
  289. "code" => 409,
  290. "data" => %{
  291. "email" => "newuser@pleroma.social",
  292. "nickname" => "newuser"
  293. },
  294. "error" => "",
  295. "type" => "error"
  296. }
  297. ]
  298. assert User.get_by_nickname("newuser") === nil
  299. end
  300. end
  301. describe "/api/pleroma/admin/users/:nickname" do
  302. test "Show", %{conn: conn} do
  303. user = insert(:user)
  304. conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}")
  305. expected = %{
  306. "deactivated" => false,
  307. "id" => to_string(user.id),
  308. "local" => true,
  309. "nickname" => user.nickname,
  310. "roles" => %{"admin" => false, "moderator" => false},
  311. "tags" => [],
  312. "avatar" => User.avatar_url(user) |> MediaProxy.url(),
  313. "display_name" => HTML.strip_tags(user.name || user.nickname),
  314. "confirmation_pending" => false,
  315. "approval_pending" => false,
  316. "url" => user.ap_id,
  317. "registration_reason" => nil,
  318. "actor_type" => "Person"
  319. }
  320. assert expected == json_response(conn, 200)
  321. end
  322. test "when the user doesn't exist", %{conn: conn} do
  323. user = build(:user)
  324. conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}")
  325. assert %{"error" => "Not found"} == json_response(conn, 404)
  326. end
  327. end
  328. describe "/api/pleroma/admin/users/follow" do
  329. test "allows to force-follow another user", %{admin: admin, conn: conn} do
  330. user = insert(:user)
  331. follower = insert(:user)
  332. conn
  333. |> put_req_header("accept", "application/json")
  334. |> post("/api/pleroma/admin/users/follow", %{
  335. "follower" => follower.nickname,
  336. "followed" => user.nickname
  337. })
  338. user = User.get_cached_by_id(user.id)
  339. follower = User.get_cached_by_id(follower.id)
  340. assert User.following?(follower, user)
  341. log_entry = Repo.one(ModerationLog)
  342. assert ModerationLog.get_log_entry_message(log_entry) ==
  343. "@#{admin.nickname} made @#{follower.nickname} follow @#{user.nickname}"
  344. end
  345. end
  346. describe "/api/pleroma/admin/users/unfollow" do
  347. test "allows to force-unfollow another user", %{admin: admin, conn: conn} do
  348. user = insert(:user)
  349. follower = insert(:user)
  350. User.follow(follower, user)
  351. conn
  352. |> put_req_header("accept", "application/json")
  353. |> post("/api/pleroma/admin/users/unfollow", %{
  354. "follower" => follower.nickname,
  355. "followed" => user.nickname
  356. })
  357. user = User.get_cached_by_id(user.id)
  358. follower = User.get_cached_by_id(follower.id)
  359. refute User.following?(follower, user)
  360. log_entry = Repo.one(ModerationLog)
  361. assert ModerationLog.get_log_entry_message(log_entry) ==
  362. "@#{admin.nickname} made @#{follower.nickname} unfollow @#{user.nickname}"
  363. end
  364. end
  365. describe "PUT /api/pleroma/admin/users/tag" do
  366. setup %{conn: conn} do
  367. user1 = insert(:user, %{tags: ["x"]})
  368. user2 = insert(:user, %{tags: ["y"]})
  369. user3 = insert(:user, %{tags: ["unchanged"]})
  370. conn =
  371. conn
  372. |> put_req_header("accept", "application/json")
  373. |> put(
  374. "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <>
  375. "#{user2.nickname}&tags[]=foo&tags[]=bar"
  376. )
  377. %{conn: conn, user1: user1, user2: user2, user3: user3}
  378. end
  379. test "it appends specified tags to users with specified nicknames", %{
  380. conn: conn,
  381. admin: admin,
  382. user1: user1,
  383. user2: user2
  384. } do
  385. assert empty_json_response(conn)
  386. assert User.get_cached_by_id(user1.id).tags == ["x", "foo", "bar"]
  387. assert User.get_cached_by_id(user2.id).tags == ["y", "foo", "bar"]
  388. log_entry = Repo.one(ModerationLog)
  389. users =
  390. [user1.nickname, user2.nickname]
  391. |> Enum.map(&"@#{&1}")
  392. |> Enum.join(", ")
  393. tags = ["foo", "bar"] |> Enum.join(", ")
  394. assert ModerationLog.get_log_entry_message(log_entry) ==
  395. "@#{admin.nickname} added tags: #{tags} to users: #{users}"
  396. end
  397. test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do
  398. assert empty_json_response(conn)
  399. assert User.get_cached_by_id(user3.id).tags == ["unchanged"]
  400. end
  401. end
  402. describe "DELETE /api/pleroma/admin/users/tag" do
  403. setup %{conn: conn} do
  404. user1 = insert(:user, %{tags: ["x"]})
  405. user2 = insert(:user, %{tags: ["y", "z"]})
  406. user3 = insert(:user, %{tags: ["unchanged"]})
  407. conn =
  408. conn
  409. |> put_req_header("accept", "application/json")
  410. |> delete(
  411. "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <>
  412. "#{user2.nickname}&tags[]=x&tags[]=z"
  413. )
  414. %{conn: conn, user1: user1, user2: user2, user3: user3}
  415. end
  416. test "it removes specified tags from users with specified nicknames", %{
  417. conn: conn,
  418. admin: admin,
  419. user1: user1,
  420. user2: user2
  421. } do
  422. assert empty_json_response(conn)
  423. assert User.get_cached_by_id(user1.id).tags == []
  424. assert User.get_cached_by_id(user2.id).tags == ["y"]
  425. log_entry = Repo.one(ModerationLog)
  426. users =
  427. [user1.nickname, user2.nickname]
  428. |> Enum.map(&"@#{&1}")
  429. |> Enum.join(", ")
  430. tags = ["x", "z"] |> Enum.join(", ")
  431. assert ModerationLog.get_log_entry_message(log_entry) ==
  432. "@#{admin.nickname} removed tags: #{tags} from users: #{users}"
  433. end
  434. test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do
  435. assert empty_json_response(conn)
  436. assert User.get_cached_by_id(user3.id).tags == ["unchanged"]
  437. end
  438. end
  439. describe "/api/pleroma/admin/users/:nickname/permission_group" do
  440. test "GET is giving user_info", %{admin: admin, conn: conn} do
  441. conn =
  442. conn
  443. |> put_req_header("accept", "application/json")
  444. |> get("/api/pleroma/admin/users/#{admin.nickname}/permission_group/")
  445. assert json_response(conn, 200) == %{
  446. "is_admin" => true,
  447. "is_moderator" => false
  448. }
  449. end
  450. test "/:right POST, can add to a permission group", %{admin: admin, conn: conn} do
  451. user = insert(:user)
  452. conn =
  453. conn
  454. |> put_req_header("accept", "application/json")
  455. |> post("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin")
  456. assert json_response(conn, 200) == %{
  457. "is_admin" => true
  458. }
  459. log_entry = Repo.one(ModerationLog)
  460. assert ModerationLog.get_log_entry_message(log_entry) ==
  461. "@#{admin.nickname} made @#{user.nickname} admin"
  462. end
  463. test "/:right POST, can add to a permission group (multiple)", %{admin: admin, conn: conn} do
  464. user_one = insert(:user)
  465. user_two = insert(:user)
  466. conn =
  467. conn
  468. |> put_req_header("accept", "application/json")
  469. |> post("/api/pleroma/admin/users/permission_group/admin", %{
  470. nicknames: [user_one.nickname, user_two.nickname]
  471. })
  472. assert json_response(conn, 200) == %{"is_admin" => true}
  473. log_entry = Repo.one(ModerationLog)
  474. assert ModerationLog.get_log_entry_message(log_entry) ==
  475. "@#{admin.nickname} made @#{user_one.nickname}, @#{user_two.nickname} admin"
  476. end
  477. test "/:right DELETE, can remove from a permission group", %{admin: admin, conn: conn} do
  478. user = insert(:user, is_admin: true)
  479. conn =
  480. conn
  481. |> put_req_header("accept", "application/json")
  482. |> delete("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin")
  483. assert json_response(conn, 200) == %{"is_admin" => false}
  484. log_entry = Repo.one(ModerationLog)
  485. assert ModerationLog.get_log_entry_message(log_entry) ==
  486. "@#{admin.nickname} revoked admin role from @#{user.nickname}"
  487. end
  488. test "/:right DELETE, can remove from a permission group (multiple)", %{
  489. admin: admin,
  490. conn: conn
  491. } do
  492. user_one = insert(:user, is_admin: true)
  493. user_two = insert(:user, is_admin: true)
  494. conn =
  495. conn
  496. |> put_req_header("accept", "application/json")
  497. |> delete("/api/pleroma/admin/users/permission_group/admin", %{
  498. nicknames: [user_one.nickname, user_two.nickname]
  499. })
  500. assert json_response(conn, 200) == %{"is_admin" => false}
  501. log_entry = Repo.one(ModerationLog)
  502. assert ModerationLog.get_log_entry_message(log_entry) ==
  503. "@#{admin.nickname} revoked admin role from @#{user_one.nickname}, @#{
  504. user_two.nickname
  505. }"
  506. end
  507. end
  508. test "/api/pleroma/admin/users/:nickname/password_reset", %{conn: conn} do
  509. user = insert(:user)
  510. conn =
  511. conn
  512. |> put_req_header("accept", "application/json")
  513. |> get("/api/pleroma/admin/users/#{user.nickname}/password_reset")
  514. resp = json_response(conn, 200)
  515. assert Regex.match?(~r/(http:\/\/|https:\/\/)/, resp["link"])
  516. end
  517. describe "GET /api/pleroma/admin/users" do
  518. test "renders users array for the first page", %{conn: conn, admin: admin} do
  519. user = insert(:user, local: false, tags: ["foo", "bar"])
  520. user2 = insert(:user, approval_pending: true, registration_reason: "I'm a chill dude")
  521. conn = get(conn, "/api/pleroma/admin/users?page=1")
  522. users =
  523. [
  524. %{
  525. "deactivated" => admin.deactivated,
  526. "id" => admin.id,
  527. "nickname" => admin.nickname,
  528. "roles" => %{"admin" => true, "moderator" => false},
  529. "local" => true,
  530. "tags" => [],
  531. "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
  532. "display_name" => HTML.strip_tags(admin.name || admin.nickname),
  533. "confirmation_pending" => false,
  534. "approval_pending" => false,
  535. "url" => admin.ap_id,
  536. "registration_reason" => nil,
  537. "actor_type" => "Person"
  538. },
  539. %{
  540. "deactivated" => user.deactivated,
  541. "id" => user.id,
  542. "nickname" => user.nickname,
  543. "roles" => %{"admin" => false, "moderator" => false},
  544. "local" => false,
  545. "tags" => ["foo", "bar"],
  546. "avatar" => User.avatar_url(user) |> MediaProxy.url(),
  547. "display_name" => HTML.strip_tags(user.name || user.nickname),
  548. "confirmation_pending" => false,
  549. "approval_pending" => false,
  550. "url" => user.ap_id,
  551. "registration_reason" => nil,
  552. "actor_type" => "Person"
  553. },
  554. %{
  555. "deactivated" => user2.deactivated,
  556. "id" => user2.id,
  557. "nickname" => user2.nickname,
  558. "roles" => %{"admin" => false, "moderator" => false},
  559. "local" => true,
  560. "tags" => [],
  561. "avatar" => User.avatar_url(user2) |> MediaProxy.url(),
  562. "display_name" => HTML.strip_tags(user2.name || user2.nickname),
  563. "confirmation_pending" => false,
  564. "approval_pending" => true,
  565. "url" => user2.ap_id,
  566. "registration_reason" => "I'm a chill dude",
  567. "actor_type" => "Person"
  568. }
  569. ]
  570. |> Enum.sort_by(& &1["nickname"])
  571. assert json_response(conn, 200) == %{
  572. "count" => 3,
  573. "page_size" => 50,
  574. "users" => users
  575. }
  576. end
  577. test "pagination works correctly with service users", %{conn: conn} do
  578. service1 = User.get_or_create_service_actor_by_ap_id(Web.base_url() <> "/meido", "meido")
  579. insert_list(25, :user)
  580. assert %{"count" => 26, "page_size" => 10, "users" => users1} =
  581. conn
  582. |> get("/api/pleroma/admin/users?page=1&filters=", %{page_size: "10"})
  583. |> json_response(200)
  584. assert Enum.count(users1) == 10
  585. assert service1 not in users1
  586. assert %{"count" => 26, "page_size" => 10, "users" => users2} =
  587. conn
  588. |> get("/api/pleroma/admin/users?page=2&filters=", %{page_size: "10"})
  589. |> json_response(200)
  590. assert Enum.count(users2) == 10
  591. assert service1 not in users2
  592. assert %{"count" => 26, "page_size" => 10, "users" => users3} =
  593. conn
  594. |> get("/api/pleroma/admin/users?page=3&filters=", %{page_size: "10"})
  595. |> json_response(200)
  596. assert Enum.count(users3) == 6
  597. assert service1 not in users3
  598. end
  599. test "renders empty array for the second page", %{conn: conn} do
  600. insert(:user)
  601. conn = get(conn, "/api/pleroma/admin/users?page=2")
  602. assert json_response(conn, 200) == %{
  603. "count" => 2,
  604. "page_size" => 50,
  605. "users" => []
  606. }
  607. end
  608. test "regular search", %{conn: conn} do
  609. user = insert(:user, nickname: "bob")
  610. conn = get(conn, "/api/pleroma/admin/users?query=bo")
  611. assert json_response(conn, 200) == %{
  612. "count" => 1,
  613. "page_size" => 50,
  614. "users" => [
  615. %{
  616. "deactivated" => user.deactivated,
  617. "id" => user.id,
  618. "nickname" => user.nickname,
  619. "roles" => %{"admin" => false, "moderator" => false},
  620. "local" => true,
  621. "tags" => [],
  622. "avatar" => User.avatar_url(user) |> MediaProxy.url(),
  623. "display_name" => HTML.strip_tags(user.name || user.nickname),
  624. "confirmation_pending" => false,
  625. "approval_pending" => false,
  626. "url" => user.ap_id,
  627. "registration_reason" => nil,
  628. "actor_type" => "Person"
  629. }
  630. ]
  631. }
  632. end
  633. test "search by domain", %{conn: conn} do
  634. user = insert(:user, nickname: "nickname@domain.com")
  635. insert(:user)
  636. conn = get(conn, "/api/pleroma/admin/users?query=domain.com")
  637. assert json_response(conn, 200) == %{
  638. "count" => 1,
  639. "page_size" => 50,
  640. "users" => [
  641. %{
  642. "deactivated" => user.deactivated,
  643. "id" => user.id,
  644. "nickname" => user.nickname,
  645. "roles" => %{"admin" => false, "moderator" => false},
  646. "local" => true,
  647. "tags" => [],
  648. "avatar" => User.avatar_url(user) |> MediaProxy.url(),
  649. "display_name" => HTML.strip_tags(user.name || user.nickname),
  650. "confirmation_pending" => false,
  651. "approval_pending" => false,
  652. "url" => user.ap_id,
  653. "registration_reason" => nil,
  654. "actor_type" => "Person"
  655. }
  656. ]
  657. }
  658. end
  659. test "search by full nickname", %{conn: conn} do
  660. user = insert(:user, nickname: "nickname@domain.com")
  661. insert(:user)
  662. conn = get(conn, "/api/pleroma/admin/users?query=nickname@domain.com")
  663. assert json_response(conn, 200) == %{
  664. "count" => 1,
  665. "page_size" => 50,
  666. "users" => [
  667. %{
  668. "deactivated" => user.deactivated,
  669. "id" => user.id,
  670. "nickname" => user.nickname,
  671. "roles" => %{"admin" => false, "moderator" => false},
  672. "local" => true,
  673. "tags" => [],
  674. "avatar" => User.avatar_url(user) |> MediaProxy.url(),
  675. "display_name" => HTML.strip_tags(user.name || user.nickname),
  676. "confirmation_pending" => false,
  677. "approval_pending" => false,
  678. "url" => user.ap_id,
  679. "registration_reason" => nil,
  680. "actor_type" => "Person"
  681. }
  682. ]
  683. }
  684. end
  685. test "search by display name", %{conn: conn} do
  686. user = insert(:user, name: "Display name")
  687. insert(:user)
  688. conn = get(conn, "/api/pleroma/admin/users?name=display")
  689. assert json_response(conn, 200) == %{
  690. "count" => 1,
  691. "page_size" => 50,
  692. "users" => [
  693. %{
  694. "deactivated" => user.deactivated,
  695. "id" => user.id,
  696. "nickname" => user.nickname,
  697. "roles" => %{"admin" => false, "moderator" => false},
  698. "local" => true,
  699. "tags" => [],
  700. "avatar" => User.avatar_url(user) |> MediaProxy.url(),
  701. "display_name" => HTML.strip_tags(user.name || user.nickname),
  702. "confirmation_pending" => false,
  703. "approval_pending" => false,
  704. "url" => user.ap_id,
  705. "registration_reason" => nil,
  706. "actor_type" => "Person"
  707. }
  708. ]
  709. }
  710. end
  711. test "search by email", %{conn: conn} do
  712. user = insert(:user, email: "email@example.com")
  713. insert(:user)
  714. conn = get(conn, "/api/pleroma/admin/users?email=email@example.com")
  715. assert json_response(conn, 200) == %{
  716. "count" => 1,
  717. "page_size" => 50,
  718. "users" => [
  719. %{
  720. "deactivated" => user.deactivated,
  721. "id" => user.id,
  722. "nickname" => user.nickname,
  723. "roles" => %{"admin" => false, "moderator" => false},
  724. "local" => true,
  725. "tags" => [],
  726. "avatar" => User.avatar_url(user) |> MediaProxy.url(),
  727. "display_name" => HTML.strip_tags(user.name || user.nickname),
  728. "confirmation_pending" => false,
  729. "approval_pending" => false,
  730. "url" => user.ap_id,
  731. "registration_reason" => nil,
  732. "actor_type" => "Person"
  733. }
  734. ]
  735. }
  736. end
  737. test "regular search with page size", %{conn: conn} do
  738. user = insert(:user, nickname: "aalice")
  739. user2 = insert(:user, nickname: "alice")
  740. conn1 = get(conn, "/api/pleroma/admin/users?query=a&page_size=1&page=1")
  741. assert json_response(conn1, 200) == %{
  742. "count" => 2,
  743. "page_size" => 1,
  744. "users" => [
  745. %{
  746. "deactivated" => user.deactivated,
  747. "id" => user.id,
  748. "nickname" => user.nickname,
  749. "roles" => %{"admin" => false, "moderator" => false},
  750. "local" => true,
  751. "tags" => [],
  752. "avatar" => User.avatar_url(user) |> MediaProxy.url(),
  753. "display_name" => HTML.strip_tags(user.name || user.nickname),
  754. "confirmation_pending" => false,
  755. "approval_pending" => false,
  756. "url" => user.ap_id,
  757. "registration_reason" => nil,
  758. "actor_type" => "Person"
  759. }
  760. ]
  761. }
  762. conn2 = get(conn, "/api/pleroma/admin/users?query=a&page_size=1&page=2")
  763. assert json_response(conn2, 200) == %{
  764. "count" => 2,
  765. "page_size" => 1,
  766. "users" => [
  767. %{
  768. "deactivated" => user2.deactivated,
  769. "id" => user2.id,
  770. "nickname" => user2.nickname,
  771. "roles" => %{"admin" => false, "moderator" => false},
  772. "local" => true,
  773. "tags" => [],
  774. "avatar" => User.avatar_url(user2) |> MediaProxy.url(),
  775. "display_name" => HTML.strip_tags(user2.name || user2.nickname),
  776. "confirmation_pending" => false,
  777. "approval_pending" => false,
  778. "url" => user2.ap_id,
  779. "registration_reason" => nil,
  780. "actor_type" => "Person"
  781. }
  782. ]
  783. }
  784. end
  785. test "only local users" do
  786. admin = insert(:user, is_admin: true, nickname: "john")
  787. token = insert(:oauth_admin_token, user: admin)
  788. user = insert(:user, nickname: "bob")
  789. insert(:user, nickname: "bobb", local: false)
  790. conn =
  791. build_conn()
  792. |> assign(:user, admin)
  793. |> assign(:token, token)
  794. |> get("/api/pleroma/admin/users?query=bo&filters=local")
  795. assert json_response(conn, 200) == %{
  796. "count" => 1,
  797. "page_size" => 50,
  798. "users" => [
  799. %{
  800. "deactivated" => user.deactivated,
  801. "id" => user.id,
  802. "nickname" => user.nickname,
  803. "roles" => %{"admin" => false, "moderator" => false},
  804. "local" => true,
  805. "tags" => [],
  806. "avatar" => User.avatar_url(user) |> MediaProxy.url(),
  807. "display_name" => HTML.strip_tags(user.name || user.nickname),
  808. "confirmation_pending" => false,
  809. "approval_pending" => false,
  810. "url" => user.ap_id,
  811. "registration_reason" => nil,
  812. "actor_type" => "Person"
  813. }
  814. ]
  815. }
  816. end
  817. test "only local users with no query", %{conn: conn, admin: old_admin} do
  818. admin = insert(:user, is_admin: true, nickname: "john")
  819. user = insert(:user, nickname: "bob")
  820. insert(:user, nickname: "bobb", local: false)
  821. conn = get(conn, "/api/pleroma/admin/users?filters=local")
  822. users =
  823. [
  824. %{
  825. "deactivated" => user.deactivated,
  826. "id" => user.id,
  827. "nickname" => user.nickname,
  828. "roles" => %{"admin" => false, "moderator" => false},
  829. "local" => true,
  830. "tags" => [],
  831. "avatar" => User.avatar_url(user) |> MediaProxy.url(),
  832. "display_name" => HTML.strip_tags(user.name || user.nickname),
  833. "confirmation_pending" => false,
  834. "approval_pending" => false,
  835. "url" => user.ap_id,
  836. "registration_reason" => nil,
  837. "actor_type" => "Person"
  838. },
  839. %{
  840. "deactivated" => admin.deactivated,
  841. "id" => admin.id,
  842. "nickname" => admin.nickname,
  843. "roles" => %{"admin" => true, "moderator" => false},
  844. "local" => true,
  845. "tags" => [],
  846. "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
  847. "display_name" => HTML.strip_tags(admin.name || admin.nickname),
  848. "confirmation_pending" => false,
  849. "approval_pending" => false,
  850. "url" => admin.ap_id,
  851. "registration_reason" => nil,
  852. "actor_type" => "Person"
  853. },
  854. %{
  855. "deactivated" => false,
  856. "id" => old_admin.id,
  857. "local" => true,
  858. "nickname" => old_admin.nickname,
  859. "roles" => %{"admin" => true, "moderator" => false},
  860. "tags" => [],
  861. "avatar" => User.avatar_url(old_admin) |> MediaProxy.url(),
  862. "display_name" => HTML.strip_tags(old_admin.name || old_admin.nickname),
  863. "confirmation_pending" => false,
  864. "approval_pending" => false,
  865. "url" => old_admin.ap_id,
  866. "registration_reason" => nil,
  867. "actor_type" => "Person"
  868. }
  869. ]
  870. |> Enum.sort_by(& &1["nickname"])
  871. assert json_response(conn, 200) == %{
  872. "count" => 3,
  873. "page_size" => 50,
  874. "users" => users
  875. }
  876. end
  877. test "only unapproved users", %{conn: conn} do
  878. user =
  879. insert(:user,
  880. nickname: "sadboy",
  881. approval_pending: true,
  882. registration_reason: "Plz let me in!"
  883. )
  884. insert(:user, nickname: "happyboy", approval_pending: false)
  885. conn = get(conn, "/api/pleroma/admin/users?filters=need_approval")
  886. users =
  887. [
  888. %{
  889. "deactivated" => user.deactivated,
  890. "id" => user.id,
  891. "nickname" => user.nickname,
  892. "roles" => %{"admin" => false, "moderator" => false},
  893. "local" => true,
  894. "tags" => [],
  895. "avatar" => User.avatar_url(user) |> MediaProxy.url(),
  896. "display_name" => HTML.strip_tags(user.name || user.nickname),
  897. "confirmation_pending" => false,
  898. "approval_pending" => true,
  899. "url" => user.ap_id,
  900. "registration_reason" => "Plz let me in!",
  901. "actor_type" => "Person"
  902. }
  903. ]
  904. |> Enum.sort_by(& &1["nickname"])
  905. assert json_response(conn, 200) == %{
  906. "count" => 1,
  907. "page_size" => 50,
  908. "users" => users
  909. }
  910. end
  911. test "load only admins", %{conn: conn, admin: admin} do
  912. second_admin = insert(:user, is_admin: true)
  913. insert(:user)
  914. insert(:user)
  915. conn = get(conn, "/api/pleroma/admin/users?filters=is_admin")
  916. users =
  917. [
  918. %{
  919. "deactivated" => false,
  920. "id" => admin.id,
  921. "nickname" => admin.nickname,
  922. "roles" => %{"admin" => true, "moderator" => false},
  923. "local" => admin.local,
  924. "tags" => [],
  925. "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
  926. "display_name" => HTML.strip_tags(admin.name || admin.nickname),
  927. "confirmation_pending" => false,
  928. "approval_pending" => false,
  929. "url" => admin.ap_id,
  930. "registration_reason" => nil,
  931. "actor_type" => "Person"
  932. },
  933. %{
  934. "deactivated" => false,
  935. "id" => second_admin.id,
  936. "nickname" => second_admin.nickname,
  937. "roles" => %{"admin" => true, "moderator" => false},
  938. "local" => second_admin.local,
  939. "tags" => [],
  940. "avatar" => User.avatar_url(second_admin) |> MediaProxy.url(),
  941. "display_name" => HTML.strip_tags(second_admin.name || second_admin.nickname),
  942. "confirmation_pending" => false,
  943. "approval_pending" => false,
  944. "url" => second_admin.ap_id,
  945. "registration_reason" => nil,
  946. "actor_type" => "Person"
  947. }
  948. ]
  949. |> Enum.sort_by(& &1["nickname"])
  950. assert json_response(conn, 200) == %{
  951. "count" => 2,
  952. "page_size" => 50,
  953. "users" => users
  954. }
  955. end
  956. test "load only moderators", %{conn: conn} do
  957. moderator = insert(:user, is_moderator: true)
  958. insert(:user)
  959. insert(:user)
  960. conn = get(conn, "/api/pleroma/admin/users?filters=is_moderator")
  961. assert json_response(conn, 200) == %{
  962. "count" => 1,
  963. "page_size" => 50,
  964. "users" => [
  965. %{
  966. "deactivated" => false,
  967. "id" => moderator.id,
  968. "nickname" => moderator.nickname,
  969. "roles" => %{"admin" => false, "moderator" => true},
  970. "local" => moderator.local,
  971. "tags" => [],
  972. "avatar" => User.avatar_url(moderator) |> MediaProxy.url(),
  973. "display_name" => HTML.strip_tags(moderator.name || moderator.nickname),
  974. "confirmation_pending" => false,
  975. "approval_pending" => false,
  976. "url" => moderator.ap_id,
  977. "registration_reason" => nil,
  978. "actor_type" => "Person"
  979. }
  980. ]
  981. }
  982. end
  983. test "load users with tags list", %{conn: conn} do
  984. user1 = insert(:user, tags: ["first"])
  985. user2 = insert(:user, tags: ["second"])
  986. insert(:user)
  987. insert(:user)
  988. conn = get(conn, "/api/pleroma/admin/users?tags[]=first&tags[]=second")
  989. users =
  990. [
  991. %{
  992. "deactivated" => false,
  993. "id" => user1.id,
  994. "nickname" => user1.nickname,
  995. "roles" => %{"admin" => false, "moderator" => false},
  996. "local" => user1.local,
  997. "tags" => ["first"],
  998. "avatar" => User.avatar_url(user1) |> MediaProxy.url(),
  999. "display_name" => HTML.strip_tags(user1.name || user1.nickname),
  1000. "confirmation_pending" => false,
  1001. "approval_pending" => false,
  1002. "url" => user1.ap_id,
  1003. "registration_reason" => nil,
  1004. "actor_type" => "Person"
  1005. },
  1006. %{
  1007. "deactivated" => false,
  1008. "id" => user2.id,
  1009. "nickname" => user2.nickname,
  1010. "roles" => %{"admin" => false, "moderator" => false},
  1011. "local" => user2.local,
  1012. "tags" => ["second"],
  1013. "avatar" => User.avatar_url(user2) |> MediaProxy.url(),
  1014. "display_name" => HTML.strip_tags(user2.name || user2.nickname),
  1015. "confirmation_pending" => false,
  1016. "approval_pending" => false,
  1017. "url" => user2.ap_id,
  1018. "registration_reason" => nil,
  1019. "actor_type" => "Person"
  1020. }
  1021. ]
  1022. |> Enum.sort_by(& &1["nickname"])
  1023. assert json_response(conn, 200) == %{
  1024. "count" => 2,
  1025. "page_size" => 50,
  1026. "users" => users
  1027. }
  1028. end
  1029. test "`active` filters out users pending approval", %{token: token} do
  1030. insert(:user, approval_pending: true)
  1031. %{id: user_id} = insert(:user, approval_pending: false)
  1032. %{id: admin_id} = token.user
  1033. conn =
  1034. build_conn()
  1035. |> assign(:user, token.user)
  1036. |> assign(:token, token)
  1037. |> get("/api/pleroma/admin/users?filters=active")
  1038. assert %{
  1039. "count" => 2,
  1040. "page_size" => 50,
  1041. "users" => [
  1042. %{"id" => ^admin_id},
  1043. %{"id" => ^user_id}
  1044. ]
  1045. } = json_response(conn, 200)
  1046. end
  1047. test "it works with multiple filters" do
  1048. admin = insert(:user, nickname: "john", is_admin: true)
  1049. token = insert(:oauth_admin_token, user: admin)
  1050. user = insert(:user, nickname: "bob", local: false, deactivated: true)
  1051. insert(:user, nickname: "ken", local: true, deactivated: true)
  1052. insert(:user, nickname: "bobb", local: false, deactivated: false)
  1053. conn =
  1054. build_conn()
  1055. |> assign(:user, admin)
  1056. |> assign(:token, token)
  1057. |> get("/api/pleroma/admin/users?filters=deactivated,external")
  1058. assert json_response(conn, 200) == %{
  1059. "count" => 1,
  1060. "page_size" => 50,
  1061. "users" => [
  1062. %{
  1063. "deactivated" => user.deactivated,
  1064. "id" => user.id,
  1065. "nickname" => user.nickname,
  1066. "roles" => %{"admin" => false, "moderator" => false},
  1067. "local" => user.local,
  1068. "tags" => [],
  1069. "avatar" => User.avatar_url(user) |> MediaProxy.url(),
  1070. "display_name" => HTML.strip_tags(user.name || user.nickname),
  1071. "confirmation_pending" => false,
  1072. "approval_pending" => false,
  1073. "url" => user.ap_id,
  1074. "registration_reason" => nil,
  1075. "actor_type" => "Person"
  1076. }
  1077. ]
  1078. }
  1079. end
  1080. test "it omits relay user", %{admin: admin, conn: conn} do
  1081. assert %User{} = Relay.get_actor()
  1082. conn = get(conn, "/api/pleroma/admin/users")
  1083. assert json_response(conn, 200) == %{
  1084. "count" => 1,
  1085. "page_size" => 50,
  1086. "users" => [
  1087. %{
  1088. "deactivated" => admin.deactivated,
  1089. "id" => admin.id,
  1090. "nickname" => admin.nickname,
  1091. "roles" => %{"admin" => true, "moderator" => false},
  1092. "local" => true,
  1093. "tags" => [],
  1094. "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
  1095. "display_name" => HTML.strip_tags(admin.name || admin.nickname),
  1096. "confirmation_pending" => false,
  1097. "approval_pending" => false,
  1098. "url" => admin.ap_id,
  1099. "registration_reason" => nil,
  1100. "actor_type" => "Person"
  1101. }
  1102. ]
  1103. }
  1104. end
  1105. end
  1106. test "PATCH /api/pleroma/admin/users/activate", %{admin: admin, conn: conn} do
  1107. user_one = insert(:user, deactivated: true)
  1108. user_two = insert(:user, deactivated: true)
  1109. conn =
  1110. patch(
  1111. conn,
  1112. "/api/pleroma/admin/users/activate",
  1113. %{nicknames: [user_one.nickname, user_two.nickname]}
  1114. )
  1115. response = json_response(conn, 200)
  1116. assert Enum.map(response["users"], & &1["deactivated"]) == [false, false]
  1117. log_entry = Repo.one(ModerationLog)
  1118. assert ModerationLog.get_log_entry_message(log_entry) ==
  1119. "@#{admin.nickname} activated users: @#{user_one.nickname}, @#{user_two.nickname}"
  1120. end
  1121. test "PATCH /api/pleroma/admin/users/deactivate", %{admin: admin, conn: conn} do
  1122. user_one = insert(:user, deactivated: false)
  1123. user_two = insert(:user, deactivated: false)
  1124. conn =
  1125. patch(
  1126. conn,
  1127. "/api/pleroma/admin/users/deactivate",
  1128. %{nicknames: [user_one.nickname, user_two.nickname]}
  1129. )
  1130. response = json_response(conn, 200)
  1131. assert Enum.map(response["users"], & &1["deactivated"]) == [true, true]
  1132. log_entry = Repo.one(ModerationLog)
  1133. assert ModerationLog.get_log_entry_message(log_entry) ==
  1134. "@#{admin.nickname} deactivated users: @#{user_one.nickname}, @#{user_two.nickname}"
  1135. end
  1136. test "PATCH /api/pleroma/admin/users/approve", %{admin: admin, conn: conn} do
  1137. user_one = insert(:user, approval_pending: true)
  1138. user_two = insert(:user, approval_pending: true)
  1139. conn =
  1140. patch(
  1141. conn,
  1142. "/api/pleroma/admin/users/approve",
  1143. %{nicknames: [user_one.nickname, user_two.nickname]}
  1144. )
  1145. response = json_response(conn, 200)
  1146. assert Enum.map(response["users"], & &1["approval_pending"]) == [false, false]
  1147. log_entry = Repo.one(ModerationLog)
  1148. assert ModerationLog.get_log_entry_message(log_entry) ==
  1149. "@#{admin.nickname} approved users: @#{user_one.nickname}, @#{user_two.nickname}"
  1150. end
  1151. test "PATCH /api/pleroma/admin/users/:nickname/toggle_activation", %{admin: admin, conn: conn} do
  1152. user = insert(:user)
  1153. conn = patch(conn, "/api/pleroma/admin/users/#{user.nickname}/toggle_activation")
  1154. assert json_response(conn, 200) ==
  1155. %{
  1156. "deactivated" => !user.deactivated,
  1157. "id" => user.id,
  1158. "nickname" => user.nickname,
  1159. "roles" => %{"admin" => false, "moderator" => false},
  1160. "local" => true,
  1161. "tags" => [],
  1162. "avatar" => User.avatar_url(user) |> MediaProxy.url(),
  1163. "display_name" => HTML.strip_tags(user.name || user.nickname),
  1164. "confirmation_pending" => false,
  1165. "approval_pending" => false,
  1166. "url" => user.ap_id,
  1167. "registration_reason" => nil,
  1168. "actor_type" => "Person"
  1169. }
  1170. log_entry = Repo.one(ModerationLog)
  1171. assert ModerationLog.get_log_entry_message(log_entry) ==
  1172. "@#{admin.nickname} deactivated users: @#{user.nickname}"
  1173. end
  1174. describe "PUT disable_mfa" do
  1175. test "returns 200 and disable 2fa", %{conn: conn} do
  1176. user =
  1177. insert(:user,
  1178. multi_factor_authentication_settings: %MFA.Settings{
  1179. enabled: true,
  1180. totp: %MFA.Settings.TOTP{secret: "otp_secret", confirmed: true}
  1181. }
  1182. )
  1183. response =
  1184. conn
  1185. |> put("/api/pleroma/admin/users/disable_mfa", %{nickname: user.nickname})
  1186. |> json_response(200)
  1187. assert response == user.nickname
  1188. mfa_settings = refresh_record(user).multi_factor_authentication_settings
  1189. refute mfa_settings.enabled
  1190. refute mfa_settings.totp.confirmed
  1191. end
  1192. test "returns 404 if user not found", %{conn: conn} do
  1193. response =
  1194. conn
  1195. |> put("/api/pleroma/admin/users/disable_mfa", %{nickname: "nickname"})
  1196. |> json_response(404)
  1197. assert response == %{"error" => "Not found"}
  1198. end
  1199. end
  1200. describe "GET /api/pleroma/admin/restart" do
  1201. setup do: clear_config(:configurable_from_database, true)
  1202. test "pleroma restarts", %{conn: conn} do
  1203. capture_log(fn ->
  1204. assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{}
  1205. end) =~ "pleroma restarted"
  1206. refute Restarter.Pleroma.need_reboot?()
  1207. end
  1208. end
  1209. test "need_reboot flag", %{conn: conn} do
  1210. assert conn
  1211. |> get("/api/pleroma/admin/need_reboot")
  1212. |> json_response(200) == %{"need_reboot" => false}
  1213. Restarter.Pleroma.need_reboot()
  1214. assert conn
  1215. |> get("/api/pleroma/admin/need_reboot")
  1216. |> json_response(200) == %{"need_reboot" => true}
  1217. on_exit(fn -> Restarter.Pleroma.refresh() end)
  1218. end
  1219. describe "GET /api/pleroma/admin/users/:nickname/statuses" do
  1220. setup do
  1221. user = insert(:user)
  1222. date1 = (DateTime.to_unix(DateTime.utc_now()) + 2000) |> DateTime.from_unix!()
  1223. date2 = (DateTime.to_unix(DateTime.utc_now()) + 1000) |> DateTime.from_unix!()
  1224. date3 = (DateTime.to_unix(DateTime.utc_now()) + 3000) |> DateTime.from_unix!()
  1225. insert(:note_activity, user: user, published: date1)
  1226. insert(:note_activity, user: user, published: date2)
  1227. insert(:note_activity, user: user, published: date3)
  1228. %{user: user}
  1229. end
  1230. test "renders user's statuses", %{conn: conn, user: user} do
  1231. conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
  1232. assert json_response(conn, 200) |> length() == 3
  1233. end
  1234. test "renders user's statuses with a limit", %{conn: conn, user: user} do
  1235. conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=2")
  1236. assert json_response(conn, 200) |> length() == 2
  1237. end
  1238. test "doesn't return private statuses by default", %{conn: conn, user: user} do
  1239. {:ok, _private_status} = CommonAPI.post(user, %{status: "private", visibility: "private"})
  1240. {:ok, _public_status} = CommonAPI.post(user, %{status: "public", visibility: "public"})
  1241. conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
  1242. assert json_response(conn, 200) |> length() == 4
  1243. end
  1244. test "returns private statuses with godmode on", %{conn: conn, user: user} do
  1245. {:ok, _private_status} = CommonAPI.post(user, %{status: "private", visibility: "private"})
  1246. {:ok, _public_status} = CommonAPI.post(user, %{status: "public", visibility: "public"})
  1247. conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?godmode=true")
  1248. assert json_response(conn, 200) |> length() == 5
  1249. end
  1250. test "excludes reblogs by default", %{conn: conn, user: user} do
  1251. other_user = insert(:user)
  1252. {:ok, activity} = CommonAPI.post(user, %{status: "."})
  1253. {:ok, %Activity{}} = CommonAPI.repeat(activity.id, other_user)
  1254. conn_res = get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses")
  1255. assert json_response(conn_res, 200) |> length() == 0
  1256. conn_res =
  1257. get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses?with_reblogs=true")
  1258. assert json_response(conn_res, 200) |> length() == 1
  1259. end
  1260. end
  1261. describe "GET /api/pleroma/admin/users/:nickname/chats" do
  1262. setup do
  1263. user = insert(:user)
  1264. recipients = insert_list(3, :user)
  1265. Enum.each(recipients, fn recipient ->
  1266. CommonAPI.post_chat_message(user, recipient, "yo")
  1267. end)
  1268. %{user: user}
  1269. end
  1270. test "renders user's chats", %{conn: conn, user: user} do
  1271. conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/chats")
  1272. assert json_response(conn, 200) |> length() == 3
  1273. end
  1274. end
  1275. describe "GET /api/pleroma/admin/users/:nickname/chats unauthorized" do
  1276. setup do
  1277. user = insert(:user)
  1278. recipient = insert(:user)
  1279. CommonAPI.post_chat_message(user, recipient, "yo")
  1280. %{conn: conn} = oauth_access(["read:chats"])
  1281. %{conn: conn, user: user}
  1282. end
  1283. test "returns 403", %{conn: conn, user: user} do
  1284. conn
  1285. |> get("/api/pleroma/admin/users/#{user.nickname}/chats")
  1286. |> json_response(403)
  1287. end
  1288. end
  1289. describe "GET /api/pleroma/admin/users/:nickname/chats unauthenticated" do
  1290. setup do
  1291. user = insert(:user)
  1292. recipient = insert(:user)
  1293. CommonAPI.post_chat_message(user, recipient, "yo")
  1294. %{conn: build_conn(), user: user}
  1295. end
  1296. test "returns 403", %{conn: conn, user: user} do
  1297. conn
  1298. |> get("/api/pleroma/admin/users/#{user.nickname}/chats")
  1299. |> json_response(403)
  1300. end
  1301. end
  1302. describe "GET /api/pleroma/admin/moderation_log" do
  1303. setup do
  1304. moderator = insert(:user, is_moderator: true)
  1305. %{moderator: moderator}
  1306. end
  1307. test "returns the log", %{conn: conn, admin: admin} do
  1308. Repo.insert(%ModerationLog{
  1309. data: %{
  1310. actor: %{
  1311. "id" => admin.id,
  1312. "nickname" => admin.nickname,
  1313. "type" => "user"
  1314. },
  1315. action: "relay_follow",
  1316. target: "https://example.org/relay"
  1317. },
  1318. inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
  1319. })
  1320. Repo.insert(%ModerationLog{
  1321. data: %{
  1322. actor: %{
  1323. "id" => admin.id,
  1324. "nickname" => admin.nickname,
  1325. "type" => "user"
  1326. },
  1327. action: "relay_unfollow",
  1328. target: "https://example.org/relay"
  1329. },
  1330. inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
  1331. })
  1332. conn = get(conn, "/api/pleroma/admin/moderation_log")
  1333. response = json_response(conn, 200)
  1334. [first_entry, second_entry] = response["items"]
  1335. assert response["total"] == 2
  1336. assert first_entry["data"]["action"] == "relay_unfollow"
  1337. assert first_entry["message"] ==
  1338. "@#{admin.nickname} unfollowed relay: https://example.org/relay"
  1339. assert second_entry["data"]["action"] == "relay_follow"
  1340. assert second_entry["message"] ==
  1341. "@#{admin.nickname} followed relay: https://example.org/relay"
  1342. end
  1343. test "returns the log with pagination", %{conn: conn, admin: admin} do
  1344. Repo.insert(%ModerationLog{
  1345. data: %{
  1346. actor: %{
  1347. "id" => admin.id,
  1348. "nickname" => admin.nickname,
  1349. "type" => "user"
  1350. },
  1351. action: "relay_follow",
  1352. target: "https://example.org/relay"
  1353. },
  1354. inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
  1355. })
  1356. Repo.insert(%ModerationLog{
  1357. data: %{
  1358. actor: %{
  1359. "id" => admin.id,
  1360. "nickname" => admin.nickname,
  1361. "type" => "user"
  1362. },
  1363. action: "relay_unfollow",
  1364. target: "https://example.org/relay"
  1365. },
  1366. inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
  1367. })
  1368. conn1 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=1")
  1369. response1 = json_response(conn1, 200)
  1370. [first_entry] = response1["items"]
  1371. assert response1["total"] == 2
  1372. assert response1["items"] |> length() == 1
  1373. assert first_entry["data"]["action"] == "relay_unfollow"
  1374. assert first_entry["message"] ==
  1375. "@#{admin.nickname} unfollowed relay: https://example.org/relay"
  1376. conn2 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=2")
  1377. response2 = json_response(conn2, 200)
  1378. [second_entry] = response2["items"]
  1379. assert response2["total"] == 2
  1380. assert response2["items"] |> length() == 1
  1381. assert second_entry["data"]["action"] == "relay_follow"
  1382. assert second_entry["message"] ==
  1383. "@#{admin.nickname} followed relay: https://example.org/relay"
  1384. end
  1385. test "filters log by date", %{conn: conn, admin: admin} do
  1386. first_date = "2017-08-15T15:47:06Z"
  1387. second_date = "2017-08-20T15:47:06Z"
  1388. Repo.insert(%ModerationLog{
  1389. data: %{
  1390. actor: %{
  1391. "id" => admin.id,
  1392. "nickname" => admin.nickname,
  1393. "type" => "user"
  1394. },
  1395. action: "relay_follow",
  1396. target: "https://example.org/relay"
  1397. },
  1398. inserted_at: NaiveDateTime.from_iso8601!(first_date)
  1399. })
  1400. Repo.insert(%ModerationLog{
  1401. data: %{
  1402. actor: %{
  1403. "id" => admin.id,
  1404. "nickname" => admin.nickname,
  1405. "type" => "user"
  1406. },
  1407. action: "relay_unfollow",
  1408. target: "https://example.org/relay"
  1409. },
  1410. inserted_at: NaiveDateTime.from_iso8601!(second_date)
  1411. })
  1412. conn1 =
  1413. get(
  1414. conn,
  1415. "/api/pleroma/admin/moderation_log?start_date=#{second_date}"
  1416. )
  1417. response1 = json_response(conn1, 200)
  1418. [first_entry] = response1["items"]
  1419. assert response1["total"] == 1
  1420. assert first_entry["data"]["action"] == "relay_unfollow"
  1421. assert first_entry["message"] ==
  1422. "@#{admin.nickname} unfollowed relay: https://example.org/relay"
  1423. end
  1424. test "returns log filtered by user", %{conn: conn, admin: admin, moderator: moderator} do
  1425. Repo.insert(%ModerationLog{
  1426. data: %{
  1427. actor: %{
  1428. "id" => admin.id,
  1429. "nickname" => admin.nickname,
  1430. "type" => "user"
  1431. },
  1432. action: "relay_follow",
  1433. target: "https://example.org/relay"
  1434. }
  1435. })
  1436. Repo.insert(%ModerationLog{
  1437. data: %{
  1438. actor: %{
  1439. "id" => moderator.id,
  1440. "nickname" => moderator.nickname,
  1441. "type" => "user"
  1442. },
  1443. action: "relay_unfollow",
  1444. target: "https://example.org/relay"
  1445. }
  1446. })
  1447. conn1 = get(conn, "/api/pleroma/admin/moderation_log?user_id=#{moderator.id}")
  1448. response1 = json_response(conn1, 200)
  1449. [first_entry] = response1["items"]
  1450. assert response1["total"] == 1
  1451. assert get_in(first_entry, ["data", "actor", "id"]) == moderator.id
  1452. end
  1453. test "returns log filtered by search", %{conn: conn, moderator: moderator} do
  1454. ModerationLog.insert_log(%{
  1455. actor: moderator,
  1456. action: "relay_follow",
  1457. target: "https://example.org/relay"
  1458. })
  1459. ModerationLog.insert_log(%{
  1460. actor: moderator,
  1461. action: "relay_unfollow",
  1462. target: "https://example.org/relay"
  1463. })
  1464. conn1 = get(conn, "/api/pleroma/admin/moderation_log?search=unfo")
  1465. response1 = json_response(conn1, 200)
  1466. [first_entry] = response1["items"]
  1467. assert response1["total"] == 1
  1468. assert get_in(first_entry, ["data", "message"]) ==
  1469. "@#{moderator.nickname} unfollowed relay: https://example.org/relay"
  1470. end
  1471. end
  1472. test "gets a remote users when [:instance, :limit_to_local_content] is set to :unauthenticated",
  1473. %{conn: conn} do
  1474. clear_config(Pleroma.Config.get([:instance, :limit_to_local_content]), :unauthenticated)
  1475. user = insert(:user, %{local: false, nickname: "u@peer1.com"})
  1476. conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials")
  1477. assert json_response(conn, 200)
  1478. end
  1479. describe "GET /users/:nickname/credentials" do
  1480. test "gets the user credentials", %{conn: conn} do
  1481. user = insert(:user)
  1482. conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials")
  1483. response = assert json_response(conn, 200)
  1484. assert response["email"] == user.email
  1485. end
  1486. test "returns 403 if requested by a non-admin" do
  1487. user = insert(:user)
  1488. conn =
  1489. build_conn()
  1490. |> assign(:user, user)
  1491. |> get("/api/pleroma/admin/users/#{user.nickname}/credentials")
  1492. assert json_response(conn, :forbidden)
  1493. end
  1494. end
  1495. describe "PATCH /users/:nickname/credentials" do
  1496. setup do
  1497. user = insert(:user)
  1498. [user: user]
  1499. end
  1500. test "changes password and email", %{conn: conn, admin: admin, user: user} do
  1501. assert user.password_reset_pending == false
  1502. conn =
  1503. patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
  1504. "password" => "new_password",
  1505. "email" => "new_email@example.com",
  1506. "name" => "new_name"
  1507. })
  1508. assert json_response(conn, 200) == %{"status" => "success"}
  1509. ObanHelpers.perform_all()
  1510. updated_user = User.get_by_id(user.id)
  1511. assert updated_user.email == "new_email@example.com"
  1512. assert updated_user.name == "new_name"
  1513. assert updated_user.password_hash != user.password_hash
  1514. assert updated_user.password_reset_pending == true
  1515. [log_entry2, log_entry1] = ModerationLog |> Repo.all() |> Enum.sort()
  1516. assert ModerationLog.get_log_entry_message(log_entry1) ==
  1517. "@#{admin.nickname} updated users: @#{user.nickname}"
  1518. assert ModerationLog.get_log_entry_message(log_entry2) ==
  1519. "@#{admin.nickname} forced password reset for users: @#{user.nickname}"
  1520. end
  1521. test "returns 403 if requested by a non-admin", %{user: user} do
  1522. conn =
  1523. build_conn()
  1524. |> assign(:user, user)
  1525. |> patch("/api/pleroma/admin/users/#{user.nickname}/credentials", %{
  1526. "password" => "new_password",
  1527. "email" => "new_email@example.com",
  1528. "name" => "new_name"
  1529. })
  1530. assert json_response(conn, :forbidden)
  1531. end
  1532. test "changes actor type from permitted list", %{conn: conn, user: user} do
  1533. assert user.actor_type == "Person"
  1534. assert patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
  1535. "actor_type" => "Service"
  1536. })
  1537. |> json_response(200) == %{"status" => "success"}
  1538. updated_user = User.get_by_id(user.id)
  1539. assert updated_user.actor_type == "Service"
  1540. assert patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
  1541. "actor_type" => "Application"
  1542. })
  1543. |> json_response(400) == %{"errors" => %{"actor_type" => "is invalid"}}
  1544. end
  1545. test "update non existing user", %{conn: conn} do
  1546. assert patch(conn, "/api/pleroma/admin/users/non-existing/credentials", %{
  1547. "password" => "new_password"
  1548. })
  1549. |> json_response(404) == %{"error" => "Not found"}
  1550. end
  1551. end
  1552. describe "PATCH /users/:nickname/force_password_reset" do
  1553. test "sets password_reset_pending to true", %{conn: conn} do
  1554. user = insert(:user)
  1555. assert user.password_reset_pending == false
  1556. conn =
  1557. patch(conn, "/api/pleroma/admin/users/force_password_reset", %{nicknames: [user.nickname]})
  1558. assert empty_json_response(conn) == ""
  1559. ObanHelpers.perform_all()
  1560. assert User.get_by_id(user.id).password_reset_pending == true
  1561. end
  1562. end
  1563. describe "instances" do
  1564. test "GET /instances/:instance/statuses", %{conn: conn} do
  1565. user = insert(:user, local: false, nickname: "archaeme@archae.me")
  1566. user2 = insert(:user, local: false, nickname: "test@test.com")
  1567. insert_pair(:note_activity, user: user)
  1568. activity = insert(:note_activity, user: user2)
  1569. ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
  1570. response = json_response(ret_conn, 200)
  1571. assert length(response) == 2
  1572. ret_conn = get(conn, "/api/pleroma/admin/instances/test.com/statuses")
  1573. response = json_response(ret_conn, 200)
  1574. assert length(response) == 1
  1575. ret_conn = get(conn, "/api/pleroma/admin/instances/nonexistent.com/statuses")
  1576. response = json_response(ret_conn, 200)
  1577. assert Enum.empty?(response)
  1578. CommonAPI.repeat(activity.id, user)
  1579. ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
  1580. response = json_response(ret_conn, 200)
  1581. assert length(response) == 2
  1582. ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses?with_reblogs=true")
  1583. response = json_response(ret_conn, 200)
  1584. assert length(response) == 3
  1585. end
  1586. end
  1587. describe "PATCH /confirm_email" do
  1588. test "it confirms emails of two users", %{conn: conn, admin: admin} do
  1589. [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
  1590. assert first_user.confirmation_pending == true
  1591. assert second_user.confirmation_pending == true
  1592. ret_conn =
  1593. patch(conn, "/api/pleroma/admin/users/confirm_email", %{
  1594. nicknames: [
  1595. first_user.nickname,
  1596. second_user.nickname
  1597. ]
  1598. })
  1599. assert ret_conn.status == 200
  1600. assert first_user.confirmation_pending == true
  1601. assert second_user.confirmation_pending == true
  1602. log_entry = Repo.one(ModerationLog)
  1603. assert ModerationLog.get_log_entry_message(log_entry) ==
  1604. "@#{admin.nickname} confirmed email for users: @#{first_user.nickname}, @#{
  1605. second_user.nickname
  1606. }"
  1607. end
  1608. end
  1609. describe "PATCH /resend_confirmation_email" do
  1610. test "it resend emails for two users", %{conn: conn, admin: admin} do
  1611. [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
  1612. ret_conn =
  1613. patch(conn, "/api/pleroma/admin/users/resend_confirmation_email", %{
  1614. nicknames: [
  1615. first_user.nickname,
  1616. second_user.nickname
  1617. ]
  1618. })
  1619. assert ret_conn.status == 200
  1620. log_entry = Repo.one(ModerationLog)
  1621. assert ModerationLog.get_log_entry_message(log_entry) ==
  1622. "@#{admin.nickname} re-sent confirmation email for users: @#{first_user.nickname}, @#{
  1623. second_user.nickname
  1624. }"
  1625. ObanHelpers.perform_all()
  1626. Pleroma.Emails.UserEmail.account_confirmation_email(first_user)
  1627. # temporary hackney fix until hackney max_connections bug is fixed
  1628. # https://git.pleroma.social/pleroma/pleroma/-/issues/2101
  1629. |> Swoosh.Email.put_private(:hackney_options, ssl_options: [versions: [:"tlsv1.2"]])
  1630. |> assert_email_sent()
  1631. end
  1632. end
  1633. describe "/api/pleroma/admin/stats" do
  1634. test "status visibility count", %{conn: conn} do
  1635. admin = insert(:user, is_admin: true)
  1636. user = insert(:user)
  1637. CommonAPI.post(user, %{visibility: "public", status: "hey"})
  1638. CommonAPI.post(user, %{visibility: "unlisted", status: "hey"})
  1639. CommonAPI.post(user, %{visibility: "unlisted", status: "hey"})
  1640. response =
  1641. conn
  1642. |> assign(:user, admin)
  1643. |> get("/api/pleroma/admin/stats")
  1644. |> json_response(200)
  1645. assert %{"direct" => 0, "private" => 0, "public" => 1, "unlisted" => 2} =
  1646. response["status_visibility"]
  1647. end
  1648. test "by instance", %{conn: conn} do
  1649. admin = insert(:user, is_admin: true)
  1650. user1 = insert(:user)
  1651. instance2 = "instance2.tld"
  1652. user2 = insert(:user, %{ap_id: "https://#{instance2}/@actor"})
  1653. CommonAPI.post(user1, %{visibility: "public", status: "hey"})
  1654. CommonAPI.post(user2, %{visibility: "unlisted", status: "hey"})
  1655. CommonAPI.post(user2, %{visibility: "private", status: "hey"})
  1656. response =
  1657. conn
  1658. |> assign(:user, admin)
  1659. |> get("/api/pleroma/admin/stats", instance: instance2)
  1660. |> json_response(200)
  1661. assert %{"direct" => 0, "private" => 1, "public" => 0, "unlisted" => 1} =
  1662. response["status_visibility"]
  1663. end
  1664. end
  1665. end
  1666. # Needed for testing
  1667. defmodule Pleroma.Web.Endpoint.NotReal do
  1668. end
  1669. defmodule Pleroma.Captcha.NotReal do
  1670. end