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