logo

pleroma

My custom branche(s) on git.pleroma.social/pleroma/pleroma git clone https://hacktivis.me/git/pleroma.git

account_controller_test.exs (75540B)


  1. # Pleroma: A lightweight social networking server
  2. # Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
  3. # SPDX-License-Identifier: AGPL-3.0-only
  4. defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
  5. use Pleroma.Web.ConnCase
  6. alias Pleroma.Object
  7. alias Pleroma.Repo
  8. alias Pleroma.Tests.ObanHelpers
  9. alias Pleroma.User
  10. alias Pleroma.UserRelationship
  11. alias Pleroma.Web.ActivityPub.ActivityPub
  12. alias Pleroma.Web.ActivityPub.InternalFetchActor
  13. alias Pleroma.Web.CommonAPI
  14. alias Pleroma.Web.OAuth.Token
  15. alias Pleroma.Web.Plugs.SetLocalePlug
  16. import Pleroma.Factory
  17. setup do
  18. Mox.stub_with(Pleroma.UnstubbedConfigMock, Pleroma.Config)
  19. :ok
  20. end
  21. describe "account fetching" do
  22. test "works by id" do
  23. %User{id: user_id} = insert(:user)
  24. assert %{"id" => ^user_id} =
  25. build_conn()
  26. |> get("/api/v1/accounts/#{user_id}")
  27. |> json_response_and_validate_schema(200)
  28. assert %{"error" => "Can't find user"} =
  29. build_conn()
  30. |> get("/api/v1/accounts/-1")
  31. |> json_response_and_validate_schema(404)
  32. end
  33. test "relationship field" do
  34. %{conn: conn, user: user} = oauth_access(["read"])
  35. other_user = insert(:user)
  36. response =
  37. conn
  38. |> get("/api/v1/accounts/#{other_user.id}")
  39. |> json_response_and_validate_schema(200)
  40. assert response["id"] == other_user.id
  41. assert response["pleroma"]["relationship"] == %{}
  42. assert %{"pleroma" => %{"relationship" => %{"following" => false, "followed_by" => false}}} =
  43. conn
  44. |> get("/api/v1/accounts/#{other_user.id}?with_relationships=true")
  45. |> json_response_and_validate_schema(200)
  46. {:ok, _, %{id: other_id}} = User.follow(user, other_user)
  47. assert %{
  48. "id" => ^other_id,
  49. "pleroma" => %{"relationship" => %{"following" => true, "followed_by" => false}}
  50. } =
  51. conn
  52. |> get("/api/v1/accounts/#{other_id}?with_relationships=true")
  53. |> json_response_and_validate_schema(200)
  54. {:ok, _, _} = User.follow(other_user, user)
  55. assert %{
  56. "id" => ^other_id,
  57. "pleroma" => %{"relationship" => %{"following" => true, "followed_by" => true}}
  58. } =
  59. conn
  60. |> get("/api/v1/accounts/#{other_id}?with_relationships=true")
  61. |> json_response_and_validate_schema(200)
  62. end
  63. test "works by nickname" do
  64. user = insert(:user)
  65. assert %{"id" => _user_id} =
  66. build_conn()
  67. |> get("/api/v1/accounts/#{user.nickname}")
  68. |> json_response_and_validate_schema(200)
  69. end
  70. test "works by nickname for remote users" do
  71. clear_config([:instance, :limit_to_local_content], false)
  72. user = insert(:user, nickname: "user@example.com", local: false)
  73. assert %{"id" => _user_id} =
  74. build_conn()
  75. |> get("/api/v1/accounts/#{user.nickname}")
  76. |> json_response_and_validate_schema(200)
  77. end
  78. test "respects limit_to_local_content == :all for remote user nicknames" do
  79. clear_config([:instance, :limit_to_local_content], :all)
  80. user = insert(:user, nickname: "user@example.com", local: false)
  81. assert build_conn()
  82. |> get("/api/v1/accounts/#{user.nickname}")
  83. |> json_response_and_validate_schema(404)
  84. end
  85. test "respects limit_to_local_content == :unauthenticated for remote user nicknames" do
  86. clear_config([:instance, :limit_to_local_content], :unauthenticated)
  87. user = insert(:user, nickname: "user@example.com", local: false)
  88. reading_user = insert(:user)
  89. conn =
  90. build_conn()
  91. |> get("/api/v1/accounts/#{user.nickname}")
  92. assert json_response_and_validate_schema(conn, 404)
  93. conn =
  94. build_conn()
  95. |> assign(:user, reading_user)
  96. |> assign(:token, insert(:oauth_token, user: reading_user, scopes: ["read:accounts"]))
  97. |> get("/api/v1/accounts/#{user.nickname}")
  98. assert %{"id" => id} = json_response_and_validate_schema(conn, 200)
  99. assert id == user.id
  100. end
  101. test "accounts fetches correct account for nicknames beginning with numbers", %{conn: conn} do
  102. # Need to set an old-style integer ID to reproduce the problem
  103. # (these are no longer assigned to new accounts but were preserved
  104. # for existing accounts during the migration to flakeIDs)
  105. user_one = insert(:user, %{id: 1212})
  106. user_two = insert(:user, %{nickname: "#{user_one.id}garbage"})
  107. acc_one =
  108. conn
  109. |> get("/api/v1/accounts/#{user_one.id}")
  110. |> json_response_and_validate_schema(:ok)
  111. acc_two =
  112. conn
  113. |> get("/api/v1/accounts/#{user_two.nickname}")
  114. |> json_response_and_validate_schema(:ok)
  115. acc_three =
  116. conn
  117. |> get("/api/v1/accounts/#{user_two.id}")
  118. |> json_response_and_validate_schema(:ok)
  119. refute acc_one == acc_two
  120. assert acc_two == acc_three
  121. end
  122. test "returns 404 when user is invisible", %{conn: conn} do
  123. user = insert(:user, %{invisible: true})
  124. assert %{"error" => "Can't find user"} =
  125. conn
  126. |> get("/api/v1/accounts/#{user.nickname}")
  127. |> json_response_and_validate_schema(404)
  128. end
  129. test "returns 404 for internal.fetch actor", %{conn: conn} do
  130. %User{nickname: "internal.fetch"} = InternalFetchActor.get_actor()
  131. assert %{"error" => "Can't find user"} =
  132. conn
  133. |> get("/api/v1/accounts/internal.fetch")
  134. |> json_response_and_validate_schema(404)
  135. end
  136. test "returns 404 for deactivated user", %{conn: conn} do
  137. user = insert(:user, is_active: false)
  138. assert %{"error" => "Can't find user"} =
  139. conn
  140. |> get("/api/v1/accounts/#{user.id}")
  141. |> json_response_and_validate_schema(:not_found)
  142. end
  143. end
  144. defp local_and_remote_users do
  145. local = insert(:user)
  146. remote = insert(:user, local: false)
  147. {:ok, local: local, remote: remote}
  148. end
  149. describe "user fetching with restrict unauthenticated profiles for local and remote" do
  150. setup do: local_and_remote_users()
  151. setup do: clear_config([:restrict_unauthenticated, :profiles, :local], true)
  152. setup do: clear_config([:restrict_unauthenticated, :profiles, :remote], true)
  153. test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
  154. assert %{"error" => "This API requires an authenticated user"} ==
  155. conn
  156. |> get("/api/v1/accounts/#{local.id}")
  157. |> json_response_and_validate_schema(:unauthorized)
  158. assert %{"error" => "This API requires an authenticated user"} ==
  159. conn
  160. |> get("/api/v1/accounts/#{remote.id}")
  161. |> json_response_and_validate_schema(:unauthorized)
  162. end
  163. test "if user is authenticated", %{local: local, remote: remote} do
  164. %{conn: conn} = oauth_access(["read"])
  165. res_conn = get(conn, "/api/v1/accounts/#{local.id}")
  166. assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200)
  167. res_conn = get(conn, "/api/v1/accounts/#{remote.id}")
  168. assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200)
  169. end
  170. end
  171. describe "user fetching with restrict unauthenticated profiles for local" do
  172. setup do: local_and_remote_users()
  173. setup do: clear_config([:restrict_unauthenticated, :profiles, :local], true)
  174. test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
  175. res_conn = get(conn, "/api/v1/accounts/#{local.id}")
  176. assert json_response_and_validate_schema(res_conn, :unauthorized) == %{
  177. "error" => "This API requires an authenticated user"
  178. }
  179. res_conn = get(conn, "/api/v1/accounts/#{remote.id}")
  180. assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200)
  181. end
  182. test "if user is authenticated", %{local: local, remote: remote} do
  183. %{conn: conn} = oauth_access(["read"])
  184. res_conn = get(conn, "/api/v1/accounts/#{local.id}")
  185. assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200)
  186. res_conn = get(conn, "/api/v1/accounts/#{remote.id}")
  187. assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200)
  188. end
  189. end
  190. describe "user fetching with restrict unauthenticated profiles for remote" do
  191. setup do: local_and_remote_users()
  192. setup do: clear_config([:restrict_unauthenticated, :profiles, :remote], true)
  193. test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
  194. res_conn = get(conn, "/api/v1/accounts/#{local.id}")
  195. assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200)
  196. res_conn = get(conn, "/api/v1/accounts/#{remote.id}")
  197. assert json_response_and_validate_schema(res_conn, :unauthorized) == %{
  198. "error" => "This API requires an authenticated user"
  199. }
  200. end
  201. test "if user is authenticated", %{local: local, remote: remote} do
  202. %{conn: conn} = oauth_access(["read"])
  203. res_conn = get(conn, "/api/v1/accounts/#{local.id}")
  204. assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200)
  205. res_conn = get(conn, "/api/v1/accounts/#{remote.id}")
  206. assert %{"id" => _} = json_response_and_validate_schema(res_conn, 200)
  207. end
  208. end
  209. describe "user timelines" do
  210. setup do: oauth_access(["read:statuses"])
  211. test "works with announces that are just addressed to public", %{conn: conn} do
  212. user = insert(:user, ap_id: "https://honktest/u/test", local: false)
  213. other_user = insert(:user)
  214. {:ok, post} = CommonAPI.post(other_user, %{status: "bonkeronk"})
  215. {:ok, announce, _} =
  216. %{
  217. "@context" => "https://www.w3.org/ns/activitystreams",
  218. "actor" => "https://honktest/u/test",
  219. "id" => "https://honktest/u/test/bonk/1793M7B9MQ48847vdx",
  220. "object" => post.data["object"],
  221. "published" => "2019-06-25T19:33:58Z",
  222. "to" => ["https://www.w3.org/ns/activitystreams#Public"],
  223. "type" => "Announce"
  224. }
  225. |> ActivityPub.persist(local: false)
  226. assert resp =
  227. conn
  228. |> get("/api/v1/accounts/#{user.id}/statuses")
  229. |> json_response_and_validate_schema(200)
  230. assert [%{"id" => id}] = resp
  231. assert id == announce.id
  232. end
  233. test "deactivated user", %{conn: conn} do
  234. user = insert(:user, is_active: false)
  235. assert %{"error" => "Can't find user"} ==
  236. conn
  237. |> get("/api/v1/accounts/#{user.id}/statuses")
  238. |> json_response_and_validate_schema(:not_found)
  239. end
  240. test "returns 404 when user is invisible", %{conn: conn} do
  241. user = insert(:user, %{invisible: true})
  242. assert %{"error" => "Can't find user"} =
  243. conn
  244. |> get("/api/v1/accounts/#{user.id}")
  245. |> json_response_and_validate_schema(404)
  246. end
  247. test "respects blocks", %{user: user_one, conn: conn} do
  248. user_two = insert(:user)
  249. user_three = insert(:user)
  250. User.block(user_one, user_two)
  251. {:ok, activity} = CommonAPI.post(user_two, %{status: "User one sux0rz"})
  252. {:ok, repeat} = CommonAPI.repeat(activity.id, user_three)
  253. assert resp =
  254. conn
  255. |> get("/api/v1/accounts/#{user_two.id}/statuses")
  256. |> json_response_and_validate_schema(200)
  257. assert [%{"id" => id}] = resp
  258. assert id == activity.id
  259. # Even a blocked user will deliver the full user timeline, there would be
  260. # no point in looking at a blocked users timeline otherwise
  261. assert resp =
  262. conn
  263. |> get("/api/v1/accounts/#{user_two.id}/statuses")
  264. |> json_response_and_validate_schema(200)
  265. assert [%{"id" => id}] = resp
  266. assert id == activity.id
  267. # Third user's timeline includes the repeat when viewed by unauthenticated user
  268. resp =
  269. build_conn()
  270. |> get("/api/v1/accounts/#{user_three.id}/statuses")
  271. |> json_response_and_validate_schema(200)
  272. assert [%{"id" => id}] = resp
  273. assert id == repeat.id
  274. # When viewing a third user's timeline, the blocked users' statuses will NOT be shown
  275. resp = get(conn, "/api/v1/accounts/#{user_three.id}/statuses")
  276. assert [] == json_response_and_validate_schema(resp, 200)
  277. end
  278. test "gets users statuses", %{conn: conn} do
  279. user_one = insert(:user)
  280. user_two = insert(:user)
  281. user_three = insert(:user)
  282. {:ok, _user_three, _user_one} = User.follow(user_three, user_one)
  283. {:ok, activity} = CommonAPI.post(user_one, %{status: "HI!!!"})
  284. {:ok, direct_activity} =
  285. CommonAPI.post(user_one, %{
  286. status: "Hi, @#{user_two.nickname}.",
  287. visibility: "direct"
  288. })
  289. {:ok, private_activity} =
  290. CommonAPI.post(user_one, %{status: "private", visibility: "private"})
  291. # TODO!!!
  292. resp =
  293. conn
  294. |> get("/api/v1/accounts/#{user_one.id}/statuses")
  295. |> json_response_and_validate_schema(200)
  296. assert [%{"id" => id}] = resp
  297. assert id == to_string(activity.id)
  298. resp =
  299. conn
  300. |> assign(:user, user_two)
  301. |> assign(:token, insert(:oauth_token, user: user_two, scopes: ["read:statuses"]))
  302. |> get("/api/v1/accounts/#{user_one.id}/statuses")
  303. |> json_response_and_validate_schema(200)
  304. assert [%{"id" => id_one}, %{"id" => id_two}] = resp
  305. assert id_one == to_string(direct_activity.id)
  306. assert id_two == to_string(activity.id)
  307. resp =
  308. conn
  309. |> assign(:user, user_three)
  310. |> assign(:token, insert(:oauth_token, user: user_three, scopes: ["read:statuses"]))
  311. |> get("/api/v1/accounts/#{user_one.id}/statuses")
  312. |> json_response_and_validate_schema(200)
  313. assert [%{"id" => id_one}, %{"id" => id_two}] = resp
  314. assert id_one == to_string(private_activity.id)
  315. assert id_two == to_string(activity.id)
  316. end
  317. test "gets local-only statuses for authenticated users", %{user: _user, conn: conn} do
  318. user_one = insert(:user)
  319. {:ok, activity} = CommonAPI.post(user_one, %{status: "HI!!!", visibility: "local"})
  320. resp =
  321. conn
  322. |> get("/api/v1/accounts/#{user_one.id}/statuses")
  323. |> json_response_and_validate_schema(200)
  324. assert [%{"id" => id}] = resp
  325. assert id == to_string(activity.id)
  326. end
  327. test "gets an users media, excludes reblogs", %{conn: conn} do
  328. note = insert(:note_activity)
  329. user = User.get_cached_by_ap_id(note.data["actor"])
  330. other_user = insert(:user)
  331. file = %Plug.Upload{
  332. content_type: "image/jpeg",
  333. path: Path.absname("test/fixtures/image.jpg"),
  334. filename: "an_image.jpg"
  335. }
  336. {:ok, %{id: media_id}} = ActivityPub.upload(file, actor: user.ap_id)
  337. {:ok, %{id: image_post_id}} = CommonAPI.post(user, %{status: "cofe", media_ids: [media_id]})
  338. {:ok, %{id: media_id}} = ActivityPub.upload(file, actor: other_user.ap_id)
  339. {:ok, %{id: other_image_post_id}} =
  340. CommonAPI.post(other_user, %{status: "cofe2", media_ids: [media_id]})
  341. {:ok, _announce} = CommonAPI.repeat(other_image_post_id, user)
  342. conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?only_media=true")
  343. assert [%{"id" => ^image_post_id}] = json_response_and_validate_schema(conn, 200)
  344. conn = get(build_conn(), "/api/v1/accounts/#{user.id}/statuses?only_media=1")
  345. assert [%{"id" => ^image_post_id}] = json_response_and_validate_schema(conn, 200)
  346. end
  347. test "gets a user's statuses without reblogs", %{user: user, conn: conn} do
  348. {:ok, %{id: post_id}} = CommonAPI.post(user, %{status: "HI!!!"})
  349. {:ok, _} = CommonAPI.repeat(post_id, user)
  350. conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?exclude_reblogs=true")
  351. assert [%{"id" => ^post_id}] = json_response_and_validate_schema(conn, 200)
  352. conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?exclude_reblogs=1")
  353. assert [%{"id" => ^post_id}] = json_response_and_validate_schema(conn, 200)
  354. end
  355. test "filters user's statuses by a hashtag", %{user: user, conn: conn} do
  356. {:ok, %{id: post_id}} = CommonAPI.post(user, %{status: "#hashtag"})
  357. {:ok, _post} = CommonAPI.post(user, %{status: "hashtag"})
  358. conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?tagged=hashtag")
  359. assert [%{"id" => ^post_id}] = json_response_and_validate_schema(conn, 200)
  360. end
  361. test "the user views their own timelines and excludes direct messages", %{
  362. user: user,
  363. conn: conn
  364. } do
  365. {:ok, %{id: public_activity_id}} =
  366. CommonAPI.post(user, %{status: ".", visibility: "public"})
  367. {:ok, _direct_activity} = CommonAPI.post(user, %{status: ".", visibility: "direct"})
  368. conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?exclude_visibilities[]=direct")
  369. assert [%{"id" => ^public_activity_id}] = json_response_and_validate_schema(conn, 200)
  370. end
  371. test "muted reactions", %{user: user, conn: conn} do
  372. user2 = insert(:user)
  373. User.mute(user, user2)
  374. {:ok, activity} = CommonAPI.post(user, %{status: "."})
  375. {:ok, _} = CommonAPI.react_with_emoji(activity.id, user2, "🎅")
  376. result =
  377. conn
  378. |> get("/api/v1/accounts/#{user.id}/statuses")
  379. |> json_response_and_validate_schema(200)
  380. assert [
  381. %{
  382. "pleroma" => %{
  383. "emoji_reactions" => []
  384. }
  385. }
  386. ] = result
  387. result =
  388. conn
  389. |> get("/api/v1/accounts/#{user.id}/statuses?with_muted=true")
  390. |> json_response_and_validate_schema(200)
  391. assert [
  392. %{
  393. "pleroma" => %{
  394. "emoji_reactions" => [%{"count" => 1, "me" => false, "name" => "🎅"}]
  395. }
  396. }
  397. ] = result
  398. end
  399. test "paginates a user's statuses", %{user: user, conn: conn} do
  400. {:ok, post_1} = CommonAPI.post(user, %{status: "first post"})
  401. {:ok, post_2} = CommonAPI.post(user, %{status: "second post"})
  402. response_1 = get(conn, "/api/v1/accounts/#{user.id}/statuses?limit=1")
  403. assert [res] = json_response_and_validate_schema(response_1, 200)
  404. assert res["id"] == post_2.id
  405. response_2 = get(conn, "/api/v1/accounts/#{user.id}/statuses?limit=1&max_id=#{res["id"]}")
  406. assert [res] = json_response_and_validate_schema(response_2, 200)
  407. assert res["id"] == post_1.id
  408. refute response_1 == response_2
  409. end
  410. end
  411. defp local_and_remote_activities(%{local: local, remote: remote}) do
  412. insert(:note_activity, user: local)
  413. insert(:note_activity, user: remote, local: false)
  414. :ok
  415. end
  416. describe "statuses with restrict unauthenticated profiles for local and remote" do
  417. setup do: local_and_remote_users()
  418. setup :local_and_remote_activities
  419. setup do: clear_config([:restrict_unauthenticated, :profiles, :local], true)
  420. setup do: clear_config([:restrict_unauthenticated, :profiles, :remote], true)
  421. test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
  422. assert %{"error" => "This API requires an authenticated user"} ==
  423. conn
  424. |> get("/api/v1/accounts/#{local.id}/statuses")
  425. |> json_response_and_validate_schema(:unauthorized)
  426. assert %{"error" => "This API requires an authenticated user"} ==
  427. conn
  428. |> get("/api/v1/accounts/#{remote.id}/statuses")
  429. |> json_response_and_validate_schema(:unauthorized)
  430. end
  431. test "if user is authenticated", %{local: local, remote: remote} do
  432. %{conn: conn} = oauth_access(["read"])
  433. res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses")
  434. assert length(json_response_and_validate_schema(res_conn, 200)) == 1
  435. res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
  436. assert length(json_response_and_validate_schema(res_conn, 200)) == 1
  437. end
  438. end
  439. describe "statuses with restrict unauthenticated profiles for local" do
  440. setup do: local_and_remote_users()
  441. setup :local_and_remote_activities
  442. setup do: clear_config([:restrict_unauthenticated, :profiles, :local], true)
  443. test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
  444. assert %{"error" => "This API requires an authenticated user"} ==
  445. conn
  446. |> get("/api/v1/accounts/#{local.id}/statuses")
  447. |> json_response_and_validate_schema(:unauthorized)
  448. res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
  449. assert length(json_response_and_validate_schema(res_conn, 200)) == 1
  450. end
  451. test "if user is authenticated", %{local: local, remote: remote} do
  452. %{conn: conn} = oauth_access(["read"])
  453. res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses")
  454. assert length(json_response_and_validate_schema(res_conn, 200)) == 1
  455. res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
  456. assert length(json_response_and_validate_schema(res_conn, 200)) == 1
  457. end
  458. end
  459. describe "statuses with restrict unauthenticated profiles for remote" do
  460. setup do: local_and_remote_users()
  461. setup :local_and_remote_activities
  462. setup do: clear_config([:restrict_unauthenticated, :profiles, :remote], true)
  463. test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
  464. res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses")
  465. assert length(json_response_and_validate_schema(res_conn, 200)) == 1
  466. assert %{"error" => "This API requires an authenticated user"} ==
  467. conn
  468. |> get("/api/v1/accounts/#{remote.id}/statuses")
  469. |> json_response_and_validate_schema(:unauthorized)
  470. end
  471. test "if user is authenticated", %{local: local, remote: remote} do
  472. %{conn: conn} = oauth_access(["read"])
  473. res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses")
  474. assert length(json_response_and_validate_schema(res_conn, 200)) == 1
  475. res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
  476. assert length(json_response_and_validate_schema(res_conn, 200)) == 1
  477. end
  478. end
  479. describe "followers" do
  480. setup do: oauth_access(["read:accounts"])
  481. test "getting followers", %{user: user, conn: conn} do
  482. other_user = insert(:user)
  483. {:ok, %{id: user_id}, other_user} = User.follow(user, other_user)
  484. conn = get(conn, "/api/v1/accounts/#{other_user.id}/followers")
  485. assert [%{"id" => ^user_id}] = json_response_and_validate_schema(conn, 200)
  486. end
  487. test "following with relationship", %{conn: conn, user: user} do
  488. other_user = insert(:user)
  489. {:ok, %{id: id}, _} = User.follow(other_user, user)
  490. assert [
  491. %{
  492. "id" => ^id,
  493. "pleroma" => %{
  494. "relationship" => %{
  495. "id" => ^id,
  496. "following" => false,
  497. "followed_by" => true
  498. }
  499. }
  500. }
  501. ] =
  502. conn
  503. |> get("/api/v1/accounts/#{user.id}/followers?with_relationships=true")
  504. |> json_response_and_validate_schema(200)
  505. {:ok, _, _} = User.follow(user, other_user)
  506. assert [
  507. %{
  508. "id" => ^id,
  509. "pleroma" => %{
  510. "relationship" => %{
  511. "id" => ^id,
  512. "following" => true,
  513. "followed_by" => true
  514. }
  515. }
  516. }
  517. ] =
  518. conn
  519. |> get("/api/v1/accounts/#{user.id}/followers?with_relationships=true")
  520. |> json_response_and_validate_schema(200)
  521. end
  522. test "getting followers, hide_followers", %{user: user, conn: conn} do
  523. other_user = insert(:user, hide_followers: true)
  524. {:ok, _user, _other_user} = User.follow(user, other_user)
  525. conn = get(conn, "/api/v1/accounts/#{other_user.id}/followers")
  526. assert [] == json_response_and_validate_schema(conn, 200)
  527. end
  528. test "getting followers, hide_followers, same user requesting" do
  529. user = insert(:user)
  530. other_user = insert(:user, hide_followers: true)
  531. {:ok, _user, _other_user} = User.follow(user, other_user)
  532. conn =
  533. build_conn()
  534. |> assign(:user, other_user)
  535. |> assign(:token, insert(:oauth_token, user: other_user, scopes: ["read:accounts"]))
  536. |> get("/api/v1/accounts/#{other_user.id}/followers")
  537. refute [] == json_response_and_validate_schema(conn, 200)
  538. end
  539. test "getting followers, pagination", %{user: user, conn: conn} do
  540. {:ok, %User{id: follower1_id}, _user} = :user |> insert() |> User.follow(user)
  541. {:ok, %User{id: follower2_id}, _user} = :user |> insert() |> User.follow(user)
  542. {:ok, %User{id: follower3_id}, _user} = :user |> insert() |> User.follow(user)
  543. assert [%{"id" => ^follower3_id}, %{"id" => ^follower2_id}] =
  544. conn
  545. |> get("/api/v1/accounts/#{user.id}/followers?since_id=#{follower1_id}")
  546. |> json_response_and_validate_schema(200)
  547. assert [%{"id" => ^follower2_id}, %{"id" => ^follower1_id}] =
  548. conn
  549. |> get("/api/v1/accounts/#{user.id}/followers?max_id=#{follower3_id}")
  550. |> json_response_and_validate_schema(200)
  551. assert [%{"id" => ^follower2_id}, %{"id" => ^follower1_id}] =
  552. conn
  553. |> get(
  554. "/api/v1/accounts/#{user.id}/followers?id=#{user.id}&limit=20&max_id=#{follower3_id}"
  555. )
  556. |> json_response_and_validate_schema(200)
  557. res_conn = get(conn, "/api/v1/accounts/#{user.id}/followers?limit=1&max_id=#{follower3_id}")
  558. assert [%{"id" => ^follower2_id}] = json_response_and_validate_schema(res_conn, 200)
  559. assert [link_header] = get_resp_header(res_conn, "link")
  560. assert link_header =~ ~r/min_id=#{follower2_id}/
  561. assert link_header =~ ~r/max_id=#{follower2_id}/
  562. end
  563. end
  564. describe "following" do
  565. setup do: oauth_access(["read:accounts"])
  566. test "getting following", %{user: user, conn: conn} do
  567. other_user = insert(:user)
  568. {:ok, user, other_user} = User.follow(user, other_user)
  569. conn = get(conn, "/api/v1/accounts/#{user.id}/following")
  570. assert [%{"id" => id}] = json_response_and_validate_schema(conn, 200)
  571. assert id == to_string(other_user.id)
  572. end
  573. test "following with relationship", %{conn: conn, user: user} do
  574. other_user = insert(:user)
  575. {:ok, user, other_user} = User.follow(user, other_user)
  576. conn = get(conn, "/api/v1/accounts/#{user.id}/following?with_relationships=true")
  577. id = other_user.id
  578. assert [
  579. %{
  580. "id" => ^id,
  581. "pleroma" => %{
  582. "relationship" => %{"id" => ^id, "following" => true, "followed_by" => false}
  583. }
  584. }
  585. ] = json_response_and_validate_schema(conn, 200)
  586. end
  587. test "getting following, hide_follows, other user requesting" do
  588. user = insert(:user, hide_follows: true)
  589. other_user = insert(:user)
  590. {:ok, user, other_user} = User.follow(user, other_user)
  591. conn =
  592. build_conn()
  593. |> assign(:user, other_user)
  594. |> assign(:token, insert(:oauth_token, user: other_user, scopes: ["read:accounts"]))
  595. |> get("/api/v1/accounts/#{user.id}/following")
  596. assert [] == json_response_and_validate_schema(conn, 200)
  597. end
  598. test "getting following, hide_follows, same user requesting" do
  599. user = insert(:user, hide_follows: true)
  600. other_user = insert(:user)
  601. {:ok, user, _other_user} = User.follow(user, other_user)
  602. conn =
  603. build_conn()
  604. |> assign(:user, user)
  605. |> assign(:token, insert(:oauth_token, user: user, scopes: ["read:accounts"]))
  606. |> get("/api/v1/accounts/#{user.id}/following")
  607. refute [] == json_response_and_validate_schema(conn, 200)
  608. end
  609. test "getting following, pagination", %{user: user, conn: conn} do
  610. following1 = insert(:user)
  611. following2 = insert(:user)
  612. following3 = insert(:user)
  613. {:ok, _, _} = User.follow(user, following1)
  614. {:ok, _, _} = User.follow(user, following2)
  615. {:ok, _, _} = User.follow(user, following3)
  616. res_conn = get(conn, "/api/v1/accounts/#{user.id}/following?since_id=#{following1.id}")
  617. assert [%{"id" => id3}, %{"id" => id2}] = json_response_and_validate_schema(res_conn, 200)
  618. assert id3 == following3.id
  619. assert id2 == following2.id
  620. res_conn = get(conn, "/api/v1/accounts/#{user.id}/following?max_id=#{following3.id}")
  621. assert [%{"id" => id2}, %{"id" => id1}] = json_response_and_validate_schema(res_conn, 200)
  622. assert id2 == following2.id
  623. assert id1 == following1.id
  624. res_conn =
  625. get(
  626. conn,
  627. "/api/v1/accounts/#{user.id}/following?id=#{user.id}&limit=20&max_id=#{following3.id}"
  628. )
  629. assert [%{"id" => id2}, %{"id" => id1}] = json_response_and_validate_schema(res_conn, 200)
  630. assert id2 == following2.id
  631. assert id1 == following1.id
  632. res_conn =
  633. get(conn, "/api/v1/accounts/#{user.id}/following?limit=1&max_id=#{following3.id}")
  634. assert [%{"id" => id2}] = json_response_and_validate_schema(res_conn, 200)
  635. assert id2 == following2.id
  636. assert [link_header] = get_resp_header(res_conn, "link")
  637. assert link_header =~ ~r/min_id=#{following2.id}/
  638. assert link_header =~ ~r/max_id=#{following2.id}/
  639. end
  640. end
  641. describe "follow/unfollow" do
  642. setup do: oauth_access(["follow"])
  643. test "following / unfollowing a user", %{conn: conn} do
  644. %{id: other_user_id, nickname: other_user_nickname} = insert(:user)
  645. assert %{"id" => _id, "following" => true} =
  646. conn
  647. |> post("/api/v1/accounts/#{other_user_id}/follow")
  648. |> json_response_and_validate_schema(200)
  649. assert %{"id" => _id, "following" => false} =
  650. conn
  651. |> post("/api/v1/accounts/#{other_user_id}/unfollow")
  652. |> json_response_and_validate_schema(200)
  653. assert %{"id" => ^other_user_id} =
  654. conn
  655. |> put_req_header("content-type", "application/json")
  656. |> post("/api/v1/follows", %{"uri" => other_user_nickname})
  657. |> json_response_and_validate_schema(200)
  658. end
  659. test "cancelling follow request", %{conn: conn} do
  660. %{id: other_user_id} = insert(:user, %{is_locked: true})
  661. assert %{"id" => ^other_user_id, "following" => false, "requested" => true} =
  662. conn
  663. |> post("/api/v1/accounts/#{other_user_id}/follow")
  664. |> json_response_and_validate_schema(:ok)
  665. assert %{"id" => ^other_user_id, "following" => false, "requested" => false} =
  666. conn
  667. |> post("/api/v1/accounts/#{other_user_id}/unfollow")
  668. |> json_response_and_validate_schema(:ok)
  669. end
  670. test "following without reblogs" do
  671. %{conn: conn} = oauth_access(["follow", "read:statuses"])
  672. followed = insert(:user)
  673. other_user = insert(:user)
  674. ret_conn =
  675. conn
  676. |> put_req_header("content-type", "application/json")
  677. |> post("/api/v1/accounts/#{followed.id}/follow", %{reblogs: false})
  678. assert %{"showing_reblogs" => false} = json_response_and_validate_schema(ret_conn, 200)
  679. {:ok, activity} = CommonAPI.post(other_user, %{status: "hey"})
  680. {:ok, %{id: reblog_id}} = CommonAPI.repeat(activity.id, followed)
  681. assert [] ==
  682. conn
  683. |> get("/api/v1/timelines/home")
  684. |> json_response_and_validate_schema(200)
  685. assert %{"showing_reblogs" => true} =
  686. conn
  687. |> put_req_header("content-type", "application/json")
  688. |> post("/api/v1/accounts/#{followed.id}/follow", %{reblogs: true})
  689. |> json_response_and_validate_schema(200)
  690. assert %{"showing_reblogs" => true} =
  691. conn
  692. |> put_req_header("content-type", "application/json")
  693. |> post("/api/v1/accounts/#{followed.id}/follow", %{reblogs: "1"})
  694. |> json_response_and_validate_schema(200)
  695. assert [%{"id" => ^reblog_id}] =
  696. conn
  697. |> get("/api/v1/timelines/home")
  698. |> json_response_and_validate_schema(200)
  699. end
  700. test "following with reblogs" do
  701. %{conn: conn} = oauth_access(["follow", "read:statuses"])
  702. followed = insert(:user)
  703. other_user = insert(:user)
  704. ret_conn = post(conn, "/api/v1/accounts/#{followed.id}/follow")
  705. assert %{"showing_reblogs" => true} = json_response_and_validate_schema(ret_conn, 200)
  706. {:ok, activity} = CommonAPI.post(other_user, %{status: "hey"})
  707. {:ok, %{id: reblog_id}} = CommonAPI.repeat(activity.id, followed)
  708. assert [%{"id" => ^reblog_id}] =
  709. conn
  710. |> get("/api/v1/timelines/home")
  711. |> json_response_and_validate_schema(200)
  712. assert %{"showing_reblogs" => false} =
  713. conn
  714. |> put_req_header("content-type", "application/json")
  715. |> post("/api/v1/accounts/#{followed.id}/follow", %{reblogs: false})
  716. |> json_response_and_validate_schema(200)
  717. assert %{"showing_reblogs" => false} =
  718. conn
  719. |> put_req_header("content-type", "application/json")
  720. |> post("/api/v1/accounts/#{followed.id}/follow", %{reblogs: "0"})
  721. |> json_response_and_validate_schema(200)
  722. assert [] ==
  723. conn
  724. |> get("/api/v1/timelines/home")
  725. |> json_response_and_validate_schema(200)
  726. end
  727. test "following with subscription and unsubscribing" do
  728. %{conn: conn} = oauth_access(["follow"])
  729. followed = insert(:user)
  730. assert %{"subscribing" => true} =
  731. conn
  732. |> put_req_header("content-type", "application/json")
  733. |> post("/api/v1/accounts/#{followed.id}/follow", %{notify: true})
  734. |> json_response_and_validate_schema(200)
  735. assert %{"subscribing" => true} =
  736. conn
  737. |> put_req_header("content-type", "application/json")
  738. |> post("/api/v1/accounts/#{followed.id}/follow", %{notify: "1"})
  739. |> json_response_and_validate_schema(200)
  740. assert %{"subscribing" => false} =
  741. conn
  742. |> put_req_header("content-type", "application/json")
  743. |> post("/api/v1/accounts/#{followed.id}/follow", %{notify: false})
  744. |> json_response_and_validate_schema(200)
  745. end
  746. test "following / unfollowing errors", %{user: user, conn: conn} do
  747. # self follow
  748. conn_res = post(conn, "/api/v1/accounts/#{user.id}/follow")
  749. assert %{"error" => "Can not follow yourself"} =
  750. json_response_and_validate_schema(conn_res, 400)
  751. # self unfollow
  752. user = User.get_cached_by_id(user.id)
  753. conn_res = post(conn, "/api/v1/accounts/#{user.id}/unfollow")
  754. assert %{"error" => "Can not unfollow yourself"} =
  755. json_response_and_validate_schema(conn_res, 400)
  756. # self follow via uri
  757. user = User.get_cached_by_id(user.id)
  758. assert %{"error" => "Can not follow yourself"} =
  759. conn
  760. |> put_req_header("content-type", "multipart/form-data")
  761. |> post("/api/v1/follows", %{"uri" => user.nickname})
  762. |> json_response_and_validate_schema(400)
  763. # follow non existing user
  764. conn_res = post(conn, "/api/v1/accounts/doesntexist/follow")
  765. assert %{"error" => "Record not found"} = json_response_and_validate_schema(conn_res, 404)
  766. # follow non existing user via uri
  767. conn_res =
  768. conn
  769. |> put_req_header("content-type", "multipart/form-data")
  770. |> post("/api/v1/follows", %{"uri" => "doesntexist"})
  771. assert %{"error" => "Record not found"} = json_response_and_validate_schema(conn_res, 404)
  772. # unfollow non existing user
  773. conn_res = post(conn, "/api/v1/accounts/doesntexist/unfollow")
  774. assert %{"error" => "Record not found"} = json_response_and_validate_schema(conn_res, 404)
  775. end
  776. end
  777. describe "mute/unmute" do
  778. setup do: oauth_access(["write:mutes"])
  779. test "with notifications", %{conn: conn} do
  780. other_user = insert(:user)
  781. assert %{"id" => _id, "muting" => true, "muting_notifications" => true} =
  782. conn
  783. |> post("/api/v1/accounts/#{other_user.id}/mute")
  784. |> json_response_and_validate_schema(200)
  785. conn = post(conn, "/api/v1/accounts/#{other_user.id}/unmute")
  786. assert %{"id" => _id, "muting" => false, "muting_notifications" => false} =
  787. json_response_and_validate_schema(conn, 200)
  788. end
  789. test "without notifications", %{conn: conn} do
  790. other_user = insert(:user)
  791. ret_conn =
  792. conn
  793. |> put_req_header("content-type", "multipart/form-data")
  794. |> post("/api/v1/accounts/#{other_user.id}/mute", %{"notifications" => "false"})
  795. assert %{"id" => _id, "muting" => true, "muting_notifications" => false} =
  796. json_response_and_validate_schema(ret_conn, 200)
  797. conn = post(conn, "/api/v1/accounts/#{other_user.id}/unmute")
  798. assert %{"id" => _id, "muting" => false, "muting_notifications" => false} =
  799. json_response_and_validate_schema(conn, 200)
  800. end
  801. test "expiring", %{conn: conn, user: user} do
  802. other_user = insert(:user)
  803. conn =
  804. conn
  805. |> put_req_header("content-type", "multipart/form-data")
  806. |> post("/api/v1/accounts/#{other_user.id}/mute", %{"duration" => "86400"})
  807. assert %{"id" => _id, "muting" => true} = json_response_and_validate_schema(conn, 200)
  808. mute_expires_at = UserRelationship.get_mute_expire_date(user, other_user)
  809. assert DateTime.diff(
  810. mute_expires_at,
  811. DateTime.utc_now() |> DateTime.add(24 * 60 * 60)
  812. ) in -3..3
  813. end
  814. test "falls back to expires_in", %{conn: conn, user: user} do
  815. other_user = insert(:user)
  816. conn
  817. |> put_req_header("content-type", "multipart/form-data")
  818. |> post("/api/v1/accounts/#{other_user.id}/mute", %{"expires_in" => "86400"})
  819. |> json_response_and_validate_schema(200)
  820. mute_expires_at = UserRelationship.get_mute_expire_date(user, other_user)
  821. assert DateTime.diff(
  822. mute_expires_at,
  823. DateTime.utc_now() |> DateTime.add(24 * 60 * 60)
  824. ) in -3..3
  825. end
  826. end
  827. describe "pinned statuses" do
  828. setup do
  829. user = insert(:user)
  830. {:ok, activity} = CommonAPI.post(user, %{status: "HI!!!"})
  831. %{conn: conn} = oauth_access(["read:statuses"], user: user)
  832. [conn: conn, user: user, activity: activity]
  833. end
  834. test "returns pinned statuses", %{conn: conn, user: user, activity: %{id: activity_id}} do
  835. {:ok, _} = CommonAPI.pin(activity_id, user)
  836. assert [%{"id" => ^activity_id, "pinned" => true}] =
  837. conn
  838. |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
  839. |> json_response_and_validate_schema(200)
  840. end
  841. end
  842. test "view pinned private statuses" do
  843. user = insert(:user)
  844. reader = insert(:user)
  845. # Create a private status and pin it
  846. {:ok, %{id: activity_id} = activity} =
  847. CommonAPI.post(user, %{status: "psst", visibility: "private"})
  848. %{data: %{"id" => object_ap_id}} = Object.normalize(activity)
  849. {:ok, _} = User.add_pinned_object_id(user, object_ap_id)
  850. %{conn: conn} = oauth_access(["read:statuses"], user: reader)
  851. # A non-follower can't see the pinned status
  852. assert [] ==
  853. conn
  854. |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
  855. |> json_response_and_validate_schema(200)
  856. # Follow the user, then the pinned status can be seen
  857. CommonAPI.follow(reader, user)
  858. ObanHelpers.perform_all()
  859. assert [%{"id" => ^activity_id, "pinned" => true}] =
  860. conn
  861. |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
  862. |> json_response_and_validate_schema(200)
  863. end
  864. test "blocking / unblocking a user" do
  865. %{conn: conn} = oauth_access(["follow"])
  866. other_user = insert(:user)
  867. ret_conn = post(conn, "/api/v1/accounts/#{other_user.id}/block")
  868. assert %{"id" => _id, "blocking" => true} = json_response_and_validate_schema(ret_conn, 200)
  869. conn = post(conn, "/api/v1/accounts/#{other_user.id}/unblock")
  870. assert %{"id" => _id, "blocking" => false} = json_response_and_validate_schema(conn, 200)
  871. end
  872. describe "create account by app" do
  873. setup do
  874. valid_params = %{
  875. username: "lain",
  876. email: "lain@example.org",
  877. password: "PlzDontHackLain",
  878. agreement: true
  879. }
  880. [valid_params: valid_params]
  881. end
  882. test "registers and logs in without :account_activation_required / :account_approval_required",
  883. %{conn: conn} do
  884. clear_config([:instance, :account_activation_required], false)
  885. clear_config([:instance, :account_approval_required], false)
  886. conn =
  887. conn
  888. |> put_req_header("content-type", "application/json")
  889. |> post("/api/v1/apps", %{
  890. client_name: "client_name",
  891. redirect_uris: "urn:ietf:wg:oauth:2.0:oob",
  892. scopes: "read, write, follow"
  893. })
  894. assert %{
  895. "client_id" => client_id,
  896. "client_secret" => client_secret,
  897. "id" => _,
  898. "name" => "client_name",
  899. "redirect_uri" => "urn:ietf:wg:oauth:2.0:oob",
  900. "vapid_key" => _,
  901. "website" => nil
  902. } = json_response_and_validate_schema(conn, 200)
  903. conn =
  904. post(conn, "/oauth/token", %{
  905. grant_type: "client_credentials",
  906. client_id: client_id,
  907. client_secret: client_secret
  908. })
  909. assert %{"access_token" => token, "refresh_token" => refresh, "scope" => scope} =
  910. json_response(conn, 200)
  911. assert token
  912. token_from_db = Repo.get_by(Token, token: token)
  913. assert token_from_db
  914. assert refresh
  915. assert scope == "read write follow"
  916. clear_config([User, :email_blacklist], ["example.org"])
  917. params = %{
  918. username: "lain",
  919. email: "lain@example.org",
  920. password: "PlzDontHackLain",
  921. bio: "Test Bio",
  922. agreement: true
  923. }
  924. conn =
  925. build_conn()
  926. |> put_req_header("content-type", "multipart/form-data")
  927. |> put_req_header("authorization", "Bearer " <> token)
  928. |> post("/api/v1/accounts", params)
  929. assert %{"error" => "{\"email\":[\"Invalid email\"]}"} =
  930. json_response_and_validate_schema(conn, 400)
  931. clear_config([User, :email_blacklist], [])
  932. conn =
  933. build_conn()
  934. |> put_req_header("content-type", "multipart/form-data")
  935. |> put_req_header("authorization", "Bearer " <> token)
  936. |> post("/api/v1/accounts", params)
  937. %{
  938. "access_token" => token,
  939. "created_at" => _created_at,
  940. "scope" => ^scope,
  941. "token_type" => "Bearer"
  942. } = json_response_and_validate_schema(conn, 200)
  943. token_from_db = Repo.get_by(Token, token: token)
  944. assert token_from_db
  945. user = Repo.preload(token_from_db, :user).user
  946. assert user
  947. assert user.is_confirmed
  948. assert user.is_approved
  949. end
  950. test "registers but does not log in with :account_activation_required", %{conn: conn} do
  951. clear_config([:instance, :account_activation_required], true)
  952. clear_config([:instance, :account_approval_required], false)
  953. conn =
  954. conn
  955. |> put_req_header("content-type", "application/json")
  956. |> post("/api/v1/apps", %{
  957. client_name: "client_name",
  958. redirect_uris: "urn:ietf:wg:oauth:2.0:oob",
  959. scopes: "read, write, follow"
  960. })
  961. assert %{
  962. "client_id" => client_id,
  963. "client_secret" => client_secret,
  964. "id" => _,
  965. "name" => "client_name",
  966. "redirect_uri" => "urn:ietf:wg:oauth:2.0:oob",
  967. "vapid_key" => _,
  968. "website" => nil
  969. } = json_response_and_validate_schema(conn, 200)
  970. conn =
  971. post(conn, "/oauth/token", %{
  972. grant_type: "client_credentials",
  973. client_id: client_id,
  974. client_secret: client_secret
  975. })
  976. assert %{"access_token" => token, "refresh_token" => refresh, "scope" => scope} =
  977. json_response(conn, 200)
  978. assert token
  979. token_from_db = Repo.get_by(Token, token: token)
  980. assert token_from_db
  981. assert refresh
  982. assert scope == "read write follow"
  983. conn =
  984. build_conn()
  985. |> put_req_header("content-type", "multipart/form-data")
  986. |> put_req_header("authorization", "Bearer " <> token)
  987. |> post("/api/v1/accounts", %{
  988. username: "lain",
  989. email: "lain@example.org",
  990. password: "PlzDontHackLain",
  991. bio: "Test Bio",
  992. agreement: true
  993. })
  994. response = json_response_and_validate_schema(conn, 200)
  995. assert %{"identifier" => "missing_confirmed_email"} = response
  996. refute response["access_token"]
  997. refute response["token_type"]
  998. user = Repo.get_by(User, email: "lain@example.org")
  999. refute user.is_confirmed
  1000. end
  1001. test "registers but does not log in with :account_approval_required", %{conn: conn} do
  1002. clear_config([:instance, :account_approval_required], true)
  1003. clear_config([:instance, :account_activation_required], false)
  1004. conn =
  1005. conn
  1006. |> put_req_header("content-type", "application/json")
  1007. |> post("/api/v1/apps", %{
  1008. client_name: "client_name",
  1009. redirect_uris: "urn:ietf:wg:oauth:2.0:oob",
  1010. scopes: "read, write, follow"
  1011. })
  1012. assert %{
  1013. "client_id" => client_id,
  1014. "client_secret" => client_secret,
  1015. "id" => _,
  1016. "name" => "client_name",
  1017. "redirect_uri" => "urn:ietf:wg:oauth:2.0:oob",
  1018. "vapid_key" => _,
  1019. "website" => nil
  1020. } = json_response_and_validate_schema(conn, 200)
  1021. conn =
  1022. post(conn, "/oauth/token", %{
  1023. grant_type: "client_credentials",
  1024. client_id: client_id,
  1025. client_secret: client_secret
  1026. })
  1027. assert %{"access_token" => token, "refresh_token" => refresh, "scope" => scope} =
  1028. json_response(conn, 200)
  1029. assert token
  1030. token_from_db = Repo.get_by(Token, token: token)
  1031. assert token_from_db
  1032. assert refresh
  1033. assert scope == "read write follow"
  1034. conn =
  1035. build_conn()
  1036. |> put_req_header("content-type", "multipart/form-data")
  1037. |> put_req_header("authorization", "Bearer " <> token)
  1038. |> post("/api/v1/accounts", %{
  1039. username: "lain",
  1040. email: "lain@example.org",
  1041. password: "PlzDontHackLain",
  1042. bio: "Test Bio",
  1043. agreement: true,
  1044. reason: "I'm a cool dude, bro"
  1045. })
  1046. response = json_response_and_validate_schema(conn, 200)
  1047. assert %{"identifier" => "awaiting_approval"} = response
  1048. refute response["access_token"]
  1049. refute response["token_type"]
  1050. user = Repo.get_by(User, email: "lain@example.org")
  1051. refute user.is_approved
  1052. assert user.registration_reason == "I'm a cool dude, bro"
  1053. end
  1054. test "returns error when user already registered", %{conn: conn, valid_params: valid_params} do
  1055. _user = insert(:user, email: "lain@example.org")
  1056. app_token = insert(:oauth_token, user: nil)
  1057. res =
  1058. conn
  1059. |> put_req_header("authorization", "Bearer " <> app_token.token)
  1060. |> put_req_header("content-type", "application/json")
  1061. |> post("/api/v1/accounts", valid_params)
  1062. assert json_response_and_validate_schema(res, 400) == %{
  1063. "error" => "{\"email\":[\"has already been taken\"]}"
  1064. }
  1065. end
  1066. test "returns bad_request if missing required params", %{
  1067. conn: conn,
  1068. valid_params: valid_params
  1069. } do
  1070. app_token = insert(:oauth_token, user: nil)
  1071. conn =
  1072. conn
  1073. |> put_req_header("authorization", "Bearer " <> app_token.token)
  1074. |> put_req_header("content-type", "application/json")
  1075. res = post(conn, "/api/v1/accounts", valid_params)
  1076. assert json_response_and_validate_schema(res, 200)
  1077. [{127, 0, 0, 1}, {127, 0, 0, 2}, {127, 0, 0, 3}, {127, 0, 0, 4}]
  1078. |> Stream.zip(Map.delete(valid_params, :email))
  1079. |> Enum.each(fn {ip, {attr, _}} ->
  1080. res =
  1081. conn
  1082. |> Map.put(:remote_ip, ip)
  1083. |> post("/api/v1/accounts", Map.delete(valid_params, attr))
  1084. |> json_response_and_validate_schema(400)
  1085. assert res == %{
  1086. "error" => "Missing field: #{attr}.",
  1087. "errors" => [
  1088. %{
  1089. "message" => "Missing field: #{attr}",
  1090. "source" => %{"pointer" => "/#{attr}"},
  1091. "title" => "Invalid value"
  1092. }
  1093. ]
  1094. }
  1095. end)
  1096. end
  1097. test "returns bad_request if missing email params when :account_activation_required is enabled",
  1098. %{conn: conn, valid_params: valid_params} do
  1099. clear_config([:instance, :account_activation_required], true)
  1100. app_token = insert(:oauth_token, user: nil)
  1101. conn =
  1102. conn
  1103. |> put_req_header("authorization", "Bearer " <> app_token.token)
  1104. |> put_req_header("content-type", "application/json")
  1105. res =
  1106. conn
  1107. |> Map.put(:remote_ip, {127, 0, 0, 5})
  1108. |> post("/api/v1/accounts", Map.delete(valid_params, :email))
  1109. assert json_response_and_validate_schema(res, 400) ==
  1110. %{"error" => "Missing parameter: email"}
  1111. res =
  1112. conn
  1113. |> Map.put(:remote_ip, {127, 0, 0, 6})
  1114. |> post("/api/v1/accounts", Map.put(valid_params, :email, ""))
  1115. assert json_response_and_validate_schema(res, 400) == %{
  1116. "error" => "{\"email\":[\"can't be blank\"]}"
  1117. }
  1118. end
  1119. test "allow registration without an email", %{conn: conn, valid_params: valid_params} do
  1120. app_token = insert(:oauth_token, user: nil)
  1121. conn = put_req_header(conn, "authorization", "Bearer " <> app_token.token)
  1122. res =
  1123. conn
  1124. |> put_req_header("content-type", "application/json")
  1125. |> Map.put(:remote_ip, {127, 0, 0, 7})
  1126. |> post("/api/v1/accounts", Map.delete(valid_params, :email))
  1127. assert json_response_and_validate_schema(res, 200)
  1128. end
  1129. test "allow registration with an empty email", %{conn: conn, valid_params: valid_params} do
  1130. app_token = insert(:oauth_token, user: nil)
  1131. conn = put_req_header(conn, "authorization", "Bearer " <> app_token.token)
  1132. res =
  1133. conn
  1134. |> put_req_header("content-type", "application/json")
  1135. |> Map.put(:remote_ip, {127, 0, 0, 8})
  1136. |> post("/api/v1/accounts", Map.put(valid_params, :email, ""))
  1137. assert json_response_and_validate_schema(res, 200)
  1138. end
  1139. test "returns forbidden if token is invalid", %{conn: conn, valid_params: valid_params} do
  1140. res =
  1141. conn
  1142. |> put_req_header("authorization", "Bearer " <> "invalid-token")
  1143. |> put_req_header("content-type", "multipart/form-data")
  1144. |> post("/api/v1/accounts", valid_params)
  1145. assert json_response_and_validate_schema(res, 403) == %{"error" => "Invalid credentials"}
  1146. end
  1147. test "registration from trusted app" do
  1148. clear_config([Pleroma.Captcha, :enabled], true)
  1149. app = insert(:oauth_app, trusted: true, scopes: ["read", "write", "follow", "push"])
  1150. conn =
  1151. build_conn()
  1152. |> post("/oauth/token", %{
  1153. "grant_type" => "client_credentials",
  1154. "client_id" => app.client_id,
  1155. "client_secret" => app.client_secret
  1156. })
  1157. assert %{"access_token" => token, "token_type" => "Bearer"} = json_response(conn, 200)
  1158. response =
  1159. build_conn()
  1160. |> Plug.Conn.put_req_header("authorization", "Bearer " <> token)
  1161. |> put_req_header("content-type", "multipart/form-data")
  1162. |> post("/api/v1/accounts", %{
  1163. nickname: "nickname",
  1164. agreement: true,
  1165. email: "email@example.com",
  1166. fullname: "Lain",
  1167. username: "Lain",
  1168. password: "some_password",
  1169. confirm: "some_password"
  1170. })
  1171. |> json_response_and_validate_schema(200)
  1172. assert %{
  1173. "access_token" => access_token,
  1174. "created_at" => _,
  1175. "scope" => "read write follow push",
  1176. "token_type" => "Bearer"
  1177. } = response
  1178. response =
  1179. build_conn()
  1180. |> Plug.Conn.put_req_header("authorization", "Bearer " <> access_token)
  1181. |> get("/api/v1/accounts/verify_credentials")
  1182. |> json_response_and_validate_schema(200)
  1183. assert %{
  1184. "acct" => "Lain",
  1185. "bot" => false,
  1186. "display_name" => "Lain",
  1187. "follow_requests_count" => 0,
  1188. "followers_count" => 0,
  1189. "following_count" => 0,
  1190. "locked" => false,
  1191. "note" => "",
  1192. "source" => %{
  1193. "fields" => [],
  1194. "note" => "",
  1195. "pleroma" => %{
  1196. "actor_type" => "Person",
  1197. "discoverable" => false,
  1198. "no_rich_text" => false,
  1199. "show_role" => true
  1200. },
  1201. "privacy" => "public",
  1202. "sensitive" => false
  1203. },
  1204. "statuses_count" => 0,
  1205. "username" => "Lain"
  1206. } = response
  1207. end
  1208. end
  1209. describe "create account by app / rate limit" do
  1210. setup do: clear_config([:rate_limit, :app_account_creation], {10_000, 2})
  1211. test "respects rate limit setting", %{conn: conn} do
  1212. app_token = insert(:oauth_token, user: nil)
  1213. conn =
  1214. conn
  1215. |> put_req_header("authorization", "Bearer " <> app_token.token)
  1216. |> Map.put(:remote_ip, {15, 15, 15, 15})
  1217. |> put_req_header("content-type", "multipart/form-data")
  1218. for i <- 1..2 do
  1219. conn =
  1220. conn
  1221. |> post("/api/v1/accounts", %{
  1222. username: "#{i}lain",
  1223. email: "#{i}lain@example.org",
  1224. password: "PlzDontHackLain",
  1225. agreement: true
  1226. })
  1227. %{
  1228. "access_token" => token,
  1229. "created_at" => _created_at,
  1230. "scope" => _scope,
  1231. "token_type" => "Bearer"
  1232. } = json_response_and_validate_schema(conn, 200)
  1233. token_from_db = Repo.get_by(Token, token: token)
  1234. assert token_from_db
  1235. token_from_db = Repo.preload(token_from_db, :user)
  1236. assert token_from_db.user
  1237. end
  1238. conn =
  1239. post(conn, "/api/v1/accounts", %{
  1240. username: "6lain",
  1241. email: "6lain@example.org",
  1242. password: "PlzDontHackLain",
  1243. agreement: true
  1244. })
  1245. assert json_response_and_validate_schema(conn, :too_many_requests) == %{
  1246. "error" => "Throttled"
  1247. }
  1248. end
  1249. end
  1250. describe "create account with enabled captcha" do
  1251. setup %{conn: conn} do
  1252. app_token = insert(:oauth_token, user: nil)
  1253. conn =
  1254. conn
  1255. |> put_req_header("authorization", "Bearer " <> app_token.token)
  1256. |> put_req_header("content-type", "multipart/form-data")
  1257. [conn: conn]
  1258. end
  1259. setup do: clear_config([Pleroma.Captcha, :enabled], true)
  1260. test "creates an account and returns 200 if captcha is valid", %{conn: conn} do
  1261. %{token: token, answer_data: answer_data} = Pleroma.Captcha.new()
  1262. params = %{
  1263. username: "lain",
  1264. email: "lain@example.org",
  1265. password: "PlzDontHackLain",
  1266. agreement: true,
  1267. captcha_solution: Pleroma.Captcha.Mock.solution(),
  1268. captcha_token: token,
  1269. captcha_answer_data: answer_data
  1270. }
  1271. assert %{
  1272. "access_token" => access_token,
  1273. "created_at" => _,
  1274. "scope" => "read",
  1275. "token_type" => "Bearer"
  1276. } =
  1277. conn
  1278. |> post("/api/v1/accounts", params)
  1279. |> json_response_and_validate_schema(:ok)
  1280. assert Token |> Repo.get_by(token: access_token) |> Repo.preload(:user) |> Map.get(:user)
  1281. end
  1282. test "returns 400 if any captcha field is not provided", %{conn: conn} do
  1283. captcha_fields = [:captcha_solution, :captcha_token, :captcha_answer_data]
  1284. valid_params = %{
  1285. username: "lain",
  1286. email: "lain@example.org",
  1287. password: "PlzDontHackLain",
  1288. agreement: true,
  1289. captcha_solution: "xx",
  1290. captcha_token: "xx",
  1291. captcha_answer_data: "xx"
  1292. }
  1293. for field <- captcha_fields do
  1294. expected = %{
  1295. "error" => "{\"captcha\":[\"Invalid CAPTCHA (Missing parameter: #{field})\"]}"
  1296. }
  1297. assert expected ==
  1298. conn
  1299. |> post("/api/v1/accounts", Map.delete(valid_params, field))
  1300. |> json_response_and_validate_schema(:bad_request)
  1301. end
  1302. end
  1303. test "returns an error if captcha is invalid", %{conn: conn} do
  1304. params = %{
  1305. username: "lain",
  1306. email: "lain@example.org",
  1307. password: "PlzDontHackLain",
  1308. agreement: true,
  1309. captcha_solution: "cofe",
  1310. captcha_token: "cofe",
  1311. captcha_answer_data: "cofe"
  1312. }
  1313. assert %{"error" => "{\"captcha\":[\"Invalid answer data\"]}"} ==
  1314. conn
  1315. |> post("/api/v1/accounts", params)
  1316. |> json_response_and_validate_schema(:bad_request)
  1317. end
  1318. end
  1319. describe "create account with required birth date" do
  1320. setup %{conn: conn} do
  1321. clear_config([:instance, :birthday_required], true)
  1322. clear_config([:instance, :birthday_min_age], 18 * 365)
  1323. app_token = insert(:oauth_token, user: nil)
  1324. conn =
  1325. conn
  1326. |> put_req_header("authorization", "Bearer " <> app_token.token)
  1327. |> put_req_header("content-type", "multipart/form-data")
  1328. [conn: conn]
  1329. end
  1330. test "creates an account if provided valid birth date", %{conn: conn} do
  1331. birthday =
  1332. Date.utc_today()
  1333. |> Date.add(-19 * 365)
  1334. |> Date.to_string()
  1335. params = %{
  1336. username: "mkljczk",
  1337. email: "mkljczk@example.org",
  1338. password: "dupa.8",
  1339. agreement: true,
  1340. birthday: birthday
  1341. }
  1342. res =
  1343. conn
  1344. |> post("/api/v1/accounts", params)
  1345. assert json_response_and_validate_schema(res, 200)
  1346. end
  1347. test "returns an error if missing birth date", %{conn: conn} do
  1348. params = %{
  1349. username: "mkljczk",
  1350. email: "mkljczk@example.org",
  1351. password: "dupa.8",
  1352. agreement: true
  1353. }
  1354. res =
  1355. conn
  1356. |> post("/api/v1/accounts", params)
  1357. assert json_response_and_validate_schema(res, 400) == %{
  1358. "error" => "{\"birthday\":[\"can't be blank\"]}"
  1359. }
  1360. end
  1361. end
  1362. describe "create account with language" do
  1363. setup %{conn: conn} do
  1364. app_token = insert(:oauth_token, user: nil)
  1365. conn =
  1366. conn
  1367. |> put_req_header("authorization", "Bearer " <> app_token.token)
  1368. |> put_req_header("content-type", "multipart/form-data")
  1369. |> put_req_cookie(SetLocalePlug.frontend_language_cookie_name(), "zh-Hans")
  1370. |> SetLocalePlug.call([])
  1371. [conn: conn]
  1372. end
  1373. test "creates an account with language parameter", %{conn: conn} do
  1374. params = %{
  1375. username: "foo",
  1376. email: "foo@example.org",
  1377. password: "dupa.8",
  1378. agreement: true,
  1379. language: "ru"
  1380. }
  1381. res =
  1382. conn
  1383. |> post("/api/v1/accounts", params)
  1384. assert json_response_and_validate_schema(res, 200)
  1385. assert %{language: "ru"} = Pleroma.User.get_by_nickname("foo")
  1386. end
  1387. test "language parameter should be normalized", %{conn: conn} do
  1388. params = %{
  1389. username: "foo",
  1390. email: "foo@example.org",
  1391. password: "dupa.8",
  1392. agreement: true,
  1393. language: "ru-RU"
  1394. }
  1395. res =
  1396. conn
  1397. |> post("/api/v1/accounts", params)
  1398. assert json_response_and_validate_schema(res, 200)
  1399. assert %{language: "ru_RU"} = Pleroma.User.get_by_nickname("foo")
  1400. end
  1401. test "creating an account without language parameter should fallback to cookie/header language",
  1402. %{conn: conn} do
  1403. params = %{
  1404. username: "foo2",
  1405. email: "foo2@example.org",
  1406. password: "dupa.8",
  1407. agreement: true
  1408. }
  1409. res =
  1410. conn
  1411. |> post("/api/v1/accounts", params)
  1412. assert json_response_and_validate_schema(res, 200)
  1413. assert %{language: "zh_Hans"} = Pleroma.User.get_by_nickname("foo2")
  1414. end
  1415. end
  1416. describe "GET /api/v1/accounts/:id/lists - account_lists" do
  1417. test "returns lists to which the account belongs" do
  1418. %{user: user, conn: conn} = oauth_access(["read:lists"])
  1419. other_user = insert(:user)
  1420. assert {:ok, %Pleroma.List{id: _list_id} = list} = Pleroma.List.create("Test List", user)
  1421. {:ok, %{following: _following}} = Pleroma.List.follow(list, other_user)
  1422. assert [%{"id" => _list_id, "title" => "Test List"}] =
  1423. conn
  1424. |> get("/api/v1/accounts/#{other_user.id}/lists")
  1425. |> json_response_and_validate_schema(200)
  1426. end
  1427. end
  1428. describe "verify_credentials" do
  1429. test "verify_credentials" do
  1430. %{user: user, conn: conn} = oauth_access(["read:accounts"])
  1431. [notification | _] =
  1432. insert_list(7, :notification, user: user, activity: insert(:note_activity))
  1433. Pleroma.Notification.set_read_up_to(user, notification.id)
  1434. conn = get(conn, "/api/v1/accounts/verify_credentials")
  1435. response = json_response_and_validate_schema(conn, 200)
  1436. assert %{"id" => id, "source" => %{"privacy" => "public"}} = response
  1437. assert response["pleroma"]["chat_token"]
  1438. assert response["pleroma"]["unread_notifications_count"] == 6
  1439. assert id == to_string(user.id)
  1440. end
  1441. test "verify_credentials default scope unlisted" do
  1442. user = insert(:user, default_scope: "unlisted")
  1443. %{conn: conn} = oauth_access(["read:accounts"], user: user)
  1444. conn = get(conn, "/api/v1/accounts/verify_credentials")
  1445. assert %{"id" => id, "source" => %{"privacy" => "unlisted"}} =
  1446. json_response_and_validate_schema(conn, 200)
  1447. assert id == to_string(user.id)
  1448. end
  1449. test "locked accounts" do
  1450. user = insert(:user, default_scope: "private")
  1451. %{conn: conn} = oauth_access(["read:accounts"], user: user)
  1452. conn = get(conn, "/api/v1/accounts/verify_credentials")
  1453. assert %{"id" => id, "source" => %{"privacy" => "private"}} =
  1454. json_response_and_validate_schema(conn, 200)
  1455. assert id == to_string(user.id)
  1456. end
  1457. end
  1458. describe "user relationships" do
  1459. setup do: oauth_access(["read:follows"])
  1460. test "returns the relationships for the current user", %{user: user, conn: conn} do
  1461. %{id: other_user_id} = other_user = insert(:user)
  1462. {:ok, _user, _other_user} = User.follow(user, other_user)
  1463. assert [%{"id" => ^other_user_id}] =
  1464. conn
  1465. |> get("/api/v1/accounts/relationships?id=#{other_user.id}")
  1466. |> json_response_and_validate_schema(200)
  1467. assert [%{"id" => ^other_user_id}] =
  1468. conn
  1469. |> get("/api/v1/accounts/relationships?id[]=#{other_user.id}")
  1470. |> json_response_and_validate_schema(200)
  1471. end
  1472. test "returns an empty list on a bad request", %{conn: conn} do
  1473. conn = get(conn, "/api/v1/accounts/relationships", %{})
  1474. assert [] = json_response_and_validate_schema(conn, 200)
  1475. end
  1476. end
  1477. test "getting a list of mutes" do
  1478. %{user: user, conn: conn} = oauth_access(["read:mutes"])
  1479. %{id: id1} = other_user1 = insert(:user)
  1480. %{id: id2} = other_user2 = insert(:user)
  1481. %{id: id3} = other_user3 = insert(:user)
  1482. {:ok, _user_relationships} = User.mute(user, other_user1)
  1483. {:ok, _user_relationships} = User.mute(user, other_user2)
  1484. {:ok, _user_relationships} = User.mute(user, other_user3)
  1485. result =
  1486. conn
  1487. |> get("/api/v1/mutes")
  1488. |> json_response_and_validate_schema(200)
  1489. assert [id3, id2, id1] == Enum.map(result, & &1["id"])
  1490. result =
  1491. conn
  1492. |> get("/api/v1/mutes?limit=1")
  1493. |> json_response_and_validate_schema(200)
  1494. assert [%{"id" => ^id3}] = result
  1495. result =
  1496. conn
  1497. |> get("/api/v1/mutes?since_id=#{id1}")
  1498. |> json_response_and_validate_schema(200)
  1499. assert [%{"id" => ^id3}, %{"id" => ^id2}] = result
  1500. result =
  1501. conn
  1502. |> get("/api/v1/mutes?since_id=#{id1}&max_id=#{id3}")
  1503. |> json_response_and_validate_schema(200)
  1504. assert [%{"id" => ^id2}] = result
  1505. result =
  1506. conn
  1507. |> get("/api/v1/mutes?since_id=#{id1}&limit=1")
  1508. |> json_response_and_validate_schema(200)
  1509. assert [%{"id" => ^id3}] = result
  1510. end
  1511. test "list of mutes with with_relationships parameter" do
  1512. %{user: user, conn: conn} = oauth_access(["read:mutes"])
  1513. %{id: id1} = other_user1 = insert(:user)
  1514. %{id: id2} = other_user2 = insert(:user)
  1515. %{id: id3} = other_user3 = insert(:user)
  1516. {:ok, _, _} = User.follow(other_user1, user)
  1517. {:ok, _, _} = User.follow(other_user2, user)
  1518. {:ok, _, _} = User.follow(other_user3, user)
  1519. {:ok, _} = User.mute(user, other_user1)
  1520. {:ok, _} = User.mute(user, other_user2)
  1521. {:ok, _} = User.mute(user, other_user3)
  1522. assert [
  1523. %{
  1524. "id" => ^id3,
  1525. "pleroma" => %{"relationship" => %{"muting" => true, "followed_by" => true}}
  1526. },
  1527. %{
  1528. "id" => ^id2,
  1529. "pleroma" => %{"relationship" => %{"muting" => true, "followed_by" => true}}
  1530. },
  1531. %{
  1532. "id" => ^id1,
  1533. "pleroma" => %{"relationship" => %{"muting" => true, "followed_by" => true}}
  1534. }
  1535. ] =
  1536. conn
  1537. |> get("/api/v1/mutes?with_relationships=true")
  1538. |> json_response_and_validate_schema(200)
  1539. end
  1540. test "getting a list of blocks" do
  1541. %{user: user, conn: conn} = oauth_access(["read:blocks"])
  1542. %{id: id1} = other_user1 = insert(:user)
  1543. %{id: id2} = other_user2 = insert(:user)
  1544. %{id: id3} = other_user3 = insert(:user)
  1545. {:ok, _user_relationship} = User.block(user, other_user1)
  1546. {:ok, _user_relationship} = User.block(user, other_user3)
  1547. {:ok, _user_relationship} = User.block(user, other_user2)
  1548. result =
  1549. conn
  1550. |> assign(:user, user)
  1551. |> get("/api/v1/blocks")
  1552. |> json_response_and_validate_schema(200)
  1553. assert [id3, id2, id1] == Enum.map(result, & &1["id"])
  1554. result =
  1555. conn
  1556. |> assign(:user, user)
  1557. |> get("/api/v1/blocks?limit=1")
  1558. |> json_response_and_validate_schema(200)
  1559. assert [%{"id" => ^id3}] = result
  1560. result =
  1561. conn
  1562. |> assign(:user, user)
  1563. |> get("/api/v1/blocks?since_id=#{id1}")
  1564. |> json_response_and_validate_schema(200)
  1565. assert [%{"id" => ^id3}, %{"id" => ^id2}] = result
  1566. result =
  1567. conn
  1568. |> assign(:user, user)
  1569. |> get("/api/v1/blocks?since_id=#{id1}&max_id=#{id3}")
  1570. |> json_response_and_validate_schema(200)
  1571. assert [%{"id" => ^id2}] = result
  1572. result =
  1573. conn
  1574. |> assign(:user, user)
  1575. |> get("/api/v1/blocks?since_id=#{id1}&limit=1")
  1576. |> json_response_and_validate_schema(200)
  1577. assert [%{"id" => ^id3}] = result
  1578. conn_res =
  1579. conn
  1580. |> assign(:user, user)
  1581. |> get("/api/v1/blocks?limit=2")
  1582. next_url =
  1583. ~r{<.+?(?<link>/api[^>]+)>; rel=\"next\"}
  1584. |> Regex.named_captures(get_resp_header(conn_res, "link") |> Enum.at(0))
  1585. |> Map.get("link")
  1586. result =
  1587. conn_res
  1588. |> json_response_and_validate_schema(200)
  1589. assert [%{"id" => ^id3}, %{"id" => ^id2}] = result
  1590. result =
  1591. conn
  1592. |> assign(:user, user)
  1593. |> get(next_url)
  1594. |> json_response_and_validate_schema(200)
  1595. assert [%{"id" => ^id1}] = result
  1596. end
  1597. test "list of blocks with with_relationships parameter" do
  1598. %{user: user, conn: conn} = oauth_access(["read:blocks"])
  1599. %{id: id1} = other_user1 = insert(:user)
  1600. %{id: id2} = other_user2 = insert(:user)
  1601. %{id: id3} = other_user3 = insert(:user)
  1602. {:ok, _, _} = User.follow(other_user1, user)
  1603. {:ok, _, _} = User.follow(other_user2, user)
  1604. {:ok, _, _} = User.follow(other_user3, user)
  1605. {:ok, _} = User.block(user, other_user1)
  1606. {:ok, _} = User.block(user, other_user2)
  1607. {:ok, _} = User.block(user, other_user3)
  1608. assert [
  1609. %{
  1610. "id" => ^id3,
  1611. "pleroma" => %{"relationship" => %{"blocking" => true, "followed_by" => false}}
  1612. },
  1613. %{
  1614. "id" => ^id2,
  1615. "pleroma" => %{"relationship" => %{"blocking" => true, "followed_by" => false}}
  1616. },
  1617. %{
  1618. "id" => ^id1,
  1619. "pleroma" => %{"relationship" => %{"blocking" => true, "followed_by" => false}}
  1620. }
  1621. ] =
  1622. conn
  1623. |> get("/api/v1/blocks?with_relationships=true")
  1624. |> json_response_and_validate_schema(200)
  1625. end
  1626. test "account lookup", %{conn: conn} do
  1627. %{nickname: acct} = insert(:user, %{nickname: "nickname"})
  1628. %{nickname: acct_two} = insert(:user, %{nickname: "nickname@notlocaldoma.in"})
  1629. result =
  1630. conn
  1631. |> get("/api/v1/accounts/lookup?acct=#{acct}")
  1632. |> json_response_and_validate_schema(200)
  1633. assert %{"acct" => ^acct} = result
  1634. result =
  1635. conn
  1636. |> get("/api/v1/accounts/lookup?acct=#{acct_two}")
  1637. |> json_response_and_validate_schema(200)
  1638. assert %{"acct" => ^acct_two} = result
  1639. _result =
  1640. conn
  1641. |> get("/api/v1/accounts/lookup?acct=unexisting_nickname")
  1642. |> json_response_and_validate_schema(404)
  1643. end
  1644. test "create a note on a user" do
  1645. %{conn: conn} = oauth_access(["write:accounts", "read:follows"])
  1646. other_user = insert(:user)
  1647. conn
  1648. |> put_req_header("content-type", "application/json")
  1649. |> post("/api/v1/accounts/#{other_user.id}/note", %{
  1650. "comment" => "Example note"
  1651. })
  1652. assert [%{"note" => "Example note"}] =
  1653. conn
  1654. |> put_req_header("content-type", "application/json")
  1655. |> get("/api/v1/accounts/relationships?id=#{other_user.id}")
  1656. |> json_response_and_validate_schema(200)
  1657. end
  1658. describe "account endorsements" do
  1659. setup do: oauth_access(["read:accounts", "write:accounts", "write:follows"])
  1660. setup do: clear_config([:instance, :max_endorsed_users], 1)
  1661. test "pin account", %{user: user, conn: conn} do
  1662. %{id: id1} = other_user1 = insert(:user)
  1663. CommonAPI.follow(user, other_user1)
  1664. assert %{"id" => ^id1, "endorsed" => true} =
  1665. conn
  1666. |> put_req_header("content-type", "application/json")
  1667. |> post("/api/v1/accounts/#{id1}/pin")
  1668. |> json_response_and_validate_schema(200)
  1669. assert [%{"id" => ^id1}] =
  1670. conn
  1671. |> put_req_header("content-type", "application/json")
  1672. |> get("/api/v1/endorsements")
  1673. |> json_response_and_validate_schema(200)
  1674. end
  1675. test "unpin account", %{user: user, conn: conn} do
  1676. %{id: id1} = other_user1 = insert(:user)
  1677. CommonAPI.follow(user, other_user1)
  1678. User.endorse(user, other_user1)
  1679. assert %{"id" => ^id1, "endorsed" => false} =
  1680. conn
  1681. |> put_req_header("content-type", "application/json")
  1682. |> post("/api/v1/accounts/#{id1}/unpin")
  1683. |> json_response_and_validate_schema(200)
  1684. assert [] =
  1685. conn
  1686. |> put_req_header("content-type", "application/json")
  1687. |> get("/api/v1/endorsements")
  1688. |> json_response_and_validate_schema(200)
  1689. end
  1690. test "max pinned accounts", %{user: user, conn: conn} do
  1691. %{id: id1} = other_user1 = insert(:user)
  1692. %{id: id2} = other_user2 = insert(:user)
  1693. CommonAPI.follow(user, other_user1)
  1694. CommonAPI.follow(user, other_user2)
  1695. conn
  1696. |> put_req_header("content-type", "application/json")
  1697. |> post("/api/v1/accounts/#{id1}/pin")
  1698. |> json_response_and_validate_schema(200)
  1699. assert %{"error" => "You have already pinned the maximum number of users"} =
  1700. conn
  1701. |> assign(:user, user)
  1702. |> post("/api/v1/accounts/#{id2}/pin")
  1703. |> json_response_and_validate_schema(400)
  1704. end
  1705. end
  1706. describe "remove from followers" do
  1707. setup do: oauth_access(["follow"])
  1708. test "removing user from followers", %{conn: conn, user: user} do
  1709. %{id: other_user_id} = other_user = insert(:user)
  1710. CommonAPI.follow(other_user, user)
  1711. assert %{"id" => ^other_user_id, "followed_by" => false} =
  1712. conn
  1713. |> post("/api/v1/accounts/#{other_user_id}/remove_from_followers")
  1714. |> json_response_and_validate_schema(200)
  1715. refute User.following?(other_user, user)
  1716. end
  1717. test "removing remote user from followers", %{conn: conn, user: user} do
  1718. %{id: other_user_id} = other_user = insert(:user, local: false)
  1719. CommonAPI.follow(other_user, user)
  1720. assert User.following?(other_user, user)
  1721. assert %{"id" => ^other_user_id, "followed_by" => false} =
  1722. conn
  1723. |> post("/api/v1/accounts/#{other_user_id}/remove_from_followers")
  1724. |> json_response_and_validate_schema(200)
  1725. refute User.following?(other_user, user)
  1726. end
  1727. test "removing user from followers errors", %{user: user, conn: conn} do
  1728. # self remove
  1729. conn_res = post(conn, "/api/v1/accounts/#{user.id}/remove_from_followers")
  1730. assert %{"error" => "Can not unfollow yourself"} =
  1731. json_response_and_validate_schema(conn_res, 400)
  1732. # remove non existing user
  1733. conn_res = post(conn, "/api/v1/accounts/doesntexist/remove_from_followers")
  1734. assert %{"error" => "Record not found"} = json_response_and_validate_schema(conn_res, 404)
  1735. end
  1736. end
  1737. end