Merge remote-tracking branch 'origin/develop' into pleroma-conversations
[akkoma] / test / web / mastodon_api / mastodon_api_controller_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
6 use Pleroma.Web.ConnCase
7
8 alias Ecto.Changeset
9 alias Pleroma.Activity
10 alias Pleroma.Notification
11 alias Pleroma.Object
12 alias Pleroma.Repo
13 alias Pleroma.ScheduledActivity
14 alias Pleroma.User
15 alias Pleroma.Web.ActivityPub.ActivityPub
16 alias Pleroma.Web.CommonAPI
17 alias Pleroma.Web.MastodonAPI.FilterView
18 alias Pleroma.Web.OAuth.App
19 alias Pleroma.Web.OAuth.Token
20 alias Pleroma.Web.OStatus
21 alias Pleroma.Web.Push
22 alias Pleroma.Web.TwitterAPI.TwitterAPI
23 import Pleroma.Factory
24 import ExUnit.CaptureLog
25 import Tesla.Mock
26 import Swoosh.TestAssertions
27
28 @image "data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7"
29
30 setup do
31 mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
32 :ok
33 end
34
35 test "the home timeline", %{conn: conn} do
36 user = insert(:user)
37 following = insert(:user)
38
39 {:ok, _activity} = CommonAPI.post(following, %{"status" => "test"})
40
41 conn =
42 conn
43 |> assign(:user, user)
44 |> get("/api/v1/timelines/home")
45
46 assert Enum.empty?(json_response(conn, 200))
47
48 {:ok, user} = User.follow(user, following)
49
50 conn =
51 build_conn()
52 |> assign(:user, user)
53 |> get("/api/v1/timelines/home")
54
55 assert [%{"content" => "test"}] = json_response(conn, 200)
56 end
57
58 test "the public timeline", %{conn: conn} do
59 following = insert(:user)
60
61 capture_log(fn ->
62 {:ok, _activity} = CommonAPI.post(following, %{"status" => "test"})
63
64 {:ok, [_activity]} =
65 OStatus.fetch_activity_from_url("https://shitposter.club/notice/2827873")
66
67 conn =
68 conn
69 |> get("/api/v1/timelines/public", %{"local" => "False"})
70
71 assert length(json_response(conn, 200)) == 2
72
73 conn =
74 build_conn()
75 |> get("/api/v1/timelines/public", %{"local" => "True"})
76
77 assert [%{"content" => "test"}] = json_response(conn, 200)
78
79 conn =
80 build_conn()
81 |> get("/api/v1/timelines/public", %{"local" => "1"})
82
83 assert [%{"content" => "test"}] = json_response(conn, 200)
84 end)
85 end
86
87 test "the public timeline when public is set to false", %{conn: conn} do
88 public = Pleroma.Config.get([:instance, :public])
89 Pleroma.Config.put([:instance, :public], false)
90
91 on_exit(fn ->
92 Pleroma.Config.put([:instance, :public], public)
93 end)
94
95 assert conn
96 |> get("/api/v1/timelines/public", %{"local" => "False"})
97 |> json_response(403) == %{"error" => "This resource requires authentication."}
98 end
99
100 describe "posting statuses" do
101 setup do
102 user = insert(:user)
103
104 conn =
105 build_conn()
106 |> assign(:user, user)
107
108 [conn: conn]
109 end
110
111 test "posting a status", %{conn: conn} do
112 idempotency_key = "Pikachu rocks!"
113
114 conn_one =
115 conn
116 |> put_req_header("idempotency-key", idempotency_key)
117 |> post("/api/v1/statuses", %{
118 "status" => "cofe",
119 "spoiler_text" => "2hu",
120 "sensitive" => "false"
121 })
122
123 {:ok, ttl} = Cachex.ttl(:idempotency_cache, idempotency_key)
124 # Six hours
125 assert ttl > :timer.seconds(6 * 60 * 60 - 1)
126
127 assert %{"content" => "cofe", "id" => id, "spoiler_text" => "2hu", "sensitive" => false} =
128 json_response(conn_one, 200)
129
130 assert Activity.get_by_id(id)
131
132 conn_two =
133 conn
134 |> put_req_header("idempotency-key", idempotency_key)
135 |> post("/api/v1/statuses", %{
136 "status" => "cofe",
137 "spoiler_text" => "2hu",
138 "sensitive" => "false"
139 })
140
141 assert %{"id" => second_id} = json_response(conn_two, 200)
142 assert id == second_id
143
144 conn_three =
145 conn
146 |> post("/api/v1/statuses", %{
147 "status" => "cofe",
148 "spoiler_text" => "2hu",
149 "sensitive" => "false"
150 })
151
152 assert %{"id" => third_id} = json_response(conn_three, 200)
153 refute id == third_id
154 end
155
156 test "replying to a status", %{conn: conn} do
157 user = insert(:user)
158 {:ok, replied_to} = CommonAPI.post(user, %{"status" => "cofe"})
159
160 conn =
161 conn
162 |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => replied_to.id})
163
164 assert %{"content" => "xD", "id" => id} = json_response(conn, 200)
165
166 activity = Activity.get_by_id(id)
167
168 assert activity.data["context"] == replied_to.data["context"]
169 assert Activity.get_in_reply_to_activity(activity).id == replied_to.id
170 end
171
172 test "replying to a direct message with visibility other than direct", %{conn: conn} do
173 user = insert(:user)
174 {:ok, replied_to} = CommonAPI.post(user, %{"status" => "suya..", "visibility" => "direct"})
175
176 Enum.each(["public", "private", "unlisted"], fn visibility ->
177 conn =
178 conn
179 |> post("/api/v1/statuses", %{
180 "status" => "@#{user.nickname} hey",
181 "in_reply_to_id" => replied_to.id,
182 "visibility" => visibility
183 })
184
185 assert json_response(conn, 422) == %{"error" => "The message visibility must be direct"}
186 end)
187 end
188
189 test "posting a status with an invalid in_reply_to_id", %{conn: conn} do
190 conn =
191 conn
192 |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => ""})
193
194 assert %{"content" => "xD", "id" => id} = json_response(conn, 200)
195 assert Activity.get_by_id(id)
196 end
197
198 test "posting a sensitive status", %{conn: conn} do
199 conn =
200 conn
201 |> post("/api/v1/statuses", %{"status" => "cofe", "sensitive" => true})
202
203 assert %{"content" => "cofe", "id" => id, "sensitive" => true} = json_response(conn, 200)
204 assert Activity.get_by_id(id)
205 end
206
207 test "posting a fake status", %{conn: conn} do
208 real_conn =
209 conn
210 |> post("/api/v1/statuses", %{
211 "status" =>
212 "\"Tenshi Eating a Corndog\" is a much discussed concept on /jp/. The significance of it is disputed, so I will focus on one core concept: the symbolism behind it"
213 })
214
215 real_status = json_response(real_conn, 200)
216
217 assert real_status
218 assert Object.get_by_ap_id(real_status["uri"])
219
220 real_status =
221 real_status
222 |> Map.put("id", nil)
223 |> Map.put("url", nil)
224 |> Map.put("uri", nil)
225 |> Map.put("created_at", nil)
226 |> Kernel.put_in(["pleroma", "conversation_id"], nil)
227
228 fake_conn =
229 conn
230 |> post("/api/v1/statuses", %{
231 "status" =>
232 "\"Tenshi Eating a Corndog\" is a much discussed concept on /jp/. The significance of it is disputed, so I will focus on one core concept: the symbolism behind it",
233 "preview" => true
234 })
235
236 fake_status = json_response(fake_conn, 200)
237
238 assert fake_status
239 refute Object.get_by_ap_id(fake_status["uri"])
240
241 fake_status =
242 fake_status
243 |> Map.put("id", nil)
244 |> Map.put("url", nil)
245 |> Map.put("uri", nil)
246 |> Map.put("created_at", nil)
247 |> Kernel.put_in(["pleroma", "conversation_id"], nil)
248
249 assert real_status == fake_status
250 end
251
252 test "posting a status with OGP link preview", %{conn: conn} do
253 Pleroma.Config.put([:rich_media, :enabled], true)
254
255 conn =
256 conn
257 |> post("/api/v1/statuses", %{
258 "status" => "https://example.com/ogp"
259 })
260
261 assert %{"id" => id, "card" => %{"title" => "The Rock"}} = json_response(conn, 200)
262 assert Activity.get_by_id(id)
263 Pleroma.Config.put([:rich_media, :enabled], false)
264 end
265
266 test "posting a direct status", %{conn: conn} do
267 user2 = insert(:user)
268 content = "direct cofe @#{user2.nickname}"
269
270 conn =
271 conn
272 |> post("api/v1/statuses", %{"status" => content, "visibility" => "direct"})
273
274 assert %{"id" => id, "visibility" => "direct"} = json_response(conn, 200)
275 assert activity = Activity.get_by_id(id)
276 assert activity.recipients == [user2.ap_id, conn.assigns[:user].ap_id]
277 assert activity.data["to"] == [user2.ap_id]
278 assert activity.data["cc"] == []
279 end
280 end
281
282 describe "posting polls" do
283 test "posting a poll", %{conn: conn} do
284 user = insert(:user)
285 time = NaiveDateTime.utc_now()
286
287 conn =
288 conn
289 |> assign(:user, user)
290 |> post("/api/v1/statuses", %{
291 "status" => "Who is the #bestgrill?",
292 "poll" => %{"options" => ["Rei", "Asuka", "Misato"], "expires_in" => 420}
293 })
294
295 response = json_response(conn, 200)
296
297 assert Enum.all?(response["poll"]["options"], fn %{"title" => title} ->
298 title in ["Rei", "Asuka", "Misato"]
299 end)
300
301 assert NaiveDateTime.diff(NaiveDateTime.from_iso8601!(response["poll"]["expires_at"]), time) in 420..430
302 refute response["poll"]["expred"]
303 end
304
305 test "option limit is enforced", %{conn: conn} do
306 user = insert(:user)
307 limit = Pleroma.Config.get([:instance, :poll_limits, :max_options])
308
309 conn =
310 conn
311 |> assign(:user, user)
312 |> post("/api/v1/statuses", %{
313 "status" => "desu~",
314 "poll" => %{"options" => Enum.map(0..limit, fn _ -> "desu" end), "expires_in" => 1}
315 })
316
317 %{"error" => error} = json_response(conn, 422)
318 assert error == "Poll can't contain more than #{limit} options"
319 end
320
321 test "option character limit is enforced", %{conn: conn} do
322 user = insert(:user)
323 limit = Pleroma.Config.get([:instance, :poll_limits, :max_option_chars])
324
325 conn =
326 conn
327 |> assign(:user, user)
328 |> post("/api/v1/statuses", %{
329 "status" => "...",
330 "poll" => %{
331 "options" => [Enum.reduce(0..limit, "", fn _, acc -> acc <> "." end)],
332 "expires_in" => 1
333 }
334 })
335
336 %{"error" => error} = json_response(conn, 422)
337 assert error == "Poll options cannot be longer than #{limit} characters each"
338 end
339
340 test "minimal date limit is enforced", %{conn: conn} do
341 user = insert(:user)
342 limit = Pleroma.Config.get([:instance, :poll_limits, :min_expiration])
343
344 conn =
345 conn
346 |> assign(:user, user)
347 |> post("/api/v1/statuses", %{
348 "status" => "imagine arbitrary limits",
349 "poll" => %{
350 "options" => ["this post was made by pleroma gang"],
351 "expires_in" => limit - 1
352 }
353 })
354
355 %{"error" => error} = json_response(conn, 422)
356 assert error == "Expiration date is too soon"
357 end
358
359 test "maximum date limit is enforced", %{conn: conn} do
360 user = insert(:user)
361 limit = Pleroma.Config.get([:instance, :poll_limits, :max_expiration])
362
363 conn =
364 conn
365 |> assign(:user, user)
366 |> post("/api/v1/statuses", %{
367 "status" => "imagine arbitrary limits",
368 "poll" => %{
369 "options" => ["this post was made by pleroma gang"],
370 "expires_in" => limit + 1
371 }
372 })
373
374 %{"error" => error} = json_response(conn, 422)
375 assert error == "Expiration date is too far in the future"
376 end
377 end
378
379 test "direct timeline", %{conn: conn} do
380 user_one = insert(:user)
381 user_two = insert(:user)
382
383 {:ok, user_two} = User.follow(user_two, user_one)
384
385 {:ok, direct} =
386 CommonAPI.post(user_one, %{
387 "status" => "Hi @#{user_two.nickname}!",
388 "visibility" => "direct"
389 })
390
391 {:ok, _follower_only} =
392 CommonAPI.post(user_one, %{
393 "status" => "Hi @#{user_two.nickname}!",
394 "visibility" => "private"
395 })
396
397 # Only direct should be visible here
398 res_conn =
399 conn
400 |> assign(:user, user_two)
401 |> get("api/v1/timelines/direct")
402
403 [status] = json_response(res_conn, 200)
404
405 assert %{"visibility" => "direct"} = status
406 assert status["url"] != direct.data["id"]
407
408 # User should be able to see his own direct message
409 res_conn =
410 build_conn()
411 |> assign(:user, user_one)
412 |> get("api/v1/timelines/direct")
413
414 [status] = json_response(res_conn, 200)
415
416 assert %{"visibility" => "direct"} = status
417
418 # Both should be visible here
419 res_conn =
420 conn
421 |> assign(:user, user_two)
422 |> get("api/v1/timelines/home")
423
424 [_s1, _s2] = json_response(res_conn, 200)
425
426 # Test pagination
427 Enum.each(1..20, fn _ ->
428 {:ok, _} =
429 CommonAPI.post(user_one, %{
430 "status" => "Hi @#{user_two.nickname}!",
431 "visibility" => "direct"
432 })
433 end)
434
435 res_conn =
436 conn
437 |> assign(:user, user_two)
438 |> get("api/v1/timelines/direct")
439
440 statuses = json_response(res_conn, 200)
441 assert length(statuses) == 20
442
443 res_conn =
444 conn
445 |> assign(:user, user_two)
446 |> get("api/v1/timelines/direct", %{max_id: List.last(statuses)["id"]})
447
448 [status] = json_response(res_conn, 200)
449
450 assert status["url"] != direct.data["id"]
451 end
452
453 test "Conversations", %{conn: conn} do
454 user_one = insert(:user)
455 user_two = insert(:user)
456 user_three = insert(:user)
457
458 {:ok, user_two} = User.follow(user_two, user_one)
459
460 {:ok, direct} =
461 CommonAPI.post(user_one, %{
462 "status" => "Hi @#{user_two.nickname}, @#{user_three.nickname}!",
463 "visibility" => "direct"
464 })
465
466 {:ok, _follower_only} =
467 CommonAPI.post(user_one, %{
468 "status" => "Hi @#{user_two.nickname}!",
469 "visibility" => "private"
470 })
471
472 res_conn =
473 conn
474 |> assign(:user, user_one)
475 |> get("/api/v1/conversations")
476
477 assert response = json_response(res_conn, 200)
478
479 assert [
480 %{
481 "id" => res_id,
482 "accounts" => res_accounts,
483 "last_status" => res_last_status,
484 "unread" => unread
485 }
486 ] = response
487
488 account_ids = Enum.map(res_accounts, & &1["id"])
489 assert length(res_accounts) == 2
490 assert user_two.id in account_ids
491 assert user_three.id in account_ids
492 assert is_binary(res_id)
493 assert unread == true
494 assert res_last_status["id"] == direct.id
495
496 # Apparently undocumented API endpoint
497 res_conn =
498 conn
499 |> assign(:user, user_one)
500 |> post("/api/v1/conversations/#{res_id}/read")
501
502 assert response = json_response(res_conn, 200)
503 assert length(response["accounts"]) == 2
504 assert response["last_status"]["id"] == direct.id
505 assert response["unread"] == false
506
507 # (vanilla) Mastodon frontend behaviour
508 res_conn =
509 conn
510 |> assign(:user, user_one)
511 |> get("/api/v1/statuses/#{res_last_status["id"]}/context")
512
513 assert %{"ancestors" => [], "descendants" => []} == json_response(res_conn, 200)
514 end
515
516 test "doesn't include DMs from blocked users", %{conn: conn} do
517 blocker = insert(:user)
518 blocked = insert(:user)
519 user = insert(:user)
520 {:ok, blocker} = User.block(blocker, blocked)
521
522 {:ok, _blocked_direct} =
523 CommonAPI.post(blocked, %{
524 "status" => "Hi @#{blocker.nickname}!",
525 "visibility" => "direct"
526 })
527
528 {:ok, direct} =
529 CommonAPI.post(user, %{
530 "status" => "Hi @#{blocker.nickname}!",
531 "visibility" => "direct"
532 })
533
534 res_conn =
535 conn
536 |> assign(:user, user)
537 |> get("api/v1/timelines/direct")
538
539 [status] = json_response(res_conn, 200)
540 assert status["id"] == direct.id
541 end
542
543 test "verify_credentials", %{conn: conn} do
544 user = insert(:user)
545
546 conn =
547 conn
548 |> assign(:user, user)
549 |> get("/api/v1/accounts/verify_credentials")
550
551 response = json_response(conn, 200)
552
553 assert %{"id" => id, "source" => %{"privacy" => "public"}} = response
554 assert response["pleroma"]["chat_token"]
555 assert id == to_string(user.id)
556 end
557
558 test "verify_credentials default scope unlisted", %{conn: conn} do
559 user = insert(:user, %{info: %User.Info{default_scope: "unlisted"}})
560
561 conn =
562 conn
563 |> assign(:user, user)
564 |> get("/api/v1/accounts/verify_credentials")
565
566 assert %{"id" => id, "source" => %{"privacy" => "unlisted"}} = json_response(conn, 200)
567 assert id == to_string(user.id)
568 end
569
570 test "apps/verify_credentials", %{conn: conn} do
571 token = insert(:oauth_token)
572
573 conn =
574 conn
575 |> assign(:user, token.user)
576 |> assign(:token, token)
577 |> get("/api/v1/apps/verify_credentials")
578
579 app = Repo.preload(token, :app).app
580
581 expected = %{
582 "name" => app.client_name,
583 "website" => app.website,
584 "vapid_key" => Push.vapid_config() |> Keyword.get(:public_key)
585 }
586
587 assert expected == json_response(conn, 200)
588 end
589
590 test "user avatar can be set", %{conn: conn} do
591 user = insert(:user)
592 avatar_image = File.read!("test/fixtures/avatar_data_uri")
593
594 conn =
595 conn
596 |> assign(:user, user)
597 |> patch("/api/v1/pleroma/accounts/update_avatar", %{img: avatar_image})
598
599 user = refresh_record(user)
600
601 assert %{
602 "name" => _,
603 "type" => _,
604 "url" => [
605 %{
606 "href" => _,
607 "mediaType" => _,
608 "type" => _
609 }
610 ]
611 } = user.avatar
612
613 assert %{"url" => _} = json_response(conn, 200)
614 end
615
616 test "user avatar can be reset", %{conn: conn} do
617 user = insert(:user)
618
619 conn =
620 conn
621 |> assign(:user, user)
622 |> patch("/api/v1/pleroma/accounts/update_avatar", %{img: ""})
623
624 user = User.get_cached_by_id(user.id)
625
626 assert user.avatar == nil
627
628 assert %{"url" => nil} = json_response(conn, 200)
629 end
630
631 test "can set profile banner", %{conn: conn} do
632 user = insert(:user)
633
634 conn =
635 conn
636 |> assign(:user, user)
637 |> patch("/api/v1/pleroma/accounts/update_banner", %{"banner" => @image})
638
639 user = refresh_record(user)
640 assert user.info.banner["type"] == "Image"
641
642 assert %{"url" => _} = json_response(conn, 200)
643 end
644
645 test "can reset profile banner", %{conn: conn} do
646 user = insert(:user)
647
648 conn =
649 conn
650 |> assign(:user, user)
651 |> patch("/api/v1/pleroma/accounts/update_banner", %{"banner" => ""})
652
653 user = refresh_record(user)
654 assert user.info.banner == %{}
655
656 assert %{"url" => nil} = json_response(conn, 200)
657 end
658
659 test "background image can be set", %{conn: conn} do
660 user = insert(:user)
661
662 conn =
663 conn
664 |> assign(:user, user)
665 |> patch("/api/v1/pleroma/accounts/update_background", %{"img" => @image})
666
667 user = refresh_record(user)
668 assert user.info.background["type"] == "Image"
669 assert %{"url" => _} = json_response(conn, 200)
670 end
671
672 test "background image can be reset", %{conn: conn} do
673 user = insert(:user)
674
675 conn =
676 conn
677 |> assign(:user, user)
678 |> patch("/api/v1/pleroma/accounts/update_background", %{"img" => ""})
679
680 user = refresh_record(user)
681 assert user.info.background == %{}
682 assert %{"url" => nil} = json_response(conn, 200)
683 end
684
685 test "creates an oauth app", %{conn: conn} do
686 user = insert(:user)
687 app_attrs = build(:oauth_app)
688
689 conn =
690 conn
691 |> assign(:user, user)
692 |> post("/api/v1/apps", %{
693 client_name: app_attrs.client_name,
694 redirect_uris: app_attrs.redirect_uris
695 })
696
697 [app] = Repo.all(App)
698
699 expected = %{
700 "name" => app.client_name,
701 "website" => app.website,
702 "client_id" => app.client_id,
703 "client_secret" => app.client_secret,
704 "id" => app.id |> to_string(),
705 "redirect_uri" => app.redirect_uris,
706 "vapid_key" => Push.vapid_config() |> Keyword.get(:public_key)
707 }
708
709 assert expected == json_response(conn, 200)
710 end
711
712 test "get a status", %{conn: conn} do
713 activity = insert(:note_activity)
714
715 conn =
716 conn
717 |> get("/api/v1/statuses/#{activity.id}")
718
719 assert %{"id" => id} = json_response(conn, 200)
720 assert id == to_string(activity.id)
721 end
722
723 describe "deleting a status" do
724 test "when you created it", %{conn: conn} do
725 activity = insert(:note_activity)
726 author = User.get_cached_by_ap_id(activity.data["actor"])
727
728 conn =
729 conn
730 |> assign(:user, author)
731 |> delete("/api/v1/statuses/#{activity.id}")
732
733 assert %{} = json_response(conn, 200)
734
735 refute Activity.get_by_id(activity.id)
736 end
737
738 test "when you didn't create it", %{conn: conn} do
739 activity = insert(:note_activity)
740 user = insert(:user)
741
742 conn =
743 conn
744 |> assign(:user, user)
745 |> delete("/api/v1/statuses/#{activity.id}")
746
747 assert %{"error" => _} = json_response(conn, 403)
748
749 assert Activity.get_by_id(activity.id) == activity
750 end
751
752 test "when you're an admin or moderator", %{conn: conn} do
753 activity1 = insert(:note_activity)
754 activity2 = insert(:note_activity)
755 admin = insert(:user, info: %{is_admin: true})
756 moderator = insert(:user, info: %{is_moderator: true})
757
758 res_conn =
759 conn
760 |> assign(:user, admin)
761 |> delete("/api/v1/statuses/#{activity1.id}")
762
763 assert %{} = json_response(res_conn, 200)
764
765 res_conn =
766 conn
767 |> assign(:user, moderator)
768 |> delete("/api/v1/statuses/#{activity2.id}")
769
770 assert %{} = json_response(res_conn, 200)
771
772 refute Activity.get_by_id(activity1.id)
773 refute Activity.get_by_id(activity2.id)
774 end
775 end
776
777 describe "filters" do
778 test "creating a filter", %{conn: conn} do
779 user = insert(:user)
780
781 filter = %Pleroma.Filter{
782 phrase: "knights",
783 context: ["home"]
784 }
785
786 conn =
787 conn
788 |> assign(:user, user)
789 |> post("/api/v1/filters", %{"phrase" => filter.phrase, context: filter.context})
790
791 assert response = json_response(conn, 200)
792 assert response["phrase"] == filter.phrase
793 assert response["context"] == filter.context
794 assert response["irreversible"] == false
795 assert response["id"] != nil
796 assert response["id"] != ""
797 end
798
799 test "fetching a list of filters", %{conn: conn} do
800 user = insert(:user)
801
802 query_one = %Pleroma.Filter{
803 user_id: user.id,
804 filter_id: 1,
805 phrase: "knights",
806 context: ["home"]
807 }
808
809 query_two = %Pleroma.Filter{
810 user_id: user.id,
811 filter_id: 2,
812 phrase: "who",
813 context: ["home"]
814 }
815
816 {:ok, filter_one} = Pleroma.Filter.create(query_one)
817 {:ok, filter_two} = Pleroma.Filter.create(query_two)
818
819 response =
820 conn
821 |> assign(:user, user)
822 |> get("/api/v1/filters")
823 |> json_response(200)
824
825 assert response ==
826 render_json(
827 FilterView,
828 "filters.json",
829 filters: [filter_two, filter_one]
830 )
831 end
832
833 test "get a filter", %{conn: conn} do
834 user = insert(:user)
835
836 query = %Pleroma.Filter{
837 user_id: user.id,
838 filter_id: 2,
839 phrase: "knight",
840 context: ["home"]
841 }
842
843 {:ok, filter} = Pleroma.Filter.create(query)
844
845 conn =
846 conn
847 |> assign(:user, user)
848 |> get("/api/v1/filters/#{filter.filter_id}")
849
850 assert _response = json_response(conn, 200)
851 end
852
853 test "update a filter", %{conn: conn} do
854 user = insert(:user)
855
856 query = %Pleroma.Filter{
857 user_id: user.id,
858 filter_id: 2,
859 phrase: "knight",
860 context: ["home"]
861 }
862
863 {:ok, _filter} = Pleroma.Filter.create(query)
864
865 new = %Pleroma.Filter{
866 phrase: "nii",
867 context: ["home"]
868 }
869
870 conn =
871 conn
872 |> assign(:user, user)
873 |> put("/api/v1/filters/#{query.filter_id}", %{
874 phrase: new.phrase,
875 context: new.context
876 })
877
878 assert response = json_response(conn, 200)
879 assert response["phrase"] == new.phrase
880 assert response["context"] == new.context
881 end
882
883 test "delete a filter", %{conn: conn} do
884 user = insert(:user)
885
886 query = %Pleroma.Filter{
887 user_id: user.id,
888 filter_id: 2,
889 phrase: "knight",
890 context: ["home"]
891 }
892
893 {:ok, filter} = Pleroma.Filter.create(query)
894
895 conn =
896 conn
897 |> assign(:user, user)
898 |> delete("/api/v1/filters/#{filter.filter_id}")
899
900 assert response = json_response(conn, 200)
901 assert response == %{}
902 end
903 end
904
905 describe "lists" do
906 test "creating a list", %{conn: conn} do
907 user = insert(:user)
908
909 conn =
910 conn
911 |> assign(:user, user)
912 |> post("/api/v1/lists", %{"title" => "cuties"})
913
914 assert %{"title" => title} = json_response(conn, 200)
915 assert title == "cuties"
916 end
917
918 test "adding users to a list", %{conn: conn} do
919 user = insert(:user)
920 other_user = insert(:user)
921 {:ok, list} = Pleroma.List.create("name", user)
922
923 conn =
924 conn
925 |> assign(:user, user)
926 |> post("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]})
927
928 assert %{} == json_response(conn, 200)
929 %Pleroma.List{following: following} = Pleroma.List.get(list.id, user)
930 assert following == [other_user.follower_address]
931 end
932
933 test "removing users from a list", %{conn: conn} do
934 user = insert(:user)
935 other_user = insert(:user)
936 third_user = insert(:user)
937 {:ok, list} = Pleroma.List.create("name", user)
938 {:ok, list} = Pleroma.List.follow(list, other_user)
939 {:ok, list} = Pleroma.List.follow(list, third_user)
940
941 conn =
942 conn
943 |> assign(:user, user)
944 |> delete("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]})
945
946 assert %{} == json_response(conn, 200)
947 %Pleroma.List{following: following} = Pleroma.List.get(list.id, user)
948 assert following == [third_user.follower_address]
949 end
950
951 test "listing users in a list", %{conn: conn} do
952 user = insert(:user)
953 other_user = insert(:user)
954 {:ok, list} = Pleroma.List.create("name", user)
955 {:ok, list} = Pleroma.List.follow(list, other_user)
956
957 conn =
958 conn
959 |> assign(:user, user)
960 |> get("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]})
961
962 assert [%{"id" => id}] = json_response(conn, 200)
963 assert id == to_string(other_user.id)
964 end
965
966 test "retrieving a list", %{conn: conn} do
967 user = insert(:user)
968 {:ok, list} = Pleroma.List.create("name", user)
969
970 conn =
971 conn
972 |> assign(:user, user)
973 |> get("/api/v1/lists/#{list.id}")
974
975 assert %{"id" => id} = json_response(conn, 200)
976 assert id == to_string(list.id)
977 end
978
979 test "renaming a list", %{conn: conn} do
980 user = insert(:user)
981 {:ok, list} = Pleroma.List.create("name", user)
982
983 conn =
984 conn
985 |> assign(:user, user)
986 |> put("/api/v1/lists/#{list.id}", %{"title" => "newname"})
987
988 assert %{"title" => name} = json_response(conn, 200)
989 assert name == "newname"
990 end
991
992 test "deleting a list", %{conn: conn} do
993 user = insert(:user)
994 {:ok, list} = Pleroma.List.create("name", user)
995
996 conn =
997 conn
998 |> assign(:user, user)
999 |> delete("/api/v1/lists/#{list.id}")
1000
1001 assert %{} = json_response(conn, 200)
1002 assert is_nil(Repo.get(Pleroma.List, list.id))
1003 end
1004
1005 test "list timeline", %{conn: conn} do
1006 user = insert(:user)
1007 other_user = insert(:user)
1008 {:ok, _activity_one} = CommonAPI.post(user, %{"status" => "Marisa is cute."})
1009 {:ok, activity_two} = CommonAPI.post(other_user, %{"status" => "Marisa is cute."})
1010 {:ok, list} = Pleroma.List.create("name", user)
1011 {:ok, list} = Pleroma.List.follow(list, other_user)
1012
1013 conn =
1014 conn
1015 |> assign(:user, user)
1016 |> get("/api/v1/timelines/list/#{list.id}")
1017
1018 assert [%{"id" => id}] = json_response(conn, 200)
1019
1020 assert id == to_string(activity_two.id)
1021 end
1022
1023 test "list timeline does not leak non-public statuses for unfollowed users", %{conn: conn} do
1024 user = insert(:user)
1025 other_user = insert(:user)
1026 {:ok, activity_one} = CommonAPI.post(other_user, %{"status" => "Marisa is cute."})
1027
1028 {:ok, _activity_two} =
1029 CommonAPI.post(other_user, %{
1030 "status" => "Marisa is cute.",
1031 "visibility" => "private"
1032 })
1033
1034 {:ok, list} = Pleroma.List.create("name", user)
1035 {:ok, list} = Pleroma.List.follow(list, other_user)
1036
1037 conn =
1038 conn
1039 |> assign(:user, user)
1040 |> get("/api/v1/timelines/list/#{list.id}")
1041
1042 assert [%{"id" => id}] = json_response(conn, 200)
1043
1044 assert id == to_string(activity_one.id)
1045 end
1046 end
1047
1048 describe "notifications" do
1049 test "list of notifications", %{conn: conn} do
1050 user = insert(:user)
1051 other_user = insert(:user)
1052
1053 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
1054
1055 {:ok, [_notification]} = Notification.create_notifications(activity)
1056
1057 conn =
1058 conn
1059 |> assign(:user, user)
1060 |> get("/api/v1/notifications")
1061
1062 expected_response =
1063 "hi <span class=\"h-card\"><a data-user=\"#{user.id}\" class=\"u-url mention\" href=\"#{
1064 user.ap_id
1065 }\">@<span>#{user.nickname}</span></a></span>"
1066
1067 assert [%{"status" => %{"content" => response}} | _rest] = json_response(conn, 200)
1068 assert response == expected_response
1069 end
1070
1071 test "getting a single notification", %{conn: conn} do
1072 user = insert(:user)
1073 other_user = insert(:user)
1074
1075 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
1076
1077 {:ok, [notification]} = Notification.create_notifications(activity)
1078
1079 conn =
1080 conn
1081 |> assign(:user, user)
1082 |> get("/api/v1/notifications/#{notification.id}")
1083
1084 expected_response =
1085 "hi <span class=\"h-card\"><a data-user=\"#{user.id}\" class=\"u-url mention\" href=\"#{
1086 user.ap_id
1087 }\">@<span>#{user.nickname}</span></a></span>"
1088
1089 assert %{"status" => %{"content" => response}} = json_response(conn, 200)
1090 assert response == expected_response
1091 end
1092
1093 test "dismissing a single notification", %{conn: conn} do
1094 user = insert(:user)
1095 other_user = insert(:user)
1096
1097 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
1098
1099 {:ok, [notification]} = Notification.create_notifications(activity)
1100
1101 conn =
1102 conn
1103 |> assign(:user, user)
1104 |> post("/api/v1/notifications/dismiss", %{"id" => notification.id})
1105
1106 assert %{} = json_response(conn, 200)
1107 end
1108
1109 test "clearing all notifications", %{conn: conn} do
1110 user = insert(:user)
1111 other_user = insert(:user)
1112
1113 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
1114
1115 {:ok, [_notification]} = Notification.create_notifications(activity)
1116
1117 conn =
1118 conn
1119 |> assign(:user, user)
1120 |> post("/api/v1/notifications/clear")
1121
1122 assert %{} = json_response(conn, 200)
1123
1124 conn =
1125 build_conn()
1126 |> assign(:user, user)
1127 |> get("/api/v1/notifications")
1128
1129 assert all = json_response(conn, 200)
1130 assert all == []
1131 end
1132
1133 test "paginates notifications using min_id, since_id, max_id, and limit", %{conn: conn} do
1134 user = insert(:user)
1135 other_user = insert(:user)
1136
1137 {:ok, activity1} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
1138 {:ok, activity2} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
1139 {:ok, activity3} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
1140 {:ok, activity4} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
1141
1142 notification1_id = Repo.get_by(Notification, activity_id: activity1.id).id |> to_string()
1143 notification2_id = Repo.get_by(Notification, activity_id: activity2.id).id |> to_string()
1144 notification3_id = Repo.get_by(Notification, activity_id: activity3.id).id |> to_string()
1145 notification4_id = Repo.get_by(Notification, activity_id: activity4.id).id |> to_string()
1146
1147 conn =
1148 conn
1149 |> assign(:user, user)
1150
1151 # min_id
1152 conn_res =
1153 conn
1154 |> get("/api/v1/notifications?limit=2&min_id=#{notification1_id}")
1155
1156 result = json_response(conn_res, 200)
1157 assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result
1158
1159 # since_id
1160 conn_res =
1161 conn
1162 |> get("/api/v1/notifications?limit=2&since_id=#{notification1_id}")
1163
1164 result = json_response(conn_res, 200)
1165 assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result
1166
1167 # max_id
1168 conn_res =
1169 conn
1170 |> get("/api/v1/notifications?limit=2&max_id=#{notification4_id}")
1171
1172 result = json_response(conn_res, 200)
1173 assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result
1174 end
1175
1176 test "filters notifications using exclude_types", %{conn: conn} do
1177 user = insert(:user)
1178 other_user = insert(:user)
1179
1180 {:ok, mention_activity} = CommonAPI.post(other_user, %{"status" => "hey @#{user.nickname}"})
1181 {:ok, create_activity} = CommonAPI.post(user, %{"status" => "hey"})
1182 {:ok, favorite_activity, _} = CommonAPI.favorite(create_activity.id, other_user)
1183 {:ok, reblog_activity, _} = CommonAPI.repeat(create_activity.id, other_user)
1184 {:ok, _, _, follow_activity} = CommonAPI.follow(other_user, user)
1185
1186 mention_notification_id =
1187 Repo.get_by(Notification, activity_id: mention_activity.id).id |> to_string()
1188
1189 favorite_notification_id =
1190 Repo.get_by(Notification, activity_id: favorite_activity.id).id |> to_string()
1191
1192 reblog_notification_id =
1193 Repo.get_by(Notification, activity_id: reblog_activity.id).id |> to_string()
1194
1195 follow_notification_id =
1196 Repo.get_by(Notification, activity_id: follow_activity.id).id |> to_string()
1197
1198 conn =
1199 conn
1200 |> assign(:user, user)
1201
1202 conn_res =
1203 get(conn, "/api/v1/notifications", %{exclude_types: ["mention", "favourite", "reblog"]})
1204
1205 assert [%{"id" => ^follow_notification_id}] = json_response(conn_res, 200)
1206
1207 conn_res =
1208 get(conn, "/api/v1/notifications", %{exclude_types: ["favourite", "reblog", "follow"]})
1209
1210 assert [%{"id" => ^mention_notification_id}] = json_response(conn_res, 200)
1211
1212 conn_res =
1213 get(conn, "/api/v1/notifications", %{exclude_types: ["reblog", "follow", "mention"]})
1214
1215 assert [%{"id" => ^favorite_notification_id}] = json_response(conn_res, 200)
1216
1217 conn_res =
1218 get(conn, "/api/v1/notifications", %{exclude_types: ["follow", "mention", "favourite"]})
1219
1220 assert [%{"id" => ^reblog_notification_id}] = json_response(conn_res, 200)
1221 end
1222
1223 test "destroy multiple", %{conn: conn} do
1224 user = insert(:user)
1225 other_user = insert(:user)
1226
1227 {:ok, activity1} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
1228 {:ok, activity2} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
1229 {:ok, activity3} = CommonAPI.post(user, %{"status" => "hi @#{other_user.nickname}"})
1230 {:ok, activity4} = CommonAPI.post(user, %{"status" => "hi @#{other_user.nickname}"})
1231
1232 notification1_id = Repo.get_by(Notification, activity_id: activity1.id).id |> to_string()
1233 notification2_id = Repo.get_by(Notification, activity_id: activity2.id).id |> to_string()
1234 notification3_id = Repo.get_by(Notification, activity_id: activity3.id).id |> to_string()
1235 notification4_id = Repo.get_by(Notification, activity_id: activity4.id).id |> to_string()
1236
1237 conn =
1238 conn
1239 |> assign(:user, user)
1240
1241 conn_res =
1242 conn
1243 |> get("/api/v1/notifications")
1244
1245 result = json_response(conn_res, 200)
1246 assert [%{"id" => ^notification2_id}, %{"id" => ^notification1_id}] = result
1247
1248 conn2 =
1249 conn
1250 |> assign(:user, other_user)
1251
1252 conn_res =
1253 conn2
1254 |> get("/api/v1/notifications")
1255
1256 result = json_response(conn_res, 200)
1257 assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result
1258
1259 conn_destroy =
1260 conn
1261 |> delete("/api/v1/notifications/destroy_multiple", %{
1262 "ids" => [notification1_id, notification2_id]
1263 })
1264
1265 assert json_response(conn_destroy, 200) == %{}
1266
1267 conn_res =
1268 conn2
1269 |> get("/api/v1/notifications")
1270
1271 result = json_response(conn_res, 200)
1272 assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result
1273 end
1274
1275 test "doesn't see notifications after muting user with notifications", %{conn: conn} do
1276 user = insert(:user)
1277 user2 = insert(:user)
1278
1279 {:ok, _, _, _} = CommonAPI.follow(user, user2)
1280 {:ok, _} = CommonAPI.post(user2, %{"status" => "hey @#{user.nickname}"})
1281
1282 conn = assign(conn, :user, user)
1283
1284 conn = get(conn, "/api/v1/notifications")
1285
1286 assert length(json_response(conn, 200)) == 1
1287
1288 {:ok, user} = User.mute(user, user2)
1289
1290 conn = assign(build_conn(), :user, user)
1291 conn = get(conn, "/api/v1/notifications")
1292
1293 assert json_response(conn, 200) == []
1294 end
1295
1296 test "see notifications after muting user without notifications", %{conn: conn} do
1297 user = insert(:user)
1298 user2 = insert(:user)
1299
1300 {:ok, _, _, _} = CommonAPI.follow(user, user2)
1301 {:ok, _} = CommonAPI.post(user2, %{"status" => "hey @#{user.nickname}"})
1302
1303 conn = assign(conn, :user, user)
1304
1305 conn = get(conn, "/api/v1/notifications")
1306
1307 assert length(json_response(conn, 200)) == 1
1308
1309 {:ok, user} = User.mute(user, user2, false)
1310
1311 conn = assign(build_conn(), :user, user)
1312 conn = get(conn, "/api/v1/notifications")
1313
1314 assert length(json_response(conn, 200)) == 1
1315 end
1316
1317 test "see notifications after muting user with notifications and with_muted parameter", %{
1318 conn: conn
1319 } do
1320 user = insert(:user)
1321 user2 = insert(:user)
1322
1323 {:ok, _, _, _} = CommonAPI.follow(user, user2)
1324 {:ok, _} = CommonAPI.post(user2, %{"status" => "hey @#{user.nickname}"})
1325
1326 conn = assign(conn, :user, user)
1327
1328 conn = get(conn, "/api/v1/notifications")
1329
1330 assert length(json_response(conn, 200)) == 1
1331
1332 {:ok, user} = User.mute(user, user2)
1333
1334 conn = assign(build_conn(), :user, user)
1335 conn = get(conn, "/api/v1/notifications", %{"with_muted" => "true"})
1336
1337 assert length(json_response(conn, 200)) == 1
1338 end
1339 end
1340
1341 describe "reblogging" do
1342 test "reblogs and returns the reblogged status", %{conn: conn} do
1343 activity = insert(:note_activity)
1344 user = insert(:user)
1345
1346 conn =
1347 conn
1348 |> assign(:user, user)
1349 |> post("/api/v1/statuses/#{activity.id}/reblog")
1350
1351 assert %{
1352 "reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1},
1353 "reblogged" => true
1354 } = json_response(conn, 200)
1355
1356 assert to_string(activity.id) == id
1357 end
1358
1359 test "reblogged status for another user", %{conn: conn} do
1360 activity = insert(:note_activity)
1361 user1 = insert(:user)
1362 user2 = insert(:user)
1363 user3 = insert(:user)
1364 CommonAPI.favorite(activity.id, user2)
1365 {:ok, _bookmark} = Pleroma.Bookmark.create(user2.id, activity.id)
1366 {:ok, reblog_activity1, _object} = CommonAPI.repeat(activity.id, user1)
1367 {:ok, _, _object} = CommonAPI.repeat(activity.id, user2)
1368
1369 conn_res =
1370 conn
1371 |> assign(:user, user3)
1372 |> get("/api/v1/statuses/#{reblog_activity1.id}")
1373
1374 assert %{
1375 "reblog" => %{"id" => id, "reblogged" => false, "reblogs_count" => 2},
1376 "reblogged" => false,
1377 "favourited" => false,
1378 "bookmarked" => false
1379 } = json_response(conn_res, 200)
1380
1381 conn_res =
1382 conn
1383 |> assign(:user, user2)
1384 |> get("/api/v1/statuses/#{reblog_activity1.id}")
1385
1386 assert %{
1387 "reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 2},
1388 "reblogged" => true,
1389 "favourited" => true,
1390 "bookmarked" => true
1391 } = json_response(conn_res, 200)
1392
1393 assert to_string(activity.id) == id
1394 end
1395
1396 test "returns 400 error when activity is not exist", %{conn: conn} do
1397 user = insert(:user)
1398
1399 conn =
1400 conn
1401 |> assign(:user, user)
1402 |> post("/api/v1/statuses/foo/reblog")
1403
1404 assert json_response(conn, 400) == %{"error" => "Could not repeat"}
1405 end
1406 end
1407
1408 describe "unreblogging" do
1409 test "unreblogs and returns the unreblogged status", %{conn: conn} do
1410 activity = insert(:note_activity)
1411 user = insert(:user)
1412
1413 {:ok, _, _} = CommonAPI.repeat(activity.id, user)
1414
1415 conn =
1416 conn
1417 |> assign(:user, user)
1418 |> post("/api/v1/statuses/#{activity.id}/unreblog")
1419
1420 assert %{"id" => id, "reblogged" => false, "reblogs_count" => 0} = json_response(conn, 200)
1421
1422 assert to_string(activity.id) == id
1423 end
1424
1425 test "returns 400 error when activity is not exist", %{conn: conn} do
1426 user = insert(:user)
1427
1428 conn =
1429 conn
1430 |> assign(:user, user)
1431 |> post("/api/v1/statuses/foo/unreblog")
1432
1433 assert json_response(conn, 400) == %{"error" => "Could not unrepeat"}
1434 end
1435 end
1436
1437 describe "favoriting" do
1438 test "favs a status and returns it", %{conn: conn} do
1439 activity = insert(:note_activity)
1440 user = insert(:user)
1441
1442 conn =
1443 conn
1444 |> assign(:user, user)
1445 |> post("/api/v1/statuses/#{activity.id}/favourite")
1446
1447 assert %{"id" => id, "favourites_count" => 1, "favourited" => true} =
1448 json_response(conn, 200)
1449
1450 assert to_string(activity.id) == id
1451 end
1452
1453 test "returns 400 error for a wrong id", %{conn: conn} do
1454 user = insert(:user)
1455
1456 conn =
1457 conn
1458 |> assign(:user, user)
1459 |> post("/api/v1/statuses/1/favourite")
1460
1461 assert json_response(conn, 400) == %{"error" => "Could not favorite"}
1462 end
1463 end
1464
1465 describe "unfavoriting" do
1466 test "unfavorites a status and returns it", %{conn: conn} do
1467 activity = insert(:note_activity)
1468 user = insert(:user)
1469
1470 {:ok, _, _} = CommonAPI.favorite(activity.id, user)
1471
1472 conn =
1473 conn
1474 |> assign(:user, user)
1475 |> post("/api/v1/statuses/#{activity.id}/unfavourite")
1476
1477 assert %{"id" => id, "favourites_count" => 0, "favourited" => false} =
1478 json_response(conn, 200)
1479
1480 assert to_string(activity.id) == id
1481 end
1482
1483 test "returns 400 error for a wrong id", %{conn: conn} do
1484 user = insert(:user)
1485
1486 conn =
1487 conn
1488 |> assign(:user, user)
1489 |> post("/api/v1/statuses/1/unfavourite")
1490
1491 assert json_response(conn, 400) == %{"error" => "Could not unfavorite"}
1492 end
1493 end
1494
1495 describe "user timelines" do
1496 test "gets a users statuses", %{conn: conn} do
1497 user_one = insert(:user)
1498 user_two = insert(:user)
1499 user_three = insert(:user)
1500
1501 {:ok, user_three} = User.follow(user_three, user_one)
1502
1503 {:ok, activity} = CommonAPI.post(user_one, %{"status" => "HI!!!"})
1504
1505 {:ok, direct_activity} =
1506 CommonAPI.post(user_one, %{
1507 "status" => "Hi, @#{user_two.nickname}.",
1508 "visibility" => "direct"
1509 })
1510
1511 {:ok, private_activity} =
1512 CommonAPI.post(user_one, %{"status" => "private", "visibility" => "private"})
1513
1514 resp =
1515 conn
1516 |> get("/api/v1/accounts/#{user_one.id}/statuses")
1517
1518 assert [%{"id" => id}] = json_response(resp, 200)
1519 assert id == to_string(activity.id)
1520
1521 resp =
1522 conn
1523 |> assign(:user, user_two)
1524 |> get("/api/v1/accounts/#{user_one.id}/statuses")
1525
1526 assert [%{"id" => id_one}, %{"id" => id_two}] = json_response(resp, 200)
1527 assert id_one == to_string(direct_activity.id)
1528 assert id_two == to_string(activity.id)
1529
1530 resp =
1531 conn
1532 |> assign(:user, user_three)
1533 |> get("/api/v1/accounts/#{user_one.id}/statuses")
1534
1535 assert [%{"id" => id_one}, %{"id" => id_two}] = json_response(resp, 200)
1536 assert id_one == to_string(private_activity.id)
1537 assert id_two == to_string(activity.id)
1538 end
1539
1540 test "unimplemented pinned statuses feature", %{conn: conn} do
1541 note = insert(:note_activity)
1542 user = User.get_cached_by_ap_id(note.data["actor"])
1543
1544 conn =
1545 conn
1546 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
1547
1548 assert json_response(conn, 200) == []
1549 end
1550
1551 test "gets an users media", %{conn: conn} do
1552 note = insert(:note_activity)
1553 user = User.get_cached_by_ap_id(note.data["actor"])
1554
1555 file = %Plug.Upload{
1556 content_type: "image/jpg",
1557 path: Path.absname("test/fixtures/image.jpg"),
1558 filename: "an_image.jpg"
1559 }
1560
1561 media =
1562 TwitterAPI.upload(file, user, "json")
1563 |> Jason.decode!()
1564
1565 {:ok, image_post} =
1566 CommonAPI.post(user, %{"status" => "cofe", "media_ids" => [media["media_id"]]})
1567
1568 conn =
1569 conn
1570 |> get("/api/v1/accounts/#{user.id}/statuses", %{"only_media" => "true"})
1571
1572 assert [%{"id" => id}] = json_response(conn, 200)
1573 assert id == to_string(image_post.id)
1574
1575 conn =
1576 build_conn()
1577 |> get("/api/v1/accounts/#{user.id}/statuses", %{"only_media" => "1"})
1578
1579 assert [%{"id" => id}] = json_response(conn, 200)
1580 assert id == to_string(image_post.id)
1581 end
1582
1583 test "gets a user's statuses without reblogs", %{conn: conn} do
1584 user = insert(:user)
1585 {:ok, post} = CommonAPI.post(user, %{"status" => "HI!!!"})
1586 {:ok, _, _} = CommonAPI.repeat(post.id, user)
1587
1588 conn =
1589 conn
1590 |> get("/api/v1/accounts/#{user.id}/statuses", %{"exclude_reblogs" => "true"})
1591
1592 assert [%{"id" => id}] = json_response(conn, 200)
1593 assert id == to_string(post.id)
1594
1595 conn =
1596 conn
1597 |> get("/api/v1/accounts/#{user.id}/statuses", %{"exclude_reblogs" => "1"})
1598
1599 assert [%{"id" => id}] = json_response(conn, 200)
1600 assert id == to_string(post.id)
1601 end
1602
1603 test "filters user's statuses by a hashtag", %{conn: conn} do
1604 user = insert(:user)
1605 {:ok, post} = CommonAPI.post(user, %{"status" => "#hashtag"})
1606 {:ok, _post} = CommonAPI.post(user, %{"status" => "hashtag"})
1607
1608 conn =
1609 conn
1610 |> get("/api/v1/accounts/#{user.id}/statuses", %{"tagged" => "hashtag"})
1611
1612 assert [%{"id" => id}] = json_response(conn, 200)
1613 assert id == to_string(post.id)
1614 end
1615 end
1616
1617 describe "user relationships" do
1618 test "returns the relationships for the current user", %{conn: conn} do
1619 user = insert(:user)
1620 other_user = insert(:user)
1621 {:ok, user} = User.follow(user, other_user)
1622
1623 conn =
1624 conn
1625 |> assign(:user, user)
1626 |> get("/api/v1/accounts/relationships", %{"id" => [other_user.id]})
1627
1628 assert [relationship] = json_response(conn, 200)
1629
1630 assert to_string(other_user.id) == relationship["id"]
1631 end
1632 end
1633
1634 describe "media upload" do
1635 setup do
1636 upload_config = Pleroma.Config.get([Pleroma.Upload])
1637 proxy_config = Pleroma.Config.get([:media_proxy])
1638
1639 on_exit(fn ->
1640 Pleroma.Config.put([Pleroma.Upload], upload_config)
1641 Pleroma.Config.put([:media_proxy], proxy_config)
1642 end)
1643
1644 user = insert(:user)
1645
1646 conn =
1647 build_conn()
1648 |> assign(:user, user)
1649
1650 image = %Plug.Upload{
1651 content_type: "image/jpg",
1652 path: Path.absname("test/fixtures/image.jpg"),
1653 filename: "an_image.jpg"
1654 }
1655
1656 [conn: conn, image: image]
1657 end
1658
1659 test "returns uploaded image", %{conn: conn, image: image} do
1660 desc = "Description of the image"
1661
1662 media =
1663 conn
1664 |> post("/api/v1/media", %{"file" => image, "description" => desc})
1665 |> json_response(:ok)
1666
1667 assert media["type"] == "image"
1668 assert media["description"] == desc
1669 assert media["id"]
1670
1671 object = Repo.get(Object, media["id"])
1672 assert object.data["actor"] == User.ap_id(conn.assigns[:user])
1673 end
1674 end
1675
1676 describe "locked accounts" do
1677 test "/api/v1/follow_requests works" do
1678 user = insert(:user, %{info: %User.Info{locked: true}})
1679 other_user = insert(:user)
1680
1681 {:ok, _activity} = ActivityPub.follow(other_user, user)
1682
1683 user = User.get_cached_by_id(user.id)
1684 other_user = User.get_cached_by_id(other_user.id)
1685
1686 assert User.following?(other_user, user) == false
1687
1688 conn =
1689 build_conn()
1690 |> assign(:user, user)
1691 |> get("/api/v1/follow_requests")
1692
1693 assert [relationship] = json_response(conn, 200)
1694 assert to_string(other_user.id) == relationship["id"]
1695 end
1696
1697 test "/api/v1/follow_requests/:id/authorize works" do
1698 user = insert(:user, %{info: %User.Info{locked: true}})
1699 other_user = insert(:user)
1700
1701 {:ok, _activity} = ActivityPub.follow(other_user, user)
1702
1703 user = User.get_cached_by_id(user.id)
1704 other_user = User.get_cached_by_id(other_user.id)
1705
1706 assert User.following?(other_user, user) == false
1707
1708 conn =
1709 build_conn()
1710 |> assign(:user, user)
1711 |> post("/api/v1/follow_requests/#{other_user.id}/authorize")
1712
1713 assert relationship = json_response(conn, 200)
1714 assert to_string(other_user.id) == relationship["id"]
1715
1716 user = User.get_cached_by_id(user.id)
1717 other_user = User.get_cached_by_id(other_user.id)
1718
1719 assert User.following?(other_user, user) == true
1720 end
1721
1722 test "verify_credentials", %{conn: conn} do
1723 user = insert(:user, %{info: %User.Info{default_scope: "private"}})
1724
1725 conn =
1726 conn
1727 |> assign(:user, user)
1728 |> get("/api/v1/accounts/verify_credentials")
1729
1730 assert %{"id" => id, "source" => %{"privacy" => "private"}} = json_response(conn, 200)
1731 assert id == to_string(user.id)
1732 end
1733
1734 test "/api/v1/follow_requests/:id/reject works" do
1735 user = insert(:user, %{info: %User.Info{locked: true}})
1736 other_user = insert(:user)
1737
1738 {:ok, _activity} = ActivityPub.follow(other_user, user)
1739
1740 user = User.get_cached_by_id(user.id)
1741
1742 conn =
1743 build_conn()
1744 |> assign(:user, user)
1745 |> post("/api/v1/follow_requests/#{other_user.id}/reject")
1746
1747 assert relationship = json_response(conn, 200)
1748 assert to_string(other_user.id) == relationship["id"]
1749
1750 user = User.get_cached_by_id(user.id)
1751 other_user = User.get_cached_by_id(other_user.id)
1752
1753 assert User.following?(other_user, user) == false
1754 end
1755 end
1756
1757 test "account fetching", %{conn: conn} do
1758 user = insert(:user)
1759
1760 conn =
1761 conn
1762 |> get("/api/v1/accounts/#{user.id}")
1763
1764 assert %{"id" => id} = json_response(conn, 200)
1765 assert id == to_string(user.id)
1766
1767 conn =
1768 build_conn()
1769 |> get("/api/v1/accounts/-1")
1770
1771 assert %{"error" => "Can't find user"} = json_response(conn, 404)
1772 end
1773
1774 test "account fetching also works nickname", %{conn: conn} do
1775 user = insert(:user)
1776
1777 conn =
1778 conn
1779 |> get("/api/v1/accounts/#{user.nickname}")
1780
1781 assert %{"id" => id} = json_response(conn, 200)
1782 assert id == user.id
1783 end
1784
1785 test "mascot upload", %{conn: conn} do
1786 user = insert(:user)
1787
1788 non_image_file = %Plug.Upload{
1789 content_type: "audio/mpeg",
1790 path: Path.absname("test/fixtures/sound.mp3"),
1791 filename: "sound.mp3"
1792 }
1793
1794 conn =
1795 conn
1796 |> assign(:user, user)
1797 |> put("/api/v1/pleroma/mascot", %{"file" => non_image_file})
1798
1799 assert json_response(conn, 415)
1800
1801 file = %Plug.Upload{
1802 content_type: "image/jpg",
1803 path: Path.absname("test/fixtures/image.jpg"),
1804 filename: "an_image.jpg"
1805 }
1806
1807 conn =
1808 build_conn()
1809 |> assign(:user, user)
1810 |> put("/api/v1/pleroma/mascot", %{"file" => file})
1811
1812 assert %{"id" => _, "type" => image} = json_response(conn, 200)
1813 end
1814
1815 test "mascot retrieving", %{conn: conn} do
1816 user = insert(:user)
1817 # When user hasn't set a mascot, we should just get pleroma tan back
1818 conn =
1819 conn
1820 |> assign(:user, user)
1821 |> get("/api/v1/pleroma/mascot")
1822
1823 assert %{"url" => url} = json_response(conn, 200)
1824 assert url =~ "pleroma-fox-tan-smol"
1825
1826 # When a user sets their mascot, we should get that back
1827 file = %Plug.Upload{
1828 content_type: "image/jpg",
1829 path: Path.absname("test/fixtures/image.jpg"),
1830 filename: "an_image.jpg"
1831 }
1832
1833 conn =
1834 build_conn()
1835 |> assign(:user, user)
1836 |> put("/api/v1/pleroma/mascot", %{"file" => file})
1837
1838 assert json_response(conn, 200)
1839
1840 user = User.get_cached_by_id(user.id)
1841
1842 conn =
1843 build_conn()
1844 |> assign(:user, user)
1845 |> get("/api/v1/pleroma/mascot")
1846
1847 assert %{"url" => url, "type" => "image"} = json_response(conn, 200)
1848 assert url =~ "an_image"
1849 end
1850
1851 test "hashtag timeline", %{conn: conn} do
1852 following = insert(:user)
1853
1854 capture_log(fn ->
1855 {:ok, activity} = CommonAPI.post(following, %{"status" => "test #2hu"})
1856
1857 {:ok, [_activity]} =
1858 OStatus.fetch_activity_from_url("https://shitposter.club/notice/2827873")
1859
1860 nconn =
1861 conn
1862 |> get("/api/v1/timelines/tag/2hu")
1863
1864 assert [%{"id" => id}] = json_response(nconn, 200)
1865
1866 assert id == to_string(activity.id)
1867
1868 # works for different capitalization too
1869 nconn =
1870 conn
1871 |> get("/api/v1/timelines/tag/2HU")
1872
1873 assert [%{"id" => id}] = json_response(nconn, 200)
1874
1875 assert id == to_string(activity.id)
1876 end)
1877 end
1878
1879 test "multi-hashtag timeline", %{conn: conn} do
1880 user = insert(:user)
1881
1882 {:ok, activity_test} = CommonAPI.post(user, %{"status" => "#test"})
1883 {:ok, activity_test1} = CommonAPI.post(user, %{"status" => "#test #test1"})
1884 {:ok, activity_none} = CommonAPI.post(user, %{"status" => "#test #none"})
1885
1886 any_test =
1887 conn
1888 |> get("/api/v1/timelines/tag/test", %{"any" => ["test1"]})
1889
1890 [status_none, status_test1, status_test] = json_response(any_test, 200)
1891
1892 assert to_string(activity_test.id) == status_test["id"]
1893 assert to_string(activity_test1.id) == status_test1["id"]
1894 assert to_string(activity_none.id) == status_none["id"]
1895
1896 restricted_test =
1897 conn
1898 |> get("/api/v1/timelines/tag/test", %{"all" => ["test1"], "none" => ["none"]})
1899
1900 assert [status_test1] == json_response(restricted_test, 200)
1901
1902 all_test = conn |> get("/api/v1/timelines/tag/test", %{"all" => ["none"]})
1903
1904 assert [status_none] == json_response(all_test, 200)
1905 end
1906
1907 test "getting followers", %{conn: conn} do
1908 user = insert(:user)
1909 other_user = insert(:user)
1910 {:ok, user} = User.follow(user, other_user)
1911
1912 conn =
1913 conn
1914 |> get("/api/v1/accounts/#{other_user.id}/followers")
1915
1916 assert [%{"id" => id}] = json_response(conn, 200)
1917 assert id == to_string(user.id)
1918 end
1919
1920 test "getting followers, hide_followers", %{conn: conn} do
1921 user = insert(:user)
1922 other_user = insert(:user, %{info: %{hide_followers: true}})
1923 {:ok, _user} = User.follow(user, other_user)
1924
1925 conn =
1926 conn
1927 |> get("/api/v1/accounts/#{other_user.id}/followers")
1928
1929 assert [] == json_response(conn, 200)
1930 end
1931
1932 test "getting followers, hide_followers, same user requesting", %{conn: conn} do
1933 user = insert(:user)
1934 other_user = insert(:user, %{info: %{hide_followers: true}})
1935 {:ok, _user} = User.follow(user, other_user)
1936
1937 conn =
1938 conn
1939 |> assign(:user, other_user)
1940 |> get("/api/v1/accounts/#{other_user.id}/followers")
1941
1942 refute [] == json_response(conn, 200)
1943 end
1944
1945 test "getting followers, pagination", %{conn: conn} do
1946 user = insert(:user)
1947 follower1 = insert(:user)
1948 follower2 = insert(:user)
1949 follower3 = insert(:user)
1950 {:ok, _} = User.follow(follower1, user)
1951 {:ok, _} = User.follow(follower2, user)
1952 {:ok, _} = User.follow(follower3, user)
1953
1954 conn =
1955 conn
1956 |> assign(:user, user)
1957
1958 res_conn =
1959 conn
1960 |> get("/api/v1/accounts/#{user.id}/followers?since_id=#{follower1.id}")
1961
1962 assert [%{"id" => id3}, %{"id" => id2}] = json_response(res_conn, 200)
1963 assert id3 == follower3.id
1964 assert id2 == follower2.id
1965
1966 res_conn =
1967 conn
1968 |> get("/api/v1/accounts/#{user.id}/followers?max_id=#{follower3.id}")
1969
1970 assert [%{"id" => id2}, %{"id" => id1}] = json_response(res_conn, 200)
1971 assert id2 == follower2.id
1972 assert id1 == follower1.id
1973
1974 res_conn =
1975 conn
1976 |> get("/api/v1/accounts/#{user.id}/followers?limit=1&max_id=#{follower3.id}")
1977
1978 assert [%{"id" => id2}] = json_response(res_conn, 200)
1979 assert id2 == follower2.id
1980
1981 assert [link_header] = get_resp_header(res_conn, "link")
1982 assert link_header =~ ~r/min_id=#{follower2.id}/
1983 assert link_header =~ ~r/max_id=#{follower2.id}/
1984 end
1985
1986 test "getting following", %{conn: conn} do
1987 user = insert(:user)
1988 other_user = insert(:user)
1989 {:ok, user} = User.follow(user, other_user)
1990
1991 conn =
1992 conn
1993 |> get("/api/v1/accounts/#{user.id}/following")
1994
1995 assert [%{"id" => id}] = json_response(conn, 200)
1996 assert id == to_string(other_user.id)
1997 end
1998
1999 test "getting following, hide_follows", %{conn: conn} do
2000 user = insert(:user, %{info: %{hide_follows: true}})
2001 other_user = insert(:user)
2002 {:ok, user} = User.follow(user, other_user)
2003
2004 conn =
2005 conn
2006 |> get("/api/v1/accounts/#{user.id}/following")
2007
2008 assert [] == json_response(conn, 200)
2009 end
2010
2011 test "getting following, hide_follows, same user requesting", %{conn: conn} do
2012 user = insert(:user, %{info: %{hide_follows: true}})
2013 other_user = insert(:user)
2014 {:ok, user} = User.follow(user, other_user)
2015
2016 conn =
2017 conn
2018 |> assign(:user, user)
2019 |> get("/api/v1/accounts/#{user.id}/following")
2020
2021 refute [] == json_response(conn, 200)
2022 end
2023
2024 test "getting following, pagination", %{conn: conn} do
2025 user = insert(:user)
2026 following1 = insert(:user)
2027 following2 = insert(:user)
2028 following3 = insert(:user)
2029 {:ok, _} = User.follow(user, following1)
2030 {:ok, _} = User.follow(user, following2)
2031 {:ok, _} = User.follow(user, following3)
2032
2033 conn =
2034 conn
2035 |> assign(:user, user)
2036
2037 res_conn =
2038 conn
2039 |> get("/api/v1/accounts/#{user.id}/following?since_id=#{following1.id}")
2040
2041 assert [%{"id" => id3}, %{"id" => id2}] = json_response(res_conn, 200)
2042 assert id3 == following3.id
2043 assert id2 == following2.id
2044
2045 res_conn =
2046 conn
2047 |> get("/api/v1/accounts/#{user.id}/following?max_id=#{following3.id}")
2048
2049 assert [%{"id" => id2}, %{"id" => id1}] = json_response(res_conn, 200)
2050 assert id2 == following2.id
2051 assert id1 == following1.id
2052
2053 res_conn =
2054 conn
2055 |> get("/api/v1/accounts/#{user.id}/following?limit=1&max_id=#{following3.id}")
2056
2057 assert [%{"id" => id2}] = json_response(res_conn, 200)
2058 assert id2 == following2.id
2059
2060 assert [link_header] = get_resp_header(res_conn, "link")
2061 assert link_header =~ ~r/min_id=#{following2.id}/
2062 assert link_header =~ ~r/max_id=#{following2.id}/
2063 end
2064
2065 test "following / unfollowing a user", %{conn: conn} do
2066 user = insert(:user)
2067 other_user = insert(:user)
2068
2069 conn =
2070 conn
2071 |> assign(:user, user)
2072 |> post("/api/v1/accounts/#{other_user.id}/follow")
2073
2074 assert %{"id" => _id, "following" => true} = json_response(conn, 200)
2075
2076 user = User.get_cached_by_id(user.id)
2077
2078 conn =
2079 build_conn()
2080 |> assign(:user, user)
2081 |> post("/api/v1/accounts/#{other_user.id}/unfollow")
2082
2083 assert %{"id" => _id, "following" => false} = json_response(conn, 200)
2084
2085 user = User.get_cached_by_id(user.id)
2086
2087 conn =
2088 build_conn()
2089 |> assign(:user, user)
2090 |> post("/api/v1/follows", %{"uri" => other_user.nickname})
2091
2092 assert %{"id" => id} = json_response(conn, 200)
2093 assert id == to_string(other_user.id)
2094 end
2095
2096 test "following without reblogs" do
2097 follower = insert(:user)
2098 followed = insert(:user)
2099 other_user = insert(:user)
2100
2101 conn =
2102 build_conn()
2103 |> assign(:user, follower)
2104 |> post("/api/v1/accounts/#{followed.id}/follow?reblogs=false")
2105
2106 assert %{"showing_reblogs" => false} = json_response(conn, 200)
2107
2108 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hey"})
2109 {:ok, reblog, _} = CommonAPI.repeat(activity.id, followed)
2110
2111 conn =
2112 build_conn()
2113 |> assign(:user, User.get_cached_by_id(follower.id))
2114 |> get("/api/v1/timelines/home")
2115
2116 assert [] == json_response(conn, 200)
2117
2118 conn =
2119 build_conn()
2120 |> assign(:user, follower)
2121 |> post("/api/v1/accounts/#{followed.id}/follow?reblogs=true")
2122
2123 assert %{"showing_reblogs" => true} = json_response(conn, 200)
2124
2125 conn =
2126 build_conn()
2127 |> assign(:user, User.get_cached_by_id(follower.id))
2128 |> get("/api/v1/timelines/home")
2129
2130 expected_activity_id = reblog.id
2131 assert [%{"id" => ^expected_activity_id}] = json_response(conn, 200)
2132 end
2133
2134 test "following / unfollowing errors" do
2135 user = insert(:user)
2136
2137 conn =
2138 build_conn()
2139 |> assign(:user, user)
2140
2141 # self follow
2142 conn_res = post(conn, "/api/v1/accounts/#{user.id}/follow")
2143 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
2144
2145 # self unfollow
2146 user = User.get_cached_by_id(user.id)
2147 conn_res = post(conn, "/api/v1/accounts/#{user.id}/unfollow")
2148 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
2149
2150 # self follow via uri
2151 user = User.get_cached_by_id(user.id)
2152 conn_res = post(conn, "/api/v1/follows", %{"uri" => user.nickname})
2153 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
2154
2155 # follow non existing user
2156 conn_res = post(conn, "/api/v1/accounts/doesntexist/follow")
2157 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
2158
2159 # follow non existing user via uri
2160 conn_res = post(conn, "/api/v1/follows", %{"uri" => "doesntexist"})
2161 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
2162
2163 # unfollow non existing user
2164 conn_res = post(conn, "/api/v1/accounts/doesntexist/unfollow")
2165 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
2166 end
2167
2168 describe "mute/unmute" do
2169 test "with notifications", %{conn: conn} do
2170 user = insert(:user)
2171 other_user = insert(:user)
2172
2173 conn =
2174 conn
2175 |> assign(:user, user)
2176 |> post("/api/v1/accounts/#{other_user.id}/mute")
2177
2178 response = json_response(conn, 200)
2179
2180 assert %{"id" => _id, "muting" => true, "muting_notifications" => true} = response
2181 user = User.get_cached_by_id(user.id)
2182
2183 conn =
2184 build_conn()
2185 |> assign(:user, user)
2186 |> post("/api/v1/accounts/#{other_user.id}/unmute")
2187
2188 response = json_response(conn, 200)
2189 assert %{"id" => _id, "muting" => false, "muting_notifications" => false} = response
2190 end
2191
2192 test "without notifications", %{conn: conn} do
2193 user = insert(:user)
2194 other_user = insert(:user)
2195
2196 conn =
2197 conn
2198 |> assign(:user, user)
2199 |> post("/api/v1/accounts/#{other_user.id}/mute", %{"notifications" => "false"})
2200
2201 response = json_response(conn, 200)
2202
2203 assert %{"id" => _id, "muting" => true, "muting_notifications" => false} = response
2204 user = User.get_cached_by_id(user.id)
2205
2206 conn =
2207 build_conn()
2208 |> assign(:user, user)
2209 |> post("/api/v1/accounts/#{other_user.id}/unmute")
2210
2211 response = json_response(conn, 200)
2212 assert %{"id" => _id, "muting" => false, "muting_notifications" => false} = response
2213 end
2214 end
2215
2216 test "subscribing / unsubscribing to a user", %{conn: conn} do
2217 user = insert(:user)
2218 subscription_target = insert(:user)
2219
2220 conn =
2221 conn
2222 |> assign(:user, user)
2223 |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/subscribe")
2224
2225 assert %{"id" => _id, "subscribing" => true} = json_response(conn, 200)
2226
2227 conn =
2228 build_conn()
2229 |> assign(:user, user)
2230 |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/unsubscribe")
2231
2232 assert %{"id" => _id, "subscribing" => false} = json_response(conn, 200)
2233 end
2234
2235 test "getting a list of mutes", %{conn: conn} do
2236 user = insert(:user)
2237 other_user = insert(:user)
2238
2239 {:ok, user} = User.mute(user, other_user)
2240
2241 conn =
2242 conn
2243 |> assign(:user, user)
2244 |> get("/api/v1/mutes")
2245
2246 other_user_id = to_string(other_user.id)
2247 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
2248 end
2249
2250 test "blocking / unblocking a user", %{conn: conn} do
2251 user = insert(:user)
2252 other_user = insert(:user)
2253
2254 conn =
2255 conn
2256 |> assign(:user, user)
2257 |> post("/api/v1/accounts/#{other_user.id}/block")
2258
2259 assert %{"id" => _id, "blocking" => true} = json_response(conn, 200)
2260
2261 user = User.get_cached_by_id(user.id)
2262
2263 conn =
2264 build_conn()
2265 |> assign(:user, user)
2266 |> post("/api/v1/accounts/#{other_user.id}/unblock")
2267
2268 assert %{"id" => _id, "blocking" => false} = json_response(conn, 200)
2269 end
2270
2271 test "getting a list of blocks", %{conn: conn} do
2272 user = insert(:user)
2273 other_user = insert(:user)
2274
2275 {:ok, user} = User.block(user, other_user)
2276
2277 conn =
2278 conn
2279 |> assign(:user, user)
2280 |> get("/api/v1/blocks")
2281
2282 other_user_id = to_string(other_user.id)
2283 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
2284 end
2285
2286 test "blocking / unblocking a domain", %{conn: conn} do
2287 user = insert(:user)
2288 other_user = insert(:user, %{ap_id: "https://dogwhistle.zone/@pundit"})
2289
2290 conn =
2291 conn
2292 |> assign(:user, user)
2293 |> post("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"})
2294
2295 assert %{} = json_response(conn, 200)
2296 user = User.get_cached_by_ap_id(user.ap_id)
2297 assert User.blocks?(user, other_user)
2298
2299 conn =
2300 build_conn()
2301 |> assign(:user, user)
2302 |> delete("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"})
2303
2304 assert %{} = json_response(conn, 200)
2305 user = User.get_cached_by_ap_id(user.ap_id)
2306 refute User.blocks?(user, other_user)
2307 end
2308
2309 test "getting a list of domain blocks", %{conn: conn} do
2310 user = insert(:user)
2311
2312 {:ok, user} = User.block_domain(user, "bad.site")
2313 {:ok, user} = User.block_domain(user, "even.worse.site")
2314
2315 conn =
2316 conn
2317 |> assign(:user, user)
2318 |> get("/api/v1/domain_blocks")
2319
2320 domain_blocks = json_response(conn, 200)
2321
2322 assert "bad.site" in domain_blocks
2323 assert "even.worse.site" in domain_blocks
2324 end
2325
2326 test "unimplemented follow_requests, blocks, domain blocks" do
2327 user = insert(:user)
2328
2329 ["blocks", "domain_blocks", "follow_requests"]
2330 |> Enum.each(fn endpoint ->
2331 conn =
2332 build_conn()
2333 |> assign(:user, user)
2334 |> get("/api/v1/#{endpoint}")
2335
2336 assert [] = json_response(conn, 200)
2337 end)
2338 end
2339
2340 test "returns the favorites of a user", %{conn: conn} do
2341 user = insert(:user)
2342 other_user = insert(:user)
2343
2344 {:ok, _} = CommonAPI.post(other_user, %{"status" => "bla"})
2345 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "traps are happy"})
2346
2347 {:ok, _, _} = CommonAPI.favorite(activity.id, user)
2348
2349 first_conn =
2350 conn
2351 |> assign(:user, user)
2352 |> get("/api/v1/favourites")
2353
2354 assert [status] = json_response(first_conn, 200)
2355 assert status["id"] == to_string(activity.id)
2356
2357 assert [{"link", _link_header}] =
2358 Enum.filter(first_conn.resp_headers, fn element -> match?({"link", _}, element) end)
2359
2360 # Honours query params
2361 {:ok, second_activity} =
2362 CommonAPI.post(other_user, %{
2363 "status" =>
2364 "Trees Are Never Sad Look At Them Every Once In Awhile They're Quite Beautiful."
2365 })
2366
2367 {:ok, _, _} = CommonAPI.favorite(second_activity.id, user)
2368
2369 last_like = status["id"]
2370
2371 second_conn =
2372 conn
2373 |> assign(:user, user)
2374 |> get("/api/v1/favourites?since_id=#{last_like}")
2375
2376 assert [second_status] = json_response(second_conn, 200)
2377 assert second_status["id"] == to_string(second_activity.id)
2378
2379 third_conn =
2380 conn
2381 |> assign(:user, user)
2382 |> get("/api/v1/favourites?limit=0")
2383
2384 assert [] = json_response(third_conn, 200)
2385 end
2386
2387 describe "getting favorites timeline of specified user" do
2388 setup do
2389 [current_user, user] = insert_pair(:user, %{info: %{hide_favorites: false}})
2390 [current_user: current_user, user: user]
2391 end
2392
2393 test "returns list of statuses favorited by specified user", %{
2394 conn: conn,
2395 current_user: current_user,
2396 user: user
2397 } do
2398 [activity | _] = insert_pair(:note_activity)
2399 CommonAPI.favorite(activity.id, user)
2400
2401 response =
2402 conn
2403 |> assign(:user, current_user)
2404 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2405 |> json_response(:ok)
2406
2407 [like] = response
2408
2409 assert length(response) == 1
2410 assert like["id"] == activity.id
2411 end
2412
2413 test "returns favorites for specified user_id when user is not logged in", %{
2414 conn: conn,
2415 user: user
2416 } do
2417 activity = insert(:note_activity)
2418 CommonAPI.favorite(activity.id, user)
2419
2420 response =
2421 conn
2422 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2423 |> json_response(:ok)
2424
2425 assert length(response) == 1
2426 end
2427
2428 test "returns favorited DM only when user is logged in and he is one of recipients", %{
2429 conn: conn,
2430 current_user: current_user,
2431 user: user
2432 } do
2433 {:ok, direct} =
2434 CommonAPI.post(current_user, %{
2435 "status" => "Hi @#{user.nickname}!",
2436 "visibility" => "direct"
2437 })
2438
2439 CommonAPI.favorite(direct.id, user)
2440
2441 response =
2442 conn
2443 |> assign(:user, current_user)
2444 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2445 |> json_response(:ok)
2446
2447 assert length(response) == 1
2448
2449 anonymous_response =
2450 conn
2451 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2452 |> json_response(:ok)
2453
2454 assert Enum.empty?(anonymous_response)
2455 end
2456
2457 test "does not return others' favorited DM when user is not one of recipients", %{
2458 conn: conn,
2459 current_user: current_user,
2460 user: user
2461 } do
2462 user_two = insert(:user)
2463
2464 {:ok, direct} =
2465 CommonAPI.post(user_two, %{
2466 "status" => "Hi @#{user.nickname}!",
2467 "visibility" => "direct"
2468 })
2469
2470 CommonAPI.favorite(direct.id, user)
2471
2472 response =
2473 conn
2474 |> assign(:user, current_user)
2475 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2476 |> json_response(:ok)
2477
2478 assert Enum.empty?(response)
2479 end
2480
2481 test "paginates favorites using since_id and max_id", %{
2482 conn: conn,
2483 current_user: current_user,
2484 user: user
2485 } do
2486 activities = insert_list(10, :note_activity)
2487
2488 Enum.each(activities, fn activity ->
2489 CommonAPI.favorite(activity.id, user)
2490 end)
2491
2492 third_activity = Enum.at(activities, 2)
2493 seventh_activity = Enum.at(activities, 6)
2494
2495 response =
2496 conn
2497 |> assign(:user, current_user)
2498 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites", %{
2499 since_id: third_activity.id,
2500 max_id: seventh_activity.id
2501 })
2502 |> json_response(:ok)
2503
2504 assert length(response) == 3
2505 refute third_activity in response
2506 refute seventh_activity in response
2507 end
2508
2509 test "limits favorites using limit parameter", %{
2510 conn: conn,
2511 current_user: current_user,
2512 user: user
2513 } do
2514 7
2515 |> insert_list(:note_activity)
2516 |> Enum.each(fn activity ->
2517 CommonAPI.favorite(activity.id, user)
2518 end)
2519
2520 response =
2521 conn
2522 |> assign(:user, current_user)
2523 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites", %{limit: "3"})
2524 |> json_response(:ok)
2525
2526 assert length(response) == 3
2527 end
2528
2529 test "returns empty response when user does not have any favorited statuses", %{
2530 conn: conn,
2531 current_user: current_user,
2532 user: user
2533 } do
2534 response =
2535 conn
2536 |> assign(:user, current_user)
2537 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2538 |> json_response(:ok)
2539
2540 assert Enum.empty?(response)
2541 end
2542
2543 test "returns 404 error when specified user is not exist", %{conn: conn} do
2544 conn = get(conn, "/api/v1/pleroma/accounts/test/favourites")
2545
2546 assert json_response(conn, 404) == %{"error" => "Record not found"}
2547 end
2548
2549 test "returns 403 error when user has hidden own favorites", %{
2550 conn: conn,
2551 current_user: current_user
2552 } do
2553 user = insert(:user, %{info: %{hide_favorites: true}})
2554 activity = insert(:note_activity)
2555 CommonAPI.favorite(activity.id, user)
2556
2557 conn =
2558 conn
2559 |> assign(:user, current_user)
2560 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2561
2562 assert json_response(conn, 403) == %{"error" => "Can't get favorites"}
2563 end
2564
2565 test "hides favorites for new users by default", %{conn: conn, current_user: current_user} do
2566 user = insert(:user)
2567 activity = insert(:note_activity)
2568 CommonAPI.favorite(activity.id, user)
2569
2570 conn =
2571 conn
2572 |> assign(:user, current_user)
2573 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2574
2575 assert user.info.hide_favorites
2576 assert json_response(conn, 403) == %{"error" => "Can't get favorites"}
2577 end
2578 end
2579
2580 test "get instance information", %{conn: conn} do
2581 conn = get(conn, "/api/v1/instance")
2582 assert result = json_response(conn, 200)
2583
2584 email = Pleroma.Config.get([:instance, :email])
2585 # Note: not checking for "max_toot_chars" since it's optional
2586 assert %{
2587 "uri" => _,
2588 "title" => _,
2589 "description" => _,
2590 "version" => _,
2591 "email" => from_config_email,
2592 "urls" => %{
2593 "streaming_api" => _
2594 },
2595 "stats" => _,
2596 "thumbnail" => _,
2597 "languages" => _,
2598 "registrations" => _,
2599 "poll_limits" => _
2600 } = result
2601
2602 assert email == from_config_email
2603 end
2604
2605 test "get instance stats", %{conn: conn} do
2606 user = insert(:user, %{local: true})
2607
2608 user2 = insert(:user, %{local: true})
2609 {:ok, _user2} = User.deactivate(user2, !user2.info.deactivated)
2610
2611 insert(:user, %{local: false, nickname: "u@peer1.com"})
2612 insert(:user, %{local: false, nickname: "u@peer2.com"})
2613
2614 {:ok, _} = CommonAPI.post(user, %{"status" => "cofe"})
2615
2616 # Stats should count users with missing or nil `info.deactivated` value
2617 user = User.get_cached_by_id(user.id)
2618 info_change = Changeset.change(user.info, %{deactivated: nil})
2619
2620 {:ok, _user} =
2621 user
2622 |> Changeset.change()
2623 |> Changeset.put_embed(:info, info_change)
2624 |> User.update_and_set_cache()
2625
2626 Pleroma.Stats.update_stats()
2627
2628 conn = get(conn, "/api/v1/instance")
2629
2630 assert result = json_response(conn, 200)
2631
2632 stats = result["stats"]
2633
2634 assert stats
2635 assert stats["user_count"] == 1
2636 assert stats["status_count"] == 1
2637 assert stats["domain_count"] == 2
2638 end
2639
2640 test "get peers", %{conn: conn} do
2641 insert(:user, %{local: false, nickname: "u@peer1.com"})
2642 insert(:user, %{local: false, nickname: "u@peer2.com"})
2643
2644 Pleroma.Stats.update_stats()
2645
2646 conn = get(conn, "/api/v1/instance/peers")
2647
2648 assert result = json_response(conn, 200)
2649
2650 assert ["peer1.com", "peer2.com"] == Enum.sort(result)
2651 end
2652
2653 test "put settings", %{conn: conn} do
2654 user = insert(:user)
2655
2656 conn =
2657 conn
2658 |> assign(:user, user)
2659 |> put("/api/web/settings", %{"data" => %{"programming" => "socks"}})
2660
2661 assert _result = json_response(conn, 200)
2662
2663 user = User.get_cached_by_ap_id(user.ap_id)
2664 assert user.info.settings == %{"programming" => "socks"}
2665 end
2666
2667 describe "pinned statuses" do
2668 setup do
2669 Pleroma.Config.put([:instance, :max_pinned_statuses], 1)
2670
2671 user = insert(:user)
2672 {:ok, activity} = CommonAPI.post(user, %{"status" => "HI!!!"})
2673
2674 [user: user, activity: activity]
2675 end
2676
2677 test "returns pinned statuses", %{conn: conn, user: user, activity: activity} do
2678 {:ok, _} = CommonAPI.pin(activity.id, user)
2679
2680 result =
2681 conn
2682 |> assign(:user, user)
2683 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2684 |> json_response(200)
2685
2686 id_str = to_string(activity.id)
2687
2688 assert [%{"id" => ^id_str, "pinned" => true}] = result
2689 end
2690
2691 test "pin status", %{conn: conn, user: user, activity: activity} do
2692 id_str = to_string(activity.id)
2693
2694 assert %{"id" => ^id_str, "pinned" => true} =
2695 conn
2696 |> assign(:user, user)
2697 |> post("/api/v1/statuses/#{activity.id}/pin")
2698 |> json_response(200)
2699
2700 assert [%{"id" => ^id_str, "pinned" => true}] =
2701 conn
2702 |> assign(:user, user)
2703 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2704 |> json_response(200)
2705 end
2706
2707 test "/pin: returns 400 error when activity is not public", %{conn: conn, user: user} do
2708 {:ok, dm} = CommonAPI.post(user, %{"status" => "test", "visibility" => "direct"})
2709
2710 conn =
2711 conn
2712 |> assign(:user, user)
2713 |> post("/api/v1/statuses/#{dm.id}/pin")
2714
2715 assert json_response(conn, 400) == %{"error" => "Could not pin"}
2716 end
2717
2718 test "unpin status", %{conn: conn, user: user, activity: activity} do
2719 {:ok, _} = CommonAPI.pin(activity.id, user)
2720
2721 id_str = to_string(activity.id)
2722 user = refresh_record(user)
2723
2724 assert %{"id" => ^id_str, "pinned" => false} =
2725 conn
2726 |> assign(:user, user)
2727 |> post("/api/v1/statuses/#{activity.id}/unpin")
2728 |> json_response(200)
2729
2730 assert [] =
2731 conn
2732 |> assign(:user, user)
2733 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2734 |> json_response(200)
2735 end
2736
2737 test "/unpin: returns 400 error when activity is not exist", %{conn: conn, user: user} do
2738 conn =
2739 conn
2740 |> assign(:user, user)
2741 |> post("/api/v1/statuses/1/unpin")
2742
2743 assert json_response(conn, 400) == %{"error" => "Could not unpin"}
2744 end
2745
2746 test "max pinned statuses", %{conn: conn, user: user, activity: activity_one} do
2747 {:ok, activity_two} = CommonAPI.post(user, %{"status" => "HI!!!"})
2748
2749 id_str_one = to_string(activity_one.id)
2750
2751 assert %{"id" => ^id_str_one, "pinned" => true} =
2752 conn
2753 |> assign(:user, user)
2754 |> post("/api/v1/statuses/#{id_str_one}/pin")
2755 |> json_response(200)
2756
2757 user = refresh_record(user)
2758
2759 assert %{"error" => "You have already pinned the maximum number of statuses"} =
2760 conn
2761 |> assign(:user, user)
2762 |> post("/api/v1/statuses/#{activity_two.id}/pin")
2763 |> json_response(400)
2764 end
2765 end
2766
2767 describe "cards" do
2768 setup do
2769 Pleroma.Config.put([:rich_media, :enabled], true)
2770
2771 on_exit(fn ->
2772 Pleroma.Config.put([:rich_media, :enabled], false)
2773 end)
2774
2775 user = insert(:user)
2776 %{user: user}
2777 end
2778
2779 test "returns rich-media card", %{conn: conn, user: user} do
2780 {:ok, activity} = CommonAPI.post(user, %{"status" => "https://example.com/ogp"})
2781
2782 card_data = %{
2783 "image" => "http://ia.media-imdb.com/images/rock.jpg",
2784 "provider_name" => "example.com",
2785 "provider_url" => "https://example.com",
2786 "title" => "The Rock",
2787 "type" => "link",
2788 "url" => "https://example.com/ogp",
2789 "description" =>
2790 "Directed by Michael Bay. With Sean Connery, Nicolas Cage, Ed Harris, John Spencer.",
2791 "pleroma" => %{
2792 "opengraph" => %{
2793 "image" => "http://ia.media-imdb.com/images/rock.jpg",
2794 "title" => "The Rock",
2795 "type" => "video.movie",
2796 "url" => "https://example.com/ogp",
2797 "description" =>
2798 "Directed by Michael Bay. With Sean Connery, Nicolas Cage, Ed Harris, John Spencer."
2799 }
2800 }
2801 }
2802
2803 response =
2804 conn
2805 |> get("/api/v1/statuses/#{activity.id}/card")
2806 |> json_response(200)
2807
2808 assert response == card_data
2809
2810 # works with private posts
2811 {:ok, activity} =
2812 CommonAPI.post(user, %{"status" => "https://example.com/ogp", "visibility" => "direct"})
2813
2814 response_two =
2815 conn
2816 |> assign(:user, user)
2817 |> get("/api/v1/statuses/#{activity.id}/card")
2818 |> json_response(200)
2819
2820 assert response_two == card_data
2821 end
2822
2823 test "replaces missing description with an empty string", %{conn: conn, user: user} do
2824 {:ok, activity} =
2825 CommonAPI.post(user, %{"status" => "https://example.com/ogp-missing-data"})
2826
2827 response =
2828 conn
2829 |> get("/api/v1/statuses/#{activity.id}/card")
2830 |> json_response(:ok)
2831
2832 assert response == %{
2833 "type" => "link",
2834 "title" => "Pleroma",
2835 "description" => "",
2836 "image" => nil,
2837 "provider_name" => "example.com",
2838 "provider_url" => "https://example.com",
2839 "url" => "https://example.com/ogp-missing-data",
2840 "pleroma" => %{
2841 "opengraph" => %{
2842 "title" => "Pleroma",
2843 "type" => "website",
2844 "url" => "https://example.com/ogp-missing-data"
2845 }
2846 }
2847 }
2848 end
2849 end
2850
2851 test "bookmarks" do
2852 user = insert(:user)
2853 for_user = insert(:user)
2854
2855 {:ok, activity1} =
2856 CommonAPI.post(user, %{
2857 "status" => "heweoo?"
2858 })
2859
2860 {:ok, activity2} =
2861 CommonAPI.post(user, %{
2862 "status" => "heweoo!"
2863 })
2864
2865 response1 =
2866 build_conn()
2867 |> assign(:user, for_user)
2868 |> post("/api/v1/statuses/#{activity1.id}/bookmark")
2869
2870 assert json_response(response1, 200)["bookmarked"] == true
2871
2872 response2 =
2873 build_conn()
2874 |> assign(:user, for_user)
2875 |> post("/api/v1/statuses/#{activity2.id}/bookmark")
2876
2877 assert json_response(response2, 200)["bookmarked"] == true
2878
2879 bookmarks =
2880 build_conn()
2881 |> assign(:user, for_user)
2882 |> get("/api/v1/bookmarks")
2883
2884 assert [json_response(response2, 200), json_response(response1, 200)] ==
2885 json_response(bookmarks, 200)
2886
2887 response1 =
2888 build_conn()
2889 |> assign(:user, for_user)
2890 |> post("/api/v1/statuses/#{activity1.id}/unbookmark")
2891
2892 assert json_response(response1, 200)["bookmarked"] == false
2893
2894 bookmarks =
2895 build_conn()
2896 |> assign(:user, for_user)
2897 |> get("/api/v1/bookmarks")
2898
2899 assert [json_response(response2, 200)] == json_response(bookmarks, 200)
2900 end
2901
2902 describe "conversation muting" do
2903 setup do
2904 user = insert(:user)
2905 {:ok, activity} = CommonAPI.post(user, %{"status" => "HIE"})
2906
2907 [user: user, activity: activity]
2908 end
2909
2910 test "mute conversation", %{conn: conn, user: user, activity: activity} do
2911 id_str = to_string(activity.id)
2912
2913 assert %{"id" => ^id_str, "muted" => true} =
2914 conn
2915 |> assign(:user, user)
2916 |> post("/api/v1/statuses/#{activity.id}/mute")
2917 |> json_response(200)
2918 end
2919
2920 test "cannot mute already muted conversation", %{conn: conn, user: user, activity: activity} do
2921 {:ok, _} = CommonAPI.add_mute(user, activity)
2922
2923 conn =
2924 conn
2925 |> assign(:user, user)
2926 |> post("/api/v1/statuses/#{activity.id}/mute")
2927
2928 assert json_response(conn, 400) == %{"error" => "conversation is already muted"}
2929 end
2930
2931 test "unmute conversation", %{conn: conn, user: user, activity: activity} do
2932 {:ok, _} = CommonAPI.add_mute(user, activity)
2933
2934 id_str = to_string(activity.id)
2935 user = refresh_record(user)
2936
2937 assert %{"id" => ^id_str, "muted" => false} =
2938 conn
2939 |> assign(:user, user)
2940 |> post("/api/v1/statuses/#{activity.id}/unmute")
2941 |> json_response(200)
2942 end
2943 end
2944
2945 describe "reports" do
2946 setup do
2947 reporter = insert(:user)
2948 target_user = insert(:user)
2949
2950 {:ok, activity} = CommonAPI.post(target_user, %{"status" => "foobar"})
2951
2952 [reporter: reporter, target_user: target_user, activity: activity]
2953 end
2954
2955 test "submit a basic report", %{conn: conn, reporter: reporter, target_user: target_user} do
2956 assert %{"action_taken" => false, "id" => _} =
2957 conn
2958 |> assign(:user, reporter)
2959 |> post("/api/v1/reports", %{"account_id" => target_user.id})
2960 |> json_response(200)
2961 end
2962
2963 test "submit a report with statuses and comment", %{
2964 conn: conn,
2965 reporter: reporter,
2966 target_user: target_user,
2967 activity: activity
2968 } do
2969 assert %{"action_taken" => false, "id" => _} =
2970 conn
2971 |> assign(:user, reporter)
2972 |> post("/api/v1/reports", %{
2973 "account_id" => target_user.id,
2974 "status_ids" => [activity.id],
2975 "comment" => "bad status!",
2976 "forward" => "false"
2977 })
2978 |> json_response(200)
2979 end
2980
2981 test "account_id is required", %{
2982 conn: conn,
2983 reporter: reporter,
2984 activity: activity
2985 } do
2986 assert %{"error" => "Valid `account_id` required"} =
2987 conn
2988 |> assign(:user, reporter)
2989 |> post("/api/v1/reports", %{"status_ids" => [activity.id]})
2990 |> json_response(400)
2991 end
2992
2993 test "comment must be up to the size specified in the config", %{
2994 conn: conn,
2995 reporter: reporter,
2996 target_user: target_user
2997 } do
2998 max_size = Pleroma.Config.get([:instance, :max_report_comment_size], 1000)
2999 comment = String.pad_trailing("a", max_size + 1, "a")
3000
3001 error = %{"error" => "Comment must be up to #{max_size} characters"}
3002
3003 assert ^error =
3004 conn
3005 |> assign(:user, reporter)
3006 |> post("/api/v1/reports", %{"account_id" => target_user.id, "comment" => comment})
3007 |> json_response(400)
3008 end
3009
3010 test "returns error when account is not exist", %{
3011 conn: conn,
3012 reporter: reporter,
3013 activity: activity
3014 } do
3015 conn =
3016 conn
3017 |> assign(:user, reporter)
3018 |> post("/api/v1/reports", %{"status_ids" => [activity.id], "account_id" => "foo"})
3019
3020 assert json_response(conn, 400) == %{"error" => "Account not found"}
3021 end
3022 end
3023
3024 describe "link headers" do
3025 test "preserves parameters in link headers", %{conn: conn} do
3026 user = insert(:user)
3027 other_user = insert(:user)
3028
3029 {:ok, activity1} =
3030 CommonAPI.post(other_user, %{
3031 "status" => "hi @#{user.nickname}",
3032 "visibility" => "public"
3033 })
3034
3035 {:ok, activity2} =
3036 CommonAPI.post(other_user, %{
3037 "status" => "hi @#{user.nickname}",
3038 "visibility" => "public"
3039 })
3040
3041 notification1 = Repo.get_by(Notification, activity_id: activity1.id)
3042 notification2 = Repo.get_by(Notification, activity_id: activity2.id)
3043
3044 conn =
3045 conn
3046 |> assign(:user, user)
3047 |> get("/api/v1/notifications", %{media_only: true})
3048
3049 assert [link_header] = get_resp_header(conn, "link")
3050 assert link_header =~ ~r/media_only=true/
3051 assert link_header =~ ~r/min_id=#{notification2.id}/
3052 assert link_header =~ ~r/max_id=#{notification1.id}/
3053 end
3054 end
3055
3056 test "accounts fetches correct account for nicknames beginning with numbers", %{conn: conn} do
3057 # Need to set an old-style integer ID to reproduce the problem
3058 # (these are no longer assigned to new accounts but were preserved
3059 # for existing accounts during the migration to flakeIDs)
3060 user_one = insert(:user, %{id: 1212})
3061 user_two = insert(:user, %{nickname: "#{user_one.id}garbage"})
3062
3063 resp_one =
3064 conn
3065 |> get("/api/v1/accounts/#{user_one.id}")
3066
3067 resp_two =
3068 conn
3069 |> get("/api/v1/accounts/#{user_two.nickname}")
3070
3071 resp_three =
3072 conn
3073 |> get("/api/v1/accounts/#{user_two.id}")
3074
3075 acc_one = json_response(resp_one, 200)
3076 acc_two = json_response(resp_two, 200)
3077 acc_three = json_response(resp_three, 200)
3078 refute acc_one == acc_two
3079 assert acc_two == acc_three
3080 end
3081
3082 describe "custom emoji" do
3083 test "with tags", %{conn: conn} do
3084 [emoji | _body] =
3085 conn
3086 |> get("/api/v1/custom_emojis")
3087 |> json_response(200)
3088
3089 assert Map.has_key?(emoji, "shortcode")
3090 assert Map.has_key?(emoji, "static_url")
3091 assert Map.has_key?(emoji, "tags")
3092 assert is_list(emoji["tags"])
3093 assert Map.has_key?(emoji, "category")
3094 assert Map.has_key?(emoji, "url")
3095 assert Map.has_key?(emoji, "visible_in_picker")
3096 end
3097 end
3098
3099 describe "index/2 redirections" do
3100 setup %{conn: conn} do
3101 session_opts = [
3102 store: :cookie,
3103 key: "_test",
3104 signing_salt: "cooldude"
3105 ]
3106
3107 conn =
3108 conn
3109 |> Plug.Session.call(Plug.Session.init(session_opts))
3110 |> fetch_session()
3111
3112 test_path = "/web/statuses/test"
3113 %{conn: conn, path: test_path}
3114 end
3115
3116 test "redirects not logged-in users to the login page", %{conn: conn, path: path} do
3117 conn = get(conn, path)
3118
3119 assert conn.status == 302
3120 assert redirected_to(conn) == "/web/login"
3121 end
3122
3123 test "redirects not logged-in users to the login page on private instances", %{
3124 conn: conn,
3125 path: path
3126 } do
3127 is_public = Pleroma.Config.get([:instance, :public])
3128 Pleroma.Config.put([:instance, :public], false)
3129
3130 conn = get(conn, path)
3131
3132 assert conn.status == 302
3133 assert redirected_to(conn) == "/web/login"
3134
3135 Pleroma.Config.put([:instance, :public], is_public)
3136 end
3137
3138 test "does not redirect logged in users to the login page", %{conn: conn, path: path} do
3139 token = insert(:oauth_token)
3140
3141 conn =
3142 conn
3143 |> assign(:user, token.user)
3144 |> put_session(:oauth_token, token.token)
3145 |> get(path)
3146
3147 assert conn.status == 200
3148 end
3149
3150 test "saves referer path to session", %{conn: conn, path: path} do
3151 conn = get(conn, path)
3152 return_to = Plug.Conn.get_session(conn, :return_to)
3153
3154 assert return_to == path
3155 end
3156
3157 test "redirects to the saved path after log in", %{conn: conn, path: path} do
3158 app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
3159 auth = insert(:oauth_authorization, app: app)
3160
3161 conn =
3162 conn
3163 |> put_session(:return_to, path)
3164 |> get("/web/login", %{code: auth.token})
3165
3166 assert conn.status == 302
3167 assert redirected_to(conn) == path
3168 end
3169
3170 test "redirects to the getting-started page when referer is not present", %{conn: conn} do
3171 app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
3172 auth = insert(:oauth_authorization, app: app)
3173
3174 conn = get(conn, "/web/login", %{code: auth.token})
3175
3176 assert conn.status == 302
3177 assert redirected_to(conn) == "/web/getting-started"
3178 end
3179 end
3180
3181 describe "scheduled activities" do
3182 test "creates a scheduled activity", %{conn: conn} do
3183 user = insert(:user)
3184 scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
3185
3186 conn =
3187 conn
3188 |> assign(:user, user)
3189 |> post("/api/v1/statuses", %{
3190 "status" => "scheduled",
3191 "scheduled_at" => scheduled_at
3192 })
3193
3194 assert %{"scheduled_at" => expected_scheduled_at} = json_response(conn, 200)
3195 assert expected_scheduled_at == Pleroma.Web.CommonAPI.Utils.to_masto_date(scheduled_at)
3196 assert [] == Repo.all(Activity)
3197 end
3198
3199 test "creates a scheduled activity with a media attachment", %{conn: conn} do
3200 user = insert(:user)
3201 scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
3202
3203 file = %Plug.Upload{
3204 content_type: "image/jpg",
3205 path: Path.absname("test/fixtures/image.jpg"),
3206 filename: "an_image.jpg"
3207 }
3208
3209 {:ok, upload} = ActivityPub.upload(file, actor: user.ap_id)
3210
3211 conn =
3212 conn
3213 |> assign(:user, user)
3214 |> post("/api/v1/statuses", %{
3215 "media_ids" => [to_string(upload.id)],
3216 "status" => "scheduled",
3217 "scheduled_at" => scheduled_at
3218 })
3219
3220 assert %{"media_attachments" => [media_attachment]} = json_response(conn, 200)
3221 assert %{"type" => "image"} = media_attachment
3222 end
3223
3224 test "skips the scheduling and creates the activity if scheduled_at is earlier than 5 minutes from now",
3225 %{conn: conn} do
3226 user = insert(:user)
3227
3228 scheduled_at =
3229 NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(5) - 1, :millisecond)
3230
3231 conn =
3232 conn
3233 |> assign(:user, user)
3234 |> post("/api/v1/statuses", %{
3235 "status" => "not scheduled",
3236 "scheduled_at" => scheduled_at
3237 })
3238
3239 assert %{"content" => "not scheduled"} = json_response(conn, 200)
3240 assert [] == Repo.all(ScheduledActivity)
3241 end
3242
3243 test "returns error when daily user limit is exceeded", %{conn: conn} do
3244 user = insert(:user)
3245
3246 today =
3247 NaiveDateTime.utc_now()
3248 |> NaiveDateTime.add(:timer.minutes(6), :millisecond)
3249 |> NaiveDateTime.to_iso8601()
3250
3251 attrs = %{params: %{}, scheduled_at: today}
3252 {:ok, _} = ScheduledActivity.create(user, attrs)
3253 {:ok, _} = ScheduledActivity.create(user, attrs)
3254
3255 conn =
3256 conn
3257 |> assign(:user, user)
3258 |> post("/api/v1/statuses", %{"status" => "scheduled", "scheduled_at" => today})
3259
3260 assert %{"error" => "daily limit exceeded"} == json_response(conn, 422)
3261 end
3262
3263 test "returns error when total user limit is exceeded", %{conn: conn} do
3264 user = insert(:user)
3265
3266 today =
3267 NaiveDateTime.utc_now()
3268 |> NaiveDateTime.add(:timer.minutes(6), :millisecond)
3269 |> NaiveDateTime.to_iso8601()
3270
3271 tomorrow =
3272 NaiveDateTime.utc_now()
3273 |> NaiveDateTime.add(:timer.hours(36), :millisecond)
3274 |> NaiveDateTime.to_iso8601()
3275
3276 attrs = %{params: %{}, scheduled_at: today}
3277 {:ok, _} = ScheduledActivity.create(user, attrs)
3278 {:ok, _} = ScheduledActivity.create(user, attrs)
3279 {:ok, _} = ScheduledActivity.create(user, %{params: %{}, scheduled_at: tomorrow})
3280
3281 conn =
3282 conn
3283 |> assign(:user, user)
3284 |> post("/api/v1/statuses", %{"status" => "scheduled", "scheduled_at" => tomorrow})
3285
3286 assert %{"error" => "total limit exceeded"} == json_response(conn, 422)
3287 end
3288
3289 test "shows scheduled activities", %{conn: conn} do
3290 user = insert(:user)
3291 scheduled_activity_id1 = insert(:scheduled_activity, user: user).id |> to_string()
3292 scheduled_activity_id2 = insert(:scheduled_activity, user: user).id |> to_string()
3293 scheduled_activity_id3 = insert(:scheduled_activity, user: user).id |> to_string()
3294 scheduled_activity_id4 = insert(:scheduled_activity, user: user).id |> to_string()
3295
3296 conn =
3297 conn
3298 |> assign(:user, user)
3299
3300 # min_id
3301 conn_res =
3302 conn
3303 |> get("/api/v1/scheduled_statuses?limit=2&min_id=#{scheduled_activity_id1}")
3304
3305 result = json_response(conn_res, 200)
3306 assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result
3307
3308 # since_id
3309 conn_res =
3310 conn
3311 |> get("/api/v1/scheduled_statuses?limit=2&since_id=#{scheduled_activity_id1}")
3312
3313 result = json_response(conn_res, 200)
3314 assert [%{"id" => ^scheduled_activity_id4}, %{"id" => ^scheduled_activity_id3}] = result
3315
3316 # max_id
3317 conn_res =
3318 conn
3319 |> get("/api/v1/scheduled_statuses?limit=2&max_id=#{scheduled_activity_id4}")
3320
3321 result = json_response(conn_res, 200)
3322 assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result
3323 end
3324
3325 test "shows a scheduled activity", %{conn: conn} do
3326 user = insert(:user)
3327 scheduled_activity = insert(:scheduled_activity, user: user)
3328
3329 res_conn =
3330 conn
3331 |> assign(:user, user)
3332 |> get("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
3333
3334 assert %{"id" => scheduled_activity_id} = json_response(res_conn, 200)
3335 assert scheduled_activity_id == scheduled_activity.id |> to_string()
3336
3337 res_conn =
3338 conn
3339 |> assign(:user, user)
3340 |> get("/api/v1/scheduled_statuses/404")
3341
3342 assert %{"error" => "Record not found"} = json_response(res_conn, 404)
3343 end
3344
3345 test "updates a scheduled activity", %{conn: conn} do
3346 user = insert(:user)
3347 scheduled_activity = insert(:scheduled_activity, user: user)
3348
3349 new_scheduled_at =
3350 NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
3351
3352 res_conn =
3353 conn
3354 |> assign(:user, user)
3355 |> put("/api/v1/scheduled_statuses/#{scheduled_activity.id}", %{
3356 scheduled_at: new_scheduled_at
3357 })
3358
3359 assert %{"scheduled_at" => expected_scheduled_at} = json_response(res_conn, 200)
3360 assert expected_scheduled_at == Pleroma.Web.CommonAPI.Utils.to_masto_date(new_scheduled_at)
3361
3362 res_conn =
3363 conn
3364 |> assign(:user, user)
3365 |> put("/api/v1/scheduled_statuses/404", %{scheduled_at: new_scheduled_at})
3366
3367 assert %{"error" => "Record not found"} = json_response(res_conn, 404)
3368 end
3369
3370 test "deletes a scheduled activity", %{conn: conn} do
3371 user = insert(:user)
3372 scheduled_activity = insert(:scheduled_activity, user: user)
3373
3374 res_conn =
3375 conn
3376 |> assign(:user, user)
3377 |> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
3378
3379 assert %{} = json_response(res_conn, 200)
3380 assert nil == Repo.get(ScheduledActivity, scheduled_activity.id)
3381
3382 res_conn =
3383 conn
3384 |> assign(:user, user)
3385 |> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
3386
3387 assert %{"error" => "Record not found"} = json_response(res_conn, 404)
3388 end
3389 end
3390
3391 test "Repeated posts that are replies incorrectly have in_reply_to_id null", %{conn: conn} do
3392 user1 = insert(:user)
3393 user2 = insert(:user)
3394 user3 = insert(:user)
3395
3396 {:ok, replied_to} = CommonAPI.post(user1, %{"status" => "cofe"})
3397
3398 # Reply to status from another user
3399 conn1 =
3400 conn
3401 |> assign(:user, user2)
3402 |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => replied_to.id})
3403
3404 assert %{"content" => "xD", "id" => id} = json_response(conn1, 200)
3405
3406 activity = Activity.get_by_id_with_object(id)
3407
3408 assert Object.normalize(activity).data["inReplyTo"] == Object.normalize(replied_to).data["id"]
3409 assert Activity.get_in_reply_to_activity(activity).id == replied_to.id
3410
3411 # Reblog from the third user
3412 conn2 =
3413 conn
3414 |> assign(:user, user3)
3415 |> post("/api/v1/statuses/#{activity.id}/reblog")
3416
3417 assert %{"reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1}} =
3418 json_response(conn2, 200)
3419
3420 assert to_string(activity.id) == id
3421
3422 # Getting third user status
3423 conn3 =
3424 conn
3425 |> assign(:user, user3)
3426 |> get("api/v1/timelines/home")
3427
3428 [reblogged_activity] = json_response(conn3, 200)
3429
3430 assert reblogged_activity["reblog"]["in_reply_to_id"] == replied_to.id
3431
3432 replied_to_user = User.get_by_ap_id(replied_to.data["actor"])
3433 assert reblogged_activity["reblog"]["in_reply_to_account_id"] == replied_to_user.id
3434 end
3435
3436 describe "create account by app" do
3437 test "Account registration via Application", %{conn: conn} do
3438 conn =
3439 conn
3440 |> post("/api/v1/apps", %{
3441 client_name: "client_name",
3442 redirect_uris: "urn:ietf:wg:oauth:2.0:oob",
3443 scopes: "read, write, follow"
3444 })
3445
3446 %{
3447 "client_id" => client_id,
3448 "client_secret" => client_secret,
3449 "id" => _,
3450 "name" => "client_name",
3451 "redirect_uri" => "urn:ietf:wg:oauth:2.0:oob",
3452 "vapid_key" => _,
3453 "website" => nil
3454 } = json_response(conn, 200)
3455
3456 conn =
3457 conn
3458 |> post("/oauth/token", %{
3459 grant_type: "client_credentials",
3460 client_id: client_id,
3461 client_secret: client_secret
3462 })
3463
3464 assert %{"access_token" => token, "refresh_token" => refresh, "scope" => scope} =
3465 json_response(conn, 200)
3466
3467 assert token
3468 token_from_db = Repo.get_by(Token, token: token)
3469 assert token_from_db
3470 assert refresh
3471 assert scope == "read write follow"
3472
3473 conn =
3474 build_conn()
3475 |> put_req_header("authorization", "Bearer " <> token)
3476 |> post("/api/v1/accounts", %{
3477 username: "lain",
3478 email: "lain@example.org",
3479 password: "PlzDontHackLain",
3480 agreement: true
3481 })
3482
3483 %{
3484 "access_token" => token,
3485 "created_at" => _created_at,
3486 "scope" => _scope,
3487 "token_type" => "Bearer"
3488 } = json_response(conn, 200)
3489
3490 token_from_db = Repo.get_by(Token, token: token)
3491 assert token_from_db
3492 token_from_db = Repo.preload(token_from_db, :user)
3493 assert token_from_db.user
3494
3495 assert token_from_db.user.info.confirmation_pending
3496 end
3497
3498 test "rate limit", %{conn: conn} do
3499 app_token = insert(:oauth_token, user: nil)
3500
3501 conn =
3502 put_req_header(conn, "authorization", "Bearer " <> app_token.token)
3503 |> Map.put(:remote_ip, {15, 15, 15, 15})
3504
3505 for i <- 1..5 do
3506 conn =
3507 conn
3508 |> post("/api/v1/accounts", %{
3509 username: "#{i}lain",
3510 email: "#{i}lain@example.org",
3511 password: "PlzDontHackLain",
3512 agreement: true
3513 })
3514
3515 %{
3516 "access_token" => token,
3517 "created_at" => _created_at,
3518 "scope" => _scope,
3519 "token_type" => "Bearer"
3520 } = json_response(conn, 200)
3521
3522 token_from_db = Repo.get_by(Token, token: token)
3523 assert token_from_db
3524 token_from_db = Repo.preload(token_from_db, :user)
3525 assert token_from_db.user
3526
3527 assert token_from_db.user.info.confirmation_pending
3528 end
3529
3530 conn =
3531 conn
3532 |> post("/api/v1/accounts", %{
3533 username: "6lain",
3534 email: "6lain@example.org",
3535 password: "PlzDontHackLain",
3536 agreement: true
3537 })
3538
3539 assert json_response(conn, :too_many_requests) == %{"error" => "Throttled"}
3540 end
3541 end
3542
3543 describe "GET /api/v1/polls/:id" do
3544 test "returns poll entity for object id", %{conn: conn} do
3545 user = insert(:user)
3546
3547 {:ok, activity} =
3548 CommonAPI.post(user, %{
3549 "status" => "Pleroma does",
3550 "poll" => %{"options" => ["what Mastodon't", "n't what Mastodoes"], "expires_in" => 20}
3551 })
3552
3553 object = Object.normalize(activity)
3554
3555 conn =
3556 conn
3557 |> assign(:user, user)
3558 |> get("/api/v1/polls/#{object.id}")
3559
3560 response = json_response(conn, 200)
3561 id = to_string(object.id)
3562 assert %{"id" => ^id, "expired" => false, "multiple" => false} = response
3563 end
3564
3565 test "does not expose polls for private statuses", %{conn: conn} do
3566 user = insert(:user)
3567 other_user = insert(:user)
3568
3569 {:ok, activity} =
3570 CommonAPI.post(user, %{
3571 "status" => "Pleroma does",
3572 "poll" => %{"options" => ["what Mastodon't", "n't what Mastodoes"], "expires_in" => 20},
3573 "visibility" => "private"
3574 })
3575
3576 object = Object.normalize(activity)
3577
3578 conn =
3579 conn
3580 |> assign(:user, other_user)
3581 |> get("/api/v1/polls/#{object.id}")
3582
3583 assert json_response(conn, 404)
3584 end
3585 end
3586
3587 describe "POST /api/v1/polls/:id/votes" do
3588 test "votes are added to the poll", %{conn: conn} do
3589 user = insert(:user)
3590 other_user = insert(:user)
3591
3592 {:ok, activity} =
3593 CommonAPI.post(user, %{
3594 "status" => "A very delicious sandwich",
3595 "poll" => %{
3596 "options" => ["Lettuce", "Grilled Bacon", "Tomato"],
3597 "expires_in" => 20,
3598 "multiple" => true
3599 }
3600 })
3601
3602 object = Object.normalize(activity)
3603
3604 conn =
3605 conn
3606 |> assign(:user, other_user)
3607 |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0, 1, 2]})
3608
3609 assert json_response(conn, 200)
3610 object = Object.get_by_id(object.id)
3611
3612 assert Enum.all?(object.data["anyOf"], fn %{"replies" => %{"totalItems" => total_items}} ->
3613 total_items == 1
3614 end)
3615 end
3616
3617 test "author can't vote", %{conn: conn} do
3618 user = insert(:user)
3619
3620 {:ok, activity} =
3621 CommonAPI.post(user, %{
3622 "status" => "Am I cute?",
3623 "poll" => %{"options" => ["Yes", "No"], "expires_in" => 20}
3624 })
3625
3626 object = Object.normalize(activity)
3627
3628 assert conn
3629 |> assign(:user, user)
3630 |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [1]})
3631 |> json_response(422) == %{"error" => "Poll's author can't vote"}
3632
3633 object = Object.get_by_id(object.id)
3634
3635 refute Enum.at(object.data["oneOf"], 1)["replies"]["totalItems"] == 1
3636 end
3637
3638 test "does not allow multiple choices on a single-choice question", %{conn: conn} do
3639 user = insert(:user)
3640 other_user = insert(:user)
3641
3642 {:ok, activity} =
3643 CommonAPI.post(user, %{
3644 "status" => "The glass is",
3645 "poll" => %{"options" => ["half empty", "half full"], "expires_in" => 20}
3646 })
3647
3648 object = Object.normalize(activity)
3649
3650 assert conn
3651 |> assign(:user, other_user)
3652 |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0, 1]})
3653 |> json_response(422) == %{"error" => "Too many choices"}
3654
3655 object = Object.get_by_id(object.id)
3656
3657 refute Enum.any?(object.data["oneOf"], fn %{"replies" => %{"totalItems" => total_items}} ->
3658 total_items == 1
3659 end)
3660 end
3661
3662 test "does not allow choice index to be greater than options count", %{conn: conn} do
3663 user = insert(:user)
3664 other_user = insert(:user)
3665
3666 {:ok, activity} =
3667 CommonAPI.post(user, %{
3668 "status" => "Am I cute?",
3669 "poll" => %{"options" => ["Yes", "No"], "expires_in" => 20}
3670 })
3671
3672 object = Object.normalize(activity)
3673
3674 conn =
3675 conn
3676 |> assign(:user, other_user)
3677 |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [2]})
3678
3679 assert json_response(conn, 422) == %{"error" => "Invalid indices"}
3680 end
3681
3682 test "returns 404 error when object is not exist", %{conn: conn} do
3683 user = insert(:user)
3684
3685 conn =
3686 conn
3687 |> assign(:user, user)
3688 |> post("/api/v1/polls/1/votes", %{"choices" => [0]})
3689
3690 assert json_response(conn, 404) == %{"error" => "Record not found"}
3691 end
3692
3693 test "returns 404 when poll is private and not available for user", %{conn: conn} do
3694 user = insert(:user)
3695 other_user = insert(:user)
3696
3697 {:ok, activity} =
3698 CommonAPI.post(user, %{
3699 "status" => "Am I cute?",
3700 "poll" => %{"options" => ["Yes", "No"], "expires_in" => 20},
3701 "visibility" => "private"
3702 })
3703
3704 object = Object.normalize(activity)
3705
3706 conn =
3707 conn
3708 |> assign(:user, other_user)
3709 |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0]})
3710
3711 assert json_response(conn, 404) == %{"error" => "Record not found"}
3712 end
3713 end
3714
3715 describe "GET /api/v1/statuses/:id/favourited_by" do
3716 setup do
3717 user = insert(:user)
3718 {:ok, activity} = CommonAPI.post(user, %{"status" => "test"})
3719
3720 conn =
3721 build_conn()
3722 |> assign(:user, user)
3723
3724 [conn: conn, activity: activity]
3725 end
3726
3727 test "returns users who have favorited the status", %{conn: conn, activity: activity} do
3728 other_user = insert(:user)
3729 {:ok, _, _} = CommonAPI.favorite(activity.id, other_user)
3730
3731 response =
3732 conn
3733 |> get("/api/v1/statuses/#{activity.id}/favourited_by")
3734 |> json_response(:ok)
3735
3736 [%{"id" => id}] = response
3737
3738 assert id == other_user.id
3739 end
3740
3741 test "returns empty array when status has not been favorited yet", %{
3742 conn: conn,
3743 activity: activity
3744 } do
3745 response =
3746 conn
3747 |> get("/api/v1/statuses/#{activity.id}/favourited_by")
3748 |> json_response(:ok)
3749
3750 assert Enum.empty?(response)
3751 end
3752
3753 test "does not return users who have favorited the status but are blocked", %{
3754 conn: %{assigns: %{user: user}} = conn,
3755 activity: activity
3756 } do
3757 other_user = insert(:user)
3758 {:ok, user} = User.block(user, other_user)
3759
3760 {:ok, _, _} = CommonAPI.favorite(activity.id, other_user)
3761
3762 response =
3763 conn
3764 |> assign(:user, user)
3765 |> get("/api/v1/statuses/#{activity.id}/favourited_by")
3766 |> json_response(:ok)
3767
3768 assert Enum.empty?(response)
3769 end
3770
3771 test "does not fail on an unauthenticated request", %{conn: conn, activity: activity} do
3772 other_user = insert(:user)
3773 {:ok, _, _} = CommonAPI.favorite(activity.id, other_user)
3774
3775 response =
3776 conn
3777 |> assign(:user, nil)
3778 |> get("/api/v1/statuses/#{activity.id}/favourited_by")
3779 |> json_response(:ok)
3780
3781 [%{"id" => id}] = response
3782 assert id == other_user.id
3783 end
3784 end
3785
3786 describe "GET /api/v1/statuses/:id/reblogged_by" do
3787 setup do
3788 user = insert(:user)
3789 {:ok, activity} = CommonAPI.post(user, %{"status" => "test"})
3790
3791 conn =
3792 build_conn()
3793 |> assign(:user, user)
3794
3795 [conn: conn, activity: activity]
3796 end
3797
3798 test "returns users who have reblogged the status", %{conn: conn, activity: activity} do
3799 other_user = insert(:user)
3800 {:ok, _, _} = CommonAPI.repeat(activity.id, other_user)
3801
3802 response =
3803 conn
3804 |> get("/api/v1/statuses/#{activity.id}/reblogged_by")
3805 |> json_response(:ok)
3806
3807 [%{"id" => id}] = response
3808
3809 assert id == other_user.id
3810 end
3811
3812 test "returns empty array when status has not been reblogged yet", %{
3813 conn: conn,
3814 activity: activity
3815 } do
3816 response =
3817 conn
3818 |> get("/api/v1/statuses/#{activity.id}/reblogged_by")
3819 |> json_response(:ok)
3820
3821 assert Enum.empty?(response)
3822 end
3823
3824 test "does not return users who have reblogged the status but are blocked", %{
3825 conn: %{assigns: %{user: user}} = conn,
3826 activity: activity
3827 } do
3828 other_user = insert(:user)
3829 {:ok, user} = User.block(user, other_user)
3830
3831 {:ok, _, _} = CommonAPI.repeat(activity.id, other_user)
3832
3833 response =
3834 conn
3835 |> assign(:user, user)
3836 |> get("/api/v1/statuses/#{activity.id}/reblogged_by")
3837 |> json_response(:ok)
3838
3839 assert Enum.empty?(response)
3840 end
3841
3842 test "does not fail on an unauthenticated request", %{conn: conn, activity: activity} do
3843 other_user = insert(:user)
3844 {:ok, _, _} = CommonAPI.repeat(activity.id, other_user)
3845
3846 response =
3847 conn
3848 |> assign(:user, nil)
3849 |> get("/api/v1/statuses/#{activity.id}/reblogged_by")
3850 |> json_response(:ok)
3851
3852 [%{"id" => id}] = response
3853 assert id == other_user.id
3854 end
3855 end
3856
3857 describe "POST /auth/password, with valid parameters" do
3858 setup %{conn: conn} do
3859 user = insert(:user)
3860 conn = post(conn, "/auth/password?email=#{user.email}")
3861 %{conn: conn, user: user}
3862 end
3863
3864 test "it returns 204", %{conn: conn} do
3865 assert json_response(conn, :no_content)
3866 end
3867
3868 test "it creates a PasswordResetToken record for user", %{user: user} do
3869 token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id)
3870 assert token_record
3871 end
3872
3873 test "it sends an email to user", %{user: user} do
3874 token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id)
3875
3876 email = Pleroma.Emails.UserEmail.password_reset_email(user, token_record.token)
3877 notify_email = Pleroma.Config.get([:instance, :notify_email])
3878 instance_name = Pleroma.Config.get([:instance, :name])
3879
3880 assert_email_sent(
3881 from: {instance_name, notify_email},
3882 to: {user.name, user.email},
3883 html_body: email.html_body
3884 )
3885 end
3886 end
3887
3888 describe "POST /auth/password, with invalid parameters" do
3889 setup do
3890 user = insert(:user)
3891 {:ok, user: user}
3892 end
3893
3894 test "it returns 404 when user is not found", %{conn: conn, user: user} do
3895 conn = post(conn, "/auth/password?email=nonexisting_#{user.email}")
3896 assert conn.status == 404
3897 assert conn.resp_body == ""
3898 end
3899
3900 test "it returns 400 when user is not local", %{conn: conn, user: user} do
3901 {:ok, user} = Repo.update(Changeset.change(user, local: false))
3902 conn = post(conn, "/auth/password?email=#{user.email}")
3903 assert conn.status == 400
3904 assert conn.resp_body == ""
3905 end
3906 end
3907
3908 describe "POST /api/v1/pleroma/accounts/confirmation_resend" do
3909 setup do
3910 setting = Pleroma.Config.get([:instance, :account_activation_required])
3911
3912 unless setting do
3913 Pleroma.Config.put([:instance, :account_activation_required], true)
3914 on_exit(fn -> Pleroma.Config.put([:instance, :account_activation_required], setting) end)
3915 end
3916
3917 user = insert(:user)
3918 info_change = User.Info.confirmation_changeset(user.info, need_confirmation: true)
3919
3920 {:ok, user} =
3921 user
3922 |> Changeset.change()
3923 |> Changeset.put_embed(:info, info_change)
3924 |> Repo.update()
3925
3926 assert user.info.confirmation_pending
3927
3928 [user: user]
3929 end
3930
3931 test "resend account confirmation email", %{conn: conn, user: user} do
3932 conn
3933 |> assign(:user, user)
3934 |> post("/api/v1/pleroma/accounts/confirmation_resend?email=#{user.email}")
3935 |> json_response(:no_content)
3936
3937 email = Pleroma.Emails.UserEmail.account_confirmation_email(user)
3938 notify_email = Pleroma.Config.get([:instance, :notify_email])
3939 instance_name = Pleroma.Config.get([:instance, :name])
3940
3941 assert_email_sent(
3942 from: {instance_name, notify_email},
3943 to: {user.name, user.email},
3944 html_body: email.html_body
3945 )
3946 end
3947 end
3948 end