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