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