Merge branch 'bugfix/unauthed-liked-by' into 'develop'
[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
1675 test "returns proxied url when media proxy is enabled", %{conn: conn, image: image} do
1676 Pleroma.Config.put([Pleroma.Upload, :base_url], "https://media.pleroma.social")
1677
1678 proxy_url = "https://cache.pleroma.social"
1679 Pleroma.Config.put([:media_proxy, :enabled], true)
1680 Pleroma.Config.put([:media_proxy, :base_url], proxy_url)
1681
1682 media =
1683 conn
1684 |> post("/api/v1/media", %{"file" => image})
1685 |> json_response(:ok)
1686
1687 assert String.starts_with?(media["url"], proxy_url)
1688 end
1689
1690 test "returns media url when proxy is enabled but media url is whitelisted", %{
1691 conn: conn,
1692 image: image
1693 } do
1694 media_url = "https://media.pleroma.social"
1695 Pleroma.Config.put([Pleroma.Upload, :base_url], media_url)
1696
1697 Pleroma.Config.put([:media_proxy, :enabled], true)
1698 Pleroma.Config.put([:media_proxy, :base_url], "https://cache.pleroma.social")
1699 Pleroma.Config.put([:media_proxy, :whitelist], ["media.pleroma.social"])
1700
1701 media =
1702 conn
1703 |> post("/api/v1/media", %{"file" => image})
1704 |> json_response(:ok)
1705
1706 assert String.starts_with?(media["url"], media_url)
1707 end
1708 end
1709
1710 describe "locked accounts" do
1711 test "/api/v1/follow_requests works" do
1712 user = insert(:user, %{info: %User.Info{locked: true}})
1713 other_user = insert(:user)
1714
1715 {:ok, _activity} = ActivityPub.follow(other_user, user)
1716
1717 user = User.get_cached_by_id(user.id)
1718 other_user = User.get_cached_by_id(other_user.id)
1719
1720 assert User.following?(other_user, user) == false
1721
1722 conn =
1723 build_conn()
1724 |> assign(:user, user)
1725 |> get("/api/v1/follow_requests")
1726
1727 assert [relationship] = json_response(conn, 200)
1728 assert to_string(other_user.id) == relationship["id"]
1729 end
1730
1731 test "/api/v1/follow_requests/:id/authorize works" do
1732 user = insert(:user, %{info: %User.Info{locked: true}})
1733 other_user = insert(:user)
1734
1735 {:ok, _activity} = ActivityPub.follow(other_user, user)
1736
1737 user = User.get_cached_by_id(user.id)
1738 other_user = User.get_cached_by_id(other_user.id)
1739
1740 assert User.following?(other_user, user) == false
1741
1742 conn =
1743 build_conn()
1744 |> assign(:user, user)
1745 |> post("/api/v1/follow_requests/#{other_user.id}/authorize")
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) == true
1754 end
1755
1756 test "verify_credentials", %{conn: conn} do
1757 user = insert(:user, %{info: %User.Info{default_scope: "private"}})
1758
1759 conn =
1760 conn
1761 |> assign(:user, user)
1762 |> get("/api/v1/accounts/verify_credentials")
1763
1764 assert %{"id" => id, "source" => %{"privacy" => "private"}} = json_response(conn, 200)
1765 assert id == to_string(user.id)
1766 end
1767
1768 test "/api/v1/follow_requests/:id/reject works" do
1769 user = insert(:user, %{info: %User.Info{locked: true}})
1770 other_user = insert(:user)
1771
1772 {:ok, _activity} = ActivityPub.follow(other_user, user)
1773
1774 user = User.get_cached_by_id(user.id)
1775
1776 conn =
1777 build_conn()
1778 |> assign(:user, user)
1779 |> post("/api/v1/follow_requests/#{other_user.id}/reject")
1780
1781 assert relationship = json_response(conn, 200)
1782 assert to_string(other_user.id) == relationship["id"]
1783
1784 user = User.get_cached_by_id(user.id)
1785 other_user = User.get_cached_by_id(other_user.id)
1786
1787 assert User.following?(other_user, user) == false
1788 end
1789 end
1790
1791 test "account fetching", %{conn: conn} do
1792 user = insert(:user)
1793
1794 conn =
1795 conn
1796 |> get("/api/v1/accounts/#{user.id}")
1797
1798 assert %{"id" => id} = json_response(conn, 200)
1799 assert id == to_string(user.id)
1800
1801 conn =
1802 build_conn()
1803 |> get("/api/v1/accounts/-1")
1804
1805 assert %{"error" => "Can't find user"} = json_response(conn, 404)
1806 end
1807
1808 test "account fetching also works nickname", %{conn: conn} do
1809 user = insert(:user)
1810
1811 conn =
1812 conn
1813 |> get("/api/v1/accounts/#{user.nickname}")
1814
1815 assert %{"id" => id} = json_response(conn, 200)
1816 assert id == user.id
1817 end
1818
1819 test "mascot upload", %{conn: conn} do
1820 user = insert(:user)
1821
1822 non_image_file = %Plug.Upload{
1823 content_type: "audio/mpeg",
1824 path: Path.absname("test/fixtures/sound.mp3"),
1825 filename: "sound.mp3"
1826 }
1827
1828 conn =
1829 conn
1830 |> assign(:user, user)
1831 |> put("/api/v1/pleroma/mascot", %{"file" => non_image_file})
1832
1833 assert json_response(conn, 415)
1834
1835 file = %Plug.Upload{
1836 content_type: "image/jpg",
1837 path: Path.absname("test/fixtures/image.jpg"),
1838 filename: "an_image.jpg"
1839 }
1840
1841 conn =
1842 build_conn()
1843 |> assign(:user, user)
1844 |> put("/api/v1/pleroma/mascot", %{"file" => file})
1845
1846 assert %{"id" => _, "type" => image} = json_response(conn, 200)
1847 end
1848
1849 test "mascot retrieving", %{conn: conn} do
1850 user = insert(:user)
1851 # When user hasn't set a mascot, we should just get pleroma tan back
1852 conn =
1853 conn
1854 |> assign(:user, user)
1855 |> get("/api/v1/pleroma/mascot")
1856
1857 assert %{"url" => url} = json_response(conn, 200)
1858 assert url =~ "pleroma-fox-tan-smol"
1859
1860 # When a user sets their mascot, we should get that back
1861 file = %Plug.Upload{
1862 content_type: "image/jpg",
1863 path: Path.absname("test/fixtures/image.jpg"),
1864 filename: "an_image.jpg"
1865 }
1866
1867 conn =
1868 build_conn()
1869 |> assign(:user, user)
1870 |> put("/api/v1/pleroma/mascot", %{"file" => file})
1871
1872 assert json_response(conn, 200)
1873
1874 user = User.get_cached_by_id(user.id)
1875
1876 conn =
1877 build_conn()
1878 |> assign(:user, user)
1879 |> get("/api/v1/pleroma/mascot")
1880
1881 assert %{"url" => url, "type" => "image"} = json_response(conn, 200)
1882 assert url =~ "an_image"
1883 end
1884
1885 test "hashtag timeline", %{conn: conn} do
1886 following = insert(:user)
1887
1888 capture_log(fn ->
1889 {:ok, activity} = CommonAPI.post(following, %{"status" => "test #2hu"})
1890
1891 {:ok, [_activity]} =
1892 OStatus.fetch_activity_from_url("https://shitposter.club/notice/2827873")
1893
1894 nconn =
1895 conn
1896 |> get("/api/v1/timelines/tag/2hu")
1897
1898 assert [%{"id" => id}] = json_response(nconn, 200)
1899
1900 assert id == to_string(activity.id)
1901
1902 # works for different capitalization too
1903 nconn =
1904 conn
1905 |> get("/api/v1/timelines/tag/2HU")
1906
1907 assert [%{"id" => id}] = json_response(nconn, 200)
1908
1909 assert id == to_string(activity.id)
1910 end)
1911 end
1912
1913 test "multi-hashtag timeline", %{conn: conn} do
1914 user = insert(:user)
1915
1916 {:ok, activity_test} = CommonAPI.post(user, %{"status" => "#test"})
1917 {:ok, activity_test1} = CommonAPI.post(user, %{"status" => "#test #test1"})
1918 {:ok, activity_none} = CommonAPI.post(user, %{"status" => "#test #none"})
1919
1920 any_test =
1921 conn
1922 |> get("/api/v1/timelines/tag/test", %{"any" => ["test1"]})
1923
1924 [status_none, status_test1, status_test] = json_response(any_test, 200)
1925
1926 assert to_string(activity_test.id) == status_test["id"]
1927 assert to_string(activity_test1.id) == status_test1["id"]
1928 assert to_string(activity_none.id) == status_none["id"]
1929
1930 restricted_test =
1931 conn
1932 |> get("/api/v1/timelines/tag/test", %{"all" => ["test1"], "none" => ["none"]})
1933
1934 assert [status_test1] == json_response(restricted_test, 200)
1935
1936 all_test = conn |> get("/api/v1/timelines/tag/test", %{"all" => ["none"]})
1937
1938 assert [status_none] == json_response(all_test, 200)
1939 end
1940
1941 test "getting followers", %{conn: conn} do
1942 user = insert(:user)
1943 other_user = insert(:user)
1944 {:ok, user} = User.follow(user, other_user)
1945
1946 conn =
1947 conn
1948 |> get("/api/v1/accounts/#{other_user.id}/followers")
1949
1950 assert [%{"id" => id}] = json_response(conn, 200)
1951 assert id == to_string(user.id)
1952 end
1953
1954 test "getting followers, hide_followers", %{conn: conn} do
1955 user = insert(:user)
1956 other_user = insert(:user, %{info: %{hide_followers: true}})
1957 {:ok, _user} = User.follow(user, other_user)
1958
1959 conn =
1960 conn
1961 |> get("/api/v1/accounts/#{other_user.id}/followers")
1962
1963 assert [] == json_response(conn, 200)
1964 end
1965
1966 test "getting followers, hide_followers, same user requesting", %{conn: conn} do
1967 user = insert(:user)
1968 other_user = insert(:user, %{info: %{hide_followers: true}})
1969 {:ok, _user} = User.follow(user, other_user)
1970
1971 conn =
1972 conn
1973 |> assign(:user, other_user)
1974 |> get("/api/v1/accounts/#{other_user.id}/followers")
1975
1976 refute [] == json_response(conn, 200)
1977 end
1978
1979 test "getting followers, pagination", %{conn: conn} do
1980 user = insert(:user)
1981 follower1 = insert(:user)
1982 follower2 = insert(:user)
1983 follower3 = insert(:user)
1984 {:ok, _} = User.follow(follower1, user)
1985 {:ok, _} = User.follow(follower2, user)
1986 {:ok, _} = User.follow(follower3, user)
1987
1988 conn =
1989 conn
1990 |> assign(:user, user)
1991
1992 res_conn =
1993 conn
1994 |> get("/api/v1/accounts/#{user.id}/followers?since_id=#{follower1.id}")
1995
1996 assert [%{"id" => id3}, %{"id" => id2}] = json_response(res_conn, 200)
1997 assert id3 == follower3.id
1998 assert id2 == follower2.id
1999
2000 res_conn =
2001 conn
2002 |> get("/api/v1/accounts/#{user.id}/followers?max_id=#{follower3.id}")
2003
2004 assert [%{"id" => id2}, %{"id" => id1}] = json_response(res_conn, 200)
2005 assert id2 == follower2.id
2006 assert id1 == follower1.id
2007
2008 res_conn =
2009 conn
2010 |> get("/api/v1/accounts/#{user.id}/followers?limit=1&max_id=#{follower3.id}")
2011
2012 assert [%{"id" => id2}] = json_response(res_conn, 200)
2013 assert id2 == follower2.id
2014
2015 assert [link_header] = get_resp_header(res_conn, "link")
2016 assert link_header =~ ~r/min_id=#{follower2.id}/
2017 assert link_header =~ ~r/max_id=#{follower2.id}/
2018 end
2019
2020 test "getting following", %{conn: conn} do
2021 user = insert(:user)
2022 other_user = insert(:user)
2023 {:ok, user} = User.follow(user, other_user)
2024
2025 conn =
2026 conn
2027 |> get("/api/v1/accounts/#{user.id}/following")
2028
2029 assert [%{"id" => id}] = json_response(conn, 200)
2030 assert id == to_string(other_user.id)
2031 end
2032
2033 test "getting following, hide_follows", %{conn: conn} do
2034 user = insert(:user, %{info: %{hide_follows: true}})
2035 other_user = insert(:user)
2036 {:ok, user} = User.follow(user, other_user)
2037
2038 conn =
2039 conn
2040 |> get("/api/v1/accounts/#{user.id}/following")
2041
2042 assert [] == json_response(conn, 200)
2043 end
2044
2045 test "getting following, hide_follows, same user requesting", %{conn: conn} do
2046 user = insert(:user, %{info: %{hide_follows: true}})
2047 other_user = insert(:user)
2048 {:ok, user} = User.follow(user, other_user)
2049
2050 conn =
2051 conn
2052 |> assign(:user, user)
2053 |> get("/api/v1/accounts/#{user.id}/following")
2054
2055 refute [] == json_response(conn, 200)
2056 end
2057
2058 test "getting following, pagination", %{conn: conn} do
2059 user = insert(:user)
2060 following1 = insert(:user)
2061 following2 = insert(:user)
2062 following3 = insert(:user)
2063 {:ok, _} = User.follow(user, following1)
2064 {:ok, _} = User.follow(user, following2)
2065 {:ok, _} = User.follow(user, following3)
2066
2067 conn =
2068 conn
2069 |> assign(:user, user)
2070
2071 res_conn =
2072 conn
2073 |> get("/api/v1/accounts/#{user.id}/following?since_id=#{following1.id}")
2074
2075 assert [%{"id" => id3}, %{"id" => id2}] = json_response(res_conn, 200)
2076 assert id3 == following3.id
2077 assert id2 == following2.id
2078
2079 res_conn =
2080 conn
2081 |> get("/api/v1/accounts/#{user.id}/following?max_id=#{following3.id}")
2082
2083 assert [%{"id" => id2}, %{"id" => id1}] = json_response(res_conn, 200)
2084 assert id2 == following2.id
2085 assert id1 == following1.id
2086
2087 res_conn =
2088 conn
2089 |> get("/api/v1/accounts/#{user.id}/following?limit=1&max_id=#{following3.id}")
2090
2091 assert [%{"id" => id2}] = json_response(res_conn, 200)
2092 assert id2 == following2.id
2093
2094 assert [link_header] = get_resp_header(res_conn, "link")
2095 assert link_header =~ ~r/min_id=#{following2.id}/
2096 assert link_header =~ ~r/max_id=#{following2.id}/
2097 end
2098
2099 test "following / unfollowing a user", %{conn: conn} do
2100 user = insert(:user)
2101 other_user = insert(:user)
2102
2103 conn =
2104 conn
2105 |> assign(:user, user)
2106 |> post("/api/v1/accounts/#{other_user.id}/follow")
2107
2108 assert %{"id" => _id, "following" => true} = json_response(conn, 200)
2109
2110 user = User.get_cached_by_id(user.id)
2111
2112 conn =
2113 build_conn()
2114 |> assign(:user, user)
2115 |> post("/api/v1/accounts/#{other_user.id}/unfollow")
2116
2117 assert %{"id" => _id, "following" => false} = json_response(conn, 200)
2118
2119 user = User.get_cached_by_id(user.id)
2120
2121 conn =
2122 build_conn()
2123 |> assign(:user, user)
2124 |> post("/api/v1/follows", %{"uri" => other_user.nickname})
2125
2126 assert %{"id" => id} = json_response(conn, 200)
2127 assert id == to_string(other_user.id)
2128 end
2129
2130 test "following without reblogs" do
2131 follower = insert(:user)
2132 followed = insert(:user)
2133 other_user = insert(:user)
2134
2135 conn =
2136 build_conn()
2137 |> assign(:user, follower)
2138 |> post("/api/v1/accounts/#{followed.id}/follow?reblogs=false")
2139
2140 assert %{"showing_reblogs" => false} = json_response(conn, 200)
2141
2142 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hey"})
2143 {:ok, reblog, _} = CommonAPI.repeat(activity.id, followed)
2144
2145 conn =
2146 build_conn()
2147 |> assign(:user, User.get_cached_by_id(follower.id))
2148 |> get("/api/v1/timelines/home")
2149
2150 assert [] == json_response(conn, 200)
2151
2152 conn =
2153 build_conn()
2154 |> assign(:user, follower)
2155 |> post("/api/v1/accounts/#{followed.id}/follow?reblogs=true")
2156
2157 assert %{"showing_reblogs" => true} = json_response(conn, 200)
2158
2159 conn =
2160 build_conn()
2161 |> assign(:user, User.get_cached_by_id(follower.id))
2162 |> get("/api/v1/timelines/home")
2163
2164 expected_activity_id = reblog.id
2165 assert [%{"id" => ^expected_activity_id}] = json_response(conn, 200)
2166 end
2167
2168 test "following / unfollowing errors" do
2169 user = insert(:user)
2170
2171 conn =
2172 build_conn()
2173 |> assign(:user, user)
2174
2175 # self follow
2176 conn_res = post(conn, "/api/v1/accounts/#{user.id}/follow")
2177 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
2178
2179 # self unfollow
2180 user = User.get_cached_by_id(user.id)
2181 conn_res = post(conn, "/api/v1/accounts/#{user.id}/unfollow")
2182 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
2183
2184 # self follow via uri
2185 user = User.get_cached_by_id(user.id)
2186 conn_res = post(conn, "/api/v1/follows", %{"uri" => user.nickname})
2187 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
2188
2189 # follow non existing user
2190 conn_res = post(conn, "/api/v1/accounts/doesntexist/follow")
2191 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
2192
2193 # follow non existing user via uri
2194 conn_res = post(conn, "/api/v1/follows", %{"uri" => "doesntexist"})
2195 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
2196
2197 # unfollow non existing user
2198 conn_res = post(conn, "/api/v1/accounts/doesntexist/unfollow")
2199 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
2200 end
2201
2202 describe "mute/unmute" do
2203 test "with notifications", %{conn: conn} do
2204 user = insert(:user)
2205 other_user = insert(:user)
2206
2207 conn =
2208 conn
2209 |> assign(:user, user)
2210 |> post("/api/v1/accounts/#{other_user.id}/mute")
2211
2212 response = json_response(conn, 200)
2213
2214 assert %{"id" => _id, "muting" => true, "muting_notifications" => true} = response
2215 user = User.get_cached_by_id(user.id)
2216
2217 conn =
2218 build_conn()
2219 |> assign(:user, user)
2220 |> post("/api/v1/accounts/#{other_user.id}/unmute")
2221
2222 response = json_response(conn, 200)
2223 assert %{"id" => _id, "muting" => false, "muting_notifications" => false} = response
2224 end
2225
2226 test "without notifications", %{conn: conn} do
2227 user = insert(:user)
2228 other_user = insert(:user)
2229
2230 conn =
2231 conn
2232 |> assign(:user, user)
2233 |> post("/api/v1/accounts/#{other_user.id}/mute", %{"notifications" => "false"})
2234
2235 response = json_response(conn, 200)
2236
2237 assert %{"id" => _id, "muting" => true, "muting_notifications" => false} = response
2238 user = User.get_cached_by_id(user.id)
2239
2240 conn =
2241 build_conn()
2242 |> assign(:user, user)
2243 |> post("/api/v1/accounts/#{other_user.id}/unmute")
2244
2245 response = json_response(conn, 200)
2246 assert %{"id" => _id, "muting" => false, "muting_notifications" => false} = response
2247 end
2248 end
2249
2250 test "subscribing / unsubscribing to a user", %{conn: conn} do
2251 user = insert(:user)
2252 subscription_target = insert(:user)
2253
2254 conn =
2255 conn
2256 |> assign(:user, user)
2257 |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/subscribe")
2258
2259 assert %{"id" => _id, "subscribing" => true} = json_response(conn, 200)
2260
2261 conn =
2262 build_conn()
2263 |> assign(:user, user)
2264 |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/unsubscribe")
2265
2266 assert %{"id" => _id, "subscribing" => false} = json_response(conn, 200)
2267 end
2268
2269 test "getting a list of mutes", %{conn: conn} do
2270 user = insert(:user)
2271 other_user = insert(:user)
2272
2273 {:ok, user} = User.mute(user, other_user)
2274
2275 conn =
2276 conn
2277 |> assign(:user, user)
2278 |> get("/api/v1/mutes")
2279
2280 other_user_id = to_string(other_user.id)
2281 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
2282 end
2283
2284 test "blocking / unblocking a user", %{conn: conn} do
2285 user = insert(:user)
2286 other_user = insert(:user)
2287
2288 conn =
2289 conn
2290 |> assign(:user, user)
2291 |> post("/api/v1/accounts/#{other_user.id}/block")
2292
2293 assert %{"id" => _id, "blocking" => true} = json_response(conn, 200)
2294
2295 user = User.get_cached_by_id(user.id)
2296
2297 conn =
2298 build_conn()
2299 |> assign(:user, user)
2300 |> post("/api/v1/accounts/#{other_user.id}/unblock")
2301
2302 assert %{"id" => _id, "blocking" => false} = json_response(conn, 200)
2303 end
2304
2305 test "getting a list of blocks", %{conn: conn} do
2306 user = insert(:user)
2307 other_user = insert(:user)
2308
2309 {:ok, user} = User.block(user, other_user)
2310
2311 conn =
2312 conn
2313 |> assign(:user, user)
2314 |> get("/api/v1/blocks")
2315
2316 other_user_id = to_string(other_user.id)
2317 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
2318 end
2319
2320 test "blocking / unblocking a domain", %{conn: conn} do
2321 user = insert(:user)
2322 other_user = insert(:user, %{ap_id: "https://dogwhistle.zone/@pundit"})
2323
2324 conn =
2325 conn
2326 |> assign(:user, user)
2327 |> post("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"})
2328
2329 assert %{} = json_response(conn, 200)
2330 user = User.get_cached_by_ap_id(user.ap_id)
2331 assert User.blocks?(user, other_user)
2332
2333 conn =
2334 build_conn()
2335 |> assign(:user, user)
2336 |> delete("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"})
2337
2338 assert %{} = json_response(conn, 200)
2339 user = User.get_cached_by_ap_id(user.ap_id)
2340 refute User.blocks?(user, other_user)
2341 end
2342
2343 test "getting a list of domain blocks", %{conn: conn} do
2344 user = insert(:user)
2345
2346 {:ok, user} = User.block_domain(user, "bad.site")
2347 {:ok, user} = User.block_domain(user, "even.worse.site")
2348
2349 conn =
2350 conn
2351 |> assign(:user, user)
2352 |> get("/api/v1/domain_blocks")
2353
2354 domain_blocks = json_response(conn, 200)
2355
2356 assert "bad.site" in domain_blocks
2357 assert "even.worse.site" in domain_blocks
2358 end
2359
2360 test "unimplemented follow_requests, blocks, domain blocks" do
2361 user = insert(:user)
2362
2363 ["blocks", "domain_blocks", "follow_requests"]
2364 |> Enum.each(fn endpoint ->
2365 conn =
2366 build_conn()
2367 |> assign(:user, user)
2368 |> get("/api/v1/#{endpoint}")
2369
2370 assert [] = json_response(conn, 200)
2371 end)
2372 end
2373
2374 test "returns the favorites of a user", %{conn: conn} do
2375 user = insert(:user)
2376 other_user = insert(:user)
2377
2378 {:ok, _} = CommonAPI.post(other_user, %{"status" => "bla"})
2379 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "traps are happy"})
2380
2381 {:ok, _, _} = CommonAPI.favorite(activity.id, user)
2382
2383 first_conn =
2384 conn
2385 |> assign(:user, user)
2386 |> get("/api/v1/favourites")
2387
2388 assert [status] = json_response(first_conn, 200)
2389 assert status["id"] == to_string(activity.id)
2390
2391 assert [{"link", _link_header}] =
2392 Enum.filter(first_conn.resp_headers, fn element -> match?({"link", _}, element) end)
2393
2394 # Honours query params
2395 {:ok, second_activity} =
2396 CommonAPI.post(other_user, %{
2397 "status" =>
2398 "Trees Are Never Sad Look At Them Every Once In Awhile They're Quite Beautiful."
2399 })
2400
2401 {:ok, _, _} = CommonAPI.favorite(second_activity.id, user)
2402
2403 last_like = status["id"]
2404
2405 second_conn =
2406 conn
2407 |> assign(:user, user)
2408 |> get("/api/v1/favourites?since_id=#{last_like}")
2409
2410 assert [second_status] = json_response(second_conn, 200)
2411 assert second_status["id"] == to_string(second_activity.id)
2412
2413 third_conn =
2414 conn
2415 |> assign(:user, user)
2416 |> get("/api/v1/favourites?limit=0")
2417
2418 assert [] = json_response(third_conn, 200)
2419 end
2420
2421 describe "getting favorites timeline of specified user" do
2422 setup do
2423 [current_user, user] = insert_pair(:user, %{info: %{hide_favorites: false}})
2424 [current_user: current_user, user: user]
2425 end
2426
2427 test "returns list of statuses favorited by specified user", %{
2428 conn: conn,
2429 current_user: current_user,
2430 user: user
2431 } do
2432 [activity | _] = insert_pair(:note_activity)
2433 CommonAPI.favorite(activity.id, user)
2434
2435 response =
2436 conn
2437 |> assign(:user, current_user)
2438 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2439 |> json_response(:ok)
2440
2441 [like] = response
2442
2443 assert length(response) == 1
2444 assert like["id"] == activity.id
2445 end
2446
2447 test "returns favorites for specified user_id when user is not logged in", %{
2448 conn: conn,
2449 user: user
2450 } do
2451 activity = insert(:note_activity)
2452 CommonAPI.favorite(activity.id, user)
2453
2454 response =
2455 conn
2456 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2457 |> json_response(:ok)
2458
2459 assert length(response) == 1
2460 end
2461
2462 test "returns favorited DM only when user is logged in and he is one of recipients", %{
2463 conn: conn,
2464 current_user: current_user,
2465 user: user
2466 } do
2467 {:ok, direct} =
2468 CommonAPI.post(current_user, %{
2469 "status" => "Hi @#{user.nickname}!",
2470 "visibility" => "direct"
2471 })
2472
2473 CommonAPI.favorite(direct.id, user)
2474
2475 response =
2476 conn
2477 |> assign(:user, current_user)
2478 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2479 |> json_response(:ok)
2480
2481 assert length(response) == 1
2482
2483 anonymous_response =
2484 conn
2485 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2486 |> json_response(:ok)
2487
2488 assert Enum.empty?(anonymous_response)
2489 end
2490
2491 test "does not return others' favorited DM when user is not one of recipients", %{
2492 conn: conn,
2493 current_user: current_user,
2494 user: user
2495 } do
2496 user_two = insert(:user)
2497
2498 {:ok, direct} =
2499 CommonAPI.post(user_two, %{
2500 "status" => "Hi @#{user.nickname}!",
2501 "visibility" => "direct"
2502 })
2503
2504 CommonAPI.favorite(direct.id, user)
2505
2506 response =
2507 conn
2508 |> assign(:user, current_user)
2509 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2510 |> json_response(:ok)
2511
2512 assert Enum.empty?(response)
2513 end
2514
2515 test "paginates favorites using since_id and max_id", %{
2516 conn: conn,
2517 current_user: current_user,
2518 user: user
2519 } do
2520 activities = insert_list(10, :note_activity)
2521
2522 Enum.each(activities, fn activity ->
2523 CommonAPI.favorite(activity.id, user)
2524 end)
2525
2526 third_activity = Enum.at(activities, 2)
2527 seventh_activity = Enum.at(activities, 6)
2528
2529 response =
2530 conn
2531 |> assign(:user, current_user)
2532 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites", %{
2533 since_id: third_activity.id,
2534 max_id: seventh_activity.id
2535 })
2536 |> json_response(:ok)
2537
2538 assert length(response) == 3
2539 refute third_activity in response
2540 refute seventh_activity in response
2541 end
2542
2543 test "limits favorites using limit parameter", %{
2544 conn: conn,
2545 current_user: current_user,
2546 user: user
2547 } do
2548 7
2549 |> insert_list(:note_activity)
2550 |> Enum.each(fn activity ->
2551 CommonAPI.favorite(activity.id, user)
2552 end)
2553
2554 response =
2555 conn
2556 |> assign(:user, current_user)
2557 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites", %{limit: "3"})
2558 |> json_response(:ok)
2559
2560 assert length(response) == 3
2561 end
2562
2563 test "returns empty response when user does not have any favorited statuses", %{
2564 conn: conn,
2565 current_user: current_user,
2566 user: user
2567 } do
2568 response =
2569 conn
2570 |> assign(:user, current_user)
2571 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2572 |> json_response(:ok)
2573
2574 assert Enum.empty?(response)
2575 end
2576
2577 test "returns 404 error when specified user is not exist", %{conn: conn} do
2578 conn = get(conn, "/api/v1/pleroma/accounts/test/favourites")
2579
2580 assert json_response(conn, 404) == %{"error" => "Record not found"}
2581 end
2582
2583 test "returns 403 error when user has hidden own favorites", %{
2584 conn: conn,
2585 current_user: current_user
2586 } do
2587 user = insert(:user, %{info: %{hide_favorites: true}})
2588 activity = insert(:note_activity)
2589 CommonAPI.favorite(activity.id, user)
2590
2591 conn =
2592 conn
2593 |> assign(:user, current_user)
2594 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2595
2596 assert json_response(conn, 403) == %{"error" => "Can't get favorites"}
2597 end
2598
2599 test "hides favorites for new users by default", %{conn: conn, current_user: current_user} do
2600 user = insert(:user)
2601 activity = insert(:note_activity)
2602 CommonAPI.favorite(activity.id, user)
2603
2604 conn =
2605 conn
2606 |> assign(:user, current_user)
2607 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2608
2609 assert user.info.hide_favorites
2610 assert json_response(conn, 403) == %{"error" => "Can't get favorites"}
2611 end
2612 end
2613
2614 test "get instance information", %{conn: conn} do
2615 conn = get(conn, "/api/v1/instance")
2616 assert result = json_response(conn, 200)
2617
2618 email = Pleroma.Config.get([:instance, :email])
2619 # Note: not checking for "max_toot_chars" since it's optional
2620 assert %{
2621 "uri" => _,
2622 "title" => _,
2623 "description" => _,
2624 "version" => _,
2625 "email" => from_config_email,
2626 "urls" => %{
2627 "streaming_api" => _
2628 },
2629 "stats" => _,
2630 "thumbnail" => _,
2631 "languages" => _,
2632 "registrations" => _,
2633 "poll_limits" => _
2634 } = result
2635
2636 assert email == from_config_email
2637 end
2638
2639 test "get instance stats", %{conn: conn} do
2640 user = insert(:user, %{local: true})
2641
2642 user2 = insert(:user, %{local: true})
2643 {:ok, _user2} = User.deactivate(user2, !user2.info.deactivated)
2644
2645 insert(:user, %{local: false, nickname: "u@peer1.com"})
2646 insert(:user, %{local: false, nickname: "u@peer2.com"})
2647
2648 {:ok, _} = CommonAPI.post(user, %{"status" => "cofe"})
2649
2650 # Stats should count users with missing or nil `info.deactivated` value
2651 user = User.get_cached_by_id(user.id)
2652 info_change = Changeset.change(user.info, %{deactivated: nil})
2653
2654 {:ok, _user} =
2655 user
2656 |> Changeset.change()
2657 |> Changeset.put_embed(:info, info_change)
2658 |> User.update_and_set_cache()
2659
2660 Pleroma.Stats.update_stats()
2661
2662 conn = get(conn, "/api/v1/instance")
2663
2664 assert result = json_response(conn, 200)
2665
2666 stats = result["stats"]
2667
2668 assert stats
2669 assert stats["user_count"] == 1
2670 assert stats["status_count"] == 1
2671 assert stats["domain_count"] == 2
2672 end
2673
2674 test "get peers", %{conn: conn} do
2675 insert(:user, %{local: false, nickname: "u@peer1.com"})
2676 insert(:user, %{local: false, nickname: "u@peer2.com"})
2677
2678 Pleroma.Stats.update_stats()
2679
2680 conn = get(conn, "/api/v1/instance/peers")
2681
2682 assert result = json_response(conn, 200)
2683
2684 assert ["peer1.com", "peer2.com"] == Enum.sort(result)
2685 end
2686
2687 test "put settings", %{conn: conn} do
2688 user = insert(:user)
2689
2690 conn =
2691 conn
2692 |> assign(:user, user)
2693 |> put("/api/web/settings", %{"data" => %{"programming" => "socks"}})
2694
2695 assert _result = json_response(conn, 200)
2696
2697 user = User.get_cached_by_ap_id(user.ap_id)
2698 assert user.info.settings == %{"programming" => "socks"}
2699 end
2700
2701 describe "pinned statuses" do
2702 setup do
2703 Pleroma.Config.put([:instance, :max_pinned_statuses], 1)
2704
2705 user = insert(:user)
2706 {:ok, activity} = CommonAPI.post(user, %{"status" => "HI!!!"})
2707
2708 [user: user, activity: activity]
2709 end
2710
2711 test "returns pinned statuses", %{conn: conn, user: user, activity: activity} do
2712 {:ok, _} = CommonAPI.pin(activity.id, user)
2713
2714 result =
2715 conn
2716 |> assign(:user, user)
2717 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2718 |> json_response(200)
2719
2720 id_str = to_string(activity.id)
2721
2722 assert [%{"id" => ^id_str, "pinned" => true}] = result
2723 end
2724
2725 test "pin status", %{conn: conn, user: user, activity: activity} do
2726 id_str = to_string(activity.id)
2727
2728 assert %{"id" => ^id_str, "pinned" => true} =
2729 conn
2730 |> assign(:user, user)
2731 |> post("/api/v1/statuses/#{activity.id}/pin")
2732 |> json_response(200)
2733
2734 assert [%{"id" => ^id_str, "pinned" => true}] =
2735 conn
2736 |> assign(:user, user)
2737 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2738 |> json_response(200)
2739 end
2740
2741 test "/pin: returns 400 error when activity is not public", %{conn: conn, user: user} do
2742 {:ok, dm} = CommonAPI.post(user, %{"status" => "test", "visibility" => "direct"})
2743
2744 conn =
2745 conn
2746 |> assign(:user, user)
2747 |> post("/api/v1/statuses/#{dm.id}/pin")
2748
2749 assert json_response(conn, 400) == %{"error" => "Could not pin"}
2750 end
2751
2752 test "unpin status", %{conn: conn, user: user, activity: activity} do
2753 {:ok, _} = CommonAPI.pin(activity.id, user)
2754
2755 id_str = to_string(activity.id)
2756 user = refresh_record(user)
2757
2758 assert %{"id" => ^id_str, "pinned" => false} =
2759 conn
2760 |> assign(:user, user)
2761 |> post("/api/v1/statuses/#{activity.id}/unpin")
2762 |> json_response(200)
2763
2764 assert [] =
2765 conn
2766 |> assign(:user, user)
2767 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2768 |> json_response(200)
2769 end
2770
2771 test "/unpin: returns 400 error when activity is not exist", %{conn: conn, user: user} do
2772 conn =
2773 conn
2774 |> assign(:user, user)
2775 |> post("/api/v1/statuses/1/unpin")
2776
2777 assert json_response(conn, 400) == %{"error" => "Could not unpin"}
2778 end
2779
2780 test "max pinned statuses", %{conn: conn, user: user, activity: activity_one} do
2781 {:ok, activity_two} = CommonAPI.post(user, %{"status" => "HI!!!"})
2782
2783 id_str_one = to_string(activity_one.id)
2784
2785 assert %{"id" => ^id_str_one, "pinned" => true} =
2786 conn
2787 |> assign(:user, user)
2788 |> post("/api/v1/statuses/#{id_str_one}/pin")
2789 |> json_response(200)
2790
2791 user = refresh_record(user)
2792
2793 assert %{"error" => "You have already pinned the maximum number of statuses"} =
2794 conn
2795 |> assign(:user, user)
2796 |> post("/api/v1/statuses/#{activity_two.id}/pin")
2797 |> json_response(400)
2798 end
2799 end
2800
2801 describe "cards" do
2802 setup do
2803 Pleroma.Config.put([:rich_media, :enabled], true)
2804
2805 on_exit(fn ->
2806 Pleroma.Config.put([:rich_media, :enabled], false)
2807 end)
2808
2809 user = insert(:user)
2810 %{user: user}
2811 end
2812
2813 test "returns rich-media card", %{conn: conn, user: user} do
2814 {:ok, activity} = CommonAPI.post(user, %{"status" => "https://example.com/ogp"})
2815
2816 card_data = %{
2817 "image" => "http://ia.media-imdb.com/images/rock.jpg",
2818 "provider_name" => "www.imdb.com",
2819 "provider_url" => "http://www.imdb.com",
2820 "title" => "The Rock",
2821 "type" => "link",
2822 "url" => "http://www.imdb.com/title/tt0117500/",
2823 "description" =>
2824 "Directed by Michael Bay. With Sean Connery, Nicolas Cage, Ed Harris, John Spencer.",
2825 "pleroma" => %{
2826 "opengraph" => %{
2827 "image" => "http://ia.media-imdb.com/images/rock.jpg",
2828 "title" => "The Rock",
2829 "type" => "video.movie",
2830 "url" => "http://www.imdb.com/title/tt0117500/",
2831 "description" =>
2832 "Directed by Michael Bay. With Sean Connery, Nicolas Cage, Ed Harris, John Spencer."
2833 }
2834 }
2835 }
2836
2837 response =
2838 conn
2839 |> get("/api/v1/statuses/#{activity.id}/card")
2840 |> json_response(200)
2841
2842 assert response == card_data
2843
2844 # works with private posts
2845 {:ok, activity} =
2846 CommonAPI.post(user, %{"status" => "https://example.com/ogp", "visibility" => "direct"})
2847
2848 response_two =
2849 conn
2850 |> assign(:user, user)
2851 |> get("/api/v1/statuses/#{activity.id}/card")
2852 |> json_response(200)
2853
2854 assert response_two == card_data
2855 end
2856
2857 test "replaces missing description with an empty string", %{conn: conn, user: user} do
2858 {:ok, activity} =
2859 CommonAPI.post(user, %{"status" => "https://example.com/ogp-missing-data"})
2860
2861 response =
2862 conn
2863 |> get("/api/v1/statuses/#{activity.id}/card")
2864 |> json_response(:ok)
2865
2866 assert response == %{
2867 "type" => "link",
2868 "title" => "Pleroma",
2869 "description" => "",
2870 "image" => nil,
2871 "provider_name" => "pleroma.social",
2872 "provider_url" => "https://pleroma.social",
2873 "url" => "https://pleroma.social/",
2874 "pleroma" => %{
2875 "opengraph" => %{
2876 "title" => "Pleroma",
2877 "type" => "website",
2878 "url" => "https://pleroma.social/"
2879 }
2880 }
2881 }
2882 end
2883 end
2884
2885 test "bookmarks" do
2886 user = insert(:user)
2887 for_user = insert(:user)
2888
2889 {:ok, activity1} =
2890 CommonAPI.post(user, %{
2891 "status" => "heweoo?"
2892 })
2893
2894 {:ok, activity2} =
2895 CommonAPI.post(user, %{
2896 "status" => "heweoo!"
2897 })
2898
2899 response1 =
2900 build_conn()
2901 |> assign(:user, for_user)
2902 |> post("/api/v1/statuses/#{activity1.id}/bookmark")
2903
2904 assert json_response(response1, 200)["bookmarked"] == true
2905
2906 response2 =
2907 build_conn()
2908 |> assign(:user, for_user)
2909 |> post("/api/v1/statuses/#{activity2.id}/bookmark")
2910
2911 assert json_response(response2, 200)["bookmarked"] == true
2912
2913 bookmarks =
2914 build_conn()
2915 |> assign(:user, for_user)
2916 |> get("/api/v1/bookmarks")
2917
2918 assert [json_response(response2, 200), json_response(response1, 200)] ==
2919 json_response(bookmarks, 200)
2920
2921 response1 =
2922 build_conn()
2923 |> assign(:user, for_user)
2924 |> post("/api/v1/statuses/#{activity1.id}/unbookmark")
2925
2926 assert json_response(response1, 200)["bookmarked"] == false
2927
2928 bookmarks =
2929 build_conn()
2930 |> assign(:user, for_user)
2931 |> get("/api/v1/bookmarks")
2932
2933 assert [json_response(response2, 200)] == json_response(bookmarks, 200)
2934 end
2935
2936 describe "conversation muting" do
2937 setup do
2938 user = insert(:user)
2939 {:ok, activity} = CommonAPI.post(user, %{"status" => "HIE"})
2940
2941 [user: user, activity: activity]
2942 end
2943
2944 test "mute conversation", %{conn: conn, user: user, activity: activity} do
2945 id_str = to_string(activity.id)
2946
2947 assert %{"id" => ^id_str, "muted" => true} =
2948 conn
2949 |> assign(:user, user)
2950 |> post("/api/v1/statuses/#{activity.id}/mute")
2951 |> json_response(200)
2952 end
2953
2954 test "cannot mute already muted conversation", %{conn: conn, user: user, activity: activity} do
2955 {:ok, _} = CommonAPI.add_mute(user, activity)
2956
2957 conn =
2958 conn
2959 |> assign(:user, user)
2960 |> post("/api/v1/statuses/#{activity.id}/mute")
2961
2962 assert json_response(conn, 400) == %{"error" => "conversation is already muted"}
2963 end
2964
2965 test "unmute conversation", %{conn: conn, user: user, activity: activity} do
2966 {:ok, _} = CommonAPI.add_mute(user, activity)
2967
2968 id_str = to_string(activity.id)
2969 user = refresh_record(user)
2970
2971 assert %{"id" => ^id_str, "muted" => false} =
2972 conn
2973 |> assign(:user, user)
2974 |> post("/api/v1/statuses/#{activity.id}/unmute")
2975 |> json_response(200)
2976 end
2977 end
2978
2979 describe "reports" do
2980 setup do
2981 reporter = insert(:user)
2982 target_user = insert(:user)
2983
2984 {:ok, activity} = CommonAPI.post(target_user, %{"status" => "foobar"})
2985
2986 [reporter: reporter, target_user: target_user, activity: activity]
2987 end
2988
2989 test "submit a basic report", %{conn: conn, reporter: reporter, target_user: target_user} do
2990 assert %{"action_taken" => false, "id" => _} =
2991 conn
2992 |> assign(:user, reporter)
2993 |> post("/api/v1/reports", %{"account_id" => target_user.id})
2994 |> json_response(200)
2995 end
2996
2997 test "submit a report with statuses and comment", %{
2998 conn: conn,
2999 reporter: reporter,
3000 target_user: target_user,
3001 activity: activity
3002 } do
3003 assert %{"action_taken" => false, "id" => _} =
3004 conn
3005 |> assign(:user, reporter)
3006 |> post("/api/v1/reports", %{
3007 "account_id" => target_user.id,
3008 "status_ids" => [activity.id],
3009 "comment" => "bad status!",
3010 "forward" => "false"
3011 })
3012 |> json_response(200)
3013 end
3014
3015 test "account_id is required", %{
3016 conn: conn,
3017 reporter: reporter,
3018 activity: activity
3019 } do
3020 assert %{"error" => "Valid `account_id` required"} =
3021 conn
3022 |> assign(:user, reporter)
3023 |> post("/api/v1/reports", %{"status_ids" => [activity.id]})
3024 |> json_response(400)
3025 end
3026
3027 test "comment must be up to the size specified in the config", %{
3028 conn: conn,
3029 reporter: reporter,
3030 target_user: target_user
3031 } do
3032 max_size = Pleroma.Config.get([:instance, :max_report_comment_size], 1000)
3033 comment = String.pad_trailing("a", max_size + 1, "a")
3034
3035 error = %{"error" => "Comment must be up to #{max_size} characters"}
3036
3037 assert ^error =
3038 conn
3039 |> assign(:user, reporter)
3040 |> post("/api/v1/reports", %{"account_id" => target_user.id, "comment" => comment})
3041 |> json_response(400)
3042 end
3043
3044 test "returns error when account is not exist", %{
3045 conn: conn,
3046 reporter: reporter,
3047 activity: activity
3048 } do
3049 conn =
3050 conn
3051 |> assign(:user, reporter)
3052 |> post("/api/v1/reports", %{"status_ids" => [activity.id], "account_id" => "foo"})
3053
3054 assert json_response(conn, 400) == %{"error" => "Account not found"}
3055 end
3056 end
3057
3058 describe "link headers" do
3059 test "preserves parameters in link headers", %{conn: conn} do
3060 user = insert(:user)
3061 other_user = insert(:user)
3062
3063 {:ok, activity1} =
3064 CommonAPI.post(other_user, %{
3065 "status" => "hi @#{user.nickname}",
3066 "visibility" => "public"
3067 })
3068
3069 {:ok, activity2} =
3070 CommonAPI.post(other_user, %{
3071 "status" => "hi @#{user.nickname}",
3072 "visibility" => "public"
3073 })
3074
3075 notification1 = Repo.get_by(Notification, activity_id: activity1.id)
3076 notification2 = Repo.get_by(Notification, activity_id: activity2.id)
3077
3078 conn =
3079 conn
3080 |> assign(:user, user)
3081 |> get("/api/v1/notifications", %{media_only: true})
3082
3083 assert [link_header] = get_resp_header(conn, "link")
3084 assert link_header =~ ~r/media_only=true/
3085 assert link_header =~ ~r/min_id=#{notification2.id}/
3086 assert link_header =~ ~r/max_id=#{notification1.id}/
3087 end
3088 end
3089
3090 test "accounts fetches correct account for nicknames beginning with numbers", %{conn: conn} do
3091 # Need to set an old-style integer ID to reproduce the problem
3092 # (these are no longer assigned to new accounts but were preserved
3093 # for existing accounts during the migration to flakeIDs)
3094 user_one = insert(:user, %{id: 1212})
3095 user_two = insert(:user, %{nickname: "#{user_one.id}garbage"})
3096
3097 resp_one =
3098 conn
3099 |> get("/api/v1/accounts/#{user_one.id}")
3100
3101 resp_two =
3102 conn
3103 |> get("/api/v1/accounts/#{user_two.nickname}")
3104
3105 resp_three =
3106 conn
3107 |> get("/api/v1/accounts/#{user_two.id}")
3108
3109 acc_one = json_response(resp_one, 200)
3110 acc_two = json_response(resp_two, 200)
3111 acc_three = json_response(resp_three, 200)
3112 refute acc_one == acc_two
3113 assert acc_two == acc_three
3114 end
3115
3116 describe "custom emoji" do
3117 test "with tags", %{conn: conn} do
3118 [emoji | _body] =
3119 conn
3120 |> get("/api/v1/custom_emojis")
3121 |> json_response(200)
3122
3123 assert Map.has_key?(emoji, "shortcode")
3124 assert Map.has_key?(emoji, "static_url")
3125 assert Map.has_key?(emoji, "tags")
3126 assert is_list(emoji["tags"])
3127 assert Map.has_key?(emoji, "category")
3128 assert Map.has_key?(emoji, "url")
3129 assert Map.has_key?(emoji, "visible_in_picker")
3130 end
3131 end
3132
3133 describe "index/2 redirections" do
3134 setup %{conn: conn} do
3135 session_opts = [
3136 store: :cookie,
3137 key: "_test",
3138 signing_salt: "cooldude"
3139 ]
3140
3141 conn =
3142 conn
3143 |> Plug.Session.call(Plug.Session.init(session_opts))
3144 |> fetch_session()
3145
3146 test_path = "/web/statuses/test"
3147 %{conn: conn, path: test_path}
3148 end
3149
3150 test "redirects not logged-in users to the login page", %{conn: conn, path: path} do
3151 conn = get(conn, path)
3152
3153 assert conn.status == 302
3154 assert redirected_to(conn) == "/web/login"
3155 end
3156
3157 test "does not redirect logged in users to the login page", %{conn: conn, path: path} do
3158 token = insert(:oauth_token)
3159
3160 conn =
3161 conn
3162 |> assign(:user, token.user)
3163 |> put_session(:oauth_token, token.token)
3164 |> get(path)
3165
3166 assert conn.status == 200
3167 end
3168
3169 test "saves referer path to session", %{conn: conn, path: path} do
3170 conn = get(conn, path)
3171 return_to = Plug.Conn.get_session(conn, :return_to)
3172
3173 assert return_to == path
3174 end
3175
3176 test "redirects to the saved path after log in", %{conn: conn, path: path} do
3177 app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
3178 auth = insert(:oauth_authorization, app: app)
3179
3180 conn =
3181 conn
3182 |> put_session(:return_to, path)
3183 |> get("/web/login", %{code: auth.token})
3184
3185 assert conn.status == 302
3186 assert redirected_to(conn) == path
3187 end
3188
3189 test "redirects to the getting-started page when referer is not present", %{conn: conn} do
3190 app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
3191 auth = insert(:oauth_authorization, app: app)
3192
3193 conn = get(conn, "/web/login", %{code: auth.token})
3194
3195 assert conn.status == 302
3196 assert redirected_to(conn) == "/web/getting-started"
3197 end
3198 end
3199
3200 describe "scheduled activities" do
3201 test "creates a scheduled activity", %{conn: conn} do
3202 user = insert(:user)
3203 scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
3204
3205 conn =
3206 conn
3207 |> assign(:user, user)
3208 |> post("/api/v1/statuses", %{
3209 "status" => "scheduled",
3210 "scheduled_at" => scheduled_at
3211 })
3212
3213 assert %{"scheduled_at" => expected_scheduled_at} = json_response(conn, 200)
3214 assert expected_scheduled_at == Pleroma.Web.CommonAPI.Utils.to_masto_date(scheduled_at)
3215 assert [] == Repo.all(Activity)
3216 end
3217
3218 test "creates a scheduled activity with a media attachment", %{conn: conn} do
3219 user = insert(:user)
3220 scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
3221
3222 file = %Plug.Upload{
3223 content_type: "image/jpg",
3224 path: Path.absname("test/fixtures/image.jpg"),
3225 filename: "an_image.jpg"
3226 }
3227
3228 {:ok, upload} = ActivityPub.upload(file, actor: user.ap_id)
3229
3230 conn =
3231 conn
3232 |> assign(:user, user)
3233 |> post("/api/v1/statuses", %{
3234 "media_ids" => [to_string(upload.id)],
3235 "status" => "scheduled",
3236 "scheduled_at" => scheduled_at
3237 })
3238
3239 assert %{"media_attachments" => [media_attachment]} = json_response(conn, 200)
3240 assert %{"type" => "image"} = media_attachment
3241 end
3242
3243 test "skips the scheduling and creates the activity if scheduled_at is earlier than 5 minutes from now",
3244 %{conn: conn} do
3245 user = insert(:user)
3246
3247 scheduled_at =
3248 NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(5) - 1, :millisecond)
3249
3250 conn =
3251 conn
3252 |> assign(:user, user)
3253 |> post("/api/v1/statuses", %{
3254 "status" => "not scheduled",
3255 "scheduled_at" => scheduled_at
3256 })
3257
3258 assert %{"content" => "not scheduled"} = json_response(conn, 200)
3259 assert [] == Repo.all(ScheduledActivity)
3260 end
3261
3262 test "returns error when daily user limit is exceeded", %{conn: conn} do
3263 user = insert(:user)
3264
3265 today =
3266 NaiveDateTime.utc_now()
3267 |> NaiveDateTime.add(:timer.minutes(6), :millisecond)
3268 |> NaiveDateTime.to_iso8601()
3269
3270 attrs = %{params: %{}, scheduled_at: today}
3271 {:ok, _} = ScheduledActivity.create(user, attrs)
3272 {:ok, _} = ScheduledActivity.create(user, attrs)
3273
3274 conn =
3275 conn
3276 |> assign(:user, user)
3277 |> post("/api/v1/statuses", %{"status" => "scheduled", "scheduled_at" => today})
3278
3279 assert %{"error" => "daily limit exceeded"} == json_response(conn, 422)
3280 end
3281
3282 test "returns error when total user limit is exceeded", %{conn: conn} do
3283 user = insert(:user)
3284
3285 today =
3286 NaiveDateTime.utc_now()
3287 |> NaiveDateTime.add(:timer.minutes(6), :millisecond)
3288 |> NaiveDateTime.to_iso8601()
3289
3290 tomorrow =
3291 NaiveDateTime.utc_now()
3292 |> NaiveDateTime.add(:timer.hours(36), :millisecond)
3293 |> NaiveDateTime.to_iso8601()
3294
3295 attrs = %{params: %{}, scheduled_at: today}
3296 {:ok, _} = ScheduledActivity.create(user, attrs)
3297 {:ok, _} = ScheduledActivity.create(user, attrs)
3298 {:ok, _} = ScheduledActivity.create(user, %{params: %{}, scheduled_at: tomorrow})
3299
3300 conn =
3301 conn
3302 |> assign(:user, user)
3303 |> post("/api/v1/statuses", %{"status" => "scheduled", "scheduled_at" => tomorrow})
3304
3305 assert %{"error" => "total limit exceeded"} == json_response(conn, 422)
3306 end
3307
3308 test "shows scheduled activities", %{conn: conn} do
3309 user = insert(:user)
3310 scheduled_activity_id1 = insert(:scheduled_activity, user: user).id |> to_string()
3311 scheduled_activity_id2 = insert(:scheduled_activity, user: user).id |> to_string()
3312 scheduled_activity_id3 = insert(:scheduled_activity, user: user).id |> to_string()
3313 scheduled_activity_id4 = insert(:scheduled_activity, user: user).id |> to_string()
3314
3315 conn =
3316 conn
3317 |> assign(:user, user)
3318
3319 # min_id
3320 conn_res =
3321 conn
3322 |> get("/api/v1/scheduled_statuses?limit=2&min_id=#{scheduled_activity_id1}")
3323
3324 result = json_response(conn_res, 200)
3325 assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result
3326
3327 # since_id
3328 conn_res =
3329 conn
3330 |> get("/api/v1/scheduled_statuses?limit=2&since_id=#{scheduled_activity_id1}")
3331
3332 result = json_response(conn_res, 200)
3333 assert [%{"id" => ^scheduled_activity_id4}, %{"id" => ^scheduled_activity_id3}] = result
3334
3335 # max_id
3336 conn_res =
3337 conn
3338 |> get("/api/v1/scheduled_statuses?limit=2&max_id=#{scheduled_activity_id4}")
3339
3340 result = json_response(conn_res, 200)
3341 assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result
3342 end
3343
3344 test "shows a scheduled activity", %{conn: conn} do
3345 user = insert(:user)
3346 scheduled_activity = insert(:scheduled_activity, user: user)
3347
3348 res_conn =
3349 conn
3350 |> assign(:user, user)
3351 |> get("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
3352
3353 assert %{"id" => scheduled_activity_id} = json_response(res_conn, 200)
3354 assert scheduled_activity_id == scheduled_activity.id |> to_string()
3355
3356 res_conn =
3357 conn
3358 |> assign(:user, user)
3359 |> get("/api/v1/scheduled_statuses/404")
3360
3361 assert %{"error" => "Record not found"} = json_response(res_conn, 404)
3362 end
3363
3364 test "updates a scheduled activity", %{conn: conn} do
3365 user = insert(:user)
3366 scheduled_activity = insert(:scheduled_activity, user: user)
3367
3368 new_scheduled_at =
3369 NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
3370
3371 res_conn =
3372 conn
3373 |> assign(:user, user)
3374 |> put("/api/v1/scheduled_statuses/#{scheduled_activity.id}", %{
3375 scheduled_at: new_scheduled_at
3376 })
3377
3378 assert %{"scheduled_at" => expected_scheduled_at} = json_response(res_conn, 200)
3379 assert expected_scheduled_at == Pleroma.Web.CommonAPI.Utils.to_masto_date(new_scheduled_at)
3380
3381 res_conn =
3382 conn
3383 |> assign(:user, user)
3384 |> put("/api/v1/scheduled_statuses/404", %{scheduled_at: new_scheduled_at})
3385
3386 assert %{"error" => "Record not found"} = json_response(res_conn, 404)
3387 end
3388
3389 test "deletes a scheduled activity", %{conn: conn} do
3390 user = insert(:user)
3391 scheduled_activity = insert(:scheduled_activity, user: user)
3392
3393 res_conn =
3394 conn
3395 |> assign(:user, user)
3396 |> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
3397
3398 assert %{} = json_response(res_conn, 200)
3399 assert nil == Repo.get(ScheduledActivity, scheduled_activity.id)
3400
3401 res_conn =
3402 conn
3403 |> assign(:user, user)
3404 |> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
3405
3406 assert %{"error" => "Record not found"} = json_response(res_conn, 404)
3407 end
3408 end
3409
3410 test "Repeated posts that are replies incorrectly have in_reply_to_id null", %{conn: conn} do
3411 user1 = insert(:user)
3412 user2 = insert(:user)
3413 user3 = insert(:user)
3414
3415 {:ok, replied_to} = CommonAPI.post(user1, %{"status" => "cofe"})
3416
3417 # Reply to status from another user
3418 conn1 =
3419 conn
3420 |> assign(:user, user2)
3421 |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => replied_to.id})
3422
3423 assert %{"content" => "xD", "id" => id} = json_response(conn1, 200)
3424
3425 activity = Activity.get_by_id_with_object(id)
3426
3427 assert Object.normalize(activity).data["inReplyTo"] == Object.normalize(replied_to).data["id"]
3428 assert Activity.get_in_reply_to_activity(activity).id == replied_to.id
3429
3430 # Reblog from the third user
3431 conn2 =
3432 conn
3433 |> assign(:user, user3)
3434 |> post("/api/v1/statuses/#{activity.id}/reblog")
3435
3436 assert %{"reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1}} =
3437 json_response(conn2, 200)
3438
3439 assert to_string(activity.id) == id
3440
3441 # Getting third user status
3442 conn3 =
3443 conn
3444 |> assign(:user, user3)
3445 |> get("api/v1/timelines/home")
3446
3447 [reblogged_activity] = json_response(conn3, 200)
3448
3449 assert reblogged_activity["reblog"]["in_reply_to_id"] == replied_to.id
3450
3451 replied_to_user = User.get_by_ap_id(replied_to.data["actor"])
3452 assert reblogged_activity["reblog"]["in_reply_to_account_id"] == replied_to_user.id
3453 end
3454
3455 describe "create account by app" do
3456 test "Account registration via Application", %{conn: conn} do
3457 conn =
3458 conn
3459 |> post("/api/v1/apps", %{
3460 client_name: "client_name",
3461 redirect_uris: "urn:ietf:wg:oauth:2.0:oob",
3462 scopes: "read, write, follow"
3463 })
3464
3465 %{
3466 "client_id" => client_id,
3467 "client_secret" => client_secret,
3468 "id" => _,
3469 "name" => "client_name",
3470 "redirect_uri" => "urn:ietf:wg:oauth:2.0:oob",
3471 "vapid_key" => _,
3472 "website" => nil
3473 } = json_response(conn, 200)
3474
3475 conn =
3476 conn
3477 |> post("/oauth/token", %{
3478 grant_type: "client_credentials",
3479 client_id: client_id,
3480 client_secret: client_secret
3481 })
3482
3483 assert %{"access_token" => token, "refresh_token" => refresh, "scope" => scope} =
3484 json_response(conn, 200)
3485
3486 assert token
3487 token_from_db = Repo.get_by(Token, token: token)
3488 assert token_from_db
3489 assert refresh
3490 assert scope == "read write follow"
3491
3492 conn =
3493 build_conn()
3494 |> put_req_header("authorization", "Bearer " <> token)
3495 |> post("/api/v1/accounts", %{
3496 username: "lain",
3497 email: "lain@example.org",
3498 password: "PlzDontHackLain",
3499 agreement: true
3500 })
3501
3502 %{
3503 "access_token" => token,
3504 "created_at" => _created_at,
3505 "scope" => _scope,
3506 "token_type" => "Bearer"
3507 } = json_response(conn, 200)
3508
3509 token_from_db = Repo.get_by(Token, token: token)
3510 assert token_from_db
3511 token_from_db = Repo.preload(token_from_db, :user)
3512 assert token_from_db.user
3513
3514 assert token_from_db.user.info.confirmation_pending
3515 end
3516
3517 test "rate limit", %{conn: conn} do
3518 app_token = insert(:oauth_token, user: nil)
3519
3520 conn =
3521 put_req_header(conn, "authorization", "Bearer " <> app_token.token)
3522 |> Map.put(:remote_ip, {15, 15, 15, 15})
3523
3524 for i <- 1..5 do
3525 conn =
3526 conn
3527 |> post("/api/v1/accounts", %{
3528 username: "#{i}lain",
3529 email: "#{i}lain@example.org",
3530 password: "PlzDontHackLain",
3531 agreement: true
3532 })
3533
3534 %{
3535 "access_token" => token,
3536 "created_at" => _created_at,
3537 "scope" => _scope,
3538 "token_type" => "Bearer"
3539 } = json_response(conn, 200)
3540
3541 token_from_db = Repo.get_by(Token, token: token)
3542 assert token_from_db
3543 token_from_db = Repo.preload(token_from_db, :user)
3544 assert token_from_db.user
3545
3546 assert token_from_db.user.info.confirmation_pending
3547 end
3548
3549 conn =
3550 conn
3551 |> post("/api/v1/accounts", %{
3552 username: "6lain",
3553 email: "6lain@example.org",
3554 password: "PlzDontHackLain",
3555 agreement: true
3556 })
3557
3558 assert json_response(conn, :too_many_requests) == %{"error" => "Throttled"}
3559 end
3560 end
3561
3562 describe "GET /api/v1/polls/:id" do
3563 test "returns poll entity for object id", %{conn: conn} do
3564 user = insert(:user)
3565
3566 {:ok, activity} =
3567 CommonAPI.post(user, %{
3568 "status" => "Pleroma does",
3569 "poll" => %{"options" => ["what Mastodon't", "n't what Mastodoes"], "expires_in" => 20}
3570 })
3571
3572 object = Object.normalize(activity)
3573
3574 conn =
3575 conn
3576 |> assign(:user, user)
3577 |> get("/api/v1/polls/#{object.id}")
3578
3579 response = json_response(conn, 200)
3580 id = to_string(object.id)
3581 assert %{"id" => ^id, "expired" => false, "multiple" => false} = response
3582 end
3583
3584 test "does not expose polls for private statuses", %{conn: conn} do
3585 user = insert(:user)
3586 other_user = insert(:user)
3587
3588 {:ok, activity} =
3589 CommonAPI.post(user, %{
3590 "status" => "Pleroma does",
3591 "poll" => %{"options" => ["what Mastodon't", "n't what Mastodoes"], "expires_in" => 20},
3592 "visibility" => "private"
3593 })
3594
3595 object = Object.normalize(activity)
3596
3597 conn =
3598 conn
3599 |> assign(:user, other_user)
3600 |> get("/api/v1/polls/#{object.id}")
3601
3602 assert json_response(conn, 404)
3603 end
3604 end
3605
3606 describe "POST /api/v1/polls/:id/votes" do
3607 test "votes are added to the poll", %{conn: conn} do
3608 user = insert(:user)
3609 other_user = insert(:user)
3610
3611 {:ok, activity} =
3612 CommonAPI.post(user, %{
3613 "status" => "A very delicious sandwich",
3614 "poll" => %{
3615 "options" => ["Lettuce", "Grilled Bacon", "Tomato"],
3616 "expires_in" => 20,
3617 "multiple" => true
3618 }
3619 })
3620
3621 object = Object.normalize(activity)
3622
3623 conn =
3624 conn
3625 |> assign(:user, other_user)
3626 |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0, 1, 2]})
3627
3628 assert json_response(conn, 200)
3629 object = Object.get_by_id(object.id)
3630
3631 assert Enum.all?(object.data["anyOf"], fn %{"replies" => %{"totalItems" => total_items}} ->
3632 total_items == 1
3633 end)
3634 end
3635
3636 test "author can't vote", %{conn: conn} do
3637 user = insert(:user)
3638
3639 {:ok, activity} =
3640 CommonAPI.post(user, %{
3641 "status" => "Am I cute?",
3642 "poll" => %{"options" => ["Yes", "No"], "expires_in" => 20}
3643 })
3644
3645 object = Object.normalize(activity)
3646
3647 assert conn
3648 |> assign(:user, user)
3649 |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [1]})
3650 |> json_response(422) == %{"error" => "Poll's author can't vote"}
3651
3652 object = Object.get_by_id(object.id)
3653
3654 refute Enum.at(object.data["oneOf"], 1)["replies"]["totalItems"] == 1
3655 end
3656
3657 test "does not allow multiple choices on a single-choice question", %{conn: conn} do
3658 user = insert(:user)
3659 other_user = insert(:user)
3660
3661 {:ok, activity} =
3662 CommonAPI.post(user, %{
3663 "status" => "The glass is",
3664 "poll" => %{"options" => ["half empty", "half full"], "expires_in" => 20}
3665 })
3666
3667 object = Object.normalize(activity)
3668
3669 assert conn
3670 |> assign(:user, other_user)
3671 |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0, 1]})
3672 |> json_response(422) == %{"error" => "Too many choices"}
3673
3674 object = Object.get_by_id(object.id)
3675
3676 refute Enum.any?(object.data["oneOf"], fn %{"replies" => %{"totalItems" => total_items}} ->
3677 total_items == 1
3678 end)
3679 end
3680
3681 test "does not allow choice index to be greater than options count", %{conn: conn} do
3682 user = insert(:user)
3683 other_user = insert(:user)
3684
3685 {:ok, activity} =
3686 CommonAPI.post(user, %{
3687 "status" => "Am I cute?",
3688 "poll" => %{"options" => ["Yes", "No"], "expires_in" => 20}
3689 })
3690
3691 object = Object.normalize(activity)
3692
3693 conn =
3694 conn
3695 |> assign(:user, other_user)
3696 |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [2]})
3697
3698 assert json_response(conn, 422) == %{"error" => "Invalid indices"}
3699 end
3700
3701 test "returns 404 error when object is not exist", %{conn: conn} do
3702 user = insert(:user)
3703
3704 conn =
3705 conn
3706 |> assign(:user, user)
3707 |> post("/api/v1/polls/1/votes", %{"choices" => [0]})
3708
3709 assert json_response(conn, 404) == %{"error" => "Record not found"}
3710 end
3711
3712 test "returns 404 when poll is private and not available for user", %{conn: conn} do
3713 user = insert(:user)
3714 other_user = insert(:user)
3715
3716 {:ok, activity} =
3717 CommonAPI.post(user, %{
3718 "status" => "Am I cute?",
3719 "poll" => %{"options" => ["Yes", "No"], "expires_in" => 20},
3720 "visibility" => "private"
3721 })
3722
3723 object = Object.normalize(activity)
3724
3725 conn =
3726 conn
3727 |> assign(:user, other_user)
3728 |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0]})
3729
3730 assert json_response(conn, 404) == %{"error" => "Record not found"}
3731 end
3732 end
3733
3734 describe "GET /api/v1/statuses/:id/favourited_by" do
3735 setup do
3736 user = insert(:user)
3737 {:ok, activity} = CommonAPI.post(user, %{"status" => "test"})
3738
3739 conn =
3740 build_conn()
3741 |> assign(:user, user)
3742
3743 [conn: conn, activity: activity]
3744 end
3745
3746 test "returns users who have favorited the status", %{conn: conn, activity: activity} do
3747 other_user = insert(:user)
3748 {:ok, _, _} = CommonAPI.favorite(activity.id, other_user)
3749
3750 response =
3751 conn
3752 |> get("/api/v1/statuses/#{activity.id}/favourited_by")
3753 |> json_response(:ok)
3754
3755 [%{"id" => id}] = response
3756
3757 assert id == other_user.id
3758 end
3759
3760 test "returns empty array when status has not been favorited yet", %{
3761 conn: conn,
3762 activity: activity
3763 } do
3764 response =
3765 conn
3766 |> get("/api/v1/statuses/#{activity.id}/favourited_by")
3767 |> json_response(:ok)
3768
3769 assert Enum.empty?(response)
3770 end
3771
3772 test "does not return users who have favorited the status but are blocked", %{
3773 conn: %{assigns: %{user: user}} = conn,
3774 activity: activity
3775 } do
3776 other_user = insert(:user)
3777 {:ok, user} = User.block(user, other_user)
3778
3779 {:ok, _, _} = CommonAPI.favorite(activity.id, other_user)
3780
3781 response =
3782 conn
3783 |> assign(:user, user)
3784 |> get("/api/v1/statuses/#{activity.id}/favourited_by")
3785 |> json_response(:ok)
3786
3787 assert Enum.empty?(response)
3788 end
3789
3790 test "does not fail on an unauthenticated request", %{conn: conn, activity: activity} do
3791 other_user = insert(:user)
3792 {:ok, _, _} = CommonAPI.favorite(activity.id, other_user)
3793
3794 response =
3795 conn
3796 |> assign(:user, nil)
3797 |> get("/api/v1/statuses/#{activity.id}/favourited_by")
3798 |> json_response(:ok)
3799
3800 [%{"id" => id}] = response
3801 assert id == other_user.id
3802 end
3803 end
3804
3805 describe "GET /api/v1/statuses/:id/reblogged_by" do
3806 setup do
3807 user = insert(:user)
3808 {:ok, activity} = CommonAPI.post(user, %{"status" => "test"})
3809
3810 conn =
3811 build_conn()
3812 |> assign(:user, user)
3813
3814 [conn: conn, activity: activity]
3815 end
3816
3817 test "returns users who have reblogged the status", %{conn: conn, activity: activity} do
3818 other_user = insert(:user)
3819 {:ok, _, _} = CommonAPI.repeat(activity.id, other_user)
3820
3821 response =
3822 conn
3823 |> get("/api/v1/statuses/#{activity.id}/reblogged_by")
3824 |> json_response(:ok)
3825
3826 [%{"id" => id}] = response
3827
3828 assert id == other_user.id
3829 end
3830
3831 test "returns empty array when status has not been reblogged yet", %{
3832 conn: conn,
3833 activity: activity
3834 } do
3835 response =
3836 conn
3837 |> get("/api/v1/statuses/#{activity.id}/reblogged_by")
3838 |> json_response(:ok)
3839
3840 assert Enum.empty?(response)
3841 end
3842
3843 test "does not return users who have reblogged the status but are blocked", %{
3844 conn: %{assigns: %{user: user}} = conn,
3845 activity: activity
3846 } do
3847 other_user = insert(:user)
3848 {:ok, user} = User.block(user, other_user)
3849
3850 {:ok, _, _} = CommonAPI.repeat(activity.id, other_user)
3851
3852 response =
3853 conn
3854 |> assign(:user, user)
3855 |> get("/api/v1/statuses/#{activity.id}/reblogged_by")
3856 |> json_response(:ok)
3857
3858 assert Enum.empty?(response)
3859 end
3860
3861 test "does not fail on an unauthenticated request", %{conn: conn, activity: activity} do
3862 other_user = insert(:user)
3863 {:ok, _, _} = CommonAPI.repeat(activity.id, other_user)
3864
3865 response =
3866 conn
3867 |> assign(:user, nil)
3868 |> get("/api/v1/statuses/#{activity.id}/reblogged_by")
3869 |> json_response(:ok)
3870
3871 [%{"id" => id}] = response
3872 assert id == other_user.id
3873 end
3874 end
3875
3876 describe "POST /auth/password, with valid parameters" do
3877 setup %{conn: conn} do
3878 user = insert(:user)
3879 conn = post(conn, "/auth/password?email=#{user.email}")
3880 %{conn: conn, user: user}
3881 end
3882
3883 test "it returns 204", %{conn: conn} do
3884 assert json_response(conn, :no_content)
3885 end
3886
3887 test "it creates a PasswordResetToken record for user", %{user: user} do
3888 token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id)
3889 assert token_record
3890 end
3891
3892 test "it sends an email to user", %{user: user} do
3893 token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id)
3894
3895 email = Pleroma.Emails.UserEmail.password_reset_email(user, token_record.token)
3896 notify_email = Pleroma.Config.get([:instance, :notify_email])
3897 instance_name = Pleroma.Config.get([:instance, :name])
3898
3899 assert_email_sent(
3900 from: {instance_name, notify_email},
3901 to: {user.name, user.email},
3902 html_body: email.html_body
3903 )
3904 end
3905 end
3906
3907 describe "POST /auth/password, with invalid parameters" do
3908 setup do
3909 user = insert(:user)
3910 {:ok, user: user}
3911 end
3912
3913 test "it returns 404 when user is not found", %{conn: conn, user: user} do
3914 conn = post(conn, "/auth/password?email=nonexisting_#{user.email}")
3915 assert conn.status == 404
3916 assert conn.resp_body == ""
3917 end
3918
3919 test "it returns 400 when user is not local", %{conn: conn, user: user} do
3920 {:ok, user} = Repo.update(Changeset.change(user, local: false))
3921 conn = post(conn, "/auth/password?email=#{user.email}")
3922 assert conn.status == 400
3923 assert conn.resp_body == ""
3924 end
3925 end
3926 end