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